From 295eceece371b516e771de93b6127bf728999483 Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 26 Jul 2014 19:24:00 -0400 Subject: initial commit so far source analysis is working. =) --- src/cuchaz/enigma/ClassFile.java | 45 ++++ src/cuchaz/enigma/Deobfuscator.java | 109 +++++++++ src/cuchaz/enigma/Main.java | 63 ++++++ src/cuchaz/enigma/Util.java | 65 ++++++ src/cuchaz/enigma/analysis/Analyzer.java | 252 +++++++++++++++++++++ src/cuchaz/enigma/analysis/ClassNameIndex.java | 19 ++ .../enigma/analysis/JavaSourceFromString.java | 31 +++ src/cuchaz/enigma/analysis/Lexer.java | 41 ++++ src/cuchaz/enigma/analysis/SourceIndex.java | 57 +++++ src/cuchaz/enigma/analysis/SourcedAst.java | 111 +++++++++ src/cuchaz/enigma/gui/BoxHighlightPainter.java | 54 +++++ src/cuchaz/enigma/gui/ClassSelectionHandler.java | 18 ++ src/cuchaz/enigma/gui/Gui.java | 163 +++++++++++++ .../gui/ObfuscatedClassListCellRenderer.java | 40 ++++ src/cuchaz/enigma/gui/SourceFormatter.java | 62 +++++ src/cuchaz/enigma/mapping/ArgumentEntry.java | 88 +++++++ src/cuchaz/enigma/mapping/ClassEntry.java | 67 ++++++ src/cuchaz/enigma/mapping/FieldEntry.java | 76 +++++++ src/cuchaz/enigma/mapping/MethodEntry.java | 88 +++++++ 19 files changed, 1449 insertions(+) create mode 100644 src/cuchaz/enigma/ClassFile.java create mode 100644 src/cuchaz/enigma/Deobfuscator.java create mode 100644 src/cuchaz/enigma/Main.java create mode 100644 src/cuchaz/enigma/Util.java create mode 100644 src/cuchaz/enigma/analysis/Analyzer.java create mode 100644 src/cuchaz/enigma/analysis/ClassNameIndex.java create mode 100644 src/cuchaz/enigma/analysis/JavaSourceFromString.java create mode 100644 src/cuchaz/enigma/analysis/Lexer.java create mode 100644 src/cuchaz/enigma/analysis/SourceIndex.java create mode 100644 src/cuchaz/enigma/analysis/SourcedAst.java create mode 100644 src/cuchaz/enigma/gui/BoxHighlightPainter.java create mode 100644 src/cuchaz/enigma/gui/ClassSelectionHandler.java create mode 100644 src/cuchaz/enigma/gui/Gui.java create mode 100644 src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java create mode 100644 src/cuchaz/enigma/gui/SourceFormatter.java create mode 100644 src/cuchaz/enigma/mapping/ArgumentEntry.java create mode 100644 src/cuchaz/enigma/mapping/ClassEntry.java create mode 100644 src/cuchaz/enigma/mapping/FieldEntry.java create mode 100644 src/cuchaz/enigma/mapping/MethodEntry.java (limited to 'src') diff --git a/src/cuchaz/enigma/ClassFile.java b/src/cuchaz/enigma/ClassFile.java new file mode 100644 index 00000000..221a119e --- /dev/null +++ b/src/cuchaz/enigma/ClassFile.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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 java.util.regex.Pattern; + +public class ClassFile +{ + private static Pattern m_obfuscatedClassPattern; + + static + { + m_obfuscatedClassPattern = Pattern.compile( "^[a-z]+$" ); + } + + private String m_name; + + public ClassFile( String name ) + { + m_name = name; + } + + public String getName( ) + { + return m_name; + } + + public boolean isObfuscated( ) + { + return m_obfuscatedClassPattern.matcher( m_name ).matches(); + } + + public String getPath( ) + { + return m_name.replace( ".", "/" ) + ".class"; + } +} diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java new file mode 100644 index 00000000..83a21719 --- /dev/null +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * 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 java.io.File; +import java.io.IOException; +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; +import java.util.jar.JarFile; + +import com.strobel.assembler.metadata.JarTypeLoader; +import com.strobel.decompiler.Decompiler; +import com.strobel.decompiler.DecompilerSettings; +import com.strobel.decompiler.PlainTextOutput; + +public class Deobfuscator +{ + private File m_file; + private JarFile m_jar; + private DecompilerSettings m_settings; + + 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 + { + m_file = file; + m_jar = new JarFile( m_file ); + m_settings = DecompilerSettings.javaDefaults(); + m_settings.setTypeLoader( new JarTypeLoader( m_jar ) ); + m_settings.setForceExplicitImports( true ); + m_settings.setShowSyntheticMembers( true ); + } + + public List getObfuscatedClasses( ) + { + 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 ) + { + continue; + } + + ClassFile classFile = new ClassFile( className ); + if( classFile.isObfuscated() ) + { + classes.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 ); + return buf.toString(); + } +} diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java new file mode 100644 index 00000000..e08c16ed --- /dev/null +++ b/src/cuchaz/enigma/Main.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * 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 java.io.File; + +import cuchaz.enigma.analysis.Analyzer; +import cuchaz.enigma.analysis.SourceIndex; +import cuchaz.enigma.gui.ClassSelectionHandler; +import cuchaz.enigma.gui.Gui; + +public class Main +{ + public static void main( String[] args ) + throws Exception + { + startGui(); + } + + private static void startGui( ) + throws Exception + { + final Gui gui = new Gui(); + + // settings + final File jarFile = new File( "/home/jeff/.minecraft/versions/1.7.10/1.7.10.jar" ); + gui.setTitle( jarFile.getName() ); + + // init the deobfuscator + final Deobfuscator deobfuscator = new Deobfuscator( jarFile ); + gui.setObfClasses( deobfuscator.getObfuscatedClasses() ); + + // handle events + gui.setClassSelectionHandler( new ClassSelectionHandler( ) + { + @Override + public void classSelected( final ClassFile classFile ) + { + 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( ) + { + String source = deobfuscator.getSource( classFile ); + SourceIndex index = Analyzer.analyze( classFile.getName(), source ); + gui.setSource( source, index ); + } + }.start(); + } + } ); + } +} diff --git a/src/cuchaz/enigma/Util.java b/src/cuchaz/enigma/Util.java new file mode 100644 index 00000000..c51eb621 --- /dev/null +++ b/src/cuchaz/enigma/Util.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * 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 java.io.Closeable; +import java.io.IOException; +import java.util.jar.JarFile; + + +public class Util +{ + public static int combineHashesOrdered( Object ... objs ) + { + final int prime = 67; + int result = 1; + for( Object obj : objs ) + { + result *= prime; + if( obj != null ) + { + result += obj.hashCode(); + } + } + return result; + } + + public static void closeQuietly( Closeable closeable ) + { + if( closeable != null ) + { + try + { + closeable.close(); + } + catch( IOException ex ) + { + // just ignore any further exceptions + } + } + } + + public static void closeQuietly( JarFile jarFile ) + { + // silly library should implement Closeable... + if( jarFile != null ) + { + try + { + jarFile.close(); + } + catch( IOException ex ) + { + // just ignore any further exceptions + } + } + } +} diff --git a/src/cuchaz/enigma/analysis/Analyzer.java b/src/cuchaz/enigma/analysis/Analyzer.java new file mode 100644 index 00000000..1cdabe75 --- /dev/null +++ b/src/cuchaz/enigma/analysis/Analyzer.java @@ -0,0 +1,252 @@ +/******************************************************************************* + * 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.analysis; + +import java.io.IOException; +import java.util.Arrays; + +import javax.tools.JavaCompiler; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import jsyntaxpane.Token; +import jsyntaxpane.TokenType; + +import com.sun.source.tree.ArrayTypeTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.PrimitiveTypeTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.Tree.Kind; +import com.sun.source.tree.VariableTree; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TreeScanner; +import com.sun.source.util.Trees; + +import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; + +class TreeVisitor extends TreeScanner +{ + private SourceIndex m_index; + + public TreeVisitor( SourceIndex index ) + { + m_index = index; + } + + @Override + public CompilationUnitTree visitClass( ClassTree classTree, SourcedAst ast ) + { + ClassEntry classEntry = indexClass( classTree, ast ); + + // look at the class members + for( Tree memberTree : classTree.getMembers() ) + { + if( memberTree.getKind() == Kind.VARIABLE ) + { + indexField( (VariableTree)memberTree, ast, classEntry ); + } + else if( memberTree.getKind() == Kind.METHOD ) + { + MethodTree methodTree = (MethodTree)memberTree; + MethodEntry methodEntry = indexMethod( methodTree, ast, classEntry ); + + // look at method arguments + int argNum = 0; + for( VariableTree variableTree : methodTree.getParameters() ) + { + indexArgument( variableTree, ast, methodEntry, argNum++ ); + } + } + } + + return super.visitClass( classTree, ast ); + } + + private ClassEntry indexClass( ClassTree classTree, SourcedAst ast ) + { + // build the entry + ClassEntry entry = new ClassEntry( ast.getFullClassName( classTree.getSimpleName().toString() ) ); + + // lex the source at this tree node + for( Token token : new Lexer( ast.getSource( classTree ).toString() ) ) + { + // scan until we get the first identifier + if( token.type == TokenType.IDENTIFIER ) + { + m_index.add( entry, offsetToken( token, ast.getStart( classTree ) ) ); + break; + } + } + + return entry; + } + + private FieldEntry indexField( VariableTree variableTree, SourcedAst ast, ClassEntry classEntry ) + { + // build the entry + FieldEntry entry = new FieldEntry( classEntry, variableTree.getName().toString() ); + + // lex the source at this tree node + Lexer lexer = new Lexer( ast.getSource( variableTree ).toString() ); + for( Token token : lexer ) + { + // scan until we find an identifier that matches the field name + if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) ) + { + m_index.add( entry, offsetToken( token, ast.getStart( variableTree ) ) ); + break; + } + } + + return entry; + } + + private MethodEntry indexMethod( MethodTree methodTree, SourcedAst ast, ClassEntry classEntry ) + { + // build the entry + StringBuilder signature = new StringBuilder(); + signature.append( "(" ); + for( VariableTree variableTree : methodTree.getParameters() ) + { + signature.append( toJvmType( variableTree.getType(), ast ) ); + } + signature.append( ")" ); + if( methodTree.getReturnType() != null ) + { + signature.append( toJvmType( methodTree.getReturnType(), ast ) ); + } + else + { + signature.append( "V" ); + } + MethodEntry entry = new MethodEntry( classEntry, methodTree.getName().toString(), signature.toString() ); + + // lex the source at this tree node + Lexer lexer = new Lexer( ast.getSource( methodTree ).toString() ); + for( Token token : lexer ) + { + // scan until we find an identifier that matches the method name + if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) ) + { + m_index.add( entry, offsetToken( token, ast.getStart( methodTree ) ) ); + break; + } + } + + return entry; + } + + private void indexArgument( VariableTree variableTree, SourcedAst ast, MethodEntry methodEntry, int index ) + { + System.out.println( "\tFound argument: " + variableTree.getName() ); + + // build the entry + ArgumentEntry entry = new ArgumentEntry( methodEntry, index, variableTree.getName().toString() ); + + // lex the source at this tree node + Lexer lexer = new Lexer( ast.getSource( variableTree ).toString() ); + for( Token token : lexer ) + { + // scan until we find an identifier that matches the variable name + if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) ) + { + m_index.add( entry, offsetToken( token, ast.getStart( variableTree ) ) ); + break; + } + } + } + + private Token offsetToken( Token in, int offset ) + { + return new Token( in.type, in.start + offset, in.length ); + } + + private String toJvmType( Tree tree, SourcedAst ast ) + { + switch( tree.getKind() ) + { + case PRIMITIVE_TYPE: + { + PrimitiveTypeTree primitiveTypeTree = (PrimitiveTypeTree)tree; + switch( primitiveTypeTree.getPrimitiveTypeKind() ) + { + case BOOLEAN: return "Z"; + case BYTE: return "B"; + case CHAR: return "C"; + case DOUBLE: return "D"; + case FLOAT: return "F"; + case INT: return "I"; + case LONG: return "J"; + case SHORT: return "S"; + case VOID: return "V"; + + default: + throw new Error( "Unsupported primitive type: " + primitiveTypeTree.getPrimitiveTypeKind() ); + } + } + + case IDENTIFIER: + { + IdentifierTree identifierTree = (IdentifierTree)tree; + String className = identifierTree.getName().toString(); + className = ast.getFullClassName( className ); + return "L" + className.replace( ".", "/" ) + ";"; + } + + case ARRAY_TYPE: + { + ArrayTypeTree arrayTree = (ArrayTypeTree)tree; + return "[" + toJvmType( arrayTree.getType(), ast ); + } + + + default: + throw new Error( "Unsupported type kind: " + tree.getKind() ); + } + } +} + +public class Analyzer +{ + public static SourceIndex analyze( String className, String source ) + { + SourceIndex index = new SourceIndex(); + SourcedAst ast = getAst( className, source ); + ast.visit( new TreeVisitor( index ) ); + return index; + } + + private static SourcedAst getAst( String className, String source ) + { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null ); + JavaSourceFromString unit = new JavaSourceFromString( className, source ); + JavacTask task = (JavacTask)compiler.getTask( null, fileManager, null, null, null, Arrays.asList( unit ) ); + + try + { + return new SourcedAst( + task.parse().iterator().next(), + Trees.instance( task ) + ); + } + catch( IOException ex ) + { + throw new Error( ex ); + } + } +} diff --git a/src/cuchaz/enigma/analysis/ClassNameIndex.java b/src/cuchaz/enigma/analysis/ClassNameIndex.java new file mode 100644 index 00000000..ea3e2cae --- /dev/null +++ b/src/cuchaz/enigma/analysis/ClassNameIndex.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * 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.analysis; + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.util.TreeScanner; + +public class ClassNameIndex extends TreeScanner +{ + +} diff --git a/src/cuchaz/enigma/analysis/JavaSourceFromString.java b/src/cuchaz/enigma/analysis/JavaSourceFromString.java new file mode 100644 index 00000000..cf5c4c27 --- /dev/null +++ b/src/cuchaz/enigma/analysis/JavaSourceFromString.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * 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.analysis; + +import java.net.URI; + +import javax.tools.SimpleJavaFileObject; + +public class JavaSourceFromString extends SimpleJavaFileObject +{ + private final String m_source; + + JavaSourceFromString( String name, String source ) + { + super( URI.create( "string:///" + name.replace( '.', '/' ) + Kind.SOURCE.extension ), Kind.SOURCE ); + m_source = source; + } + + public CharSequence getCharContent( boolean ignoreEncodingErrors ) + { + return m_source; + } +} diff --git a/src/cuchaz/enigma/analysis/Lexer.java b/src/cuchaz/enigma/analysis/Lexer.java new file mode 100644 index 00000000..acb52bf8 --- /dev/null +++ b/src/cuchaz/enigma/analysis/Lexer.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.analysis; + +import java.util.Iterator; + +import jsyntaxpane.SyntaxDocument; +import jsyntaxpane.Token; +import jsyntaxpane.lexers.JavaLexer; + +public class Lexer implements Iterable +{ + private SyntaxDocument m_doc; + private Iterator m_iter; + + public Lexer( String source ) + { + m_doc = new SyntaxDocument( new JavaLexer() ); + m_doc.append( source ); + m_iter = m_doc.getTokens( 0, m_doc.getLength() ); + } + + @Override + public Iterator iterator( ) + { + return m_iter; + } + + public String getText( Token token ) + { + return token.getString( m_doc ); + } +} diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java new file mode 100644 index 00000000..a4b5329b --- /dev/null +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * 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.analysis; + +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import jsyntaxpane.Token; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; + +public class SourceIndex implements Iterable> +{ + private BiMap m_entryToToken; + private BiMap m_tokenToEntry; + + public SourceIndex( ) + { + m_entryToToken = HashBiMap.create(); + m_tokenToEntry = m_entryToToken.inverse(); + } + + public void add( Object entry, Token token ) + { + m_entryToToken.put( entry, token ); + } + + public Iterator> iterator( ) + { + return m_entryToToken.entrySet().iterator(); + } + + public Set tokens( ) + { + return m_entryToToken.values(); + } + + public Object getEntry( Token token ) + { + return m_tokenToEntry.get( token ); + } + + public Object getToken( Object entry ) + { + return m_entryToToken.get( entry ); + } +} diff --git a/src/cuchaz/enigma/analysis/SourcedAst.java b/src/cuchaz/enigma/analysis/SourcedAst.java new file mode 100644 index 00000000..04c6f03b --- /dev/null +++ b/src/cuchaz/enigma/analysis/SourcedAst.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * 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.analysis; + +import java.io.IOException; +import java.util.HashMap; + +import com.google.common.collect.Maps; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.ImportTree; +import com.sun.source.tree.Tree; +import com.sun.source.util.SourcePositions; +import com.sun.source.util.Trees; + +public class SourcedAst +{ + private CompilationUnitTree m_tree; + private Trees m_trees; + private SourcePositions m_positions; + private HashMap m_classNameIndex; + + public SourcedAst( CompilationUnitTree tree, Trees trees ) + { + m_tree = tree; + m_trees = trees; + m_positions = m_trees.getSourcePositions(); + m_classNameIndex = Maps.newHashMap(); + + // index all the class names + for( ImportTree importTree : m_tree.getImports() ) + { + // ignore static imports for now + if( importTree.isStatic() ) + { + continue; + } + + // get the full and simple class names + String fullName = importTree.getQualifiedIdentifier().toString(); + String simpleName = fullName; + String[] parts = fullName.split( "\\." ); + if( parts.length > 0 ) + { + simpleName = parts[parts.length - 1]; + } + + m_classNameIndex.put( simpleName, fullName ); + } + } + + public int getStart( Tree node ) + { + return (int)m_positions.getStartPosition( m_tree, node ); + } + + public int getEnd( Tree node ) + { + return (int)m_positions.getEndPosition( m_tree, node ); + } + + public int getLine( Tree node ) + { + return getLine( getStart( node ) ); + } + + public int getLine( int pos ) + { + return (int)m_tree.getLineMap().getLineNumber( pos ); + } + + public CharSequence getSource( ) + { + try + { + return m_tree.getSourceFile().getCharContent( true ); + } + catch( IOException ex ) + { + throw new Error( ex ); + } + } + + public CharSequence getSource( Tree node ) + { + return getSource().subSequence( getStart( node ), getEnd( node ) ); + } + + public void visit( TreeVisitor visitor ) + { + m_tree.accept( visitor, this ); + } + + public String getFullClassName( String simpleClassName ) + { + String fullClassName = m_classNameIndex.get( simpleClassName ); + if( fullClassName == null ) + { + // no mapping was found, the name is probably already fully-qualified + fullClassName = simpleClassName; + } + return fullClassName; + } +} diff --git a/src/cuchaz/enigma/gui/BoxHighlightPainter.java b/src/cuchaz/enigma/gui/BoxHighlightPainter.java new file mode 100644 index 00000000..22db28b7 --- /dev/null +++ b/src/cuchaz/enigma/gui/BoxHighlightPainter.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * 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; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; + +import javax.swing.text.BadLocationException; +import javax.swing.text.Highlighter; +import javax.swing.text.JTextComponent; + +public 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 ); + + @Override + public void paint( Graphics g, int start, int end, Shape shape, JTextComponent text ) + { + try + { + // determine the bounds of the text + Rectangle bounds = text.getUI().modelToView( text, start ).union( text.getUI().modelToView( text, end ) ); + + // adjust the box so it looks nice + bounds.x -= 2; + bounds.width += 2; + bounds.y += 1; + bounds.height -= 2; + + // fill the area + g.setColor( FillColor ); + g.fillRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); + + // draw a box around the area + g.setColor( BorderColor ); + g.drawRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); + } + catch( BadLocationException ex ) + { + throw new Error( ex ); + } + } +} diff --git a/src/cuchaz/enigma/gui/ClassSelectionHandler.java b/src/cuchaz/enigma/gui/ClassSelectionHandler.java new file mode 100644 index 00000000..a50cf6a3 --- /dev/null +++ b/src/cuchaz/enigma/gui/ClassSelectionHandler.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * 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 cuchaz.enigma.ClassFile; + +public interface ClassSelectionHandler +{ + void classSelected( ClassFile classFile ); +} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java new file mode 100644 index 00000000..e0d53d83 --- /dev/null +++ b/src/cuchaz/enigma/gui/Gui.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * 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.BorderLayout; +import java.awt.Container; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; +import java.util.Vector; + +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.ListSelectionModel; +import javax.swing.WindowConstants; +import javax.swing.text.BadLocationException; + +import jsyntaxpane.DefaultSyntaxKit; +import jsyntaxpane.Token; +import cuchaz.enigma.ClassFile; +import cuchaz.enigma.analysis.SourceIndex; + +public class Gui +{ + private static final String Name = "Enigma"; + + // controls + private JFrame m_frame; + private JList m_obfClasses; + private JList m_deobfClasses; + private JEditorPane m_editor; + + // handlers + private ClassSelectionHandler m_classSelectionHandler; + + private BoxHighlightPainter m_highlightPainter; + + public Gui( ) + { + // init frame + m_frame = new JFrame( Name ); + final Container pane = m_frame.getContentPane(); + pane.setLayout( new BorderLayout() ); + + // init obfuscated classes list + m_obfClasses = new JList(); + m_obfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); + m_obfClasses.setLayoutOrientation( JList.VERTICAL ); + m_obfClasses.setCellRenderer( new ObfuscatedClassListCellRenderer() ); + m_obfClasses.addMouseListener( new MouseAdapter() + { + public void mouseClicked( MouseEvent event ) + { + if( event.getClickCount() == 2 ) + { + if( m_classSelectionHandler != null ) + { + ClassFile selected = m_obfClasses.getSelectedValue(); + if( selected != null ) + { + m_classSelectionHandler.classSelected( selected ); + } + } + } + } + } ); + JScrollPane obfScroller = new JScrollPane( m_obfClasses ); + JPanel obfPanel = new JPanel(); + obfPanel.setLayout( new BorderLayout() ); + obfPanel.add( new JLabel( "Obfuscated Classes" ), BorderLayout.NORTH ); + obfPanel.add( obfScroller, BorderLayout.CENTER ); + + // init deobfuscated classes list + m_deobfClasses = new JList(); + m_obfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); + m_obfClasses.setLayoutOrientation( JList.VERTICAL ); + JScrollPane deobfScroller = new JScrollPane( m_deobfClasses ); + JPanel deobfPanel = new JPanel(); + deobfPanel.setLayout( new BorderLayout() ); + deobfPanel.add( new JLabel( "De-obfuscated Classes" ), BorderLayout.NORTH ); + deobfPanel.add( deobfScroller, BorderLayout.CENTER ); + + // init editor + DefaultSyntaxKit.initKit(); + m_editor = new JEditorPane(); + m_editor.setEditable( false ); + JScrollPane sourceScroller = new JScrollPane( m_editor ); + m_editor.setContentType( "text/java" ); + + // layout controls + JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); + JSplitPane splitMain = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, sourceScroller ); + pane.add( splitMain, BorderLayout.CENTER ); + + // show the frame + pane.doLayout(); + m_frame.setSize( 800, 600 ); + m_frame.setVisible( true ); + m_frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE ); + + // init handlers + m_classSelectionHandler = null; + + m_highlightPainter = new BoxHighlightPainter(); + } + + public void setTitle( String title ) + { + m_frame.setTitle( Name + " - " + title ); + } + + public void setObfClasses( List classes ) + { + m_obfClasses.setListData( new Vector( classes ) ); + } + + public void setSource( String source ) + { + setSource( source, null ); + } + + public void setSource( String source, SourceIndex index ) + { + m_editor.setText( source ); + + // remove any old highlighters + m_editor.getHighlighter().removeAllHighlights();; + + if( index != null ) + { + // color things based on the index + for( Token token : index.tokens() ) + { + try + { + m_editor.getHighlighter().addHighlight( token.start, token.end(), m_highlightPainter ); + } + catch( BadLocationException ex ) + { + throw new Error( ex ); + } + } + } + } + + public void setClassSelectionHandler( ClassSelectionHandler val ) + { + m_classSelectionHandler = val; + } +} diff --git a/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java b/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java new file mode 100644 index 00000000..0badb3b9 --- /dev/null +++ b/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.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 ObfuscatedClassListCellRenderer implements ListCellRenderer +{ + private DefaultListCellRenderer m_defaultRenderer; + + public ObfuscatedClassListCellRenderer( ) + { + m_defaultRenderer = new DefaultListCellRenderer(); + } + + @Override + public Component getListCellRendererComponent( JList 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/SourceFormatter.java b/src/cuchaz/enigma/gui/SourceFormatter.java new file mode 100644 index 00000000..f3878405 --- /dev/null +++ b/src/cuchaz/enigma/gui/SourceFormatter.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * 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.BufferedReader; +import java.io.IOException; +import java.io.StringReader; + +public class SourceFormatter +{ + public static String format( String in ) + { + return collapseNewlines( in ); + } + + private static String collapseNewlines( String in ) + { + StringBuffer buf = new StringBuffer(); + int numBlankLines = 0; + + BufferedReader reader = new BufferedReader( new StringReader( in ) ); + String line = null; + try + { + while( ( line = reader.readLine() ) != null ) + { + // how blank lines is this? + boolean isBlank = line.trim().length() == 0; + if( isBlank ) + { + numBlankLines++; + + // stop printing blank lines after the first one + if( numBlankLines < 2 ) + { + buf.append( line ); + buf.append( "\n" ); + } + } + else + { + numBlankLines = 0; + buf.append( line ); + buf.append( "\n" ); + } + } + } + catch( IOException ex ) + { + // StringReader will never throw an IOExecption here... + } + return buf.toString(); + } +} diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java new file mode 100644 index 00000000..6c108d7c --- /dev/null +++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * 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 cuchaz.enigma.Util; + +public class ArgumentEntry implements Serializable +{ + private static final long serialVersionUID = 4472172468162696006L; + + private MethodEntry m_methodEntry; + private int m_index; + private String m_name; + + public ArgumentEntry( MethodEntry methodEntry, int index, String name ) + { + if( methodEntry == null ) + { + throw new IllegalArgumentException( "Method cannot be null!" ); + } + if( index < 0 ) + { + throw new IllegalArgumentException( "Index must be non-negative!" ); + } + if( name == null ) + { + throw new IllegalArgumentException( "Argument name cannot be null!" ); + } + + m_methodEntry = methodEntry; + m_index = index; + m_name = name; + } + + public MethodEntry getMethodEntry( ) + { + return m_methodEntry; + } + + public int getIndex( ) + { + return m_index; + } + + public String getName( ) + { + return m_name; + } + + @Override + public int hashCode( ) + { + return Util.combineHashesOrdered( m_methodEntry, Integer.valueOf( m_index ).hashCode(), m_name.hashCode() ); + } + + @Override + public boolean equals( Object other ) + { + if( other instanceof ArgumentEntry ) + { + return equals( (ArgumentEntry)other ); + } + return false; + } + + public boolean equals( ArgumentEntry other ) + { + return m_methodEntry.equals( other.m_methodEntry ) + && m_index == other.m_index + && m_name.equals( other.m_name ); + } + + @Override + public String toString( ) + { + return m_methodEntry.toString() + "(" + m_index + ":" + m_name + ")"; + } +} diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java new file mode 100644 index 00000000..7e78d4c0 --- /dev/null +++ b/src/cuchaz/enigma/mapping/ClassEntry.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.io.Serializable; + + +public class ClassEntry implements Serializable +{ + private static final long serialVersionUID = 4235460580973955811L; + + private String m_name; + + public ClassEntry( String className ) + { + if( className == null ) + { + throw new IllegalArgumentException( "Class name cannot be null!" ); + } + if( className.contains( "." ) ) + { + throw new IllegalArgumentException( "Class name must be in JVM format. ie, path/to/package/class$inner" ); + } + + m_name = className; + } + + public String getName( ) + { + return m_name; + } + + @Override + public int hashCode( ) + { + return m_name.hashCode(); + } + + @Override + public boolean equals( Object other ) + { + if( other instanceof ClassEntry ) + { + return equals( (ClassEntry)other ); + } + return false; + } + + public boolean equals( ClassEntry other ) + { + return m_name.equals( other.m_name ); + } + + @Override + public String toString( ) + { + return m_name; + } +} diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java new file mode 100644 index 00000000..15a93520 --- /dev/null +++ b/src/cuchaz/enigma/mapping/FieldEntry.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * 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 cuchaz.enigma.Util; + +public class FieldEntry implements Serializable +{ + private static final long serialVersionUID = 3004663582802885451L; + + private ClassEntry m_classEntry; + private String m_name; + + public FieldEntry( ClassEntry classEntry, String name ) + { + if( classEntry == null ) + { + throw new IllegalArgumentException( "Class cannot be null!" ); + } + if( name == null ) + { + throw new IllegalArgumentException( "Field name cannot be null!" ); + } + + m_classEntry = classEntry; + m_name = name; + } + + public ClassEntry getClassEntry( ) + { + return m_classEntry; + } + + public String getName( ) + { + return m_name; + } + + @Override + public int hashCode( ) + { + return Util.combineHashesOrdered( m_classEntry, m_name ); + } + + @Override + public boolean equals( Object other ) + { + if( other instanceof FieldEntry ) + { + return equals( (FieldEntry)other ); + } + return false; + } + + public boolean equals( FieldEntry other ) + { + return m_classEntry.equals( other.m_classEntry ) + && m_name.equals( other.m_name ); + } + + @Override + public String toString( ) + { + return m_classEntry.getName() + "." + m_name; + } +} diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java new file mode 100644 index 00000000..e71a4664 --- /dev/null +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * 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 cuchaz.enigma.Util; + +public class MethodEntry implements Serializable +{ + private static final long serialVersionUID = 4770915224467247458L; + + private ClassEntry m_classEntry; + private String m_name; + private String m_signature; + + public MethodEntry( ClassEntry classEntry, String name, String signature ) + { + if( classEntry == null ) + { + throw new IllegalArgumentException( "Class cannot be null!" ); + } + if( name == null ) + { + throw new IllegalArgumentException( "Method name cannot be null!" ); + } + if( signature == null ) + { + throw new IllegalArgumentException( "Method signature cannot be null!" ); + } + + m_classEntry = classEntry; + m_name = name; + m_signature = signature; + } + + public ClassEntry getClassEntry( ) + { + return m_classEntry; + } + + public String getName( ) + { + return m_name; + } + + public String getSignature( ) + { + return m_signature; + } + + @Override + public int hashCode( ) + { + return Util.combineHashesOrdered( m_classEntry, m_name, m_signature ); + } + + @Override + public boolean equals( Object other ) + { + if( other instanceof MethodEntry ) + { + return equals( (MethodEntry)other ); + } + return false; + } + + public boolean equals( MethodEntry other ) + { + return m_classEntry.equals( other.m_classEntry ) + && m_name.equals( other.m_name ) + && m_signature.equals( other.m_signature ); + } + + @Override + public String toString( ) + { + return m_classEntry.getName() + "." + m_name + ":" + m_signature; + } +} -- cgit v1.2.3 From 4ea3e0cffa54326bc2566fa563c6b5aa5b9b1c96 Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 26 Jul 2014 19:52:30 -0400 Subject: got rid of temp debug traces --- src/cuchaz/enigma/analysis/Analyzer.java | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/Analyzer.java b/src/cuchaz/enigma/analysis/Analyzer.java index 1cdabe75..dad8dc52 100644 --- a/src/cuchaz/enigma/analysis/Analyzer.java +++ b/src/cuchaz/enigma/analysis/Analyzer.java @@ -152,8 +152,6 @@ class TreeVisitor extends TreeScanner private void indexArgument( VariableTree variableTree, SourcedAst ast, MethodEntry methodEntry, int index ) { - System.out.println( "\tFound argument: " + variableTree.getName() ); - // build the entry ArgumentEntry entry = new ArgumentEntry( methodEntry, index, variableTree.getName().toString() ); -- cgit v1.2.3 From 999c64037fb7251f87bd7b105231b3763e003c07 Mon Sep 17 00:00:00 2001 From: hg Date: Sun, 27 Jul 2014 00:52:28 -0400 Subject: made gui responsive to caret position and show identifier info --- src/cuchaz/enigma/Controller.java | 83 ++++++++ src/cuchaz/enigma/Deobfuscator.java | 5 + src/cuchaz/enigma/Main.java | 33 +--- src/cuchaz/enigma/analysis/SourceIndex.java | 30 ++- src/cuchaz/enigma/gui/ClassSelectionHandler.java | 18 -- src/cuchaz/enigma/gui/ClassSelectionListener.java | 18 ++ src/cuchaz/enigma/gui/Gui.java | 228 +++++++++++++++++++--- src/cuchaz/enigma/gui/RenameListener.java | 18 ++ src/cuchaz/enigma/mapping/ArgumentEntry.java | 3 +- src/cuchaz/enigma/mapping/ClassEntry.java | 3 +- src/cuchaz/enigma/mapping/Entry.java | 16 ++ src/cuchaz/enigma/mapping/FieldEntry.java | 3 +- src/cuchaz/enigma/mapping/MethodEntry.java | 3 +- 13 files changed, 379 insertions(+), 82 deletions(-) create mode 100644 src/cuchaz/enigma/Controller.java delete mode 100644 src/cuchaz/enigma/gui/ClassSelectionHandler.java create mode 100644 src/cuchaz/enigma/gui/ClassSelectionListener.java create mode 100644 src/cuchaz/enigma/gui/RenameListener.java create mode 100644 src/cuchaz/enigma/mapping/Entry.java (limited to 'src') diff --git a/src/cuchaz/enigma/Controller.java b/src/cuchaz/enigma/Controller.java new file mode 100644 index 00000000..debc5e38 --- /dev/null +++ b/src/cuchaz/enigma/Controller.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * 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.Entry; + +public class Controller implements ClassSelectionListener, CaretListener, RenameListener +{ + private Deobfuscator m_deobfuscator; + private Gui m_gui; + private SourceIndex m_index; + + public Controller( Deobfuscator deobfuscator, Gui gui ) + { + m_deobfuscator = deobfuscator; + m_gui = gui; + m_index = 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( 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(); + } + + @Override + public void caretUpdate( CaretEvent event ) + { + if( m_index != null ) + { + int pos = event.getDot(); + m_gui.showEntry( m_index.getEntry( pos ) ); + } + } + + @Override + public void rename( Entry entry, String newName ) + { + // TEMP + System.out.println( "Rename " + entry + " to " + newName ); + } +} diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 83a21719..97c57505 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -62,6 +62,11 @@ public class Deobfuscator m_settings.setShowSyntheticMembers( true ); } + public String getJarName( ) + { + return m_file.getName(); + } + public List getObfuscatedClasses( ) { List classes = new ArrayList(); diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index e08c16ed..4842e208 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -12,9 +12,6 @@ package cuchaz.enigma; import java.io.File; -import cuchaz.enigma.analysis.Analyzer; -import cuchaz.enigma.analysis.SourceIndex; -import cuchaz.enigma.gui.ClassSelectionHandler; import cuchaz.enigma.gui.Gui; public class Main @@ -28,36 +25,10 @@ public class Main private static void startGui( ) throws Exception { - final Gui gui = new Gui(); - // settings final File jarFile = new File( "/home/jeff/.minecraft/versions/1.7.10/1.7.10.jar" ); - gui.setTitle( jarFile.getName() ); - - // init the deobfuscator - final Deobfuscator deobfuscator = new Deobfuscator( jarFile ); - gui.setObfClasses( deobfuscator.getObfuscatedClasses() ); - // handle events - gui.setClassSelectionHandler( new ClassSelectionHandler( ) - { - @Override - public void classSelected( final ClassFile classFile ) - { - 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( ) - { - String source = deobfuscator.getSource( classFile ); - SourceIndex index = Analyzer.analyze( classFile.getName(), source ); - gui.setSource( source, index ); - } - }.start(); - } - } ); + // start the GUI and tie it to the deobfuscator + new Controller( new Deobfuscator( jarFile ), new Gui() ); } } diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index a4b5329b..ee92d1ed 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -19,10 +19,12 @@ import jsyntaxpane.Token; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; -public class SourceIndex implements Iterable> +import cuchaz.enigma.mapping.Entry; + +public class SourceIndex implements Iterable> { - private BiMap m_entryToToken; - private BiMap m_tokenToEntry; + private BiMap m_entryToToken; + private BiMap m_tokenToEntry; public SourceIndex( ) { @@ -30,12 +32,12 @@ public class SourceIndex implements Iterable> m_tokenToEntry = m_entryToToken.inverse(); } - public void add( Object entry, Token token ) + public void add( Entry entry, Token token ) { m_entryToToken.put( entry, token ); } - public Iterator> iterator( ) + public Iterator> iterator( ) { return m_entryToToken.entrySet().iterator(); } @@ -45,12 +47,26 @@ public class SourceIndex implements Iterable> return m_entryToToken.values(); } - public Object getEntry( Token token ) + public Entry getEntry( Token token ) { return m_tokenToEntry.get( token ); } - public Object getToken( Object entry ) + public Entry getEntry( int pos ) + { + // linear search is fast enough for now + for( Map.Entry entry : this ) + { + Token token = entry.getValue(); + if( pos >= token.start && pos <= token.end() ) + { + return entry.getKey(); + } + } + return null; + } + + public Token getToken( Entry entry ) { return m_entryToToken.get( entry ); } diff --git a/src/cuchaz/enigma/gui/ClassSelectionHandler.java b/src/cuchaz/enigma/gui/ClassSelectionHandler.java deleted file mode 100644 index a50cf6a3..00000000 --- a/src/cuchaz/enigma/gui/ClassSelectionHandler.java +++ /dev/null @@ -1,18 +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 cuchaz.enigma.ClassFile; - -public interface ClassSelectionHandler -{ - void classSelected( ClassFile classFile ); -} diff --git a/src/cuchaz/enigma/gui/ClassSelectionListener.java b/src/cuchaz/enigma/gui/ClassSelectionListener.java new file mode 100644 index 00000000..4a2aa8d0 --- /dev/null +++ b/src/cuchaz/enigma/gui/ClassSelectionListener.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * 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 cuchaz.enigma.ClassFile; + +public interface ClassSelectionListener +{ + void classSelected( ClassFile classFile ); +} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index e0d53d83..d1a3cb21 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -12,11 +12,20 @@ package cuchaz.enigma.gui; import java.awt.BorderLayout; import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.List; import java.util.Vector; +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.JButton; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JLabel; @@ -24,14 +33,21 @@ import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; +import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.WindowConstants; +import javax.swing.event.CaretListener; import javax.swing.text.BadLocationException; import jsyntaxpane.DefaultSyntaxKit; import jsyntaxpane.Token; import cuchaz.enigma.ClassFile; import cuchaz.enigma.analysis.SourceIndex; +import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; public class Gui { @@ -42,11 +58,18 @@ public class Gui private JList m_obfClasses; 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; - // handlers - private ClassSelectionHandler m_classSelectionHandler; + // listeners + private ClassSelectionListener m_classSelectionListener; + private RenameListener m_renameListener; private BoxHighlightPainter m_highlightPainter; + private Entry m_selectedEntry; public Gui( ) { @@ -66,12 +89,12 @@ public class Gui { if( event.getClickCount() == 2 ) { - if( m_classSelectionHandler != null ) + if( m_classSelectionListener != null ) { ClassFile selected = m_obfClasses.getSelectedValue(); if( selected != null ) { - m_classSelectionHandler.classSelected( selected ); + m_classSelectionListener.classSelected( selected ); } } } @@ -93,6 +116,34 @@ 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_renameListener != null && m_selectedEntry != null ) + { + m_renameListener.rename( m_selectedEntry, 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 ); + clearEntry(); + // init editor DefaultSyntaxKit.initKit(); m_editor = new JEditorPane(); @@ -102,17 +153,23 @@ public class Gui // layout controls JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); - JSplitPane splitMain = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, sourceScroller ); + JPanel rightPanel = new JPanel(); + rightPanel.setLayout( new BorderLayout() ); + rightPanel.add( m_actionPanel, BorderLayout.NORTH ); + rightPanel.add( sourceScroller, BorderLayout.CENTER ); + JSplitPane splitMain = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, rightPanel ); pane.add( splitMain, BorderLayout.CENTER ); // 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 ); - // init handlers - m_classSelectionHandler = null; + // init listeners + m_classSelectionListener = null; + m_renameListener = null; m_highlightPainter = new BoxHighlightPainter(); } @@ -135,29 +192,156 @@ public class Gui public void setSource( String source, SourceIndex index ) { m_editor.setText( source ); - + } + + public void highlightTokens( Iterable tokens ) + { // remove any old highlighters - m_editor.getHighlighter().removeAllHighlights();; + m_editor.getHighlighter().removeAllHighlights(); - if( index != null ) + if( tokens == null ) { - // color things based on the index - for( Token token : index.tokens() ) + return; + } + + // color things based on the index + for( Token token : tokens ) + { + try { - try - { - m_editor.getHighlighter().addHighlight( token.start, token.end(), m_highlightPainter ); - } - catch( BadLocationException ex ) - { - throw new Error( ex ); - } + m_editor.getHighlighter().addHighlight( token.start, token.end(), m_highlightPainter ); + } + catch( BadLocationException ex ) + { + throw new IllegalArgumentException( ex ); } } + + 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 clearEntry( ) + { + m_actionPanel.removeAll(); + JLabel label = new JLabel( "No identifier selected" ); + unboldLabel( label ); + label.setHorizontalAlignment( JLabel.CENTER ); + m_actionPanel.add( label ); + + redraw(); + } + + public void showEntry( Entry entry ) + { + if( entry == null ) + { + clearEntry(); + return; + } + + // layout the action panel + m_actionPanel.removeAll(); + m_actionPanel.add( m_renamePanel ); + m_nameField.setText( entry.getName() ); + + // layout the dynamic section + JPanel dynamicPanel = new JPanel(); + dynamicPanel.setLayout( new GridLayout( 3, 1, 0, 0 ) ); + m_actionPanel.add( dynamicPanel ); + if( entry instanceof ClassEntry ) + { + showEntry( (ClassEntry)entry, dynamicPanel ); + } + else if( entry instanceof FieldEntry ) + { + showEntry( (FieldEntry)entry, dynamicPanel ); + } + else if( entry instanceof MethodEntry ) + { + showEntry( (MethodEntry)entry, dynamicPanel ); + } + else if( entry instanceof ArgumentEntry ) + { + showEntry( (ArgumentEntry)entry, dynamicPanel ); + } + else + { + throw new Error( "Unknown entry type: " + entry.getClass().getName() ); + } + + redraw(); + } + + public void showEntry( ClassEntry entry, JPanel panel ) + { + m_typeLabel.setText( "Class: " ); + } + + public void showEntry( FieldEntry entry, JPanel panel ) + { + m_typeLabel.setText( "Field: " ); + addNameValue( panel, "Class", entry.getClassEntry().getName() ); + } + + public void showEntry( MethodEntry entry, JPanel panel ) + { + m_typeLabel.setText( "Method: " ); + addNameValue( panel, "Class", entry.getClassEntry().getName() ); + addNameValue( panel, "Signature", entry.getSignature() ); + } + + public void showEntry( ArgumentEntry entry, 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() ) ); + } + + private void addNameValue( JPanel container, String name, String value ) + { + JPanel panel = new JPanel(); + panel.setLayout( new FlowLayout( FlowLayout.LEFT, 6, 0 ) ); + container.add( panel ); + + JLabel label = new JLabel( name + ":", JLabel.RIGHT ); + label.setPreferredSize( new Dimension( 80, label.getPreferredSize().height ) ); + panel.add( label ); + + panel.add( unboldLabel( new JLabel( value, JLabel.LEFT ) ) ); + } + + private JLabel unboldLabel( JLabel label ) + { + Font font = label.getFont(); + label.setFont( font.deriveFont( font.getStyle() & ~Font.BOLD ) ); + return label; } - public void setClassSelectionHandler( ClassSelectionHandler val ) + private void redraw( ) { - m_classSelectionHandler = val; + m_frame.validate(); + m_frame.repaint(); } } diff --git a/src/cuchaz/enigma/gui/RenameListener.java b/src/cuchaz/enigma/gui/RenameListener.java new file mode 100644 index 00000000..58cdadb0 --- /dev/null +++ b/src/cuchaz/enigma/gui/RenameListener.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * 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 cuchaz.enigma.mapping.Entry; + +public interface RenameListener +{ + void rename( Entry entry, String newName ); +} diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java index 6c108d7c..dc3b4df7 100644 --- a/src/cuchaz/enigma/mapping/ArgumentEntry.java +++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java @@ -14,7 +14,7 @@ import java.io.Serializable; import cuchaz.enigma.Util; -public class ArgumentEntry implements Serializable +public class ArgumentEntry implements Entry, Serializable { private static final long serialVersionUID = 4472172468162696006L; @@ -52,6 +52,7 @@ public class ArgumentEntry implements Serializable return m_index; } + @Override public String getName( ) { return m_name; diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index 7e78d4c0..3a757675 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -13,7 +13,7 @@ package cuchaz.enigma.mapping; import java.io.Serializable; -public class ClassEntry implements Serializable +public class ClassEntry implements Entry, Serializable { private static final long serialVersionUID = 4235460580973955811L; @@ -33,6 +33,7 @@ public class ClassEntry implements Serializable m_name = className; } + @Override public String getName( ) { return m_name; diff --git a/src/cuchaz/enigma/mapping/Entry.java b/src/cuchaz/enigma/mapping/Entry.java new file mode 100644 index 00000000..14435324 --- /dev/null +++ b/src/cuchaz/enigma/mapping/Entry.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * 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 interface Entry +{ + String getName( ); +} diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java index 15a93520..25b665ab 100644 --- a/src/cuchaz/enigma/mapping/FieldEntry.java +++ b/src/cuchaz/enigma/mapping/FieldEntry.java @@ -14,7 +14,7 @@ import java.io.Serializable; import cuchaz.enigma.Util; -public class FieldEntry implements Serializable +public class FieldEntry implements Entry, Serializable { private static final long serialVersionUID = 3004663582802885451L; @@ -41,6 +41,7 @@ public class FieldEntry implements Serializable return m_classEntry; } + @Override public String getName( ) { return m_name; diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index e71a4664..4afc099b 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -14,7 +14,7 @@ import java.io.Serializable; import cuchaz.enigma.Util; -public class MethodEntry implements Serializable +public class MethodEntry implements Entry, Serializable { private static final long serialVersionUID = 4770915224467247458L; @@ -47,6 +47,7 @@ public class MethodEntry implements Serializable return m_classEntry; } + @Override public String getName( ) { return m_name; -- cgit v1.2.3 From d7321b5b0d38c575e54c770f7aa18dacbacab3c8 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 27 Jul 2014 22:33:21 -0400 Subject: added identifier renaming capability copied some code over from M3L to handle the heavy bytecode magic. It's ok... M3L will eventually depend on Enigma. Completely restructured the mappings though. This way is better. =) --- src/cuchaz/enigma/Constants.java | 18 + src/cuchaz/enigma/Controller.java | 67 +++- src/cuchaz/enigma/Deobfuscator.java | 115 ++++++- src/cuchaz/enigma/TranslatingTypeLoader.java | 93 ++++++ .../enigma/bytecode/BytecodeIndexIterator.java | 180 ++++++++++ src/cuchaz/enigma/bytecode/BytecodeTools.java | 269 +++++++++++++++ src/cuchaz/enigma/bytecode/ClassTranslator.java | 171 ++++++++++ src/cuchaz/enigma/bytecode/ConstPoolEditor.java | 316 ++++++++++++++++++ src/cuchaz/enigma/bytecode/InfoType.java | 364 +++++++++++++++++++++ .../bytecode/accessors/ClassInfoAccessor.java | 69 ++++ .../bytecode/accessors/ConstInfoAccessor.java | 199 +++++++++++ .../accessors/InvokeDynamicInfoAccessor.java | 96 ++++++ .../bytecode/accessors/MemberRefInfoAccessor.java | 96 ++++++ .../accessors/MethodHandleInfoAccessor.java | 96 ++++++ .../bytecode/accessors/MethodTypeInfoAccessor.java | 69 ++++ .../accessors/NameAndTypeInfoAccessor.java | 96 ++++++ .../bytecode/accessors/StringInfoAccessor.java | 69 ++++ .../bytecode/accessors/Utf8InfoAccessor.java | 33 ++ src/cuchaz/enigma/gui/Gui.java | 53 +-- src/cuchaz/enigma/gui/RenameListener.java | 2 +- src/cuchaz/enigma/mapping/Ancestries.java | 134 ++++++++ src/cuchaz/enigma/mapping/ArgumentEntry.java | 27 ++ src/cuchaz/enigma/mapping/ArgumentIndex.java | 41 +++ src/cuchaz/enigma/mapping/ClassEntry.java | 5 + src/cuchaz/enigma/mapping/ClassIndex.java | 159 +++++++++ .../enigma/mapping/DeobfuscatedAncestries.java | 57 ++++ src/cuchaz/enigma/mapping/EntryPair.java | 46 +++ src/cuchaz/enigma/mapping/FieldEntry.java | 17 + src/cuchaz/enigma/mapping/MethodEntry.java | 21 +- src/cuchaz/enigma/mapping/MethodIndex.java | 125 +++++++ src/cuchaz/enigma/mapping/SignatureUpdater.java | 87 +++++ .../enigma/mapping/TranslationDirection.java | 34 ++ src/cuchaz/enigma/mapping/TranslationMappings.java | 187 +++++++++++ src/cuchaz/enigma/mapping/Translator.java | 201 ++++++++++++ 34 files changed, 3566 insertions(+), 46 deletions(-) create mode 100644 src/cuchaz/enigma/Constants.java create mode 100644 src/cuchaz/enigma/TranslatingTypeLoader.java create mode 100644 src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java create mode 100644 src/cuchaz/enigma/bytecode/BytecodeTools.java create mode 100644 src/cuchaz/enigma/bytecode/ClassTranslator.java create mode 100644 src/cuchaz/enigma/bytecode/ConstPoolEditor.java create mode 100644 src/cuchaz/enigma/bytecode/InfoType.java create mode 100644 src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java create mode 100644 src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java create mode 100644 src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java create mode 100644 src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java create mode 100644 src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java create mode 100644 src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java create mode 100644 src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java create mode 100644 src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java create mode 100644 src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java create mode 100644 src/cuchaz/enigma/mapping/Ancestries.java create mode 100644 src/cuchaz/enigma/mapping/ArgumentIndex.java create mode 100644 src/cuchaz/enigma/mapping/ClassIndex.java create mode 100644 src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java create mode 100644 src/cuchaz/enigma/mapping/EntryPair.java create mode 100644 src/cuchaz/enigma/mapping/MethodIndex.java create mode 100644 src/cuchaz/enigma/mapping/SignatureUpdater.java create mode 100644 src/cuchaz/enigma/mapping/TranslationDirection.java create mode 100644 src/cuchaz/enigma/mapping/TranslationMappings.java create mode 100644 src/cuchaz/enigma/mapping/Translator.java (limited to 'src') diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java new file mode 100644 index 00000000..09787145 --- /dev/null +++ b/src/cuchaz/enigma/Constants.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * 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; + + +public class Constants +{ + public static final int MiB = 1024*1024; // 1 mebibyte + public static final int KiB = 1024; // 1 kebibyte +} diff --git a/src/cuchaz/enigma/Controller.java b/src/cuchaz/enigma/Controller.java index debc5e38..3af139e8 100644 --- a/src/cuchaz/enigma/Controller.java +++ b/src/cuchaz/enigma/Controller.java @@ -18,19 +18,23 @@ 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() ); @@ -43,7 +47,51 @@ public class Controller implements ClassSelectionListener, CaretListener, Rename } @Override - public void classSelected( final ClassFile classFile ) + 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...)" ); @@ -63,21 +111,4 @@ public class Controller implements ClassSelectionListener, CaretListener, Rename } }.start(); } - - @Override - public void caretUpdate( CaretEvent event ) - { - if( m_index != null ) - { - int pos = event.getDot(); - m_gui.showEntry( m_index.getEntry( pos ) ); - } - } - - @Override - public void rename( Entry entry, String newName ) - { - // TEMP - System.out.println( "Rename " + entry + " to " + newName ); - } } diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 97c57505..b1abd9e0 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -11,7 +11,9 @@ package cuchaz.enigma; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; @@ -21,16 +23,27 @@ import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import com.strobel.assembler.metadata.JarTypeLoader; import com.strobel.decompiler.Decompiler; import com.strobel.decompiler.DecompilerSettings; import com.strobel.decompiler.PlainTextOutput; +import cuchaz.enigma.mapping.Ancestries; +import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.TranslationDirection; +import cuchaz.enigma.mapping.TranslationMappings; +import cuchaz.enigma.mapping.Translator; + public class Deobfuscator { private File m_file; private JarFile m_jar; private DecompilerSettings m_settings; + private Ancestries m_ancestries; + private TranslationMappings m_mappings; private static Comparator m_obfuscatedClassSorter; @@ -56,8 +69,30 @@ public class Deobfuscator { m_file = file; m_jar = new JarFile( m_file ); + + // build the ancestries + InputStream jarIn = null; + try + { + m_ancestries = new Ancestries(); + jarIn = new FileInputStream( m_file ); + m_ancestries.readFromJar( jarIn ); + } + finally + { + Util.closeQuietly( jarIn ); + } + + // init mappings + m_mappings = new TranslationMappings( m_ancestries ); + + // config the decompiler m_settings = DecompilerSettings.javaDefaults(); - m_settings.setTypeLoader( new JarTypeLoader( m_jar ) ); + 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 ); } @@ -111,4 +146,80 @@ public class Deobfuscator Decompiler.decompile( classFile.getName(), new PlainTextOutput( buf ), m_settings ); return buf.toString(); } + + // NOTE: these methods are a bit messy... oh well + + public void rename( Entry entry, String newName ) + { + if( entry instanceof ClassEntry ) + { + m_mappings.setClassName( (ClassEntry)entry, newName ); + } + else if( entry instanceof FieldEntry ) + { + m_mappings.setFieldName( (FieldEntry)entry, newName ); + } + else if( entry instanceof MethodEntry ) + { + m_mappings.setMethodName( (MethodEntry)entry, newName ); + } + else if( entry instanceof ArgumentEntry ) + { + m_mappings.setArgumentName( (ArgumentEntry)entry, newName ); + } + else + { + throw new Error( "Unknown entry type: " + entry.getClass().getName() ); + } + } + + public Entry obfuscate( Entry in ) + { + Translator translator = m_mappings.getTranslator( TranslationDirection.Obfuscating ); + if( in instanceof ClassEntry ) + { + return translator.translateEntry( (ClassEntry)in ); + } + else if( in instanceof FieldEntry ) + { + return translator.translateEntry( (FieldEntry)in ); + } + else if( in instanceof MethodEntry ) + { + return translator.translateEntry( (MethodEntry)in ); + } + else if( in instanceof ArgumentEntry ) + { + return translator.translateEntry( (ArgumentEntry)in ); + } + else + { + throw new Error( "Unknown entry type: " + in.getClass().getName() ); + } + } + + public Entry deobfuscate( Entry in ) + { + Translator translator = m_mappings.getTranslator( TranslationDirection.Deobfuscating ); + if( in instanceof ClassEntry ) + { + return translator.translateEntry( (ClassEntry)in ); + } + else if( in instanceof FieldEntry ) + { + return translator.translateEntry( (FieldEntry)in ); + } + else if( in instanceof MethodEntry ) + { + return translator.translateEntry( (MethodEntry)in ); + } + else if( in instanceof ArgumentEntry ) + { + return translator.translateEntry( (ArgumentEntry)in ); + } + else + { + throw new Error( "Unknown entry type: " + in.getClass().getName() ); + } + } } diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java new file mode 100644 index 00000000..872f4861 --- /dev/null +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * 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 java.io.IOException; +import java.io.InputStream; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import javassist.ByteArrayClassPath; +import javassist.ClassPool; +import javassist.CtClass; + +import com.strobel.assembler.metadata.Buffer; +import com.strobel.assembler.metadata.ITypeLoader; + +import cuchaz.enigma.bytecode.ClassTranslator; +import cuchaz.enigma.mapping.Translator; + +public class TranslatingTypeLoader implements ITypeLoader +{ + private JarFile m_jar; + private ClassTranslator m_classTranslator; + private Translator m_obfuscatingTranslator; + + public TranslatingTypeLoader( JarFile jar, Translator deobfuscatingTranslator, Translator obfuscatingTranslator ) + { + m_jar = jar; + m_classTranslator = new ClassTranslator( deobfuscatingTranslator ); + m_obfuscatingTranslator = obfuscatingTranslator; + } + + @Override + public boolean tryLoadType( String name, Buffer out ) + { + // is this a deobufscated class name? + String obfName = m_obfuscatingTranslator.translateClass( name ); + if( obfName != null ) + { + // point to the obfuscated class + name = obfName; + } + + JarEntry entry = m_jar.getJarEntry( name + ".class" ); + if( entry == null ) + { + return false; + } + + try + { + // read the class file into a buffer + byte[] buf = new byte[(int)entry.getSize()]; + InputStream in = m_jar.getInputStream( entry ); + int bytesRead = in.read( buf ); + assert( bytesRead == buf.length ); + + // translate the class + ClassPool classPool = new ClassPool(); + classPool.insertClassPath( new ByteArrayClassPath( name, buf ) ); + try + { + CtClass c = classPool.get( name ); + m_classTranslator.translate( c ); + buf = c.toBytecode(); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + + // pass it along to the decompiler + out.reset( buf.length ); + System.arraycopy( buf, 0, out.array(), out.position(), buf.length ); + out.position( 0 ); + + return true; + } + catch( IOException ex ) + { + throw new Error( ex ); + } + } + +} diff --git a/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java new file mode 100644 index 00000000..aadbeb25 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java @@ -0,0 +1,180 @@ +/******************************************************************************* + * 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.util.Iterator; + +import javassist.bytecode.BadBytecode; +import javassist.bytecode.Bytecode; +import javassist.bytecode.CodeAttribute; +import javassist.bytecode.CodeIterator; +import javassist.bytecode.Opcode; + +public class BytecodeIndexIterator implements Iterator +{ + public static class Index + { + private CodeIterator m_iter; + private int m_pos; + private boolean m_isWide; + + protected Index( CodeIterator iter, int pos, boolean isWide ) + { + m_iter = iter; + m_pos = pos; + m_isWide = isWide; + } + + public int getIndex( ) + { + if( m_isWide ) + { + return m_iter.s16bitAt( m_pos ); + } + else + { + return m_iter.byteAt( m_pos ); + } + } + + public void setIndex( int val ) + throws BadBytecode + { + if( m_isWide ) + { + m_iter.write16bit( val, m_pos ); + } + else + { + if( val < 256 ) + { + // we can write the byte + m_iter.writeByte( val, m_pos ); + } + else + { + // we need to upgrade this instruction to LDC_W + assert( m_iter.byteAt( m_pos - 1 ) == Opcode.LDC ); + m_iter.insertGap( m_pos - 1, 1 ); + m_iter.writeByte( Opcode.LDC_W, m_pos - 1 ); + m_iter.write16bit( val, m_pos ); + m_isWide = true; + + // move the iterator to the next opcode + m_iter.move( m_pos + 2 ); + } + } + + // sanity check + assert( val == getIndex() ); + } + + public boolean isValid( Bytecode bytecode ) + { + return getIndex() >= 0 && getIndex() < bytecode.getConstPool().getSize(); + } + } + + private Bytecode m_bytecode; + private CodeAttribute m_attribute; + private CodeIterator m_iter; + private Index m_next; + + public BytecodeIndexIterator( Bytecode bytecode ) + throws BadBytecode + { + m_bytecode = bytecode; + m_attribute = bytecode.toCodeAttribute(); + m_iter = m_attribute.iterator(); + + m_next = getNext(); + } + + @Override + public boolean hasNext( ) + { + return m_next != null; + } + + @Override + public Index next( ) + { + Index out = m_next; + try + { + m_next = getNext(); + } + catch( BadBytecode ex ) + { + throw new Error( ex ); + } + return out; + } + + @Override + public void remove( ) + { + throw new UnsupportedOperationException(); + } + + private Index getNext( ) + throws BadBytecode + { + while( m_iter.hasNext() ) + { + int pos = m_iter.next(); + int opcode = m_iter.byteAt( pos ); + switch( opcode ) + { + // for only these opcodes, the next two bytes are a const pool reference + case Opcode.ANEWARRAY: + case Opcode.CHECKCAST: + case Opcode.INSTANCEOF: + case Opcode.INVOKEDYNAMIC: + case Opcode.INVOKEINTERFACE: + case Opcode.INVOKESPECIAL: + case Opcode.INVOKESTATIC: + case Opcode.INVOKEVIRTUAL: + case Opcode.LDC_W: + case Opcode.LDC2_W: + case Opcode.MULTIANEWARRAY: + case Opcode.NEW: + case Opcode.PUTFIELD: + case Opcode.PUTSTATIC: + case Opcode.GETFIELD: + case Opcode.GETSTATIC: + return new Index( m_iter, pos + 1, true ); + + case Opcode.LDC: + return new Index( m_iter, pos + 1, false ); + } + } + + return null; + } + + public Iterable indices( ) + { + return new Iterable( ) + { + @Override + public Iterator iterator( ) + { + return BytecodeIndexIterator.this; + } + }; + } + + public void saveChangesToBytecode( ) + { + BytecodeTools.setBytecode( m_bytecode, m_attribute.getCode() ); + } +} diff --git a/src/cuchaz/enigma/bytecode/BytecodeTools.java b/src/cuchaz/enigma/bytecode/BytecodeTools.java new file mode 100644 index 00000000..664350ea --- /dev/null +++ b/src/cuchaz/enigma/bytecode/BytecodeTools.java @@ -0,0 +1,269 @@ +/******************************************************************************* + * 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.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Map; +import java.util.Set; + +import javassist.CtBehavior; +import javassist.bytecode.BadBytecode; +import javassist.bytecode.Bytecode; +import javassist.bytecode.CodeAttribute; +import javassist.bytecode.ConstPool; +import javassist.bytecode.ExceptionTable; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import cuchaz.enigma.Util; +import cuchaz.enigma.bytecode.BytecodeIndexIterator.Index; +import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; + +public class BytecodeTools +{ + public static byte[] writeBytecode( Bytecode bytecode ) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream( buf ); + try + { + // write the constant pool + new ConstPoolEditor( bytecode.getConstPool() ).writePool( out ); + + // write metadata + out.writeShort( bytecode.getMaxStack() ); + out.writeShort( bytecode.getMaxLocals() ); + out.writeShort( bytecode.getStackDepth() ); + + // write the code + out.writeShort( bytecode.getSize() ); + out.write( bytecode.get() ); + + // write the exception table + int numEntries = bytecode.getExceptionTable().size(); + out.writeShort( numEntries ); + for( int i=0; i attribute.getMaxLocals() ) + { + attribute.setMaxLocals( bytecode.getMaxLocals() ); + } + if( bytecode.getMaxStack() > attribute.getMaxStack() ) + { + attribute.setMaxStack( bytecode.getMaxStack() ); + } + + return bytecode; + } + + public static Bytecode copyBytecodeToConstPool( ConstPool dest, Bytecode bytecode ) + throws BadBytecode + { + // get the entries this bytecode needs from the const pool + Set indices = Sets.newTreeSet(); + ConstPoolEditor editor = new ConstPoolEditor( bytecode.getConstPool() ); + BytecodeIndexIterator iterator = new BytecodeIndexIterator( bytecode ); + for( Index index : iterator.indices() ) + { + assert( index.isValid( bytecode ) ); + InfoType.gatherIndexTree( indices, editor, index.getIndex() ); + } + + Map indexMap = Maps.newTreeMap(); + + ConstPool src = bytecode.getConstPool(); + ConstPoolEditor editorSrc = new ConstPoolEditor( src ); + ConstPoolEditor editorDest = new ConstPoolEditor( dest ); + + // copy entries over in order of level so the index mapping is easier + for( InfoType type : InfoType.getSortedByLevel() ) + { + for( int index : indices ) + { + ConstInfoAccessor entry = editorSrc.getItem( index ); + + // skip entries that aren't this type + if( entry.getType() != type ) + { + continue; + } + + // make sure the source entry is valid before we copy it + assert( type.subIndicesAreValid( entry, editorSrc ) ); + assert( type.selfIndexIsValid( entry, editorSrc ) ); + + // make a copy of the entry so we can modify it safely + ConstInfoAccessor entryCopy = editorSrc.getItem( index ).copy(); + assert( type.subIndicesAreValid( entryCopy, editorSrc ) ); + assert( type.selfIndexIsValid( entryCopy, editorSrc ) ); + + // remap the indices + type.remapIndices( indexMap, entryCopy ); + assert( type.subIndicesAreValid( entryCopy, editorDest ) ); + + // put the copy in the destination pool + int newIndex = editorDest.addItem( entryCopy.getItem() ); + entryCopy.setIndex( newIndex ); + assert( type.selfIndexIsValid( entryCopy, editorDest ) ) : type + ", self: " + entryCopy + " dest: " + editorDest.getItem( entryCopy.getIndex() ); + + // make sure the source entry is unchanged + assert( type.subIndicesAreValid( entry, editorSrc ) ); + assert( type.selfIndexIsValid( entry, editorSrc ) ); + + // add the index mapping so we can update the bytecode later + if( indexMap.containsKey( index ) ) + { + throw new Error( "Entry at index " + index + " already copied!" ); + } + indexMap.put( index, newIndex ); + } + } + + // make a new bytecode + Bytecode newBytecode = new Bytecode( dest, bytecode.getMaxStack(), bytecode.getMaxLocals() ); + bytecode.setStackDepth( bytecode.getStackDepth() ); + setBytecode( newBytecode, bytecode.get() ); + setExceptionTable( newBytecode, bytecode.getExceptionTable() ); + + // apply the mappings to the bytecode + BytecodeIndexIterator iter = new BytecodeIndexIterator( newBytecode ); + for( Index index : iter.indices() ) + { + int oldIndex = index.getIndex(); + Integer newIndex = indexMap.get( oldIndex ); + if( newIndex != null ) + { + // make sure this mapping makes sense + InfoType typeSrc = editorSrc.getItem( oldIndex ).getType(); + InfoType typeDest = editorDest.getItem( newIndex ).getType(); + assert( typeSrc == typeDest ); + + // apply the mapping + index.setIndex( newIndex ); + } + } + iter.saveChangesToBytecode(); + + // make sure all the indices are valid + iter = new BytecodeIndexIterator( newBytecode ); + for( Index index : iter.indices() ) + { + assert( index.isValid( newBytecode ) ); + } + + return newBytecode; + } + + public static void setBytecode( Bytecode dest, byte[] src ) + { + if( src.length > dest.getSize() ) + { + dest.addGap( src.length - dest.getSize() ); + } + assert( dest.getSize() == src.length ); + for( int i=0; i=0; i-- ) + { + dest.getExceptionTable().remove( i ); + } + + // copy the exception table + for( int i=0; i classNames = getAllClassNames( c ); + ClassMap map = new ClassMap(); + for( String className : classNames ) + { + String translatedName = m_translator.translateClass( className ); + if( translatedName != null ) + { + map.put( className, translatedName ); + } + } + if( !map.isEmpty() ) + { + c.replaceClassName( map ); + } + } + + private Set getAllClassNames( CtClass c ) + { + final Set names = new HashSet(); + ClassMap map = new ClassMap( ) + { + @Override + public Object get( Object obj ) + { + if( obj instanceof String ) + { + names.add( (String)obj ); + } + return null; + } + private static final long serialVersionUID = -202160293602070641L; + }; + c.replaceClassName( map ); + return names; + } +} diff --git a/src/cuchaz/enigma/bytecode/ConstPoolEditor.java b/src/cuchaz/enigma/bytecode/ConstPoolEditor.java new file mode 100644 index 00000000..aa6149c9 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/ConstPoolEditor.java @@ -0,0 +1,316 @@ +/******************************************************************************* + * 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.DataInputStream; +import java.io.DataOutputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; + +import javassist.bytecode.ConstPool; +import javassist.bytecode.Descriptor; +import cuchaz.enigma.bytecode.accessors.ClassInfoAccessor; +import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; +import cuchaz.enigma.bytecode.accessors.MemberRefInfoAccessor; + +public class ConstPoolEditor +{ + private static Method m_getItem; + private static Method m_addItem; + private static Method m_addItem0; + private static Field m_items; + private static Field m_cache; + private static Field m_numItems; + private static Field m_objects; + private static Field m_elements; + private static Method m_methodWritePool; + private static Constructor m_constructorPool; + + static + { + try + { + m_getItem = ConstPool.class.getDeclaredMethod( "getItem", int.class ); + m_getItem.setAccessible( true ); + + m_addItem = ConstPool.class.getDeclaredMethod( "addItem", Class.forName( "javassist.bytecode.ConstInfo" ) ); + m_addItem.setAccessible( true ); + + m_addItem0 = ConstPool.class.getDeclaredMethod( "addItem0", Class.forName( "javassist.bytecode.ConstInfo" ) ); + m_addItem0.setAccessible( true ); + + m_items = ConstPool.class.getDeclaredField( "items" ); + m_items.setAccessible( true ); + + m_cache = ConstPool.class.getDeclaredField( "itemsCache" ); + m_cache.setAccessible( true ); + + m_numItems = ConstPool.class.getDeclaredField( "numOfItems" ); + m_numItems.setAccessible( true ); + + m_objects = Class.forName( "javassist.bytecode.LongVector" ).getDeclaredField( "objects" ); + m_objects.setAccessible( true ); + + m_elements = Class.forName( "javassist.bytecode.LongVector" ).getDeclaredField( "elements" ); + m_elements.setAccessible( true ); + + m_methodWritePool = ConstPool.class.getDeclaredMethod( "write", DataOutputStream.class ); + m_methodWritePool.setAccessible( true ); + + m_constructorPool = ConstPool.class.getDeclaredConstructor( DataInputStream.class ); + m_constructorPool.setAccessible( true ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + private ConstPool m_pool; + + public ConstPoolEditor( ConstPool pool ) + { + m_pool = pool; + } + + public void writePool( DataOutputStream out ) + { + try + { + m_methodWritePool.invoke( m_pool, out ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public static ConstPool readPool( DataInputStream in ) + { + try + { + return m_constructorPool.newInstance( in ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public String getMemberrefClassname( int memberrefIndex ) + { + return Descriptor.toJvmName( m_pool.getClassInfo( m_pool.getMemberClass( memberrefIndex ) ) ); + } + + public String getMemberrefName( int memberrefIndex ) + { + return m_pool.getUtf8Info( m_pool.getNameAndTypeName( m_pool.getMemberNameAndType( memberrefIndex ) ) ); + } + + public String getMemberrefType( int memberrefIndex ) + { + return m_pool.getUtf8Info( m_pool.getNameAndTypeDescriptor( m_pool.getMemberNameAndType( memberrefIndex ) ) ); + } + + public ConstInfoAccessor getItem( int index ) + { + try + { + Object entry = m_getItem.invoke( m_pool, index ); + if( entry == null ) + { + return null; + } + return new ConstInfoAccessor( entry ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public int addItem( Object item ) + { + try + { + return (Integer)m_addItem.invoke( m_pool, item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public int addItemForceNew( Object item ) + { + try + { + return (Integer)m_addItem0.invoke( m_pool, item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + @SuppressWarnings( "rawtypes" ) + public void removeLastItem( ) + { + try + { + // remove the item from the cache + HashMap cache = getCache(); + if( cache != null ) + { + Object item = getItem( m_pool.getSize() - 1 ); + cache.remove( item ); + } + + // remove the actual item + // based off of LongVector.addElement() + Object items = m_items.get( m_pool ); + Object[][] objects = (Object[][])m_objects.get( items ); + int numElements = (Integer)m_elements.get( items ) - 1; + int nth = numElements >> 7; + int offset = numElements & (128 - 1); + objects[nth][offset] = null; + + // decrement the number of items + m_elements.set( items, numElements ); + m_numItems.set( m_pool, (Integer)m_numItems.get( m_pool ) - 1 ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + @SuppressWarnings( "rawtypes" ) + /* TEMP */public HashMap getCache( ) + { + try + { + return (HashMap)m_cache.get( m_pool ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + @SuppressWarnings( { "rawtypes", "unchecked" } ) + public void changeMemberrefNameAndType( int memberrefIndex, String newName, String newType ) + { + // NOTE: when changing values, we always need to copy-on-write + try + { + // get the memberref item + Object item = getItem( memberrefIndex ).getItem(); + + // update the cache + HashMap cache = getCache(); + if( cache != null ) + { + cache.remove( item ); + } + + new MemberRefInfoAccessor( item ).setNameAndTypeIndex( m_pool.addNameAndTypeInfo( newName, newType ) ); + + // update the cache + if( cache != null ) + { + cache.put( item, item ); + } + } + catch( Exception ex ) + { + throw new Error( ex ); + } + + // make sure the change worked + assert( newName.equals( getMemberrefName( memberrefIndex ) ) ); + assert( newType.equals( getMemberrefType( memberrefIndex ) ) ); + } + + @SuppressWarnings( { "rawtypes", "unchecked" } ) + public void changeClassName( int classNameIndex, String newName ) + { + // NOTE: when changing values, we always need to copy-on-write + try + { + // get the class item + Object item = getItem( classNameIndex ).getItem(); + + // update the cache + HashMap cache = getCache(); + if( cache != null ) + { + cache.remove( item ); + } + + // add the new name and repoint the name-and-type to it + new ClassInfoAccessor( item ).setNameIndex( m_pool.addUtf8Info( newName ) ); + + // update the cache + if( cache != null ) + { + cache.put( item, item ); + } + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public static ConstPool newConstPool( ) + { + // const pool expects the name of a class to initialize itself + // but we want an empty pool + // so give it a bogus name, and then clear the entries afterwards + ConstPool pool = new ConstPool( "a" ); + + ConstPoolEditor editor = new ConstPoolEditor( pool ); + int size = pool.getSize(); + for( int i=0; i indices, ConstPoolEditor editor, ConstInfoAccessor entry ) + { + ClassInfoAccessor accessor = new ClassInfoAccessor( entry.getItem() ); + gatherIndexTree( indices, editor, accessor.getNameIndex() ); + } + + @Override + public void remapIndices( Map map, ConstInfoAccessor entry ) + { + ClassInfoAccessor accessor = new ClassInfoAccessor( entry.getItem() ); + accessor.setNameIndex( remapIndex( map, accessor.getNameIndex() ) ); + } + + @Override + public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) + { + ClassInfoAccessor accessor = new ClassInfoAccessor( entry.getItem() ); + ConstInfoAccessor nameEntry = pool.getItem( accessor.getNameIndex() ); + return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag(); + } + }, + StringInfo( 8, 1 ) + { + @Override + public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) + { + StringInfoAccessor accessor = new StringInfoAccessor( entry.getItem() ); + gatherIndexTree( indices, editor, accessor.getStringIndex() ); + } + + @Override + public void remapIndices( Map map, ConstInfoAccessor entry ) + { + StringInfoAccessor accessor = new StringInfoAccessor( entry.getItem() ); + accessor.setStringIndex( remapIndex( map, accessor.getStringIndex() ) ); + } + + @Override + public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) + { + StringInfoAccessor accessor = new StringInfoAccessor( entry.getItem() ); + ConstInfoAccessor stringEntry = pool.getItem( accessor.getStringIndex() ); + return stringEntry != null && stringEntry.getTag() == Utf8Info.getTag(); + } + }, + FieldRefInfo( 9, 2 ) + { + @Override + public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) + { + MemberRefInfoAccessor accessor = new MemberRefInfoAccessor( entry.getItem() ); + gatherIndexTree( indices, editor, accessor.getClassIndex() ); + gatherIndexTree( indices, editor, accessor.getNameAndTypeIndex() ); + } + + @Override + public void remapIndices( Map map, ConstInfoAccessor entry ) + { + MemberRefInfoAccessor accessor = new MemberRefInfoAccessor( entry.getItem() ); + accessor.setClassIndex( remapIndex( map, accessor.getClassIndex() ) ); + accessor.setNameAndTypeIndex( remapIndex( map, accessor.getNameAndTypeIndex() ) ); + } + + @Override + public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) + { + MemberRefInfoAccessor accessor = new MemberRefInfoAccessor( entry.getItem() ); + ConstInfoAccessor classEntry = pool.getItem( accessor.getClassIndex() ); + ConstInfoAccessor nameAndTypeEntry = pool.getItem( accessor.getNameAndTypeIndex() ); + return classEntry != null && classEntry.getTag() == ClassInfo.getTag() + && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag(); + } + }, + MethodRefInfo( 10, 2 ) // same as FieldRefInfo + { + @Override + public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) + { + FieldRefInfo.gatherIndexTree( indices, editor, entry ); + } + + @Override + public void remapIndices( Map map, ConstInfoAccessor entry ) + { + FieldRefInfo.remapIndices( map, entry ); + } + + @Override + public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) + { + return FieldRefInfo.subIndicesAreValid( entry, pool ); + } + }, + InterfaceMethodRefInfo( 11, 2 ) // same as FieldRefInfo + { + @Override + public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) + { + FieldRefInfo.gatherIndexTree( indices, editor, entry ); + } + + @Override + public void remapIndices( Map map, ConstInfoAccessor entry ) + { + FieldRefInfo.remapIndices( map, entry ); + } + + @Override + public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) + { + return FieldRefInfo.subIndicesAreValid( entry, pool ); + } + }, + NameAndTypeInfo( 12, 1 ) + { + @Override + public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) + { + NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor( entry.getItem() ); + gatherIndexTree( indices, editor, accessor.getNameIndex() ); + gatherIndexTree( indices, editor, accessor.getTypeIndex() ); + } + + @Override + public void remapIndices( Map map, ConstInfoAccessor entry ) + { + NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor( entry.getItem() ); + accessor.setNameIndex( remapIndex( map, accessor.getNameIndex() ) ); + accessor.setTypeIndex( remapIndex( map, accessor.getTypeIndex() ) ); + } + + @Override + public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) + { + NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor( entry.getItem() ); + ConstInfoAccessor nameEntry = pool.getItem( accessor.getNameIndex() ); + ConstInfoAccessor typeEntry = pool.getItem( accessor.getTypeIndex() ); + return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag() + && typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); + } + }, + MethodHandleInfo( 15, 3 ) + { + @Override + public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) + { + MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor( entry.getItem() ); + gatherIndexTree( indices, editor, accessor.getTypeIndex() ); + gatherIndexTree( indices, editor, accessor.getMethodRefIndex() ); + } + + @Override + public void remapIndices( Map map, ConstInfoAccessor entry ) + { + MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor( entry.getItem() ); + accessor.setTypeIndex( remapIndex( map, accessor.getTypeIndex() ) ); + accessor.setMethodRefIndex( remapIndex( map, accessor.getMethodRefIndex() ) ); + } + + @Override + public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) + { + MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor( entry.getItem() ); + ConstInfoAccessor typeEntry = pool.getItem( accessor.getTypeIndex() ); + ConstInfoAccessor methodRefEntry = pool.getItem( accessor.getMethodRefIndex() ); + return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag() + && methodRefEntry != null && methodRefEntry.getTag() == MethodRefInfo.getTag(); + } + }, + MethodTypeInfo( 16, 1 ) + { + @Override + public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) + { + MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor( entry.getItem() ); + gatherIndexTree( indices, editor, accessor.getTypeIndex() ); + } + + @Override + public void remapIndices( Map map, ConstInfoAccessor entry ) + { + MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor( entry.getItem() ); + accessor.setTypeIndex( remapIndex( map, accessor.getTypeIndex() ) ); + } + + @Override + public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) + { + MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor( entry.getItem() ); + ConstInfoAccessor typeEntry = pool.getItem( accessor.getTypeIndex() ); + return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); + } + }, + InvokeDynamicInfo( 18, 2 ) + { + @Override + public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) + { + InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor( entry.getItem() ); + gatherIndexTree( indices, editor, accessor.getBootstrapIndex() ); + gatherIndexTree( indices, editor, accessor.getNameAndTypeIndex() ); + } + + @Override + public void remapIndices( Map map, ConstInfoAccessor entry ) + { + InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor( entry.getItem() ); + accessor.setBootstrapIndex( remapIndex( map, accessor.getBootstrapIndex() ) ); + accessor.setNameAndTypeIndex( remapIndex( map, accessor.getNameAndTypeIndex() ) ); + } + + @Override + public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) + { + InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor( entry.getItem() ); + ConstInfoAccessor bootstrapEntry = pool.getItem( accessor.getBootstrapIndex() ); + ConstInfoAccessor nameAndTypeEntry = pool.getItem( accessor.getNameAndTypeIndex() ); + return bootstrapEntry != null && bootstrapEntry.getTag() == Utf8Info.getTag() + && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag(); + } + }; + + private static Map m_types; + + static + { + m_types = Maps.newTreeMap(); + for( InfoType type : values() ) + { + m_types.put( type.getTag(), type ); + } + } + + private int m_tag; + private int m_level; + + private InfoType( int tag, int level ) + { + m_tag = tag; + m_level = level; + } + + public int getTag( ) + { + return m_tag; + } + + public int getLevel( ) + { + return m_level; + } + + public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) + { + // by default, do nothing + } + + public void remapIndices( Map map, ConstInfoAccessor entry ) + { + // by default, do nothing + } + + public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) + { + // by default, everything is good + return true; + } + + public boolean selfIndexIsValid( ConstInfoAccessor entry, ConstPoolEditor pool ) + { + ConstInfoAccessor entryCheck = pool.getItem( entry.getIndex() ); + if( entryCheck == null ) + { + return false; + } + return entryCheck.getItem().equals( entry.getItem() ); + } + + public static InfoType getByTag( int tag ) + { + return m_types.get( tag ); + } + + public static List getByLevel( int level ) + { + List types = Lists.newArrayList(); + for( InfoType type : values() ) + { + if( type.getLevel() == level ) + { + types.add( type ); + } + } + return types; + } + + public static List getSortedByLevel( ) + { + List types = Lists.newArrayList(); + types.addAll( getByLevel( 0 ) ); + types.addAll( getByLevel( 1 ) ); + types.addAll( getByLevel( 2 ) ); + types.addAll( getByLevel( 3 ) ); + return types; + } + + public static void gatherIndexTree( Collection indices, ConstPoolEditor editor, int index ) + { + // add own index + indices.add( index ); + + // recurse + ConstInfoAccessor entry = editor.getItem( index ); + entry.getType().gatherIndexTree( indices, editor, entry ); + } + + private static int remapIndex( Map map, int index ) + { + Integer newIndex = map.get( index ); + if( newIndex == null ) + { + newIndex = index; + } + return newIndex; + } +} diff --git a/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java new file mode 100644 index 00000000..41e1d047 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * 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.accessors; + +import java.lang.reflect.Field; + +public class ClassInfoAccessor +{ + private static Class m_class; + private static Field m_nameIndex; + + static + { + try + { + m_class = Class.forName( "javassist.bytecode.ClassInfo" ); + m_nameIndex = m_class.getDeclaredField( "name" ); + m_nameIndex.setAccessible( true ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public static boolean isType( ConstInfoAccessor accessor ) + { + return m_class.isAssignableFrom( accessor.getItem().getClass() ); + } + + private Object m_item; + + public ClassInfoAccessor( Object item ) + { + m_item = item; + } + + public int getNameIndex( ) + { + try + { + return (Integer)m_nameIndex.get( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void setNameIndex( int val ) + { + try + { + m_nameIndex.set( m_item, val ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } +} diff --git a/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java new file mode 100644 index 00000000..3c3d3fa4 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java @@ -0,0 +1,199 @@ +/******************************************************************************* + * 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.accessors; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import cuchaz.enigma.bytecode.InfoType; + +public class ConstInfoAccessor +{ + private static Class m_class; + private static Field m_index; + private static Method m_getTag; + + static + { + try + { + m_class = Class.forName( "javassist.bytecode.ConstInfo" ); + m_index = m_class.getDeclaredField( "index" ); + m_index.setAccessible( true ); + m_getTag = m_class.getMethod( "getTag" ); + m_getTag.setAccessible( true ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + private Object m_item; + + public ConstInfoAccessor( Object item ) + { + if( item == null ) + { + throw new IllegalArgumentException( "item cannot be null!" ); + } + m_item = item; + } + + public ConstInfoAccessor( DataInputStream in ) + throws IOException + { + try + { + // read the entry + String className = in.readUTF(); + int oldIndex = in.readInt(); + + // NOTE: ConstInfo instances write a type id (a "tag"), but they don't read it back + // so we have to read it here + in.readByte(); + + Constructor constructor = Class.forName( className ).getConstructor( DataInputStream.class, int.class ); + constructor.setAccessible( true ); + m_item = constructor.newInstance( in, oldIndex ); + } + catch( IOException ex ) + { + throw ex; + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public Object getItem( ) + { + return m_item; + } + + public int getIndex( ) + { + try + { + return (Integer)m_index.get( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void setIndex( int val ) + { + try + { + m_index.set( m_item, val ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public int getTag( ) + { + try + { + return (Integer)m_getTag.invoke( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public ConstInfoAccessor copy( ) + { + return new ConstInfoAccessor( copyItem() ); + } + + public Object copyItem( ) + { + // I don't know of a simpler way to copy one of these silly things... + try + { + // serialize the item + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream( buf ); + write( out ); + + // deserialize the item + DataInputStream in = new DataInputStream( new ByteArrayInputStream( buf.toByteArray() ) ); + Object item = new ConstInfoAccessor( in ).getItem(); + in.close(); + + return item; + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void write( DataOutputStream out ) + throws IOException + { + try + { + out.writeUTF( m_item.getClass().getName() ); + out.writeInt( getIndex() ); + + Method method = m_item.getClass().getMethod( "write", DataOutputStream.class ); + method.setAccessible( true ); + method.invoke( m_item, out ); + } + catch( IOException ex ) + { + throw ex; + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + @Override + public String toString( ) + { + try + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + PrintWriter out = new PrintWriter( buf ); + Method print = m_item.getClass().getMethod( "print", PrintWriter.class ); + print.setAccessible( true ); + print.invoke( m_item, out ); + out.close(); + return buf.toString().replace( "\n", "" ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public InfoType getType( ) + { + return InfoType.getByTag( getTag() ); + } +} diff --git a/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java new file mode 100644 index 00000000..169306a4 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * 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.accessors; + +import java.lang.reflect.Field; + +public class InvokeDynamicInfoAccessor +{ + private static Class m_class; + private static Field m_bootstrapIndex; + private static Field m_nameAndTypeIndex; + + static + { + try + { + m_class = Class.forName( "javassist.bytecode.InvokeDynamicInfo" ); + m_bootstrapIndex = m_class.getDeclaredField( "bootstrap" ); + m_bootstrapIndex.setAccessible( true ); + m_nameAndTypeIndex = m_class.getDeclaredField( "nameAndType" ); + m_nameAndTypeIndex.setAccessible( true ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public static boolean isType( ConstInfoAccessor accessor ) + { + return m_class.isAssignableFrom( accessor.getItem().getClass() ); + } + + private Object m_item; + + public InvokeDynamicInfoAccessor( Object item ) + { + m_item = item; + } + + public int getBootstrapIndex( ) + { + try + { + return (Integer)m_bootstrapIndex.get( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void setBootstrapIndex( int val ) + { + try + { + m_bootstrapIndex.set( m_item, val ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public int getNameAndTypeIndex( ) + { + try + { + return (Integer)m_nameAndTypeIndex.get( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void setNameAndTypeIndex( int val ) + { + try + { + m_nameAndTypeIndex.set( m_item, val ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } +} diff --git a/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java new file mode 100644 index 00000000..2ee3aff8 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * 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.accessors; + +import java.lang.reflect.Field; + +public class MemberRefInfoAccessor +{ + private static Class m_class; + private static Field m_classIndex; + private static Field m_nameAndTypeIndex; + + static + { + try + { + m_class = Class.forName( "javassist.bytecode.MemberrefInfo" ); + m_classIndex = m_class.getDeclaredField( "classIndex" ); + m_classIndex.setAccessible( true ); + m_nameAndTypeIndex = m_class.getDeclaredField( "nameAndTypeIndex" ); + m_nameAndTypeIndex.setAccessible( true ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public static boolean isType( ConstInfoAccessor accessor ) + { + return m_class.isAssignableFrom( accessor.getItem().getClass() ); + } + + private Object m_item; + + public MemberRefInfoAccessor( Object item ) + { + m_item = item; + } + + public int getClassIndex( ) + { + try + { + return (Integer)m_classIndex.get( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void setClassIndex( int val ) + { + try + { + m_classIndex.set( m_item, val ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public int getNameAndTypeIndex( ) + { + try + { + return (Integer)m_nameAndTypeIndex.get( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void setNameAndTypeIndex( int val ) + { + try + { + m_nameAndTypeIndex.set( m_item, val ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } +} diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java new file mode 100644 index 00000000..27b7aee8 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * 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.accessors; + +import java.lang.reflect.Field; + +public class MethodHandleInfoAccessor +{ + private static Class m_class; + private static Field m_kindIndex; + private static Field m_indexIndex; + + static + { + try + { + m_class = Class.forName( "javassist.bytecode.MethodHandleInfo" ); + m_kindIndex = m_class.getDeclaredField( "refKind" ); + m_kindIndex.setAccessible( true ); + m_indexIndex = m_class.getDeclaredField( "refIndex" ); + m_indexIndex.setAccessible( true ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public static boolean isType( ConstInfoAccessor accessor ) + { + return m_class.isAssignableFrom( accessor.getItem().getClass() ); + } + + private Object m_item; + + public MethodHandleInfoAccessor( Object item ) + { + m_item = item; + } + + public int getTypeIndex( ) + { + try + { + return (Integer)m_kindIndex.get( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void setTypeIndex( int val ) + { + try + { + m_kindIndex.set( m_item, val ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public int getMethodRefIndex( ) + { + try + { + return (Integer)m_indexIndex.get( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void setMethodRefIndex( int val ) + { + try + { + m_indexIndex.set( m_item, val ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } +} diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java new file mode 100644 index 00000000..4cba6a2a --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * 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.accessors; + +import java.lang.reflect.Field; + +public class MethodTypeInfoAccessor +{ + private static Class m_class; + private static Field m_descriptorIndex; + + static + { + try + { + m_class = Class.forName( "javassist.bytecode.MethodTypeInfo" ); + m_descriptorIndex = m_class.getDeclaredField( "descriptor" ); + m_descriptorIndex.setAccessible( true ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public static boolean isType( ConstInfoAccessor accessor ) + { + return m_class.isAssignableFrom( accessor.getItem().getClass() ); + } + + private Object m_item; + + public MethodTypeInfoAccessor( Object item ) + { + m_item = item; + } + + public int getTypeIndex( ) + { + try + { + return (Integer)m_descriptorIndex.get( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void setTypeIndex( int val ) + { + try + { + m_descriptorIndex.set( m_item, val ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } +} diff --git a/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java new file mode 100644 index 00000000..03b4de3c --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * 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.accessors; + +import java.lang.reflect.Field; + +public class NameAndTypeInfoAccessor +{ + private static Class m_class; + private static Field m_nameIndex; + private static Field m_typeIndex; + + static + { + try + { + m_class = Class.forName( "javassist.bytecode.NameAndTypeInfo" ); + m_nameIndex = m_class.getDeclaredField( "memberName" ); + m_nameIndex.setAccessible( true ); + m_typeIndex = m_class.getDeclaredField( "typeDescriptor" ); + m_typeIndex.setAccessible( true ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public static boolean isType( ConstInfoAccessor accessor ) + { + return m_class.isAssignableFrom( accessor.getItem().getClass() ); + } + + private Object m_item; + + public NameAndTypeInfoAccessor( Object item ) + { + m_item = item; + } + + public int getNameIndex( ) + { + try + { + return (Integer)m_nameIndex.get( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void setNameIndex( int val ) + { + try + { + m_nameIndex.set( m_item, val ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public int getTypeIndex( ) + { + try + { + return (Integer)m_typeIndex.get( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void setTypeIndex( int val ) + { + try + { + m_typeIndex.set( m_item, val ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } +} diff --git a/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java new file mode 100644 index 00000000..5cdfce4d --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * 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.accessors; + +import java.lang.reflect.Field; + +public class StringInfoAccessor +{ + private static Class m_class; + private static Field m_stringIndex; + + static + { + try + { + m_class = Class.forName( "javassist.bytecode.StringInfo" ); + m_stringIndex = m_class.getDeclaredField( "string" ); + m_stringIndex.setAccessible( true ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public static boolean isType( ConstInfoAccessor accessor ) + { + return m_class.isAssignableFrom( accessor.getItem().getClass() ); + } + + private Object m_item; + + public StringInfoAccessor( Object item ) + { + m_item = item; + } + + public int getStringIndex( ) + { + try + { + return (Integer)m_stringIndex.get( m_item ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public void setStringIndex( int val ) + { + try + { + m_stringIndex.set( m_item, val ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } +} diff --git a/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java new file mode 100644 index 00000000..1cadd836 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * 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.accessors; + +public class Utf8InfoAccessor +{ + private static Class m_class; + + static + { + try + { + m_class = Class.forName( "javassist.bytecode.Utf8Info" ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + + public static boolean isType( ConstInfoAccessor accessor ) + { + return m_class.isAssignableFrom( accessor.getItem().getClass() ); + } +} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index d1a3cb21..2a539a3f 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -45,7 +45,7 @@ import cuchaz.enigma.ClassFile; 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; @@ -69,7 +69,7 @@ public class Gui private RenameListener m_renameListener; private BoxHighlightPainter m_highlightPainter; - private Entry m_selectedEntry; + private EntryPair m_selectedEntryPair; public Gui( ) { @@ -128,9 +128,9 @@ public class Gui @Override public void actionPerformed( ActionEvent event ) { - if( m_renameListener != null && m_selectedEntry != null ) + if( m_renameListener != null && m_selectedEntryPair != null ) { - m_renameListener.rename( m_selectedEntry, m_nameField.getText() ); + m_renameListener.rename( m_selectedEntryPair.obf, m_nameField.getText() ); } } } ); @@ -142,7 +142,7 @@ public class Gui m_renamePanel.add( m_typeLabel ); m_renamePanel.add( m_nameField ); m_renamePanel.add( m_renameButton ); - clearEntry(); + clearEntryPair(); // init editor DefaultSyntaxKit.initKit(); @@ -241,7 +241,7 @@ public class Gui m_editor.addCaretListener( listener ); } - public void clearEntry( ) + public void clearEntryPair( ) { m_actionPanel.removeAll(); JLabel label = new JLabel( "No identifier selected" ); @@ -251,67 +251,72 @@ public class Gui redraw(); } - - public void showEntry( Entry entry ) + + public void showEntryPair( EntryPair pair ) { - if( entry == null ) + if( pair == null ) { - clearEntry(); + clearEntryPair(); return; } + // TEMP + System.out.println( "Pair:\n" + pair.obf + "\n" + pair.deobf ); + + m_selectedEntryPair = pair; + // layout the action panel m_actionPanel.removeAll(); m_actionPanel.add( m_renamePanel ); - m_nameField.setText( entry.getName() ); + 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 ); - if( entry instanceof ClassEntry ) + if( pair.deobf instanceof ClassEntry ) { - showEntry( (ClassEntry)entry, dynamicPanel ); + showEntry( (ClassEntry)pair.deobf, dynamicPanel ); } - else if( entry instanceof FieldEntry ) + else if( pair.deobf instanceof FieldEntry ) { - showEntry( (FieldEntry)entry, dynamicPanel ); + showEntry( (FieldEntry)pair.deobf, dynamicPanel ); } - else if( entry instanceof MethodEntry ) + else if( pair.deobf instanceof MethodEntry ) { - showEntry( (MethodEntry)entry, dynamicPanel ); + showEntry( (MethodEntry)pair.deobf, dynamicPanel ); } - else if( entry instanceof ArgumentEntry ) + else if( pair.deobf instanceof ArgumentEntry ) { - showEntry( (ArgumentEntry)entry, dynamicPanel ); + showEntry( (ArgumentEntry)pair.deobf, dynamicPanel ); } else { - throw new Error( "Unknown entry type: " + entry.getClass().getName() ); + throw new Error( "Unknown entry type: " + pair.deobf.getClass().getName() ); } redraw(); } - public void showEntry( ClassEntry entry, JPanel panel ) + private void showEntry( ClassEntry entry, JPanel panel ) { m_typeLabel.setText( "Class: " ); } - public void showEntry( FieldEntry entry, JPanel panel ) + private void showEntry( FieldEntry entry, JPanel panel ) { m_typeLabel.setText( "Field: " ); addNameValue( panel, "Class", entry.getClassEntry().getName() ); } - public void showEntry( MethodEntry entry, JPanel panel ) + private void showEntry( MethodEntry entry, JPanel panel ) { m_typeLabel.setText( "Method: " ); addNameValue( panel, "Class", entry.getClassEntry().getName() ); addNameValue( panel, "Signature", entry.getSignature() ); } - public void showEntry( ArgumentEntry entry, JPanel panel ) + private void showEntry( ArgumentEntry entry, JPanel panel ) { m_typeLabel.setText( "Argument: " ); addNameValue( panel, "Class", entry.getMethodEntry().getClassEntry().getName() ); diff --git a/src/cuchaz/enigma/gui/RenameListener.java b/src/cuchaz/enigma/gui/RenameListener.java index 58cdadb0..7d45505b 100644 --- a/src/cuchaz/enigma/gui/RenameListener.java +++ b/src/cuchaz/enigma/gui/RenameListener.java @@ -14,5 +14,5 @@ import cuchaz.enigma.mapping.Entry; public interface RenameListener { - void rename( Entry entry, String newName ); + void rename( Entry obfEntry, String newName ); } diff --git a/src/cuchaz/enigma/mapping/Ancestries.java b/src/cuchaz/enigma/mapping/Ancestries.java new file mode 100644 index 00000000..b7a5e249 --- /dev/null +++ b/src/cuchaz/enigma/mapping/Ancestries.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * 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.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import javassist.ByteArrayClassPath; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.NotFoundException; +import javassist.bytecode.Descriptor; + +import com.google.common.collect.Maps; + +import cuchaz.enigma.Constants; + +public class Ancestries implements Serializable +{ + private static final long serialVersionUID = 738687982126844179L; + + private Map m_superclasses; + + public Ancestries( ) + { + m_superclasses = Maps.newHashMap(); + } + + public void readFromJar( InputStream in ) + throws IOException + { + ClassPool classPool = new ClassPool(); + + ZipInputStream zin = new ZipInputStream( in ); + ZipEntry entry; + while( ( entry = zin.getNextEntry() ) != null ) + { + // filter out non-classes + if( entry.isDirectory() || !entry.getName().endsWith( ".class" ) ) + { + continue; + } + + // read the class into a buffer + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buf = new byte[Constants.KiB]; + int totalNumBytesRead = 0; + while( zin.available() > 0 ) + { + int numBytesRead = zin.read( buf ); + if( numBytesRead < 0 ) + { + break; + } + bos.write( buf, 0, numBytesRead ); + + // sanity checking + totalNumBytesRead += numBytesRead; + if( totalNumBytesRead > Constants.MiB ) + { + throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" ); + } + } + + // determine the class name (ie chop off the ".class") + String className = Descriptor.toJavaName( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) ); + + // get a javassist handle for the class + classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); + try + { + CtClass c = classPool.get( className ); + addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); + } + catch( NotFoundException ex ) + { + throw new Error( "Unable to load class: " + className ); + } + } + } + + public void addSuperclass( String className, String superclassName ) + { + className = Descriptor.toJvmName( className ); + superclassName = Descriptor.toJvmName( superclassName ); + + if( className.equals( superclassName ) ) + { + throw new IllegalArgumentException( "Class cannot be its own superclass! " + className ); + } + + if( !isJre( className ) && !isJre( superclassName ) ) + { + m_superclasses.put( className, superclassName ); + } + } + + public String getSuperclassName( String className ) + { + return m_superclasses.get( className ); + } + + public List getAncestry( String className ) + { + List ancestors = new ArrayList(); + while( className != null ) + { + className = getSuperclassName( className ); + ancestors.add( className ); + } + return ancestors; + } + + private boolean isJre( String className ) + { + return className.startsWith( "java/" ) + || className.startsWith( "javax/" ); + } +} diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java index dc3b4df7..c1624a83 100644 --- a/src/cuchaz/enigma/mapping/ArgumentEntry.java +++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java @@ -42,6 +42,13 @@ public class ArgumentEntry implements Entry, Serializable m_name = name; } + public ArgumentEntry( ArgumentEntry other ) + { + m_methodEntry = new MethodEntry( other.m_methodEntry ); + m_index = other.m_index; + m_name = other.m_name; + } + public MethodEntry getMethodEntry( ) { return m_methodEntry; @@ -58,6 +65,26 @@ public class ArgumentEntry implements Entry, Serializable return m_name; } + public ClassEntry getClassEntry( ) + { + return m_methodEntry.getClassEntry(); + } + + public String getClassName( ) + { + return m_methodEntry.getClassName(); + } + + public String getMethodName( ) + { + return m_methodEntry.getName(); + } + + public String getMethodSignature( ) + { + return m_methodEntry.getSignature(); + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/mapping/ArgumentIndex.java b/src/cuchaz/enigma/mapping/ArgumentIndex.java new file mode 100644 index 00000000..57488d14 --- /dev/null +++ b/src/cuchaz/enigma/mapping/ArgumentIndex.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 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/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index 3a757675..0968e955 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -33,6 +33,11 @@ public class ClassEntry implements Entry, Serializable m_name = className; } + public ClassEntry( ClassEntry other ) + { + m_name = other.m_name; + } + @Override public String getName( ) { diff --git a/src/cuchaz/enigma/mapping/ClassIndex.java b/src/cuchaz/enigma/mapping/ClassIndex.java new file mode 100644 index 00000000..699807b8 --- /dev/null +++ b/src/cuchaz/enigma/mapping/ClassIndex.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * 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/DeobfuscatedAncestries.java b/src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java new file mode 100644 index 00000000..5320f110 --- /dev/null +++ b/src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * 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.Map; + +public class DeobfuscatedAncestries extends Ancestries +{ + private static final long serialVersionUID = 8316248774892618324L; + + private Ancestries m_ancestries; + private Map m_classesByObf; + private Map m_classesByDeobf; + + protected DeobfuscatedAncestries( Ancestries ancestries, Map classesByObf, Map classesByDeobf ) + { + m_ancestries = ancestries; + m_classesByObf = classesByObf; + m_classesByDeobf = classesByDeobf; + } + + @Override + public String getSuperclassName( String deobfClassName ) + { + // obfuscate the class name + ClassIndex classIndex = m_classesByDeobf.get( deobfClassName ); + if( classIndex == null ) + { + return null; + } + String obfClassName = classIndex.getObfName(); + + // get the superclass + String obfSuperclassName = m_ancestries.getSuperclassName( obfClassName ); + if( obfSuperclassName == null ) + { + return null; + } + + // deobfuscate the superclass name + classIndex = m_classesByObf.get( obfSuperclassName ); + if( classIndex == null ) + { + return null; + } + + return classIndex.getDeobfName(); + } +} diff --git a/src/cuchaz/enigma/mapping/EntryPair.java b/src/cuchaz/enigma/mapping/EntryPair.java new file mode 100644 index 00000000..e40e9992 --- /dev/null +++ b/src/cuchaz/enigma/mapping/EntryPair.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * 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 cuchaz.enigma.Util; + +public class EntryPair +{ + public Entry obf; + public Entry deobf; + + public EntryPair( Entry obf, Entry 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/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java index 25b665ab..b9f42394 100644 --- a/src/cuchaz/enigma/mapping/FieldEntry.java +++ b/src/cuchaz/enigma/mapping/FieldEntry.java @@ -36,6 +36,18 @@ public class FieldEntry implements Entry, Serializable m_name = name; } + public FieldEntry( FieldEntry other ) + { + m_classEntry = new ClassEntry( other.m_classEntry ); + m_name = other.m_name; + } + + public FieldEntry( FieldEntry other, String newClassName ) + { + m_classEntry = new ClassEntry( newClassName ); + m_name = other.m_name; + } + public ClassEntry getClassEntry( ) { return m_classEntry; @@ -47,6 +59,11 @@ public class FieldEntry implements Entry, Serializable return m_name; } + public String getClassName( ) + { + return m_classEntry.getName(); + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index 4afc099b..9ea2d08e 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -42,6 +42,20 @@ public class MethodEntry implements Entry, Serializable m_signature = signature; } + public MethodEntry( MethodEntry other ) + { + m_classEntry = new ClassEntry( other.m_classEntry ); + m_name = other.m_name; + m_signature = other.m_signature; + } + + public MethodEntry( MethodEntry other, String newClassName ) + { + m_classEntry = new ClassEntry( newClassName ); + m_name = other.m_name; + m_signature = other.m_signature; + } + public ClassEntry getClassEntry( ) { return m_classEntry; @@ -58,6 +72,11 @@ public class MethodEntry implements Entry, Serializable return m_signature; } + public String getClassName( ) + { + return m_classEntry.getName(); + } + @Override public int hashCode( ) { @@ -84,6 +103,6 @@ public class MethodEntry implements Entry, Serializable @Override public String toString( ) { - return m_classEntry.getName() + "." + m_name + ":" + m_signature; + return m_classEntry.getName() + "." + m_name + m_signature; } } diff --git a/src/cuchaz/enigma/mapping/MethodIndex.java b/src/cuchaz/enigma/mapping/MethodIndex.java new file mode 100644 index 00000000..f965355d --- /dev/null +++ b/src/cuchaz/enigma/mapping/MethodIndex.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.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/SignatureUpdater.java b/src/cuchaz/enigma/mapping/SignatureUpdater.java new file mode 100644 index 00000000..4c0dbac1 --- /dev/null +++ b/src/cuchaz/enigma/mapping/SignatureUpdater.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * 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.StringReader; + +public class SignatureUpdater +{ + public interface ClassNameUpdater + { + String update( String className ); + } + + public static String update( String signature, ClassNameUpdater updater ) + { + try + { + StringBuilder buf = new StringBuilder(); + + // read the signature character-by-character + StringReader reader = new StringReader( signature ); + int i = -1; + while( ( i = reader.read() ) != -1 ) + { + char c = (char)i; + + // does this character start a class name? + if( c == 'L' ) + { + // update the class name and add it to the buffer + buf.append( 'L' ); + String className = readClass( reader ); + if( className == null ) + { + throw new IllegalArgumentException( "Malformed signature: " + signature ); + } + buf.append( updater.update( className ) ); + buf.append( ';' ); + } + else + { + // copy the character into the buffer + buf.append( c ); + } + } + + return buf.toString(); + } + catch( IOException ex ) + { + // I'm pretty sure a StringReader will never throw one of these + throw new Error( ex ); + } + } + + private static String readClass( StringReader reader ) + throws IOException + { + // read all the characters in the buffer until we hit a ';' + StringBuilder buf = new StringBuilder(); + int i = -1; + while( ( i = reader.read() ) != -1 ) + { + char c = (char)i; + + if( c == ';' ) + { + return buf.toString(); + } + else + { + buf.append( c ); + } + } + + return null; + } +} diff --git a/src/cuchaz/enigma/mapping/TranslationDirection.java b/src/cuchaz/enigma/mapping/TranslationDirection.java new file mode 100644 index 00000000..79ae0d32 --- /dev/null +++ b/src/cuchaz/enigma/mapping/TranslationDirection.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * 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 enum TranslationDirection +{ + Deobfuscating + { + @Override + public T choose( T deobfChoice, T obfChoice ) + { + return deobfChoice; + } + }, + Obfuscating + { + @Override + public T choose( T deobfChoice, T obfChoice ) + { + return obfChoice; + } + }; + + public abstract T choose( T deobfChoice, T obfChoice ); +} diff --git a/src/cuchaz/enigma/mapping/TranslationMappings.java b/src/cuchaz/enigma/mapping/TranslationMappings.java new file mode 100644 index 00000000..d6cd4491 --- /dev/null +++ b/src/cuchaz/enigma/mapping/TranslationMappings.java @@ -0,0 +1,187 @@ +/******************************************************************************* + * 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 new file mode 100644 index 00000000..bae0dce7 --- /dev/null +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -0,0 +1,201 @@ +/******************************************************************************* + * 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.ArrayList; +import java.util.List; +import java.util.Map; + +import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; + +public class Translator +{ + private TranslationDirection m_direction; + private Map m_classes; + private Ancestries m_ancestries; + + protected Translator( TranslationDirection direction, Map classes, Ancestries ancestries ) + { + m_direction = direction; + m_classes = classes; + m_ancestries = ancestries; + } + + public String translate( ClassEntry in ) + { + return translateClass( in.getName() ); + } + + public String translateClass( String in ) + { + ClassIndex classIndex = m_classes.get( in ); + if( classIndex != null ) + { + return m_direction.choose( + classIndex.getDeobfName(), + classIndex.getObfName() + ); + } + + return null; + } + + public ClassEntry translateEntry( ClassEntry in ) + { + String name = translate( in ); + if( name == null ) + { + return in; + } + return new ClassEntry( name ); + } + + public String translate( FieldEntry in ) + { + for( String className : getSelfAndAncestors( in.getClassName() ) ) + { + // look for the class + ClassIndex classIndex = m_classes.get( className ); + if( classIndex != null ) + { + // look for the field + String deobfName = m_direction.choose( + classIndex.getDeobfFieldName( in.getName() ), + classIndex.getObfFieldName( in.getName() ) + ); + if( deobfName != null ) + { + return deobfName; + } + } + } + + return null; + } + + public FieldEntry translateEntry( FieldEntry in ) + { + String name = translate( in ); + if( name == null ) + { + name = in.getName(); + } + return new FieldEntry( + translateEntry( in.getClassEntry() ), + name + ); + } + + public String translate( MethodEntry in ) + { + for( String className : getSelfAndAncestors( in.getClassName() ) ) + { + // look for the class + ClassIndex classIndex = m_classes.get( className ); + if( classIndex != null ) + { + // look for the method + MethodIndex methodIndex = m_direction.choose( + classIndex.getMethodByObf( in.getName(), in.getSignature() ), + classIndex.getMethodByDeobf( in.getName(), in.getSignature() ) + ); + if( methodIndex != null ) + { + return m_direction.choose( + methodIndex.getDeobfName(), + methodIndex.getObfName() + ); + } + } + } + + return null; + } + + public MethodEntry translateEntry( MethodEntry in ) + { + String name = translate( in ); + if( name == null ) + { + name = in.getName(); + } + return new MethodEntry( + translateEntry( in.getClassEntry() ), + name, + translateSignature( in.getSignature() ) + ); + } + + public String translate( ArgumentEntry in ) + { + for( String className : getSelfAndAncestors( in.getClassName() ) ) + { + // look for the class + ClassIndex classIndex = m_classes.get( className ); + if( classIndex != null ) + { + // look for the method + MethodIndex methodIndex = m_direction.choose( + classIndex.getMethodByObf( in.getMethodName(), in.getMethodSignature() ), + classIndex.getMethodByDeobf( in.getMethodName(), in.getMethodSignature() ) + ); + if( methodIndex != null ) + { + return m_direction.choose( + methodIndex.getDeobfArgumentName( in.getIndex() ), + methodIndex.getObfArgumentName( in.getIndex() ) + ); + } + } + } + + return null; + } + + public ArgumentEntry translateEntry( ArgumentEntry in ) + { + String name = translate( in ); + if( name == null ) + { + name = in.getName(); + } + return new ArgumentEntry( + translateEntry( in.getMethodEntry() ), + in.getIndex(), + name + ); + } + + public String translateSignature( String signature ) + { + return SignatureUpdater.update( signature, new ClassNameUpdater( ) + { + @Override + public String update( String className ) + { + String translatedName = translateClass( className ); + if( translatedName != null ) + { + return translatedName; + } + return className; + } + } ); + } + + private List getSelfAndAncestors( String className ) + { + List ancestry = new ArrayList(); + 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 --- 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 +++++++++-- 4 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 src/cuchaz/enigma/gui/AboutDialog.java (limited to 'src') 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 (limited to 'src') 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(+) (limited to 'src') 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 (limited to 'src') 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 (limited to 'src') 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 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 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 (limited to 'src') 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(-) (limited to 'src') 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)pair, dynamicPanel ); } else if( pair.deobf instanceof FieldEntry ) { - showEntry( (FieldEntry)pair.deobf, dynamicPanel ); + showFieldEntryPair( (EntryPair)pair, dynamicPanel ); } else if( pair.deobf instanceof MethodEntry ) { - showEntry( (MethodEntry)pair.deobf, dynamicPanel ); + showMethodEntryPair( (EntryPair)pair, dynamicPanel ); } else if( pair.deobf instanceof ArgumentEntry ) { - showEntry( (ArgumentEntry)pair.deobf, dynamicPanel ); + showArgumentEntryPair( (EntryPair)pair, dynamicPanel ); } else { @@ -536,30 +540,30 @@ public class Gui redraw(); } - private void showEntry( ClassEntry entry, JPanel panel ) + private void showClassEntryPair( EntryPair pair, JPanel panel ) { m_typeLabel.setText( "Class: " ); } - private void showEntry( FieldEntry entry, JPanel panel ) + private void showFieldEntryPair( EntryPair 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 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 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 (limited to 'src') 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 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> 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)pair, dynamicPanel ); + showClassEntryPair( (EntryPair)pair ); } else if( pair.deobf instanceof FieldEntry ) { - showFieldEntryPair( (EntryPair)pair, dynamicPanel ); + showFieldEntryPair( (EntryPair)pair ); } else if( pair.deobf instanceof MethodEntry ) { - showMethodEntryPair( (EntryPair)pair, dynamicPanel ); + showMethodEntryPair( (EntryPair)pair ); } else if( pair.deobf instanceof ArgumentEntry ) { - showArgumentEntryPair( (EntryPair)pair, dynamicPanel ); + showArgumentEntryPair( (EntryPair)pair ); } else { @@ -540,30 +606,30 @@ public class Gui redraw(); } - private void showClassEntryPair( EntryPair pair, JPanel panel ) + private void showClassEntryPair( EntryPair pair ) { - m_typeLabel.setText( "Class: " ); + addNameValue( m_infoPanel, "Class", pair.deobf.getName() ); } - private void showFieldEntryPair( EntryPair pair, JPanel panel ) + private void showFieldEntryPair( EntryPair 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 pair, JPanel panel ) + private void showMethodEntryPair( EntryPair 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 pair, JPanel panel ) + private void showArgumentEntryPair( EntryPair 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 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 { private static final long serialVersionUID = -4409570216084263978L; @@ -28,7 +28,7 @@ public class MethodMapping implements Serializable public MethodMapping( String obfName, String deobfName, String obfSignature, String deobfSignature ) { m_obfName = obfName; - m_deobfName = deobfName; + m_deobfName = NameValidator.validateMethodName( deobfName ); m_obfSignature = obfSignature; m_deobfSignature = deobfSignature; m_arguments = new TreeMap(); @@ -45,7 +45,7 @@ public class MethodMapping implements Serializable } public void setDeobfName( String val ) { - m_deobfName = val; + m_deobfName = NameValidator.validateMethodName( val ); } public String getObfSignature( ) @@ -133,4 +133,10 @@ public class MethodMapping implements Serializable } return buf.toString(); } + + @Override + public int compareTo( MethodMapping other ) + { + return m_obfName.compareTo( other.m_obfName ); + } } diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java index 30982dc6..a8421fa5 100644 --- a/src/cuchaz/enigma/mapping/NameValidator.java +++ b/src/cuchaz/enigma/mapping/NameValidator.java @@ -10,12 +10,28 @@ ******************************************************************************/ package cuchaz.enigma.mapping; +import java.util.Arrays; +import java.util.List; import java.util.regex.Pattern; +import javassist.bytecode.Descriptor; + public class NameValidator { - private static final String IdentifierPattern; + private static final Pattern IdentifierPattern; private static final Pattern ClassPattern; + private static final List ReservedWords = Arrays.asList( + "abstract", "continue", "for", "new", "switch", + "assert", "default", "goto", "package", "synchronized", + "boolean", "do", "if", "private", "this", + "break", "double", "implements", "protected", "throw", + "byte", "else", "import", "public", "throws", + "case", "enum", "instanceof", "return", "transient", + "catch", "extends", "int", "short", "try", + "char", "final", "interface", "static", "void", + "class", "finally", "long", "strictfp", "volatile", + "const", "float", "native", "super", "while" + ); static { @@ -34,34 +50,36 @@ public class NameValidator } } - IdentifierPattern = String.format( "[\\Q%s\\E][\\Q%s\\E]*", startChars.toString(), partChars.toString() ); - ClassPattern = Pattern.compile( String.format( "^(%s(\\.|/))*(%s)$", IdentifierPattern, IdentifierPattern ) ); + String identifierRegex = "[A-Za-z_<][A-Za-z0-9_>]*"; + IdentifierPattern = Pattern.compile( identifierRegex ); + ClassPattern = Pattern.compile( String.format( "^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex ) ); } - public String validateClassName( String name ) + public static String validateClassName( String name ) { - if( !ClassPattern.matcher( name ).matches() ) + if( name == null || !ClassPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) { - throw new IllegalArgumentException( "Illegal name: " + name ); + throw new IllegalNameException( name ); } - - return classNameToJavaName( name ); + return Descriptor.toJvmName( name ); } - public static String fileNameToClassName( String fileName ) + public static String validateFieldName( String name ) { - final String suffix = ".class"; - - if( !fileName.endsWith( suffix ) ) + if( name == null || !IdentifierPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) { - return null; + throw new IllegalNameException( name ); } - - return fileName.substring( 0, fileName.length() - suffix.length() ).replace( "/", "." ); + return name; + } + + public static String validateMethodName( String name ) + { + return validateFieldName( name ); } - public static String classNameToJavaName( String className ) + public static String validateArgumentName( String name ) { - return className.replace( ".", "/" ); + return validateFieldName( name ); } } diff --git a/src/cuchaz/enigma/mapping/Renamer.java b/src/cuchaz/enigma/mapping/Renamer.java index 4a648ad3..42ac17de 100644 --- a/src/cuchaz/enigma/mapping/Renamer.java +++ b/src/cuchaz/enigma/mapping/Renamer.java @@ -39,10 +39,6 @@ public class Renamer 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 ) @@ -54,11 +50,6 @@ public class Renamer } 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 ) @@ -73,11 +64,6 @@ public class Renamer 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 ) @@ -89,11 +75,6 @@ public class Renamer } 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 ) -- cgit v1.2.3 From 699544e76e63e044d290a75f802d082aa0834ad7 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 4 Aug 2014 23:24:48 -0400 Subject: fixed bug with renaming classes --- src/cuchaz/enigma/gui/Gui.java | 1 + src/cuchaz/enigma/mapping/Renamer.java | 4 ++++ src/cuchaz/enigma/mapping/Translator.java | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 87b93085..1f967c0c 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -451,6 +451,7 @@ public class Gui // update gui m_frame.setTitle( Constants.Name ); setObfClasses( null ); + setDeobfClasses( null ); setSource( null ); // update menu diff --git a/src/cuchaz/enigma/mapping/Renamer.java b/src/cuchaz/enigma/mapping/Renamer.java index 42ac17de..b7aa35ca 100644 --- a/src/cuchaz/enigma/mapping/Renamer.java +++ b/src/cuchaz/enigma/mapping/Renamer.java @@ -28,6 +28,7 @@ public class Renamer public void setClassName( ClassEntry obf, String deobfName ) { + deobfName = NameValidator.validateClassName( deobfName ); ClassMapping classMapping = m_mappings.m_classesByObf.get( obf.getName() ); if( classMapping == null ) { @@ -43,6 +44,7 @@ public class Renamer public void setFieldName( FieldEntry obf, String deobfName ) { + deobfName = NameValidator.validateFieldName( deobfName ); ClassMapping classMapping = m_mappings.m_classesByObf.get( obf.getClassName() ); if( classMapping == null ) { @@ -54,6 +56,7 @@ public class Renamer public void setMethodName( MethodEntry obf, String deobfName ) { + deobfName = NameValidator.validateMethodName( deobfName ); ClassMapping classMapping = m_mappings.m_classesByObf.get( obf.getClassName() ); if( classMapping == null ) { @@ -68,6 +71,7 @@ public class Renamer public void setArgumentName( ArgumentEntry obf, String deobfName ) { + deobfName = NameValidator.validateArgumentName( deobfName ); ClassMapping classMapping = m_mappings.m_classesByObf.get( obf.getClassName() ); if( classMapping == null ) { diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index 3dbc103b..4ab53bc5 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -19,7 +19,7 @@ import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class Translator { private TranslationDirection m_direction; - private Map m_classes; + /* TEMP */ public Map m_classes; private Ancestries m_ancestries; protected Translator( TranslationDirection direction, Map classes, Ancestries ancestries ) -- cgit v1.2.3 From 17ec7a6fdf2dc76b9d89b6ef3168bacb1cb3fbd1 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 4 Aug 2014 23:57:08 -0400 Subject: started on inheritance viewer --- src/cuchaz/enigma/gui/Gui.java | 85 +++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 1f967c0c..f9afb64b 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -47,6 +47,7 @@ import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.WindowConstants; @@ -99,6 +100,7 @@ public class Gui private JPanel m_infoPanel; private BoxHighlightPainter m_obfuscatedHighlightPainter; private BoxHighlightPainter m_deobfuscatedHighlightPainter; + private JPanel m_inheritancePanel; // dynamic menu items private JMenuItem m_closeJarMenu; @@ -107,6 +109,7 @@ public class Gui private JMenuItem m_saveMappingsAsMenu; private JMenuItem m_closeMappingsMenu; private JMenuItem m_renameMenu; + private JMenuItem m_inheritanceMenu; // state private EntryPair m_selectedEntryPair; @@ -197,17 +200,7 @@ public class Gui @Override public void caretUpdate( CaretEvent event ) { - m_selectedEntryPair = m_controller.getEntryPair( event.getDot() ); - if( m_selectedEntryPair != null ) - { - showEntryPair( m_selectedEntryPair ); - m_renameMenu.setEnabled( true ); - } - else - { - clearEntryPair(); - m_renameMenu.setEnabled( false ); - } + onCaretMove( event.getDot() ); } } ); m_editor.addKeyListener( new KeyAdapter( ) @@ -244,15 +237,39 @@ public class Gui popupMenu.add( menu ); m_renameMenu = menu; } + { + JMenuItem menu = new JMenuItem( "Show Inheritance" ); + menu.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + showInheritance(); + } + } ); + popupMenu.add( menu ); + m_inheritanceMenu = menu; + } + + // init inheritance panel + m_inheritancePanel = new JPanel(); // layout controls JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); - JPanel rightPanel = new JPanel(); - rightPanel.setLayout( new BorderLayout() ); - 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 ); + splitLeft.setPreferredSize( new Dimension( 200, 0 ) ); + JPanel centerPanel = new JPanel(); + centerPanel.setLayout( new BorderLayout() ); + centerPanel.add( m_infoPanel, BorderLayout.NORTH ); + centerPanel.add( sourceScroller, BorderLayout.CENTER ); + JTabbedPane tabbedPane = new JTabbedPane(); + tabbedPane.setPreferredSize( new Dimension( 200, 0 ) ); + tabbedPane.addTab( "Inheritance", m_inheritancePanel ); + JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, tabbedPane ); + splitRight.setResizeWeight( 1 ); // let the left side take all the slack + splitRight.resetToPreferredSizes(); + JSplitPane splitCenter = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, splitRight ); + splitCenter.setResizeWeight( 0 ); // let the right side take all the slack + pane.add( splitCenter, BorderLayout.CENTER ); // init menus JMenuBar menuBar = new JMenuBar(); @@ -421,7 +438,7 @@ public class Gui // show the frame pane.doLayout(); - m_frame.setSize( 800, 600 ); + m_frame.setSize( 1024, 576 ); m_frame.setMinimumSize( new Dimension( 640, 480 ) ); m_frame.setVisible( true ); m_frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); @@ -646,6 +663,27 @@ public class Gui panel.add( unboldLabel( new JLabel( value, JLabel.LEFT ) ) ); } + private void onCaretMove( int pos ) + { + m_selectedEntryPair = m_controller.getEntryPair( pos ); + if( m_selectedEntryPair != null ) + { + showEntryPair( m_selectedEntryPair ); + + boolean isClassEntry = m_selectedEntryPair.obf instanceof ClassEntry; + boolean isMethodEntry = m_selectedEntryPair.obf instanceof MethodEntry; + + m_renameMenu.setEnabled( true ); + m_inheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); + } + else + { + clearEntryPair(); + m_renameMenu.setEnabled( false ); + m_inheritanceMenu.setEnabled( false ); + } + } + private void startRename( ) { // init the text box @@ -708,6 +746,17 @@ public class Gui redraw(); } + private void showInheritance( ) + { + m_inheritancePanel.removeAll(); + + // TEMP + m_inheritancePanel.add( new JLabel( m_selectedEntryPair.obf.getName() ) ); + m_inheritancePanel.add( new JLabel( m_selectedEntryPair.deobf.getName() ) ); + + redraw(); + } + private void close( ) { if( !m_controller.isDirty() ) -- cgit v1.2.3 From d71c0af8ed298bfb4b35b4e3e61b5678bc1c7d9f Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 6 Aug 2014 00:22:25 -0400 Subject: added simple class inheritance browsing --- src/cuchaz/enigma/Deobfuscator.java | 5 ++ src/cuchaz/enigma/TranslatingTypeLoader.java | 16 ++++-- .../enigma/gui/ClassInheritanceTreeNode.java | 56 ++++++++++++++++++++ src/cuchaz/enigma/gui/Gui.java | 61 ++++++++++++++++++---- src/cuchaz/enigma/gui/GuiController.java | 22 ++++++++ src/cuchaz/enigma/mapping/Ancestries.java | 22 +++++++- 6 files changed, 169 insertions(+), 13 deletions(-) create mode 100644 src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index a3937b4c..65e618a4 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -79,6 +79,11 @@ public class Deobfuscator return m_file.getName(); } + public Ancestries getAncestries( ) + { + return m_ancestries; + } + public Mappings getMappings( ) { return m_mappings; diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index e57a09de..44fe9805 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -10,6 +10,7 @@ ******************************************************************************/ package cuchaz.enigma; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.jar.JarEntry; @@ -59,10 +60,19 @@ public class TranslatingTypeLoader implements ITypeLoader try { // read the class file into a buffer - byte[] buf = new byte[(int)entry.getSize()]; + ByteArrayOutputStream data = new ByteArrayOutputStream(); + byte[] buf = new byte[1024*1024]; // 1 KiB InputStream in = m_jar.getInputStream( entry ); - int bytesRead = in.read( buf ); - assert( bytesRead == buf.length ); + while( true ) + { + int bytesRead = in.read( buf ); + if( bytesRead <= 0 ) + { + break; + } + data.write( buf, 0, bytesRead ); + } + buf = data.toByteArray(); // translate the class ClassPool classPool = new ClassPool(); diff --git a/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java new file mode 100644 index 00000000..921a1e98 --- /dev/null +++ b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java @@ -0,0 +1,56 @@ +package cuchaz.enigma.gui; + +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; + +import com.beust.jcommander.internal.Lists; + +import cuchaz.enigma.mapping.Ancestries; + +public class ClassInheritanceTreeNode extends DefaultMutableTreeNode +{ + private static final long serialVersionUID = 4432367405826178490L; + + String m_className; + + public ClassInheritanceTreeNode( String className ) + { + m_className = className; + } + + public String getClassName( ) + { + return m_className; + } + + @Override + public String toString( ) + { + return m_className; + } + + public void load( Ancestries ancestries, boolean recurse ) + { + // get all the child nodes + List nodes = Lists.newArrayList(); + for( String subclassName : ancestries.getSubclasses( m_className ) ) + { + nodes.add( new ClassInheritanceTreeNode( subclassName ) ); + } + + // add then to this node + for( ClassInheritanceTreeNode node : nodes ) + { + this.add( node ); + } + + if( recurse ) + { + for( ClassInheritanceTreeNode node : nodes ) + { + node.load( ancestries, true ); + } + } + } +} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index f9afb64b..2002a4d2 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -49,12 +49,18 @@ import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JTextField; +import javax.swing.JTree; import javax.swing.ListSelectionModel; 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 javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; + +import com.beust.jcommander.internal.Lists; import jsyntaxpane.DefaultSyntaxKit; import jsyntaxpane.SyntaxDocument; @@ -100,7 +106,7 @@ public class Gui private JPanel m_infoPanel; private BoxHighlightPainter m_obfuscatedHighlightPainter; private BoxHighlightPainter m_deobfuscatedHighlightPainter; - private JPanel m_inheritancePanel; + private JTree m_inheritanceTree; // dynamic menu items private JMenuItem m_closeJarMenu; @@ -136,6 +142,7 @@ public class Gui m_obfClasses.setCellRenderer( new ObfuscatedClassListCellRenderer() ); m_obfClasses.addMouseListener( new MouseAdapter() { + @Override public void mouseClicked( MouseEvent event ) { if( event.getClickCount() == 2 ) @@ -161,6 +168,7 @@ public class Gui m_deobfClasses.setCellRenderer( new DeobfuscatedClassListCellRenderer() ); m_deobfClasses.addMouseListener( new MouseAdapter() { + @Override public void mouseClicked( MouseEvent event ) { if( event.getClickCount() == 2 ) @@ -252,7 +260,26 @@ public class Gui } // init inheritance panel - m_inheritancePanel = new JPanel(); + m_inheritanceTree = new JTree(); + m_inheritanceTree.setModel( null ); + m_inheritanceTree.addMouseListener( new MouseAdapter( ) + { + @Override + public void mouseClicked( MouseEvent event ) + { + if( event.getClickCount() == 2 ) + { + ClassInheritanceTreeNode node = (ClassInheritanceTreeNode)m_inheritanceTree.getSelectionPath().getLastPathComponent(); + if( node != null ) + { + m_controller.deobfuscateClass( new ClassFile( node.getClassName() ) ); + } + } + } + } ); + JPanel inheritancePanel = new JPanel(); + inheritancePanel.setLayout( new BorderLayout() ); + inheritancePanel.add( new JScrollPane( m_inheritanceTree ) ); // layout controls JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); @@ -263,7 +290,7 @@ public class Gui centerPanel.add( sourceScroller, BorderLayout.CENTER ); JTabbedPane tabbedPane = new JTabbedPane(); tabbedPane.setPreferredSize( new Dimension( 200, 0 ) ); - tabbedPane.addTab( "Inheritance", m_inheritancePanel ); + tabbedPane.addTab( "Inheritance", inheritancePanel ); JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, tabbedPane ); splitRight.setResizeWeight( 1 ); // let the left side take all the slack splitRight.resetToPreferredSizes(); @@ -748,12 +775,28 @@ public class Gui private void showInheritance( ) { - m_inheritancePanel.removeAll(); - - // TEMP - m_inheritancePanel.add( new JLabel( m_selectedEntryPair.obf.getName() ) ); - m_inheritancePanel.add( new JLabel( m_selectedEntryPair.deobf.getName() ) ); - + // get the current class + if( m_selectedEntryPair.obf instanceof ClassEntry ) + { + ClassInheritanceTreeNode classNode = m_controller.getClassInheritance( (ClassEntry)m_selectedEntryPair.obf ); + + // build the path from the root to the class node + List nodes = Lists.newArrayList(); + TreeNode node = classNode; + do + { + nodes.add( node ); + node = node.getParent(); + } + while( node != null ); + Collections.reverse( nodes ); + TreePath path = new TreePath( nodes.toArray() ); + + // show the tree at the root + m_inheritanceTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); + m_inheritanceTree.expandPath( path ); + m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); + } redraw(); } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index e1ba49a6..452632f3 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -26,6 +26,7 @@ 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; @@ -129,6 +130,27 @@ public class GuiController return m_deobfuscator.hasMapping( pair.obf ); } + public ClassInheritanceTreeNode getClassInheritance( ClassEntry classEntry ) + { + // create a node for this class + ClassInheritanceTreeNode thisNode = new ClassInheritanceTreeNode( classEntry.getName() ); + + // expand all children recursively + thisNode.load( m_deobfuscator.getAncestries(), true ); + + // get the ancestors too + ClassInheritanceTreeNode node = thisNode; + for( String superclassName : m_deobfuscator.getAncestries().getAncestry( classEntry.getName() ) ) + { + // add the parent node + ClassInheritanceTreeNode parentNode = new ClassInheritanceTreeNode( superclassName ); + parentNode.add( node ); + node = parentNode; + } + + return thisNode; + } + public void rename( Entry obfsEntry, String newName, int lineNum ) { m_deobfuscator.rename( obfsEntry, newName ); diff --git a/src/cuchaz/enigma/mapping/Ancestries.java b/src/cuchaz/enigma/mapping/Ancestries.java index b7a5e249..f77a00eb 100644 --- a/src/cuchaz/enigma/mapping/Ancestries.java +++ b/src/cuchaz/enigma/mapping/Ancestries.java @@ -26,6 +26,7 @@ import javassist.CtClass; import javassist.NotFoundException; import javassist.bytecode.Descriptor; +import com.beust.jcommander.internal.Lists; import com.google.common.collect.Maps; import cuchaz.enigma.Constants; @@ -121,11 +122,30 @@ public class Ancestries implements Serializable while( className != null ) { className = getSuperclassName( className ); - ancestors.add( className ); + if( className != null ) + { + ancestors.add( className ); + } } return ancestors; } + public List getSubclasses( String className ) + { + // linear search is fast enough for now + List subclasses = Lists.newArrayList(); + for( Map.Entry entry : m_superclasses.entrySet() ) + { + String subclass = entry.getKey(); + String superclass = entry.getValue(); + if( className.equals( superclass ) ) + { + subclasses.add( subclass ); + } + } + return subclasses; + } + private boolean isJre( String className ) { return className.startsWith( "java/" ) -- cgit v1.2.3 From 0c836a74972173d4ab991f0d6d79195b4377fe4c Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 6 Aug 2014 00:22:51 -0400 Subject: added copyright --- src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java index 921a1e98..91000ed3 100644 --- a/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java +++ b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.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.util.List; -- cgit v1.2.3 From 75d462daee9c24e19e28b4e969f92ae83a026e7b Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 6 Aug 2014 22:18:12 -0400 Subject: show deobfuscated names in class inheritance --- src/cuchaz/enigma/Deobfuscator.java | 15 +++++++---- .../enigma/gui/ClassInheritanceTreeNode.java | 29 ++++++++++++++++------ src/cuchaz/enigma/gui/Gui.java | 2 +- src/cuchaz/enigma/gui/GuiController.java | 8 ++++-- 4 files changed, 38 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 65e618a4..2fceef1c 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -100,11 +100,16 @@ public class Deobfuscator // update decompiler options m_settings.setTypeLoader( new TranslatingTypeLoader( m_jar, - m_mappings.getTranslator( m_ancestries, TranslationDirection.Obfuscating ), - m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ) + getTranslator( TranslationDirection.Obfuscating ), + getTranslator( TranslationDirection.Deobfuscating ) ) ); } + public Translator getTranslator( TranslationDirection direction ) + { + return m_mappings.getTranslator( m_ancestries, direction ); + } + public void getSeparatedClasses( List obfClasses, Map deobfClasses ) { Enumeration entries = m_jar.entries(); @@ -181,7 +186,7 @@ public class Deobfuscator public Entry obfuscateEntry( Entry deobfEntry ) { - Translator translator = m_mappings.getTranslator( m_ancestries, TranslationDirection.Obfuscating ); + Translator translator = getTranslator( TranslationDirection.Obfuscating ); if( deobfEntry instanceof ClassEntry ) { return translator.translateEntry( (ClassEntry)deobfEntry ); @@ -206,7 +211,7 @@ public class Deobfuscator public Entry deobfuscateEntry( Entry obfEntry ) { - Translator translator = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ); + Translator translator = getTranslator( TranslationDirection.Deobfuscating ); if( obfEntry instanceof ClassEntry ) { return translator.translateEntry( (ClassEntry)obfEntry ); @@ -231,7 +236,7 @@ public class Deobfuscator public boolean hasMapping( Entry obfEntry ) { - Translator translator = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ); + Translator translator = getTranslator( TranslationDirection.Deobfuscating ); if( obfEntry instanceof ClassEntry ) { String deobfName = translator.translate( (ClassEntry)obfEntry ); diff --git a/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java index 91000ed3..d8e67554 100644 --- a/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java +++ b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java @@ -17,36 +17,49 @@ import javax.swing.tree.DefaultMutableTreeNode; import com.beust.jcommander.internal.Lists; import cuchaz.enigma.mapping.Ancestries; +import cuchaz.enigma.mapping.Translator; public class ClassInheritanceTreeNode extends DefaultMutableTreeNode { private static final long serialVersionUID = 4432367405826178490L; - String m_className; + private Translator m_deobfuscatingTranslator; + private String m_obfClassName; - public ClassInheritanceTreeNode( String className ) + public ClassInheritanceTreeNode( Translator deobfuscatingTranslator, String obfClassName ) { - m_className = className; + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_obfClassName = obfClassName; } - public String getClassName( ) + public String getObfClassName( ) { - return m_className; + return m_obfClassName; + } + + public String getDeobfClassName( ) + { + return m_deobfuscatingTranslator.translateClass( m_obfClassName ); } @Override public String toString( ) { - return m_className; + String deobfClassName = getDeobfClassName(); + if( deobfClassName != null ) + { + return deobfClassName; + } + return m_obfClassName; } public void load( Ancestries ancestries, boolean recurse ) { // get all the child nodes List nodes = Lists.newArrayList(); - for( String subclassName : ancestries.getSubclasses( m_className ) ) + for( String subclassName : ancestries.getSubclasses( m_obfClassName ) ) { - nodes.add( new ClassInheritanceTreeNode( subclassName ) ); + nodes.add( new ClassInheritanceTreeNode( m_deobfuscatingTranslator, subclassName ) ); } // add then to this node diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 2002a4d2..e2ccb7d2 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -272,7 +272,7 @@ public class Gui ClassInheritanceTreeNode node = (ClassInheritanceTreeNode)m_inheritanceTree.getSelectionPath().getLastPathComponent(); if( node != null ) { - m_controller.deobfuscateClass( new ClassFile( node.getClassName() ) ); + m_controller.deobfuscateClass( new ClassFile( node.getObfClassName() ) ); } } } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 452632f3..7d37febf 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -31,6 +31,8 @@ import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.EntryPair; import cuchaz.enigma.mapping.MappingsReader; import cuchaz.enigma.mapping.MappingsWriter; +import cuchaz.enigma.mapping.TranslationDirection; +import cuchaz.enigma.mapping.Translator; public class GuiController { @@ -132,8 +134,10 @@ public class GuiController public ClassInheritanceTreeNode getClassInheritance( ClassEntry classEntry ) { + Translator deobfuscatingTranslator = m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ); + // create a node for this class - ClassInheritanceTreeNode thisNode = new ClassInheritanceTreeNode( classEntry.getName() ); + ClassInheritanceTreeNode thisNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, classEntry.getName() ); // expand all children recursively thisNode.load( m_deobfuscator.getAncestries(), true ); @@ -143,7 +147,7 @@ public class GuiController for( String superclassName : m_deobfuscator.getAncestries().getAncestry( classEntry.getName() ) ) { // add the parent node - ClassInheritanceTreeNode parentNode = new ClassInheritanceTreeNode( superclassName ); + ClassInheritanceTreeNode parentNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, superclassName ); parentNode.add( node ); node = parentNode; } -- cgit v1.2.3 From 4863d9e001e3073a51e63351828c09df39cef393 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 6 Aug 2014 22:28:17 -0400 Subject: added open entry function to popup menu --- src/cuchaz/enigma/gui/Gui.java | 52 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index e2ccb7d2..57c6ef7b 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -116,6 +116,7 @@ public class Gui private JMenuItem m_closeMappingsMenu; private JMenuItem m_renameMenu; private JMenuItem m_inheritanceMenu; + private JMenuItem m_openEntryMenu; // state private EntryPair m_selectedEntryPair; @@ -258,6 +259,19 @@ public class Gui popupMenu.add( menu ); m_inheritanceMenu = menu; } + { + JMenuItem menu = new JMenuItem( "Open Class" ); + menu.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + openEntry(); + } + } ); + popupMenu.add( menu ); + m_openEntryMenu = menu; + } // init inheritance panel m_inheritanceTree = new JTree(); @@ -693,22 +707,23 @@ public class Gui private void onCaretMove( int pos ) { m_selectedEntryPair = m_controller.getEntryPair( pos ); - if( m_selectedEntryPair != null ) + + boolean isEntry = m_selectedEntryPair != null; + boolean isClassEntry = isEntry && m_selectedEntryPair.obf instanceof ClassEntry; + boolean isMethodEntry = isEntry && m_selectedEntryPair.obf instanceof MethodEntry; + + if( isEntry ) { showEntryPair( m_selectedEntryPair ); - - boolean isClassEntry = m_selectedEntryPair.obf instanceof ClassEntry; - boolean isMethodEntry = m_selectedEntryPair.obf instanceof MethodEntry; - - m_renameMenu.setEnabled( true ); - m_inheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); } else { clearEntryPair(); - m_renameMenu.setEnabled( false ); - m_inheritanceMenu.setEnabled( false ); } + + m_renameMenu.setEnabled( isEntry ); + m_inheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); + m_openEntryMenu.setEnabled( isClassEntry ); } private void startRename( ) @@ -775,6 +790,11 @@ public class Gui private void showInheritance( ) { + if( m_selectedEntryPair == null ) + { + return; + } + // get the current class if( m_selectedEntryPair.obf instanceof ClassEntry ) { @@ -800,6 +820,20 @@ public class Gui redraw(); } + private void openEntry( ) + { + if( m_selectedEntryPair == null ) + { + return; + } + + // get the current class + if( m_selectedEntryPair.obf instanceof ClassEntry ) + { + m_controller.deobfuscateClass( new ClassFile( m_selectedEntryPair.obf.getName() ) ); + } + } + private void close( ) { if( !m_controller.isDirty() ) -- cgit v1.2.3 From 13c1b15a9278eeb62f6a4a58b89f4336d02dbf73 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 6 Aug 2014 23:00:10 -0400 Subject: added un-obfuscated classes to the deobfuscated classes list --- src/cuchaz/enigma/ClassFile.java | 5 +++++ src/cuchaz/enigma/Deobfuscator.java | 4 ++++ src/cuchaz/enigma/TranslatingTypeLoader.java | 6 ++++-- 3 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/ClassFile.java b/src/cuchaz/enigma/ClassFile.java index 613b379d..043558d0 100644 --- a/src/cuchaz/enigma/ClassFile.java +++ b/src/cuchaz/enigma/ClassFile.java @@ -33,4 +33,9 @@ public class ClassFile { return m_name.replace( ".", "/" ) + ".class"; } + + public boolean isInPackage( ) + { + return m_name.indexOf( '/' ) >= 0; + } } diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 2fceef1c..e067183e 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -133,6 +133,10 @@ public class Deobfuscator { deobfClasses.put( classFile, classMapping.getDeobfName() ); } + else if( classFile.isInPackage() ) + { + deobfClasses.put( classFile, classFile.getName() ); + } else { obfClasses.add( classFile ); diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 44fe9805..f5112e0f 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -19,6 +19,7 @@ import java.util.jar.JarFile; import javassist.ByteArrayClassPath; import javassist.ClassPool; import javassist.CtClass; +import javassist.bytecode.Descriptor; import com.strobel.assembler.metadata.Buffer; import com.strobel.assembler.metadata.ITypeLoader; @@ -75,11 +76,12 @@ public class TranslatingTypeLoader implements ITypeLoader buf = data.toByteArray(); // translate the class + String javaName = Descriptor.toJavaName( name ); ClassPool classPool = new ClassPool(); - classPool.insertClassPath( new ByteArrayClassPath( name, buf ) ); + classPool.insertClassPath( new ByteArrayClassPath( javaName, buf ) ); try { - CtClass c = classPool.get( name ); + CtClass c = classPool.get( javaName ); new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); buf = c.toBytecode(); -- cgit v1.2.3 From 6aa7c6121a2ecbe78f14f8c3d7ddb55b8ddb10bd Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 7 Aug 2014 00:55:43 -0400 Subject: started working on recognition of non-class member identifiers in the source got class extends,implements working and argument,field types added filtering to make sure highlighted class names are actually classes in the jar --- src/cuchaz/enigma/Deobfuscator.java | 87 ++++++++++++++++++++++----- src/cuchaz/enigma/analysis/Analyzer.java | 91 ++++++++++++++++------------- src/cuchaz/enigma/analysis/Lexer.java | 42 ++++++++++++- src/cuchaz/enigma/analysis/SourceIndex.java | 34 ++++++----- src/cuchaz/enigma/analysis/SourcedAst.java | 43 +++++++++----- src/cuchaz/enigma/gui/GuiController.java | 12 +++- src/cuchaz/enigma/gui/SourceFormatter.java | 62 -------------------- 7 files changed, 223 insertions(+), 148 deletions(-) delete mode 100644 src/cuchaz/enigma/gui/SourceFormatter.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index e067183e..e6e647e9 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -10,10 +10,12 @@ ******************************************************************************/ package cuchaz.enigma; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.StringReader; import java.io.StringWriter; import java.util.Enumeration; import java.util.List; @@ -21,6 +23,7 @@ import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import com.beust.jcommander.internal.Lists; import com.strobel.decompiler.Decompiler; import com.strobel.decompiler.DecompilerSettings; import com.strobel.decompiler.PlainTextOutput; @@ -45,6 +48,7 @@ public class Deobfuscator private Ancestries m_ancestries; private Mappings m_mappings; private Renamer m_renamer; + private List m_obfClassNames; public Deobfuscator( File file ) throws IOException @@ -65,6 +69,26 @@ public class Deobfuscator Util.closeQuietly( jarIn ); } + // get the obf class names + m_obfClassNames = Lists.newArrayList(); + { + Enumeration entries = m_jar.entries(); + while( entries.hasMoreElements() ) + { + JarEntry entry = entries.nextElement(); + + // skip everything but class files + if( !entry.getName().endsWith( ".class" ) ) + { + continue; + } + + // get the class name from the file + String className = entry.getName().substring( 0, entry.getName().length() - 6 ); + m_obfClassNames.add( className ); + } + } + // config the decompiler m_settings = DecompilerSettings.javaDefaults(); m_settings.setForceExplicitImports( true ); @@ -112,20 +136,9 @@ public class Deobfuscator public void getSeparatedClasses( List obfClasses, Map deobfClasses ) { - Enumeration entries = m_jar.entries(); - while( entries.hasMoreElements() ) + for( String obfClassName : m_obfClassNames ) { - JarEntry entry = entries.nextElement(); - - // skip everything but class files - if( !entry.getName().endsWith( ".class" ) ) - { - continue; - } - - // get the class name from the file - String className = entry.getName().substring( 0, entry.getName().length() - 6 ); - ClassFile classFile = new ClassFile( className ); + ClassFile classFile = new ClassFile( obfClassName ); // separate the classes ClassMapping classMapping = m_mappings.getClassByObf( classFile.getName() ); @@ -159,7 +172,41 @@ public class Deobfuscator // decompile it! StringWriter buf = new StringWriter(); Decompiler.decompile( deobfName, new PlainTextOutput( buf ), m_settings ); - return buf.toString(); + return fixSource( buf.toString() ); + } + + private String fixSource( String source ) + { + // fix the imports from the default package in the source + try + { + StringBuilder buf = new StringBuilder(); + BufferedReader reader = new BufferedReader( new StringReader( source ) ); + String line = null; + while( ( line = reader.readLine() ) != null ) + { + String[] parts = line.trim().split( " " ); + if( parts.length == 2 && parts[0].equals( "import" ) ) + { + // is this an (illegal) import from the default package? + String className = parts[1]; + if( className.indexOf( '.' ) < 0 ) + { + // this is an illegal import, replace it + line = "import __DEFAULT__." + parts[1]; + } + } + + buf.append( line ); + buf.append( "\n" ); + } + return buf.toString(); + } + catch( IOException ex ) + { + // dealing with IOExceptions on StringReaders is silly... + throw new Error( ex ); + } } // NOTE: these methods are a bit messy... oh well @@ -265,4 +312,16 @@ public class Deobfuscator throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); } } + + public boolean entryIsObfuscatedIdenfitier( Entry obfEntry ) + { + if( obfEntry instanceof ClassEntry ) + { + // obf classes must be in the list + return m_obfClassNames.contains( obfEntry.getName() ); + } + + // assume everything else is an identifier + return true; + } } diff --git a/src/cuchaz/enigma/analysis/Analyzer.java b/src/cuchaz/enigma/analysis/Analyzer.java index dad8dc52..2b7e0b0b 100644 --- a/src/cuchaz/enigma/analysis/Analyzer.java +++ b/src/cuchaz/enigma/analysis/Analyzer.java @@ -35,6 +35,7 @@ import com.sun.source.util.Trees; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MethodEntry; @@ -78,39 +79,31 @@ class TreeVisitor extends TreeScanner private ClassEntry indexClass( ClassTree classTree, SourcedAst ast ) { - // build the entry - ClassEntry entry = new ClassEntry( ast.getFullClassName( classTree.getSimpleName().toString() ) ); + // index the class name + ClassEntry classEntry = indexClassIdentifier( classTree, ast ); + assert( classEntry != null ); - // lex the source at this tree node - for( Token token : new Lexer( ast.getSource( classTree ).toString() ) ) + // index the extends clause + indexClassIdentifier( classTree.getExtendsClause(), ast ); + + // index the implements clauses + for( Tree implementsTree : classTree.getImplementsClause() ) { - // scan until we get the first identifier - if( token.type == TokenType.IDENTIFIER ) - { - m_index.add( entry, offsetToken( token, ast.getStart( classTree ) ) ); - break; - } + indexClassIdentifier( implementsTree, ast ); } - return entry; + return classEntry; } private FieldEntry indexField( VariableTree variableTree, SourcedAst ast, ClassEntry classEntry ) { - // build the entry + // index the field name FieldEntry entry = new FieldEntry( classEntry, variableTree.getName().toString() ); + Token nameToken = new Lexer( ast.getSource( variableTree ) ).getFirstIdentifierMatching( variableTree.getName() ); + addToken( entry, nameToken, variableTree, ast ); - // lex the source at this tree node - Lexer lexer = new Lexer( ast.getSource( variableTree ).toString() ); - for( Token token : lexer ) - { - // scan until we find an identifier that matches the field name - if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) ) - { - m_index.add( entry, offsetToken( token, ast.getStart( variableTree ) ) ); - break; - } - } + // index the field type + indexClassIdentifier( variableTree.getType(), ast ); return entry; } @@ -136,13 +129,13 @@ class TreeVisitor extends TreeScanner MethodEntry entry = new MethodEntry( classEntry, methodTree.getName().toString(), signature.toString() ); // lex the source at this tree node - Lexer lexer = new Lexer( ast.getSource( methodTree ).toString() ); + Lexer lexer = new Lexer( ast.getSource( methodTree ) ); for( Token token : lexer ) { // scan until we find an identifier that matches the method name if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) ) { - m_index.add( entry, offsetToken( token, ast.getStart( methodTree ) ) ); + addToken( entry, token, methodTree, ast ); break; } } @@ -152,27 +145,47 @@ class TreeVisitor extends TreeScanner private void indexArgument( VariableTree variableTree, SourcedAst ast, MethodEntry methodEntry, int index ) { - // build the entry + // index argument name ArgumentEntry entry = new ArgumentEntry( methodEntry, index, variableTree.getName().toString() ); + Token token = new Lexer( ast.getSource( variableTree ) ).getLastIdentifier(); + addToken( entry, token, variableTree, ast ); - // lex the source at this tree node - Lexer lexer = new Lexer( ast.getSource( variableTree ).toString() ); - for( Token token : lexer ) + // index argument type + indexClassIdentifier( variableTree.getType(), ast ); + } + + private ClassEntry indexClassIdentifier( Tree tree, SourcedAst ast ) + { + if( tree == null ) { - // scan until we find an identifier that matches the variable name - if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) ) - { - m_index.add( entry, offsetToken( token, ast.getStart( variableTree ) ) ); - break; - } + return null; + } + + Lexer lexer = new Lexer( ast.getSource( tree ) ); + Token token = lexer.getFirstIdentifier(); + if( token == null ) + { + return null; } + + ClassEntry classEntry = new ClassEntry( ast.getFullClassName( lexer.getText( token ) ) ); + addToken( classEntry, token, tree, ast ); + return classEntry; } - - private Token offsetToken( Token in, int offset ) + + private void addToken( Entry entry, Token token, Tree tree, SourcedAst ast ) { - return new Token( in.type, in.start + offset, in.length ); + if( token == null ) + { + throw new IllegalArgumentException( "token cannot be null!" ); + } + + // offset the token by the tree + Token offsetToken = new Token( token.type, token.start + ast.getStart( tree ), token.length ); + + m_index.add( entry, offsetToken ); } - + private String toJvmType( Tree tree, SourcedAst ast ) { switch( tree.getKind() ) diff --git a/src/cuchaz/enigma/analysis/Lexer.java b/src/cuchaz/enigma/analysis/Lexer.java index acb52bf8..602e3a9b 100644 --- a/src/cuchaz/enigma/analysis/Lexer.java +++ b/src/cuchaz/enigma/analysis/Lexer.java @@ -14,6 +14,7 @@ import java.util.Iterator; import jsyntaxpane.SyntaxDocument; import jsyntaxpane.Token; +import jsyntaxpane.TokenType; import jsyntaxpane.lexers.JavaLexer; public class Lexer implements Iterable @@ -21,10 +22,10 @@ public class Lexer implements Iterable private SyntaxDocument m_doc; private Iterator m_iter; - public Lexer( String source ) + public Lexer( CharSequence source ) { m_doc = new SyntaxDocument( new JavaLexer() ); - m_doc.append( source ); + m_doc.append( source.toString() ); m_iter = m_doc.getTokens( 0, m_doc.getLength() ); } @@ -38,4 +39,41 @@ public class Lexer implements Iterable { return token.getString( m_doc ); } + + public Token getFirstIdentifier( ) + { + for( Token token : this ) + { + if( token.type == TokenType.IDENTIFIER ) + { + return token; + } + } + return null; + } + + public Token getFirstIdentifierMatching( CharSequence val ) + { + for( Token token : this ) + { + if( token.type == TokenType.IDENTIFIER && getText( token ).equals( val.toString() ) ) + { + return token; + } + } + return null; + } + + public Token getLastIdentifier( ) + { + Token lastToken = null; + for( Token token : this ) + { + if( token.type == TokenType.IDENTIFIER ) + { + lastToken = token; + } + } + return lastToken; + } } diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 61c833ce..de163087 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -10,46 +10,52 @@ ******************************************************************************/ package cuchaz.enigma.analysis; +import java.util.Collection; import java.util.Iterator; import java.util.Map; -import java.util.Set; import jsyntaxpane.Token; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import cuchaz.enigma.mapping.Entry; public class SourceIndex implements Iterable> { - private BiMap m_entryToToken; - private BiMap m_tokenToEntry; + private Multimap m_entryToTokens; public SourceIndex( ) { - m_entryToToken = HashBiMap.create(); - m_tokenToEntry = m_entryToToken.inverse(); + m_entryToTokens = HashMultimap.create(); } public void add( Entry entry, Token token ) { - m_entryToToken.put( entry, token ); + m_entryToTokens.put( entry, token ); } public Iterator> iterator( ) { - return m_entryToToken.entrySet().iterator(); + return m_entryToTokens.entries().iterator(); } - public Set tokens( ) + public Collection tokens( ) { - return m_entryToToken.values(); + return m_entryToTokens.values(); } public Entry getEntry( Token token ) { - return m_tokenToEntry.get( token ); + // linear search is fast enough for now + for( Map.Entry entry : this ) + { + if( entry.getValue().equals( token ) ) + { + return entry.getKey(); + } + } + return null; } public Map.Entry getEntry( int pos ) @@ -66,8 +72,8 @@ public class SourceIndex implements Iterable> return null; } - public Token getToken( Entry entry ) + public Collection getTokens( Entry entry ) { - return m_entryToToken.get( entry ); + return m_entryToTokens.get( entry ); } } diff --git a/src/cuchaz/enigma/analysis/SourcedAst.java b/src/cuchaz/enigma/analysis/SourcedAst.java index 968c8804..a88cc754 100644 --- a/src/cuchaz/enigma/analysis/SourcedAst.java +++ b/src/cuchaz/enigma/analysis/SourcedAst.java @@ -16,7 +16,6 @@ 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; @@ -29,6 +28,7 @@ public class SourcedAst private Trees m_trees; private SourcePositions m_positions; private HashMap m_classNameIndex; + private String m_packageName; public SourcedAst( CompilationUnitTree tree, Trees trees ) { @@ -49,6 +49,13 @@ public class SourcedAst // get the full and simple class names String fullName = Descriptor.toJvmName( importTree.getQualifiedIdentifier().toString() ); String simpleName = fullName; + + if( fullName.startsWith( "__DEFAULT__/" ) ) + { + // remove the default package flag + fullName = fullName.substring( 12 ); + } + String[] parts = fullName.split( "/" ); if( parts.length > 0 ) { @@ -58,30 +65,26 @@ public class SourcedAst m_classNameIndex.put( simpleName, fullName ); } - // index the self class using the package name + // get the package name + m_packageName = null; if( m_tree.getPackageName() != null ) { - 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 ); - } - } + m_packageName = Descriptor.toJvmName( m_tree.getPackageName().toString() ); } } public int getStart( Tree node ) { - return (int)m_positions.getStartPosition( m_tree, node ); + int pos = (int)m_positions.getStartPosition( m_tree, node ); + assert( pos >= 0 ); + return pos; } public int getEnd( Tree node ) { - return (int)m_positions.getEndPosition( m_tree, node ); + int pos = (int)m_positions.getEndPosition( m_tree, node ); + assert( pos >= 0 ); + return pos; } public int getLine( Tree node ) @@ -121,8 +124,16 @@ public class SourcedAst String fullClassName = m_classNameIndex.get( simpleClassName ); if( fullClassName == null ) { - // no mapping was found, the name is probably already fully-qualified - fullClassName = simpleClassName; + if( m_packageName != null ) + { + // no mapping was found, assume it's in the package + fullClassName = m_packageName + "/" + simpleClassName; + } + else + { + // this must be in the default package + fullClassName = simpleClassName; + } } return fullClassName; } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 7d37febf..2219e05b 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -132,6 +132,16 @@ public class GuiController return m_deobfuscator.hasMapping( pair.obf ); } + public boolean entryIsObfuscatedIdenfitier( int pos ) + { + EntryPair pair = getEntryPair( pos ); + if( pair == null || pair.obf == null ) + { + return false; + } + return m_deobfuscator.entryIsObfuscatedIdenfitier( pair.obf ); + } + public ClassInheritanceTreeNode getClassInheritance( ClassEntry classEntry ) { Translator deobfuscatingTranslator = m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ); @@ -216,7 +226,7 @@ public class GuiController { deobfuscatedTokens.add( token ); } - else + else if( entryIsObfuscatedIdenfitier( token.start ) ) { obfuscatedTokens.add( token ); } diff --git a/src/cuchaz/enigma/gui/SourceFormatter.java b/src/cuchaz/enigma/gui/SourceFormatter.java deleted file mode 100644 index f3878405..00000000 --- a/src/cuchaz/enigma/gui/SourceFormatter.java +++ /dev/null @@ -1,62 +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.io.BufferedReader; -import java.io.IOException; -import java.io.StringReader; - -public class SourceFormatter -{ - public static String format( String in ) - { - return collapseNewlines( in ); - } - - private static String collapseNewlines( String in ) - { - StringBuffer buf = new StringBuffer(); - int numBlankLines = 0; - - BufferedReader reader = new BufferedReader( new StringReader( in ) ); - String line = null; - try - { - while( ( line = reader.readLine() ) != null ) - { - // how blank lines is this? - boolean isBlank = line.trim().length() == 0; - if( isBlank ) - { - numBlankLines++; - - // stop printing blank lines after the first one - if( numBlankLines < 2 ) - { - buf.append( line ); - buf.append( "\n" ); - } - } - else - { - numBlankLines = 0; - buf.append( line ); - buf.append( "\n" ); - } - } - } - catch( IOException ex ) - { - // StringReader will never throw an IOExecption here... - } - return buf.toString(); - } -} -- cgit v1.2.3 From b10af1dbfceb913689226c8fb75641f275eb11b4 Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 9 Aug 2014 16:42:25 -0400 Subject: added sorting for deobfuscated classes --- src/cuchaz/enigma/gui/Gui.java | 46 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 57c6ef7b..61e66e04 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -60,11 +60,12 @@ import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; -import com.beust.jcommander.internal.Lists; - import jsyntaxpane.DefaultSyntaxKit; import jsyntaxpane.SyntaxDocument; import jsyntaxpane.Token; + +import com.beust.jcommander.internal.Lists; + import cuchaz.enigma.ClassFile; import cuchaz.enigma.Constants; import cuchaz.enigma.mapping.ArgumentEntry; @@ -78,6 +79,7 @@ import cuchaz.enigma.mapping.MethodEntry; public class Gui { private static Comparator m_obfuscatedClassSorter; + private static Comparator> m_deobfuscatedClassSorter; static { @@ -94,6 +96,36 @@ public class Gui return a.getName().compareTo( b.getName() ); } }; + + m_deobfuscatedClassSorter = new Comparator>( ) + { + @Override + public int compare( Map.Entry a, Map.Entry b ) + { + // I can never keep this rule straight when writing these damn things... + // a < b => -1, a == b => 0, a > b => +1 + + String[] aparts = a.getValue().split( "\\." ); + String[] bparts = b.getValue().split( "\\." ); + for( int i=0; true; i++ ) + { + if( i >= aparts.length ) + { + return -1; + } + else if( i >= bparts.length ) + { + return 1; + } + + int result = aparts[i].compareTo( bparts[i] ); + if( result != 0 ) + { + return result; + } + } + } + }; } private GuiController m_controller; @@ -520,11 +552,11 @@ public class Gui m_closeMappingsMenu.setEnabled( false ); } - public void setObfClasses( List classes ) + public void setObfClasses( List obfClasses ) { - if( classes != null ) + if( obfClasses != null ) { - Vector sortedClasses = new Vector( classes ); + Vector sortedClasses = new Vector( obfClasses ); Collections.sort( sortedClasses, m_obfuscatedClassSorter ); m_obfClasses.setListData( sortedClasses ); } @@ -538,7 +570,9 @@ public class Gui { if( deobfClasses != null ) { - m_deobfClasses.setListData( new Vector>( deobfClasses.entrySet() ) ); + Vector> sortedClasses = new Vector>( deobfClasses.entrySet() ); + Collections.sort( sortedClasses, m_deobfuscatedClassSorter ); + m_deobfClasses.setListData( sortedClasses ); } else { -- cgit v1.2.3 From d24d2b9ad9b5c895020b56f700a72906346482e5 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 10 Aug 2014 01:03:40 -0400 Subject: completely re-wrote token recognizer to bootstrap from Procyon's AST changed imports to guava instead of whatever collections library happened to be on my classpath --- src/cuchaz/enigma/Deobfuscator.java | 114 ++-- src/cuchaz/enigma/analysis/Analyzer.java | 263 --------- src/cuchaz/enigma/analysis/ClassNameIndex.java | 19 - .../enigma/analysis/JavaSourceFromString.java | 31 -- src/cuchaz/enigma/analysis/Lexer.java | 79 --- src/cuchaz/enigma/analysis/SourceIndex.java | 99 ++-- src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 618 +++++++++++++++++++++ src/cuchaz/enigma/analysis/SourcedAst.java | 140 ----- src/cuchaz/enigma/analysis/Token.java | 49 ++ .../enigma/gui/ClassInheritanceTreeNode.java | 2 +- src/cuchaz/enigma/gui/Gui.java | 29 +- src/cuchaz/enigma/gui/GuiController.java | 56 +- src/cuchaz/enigma/mapping/Ancestries.java | 2 +- src/cuchaz/enigma/mapping/ClassMapping.java | 24 +- src/cuchaz/enigma/mapping/EntryPair.java | 5 +- src/cuchaz/enigma/mapping/Mappings.java | 2 +- 16 files changed, 865 insertions(+), 667 deletions(-) delete mode 100644 src/cuchaz/enigma/analysis/Analyzer.java delete mode 100644 src/cuchaz/enigma/analysis/ClassNameIndex.java delete mode 100644 src/cuchaz/enigma/analysis/JavaSourceFromString.java delete mode 100644 src/cuchaz/enigma/analysis/Lexer.java create mode 100644 src/cuchaz/enigma/analysis/SourceIndexVisitor.java delete mode 100644 src/cuchaz/enigma/analysis/SourcedAst.java create mode 100644 src/cuchaz/enigma/analysis/Token.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index e6e647e9..8eda889f 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -10,12 +10,10 @@ ******************************************************************************/ package cuchaz.enigma; -import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.StringReader; import java.io.StringWriter; import java.util.Enumeration; import java.util.List; @@ -23,11 +21,26 @@ import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import com.beust.jcommander.internal.Lists; -import com.strobel.decompiler.Decompiler; +import com.google.common.collect.Lists; +import com.strobel.assembler.metadata.MemberReference; +import com.strobel.assembler.metadata.MetadataSystem; +import com.strobel.assembler.metadata.TypeDefinition; +import com.strobel.componentmodel.Key; +import com.strobel.decompiler.DecompilerContext; import com.strobel.decompiler.DecompilerSettings; import com.strobel.decompiler.PlainTextOutput; +import com.strobel.decompiler.languages.java.JavaOutputVisitor; +import com.strobel.decompiler.languages.java.ast.AstBuilder; +import com.strobel.decompiler.languages.java.ast.AstNode; +import com.strobel.decompiler.languages.java.ast.CompilationUnit; +import com.strobel.decompiler.languages.java.ast.Identifier; +import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; +import com.strobel.decompiler.languages.java.ast.InvocationExpression; +import com.strobel.decompiler.languages.java.ast.Keys; +import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; +import cuchaz.enigma.analysis.SourceIndex; +import cuchaz.enigma.analysis.SourceIndexVisitor; import cuchaz.enigma.mapping.Ancestries; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; @@ -91,7 +104,6 @@ public class Deobfuscator // config the decompiler m_settings = DecompilerSettings.javaDefaults(); - m_settings.setForceExplicitImports( true ); m_settings.setShowSyntheticMembers( true ); // init mappings @@ -157,7 +169,7 @@ public class Deobfuscator } } - public String getSource( final ClassFile classFile ) + public SourceIndex getSource( final ClassFile classFile ) { // is this class deobfuscated? // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out @@ -170,45 +182,79 @@ public class Deobfuscator } // decompile it! + TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( deobfName ).resolve(); + DecompilerContext context = new DecompilerContext(); + context.setCurrentType( resolvedType ); + context.setSettings( m_settings ); + AstBuilder builder = new AstBuilder( context ); + builder.addType( resolvedType ); + builder.runTransformations( null ); + CompilationUnit root = builder.getCompilationUnit(); + + // render the AST into source StringWriter buf = new StringWriter(); - Decompiler.decompile( deobfName, new PlainTextOutput( buf ), m_settings ); - return fixSource( buf.toString() ); + root.acceptVisitor( new InsertParenthesesVisitor(), null ); + root.acceptVisitor( new JavaOutputVisitor( new PlainTextOutput( buf ), m_settings ), null ); + + // build the source index + SourceIndex index = new SourceIndex( buf.toString() ); + root.acceptVisitor( new SourceIndexVisitor(), index ); + + return index; } - private String fixSource( String source ) + private void dump( AstNode node, int depth ) { - // fix the imports from the default package in the source - try + StringBuilder buf = new StringBuilder(); + for( int i=0; i %s)", memberRef.getDeclaringType(), memberRef.getName(), memberRef.getSignature() ) ); + } + + for( Key key : Keys.ALL_KEYS ) + { + if( key == Keys.MEMBER_REFERENCE ) { - String[] parts = line.trim().split( " " ); - if( parts.length == 2 && parts[0].equals( "import" ) ) - { - // is this an (illegal) import from the default package? - String className = parts[1]; - if( className.indexOf( '.' ) < 0 ) - { - // this is an illegal import, replace it - line = "import __DEFAULT__." + parts[1]; - } - } - - buf.append( line ); - buf.append( "\n" ); + continue; + } + Object val = node.getUserData( key ); + if( val != null ) + { + buf.append( String.format( " (%s=%s)", key, val ) ); } - return buf.toString(); } - catch( IOException ex ) + + + if( node instanceof Identifier ) + { + Identifier n = (Identifier)node; + buf.append( ": " + n.getName() ); + } + else if( node instanceof MemberReferenceExpression ) + { + MemberReferenceExpression n = (MemberReferenceExpression)node; + buf.append( ": " + n.getTarget() + "." + n.getMemberName() ); + } + else if( node instanceof InvocationExpression ) { - // dealing with IOExceptions on StringReaders is silly... - throw new Error( ex ); + + } + + System.out.println( buf ); + + for( AstNode child : node.getChildren() ) + { + dump( child, depth + 1 ); } } - + // NOTE: these methods are a bit messy... oh well public void rename( Entry obfEntry, String newName ) diff --git a/src/cuchaz/enigma/analysis/Analyzer.java b/src/cuchaz/enigma/analysis/Analyzer.java deleted file mode 100644 index 2b7e0b0b..00000000 --- a/src/cuchaz/enigma/analysis/Analyzer.java +++ /dev/null @@ -1,263 +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.analysis; - -import java.io.IOException; -import java.util.Arrays; - -import javax.tools.JavaCompiler; -import javax.tools.StandardJavaFileManager; -import javax.tools.ToolProvider; - -import jsyntaxpane.Token; -import jsyntaxpane.TokenType; - -import com.sun.source.tree.ArrayTypeTree; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.PrimitiveTypeTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.Tree.Kind; -import com.sun.source.tree.VariableTree; -import com.sun.source.util.JavacTask; -import com.sun.source.util.TreeScanner; -import com.sun.source.util.Trees; - -import cuchaz.enigma.mapping.ArgumentEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.MethodEntry; - -class TreeVisitor extends TreeScanner -{ - private SourceIndex m_index; - - public TreeVisitor( SourceIndex index ) - { - m_index = index; - } - - @Override - public CompilationUnitTree visitClass( ClassTree classTree, SourcedAst ast ) - { - ClassEntry classEntry = indexClass( classTree, ast ); - - // look at the class members - for( Tree memberTree : classTree.getMembers() ) - { - if( memberTree.getKind() == Kind.VARIABLE ) - { - indexField( (VariableTree)memberTree, ast, classEntry ); - } - else if( memberTree.getKind() == Kind.METHOD ) - { - MethodTree methodTree = (MethodTree)memberTree; - MethodEntry methodEntry = indexMethod( methodTree, ast, classEntry ); - - // look at method arguments - int argNum = 0; - for( VariableTree variableTree : methodTree.getParameters() ) - { - indexArgument( variableTree, ast, methodEntry, argNum++ ); - } - } - } - - return super.visitClass( classTree, ast ); - } - - private ClassEntry indexClass( ClassTree classTree, SourcedAst ast ) - { - // index the class name - ClassEntry classEntry = indexClassIdentifier( classTree, ast ); - assert( classEntry != null ); - - // index the extends clause - indexClassIdentifier( classTree.getExtendsClause(), ast ); - - // index the implements clauses - for( Tree implementsTree : classTree.getImplementsClause() ) - { - indexClassIdentifier( implementsTree, ast ); - } - - return classEntry; - } - - private FieldEntry indexField( VariableTree variableTree, SourcedAst ast, ClassEntry classEntry ) - { - // index the field name - FieldEntry entry = new FieldEntry( classEntry, variableTree.getName().toString() ); - Token nameToken = new Lexer( ast.getSource( variableTree ) ).getFirstIdentifierMatching( variableTree.getName() ); - addToken( entry, nameToken, variableTree, ast ); - - // index the field type - indexClassIdentifier( variableTree.getType(), ast ); - - return entry; - } - - private MethodEntry indexMethod( MethodTree methodTree, SourcedAst ast, ClassEntry classEntry ) - { - // build the entry - StringBuilder signature = new StringBuilder(); - signature.append( "(" ); - for( VariableTree variableTree : methodTree.getParameters() ) - { - signature.append( toJvmType( variableTree.getType(), ast ) ); - } - signature.append( ")" ); - if( methodTree.getReturnType() != null ) - { - signature.append( toJvmType( methodTree.getReturnType(), ast ) ); - } - else - { - signature.append( "V" ); - } - MethodEntry entry = new MethodEntry( classEntry, methodTree.getName().toString(), signature.toString() ); - - // lex the source at this tree node - Lexer lexer = new Lexer( ast.getSource( methodTree ) ); - for( Token token : lexer ) - { - // scan until we find an identifier that matches the method name - if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) ) - { - addToken( entry, token, methodTree, ast ); - break; - } - } - - return entry; - } - - private void indexArgument( VariableTree variableTree, SourcedAst ast, MethodEntry methodEntry, int index ) - { - // index argument name - ArgumentEntry entry = new ArgumentEntry( methodEntry, index, variableTree.getName().toString() ); - Token token = new Lexer( ast.getSource( variableTree ) ).getLastIdentifier(); - addToken( entry, token, variableTree, ast ); - - // index argument type - indexClassIdentifier( variableTree.getType(), ast ); - } - - private ClassEntry indexClassIdentifier( Tree tree, SourcedAst ast ) - { - if( tree == null ) - { - return null; - } - - Lexer lexer = new Lexer( ast.getSource( tree ) ); - Token token = lexer.getFirstIdentifier(); - if( token == null ) - { - return null; - } - - ClassEntry classEntry = new ClassEntry( ast.getFullClassName( lexer.getText( token ) ) ); - addToken( classEntry, token, tree, ast ); - return classEntry; - } - - private void addToken( Entry entry, Token token, Tree tree, SourcedAst ast ) - { - if( token == null ) - { - throw new IllegalArgumentException( "token cannot be null!" ); - } - - // offset the token by the tree - Token offsetToken = new Token( token.type, token.start + ast.getStart( tree ), token.length ); - - m_index.add( entry, offsetToken ); - } - - private String toJvmType( Tree tree, SourcedAst ast ) - { - switch( tree.getKind() ) - { - case PRIMITIVE_TYPE: - { - PrimitiveTypeTree primitiveTypeTree = (PrimitiveTypeTree)tree; - switch( primitiveTypeTree.getPrimitiveTypeKind() ) - { - case BOOLEAN: return "Z"; - case BYTE: return "B"; - case CHAR: return "C"; - case DOUBLE: return "D"; - case FLOAT: return "F"; - case INT: return "I"; - case LONG: return "J"; - case SHORT: return "S"; - case VOID: return "V"; - - default: - throw new Error( "Unsupported primitive type: " + primitiveTypeTree.getPrimitiveTypeKind() ); - } - } - - case IDENTIFIER: - { - IdentifierTree identifierTree = (IdentifierTree)tree; - String className = identifierTree.getName().toString(); - className = ast.getFullClassName( className ); - return "L" + className.replace( ".", "/" ) + ";"; - } - - case ARRAY_TYPE: - { - ArrayTypeTree arrayTree = (ArrayTypeTree)tree; - return "[" + toJvmType( arrayTree.getType(), ast ); - } - - - default: - throw new Error( "Unsupported type kind: " + tree.getKind() ); - } - } -} - -public class Analyzer -{ - public static SourceIndex analyze( String className, String source ) - { - SourceIndex index = new SourceIndex(); - SourcedAst ast = getAst( className, source ); - ast.visit( new TreeVisitor( index ) ); - return index; - } - - private static SourcedAst getAst( String className, String source ) - { - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null ); - JavaSourceFromString unit = new JavaSourceFromString( className, source ); - JavacTask task = (JavacTask)compiler.getTask( null, fileManager, null, null, null, Arrays.asList( unit ) ); - - try - { - return new SourcedAst( - task.parse().iterator().next(), - Trees.instance( task ) - ); - } - catch( IOException ex ) - { - throw new Error( ex ); - } - } -} diff --git a/src/cuchaz/enigma/analysis/ClassNameIndex.java b/src/cuchaz/enigma/analysis/ClassNameIndex.java deleted file mode 100644 index ea3e2cae..00000000 --- a/src/cuchaz/enigma/analysis/ClassNameIndex.java +++ /dev/null @@ -1,19 +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.analysis; - -import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.util.TreeScanner; - -public class ClassNameIndex extends TreeScanner -{ - -} diff --git a/src/cuchaz/enigma/analysis/JavaSourceFromString.java b/src/cuchaz/enigma/analysis/JavaSourceFromString.java deleted file mode 100644 index cf5c4c27..00000000 --- a/src/cuchaz/enigma/analysis/JavaSourceFromString.java +++ /dev/null @@ -1,31 +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.analysis; - -import java.net.URI; - -import javax.tools.SimpleJavaFileObject; - -public class JavaSourceFromString extends SimpleJavaFileObject -{ - private final String m_source; - - JavaSourceFromString( String name, String source ) - { - super( URI.create( "string:///" + name.replace( '.', '/' ) + Kind.SOURCE.extension ), Kind.SOURCE ); - m_source = source; - } - - public CharSequence getCharContent( boolean ignoreEncodingErrors ) - { - return m_source; - } -} diff --git a/src/cuchaz/enigma/analysis/Lexer.java b/src/cuchaz/enigma/analysis/Lexer.java deleted file mode 100644 index 602e3a9b..00000000 --- a/src/cuchaz/enigma/analysis/Lexer.java +++ /dev/null @@ -1,79 +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.analysis; - -import java.util.Iterator; - -import jsyntaxpane.SyntaxDocument; -import jsyntaxpane.Token; -import jsyntaxpane.TokenType; -import jsyntaxpane.lexers.JavaLexer; - -public class Lexer implements Iterable -{ - private SyntaxDocument m_doc; - private Iterator m_iter; - - public Lexer( CharSequence source ) - { - m_doc = new SyntaxDocument( new JavaLexer() ); - m_doc.append( source.toString() ); - m_iter = m_doc.getTokens( 0, m_doc.getLength() ); - } - - @Override - public Iterator iterator( ) - { - return m_iter; - } - - public String getText( Token token ) - { - return token.getString( m_doc ); - } - - public Token getFirstIdentifier( ) - { - for( Token token : this ) - { - if( token.type == TokenType.IDENTIFIER ) - { - return token; - } - } - return null; - } - - public Token getFirstIdentifierMatching( CharSequence val ) - { - for( Token token : this ) - { - if( token.type == TokenType.IDENTIFIER && getText( token ).equals( val.toString() ) ) - { - return token; - } - } - return null; - } - - public Token getLastIdentifier( ) - { - Token lastToken = null; - for( Token token : this ) - { - if( token.type == TokenType.IDENTIFIER ) - { - lastToken = token; - } - } - return lastToken; - } -} diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index de163087..398a50d1 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -10,70 +10,101 @@ ******************************************************************************/ package cuchaz.enigma.analysis; -import java.util.Collection; -import java.util.Iterator; +import java.util.List; import java.util.Map; +import java.util.TreeMap; -import jsyntaxpane.Token; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.strobel.decompiler.languages.Region; +import com.strobel.decompiler.languages.java.ast.AstNode; import cuchaz.enigma.mapping.Entry; -public class SourceIndex implements Iterable> +public class SourceIndex { - private Multimap m_entryToTokens; + private String m_source; + private TreeMap m_tokens; + private List m_lineOffsets; - public SourceIndex( ) + public SourceIndex( String source ) { - m_entryToTokens = HashMultimap.create(); + m_source = source; + m_tokens = Maps.newTreeMap(); + m_lineOffsets = Lists.newArrayList(); + + // count the lines + m_lineOffsets.add( 0 ); + for( int i=0; i> iterator( ) + public Token getToken( AstNode node ) { - return m_entryToTokens.entries().iterator(); + // get a token for this node's region + Region region = node.getRegion(); + if( region.getBeginLine() == 0 || region.getEndLine() == 0 ) + { + throw new IllegalArgumentException( "Invalid region: " + region ); + } + return new Token( + toPos( region.getBeginLine(), region.getBeginColumn() ), + toPos( region.getEndLine(), region.getEndColumn() ) + ); } - public Collection tokens( ) + public void add( AstNode node, Entry entry ) { - return m_entryToTokens.values(); + m_tokens.put( getToken( node ), entry ); } - public Entry getEntry( Token token ) + public void add( Token token, Entry entry ) + { + m_tokens.put( token, entry ); + } + + public Token getToken( int pos ) { - // linear search is fast enough for now - for( Map.Entry entry : this ) + Map.Entry mapEntry = m_tokens.floorEntry( new Token( pos, pos ) ); + if( mapEntry == null ) { - if( entry.getValue().equals( token ) ) - { - return entry.getKey(); - } + return null; + } + Token token = mapEntry.getKey(); + if( token.contains( pos ) ) + { + return token; } return null; } - public Map.Entry getEntry( int pos ) + public Entry getEntry( Token token ) { - // linear search is fast enough for now - for( Map.Entry entry : this ) + if( token == null ) { - Token token = entry.getValue(); - if( pos >= token.start && pos <= token.end() ) - { - return entry; - } + return null; } - return null; + return m_tokens.get( token ); + } + + public Iterable tokens( ) + { + return m_tokens.keySet(); } - public Collection getTokens( Entry entry ) + private int toPos( int line, int col ) { - return m_entryToTokens.get( entry ); + // line and col are 1-based + return m_lineOffsets.get( line - 1 ) + col - 1; } } diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java new file mode 100644 index 00000000..2a26c85f --- /dev/null +++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java @@ -0,0 +1,618 @@ +/******************************************************************************* + * 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.analysis; + +import com.strobel.assembler.metadata.FieldDefinition; +import com.strobel.assembler.metadata.MemberReference; +import com.strobel.assembler.metadata.MethodDefinition; +import com.strobel.assembler.metadata.ParameterDefinition; +import com.strobel.assembler.metadata.TypeDefinition; +import com.strobel.assembler.metadata.TypeReference; +import com.strobel.componentmodel.Key; +import com.strobel.decompiler.languages.TextLocation; +import com.strobel.decompiler.languages.java.ast.Annotation; +import com.strobel.decompiler.languages.java.ast.AnonymousObjectCreationExpression; +import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression; +import com.strobel.decompiler.languages.java.ast.ArrayInitializerExpression; +import com.strobel.decompiler.languages.java.ast.ArraySpecifier; +import com.strobel.decompiler.languages.java.ast.AssertStatement; +import com.strobel.decompiler.languages.java.ast.AssignmentExpression; +import com.strobel.decompiler.languages.java.ast.AstNode; +import com.strobel.decompiler.languages.java.ast.BinaryOperatorExpression; +import com.strobel.decompiler.languages.java.ast.BlockStatement; +import com.strobel.decompiler.languages.java.ast.BreakStatement; +import com.strobel.decompiler.languages.java.ast.CaseLabel; +import com.strobel.decompiler.languages.java.ast.CastExpression; +import com.strobel.decompiler.languages.java.ast.CatchClause; +import com.strobel.decompiler.languages.java.ast.ClassOfExpression; +import com.strobel.decompiler.languages.java.ast.Comment; +import com.strobel.decompiler.languages.java.ast.CompilationUnit; +import com.strobel.decompiler.languages.java.ast.ComposedType; +import com.strobel.decompiler.languages.java.ast.ConditionalExpression; +import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; +import com.strobel.decompiler.languages.java.ast.ContinueStatement; +import com.strobel.decompiler.languages.java.ast.DoWhileStatement; +import com.strobel.decompiler.languages.java.ast.EmptyStatement; +import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; +import com.strobel.decompiler.languages.java.ast.Expression; +import com.strobel.decompiler.languages.java.ast.ExpressionStatement; +import com.strobel.decompiler.languages.java.ast.FieldDeclaration; +import com.strobel.decompiler.languages.java.ast.ForEachStatement; +import com.strobel.decompiler.languages.java.ast.ForStatement; +import com.strobel.decompiler.languages.java.ast.GotoStatement; +import com.strobel.decompiler.languages.java.ast.IAstVisitor; +import com.strobel.decompiler.languages.java.ast.Identifier; +import com.strobel.decompiler.languages.java.ast.IdentifierExpression; +import com.strobel.decompiler.languages.java.ast.IfElseStatement; +import com.strobel.decompiler.languages.java.ast.ImportDeclaration; +import com.strobel.decompiler.languages.java.ast.IndexerExpression; +import com.strobel.decompiler.languages.java.ast.InstanceInitializer; +import com.strobel.decompiler.languages.java.ast.InstanceOfExpression; +import com.strobel.decompiler.languages.java.ast.InvocationExpression; +import com.strobel.decompiler.languages.java.ast.JavaTokenNode; +import com.strobel.decompiler.languages.java.ast.Keys; +import com.strobel.decompiler.languages.java.ast.LabelStatement; +import com.strobel.decompiler.languages.java.ast.LabeledStatement; +import com.strobel.decompiler.languages.java.ast.LambdaExpression; +import com.strobel.decompiler.languages.java.ast.LocalTypeDeclarationStatement; +import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; +import com.strobel.decompiler.languages.java.ast.MethodDeclaration; +import com.strobel.decompiler.languages.java.ast.MethodGroupExpression; +import com.strobel.decompiler.languages.java.ast.NewLineNode; +import com.strobel.decompiler.languages.java.ast.NullReferenceExpression; +import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; +import com.strobel.decompiler.languages.java.ast.PackageDeclaration; +import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; +import com.strobel.decompiler.languages.java.ast.ParenthesizedExpression; +import com.strobel.decompiler.languages.java.ast.PrimitiveExpression; +import com.strobel.decompiler.languages.java.ast.ReturnStatement; +import com.strobel.decompiler.languages.java.ast.SimpleType; +import com.strobel.decompiler.languages.java.ast.SuperReferenceExpression; +import com.strobel.decompiler.languages.java.ast.SwitchSection; +import com.strobel.decompiler.languages.java.ast.SwitchStatement; +import com.strobel.decompiler.languages.java.ast.SynchronizedStatement; +import com.strobel.decompiler.languages.java.ast.TextNode; +import com.strobel.decompiler.languages.java.ast.ThisReferenceExpression; +import com.strobel.decompiler.languages.java.ast.ThrowStatement; +import com.strobel.decompiler.languages.java.ast.TryCatchStatement; +import com.strobel.decompiler.languages.java.ast.TypeDeclaration; +import com.strobel.decompiler.languages.java.ast.TypeParameterDeclaration; +import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression; +import com.strobel.decompiler.languages.java.ast.UnaryOperatorExpression; +import com.strobel.decompiler.languages.java.ast.VariableDeclarationStatement; +import com.strobel.decompiler.languages.java.ast.VariableInitializer; +import com.strobel.decompiler.languages.java.ast.WhileStatement; +import com.strobel.decompiler.languages.java.ast.WildcardType; +import com.strobel.decompiler.patterns.Pattern; + +import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; + +public class SourceIndexVisitor implements IAstVisitor +{ + @Override + public Void visitComment( Comment node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitPatternPlaceholder( AstNode node, Pattern pattern, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) + { + MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + MethodEntry methodEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); + if( node.getTarget() instanceof MemberReferenceExpression ) + { + index.add( ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(), methodEntry ); + } + + return recurse( node, index ); + } + + @Override + public Void visitTypeReference( TypeReferenceExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitJavaTokenNode( JavaTokenNode node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index ) + { + MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + if( ref != null ) + { + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); + index.add( node.getMemberNameToken(), fieldEntry ); + } + + return recurse( node, index ); + } + + @Override + public Void visitIdentifier( Identifier node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitNullReferenceExpression( NullReferenceExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitThisReferenceExpression( ThisReferenceExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitSuperReferenceExpression( SuperReferenceExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitClassOfExpression( ClassOfExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitBlockStatement( BlockStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitExpressionStatement( ExpressionStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitBreakStatement( BreakStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitContinueStatement( ContinueStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitDoWhileStatement( DoWhileStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitEmptyStatement( EmptyStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitIfElseStatement( IfElseStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitLabelStatement( LabelStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitLabeledStatement( LabeledStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitReturnStatement( ReturnStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitSwitchStatement( SwitchStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitSwitchSection( SwitchSection node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitCaseLabel( CaseLabel node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitThrowStatement( ThrowStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitCatchClause( CatchClause node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitAnnotation( Annotation node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitNewLine( NewLineNode node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitVariableDeclaration( VariableDeclarationStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitVariableInitializer( VariableInitializer node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitText( TextNode node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitImportDeclaration( ImportDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitSimpleType( SimpleType node, SourceIndex index ) + { + TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); + if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) + { + index.add( node.getIdentifierToken(), new ClassEntry( ref.getInternalName() ) ); + } + + return recurse( node, index ); + } + + @Override + public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) + { + MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + MethodEntry methodEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() ); + index.add( node.getNameToken(), methodEntry ); + + return recurse( node, index ); + } + + @Override + public Void visitInitializerBlock( InstanceInitializer node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) + { + MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); + index.add( node.getNameToken(), new ClassEntry( def.getDeclaringType().getInternalName() ) ); + + return recurse( node, index ); + } + + @Override + public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) + { + ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + MethodDefinition methodDef = (MethodDefinition)def.getMethod(); + MethodEntry methodEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); + ArgumentEntry argumentEntry = new ArgumentEntry( methodEntry, def.getPosition(), def.getName() ); + index.add( node.getNameToken(), argumentEntry ); + + return recurse( node, index ); + } + + @Override + public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) + { + FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); + assert( node.getVariables().size() == 1 ); + VariableInitializer variable = node.getVariables().firstOrNullObject(); + index.add( variable.getNameToken(), fieldEntry ); + + return recurse( node, index ); + } + + @Override + public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) + { + TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); + index.add( node.getNameToken(), new ClassEntry( def.getInternalName() ) ); + + return recurse( node, index ); + } + + @Override + public Void visitCompilationUnit( CompilationUnit node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitPackageDeclaration( PackageDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitArraySpecifier( ArraySpecifier node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitComposedType( ComposedType node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitWhileStatement( WhileStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitPrimitiveExpression( PrimitiveExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitCastExpression( CastExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitBinaryOperatorExpression( BinaryOperatorExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitInstanceOfExpression( InstanceOfExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitIndexerExpression( IndexerExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) + { + // TODO + return recurse( node, index ); + } + + @Override + public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitConditionalExpression( ConditionalExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitArrayInitializerExpression( ArrayInitializerExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitObjectCreationExpression( ObjectCreationExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitArrayCreationExpression( ArrayCreationExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitAssignmentExpression( AssignmentExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitForStatement( ForStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitForEachStatement( ForEachStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitTryCatchStatement( TryCatchStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitGotoStatement( GotoStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitParenthesizedExpression( ParenthesizedExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitSynchronizedStatement( SynchronizedStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitAnonymousObjectCreationExpression( AnonymousObjectCreationExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitWildcardType( WildcardType node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitMethodGroupExpression( MethodGroupExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitAssertStatement( AssertStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitLambdaExpression( LambdaExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitLocalTypeDeclarationStatement( LocalTypeDeclarationStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + private Void recurse( AstNode node, SourceIndex index ) + { + // TEMP: show the tree + System.out.println( getIndent( node ) + node.getClass().getSimpleName() + dumpUserData( node ) + " " + node.getRegion() ); + + for( final AstNode child : node.getChildren() ) + { + child.acceptVisitor( this, index ); + } + return null; + } + + private String dumpUserData( AstNode node ) + { + StringBuilder buf = new StringBuilder(); + for( Key key : Keys.ALL_KEYS ) + { + Object val = node.getUserData( key ); + if( val != null ) + { + buf.append( String.format( " [%s=%s]", key, val ) ); + } + } + return buf.toString(); + } + + private String getIndent( AstNode node ) + { + StringBuilder buf = new StringBuilder(); + int depth = getDepth( node ); + for( int i = 0; i < depth; i++ ) + { + buf.append( "\t" ); + } + return buf.toString(); + } + + private int getDepth( AstNode node ) + { + int depth = -1; + while( node != null ) + { + depth++; + node = node.getParent(); + } + return depth; + } +} diff --git a/src/cuchaz/enigma/analysis/SourcedAst.java b/src/cuchaz/enigma/analysis/SourcedAst.java deleted file mode 100644 index a88cc754..00000000 --- a/src/cuchaz/enigma/analysis/SourcedAst.java +++ /dev/null @@ -1,140 +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.analysis; - -import java.io.IOException; -import java.util.HashMap; - -import javassist.bytecode.Descriptor; - -import com.google.common.collect.Maps; -import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.tree.ImportTree; -import com.sun.source.tree.Tree; -import com.sun.source.util.SourcePositions; -import com.sun.source.util.Trees; - -public class SourcedAst -{ - private CompilationUnitTree m_tree; - private Trees m_trees; - private SourcePositions m_positions; - private HashMap m_classNameIndex; - private String m_packageName; - - public SourcedAst( CompilationUnitTree tree, Trees trees ) - { - m_tree = tree; - m_trees = trees; - m_positions = m_trees.getSourcePositions(); - m_classNameIndex = Maps.newHashMap(); - - // index all the class names from package imports - for( ImportTree importTree : m_tree.getImports() ) - { - // ignore static imports for now - if( importTree.isStatic() ) - { - continue; - } - - // get the full and simple class names - String fullName = Descriptor.toJvmName( importTree.getQualifiedIdentifier().toString() ); - String simpleName = fullName; - - if( fullName.startsWith( "__DEFAULT__/" ) ) - { - // remove the default package flag - fullName = fullName.substring( 12 ); - } - - String[] parts = fullName.split( "/" ); - if( parts.length > 0 ) - { - simpleName = parts[parts.length - 1]; - } - - m_classNameIndex.put( simpleName, fullName ); - } - - // get the package name - m_packageName = null; - if( m_tree.getPackageName() != null ) - { - m_packageName = Descriptor.toJvmName( m_tree.getPackageName().toString() ); - } - } - - public int getStart( Tree node ) - { - int pos = (int)m_positions.getStartPosition( m_tree, node ); - assert( pos >= 0 ); - return pos; - } - - public int getEnd( Tree node ) - { - int pos = (int)m_positions.getEndPosition( m_tree, node ); - assert( pos >= 0 ); - return pos; - } - - public int getLine( Tree node ) - { - return getLine( getStart( node ) ); - } - - public int getLine( int pos ) - { - return (int)m_tree.getLineMap().getLineNumber( pos ); - } - - public CharSequence getSource( ) - { - try - { - return m_tree.getSourceFile().getCharContent( true ); - } - catch( IOException ex ) - { - throw new Error( ex ); - } - } - - public CharSequence getSource( Tree node ) - { - return getSource().subSequence( getStart( node ), getEnd( node ) ); - } - - public void visit( TreeVisitor visitor ) - { - m_tree.accept( visitor, this ); - } - - public String getFullClassName( String simpleClassName ) - { - String fullClassName = m_classNameIndex.get( simpleClassName ); - if( fullClassName == null ) - { - if( m_packageName != null ) - { - // no mapping was found, assume it's in the package - fullClassName = m_packageName + "/" + simpleClassName; - } - else - { - // this must be in the default package - fullClassName = simpleClassName; - } - } - return fullClassName; - } -} diff --git a/src/cuchaz/enigma/analysis/Token.java b/src/cuchaz/enigma/analysis/Token.java new file mode 100644 index 00000000..74023e32 --- /dev/null +++ b/src/cuchaz/enigma/analysis/Token.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * 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.analysis; + +public class Token implements Comparable +{ + public int start; + public int end; + + public Token( int start, int end ) + { + this.start = start; + this.end = end; + } + + public boolean contains( int pos ) + { + return pos >= start && pos <= end; + } + + @Override + public int compareTo( Token other ) + { + return start - other.start; + } + + @Override + public boolean equals( Object other ) + { + if( other instanceof Token ) + { + return equals( (Token)other ); + } + return false; + } + + public boolean equals( Token other ) + { + return start == other.start && end == other.end; + } +} diff --git a/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java index d8e67554..61e582df 100644 --- a/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java +++ b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java @@ -14,7 +14,7 @@ import java.util.List; import javax.swing.tree.DefaultMutableTreeNode; -import com.beust.jcommander.internal.Lists; +import com.google.common.collect.Lists; import cuchaz.enigma.mapping.Ancestries; import cuchaz.enigma.mapping.Translator; diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 61e66e04..187852a2 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -62,12 +62,12 @@ import javax.swing.tree.TreePath; import jsyntaxpane.DefaultSyntaxKit; import jsyntaxpane.SyntaxDocument; -import jsyntaxpane.Token; -import com.beust.jcommander.internal.Lists; +import com.google.common.collect.Lists; import cuchaz.enigma.ClassFile; import cuchaz.enigma.Constants; +import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.Entry; @@ -643,7 +643,7 @@ public class Gui { try { - m_editor.getHighlighter().addHighlight( token.start, token.end(), painter ); + m_editor.getHighlighter().addHighlight( token.start, token.end, painter ); } catch( BadLocationException ex ) { @@ -740,22 +740,20 @@ public class Gui private void onCaretMove( int pos ) { - m_selectedEntryPair = m_controller.getEntryPair( pos ); - - boolean isEntry = m_selectedEntryPair != null; - boolean isClassEntry = isEntry && m_selectedEntryPair.obf instanceof ClassEntry; - boolean isMethodEntry = isEntry && m_selectedEntryPair.obf instanceof MethodEntry; - - if( isEntry ) - { - showEntryPair( m_selectedEntryPair ); - } - else + Token token = m_controller.getToken( pos ); + m_renameMenu.setEnabled( token != null ); + if( token == null ) { clearEntryPair(); + return; } - m_renameMenu.setEnabled( isEntry ); + m_selectedEntryPair = m_controller.getEntryPair( token ); + boolean isClassEntry = m_selectedEntryPair.obf instanceof ClassEntry; + boolean isMethodEntry = m_selectedEntryPair.obf instanceof MethodEntry; + + showEntryPair( m_selectedEntryPair ); + m_inheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); m_openEntryMenu.setEnabled( isClassEntry ); } @@ -803,6 +801,7 @@ public class Gui int lineNum = doc.getLineNumberAt( m_editor.getCaretPosition() ); try { + // TODO: give token to the controller so we can put the caret back there m_controller.rename( m_selectedEntryPair.obf, newName, lineNum ); } catch( IllegalNameException ex ) diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 2219e05b..e0aad860 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -17,15 +17,13 @@ import java.io.IOException; import java.util.List; import java.util.Map; -import jsyntaxpane.Token; - -import com.beust.jcommander.internal.Lists; -import com.beust.jcommander.internal.Maps; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import cuchaz.enigma.ClassFile; import cuchaz.enigma.Deobfuscator; -import cuchaz.enigma.analysis.Analyzer; import cuchaz.enigma.analysis.SourceIndex; +import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.EntryPair; @@ -105,41 +103,35 @@ public class GuiController deobfuscate( m_currentFile ); } - public EntryPair getEntryPair( int pos ) + public Token getToken( int pos ) { if( m_index == null ) { return null; } - Map.Entry deobfEntryAndToken = m_index.getEntry( pos ); - if( deobfEntryAndToken == null ) + return m_index.getToken( pos ); + } + + public EntryPair getEntryPair( Token token ) + { + if( m_index == null ) { return null; } - Entry deobfEntry = deobfEntryAndToken.getKey(); - Token token = deobfEntryAndToken.getValue(); - return new EntryPair( m_deobfuscator.obfuscateEntry( deobfEntry ), deobfEntry, token ); + + Entry deobfEntry = m_index.getEntry( token ); + return new EntryPair( m_deobfuscator.obfuscateEntry( deobfEntry ), deobfEntry ); } - public boolean entryHasMapping( int pos ) + public boolean entryHasMapping( Entry deobfEntry ) { - EntryPair pair = getEntryPair( pos ); - if( pair == null || pair.obf == null ) - { - return false; - } - return m_deobfuscator.hasMapping( pair.obf ); + return m_deobfuscator.hasMapping( m_deobfuscator.obfuscateEntry( deobfEntry ) ); } - public boolean entryIsObfuscatedIdenfitier( int pos ) + public boolean entryIsObfuscatedIdenfitier( Entry deobfEntry ) { - EntryPair pair = getEntryPair( pos ); - if( pair == null || pair.obf == null ) - { - return false; - } - return m_deobfuscator.entryIsObfuscatedIdenfitier( pair.obf ); + return m_deobfuscator.entryIsObfuscatedIdenfitier( m_deobfuscator.obfuscateEntry( deobfEntry ) ); } public ClassInheritanceTreeNode getClassInheritance( ClassEntry classEntry ) @@ -210,23 +202,21 @@ public class GuiController @Override public void run( ) { - // deobfuscate,decompile the bytecode - String source = m_deobfuscator.getSource( classFile ); - m_gui.setSource( source, lineNum ); - - // index the source file - m_index = Analyzer.analyze( classFile.getName(), source ); + // decopmile,deobfuscate the bytecode + m_index = m_deobfuscator.getSource( classFile ); + m_gui.setSource( m_index.getSource(), lineNum ); // set the highlighted tokens List obfuscatedTokens = Lists.newArrayList(); List deobfuscatedTokens = Lists.newArrayList(); for( Token token : m_index.tokens() ) { - if( entryHasMapping( token.start ) ) + Entry entry = m_index.getEntry( token ); + if( entryHasMapping( entry ) ) { deobfuscatedTokens.add( token ); } - else if( entryIsObfuscatedIdenfitier( token.start ) ) + else if( entryIsObfuscatedIdenfitier( entry ) ) { obfuscatedTokens.add( token ); } diff --git a/src/cuchaz/enigma/mapping/Ancestries.java b/src/cuchaz/enigma/mapping/Ancestries.java index f77a00eb..894cf802 100644 --- a/src/cuchaz/enigma/mapping/Ancestries.java +++ b/src/cuchaz/enigma/mapping/Ancestries.java @@ -26,7 +26,7 @@ import javassist.CtClass; import javassist.NotFoundException; import javassist.bytecode.Descriptor; -import com.beust.jcommander.internal.Lists; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import cuchaz.enigma.Constants; diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index a1cc775f..c6826f31 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -13,7 +13,7 @@ package cuchaz.enigma.mapping; import java.io.Serializable; import java.util.Map; -import com.beust.jcommander.internal.Maps; +import com.google.common.collect.Maps; public class ClassMapping implements Serializable, Comparable { @@ -135,16 +135,16 @@ public class ClassMapping implements Serializable, Comparable public void setMethodNameAndSignature( String obfName, String obfSignature, String deobfName, String deobfSignature ) { - MethodMapping methodIndex = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) ); - if( methodIndex == null ) + MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) ); + if( methodMapping == null ) { - methodIndex = createMethodIndex( obfName, obfSignature ); + methodMapping = createMethodIndex( obfName, obfSignature ); } - m_methodsByDeobf.remove( getMethodKey( methodIndex.getDeobfName(), methodIndex.getDeobfSignature() ) ); - methodIndex.setDeobfName( deobfName ); - methodIndex.setDeobfSignature( deobfSignature ); - m_methodsByDeobf.put( getMethodKey( deobfName, deobfSignature ), methodIndex ); + m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ) ); + methodMapping.setDeobfName( deobfName ); + methodMapping.setDeobfSignature( deobfSignature ); + m_methodsByDeobf.put( getMethodKey( deobfName, deobfSignature ), methodMapping ); } public void updateDeobfMethodSignatures( Translator translator ) @@ -167,11 +167,11 @@ public class ClassMapping implements Serializable, Comparable private MethodMapping createMethodIndex( String obfName, String obfSignature ) { - MethodMapping methodIndex = new MethodMapping( obfName, obfName, obfSignature, obfSignature ); + MethodMapping methodMapping = new MethodMapping( obfName, obfName, obfSignature, obfSignature ); String key = getMethodKey( obfName, obfSignature ); - m_methodsByObf.put( key, methodIndex ); - m_methodsByDeobf.put( key, methodIndex ); - return methodIndex; + m_methodsByObf.put( key, methodMapping ); + m_methodsByDeobf.put( key, methodMapping ); + return methodMapping; } @Override diff --git a/src/cuchaz/enigma/mapping/EntryPair.java b/src/cuchaz/enigma/mapping/EntryPair.java index 1bf9be09..f94d77ea 100644 --- a/src/cuchaz/enigma/mapping/EntryPair.java +++ b/src/cuchaz/enigma/mapping/EntryPair.java @@ -10,19 +10,16 @@ ******************************************************************************/ 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, Token token ) + public EntryPair( T obf, T deobf ) { this.obf = obf; this.deobf = deobf; - this.token = token; } } diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 2a39057a..4dff6935 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -17,7 +17,7 @@ import java.io.Serializable; import java.util.Map; import java.util.zip.GZIPInputStream; -import com.beust.jcommander.internal.Maps; +import com.google.common.collect.Maps; import cuchaz.enigma.Util; -- cgit v1.2.3 From 044f109bfa9ae55430456b1cf21ed56a3902bff2 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 10 Aug 2014 16:58:49 -0400 Subject: fixed recognition of static initializers fixed identifier off-by-one error --- src/cuchaz/enigma/analysis/SourceIndex.java | 16 +- src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 271 +++++++++++---------- 2 files changed, 153 insertions(+), 134 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 398a50d1..7981f879 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -57,10 +57,24 @@ public class SourceIndex { throw new IllegalArgumentException( "Invalid region: " + region ); } - return new Token( + Token token = new Token( toPos( region.getBeginLine(), region.getBeginColumn() ), toPos( region.getEndLine(), region.getEndColumn() ) ); + + // HACKHACK: sometimes node regions are off by one + // I think this is a bug in Procyon, but it's easy to work around + if( !Character.isJavaIdentifierStart( m_source.charAt( token.start ) ) ) + { + token.start++; + token.end++; + if( !Character.isJavaIdentifierStart( m_source.charAt( token.start ) ) ) + { + throw new IllegalArgumentException( "Region " + region + " does not describe valid token: '" + m_source.substring( token.start, token.end ) + "'" ); + } + } + + return token; } public void add( AstNode node, Entry entry ) diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java index 2a26c85f..5a64e4e4 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java @@ -42,7 +42,6 @@ import com.strobel.decompiler.languages.java.ast.ContinueStatement; import com.strobel.decompiler.languages.java.ast.DoWhileStatement; import com.strobel.decompiler.languages.java.ast.EmptyStatement; import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; -import com.strobel.decompiler.languages.java.ast.Expression; import com.strobel.decompiler.languages.java.ast.ExpressionStatement; import com.strobel.decompiler.languages.java.ast.FieldDeclaration; import com.strobel.decompiler.languages.java.ast.ForEachStatement; @@ -101,289 +100,344 @@ import cuchaz.enigma.mapping.MethodEntry; public class SourceIndexVisitor implements IAstVisitor { @Override - public Void visitComment( Comment node, SourceIndex index ) + public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) { + MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + MethodEntry methodEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); + if( node.getTarget() instanceof MemberReferenceExpression ) + { + index.add( ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(), methodEntry ); + } + return recurse( node, index ); } @Override - public Void visitPatternPlaceholder( AstNode node, Pattern pattern, SourceIndex index ) + public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index ) { + MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + if( ref != null ) + { + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); + index.add( node.getMemberNameToken(), fieldEntry ); + } + return recurse( node, index ); } @Override - public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) + public Void visitSimpleType( SimpleType node, SourceIndex index ) { - MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); - ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); - MethodEntry methodEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); - if( node.getTarget() instanceof MemberReferenceExpression ) + TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); + if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) { - index.add( ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(), methodEntry ); + index.add( node.getIdentifierToken(), new ClassEntry( ref.getInternalName() ) ); } return recurse( node, index ); } @Override - public Void visitTypeReference( TypeReferenceExpression node, SourceIndex index ) + public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) { + MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); + + // static initializers don't have identifier tokens + if( !def.getName().equals( "" ) ) + { + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + MethodEntry methodEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() ); + index.add( node.getNameToken(), methodEntry ); + } + return recurse( node, index ); } @Override - public Void visitJavaTokenNode( JavaTokenNode node, SourceIndex index ) + public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) { + MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); + index.add( node.getNameToken(), new ClassEntry( def.getDeclaringType().getInternalName() ) ); + return recurse( node, index ); } @Override - public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index ) + public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) { - MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); - if( ref != null ) - { - ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); - FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); - index.add( node.getMemberNameToken(), fieldEntry ); - } + ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + MethodDefinition methodDef = (MethodDefinition)def.getMethod(); + MethodEntry methodEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); + ArgumentEntry argumentEntry = new ArgumentEntry( methodEntry, def.getPosition(), def.getName() ); + index.add( node.getNameToken(), argumentEntry ); return recurse( node, index ); } @Override - public Void visitIdentifier( Identifier node, SourceIndex index ) + public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) { + FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); + assert( node.getVariables().size() == 1 ); + VariableInitializer variable = node.getVariables().firstOrNullObject(); + index.add( variable.getNameToken(), fieldEntry ); + return recurse( node, index ); } @Override - public Void visitNullReferenceExpression( NullReferenceExpression node, SourceIndex index ) + public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) { + TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); + index.add( node.getNameToken(), new ClassEntry( def.getInternalName() ) ); + return recurse( node, index ); } + private Void recurse( AstNode node, SourceIndex index ) + { + // TEMP: show the tree + System.out.println( getIndent( node ) + node.getClass().getSimpleName() + dumpUserData( node ) + " " + node.getRegion() ); + + for( final AstNode child : node.getChildren() ) + { + child.acceptVisitor( this, index ); + } + return null; + } + + private String dumpUserData( AstNode node ) + { + StringBuilder buf = new StringBuilder(); + for( Key key : Keys.ALL_KEYS ) + { + Object val = node.getUserData( key ); + if( val != null ) + { + buf.append( String.format( " [%s=%s]", key, val ) ); + } + } + return buf.toString(); + } + + private String getIndent( AstNode node ) + { + StringBuilder buf = new StringBuilder(); + int depth = getDepth( node ); + for( int i = 0; i < depth; i++ ) + { + buf.append( "\t" ); + } + return buf.toString(); + } + + private int getDepth( AstNode node ) + { + int depth = -1; + while( node != null ) + { + depth++; + node = node.getParent(); + } + return depth; + } + + // OVERRIDES WE DON'T CARE ABOUT + @Override - public Void visitThisReferenceExpression( ThisReferenceExpression node, SourceIndex index ) + public Void visitComment( Comment node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitSuperReferenceExpression( SuperReferenceExpression node, SourceIndex index ) + public Void visitPatternPlaceholder( AstNode node, Pattern pattern, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitClassOfExpression( ClassOfExpression node, SourceIndex index ) + public Void visitTypeReference( TypeReferenceExpression node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitBlockStatement( BlockStatement node, SourceIndex index ) + public Void visitJavaTokenNode( JavaTokenNode node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitExpressionStatement( ExpressionStatement node, SourceIndex index ) + public Void visitIdentifier( Identifier node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitBreakStatement( BreakStatement node, SourceIndex index ) + public Void visitNullReferenceExpression( NullReferenceExpression node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitContinueStatement( ContinueStatement node, SourceIndex index ) + public Void visitThisReferenceExpression( ThisReferenceExpression node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitDoWhileStatement( DoWhileStatement node, SourceIndex index ) + public Void visitSuperReferenceExpression( SuperReferenceExpression node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitEmptyStatement( EmptyStatement node, SourceIndex index ) + public Void visitClassOfExpression( ClassOfExpression node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitIfElseStatement( IfElseStatement node, SourceIndex index ) + public Void visitBlockStatement( BlockStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitLabelStatement( LabelStatement node, SourceIndex index ) + public Void visitExpressionStatement( ExpressionStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitLabeledStatement( LabeledStatement node, SourceIndex index ) + public Void visitBreakStatement( BreakStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitReturnStatement( ReturnStatement node, SourceIndex index ) + public Void visitContinueStatement( ContinueStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitSwitchStatement( SwitchStatement node, SourceIndex index ) + public Void visitDoWhileStatement( DoWhileStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitSwitchSection( SwitchSection node, SourceIndex index ) + public Void visitEmptyStatement( EmptyStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitCaseLabel( CaseLabel node, SourceIndex index ) + public Void visitIfElseStatement( IfElseStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitThrowStatement( ThrowStatement node, SourceIndex index ) + public Void visitLabelStatement( LabelStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitCatchClause( CatchClause node, SourceIndex index ) + public Void visitLabeledStatement( LabeledStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitAnnotation( Annotation node, SourceIndex index ) + public Void visitReturnStatement( ReturnStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitNewLine( NewLineNode node, SourceIndex index ) + public Void visitSwitchStatement( SwitchStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitVariableDeclaration( VariableDeclarationStatement node, SourceIndex index ) + public Void visitSwitchSection( SwitchSection node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitVariableInitializer( VariableInitializer node, SourceIndex index ) + public Void visitCaseLabel( CaseLabel node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitText( TextNode node, SourceIndex index ) + public Void visitThrowStatement( ThrowStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitImportDeclaration( ImportDeclaration node, SourceIndex index ) + public Void visitCatchClause( CatchClause node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitSimpleType( SimpleType node, SourceIndex index ) + public Void visitAnnotation( Annotation node, SourceIndex index ) { - TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); - if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) - { - index.add( node.getIdentifierToken(), new ClassEntry( ref.getInternalName() ) ); - } - return recurse( node, index ); } @Override - public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) + public Void visitNewLine( NewLineNode node, SourceIndex index ) { - MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - MethodEntry methodEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() ); - index.add( node.getNameToken(), methodEntry ); - return recurse( node, index ); } @Override - public Void visitInitializerBlock( InstanceInitializer node, SourceIndex index ) + public Void visitVariableDeclaration( VariableDeclarationStatement node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) + public Void visitVariableInitializer( VariableInitializer node, SourceIndex index ) { - MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); - index.add( node.getNameToken(), new ClassEntry( def.getDeclaringType().getInternalName() ) ); - return recurse( node, index ); } @Override - public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, SourceIndex index ) + public Void visitText( TextNode node, SourceIndex index ) { return recurse( node, index ); } @Override - public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) + public Void visitImportDeclaration( ImportDeclaration node, SourceIndex index ) { - ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - MethodDefinition methodDef = (MethodDefinition)def.getMethod(); - MethodEntry methodEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); - ArgumentEntry argumentEntry = new ArgumentEntry( methodEntry, def.getPosition(), def.getName() ); - index.add( node.getNameToken(), argumentEntry ); - return recurse( node, index ); } @Override - public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) + public Void visitInitializerBlock( InstanceInitializer node, SourceIndex index ) { - FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); - assert( node.getVariables().size() == 1 ); - VariableInitializer variable = node.getVariables().firstOrNullObject(); - index.add( variable.getNameToken(), fieldEntry ); - return recurse( node, index ); } @Override - public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) + public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, SourceIndex index ) { - TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); - index.add( node.getNameToken(), new ClassEntry( def.getInternalName() ) ); - return recurse( node, index ); } @@ -450,7 +504,6 @@ public class SourceIndexVisitor implements IAstVisitor @Override public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) { - // TODO return recurse( node, index ); } @@ -567,52 +620,4 @@ public class SourceIndexVisitor implements IAstVisitor { return recurse( node, index ); } - - private Void recurse( AstNode node, SourceIndex index ) - { - // TEMP: show the tree - System.out.println( getIndent( node ) + node.getClass().getSimpleName() + dumpUserData( node ) + " " + node.getRegion() ); - - for( final AstNode child : node.getChildren() ) - { - child.acceptVisitor( this, index ); - } - return null; - } - - private String dumpUserData( AstNode node ) - { - StringBuilder buf = new StringBuilder(); - for( Key key : Keys.ALL_KEYS ) - { - Object val = node.getUserData( key ); - if( val != null ) - { - buf.append( String.format( " [%s=%s]", key, val ) ); - } - } - return buf.toString(); - } - - private String getIndent( AstNode node ) - { - StringBuilder buf = new StringBuilder(); - int depth = getDepth( node ); - for( int i = 0; i < depth; i++ ) - { - buf.append( "\t" ); - } - return buf.toString(); - } - - private int getDepth( AstNode node ) - { - int depth = -1; - while( node != null ) - { - depth++; - node = node.getParent(); - } - return depth; - } } -- cgit v1.2.3 From 417689c02241ae4b44d4a892c442689bb053a436 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 10 Aug 2014 17:24:14 -0400 Subject: improved keyboard shortcuts --- src/cuchaz/enigma/gui/Gui.java | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 187852a2..79becf86 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -19,6 +19,7 @@ import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.InputEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; @@ -50,6 +51,7 @@ import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JTextField; import javax.swing.JTree; +import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.WindowConstants; import javax.swing.event.CaretEvent; @@ -254,6 +256,10 @@ public class Gui case KeyEvent.VK_R: startRename(); break; + + case KeyEvent.VK_O: + openEntry(); + break; } } } ); @@ -275,6 +281,7 @@ public class Gui startRename(); } } ); + menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_R, 0 ) ); popupMenu.add( menu ); m_renameMenu = menu; } @@ -301,6 +308,7 @@ public class Gui openEntry(); } } ); + menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_O, 0 ) ); popupMenu.add( menu ); m_openEntryMenu = menu; } @@ -427,6 +435,7 @@ public class Gui } } } ); + item.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK ) ); m_saveMappingsMenu = item; } { @@ -451,6 +460,7 @@ public class Gui } } } ); + item.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK ) ); m_saveMappingsAsMenu = item; } { -- cgit v1.2.3 From 1ea27e61b915e944f6015d1711b89b9809ddff9f Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 10 Aug 2014 18:12:20 -0400 Subject: filter out tokens that are not obfuscated --- src/cuchaz/enigma/Deobfuscator.java | 77 ++++++++----------------------------- 1 file changed, 16 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 8eda889f..16c11d3f 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -22,22 +22,15 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import com.google.common.collect.Lists; -import com.strobel.assembler.metadata.MemberReference; import com.strobel.assembler.metadata.MetadataSystem; import com.strobel.assembler.metadata.TypeDefinition; -import com.strobel.componentmodel.Key; import com.strobel.decompiler.DecompilerContext; import com.strobel.decompiler.DecompilerSettings; import com.strobel.decompiler.PlainTextOutput; import com.strobel.decompiler.languages.java.JavaOutputVisitor; import com.strobel.decompiler.languages.java.ast.AstBuilder; -import com.strobel.decompiler.languages.java.ast.AstNode; import com.strobel.decompiler.languages.java.ast.CompilationUnit; -import com.strobel.decompiler.languages.java.ast.Identifier; import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; -import com.strobel.decompiler.languages.java.ast.InvocationExpression; -import com.strobel.decompiler.languages.java.ast.Keys; -import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; @@ -203,58 +196,6 @@ public class Deobfuscator return index; } - private void dump( AstNode node, int depth ) - { - StringBuilder buf = new StringBuilder(); - for( int i=0; i %s)", memberRef.getDeclaringType(), memberRef.getName(), memberRef.getSignature() ) ); - } - - for( Key key : Keys.ALL_KEYS ) - { - if( key == Keys.MEMBER_REFERENCE ) - { - continue; - } - Object val = node.getUserData( key ); - if( val != null ) - { - buf.append( String.format( " (%s=%s)", key, val ) ); - } - } - - - if( node instanceof Identifier ) - { - Identifier n = (Identifier)node; - buf.append( ": " + n.getName() ); - } - else if( node instanceof MemberReferenceExpression ) - { - MemberReferenceExpression n = (MemberReferenceExpression)node; - buf.append( ": " + n.getTarget() + "." + n.getMemberName() ); - } - else if( node instanceof InvocationExpression ) - { - - } - - System.out.println( buf ); - - for( AstNode child : node.getChildren() ) - { - dump( child, depth + 1 ); - } - } - // NOTE: these methods are a bit messy... oh well public void rename( Entry obfEntry, String newName ) @@ -366,8 +307,22 @@ public class Deobfuscator // obf classes must be in the list return m_obfClassNames.contains( obfEntry.getName() ); } + else if( obfEntry instanceof FieldEntry ) + { + return m_obfClassNames.contains( ((FieldEntry)obfEntry).getClassName() ); + } + else if( obfEntry instanceof MethodEntry ) + { + return m_obfClassNames.contains( ((MethodEntry)obfEntry).getClassName() ); + } + else if( obfEntry instanceof ArgumentEntry ) + { + // arguments only appear in method delcarations + // since we only show declrations for obf classes, these are always obfuscated + return true; + } - // assume everything else is an identifier - return true; + // assume everything else is not obfuscated + return false; } } -- cgit v1.2.3 From e7febe4549c9fcdf1e82239959b3c6a83fad8934 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 10 Aug 2014 19:29:43 -0400 Subject: added go to entry feature --- src/cuchaz/enigma/analysis/SourceIndex.java | 11 +- src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 48 +- src/cuchaz/enigma/analysis/TreeDumpVisitor.java | 550 +++++++++++++++++++++ src/cuchaz/enigma/gui/Gui.java | 52 +- src/cuchaz/enigma/gui/GuiController.java | 47 +- src/cuchaz/enigma/mapping/ArgumentEntry.java | 1 + src/cuchaz/enigma/mapping/ClassEntry.java | 6 + src/cuchaz/enigma/mapping/Entry.java | 1 + src/cuchaz/enigma/mapping/FieldEntry.java | 1 + src/cuchaz/enigma/mapping/MethodEntry.java | 1 + 10 files changed, 621 insertions(+), 97 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/TreeDumpVisitor.java (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 7981f879..ad94cf00 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -25,12 +25,14 @@ public class SourceIndex { private String m_source; private TreeMap m_tokens; + private Map m_declarations; private List m_lineOffsets; public SourceIndex( String source ) { m_source = source; m_tokens = Maps.newTreeMap(); + m_declarations = Maps.newHashMap(); m_lineOffsets = Lists.newArrayList(); // count the lines @@ -82,9 +84,11 @@ public class SourceIndex m_tokens.put( getToken( node ), entry ); } - public void add( Token token, Entry entry ) + public void addDeclaration( AstNode node, Entry entry ) { + Token token = getToken( node ); m_tokens.put( token, entry ); + m_declarations.put( entry, token ); } public Token getToken( int pos ) @@ -116,6 +120,11 @@ public class SourceIndex return m_tokens.keySet(); } + public Token getDeclarationToken( Entry entry ) + { + return m_declarations.get( entry ); + } + private int toPos( int line, int col ) { // line and col are 1-based diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java index 5a64e4e4..0ba5996c 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java @@ -16,7 +16,6 @@ import com.strobel.assembler.metadata.MethodDefinition; import com.strobel.assembler.metadata.ParameterDefinition; import com.strobel.assembler.metadata.TypeDefinition; import com.strobel.assembler.metadata.TypeReference; -import com.strobel.componentmodel.Key; import com.strobel.decompiler.languages.TextLocation; import com.strobel.decompiler.languages.java.ast.Annotation; import com.strobel.decompiler.languages.java.ast.AnonymousObjectCreationExpression; @@ -149,7 +148,7 @@ public class SourceIndexVisitor implements IAstVisitor { ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); MethodEntry methodEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() ); - index.add( node.getNameToken(), methodEntry ); + index.addDeclaration( node.getNameToken(), methodEntry ); } return recurse( node, index ); @@ -172,7 +171,7 @@ public class SourceIndexVisitor implements IAstVisitor MethodDefinition methodDef = (MethodDefinition)def.getMethod(); MethodEntry methodEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); ArgumentEntry argumentEntry = new ArgumentEntry( methodEntry, def.getPosition(), def.getName() ); - index.add( node.getNameToken(), argumentEntry ); + index.addDeclaration( node.getNameToken(), argumentEntry ); return recurse( node, index ); } @@ -185,7 +184,7 @@ public class SourceIndexVisitor implements IAstVisitor FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); assert( node.getVariables().size() == 1 ); VariableInitializer variable = node.getVariables().firstOrNullObject(); - index.add( variable.getNameToken(), fieldEntry ); + index.addDeclaration( variable.getNameToken(), fieldEntry ); return recurse( node, index ); } @@ -194,16 +193,13 @@ public class SourceIndexVisitor implements IAstVisitor public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) { TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); - index.add( node.getNameToken(), new ClassEntry( def.getInternalName() ) ); + index.addDeclaration( node.getNameToken(), new ClassEntry( def.getInternalName() ) ); return recurse( node, index ); } private Void recurse( AstNode node, SourceIndex index ) { - // TEMP: show the tree - System.out.println( getIndent( node ) + node.getClass().getSimpleName() + dumpUserData( node ) + " " + node.getRegion() ); - for( final AstNode child : node.getChildren() ) { child.acceptVisitor( this, index ); @@ -211,42 +207,6 @@ public class SourceIndexVisitor implements IAstVisitor return null; } - private String dumpUserData( AstNode node ) - { - StringBuilder buf = new StringBuilder(); - for( Key key : Keys.ALL_KEYS ) - { - Object val = node.getUserData( key ); - if( val != null ) - { - buf.append( String.format( " [%s=%s]", key, val ) ); - } - } - return buf.toString(); - } - - private String getIndent( AstNode node ) - { - StringBuilder buf = new StringBuilder(); - int depth = getDepth( node ); - for( int i = 0; i < depth; i++ ) - { - buf.append( "\t" ); - } - return buf.toString(); - } - - private int getDepth( AstNode node ) - { - int depth = -1; - while( node != null ) - { - depth++; - node = node.getParent(); - } - return depth; - } - // OVERRIDES WE DON'T CARE ABOUT @Override diff --git a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java new file mode 100644 index 00000000..32607db9 --- /dev/null +++ b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java @@ -0,0 +1,550 @@ +package cuchaz.enigma.analysis; + +import com.strobel.componentmodel.Key; +import com.strobel.decompiler.languages.java.ast.Annotation; +import com.strobel.decompiler.languages.java.ast.AnonymousObjectCreationExpression; +import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression; +import com.strobel.decompiler.languages.java.ast.ArrayInitializerExpression; +import com.strobel.decompiler.languages.java.ast.ArraySpecifier; +import com.strobel.decompiler.languages.java.ast.AssertStatement; +import com.strobel.decompiler.languages.java.ast.AssignmentExpression; +import com.strobel.decompiler.languages.java.ast.AstNode; +import com.strobel.decompiler.languages.java.ast.BinaryOperatorExpression; +import com.strobel.decompiler.languages.java.ast.BlockStatement; +import com.strobel.decompiler.languages.java.ast.BreakStatement; +import com.strobel.decompiler.languages.java.ast.CaseLabel; +import com.strobel.decompiler.languages.java.ast.CastExpression; +import com.strobel.decompiler.languages.java.ast.CatchClause; +import com.strobel.decompiler.languages.java.ast.ClassOfExpression; +import com.strobel.decompiler.languages.java.ast.Comment; +import com.strobel.decompiler.languages.java.ast.CompilationUnit; +import com.strobel.decompiler.languages.java.ast.ComposedType; +import com.strobel.decompiler.languages.java.ast.ConditionalExpression; +import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; +import com.strobel.decompiler.languages.java.ast.ContinueStatement; +import com.strobel.decompiler.languages.java.ast.DoWhileStatement; +import com.strobel.decompiler.languages.java.ast.EmptyStatement; +import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; +import com.strobel.decompiler.languages.java.ast.ExpressionStatement; +import com.strobel.decompiler.languages.java.ast.FieldDeclaration; +import com.strobel.decompiler.languages.java.ast.ForEachStatement; +import com.strobel.decompiler.languages.java.ast.ForStatement; +import com.strobel.decompiler.languages.java.ast.GotoStatement; +import com.strobel.decompiler.languages.java.ast.IAstVisitor; +import com.strobel.decompiler.languages.java.ast.Identifier; +import com.strobel.decompiler.languages.java.ast.IdentifierExpression; +import com.strobel.decompiler.languages.java.ast.IfElseStatement; +import com.strobel.decompiler.languages.java.ast.ImportDeclaration; +import com.strobel.decompiler.languages.java.ast.IndexerExpression; +import com.strobel.decompiler.languages.java.ast.InstanceInitializer; +import com.strobel.decompiler.languages.java.ast.InstanceOfExpression; +import com.strobel.decompiler.languages.java.ast.InvocationExpression; +import com.strobel.decompiler.languages.java.ast.JavaTokenNode; +import com.strobel.decompiler.languages.java.ast.Keys; +import com.strobel.decompiler.languages.java.ast.LabelStatement; +import com.strobel.decompiler.languages.java.ast.LabeledStatement; +import com.strobel.decompiler.languages.java.ast.LambdaExpression; +import com.strobel.decompiler.languages.java.ast.LocalTypeDeclarationStatement; +import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; +import com.strobel.decompiler.languages.java.ast.MethodDeclaration; +import com.strobel.decompiler.languages.java.ast.MethodGroupExpression; +import com.strobel.decompiler.languages.java.ast.NewLineNode; +import com.strobel.decompiler.languages.java.ast.NullReferenceExpression; +import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; +import com.strobel.decompiler.languages.java.ast.PackageDeclaration; +import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; +import com.strobel.decompiler.languages.java.ast.ParenthesizedExpression; +import com.strobel.decompiler.languages.java.ast.PrimitiveExpression; +import com.strobel.decompiler.languages.java.ast.ReturnStatement; +import com.strobel.decompiler.languages.java.ast.SimpleType; +import com.strobel.decompiler.languages.java.ast.SuperReferenceExpression; +import com.strobel.decompiler.languages.java.ast.SwitchSection; +import com.strobel.decompiler.languages.java.ast.SwitchStatement; +import com.strobel.decompiler.languages.java.ast.SynchronizedStatement; +import com.strobel.decompiler.languages.java.ast.TextNode; +import com.strobel.decompiler.languages.java.ast.ThisReferenceExpression; +import com.strobel.decompiler.languages.java.ast.ThrowStatement; +import com.strobel.decompiler.languages.java.ast.TryCatchStatement; +import com.strobel.decompiler.languages.java.ast.TypeDeclaration; +import com.strobel.decompiler.languages.java.ast.TypeParameterDeclaration; +import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression; +import com.strobel.decompiler.languages.java.ast.UnaryOperatorExpression; +import com.strobel.decompiler.languages.java.ast.VariableDeclarationStatement; +import com.strobel.decompiler.languages.java.ast.VariableInitializer; +import com.strobel.decompiler.languages.java.ast.WhileStatement; +import com.strobel.decompiler.languages.java.ast.WildcardType; +import com.strobel.decompiler.patterns.Pattern; + +public class TreeDumpVisitor implements IAstVisitor +{ + private Void recurse( AstNode node, Void ignored ) + { + // show the tree + System.out.println( getIndent( node ) + node.getClass().getSimpleName() + dumpUserData( node ) + " " + node.getRegion() ); + + // recurse + for( final AstNode child : node.getChildren() ) + { + child.acceptVisitor( this, ignored ); + } + return null; + } + + private String dumpUserData( AstNode node ) + { + StringBuilder buf = new StringBuilder(); + for( Key key : Keys.ALL_KEYS ) + { + Object val = node.getUserData( key ); + if( val != null ) + { + buf.append( String.format( " [%s=%s]", key, val ) ); + } + } + return buf.toString(); + } + + private String getIndent( AstNode node ) + { + StringBuilder buf = new StringBuilder(); + int depth = getDepth( node ); + for( int i = 0; i < depth; i++ ) + { + buf.append( "\t" ); + } + return buf.toString(); + } + + private int getDepth( AstNode node ) + { + int depth = -1; + while( node != null ) + { + depth++; + node = node.getParent(); + } + return depth; + } + + // OVERRIDES WE DON'T CARE ABOUT + + @Override + public Void visitInvocationExpression( InvocationExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitMemberReferenceExpression( MemberReferenceExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitSimpleType( SimpleType node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitMethodDeclaration( MethodDeclaration node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitConstructorDeclaration( ConstructorDeclaration node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitParameterDeclaration( ParameterDeclaration node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitFieldDeclaration( FieldDeclaration node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitTypeDeclaration( TypeDeclaration node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitComment( Comment node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitPatternPlaceholder( AstNode node, Pattern pattern, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitTypeReference( TypeReferenceExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitJavaTokenNode( JavaTokenNode node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitIdentifier( Identifier node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitNullReferenceExpression( NullReferenceExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitThisReferenceExpression( ThisReferenceExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitSuperReferenceExpression( SuperReferenceExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitClassOfExpression( ClassOfExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitBlockStatement( BlockStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitExpressionStatement( ExpressionStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitBreakStatement( BreakStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitContinueStatement( ContinueStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitDoWhileStatement( DoWhileStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitEmptyStatement( EmptyStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitIfElseStatement( IfElseStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitLabelStatement( LabelStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitLabeledStatement( LabeledStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitReturnStatement( ReturnStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitSwitchStatement( SwitchStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitSwitchSection( SwitchSection node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitCaseLabel( CaseLabel node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitThrowStatement( ThrowStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitCatchClause( CatchClause node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitAnnotation( Annotation node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitNewLine( NewLineNode node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitVariableDeclaration( VariableDeclarationStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitVariableInitializer( VariableInitializer node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitText( TextNode node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitImportDeclaration( ImportDeclaration node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitInitializerBlock( InstanceInitializer node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitCompilationUnit( CompilationUnit node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitPackageDeclaration( PackageDeclaration node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitArraySpecifier( ArraySpecifier node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitComposedType( ComposedType node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitWhileStatement( WhileStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitPrimitiveExpression( PrimitiveExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitCastExpression( CastExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitBinaryOperatorExpression( BinaryOperatorExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitInstanceOfExpression( InstanceOfExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitIndexerExpression( IndexerExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitIdentifierExpression( IdentifierExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitConditionalExpression( ConditionalExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitArrayInitializerExpression( ArrayInitializerExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitObjectCreationExpression( ObjectCreationExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitArrayCreationExpression( ArrayCreationExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitAssignmentExpression( AssignmentExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitForStatement( ForStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitForEachStatement( ForEachStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitTryCatchStatement( TryCatchStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitGotoStatement( GotoStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitParenthesizedExpression( ParenthesizedExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitSynchronizedStatement( SynchronizedStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitAnonymousObjectCreationExpression( AnonymousObjectCreationExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitWildcardType( WildcardType node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitMethodGroupExpression( MethodGroupExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitEnumValueDeclaration( EnumValueDeclaration node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitAssertStatement( AssertStatement node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitLambdaExpression( LambdaExpression node, Void ignored ) + { + return recurse( node, ignored ); + } + + @Override + public Void visitLocalTypeDeclarationStatement( LocalTypeDeclarationStatement node, Void ignored ) + { + return recurse( node, ignored ); + } +} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 79becf86..bf72c85d 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -63,7 +63,6 @@ import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import jsyntaxpane.DefaultSyntaxKit; -import jsyntaxpane.SyntaxDocument; import com.google.common.collect.Lists; @@ -257,6 +256,10 @@ public class Gui startRename(); break; + case KeyEvent.VK_I: + showInheritance(); + break; + case KeyEvent.VK_O: openEntry(); break; @@ -296,10 +299,11 @@ public class Gui } } ); popupMenu.add( menu ); + menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_I, 0 ) ); m_inheritanceMenu = menu; } { - JMenuItem menu = new JMenuItem( "Open Class" ); + JMenuItem menu = new JMenuItem( "Go to Declaration" ); menu.addActionListener( new ActionListener( ) { @Override @@ -598,34 +602,13 @@ public class Gui public void setSource( String source ) { - setSource( source, 0 ); + m_editor.getHighlighter().removeAllHighlights(); + m_editor.setText( source ); } - public void setSource( String source, int lineNum ) + public void showToken( Token token ) { - // remove any old highlighters - m_editor.getHighlighter().removeAllHighlights(); - - m_editor.setText( source ); - - // 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.setCaretPosition( token.start ); m_editor.grabFocus(); } @@ -760,12 +743,13 @@ public class Gui m_selectedEntryPair = m_controller.getEntryPair( token ); boolean isClassEntry = m_selectedEntryPair.obf instanceof ClassEntry; + boolean isFieldEntry = m_selectedEntryPair.obf instanceof FieldEntry; boolean isMethodEntry = m_selectedEntryPair.obf instanceof MethodEntry; showEntryPair( m_selectedEntryPair ); m_inheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); - m_openEntryMenu.setEnabled( isClassEntry ); + m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry ); } private void startRename( ) @@ -807,12 +791,9 @@ public class Gui 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 { - // TODO: give token to the controller so we can put the caret back there - m_controller.rename( m_selectedEntryPair.obf, newName, lineNum ); + m_controller.rename( m_selectedEntryPair.obf, newName ); } catch( IllegalNameException ex ) { @@ -869,12 +850,7 @@ public class Gui { return; } - - // get the current class - if( m_selectedEntryPair.obf instanceof ClassEntry ) - { - m_controller.deobfuscateClass( new ClassFile( m_selectedEntryPair.obf.getName() ) ); - } + m_controller.openEntry( m_selectedEntryPair.obf ); } private void close( ) diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index e0aad860..834afecc 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -77,7 +77,7 @@ public class GuiController m_isDirty = false; m_gui.setMappingsFile( file ); refreshClasses(); - refreshOpenFiles(); + refreshCurrentClass(); } public void saveMappings( File file ) @@ -94,7 +94,7 @@ public class GuiController m_deobfuscator.setMappings( null ); m_gui.setMappingsFile( null ); refreshClasses(); - refreshOpenFiles(); + refreshCurrentClass(); } public void deobfuscateClass( ClassFile classFile ) @@ -157,12 +157,26 @@ public class GuiController return thisNode; } - public void rename( Entry obfsEntry, String newName, int lineNum ) + public void rename( Entry obfEntry, String newName ) { - m_deobfuscator.rename( obfsEntry, newName ); + m_deobfuscator.rename( obfEntry, newName ); m_isDirty = true; refreshClasses(); - refreshOpenFiles( lineNum ); + refreshCurrentClass( m_deobfuscator.deobfuscateEntry( obfEntry ) ); + } + + public void openEntry( Entry obfEntry ) + { + Entry deobfEntry = m_deobfuscator.deobfuscateEntry( obfEntry ); + if( !m_currentFile.getName().equals( obfEntry.getClassName() ) ) + { + m_currentFile = new ClassFile( obfEntry.getClassName() ); + deobfuscate( m_currentFile, deobfEntry ); + } + else + { + m_gui.showToken( m_index.getDeclarationToken( deobfEntry ) ); + } } private void refreshClasses( ) @@ -173,27 +187,28 @@ public class GuiController m_gui.setObfClasses( obfClasses ); m_gui.setDeobfClasses( deobfClasses ); } - - private void refreshOpenFiles( ) + + private void refreshCurrentClass( ) { - refreshOpenFiles( 0 ); + refreshCurrentClass( null ); } - private void refreshOpenFiles( int lineNum ) + private void refreshCurrentClass( Entry entryToShow ) { if( m_currentFile != null ) { - deobfuscate( m_currentFile, lineNum ); + deobfuscate( m_currentFile, entryToShow ); } } private void deobfuscate( final ClassFile classFile ) { - deobfuscate( classFile, 0 ); + deobfuscate( classFile, null ); } - private void deobfuscate( final ClassFile classFile, final int lineNum ) + private void deobfuscate( final ClassFile classFile, final Entry entryToShow ) { + m_currentFile = classFile; m_gui.setSource( "(deobfuscating...)" ); // run the deobfuscator in a separate thread so we don't block the GUI event queue @@ -202,9 +217,13 @@ public class GuiController @Override public void run( ) { - // decopmile,deobfuscate the bytecode + // decompile,deobfuscate the bytecode m_index = m_deobfuscator.getSource( classFile ); - m_gui.setSource( m_index.getSource(), lineNum ); + m_gui.setSource( m_index.getSource() ); + if( entryToShow != null ) + { + m_gui.showToken( m_index.getDeclarationToken( entryToShow ) ); + } // set the highlighted tokens List obfuscatedTokens = Lists.newArrayList(); diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java index c1624a83..0c25c4d3 100644 --- a/src/cuchaz/enigma/mapping/ArgumentEntry.java +++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java @@ -70,6 +70,7 @@ public class ArgumentEntry implements Entry, Serializable return m_methodEntry.getClassEntry(); } + @Override public String getClassName( ) { return m_methodEntry.getClassName(); diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index 0968e955..513862d9 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -44,6 +44,12 @@ public class ClassEntry implements Entry, Serializable return m_name; } + @Override + public String getClassName( ) + { + return m_name; + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/mapping/Entry.java b/src/cuchaz/enigma/mapping/Entry.java index 14435324..3ff80276 100644 --- a/src/cuchaz/enigma/mapping/Entry.java +++ b/src/cuchaz/enigma/mapping/Entry.java @@ -13,4 +13,5 @@ package cuchaz.enigma.mapping; public interface Entry { String getName( ); + String getClassName( ); } diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java index eefc4c4c..6148c84a 100644 --- a/src/cuchaz/enigma/mapping/FieldEntry.java +++ b/src/cuchaz/enigma/mapping/FieldEntry.java @@ -60,6 +60,7 @@ public class FieldEntry implements Entry, Serializable return m_name; } + @Override public String getClassName( ) { return m_classEntry.getName(); diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index 9ea2d08e..ff232c59 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -72,6 +72,7 @@ public class MethodEntry implements Entry, Serializable return m_signature; } + @Override public String getClassName( ) { return m_classEntry.getName(); -- cgit v1.2.3 From 22b6c861df68557352fb5a87948f3e065f395ef3 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 10 Aug 2014 22:13:01 -0400 Subject: refactored to remove ClassFile class to prep for upcoming stack navigation. It wasn't really necessary anymore. --- src/cuchaz/enigma/ClassFile.java | 41 -------------- src/cuchaz/enigma/Deobfuscator.java | 25 ++++----- .../enigma/gui/ClassInheritanceTreeNode.java | 2 +- src/cuchaz/enigma/gui/ClassListCellRenderer.java | 38 +++++++++++++ src/cuchaz/enigma/gui/ClassSelectionListener.java | 18 ------- .../gui/DeobfuscatedClassListCellRenderer.java | 43 --------------- src/cuchaz/enigma/gui/Gui.java | 63 +++++++++++----------- src/cuchaz/enigma/gui/GuiController.java | 37 ++++--------- .../gui/ObfuscatedClassListCellRenderer.java | 42 --------------- src/cuchaz/enigma/mapping/ArgumentEntry.java | 1 + src/cuchaz/enigma/mapping/ClassEntry.java | 6 +++ src/cuchaz/enigma/mapping/Entry.java | 1 + src/cuchaz/enigma/mapping/FieldEntry.java | 1 + src/cuchaz/enigma/mapping/MethodEntry.java | 1 + 14 files changed, 101 insertions(+), 218 deletions(-) delete mode 100644 src/cuchaz/enigma/ClassFile.java create mode 100644 src/cuchaz/enigma/gui/ClassListCellRenderer.java delete mode 100644 src/cuchaz/enigma/gui/ClassSelectionListener.java delete mode 100644 src/cuchaz/enigma/gui/DeobfuscatedClassListCellRenderer.java delete mode 100644 src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java (limited to 'src') diff --git a/src/cuchaz/enigma/ClassFile.java b/src/cuchaz/enigma/ClassFile.java deleted file mode 100644 index 043558d0..00000000 --- a/src/cuchaz/enigma/ClassFile.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; - - -public class ClassFile -{ - private String m_name; - - public ClassFile( String name ) - { - if( name.indexOf( '.' ) >= 0 ) - { - throw new IllegalArgumentException( "Class name should be in JVM format!" ); - } - m_name = name; - } - - public String getName( ) - { - return m_name; - } - - public String getPath( ) - { - return m_name.replace( ".", "/" ) + ".class"; - } - - public boolean isInPackage( ) - { - return m_name.indexOf( '/' ) >= 0; - } -} diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 16c11d3f..8d4394cd 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -17,7 +17,6 @@ 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; @@ -139,43 +138,41 @@ public class Deobfuscator return m_mappings.getTranslator( m_ancestries, direction ); } - public void getSeparatedClasses( List obfClasses, Map deobfClasses ) + public void getSeparatedClasses( List obfClasses, List deobfClasses ) { for( String obfClassName : m_obfClassNames ) { - ClassFile classFile = new ClassFile( obfClassName ); - // separate the classes - ClassMapping classMapping = m_mappings.getClassByObf( classFile.getName() ); + ClassMapping classMapping = m_mappings.getClassByObf( obfClassName ); if( classMapping != null ) { - deobfClasses.put( classFile, classMapping.getDeobfName() ); + deobfClasses.add( classMapping.getDeobfName() ); } - else if( classFile.isInPackage() ) + else if( obfClassName.indexOf( '/' ) >= 0 ) { - deobfClasses.put( classFile, classFile.getName() ); + // this class is in a package and therefore is not obfuscated + deobfClasses.add( obfClassName ); } else { - obfClasses.add( classFile ); + obfClasses.add( obfClassName ); } } } - public SourceIndex getSource( final ClassFile classFile ) + public SourceIndex getSource( String className ) { // 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() ); + ClassMapping classMapping = m_mappings.getClassByObf( className ); if( classMapping != null ) { - deobfName = classMapping.getDeobfName(); + className = classMapping.getDeobfName(); } // decompile it! - TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( deobfName ).resolve(); + TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( className ).resolve(); DecompilerContext context = new DecompilerContext(); context.setCurrentType( resolvedType ); context.setSettings( m_settings ); diff --git a/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java index 61e582df..295bebe4 100644 --- a/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java +++ b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java @@ -62,7 +62,7 @@ public class ClassInheritanceTreeNode extends DefaultMutableTreeNode nodes.add( new ClassInheritanceTreeNode( m_deobfuscatingTranslator, subclassName ) ); } - // add then to this node + // add them to this node for( ClassInheritanceTreeNode node : nodes ) { this.add( node ); diff --git a/src/cuchaz/enigma/gui/ClassListCellRenderer.java b/src/cuchaz/enigma/gui/ClassListCellRenderer.java new file mode 100644 index 00000000..d9d65788 --- /dev/null +++ b/src/cuchaz/enigma/gui/ClassListCellRenderer.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.gui; + +import java.awt.Component; + +import javassist.bytecode.Descriptor; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +public class ClassListCellRenderer implements ListCellRenderer +{ + private DefaultListCellRenderer m_defaultRenderer; + + public ClassListCellRenderer( ) + { + m_defaultRenderer = new DefaultListCellRenderer(); + } + + @Override + public Component getListCellRendererComponent( JList list, String className, int index, boolean isSelected, boolean hasFocus ) + { + JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, className, index, isSelected, hasFocus ); + label.setText( Descriptor.toJavaName( className ) ); + return label; + } +} diff --git a/src/cuchaz/enigma/gui/ClassSelectionListener.java b/src/cuchaz/enigma/gui/ClassSelectionListener.java deleted file mode 100644 index 4a2aa8d0..00000000 --- a/src/cuchaz/enigma/gui/ClassSelectionListener.java +++ /dev/null @@ -1,18 +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 cuchaz.enigma.ClassFile; - -public interface ClassSelectionListener -{ - void classSelected( ClassFile classFile ); -} diff --git a/src/cuchaz/enigma/gui/DeobfuscatedClassListCellRenderer.java b/src/cuchaz/enigma/gui/DeobfuscatedClassListCellRenderer.java deleted file mode 100644 index 3a8729d2..00000000 --- a/src/cuchaz/enigma/gui/DeobfuscatedClassListCellRenderer.java +++ /dev/null @@ -1,43 +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 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> 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/Gui.java b/src/cuchaz/enigma/gui/Gui.java index bf72c85d..6666b4c4 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -31,7 +31,6 @@ 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; @@ -66,7 +65,6 @@ import jsyntaxpane.DefaultSyntaxKit; import com.google.common.collect.Lists; -import cuchaz.enigma.ClassFile; import cuchaz.enigma.Constants; import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ArgumentEntry; @@ -79,35 +77,34 @@ import cuchaz.enigma.mapping.MethodEntry; public class Gui { - private static Comparator m_obfuscatedClassSorter; - private static Comparator> m_deobfuscatedClassSorter; + private static Comparator m_obfClassSorter; + private static Comparator m_deobfClassSorter; static { - m_obfuscatedClassSorter = new Comparator( ) + m_obfClassSorter = new Comparator( ) { @Override - public int compare( ClassFile a, ClassFile b ) + public int compare( String a, String b ) { - if( a.getName().length() != b.getName().length() ) + if( a.length() != b.length() ) { - return a.getName().length() - b.getName().length(); + return a.length() - b.length(); } - - return a.getName().compareTo( b.getName() ); + return a.compareTo( b ); } }; - m_deobfuscatedClassSorter = new Comparator>( ) + m_deobfClassSorter = new Comparator( ) { @Override - public int compare( Map.Entry a, Map.Entry b ) + public int compare( String a, String b ) { // I can never keep this rule straight when writing these damn things... // a < b => -1, a == b => 0, a > b => +1 - String[] aparts = a.getValue().split( "\\." ); - String[] bparts = b.getValue().split( "\\." ); + String[] aparts = a.split( "\\." ); + String[] bparts = b.split( "\\." ); for( int i=0; true; i++ ) { if( i >= aparts.length ) @@ -133,8 +130,8 @@ public class Gui // controls private JFrame m_frame; - private JList m_obfClasses; - private JList> m_deobfClasses; + private JList m_obfClasses; + private JList m_deobfClasses; private JEditorPane m_editor; private JPanel m_infoPanel; private BoxHighlightPainter m_obfuscatedHighlightPainter; @@ -170,10 +167,10 @@ public class Gui pane.setLayout( new BorderLayout() ); // init obfuscated classes list - m_obfClasses = new JList(); + 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() { @Override @@ -181,10 +178,10 @@ public class Gui { if( event.getClickCount() == 2 ) { - ClassFile selected = m_obfClasses.getSelectedValue(); + String selected = m_obfClasses.getSelectedValue(); if( selected != null ) { - m_controller.deobfuscateClass( selected ); + m_controller.openEntry( new ClassEntry( selected ) ); } } } @@ -196,10 +193,10 @@ 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 DeobfuscatedClassListCellRenderer() ); + m_deobfClasses.setCellRenderer( new ClassListCellRenderer() ); m_deobfClasses.addMouseListener( new MouseAdapter() { @Override @@ -207,10 +204,10 @@ public class Gui { if( event.getClickCount() == 2 ) { - Map.Entry selected = m_deobfClasses.getSelectedValue(); + String selected = m_deobfClasses.getSelectedValue(); if( selected != null ) { - m_controller.deobfuscateClass( selected.getKey() ); + m_controller.openEntry( new ClassEntry( selected ) ); } } } @@ -330,7 +327,7 @@ public class Gui ClassInheritanceTreeNode node = (ClassInheritanceTreeNode)m_inheritanceTree.getSelectionPath().getLastPathComponent(); if( node != null ) { - m_controller.deobfuscateClass( new ClassFile( node.getObfClassName() ) ); + m_controller.openEntry( new ClassEntry( node.getDeobfClassName() ) ); } } } @@ -566,31 +563,31 @@ public class Gui m_closeMappingsMenu.setEnabled( false ); } - public void setObfClasses( List obfClasses ) + public void setObfClasses( List obfClasses ) { if( obfClasses != null ) { - Vector sortedClasses = new Vector( obfClasses ); - Collections.sort( sortedClasses, m_obfuscatedClassSorter ); + Vector sortedClasses = new Vector( obfClasses ); + Collections.sort( sortedClasses, m_obfClassSorter ); m_obfClasses.setListData( sortedClasses ); } else { - m_obfClasses.setListData( new Vector() ); + m_obfClasses.setListData( new Vector() ); } } - public void setDeobfClasses( Map deobfClasses ) + public void setDeobfClasses( List deobfClasses ) { if( deobfClasses != null ) { - Vector> sortedClasses = new Vector>( deobfClasses.entrySet() ); - Collections.sort( sortedClasses, m_deobfuscatedClassSorter ); + Vector sortedClasses = new Vector( deobfClasses ); + Collections.sort( sortedClasses, m_deobfClassSorter ); m_deobfClasses.setListData( sortedClasses ); } else { - m_deobfClasses.setListData( new Vector>() ); + m_deobfClasses.setListData( new Vector() ); } } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 834afecc..6a7a7da6 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -15,12 +15,9 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.List; -import java.util.Map; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import cuchaz.enigma.ClassFile; import cuchaz.enigma.Deobfuscator; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.Token; @@ -37,7 +34,7 @@ public class GuiController private Deobfuscator m_deobfuscator; private Gui m_gui; private SourceIndex m_index; - private ClassFile m_currentFile; + private ClassEntry m_currentClass; private boolean m_isDirty; public GuiController( Gui gui ) @@ -45,7 +42,7 @@ public class GuiController m_gui = gui; m_deobfuscator = null; m_index = null; - m_currentFile = null; + m_currentClass = null; m_isDirty = false; } @@ -97,12 +94,6 @@ public class GuiController refreshCurrentClass(); } - public void deobfuscateClass( ClassFile classFile ) - { - m_currentFile = classFile; - deobfuscate( m_currentFile ); - } - public Token getToken( int pos ) { if( m_index == null ) @@ -168,10 +159,10 @@ public class GuiController public void openEntry( Entry obfEntry ) { Entry deobfEntry = m_deobfuscator.deobfuscateEntry( obfEntry ); - if( !m_currentFile.getName().equals( obfEntry.getClassName() ) ) + if( m_currentClass == null || !m_currentClass.equals( deobfEntry.getClassEntry() ) ) { - m_currentFile = new ClassFile( obfEntry.getClassName() ); - deobfuscate( m_currentFile, deobfEntry ); + m_currentClass = new ClassEntry( obfEntry.getClassEntry() ); + deobfuscate( m_currentClass, deobfEntry ); } else { @@ -181,8 +172,8 @@ public class GuiController private void refreshClasses( ) { - List obfClasses = Lists.newArrayList(); - Map deobfClasses = Maps.newHashMap(); + List obfClasses = Lists.newArrayList(); + List deobfClasses = Lists.newArrayList(); m_deobfuscator.getSeparatedClasses( obfClasses, deobfClasses ); m_gui.setObfClasses( obfClasses ); m_gui.setDeobfClasses( deobfClasses ); @@ -195,20 +186,14 @@ public class GuiController private void refreshCurrentClass( Entry entryToShow ) { - if( m_currentFile != null ) + if( m_currentClass != null ) { - deobfuscate( m_currentFile, entryToShow ); + deobfuscate( m_currentClass, entryToShow ); } } - - private void deobfuscate( final ClassFile classFile ) - { - deobfuscate( classFile, null ); - } - private void deobfuscate( final ClassFile classFile, final Entry entryToShow ) + private void deobfuscate( final ClassEntry classEntry, final Entry entryToShow ) { - m_currentFile = classFile; m_gui.setSource( "(deobfuscating...)" ); // run the deobfuscator in a separate thread so we don't block the GUI event queue @@ -218,7 +203,7 @@ public class GuiController public void run( ) { // decompile,deobfuscate the bytecode - m_index = m_deobfuscator.getSource( classFile ); + m_index = m_deobfuscator.getSource( classEntry.getClassName() ); m_gui.setSource( m_index.getSource() ); if( entryToShow != null ) { diff --git a/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java b/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java deleted file mode 100644 index d46e1ae6..00000000 --- a/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java +++ /dev/null @@ -1,42 +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 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 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/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java index 0c25c4d3..27dcc41d 100644 --- a/src/cuchaz/enigma/mapping/ArgumentEntry.java +++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java @@ -65,6 +65,7 @@ public class ArgumentEntry implements Entry, Serializable return m_name; } + @Override public ClassEntry getClassEntry( ) { return m_methodEntry.getClassEntry(); diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index 513862d9..738e8e3b 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -37,6 +37,12 @@ public class ClassEntry implements Entry, Serializable { m_name = other.m_name; } + + @Override + public ClassEntry getClassEntry( ) + { + return this; + } @Override public String getName( ) diff --git a/src/cuchaz/enigma/mapping/Entry.java b/src/cuchaz/enigma/mapping/Entry.java index 3ff80276..e1591f02 100644 --- a/src/cuchaz/enigma/mapping/Entry.java +++ b/src/cuchaz/enigma/mapping/Entry.java @@ -14,4 +14,5 @@ public interface Entry { String getName( ); String getClassName( ); + ClassEntry getClassEntry( ); } diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java index 6148c84a..435490bd 100644 --- a/src/cuchaz/enigma/mapping/FieldEntry.java +++ b/src/cuchaz/enigma/mapping/FieldEntry.java @@ -49,6 +49,7 @@ public class FieldEntry implements Entry, Serializable m_name = other.m_name; } + @Override public ClassEntry getClassEntry( ) { return m_classEntry; diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index ff232c59..b4b9c9bf 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -56,6 +56,7 @@ public class MethodEntry implements Entry, Serializable m_signature = other.m_signature; } + @Override public ClassEntry getClassEntry( ) { return m_classEntry; -- cgit v1.2.3 From dc7c8847ab69e946a20a45c955b4a0273e262d48 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 10 Aug 2014 22:39:18 -0400 Subject: added backwards navigation --- src/cuchaz/enigma/analysis/SourceIndex.java | 14 ++++----- src/cuchaz/enigma/gui/Gui.java | 26 ++++++++++++++-- src/cuchaz/enigma/gui/GuiController.java | 46 ++++++++++++++++++++++------- 3 files changed, 65 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index ad94cf00..531f3e04 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -79,16 +79,16 @@ public class SourceIndex return token; } - public void add( AstNode node, Entry entry ) + public void add( AstNode node, Entry deobfEntry ) { - m_tokens.put( getToken( node ), entry ); + m_tokens.put( getToken( node ), deobfEntry ); } - public void addDeclaration( AstNode node, Entry entry ) + public void addDeclaration( AstNode node, Entry deobfEntry ) { Token token = getToken( node ); - m_tokens.put( token, entry ); - m_declarations.put( entry, token ); + m_tokens.put( token, deobfEntry ); + m_declarations.put( deobfEntry, token ); } public Token getToken( int pos ) @@ -120,9 +120,9 @@ public class SourceIndex return m_tokens.keySet(); } - public Token getDeclarationToken( Entry entry ) + public Token getDeclarationToken( Entry deobfEntry ) { - return m_declarations.get( entry ); + return m_declarations.get( deobfEntry ); } private int toPos( int line, int col ) diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 6666b4c4..62f23918 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -147,6 +147,7 @@ public class Gui private JMenuItem m_renameMenu; private JMenuItem m_inheritanceMenu; private JMenuItem m_openEntryMenu; + private JMenuItem m_openPreviousMenu; // state private EntryPair m_selectedEntryPair; @@ -282,6 +283,7 @@ public class Gui } } ); menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_R, 0 ) ); + menu.setEnabled( false ); popupMenu.add( menu ); m_renameMenu = menu; } @@ -295,8 +297,9 @@ public class Gui showInheritance(); } } ); - popupMenu.add( menu ); menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_I, 0 ) ); + menu.setEnabled( false ); + popupMenu.add( menu ); m_inheritanceMenu = menu; } { @@ -309,10 +312,26 @@ public class Gui openEntry(); } } ); - menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_O, 0 ) ); + menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_N, 0 ) ); + menu.setEnabled( false ); popupMenu.add( menu ); m_openEntryMenu = menu; } + { + JMenuItem menu = new JMenuItem( "Go to previous" ); + menu.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + m_controller.openPreviousEntry(); + } + } ); + menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_P, 0 ) ); + menu.setEnabled( false ); + popupMenu.add( menu ); + m_openPreviousMenu = menu; + } // init inheritance panel m_inheritanceTree = new JTree(); @@ -327,7 +346,7 @@ public class Gui ClassInheritanceTreeNode node = (ClassInheritanceTreeNode)m_inheritanceTree.getSelectionPath().getLastPathComponent(); if( node != null ) { - m_controller.openEntry( new ClassEntry( node.getDeobfClassName() ) ); + m_controller.openEntry( new ClassEntry( node.getObfClassName() ) ); } } } @@ -747,6 +766,7 @@ public class Gui m_inheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry ); + m_openPreviousMenu.setEnabled( m_controller.hasPreviousEntry() ); } private void startRename( ) diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 6a7a7da6..a4228c72 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -15,6 +15,7 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.List; +import java.util.Stack; import com.google.common.collect.Lists; @@ -36,6 +37,7 @@ public class GuiController private SourceIndex m_index; private ClassEntry m_currentClass; private boolean m_isDirty; + private Stack m_entryStack; public GuiController( Gui gui ) { @@ -44,6 +46,7 @@ public class GuiController m_index = null; m_currentClass = null; m_isDirty = false; + m_entryStack = new Stack(); } public boolean isDirty( ) @@ -153,21 +156,42 @@ public class GuiController m_deobfuscator.rename( obfEntry, newName ); m_isDirty = true; refreshClasses(); - refreshCurrentClass( m_deobfuscator.deobfuscateEntry( obfEntry ) ); + refreshCurrentClass( obfEntry ); } - public void openEntry( Entry obfEntry ) + public void openEntry( Entry entry ) { - Entry deobfEntry = m_deobfuscator.deobfuscateEntry( obfEntry ); - if( m_currentClass == null || !m_currentClass.equals( deobfEntry.getClassEntry() ) ) + // go to the entry + Entry obfEntry = m_deobfuscator.obfuscateEntry( entry ); + if( m_currentClass == null || !m_currentClass.equals( obfEntry.getClassEntry() ) ) { m_currentClass = new ClassEntry( obfEntry.getClassEntry() ); - deobfuscate( m_currentClass, deobfEntry ); + deobfuscate( m_currentClass, obfEntry ); } else { - m_gui.showToken( m_index.getDeclarationToken( deobfEntry ) ); + m_gui.showToken( m_index.getDeclarationToken( m_deobfuscator.deobfuscateEntry( obfEntry ) ) ); } + + if( m_entryStack.isEmpty() || !m_entryStack.peek().equals( obfEntry ) ) + { + // update the stack + m_entryStack.push( obfEntry ); + } + } + + public void openPreviousEntry( ) + { + if( hasPreviousEntry() ) + { + m_entryStack.pop(); + openEntry( m_entryStack.peek() ); + } + } + + public boolean hasPreviousEntry( ) + { + return m_entryStack.size() > 1; } private void refreshClasses( ) @@ -184,15 +208,15 @@ public class GuiController refreshCurrentClass( null ); } - private void refreshCurrentClass( Entry entryToShow ) + private void refreshCurrentClass( Entry obfEntryToShow ) { if( m_currentClass != null ) { - deobfuscate( m_currentClass, entryToShow ); + deobfuscate( m_currentClass, obfEntryToShow ); } } - private void deobfuscate( final ClassEntry classEntry, final Entry entryToShow ) + private void deobfuscate( final ClassEntry classEntry, final Entry obfEntryToShow ) { m_gui.setSource( "(deobfuscating...)" ); @@ -205,9 +229,9 @@ public class GuiController // decompile,deobfuscate the bytecode m_index = m_deobfuscator.getSource( classEntry.getClassName() ); m_gui.setSource( m_index.getSource() ); - if( entryToShow != null ) + if( obfEntryToShow != null ) { - m_gui.showToken( m_index.getDeclarationToken( entryToShow ) ); + m_gui.showToken( m_index.getDeclarationToken( m_deobfuscator.deobfuscateEntry( obfEntryToShow ) ) ); } // set the highlighted tokens -- cgit v1.2.3 From bba7c6a19c15bc82946176c79a4eba3612b25f17 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 11 Aug 2014 00:02:00 -0400 Subject: added method inheritance browsing also finally fixed method renamer to rename all method implementations in the inheritance hierarchy. --- src/cuchaz/enigma/Deobfuscator.java | 4 +- src/cuchaz/enigma/analysis/Ancestries.java | 235 +++++++++++++++++++++ .../enigma/analysis/ClassInheritanceTreeNode.java | 99 +++++++++ .../enigma/analysis/DeobfuscatedAncestries.java | 59 ++++++ .../enigma/analysis/MethodInheritanceTreeNode.java | 134 ++++++++++++ src/cuchaz/enigma/analysis/TreeDumpVisitor.java | 10 + .../enigma/gui/ClassInheritanceTreeNode.java | 79 ------- src/cuchaz/enigma/gui/Gui.java | 61 ++++-- src/cuchaz/enigma/gui/GuiController.java | 39 ++-- src/cuchaz/enigma/mapping/Ancestries.java | 154 -------------- .../enigma/mapping/DeobfuscatedAncestries.java | 57 ----- src/cuchaz/enigma/mapping/Mappings.java | 2 + src/cuchaz/enigma/mapping/Renamer.java | 28 +++ src/cuchaz/enigma/mapping/Translator.java | 1 + 14 files changed, 634 insertions(+), 328 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/Ancestries.java create mode 100644 src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java create mode 100644 src/cuchaz/enigma/analysis/DeobfuscatedAncestries.java create mode 100644 src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java delete mode 100644 src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java delete mode 100644 src/cuchaz/enigma/mapping/Ancestries.java delete mode 100644 src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 8d4394cd..5321d2de 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -31,9 +31,9 @@ import com.strobel.decompiler.languages.java.ast.AstBuilder; import com.strobel.decompiler.languages.java.ast.CompilationUnit; import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; +import cuchaz.enigma.analysis.Ancestries; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; -import cuchaz.enigma.mapping.Ancestries; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ClassMapping; @@ -207,7 +207,7 @@ public class Deobfuscator } else if( obfEntry instanceof MethodEntry ) { - m_renamer.setMethodName( (MethodEntry)obfEntry, newName ); + m_renamer.setMethodTreeName( (MethodEntry)obfEntry, newName ); } else if( obfEntry instanceof ArgumentEntry ) { diff --git a/src/cuchaz/enigma/analysis/Ancestries.java b/src/cuchaz/enigma/analysis/Ancestries.java new file mode 100644 index 00000000..e6c8bbf1 --- /dev/null +++ b/src/cuchaz/enigma/analysis/Ancestries.java @@ -0,0 +1,235 @@ +/******************************************************************************* + * 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.analysis; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import javassist.ByteArrayClassPath; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.NotFoundException; +import javassist.bytecode.Descriptor; +import javassist.bytecode.MethodInfo; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; + +import cuchaz.enigma.Constants; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.Translator; + +public class Ancestries implements Serializable +{ + private static final long serialVersionUID = 738687982126844179L; + + private Map m_superclasses; + private Multimap m_methodImplementations; + + public Ancestries( ) + { + m_superclasses = Maps.newHashMap(); + m_methodImplementations = HashMultimap.create(); + } + + @SuppressWarnings( "unchecked" ) + public void readFromJar( InputStream in ) + throws IOException + { + ClassPool classPool = new ClassPool(); + + ZipInputStream zin = new ZipInputStream( in ); + ZipEntry entry; + while( ( entry = zin.getNextEntry() ) != null ) + { + // filter out non-classes + if( entry.isDirectory() || !entry.getName().endsWith( ".class" ) ) + { + continue; + } + + // read the class into a buffer + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buf = new byte[Constants.KiB]; + int totalNumBytesRead = 0; + while( zin.available() > 0 ) + { + int numBytesRead = zin.read( buf ); + if( numBytesRead < 0 ) + { + break; + } + bos.write( buf, 0, numBytesRead ); + + // sanity checking + totalNumBytesRead += numBytesRead; + if( totalNumBytesRead > Constants.MiB ) + { + throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" ); + } + } + + // determine the class name (ie chop off the ".class") + String className = Descriptor.toJavaName( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) ); + + // get a javassist handle for the class + classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); + try + { + CtClass c = classPool.get( className ); + addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); + addMethodImplementations( c.getName(), (List)c.getClassFile().getMethods() ); + } + catch( NotFoundException ex ) + { + throw new Error( "Unable to load class: " + className ); + } + } + } + + private void addMethodImplementations( String name, List methods ) + { + for( MethodInfo method : methods ) + { + m_methodImplementations.put( name, getMethodKey( method.getName(), method.getDescriptor() ) ); + } + } + + public void addSuperclass( String className, String superclassName ) + { + className = Descriptor.toJvmName( className ); + superclassName = Descriptor.toJvmName( superclassName ); + + if( className.equals( superclassName ) ) + { + throw new IllegalArgumentException( "Class cannot be its own superclass! " + className ); + } + + if( !isJre( className ) && !isJre( superclassName ) ) + { + m_superclasses.put( className, superclassName ); + } + } + + public String getSuperclassName( String className ) + { + return m_superclasses.get( className ); + } + + public List getAncestry( String className ) + { + List ancestors = new ArrayList(); + while( className != null ) + { + className = getSuperclassName( className ); + if( className != null ) + { + ancestors.add( className ); + } + } + return ancestors; + } + + public List getSubclasses( String className ) + { + // linear search is fast enough for now + List subclasses = Lists.newArrayList(); + for( Map.Entry entry : m_superclasses.entrySet() ) + { + String subclass = entry.getKey(); + String superclass = entry.getValue(); + if( className.equals( superclass ) ) + { + subclasses.add( subclass ); + } + } + return subclasses; + } + + public boolean isMethodImplemented( MethodEntry methodEntry ) + { + return isMethodImplemented( methodEntry.getClassName(), methodEntry.getName(), methodEntry.getSignature() ); + } + + public boolean isMethodImplemented( String className, String methodName, String methodSignature ) + { + Collection implementations = m_methodImplementations.get( className ); + if( implementations == null ) + { + return false; + } + return implementations.contains( getMethodKey( methodName, methodSignature ) ); + } + + public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) + { + // get the root node + List ancestry = getAncestry( obfClassEntry.getName() ); + ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) ); + + // expand all children recursively + rootNode.load( this, true ); + + return rootNode; + } + + public MethodInheritanceTreeNode getMethodInheritance( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) + { + // travel to the ancestor implementation + String baseImplementationClassName = obfMethodEntry.getClassName(); + for( String ancestorClassName : getAncestry( obfMethodEntry.getClassName() ) ) + { + if( isMethodImplemented( ancestorClassName, obfMethodEntry.getName(), obfMethodEntry.getSignature() ) ) + { + baseImplementationClassName = ancestorClassName; + } + } + + // make a root node at the base + MethodEntry methodEntry = new MethodEntry( + new ClassEntry( baseImplementationClassName ), + obfMethodEntry.getName(), + obfMethodEntry.getSignature() + ); + MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( + deobfuscatingTranslator, + methodEntry, + isMethodImplemented( methodEntry ) + ); + + // expand the full tree + rootNode.load( this, true ); + + return rootNode; + } + + private boolean isJre( String className ) + { + return className.startsWith( "java/" ) + || className.startsWith( "javax/" ); + } + + private String getMethodKey( String name, String signature ) + { + return name + signature; + } +} diff --git a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java new file mode 100644 index 00000000..2ed141ff --- /dev/null +++ b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * 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.analysis; + +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; + +import com.google.common.collect.Lists; + +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.Translator; + +public class ClassInheritanceTreeNode extends DefaultMutableTreeNode +{ + private static final long serialVersionUID = 4432367405826178490L; + + private Translator m_deobfuscatingTranslator; + private String m_obfClassName; + + public ClassInheritanceTreeNode( Translator deobfuscatingTranslator, String obfClassName ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_obfClassName = obfClassName; + } + + public String getObfClassName( ) + { + return m_obfClassName; + } + + public String getDeobfClassName( ) + { + return m_deobfuscatingTranslator.translateClass( m_obfClassName ); + } + + @Override + public String toString( ) + { + String deobfClassName = getDeobfClassName(); + if( deobfClassName != null ) + { + return deobfClassName; + } + return m_obfClassName; + } + + public void load( Ancestries ancestries, boolean recurse ) + { + // get all the child nodes + List nodes = Lists.newArrayList(); + for( String subclassName : ancestries.getSubclasses( m_obfClassName ) ) + { + nodes.add( new ClassInheritanceTreeNode( m_deobfuscatingTranslator, subclassName ) ); + } + + // add them to this node + for( ClassInheritanceTreeNode node : nodes ) + { + this.add( node ); + } + + if( recurse ) + { + for( ClassInheritanceTreeNode node : nodes ) + { + node.load( ancestries, true ); + } + } + } + + public static ClassInheritanceTreeNode findNode( ClassInheritanceTreeNode node, ClassEntry entry ) + { + // is this the node? + if( node.getObfClassName().equals( entry.getName() ) ) + { + return node; + } + + // recurse + for( int i=0; i m_classesByObf; + private Map m_classesByDeobf; + + public DeobfuscatedAncestries( Ancestries ancestries, Map classesByObf, Map classesByDeobf ) + { + m_ancestries = ancestries; + m_classesByObf = classesByObf; + m_classesByDeobf = classesByDeobf; + } + + @Override + public String getSuperclassName( String deobfClassName ) + { + // obfuscate the class name + ClassMapping classIndex = m_classesByDeobf.get( deobfClassName ); + if( classIndex == null ) + { + return null; + } + String obfClassName = classIndex.getObfName(); + + // get the superclass + String obfSuperclassName = m_ancestries.getSuperclassName( obfClassName ); + if( obfSuperclassName == null ) + { + return null; + } + + // deobfuscate the superclass name + classIndex = m_classesByObf.get( obfSuperclassName ); + if( classIndex == null ) + { + return null; + } + + return classIndex.getDeobfName(); + } +} diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java new file mode 100644 index 00000000..1fecf489 --- /dev/null +++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * 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.analysis; + +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; + +import com.google.common.collect.Lists; + +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.Translator; + +public class MethodInheritanceTreeNode extends DefaultMutableTreeNode +{ + private static final long serialVersionUID = 1096677030991810007L; + + private Translator m_deobfuscatingTranslator; + private MethodEntry m_entry; + private boolean m_isImplemented; + + public MethodInheritanceTreeNode( Translator deobfuscatingTranslator, MethodEntry entry, boolean isImplemented ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = entry; + m_isImplemented = isImplemented; + } + + public MethodEntry getMethodEntry( ) + { + return m_entry; + } + + public String getDeobfClassName( ) + { + return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() ); + } + + public String getDeobfMethodName( ) + { + return m_deobfuscatingTranslator.translate( m_entry ); + } + + public boolean isImplemented( ) + { + return m_isImplemented; + } + + @Override + public String toString( ) + { + String className = getDeobfClassName(); + if( className == null ) + { + className = m_entry.getClassName(); + } + + if( !m_isImplemented ) + { + return className; + } + else + { + String methodName = getDeobfMethodName(); + if( methodName == null ) + { + methodName = m_entry.getName(); + } + return className + "." + methodName + "()"; + } + } + + public void load( Ancestries ancestries, boolean recurse ) + { + // get all the child nodes + List nodes = Lists.newArrayList(); + for( String subclassName : ancestries.getSubclasses( m_entry.getClassName() ) ) + { + MethodEntry methodEntry = new MethodEntry( + new ClassEntry( subclassName ), + m_entry.getName(), + m_entry.getSignature() + ); + nodes.add( new MethodInheritanceTreeNode( + m_deobfuscatingTranslator, + methodEntry, + ancestries.isMethodImplemented( subclassName, m_entry.getName(), m_entry.getSignature() ) + ) ); + } + + // add them to this node + for( MethodInheritanceTreeNode node : nodes ) + { + this.add( node ); + } + + if( recurse ) + { + for( MethodInheritanceTreeNode node : nodes ) + { + node.load( ancestries, true ); + } + } + } + + public static MethodInheritanceTreeNode findNode( MethodInheritanceTreeNode node, MethodEntry entry ) + { + // is this the node? + if( node.getMethodEntry().equals( entry ) ) + { + return node; + } + + // recurse + for( int i=0; i nodes = Lists.newArrayList(); - for( String subclassName : ancestries.getSubclasses( m_obfClassName ) ) - { - nodes.add( new ClassInheritanceTreeNode( m_deobfuscatingTranslator, subclassName ) ); - } - - // add them to this node - for( ClassInheritanceTreeNode node : nodes ) - { - this.add( node ); - } - - if( recurse ) - { - for( ClassInheritanceTreeNode node : nodes ) - { - node.load( ancestries, true ); - } - } - } -} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 62f23918..db676777 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -66,6 +66,8 @@ import jsyntaxpane.DefaultSyntaxKit; import com.google.common.collect.Lists; import cuchaz.enigma.Constants; +import cuchaz.enigma.analysis.ClassInheritanceTreeNode; +import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; @@ -343,10 +345,24 @@ public class Gui { if( event.getClickCount() == 2 ) { - ClassInheritanceTreeNode node = (ClassInheritanceTreeNode)m_inheritanceTree.getSelectionPath().getLastPathComponent(); - if( node != null ) + // get the selected node + Object node = m_inheritanceTree.getSelectionPath().getLastPathComponent(); + if( node == null ) { - m_controller.openEntry( new ClassEntry( node.getObfClassName() ) ); + return; + } + + if( node instanceof ClassInheritanceTreeNode ) + { + m_controller.openEntry( new ClassEntry( ((ClassInheritanceTreeNode)node).getObfClassName() ) ); + } + else if( node instanceof MethodInheritanceTreeNode ) + { + MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode)node; + if( methodNode.isImplemented() ) + { + m_controller.openEntry( methodNode.getMethodEntry() ); + } } } } @@ -836,31 +852,46 @@ public class Gui return; } - // get the current class if( m_selectedEntryPair.obf instanceof ClassEntry ) { + // get the class inheritance ClassInheritanceTreeNode classNode = m_controller.getClassInheritance( (ClassEntry)m_selectedEntryPair.obf ); - // build the path from the root to the class node - List nodes = Lists.newArrayList(); - TreeNode node = classNode; - do - { - nodes.add( node ); - node = node.getParent(); - } - while( node != null ); - Collections.reverse( nodes ); - TreePath path = new TreePath( nodes.toArray() ); + // show the tree at the root + TreePath path = getPathToRoot( classNode ); + m_inheritanceTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); + m_inheritanceTree.expandPath( path ); + m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); + } + else if( m_selectedEntryPair.obf instanceof MethodEntry ) + { + // get the method inheritance + MethodInheritanceTreeNode classNode = m_controller.getMethodInheritance( (MethodEntry)m_selectedEntryPair.obf ); // show the tree at the root + TreePath path = getPathToRoot( classNode ); m_inheritanceTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); m_inheritanceTree.expandPath( path ); m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); } + redraw(); } + private TreePath getPathToRoot( TreeNode node ) + { + List nodes = Lists.newArrayList(); + TreeNode n = node; + do + { + nodes.add( n ); + n = n.getParent(); + } + while( n != null ); + Collections.reverse( nodes ); + return new TreePath( nodes.toArray() ); + } + private void openEntry( ) { if( m_selectedEntryPair == null ) diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index a4228c72..1946b4a3 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -20,6 +20,8 @@ import java.util.Stack; import com.google.common.collect.Lists; import cuchaz.enigma.Deobfuscator; +import cuchaz.enigma.analysis.ClassInheritanceTreeNode; +import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ClassEntry; @@ -27,8 +29,8 @@ import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.EntryPair; import cuchaz.enigma.mapping.MappingsReader; import cuchaz.enigma.mapping.MappingsWriter; +import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.TranslationDirection; -import cuchaz.enigma.mapping.Translator; public class GuiController { @@ -128,27 +130,22 @@ public class GuiController return m_deobfuscator.entryIsObfuscatedIdenfitier( m_deobfuscator.obfuscateEntry( deobfEntry ) ); } - public ClassInheritanceTreeNode getClassInheritance( ClassEntry classEntry ) + public ClassInheritanceTreeNode getClassInheritance( ClassEntry obfClassEntry ) { - Translator deobfuscatingTranslator = m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ); - - // create a node for this class - ClassInheritanceTreeNode thisNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, classEntry.getName() ); - - // expand all children recursively - thisNode.load( m_deobfuscator.getAncestries(), true ); - - // get the ancestors too - ClassInheritanceTreeNode node = thisNode; - for( String superclassName : m_deobfuscator.getAncestries().getAncestry( classEntry.getName() ) ) - { - // add the parent node - ClassInheritanceTreeNode parentNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, superclassName ); - parentNode.add( node ); - node = parentNode; - } - - return thisNode; + ClassInheritanceTreeNode rootNode = m_deobfuscator.getAncestries().getClassInheritance( + m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + obfClassEntry + ); + return ClassInheritanceTreeNode.findNode( rootNode, obfClassEntry ); + } + + public MethodInheritanceTreeNode getMethodInheritance( MethodEntry obfMethodEntry ) + { + MethodInheritanceTreeNode rootNode = m_deobfuscator.getAncestries().getMethodInheritance( + m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + obfMethodEntry + ); + return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); } public void rename( Entry obfEntry, String newName ) diff --git a/src/cuchaz/enigma/mapping/Ancestries.java b/src/cuchaz/enigma/mapping/Ancestries.java deleted file mode 100644 index 894cf802..00000000 --- a/src/cuchaz/enigma/mapping/Ancestries.java +++ /dev/null @@ -1,154 +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.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -import javassist.ByteArrayClassPath; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.NotFoundException; -import javassist.bytecode.Descriptor; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import cuchaz.enigma.Constants; - -public class Ancestries implements Serializable -{ - private static final long serialVersionUID = 738687982126844179L; - - private Map m_superclasses; - - public Ancestries( ) - { - m_superclasses = Maps.newHashMap(); - } - - public void readFromJar( InputStream in ) - throws IOException - { - ClassPool classPool = new ClassPool(); - - ZipInputStream zin = new ZipInputStream( in ); - ZipEntry entry; - while( ( entry = zin.getNextEntry() ) != null ) - { - // filter out non-classes - if( entry.isDirectory() || !entry.getName().endsWith( ".class" ) ) - { - continue; - } - - // read the class into a buffer - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] buf = new byte[Constants.KiB]; - int totalNumBytesRead = 0; - while( zin.available() > 0 ) - { - int numBytesRead = zin.read( buf ); - if( numBytesRead < 0 ) - { - break; - } - bos.write( buf, 0, numBytesRead ); - - // sanity checking - totalNumBytesRead += numBytesRead; - if( totalNumBytesRead > Constants.MiB ) - { - throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" ); - } - } - - // determine the class name (ie chop off the ".class") - String className = Descriptor.toJavaName( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) ); - - // get a javassist handle for the class - classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); - try - { - CtClass c = classPool.get( className ); - addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); - } - catch( NotFoundException ex ) - { - throw new Error( "Unable to load class: " + className ); - } - } - } - - public void addSuperclass( String className, String superclassName ) - { - className = Descriptor.toJvmName( className ); - superclassName = Descriptor.toJvmName( superclassName ); - - if( className.equals( superclassName ) ) - { - throw new IllegalArgumentException( "Class cannot be its own superclass! " + className ); - } - - if( !isJre( className ) && !isJre( superclassName ) ) - { - m_superclasses.put( className, superclassName ); - } - } - - public String getSuperclassName( String className ) - { - return m_superclasses.get( className ); - } - - public List getAncestry( String className ) - { - List ancestors = new ArrayList(); - while( className != null ) - { - className = getSuperclassName( className ); - if( className != null ) - { - ancestors.add( className ); - } - } - return ancestors; - } - - public List getSubclasses( String className ) - { - // linear search is fast enough for now - List subclasses = Lists.newArrayList(); - for( Map.Entry entry : m_superclasses.entrySet() ) - { - String subclass = entry.getKey(); - String superclass = entry.getValue(); - if( className.equals( superclass ) ) - { - subclasses.add( subclass ); - } - } - return subclasses; - } - - private boolean isJre( String className ) - { - return className.startsWith( "java/" ) - || className.startsWith( "javax/" ); - } -} diff --git a/src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java b/src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java deleted file mode 100644 index dcb0741a..00000000 --- a/src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java +++ /dev/null @@ -1,57 +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.util.Map; - -public class DeobfuscatedAncestries extends Ancestries -{ - private static final long serialVersionUID = 8316248774892618324L; - - private Ancestries m_ancestries; - private Map m_classesByObf; - private Map m_classesByDeobf; - - protected DeobfuscatedAncestries( Ancestries ancestries, Map classesByObf, Map classesByDeobf ) - { - m_ancestries = ancestries; - m_classesByObf = classesByObf; - m_classesByDeobf = classesByDeobf; - } - - @Override - public String getSuperclassName( String deobfClassName ) - { - // obfuscate the class name - ClassMapping classIndex = m_classesByDeobf.get( deobfClassName ); - if( classIndex == null ) - { - return null; - } - String obfClassName = classIndex.getObfName(); - - // get the superclass - String obfSuperclassName = m_ancestries.getSuperclassName( obfClassName ); - if( obfSuperclassName == null ) - { - return null; - } - - // deobfuscate the superclass name - classIndex = m_classesByObf.get( obfSuperclassName ); - if( classIndex == null ) - { - return null; - } - - return classIndex.getDeobfName(); - } -} diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 4dff6935..c7cb6a67 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -20,6 +20,8 @@ import java.util.zip.GZIPInputStream; import com.google.common.collect.Maps; import cuchaz.enigma.Util; +import cuchaz.enigma.analysis.Ancestries; +import cuchaz.enigma.analysis.DeobfuscatedAncestries; public class Mappings implements Serializable { diff --git a/src/cuchaz/enigma/mapping/Renamer.java b/src/cuchaz/enigma/mapping/Renamer.java index b7aa35ca..5a75c016 100644 --- a/src/cuchaz/enigma/mapping/Renamer.java +++ b/src/cuchaz/enigma/mapping/Renamer.java @@ -15,6 +15,9 @@ import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.zip.GZIPOutputStream; +import cuchaz.enigma.analysis.Ancestries; +import cuchaz.enigma.analysis.MethodInheritanceTreeNode; + public class Renamer { private Ancestries m_ancestries; @@ -54,6 +57,30 @@ public class Renamer classMapping.setFieldName( obf.getName(), deobfName ); } + public void setMethodTreeName( MethodEntry obf, String deobfName ) + { + // get the method tree + setMethodTreeName( + m_ancestries.getMethodInheritance( m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ), obf ), + deobfName + ); + } + + private void setMethodTreeName( MethodInheritanceTreeNode node, String deobfName ) + { + if( node.isImplemented() ) + { + // apply the name here + setMethodName( node.getMethodEntry(), deobfName ); + } + + // recurse + for( int i=0; i m_obfClassNames; @@ -65,9 +65,9 @@ public class Deobfuscator InputStream jarIn = null; try { - m_ancestries = new Ancestries(); + m_jarIndex = new JarIndex(); jarIn = new FileInputStream( m_file ); - m_ancestries.readFromJar( jarIn ); + m_jarIndex.indexJar( jarIn ); } finally { @@ -107,9 +107,9 @@ public class Deobfuscator return m_file.getName(); } - public Ancestries getAncestries( ) + public JarIndex getJarIndex( ) { - return m_ancestries; + return m_jarIndex; } public Mappings getMappings( ) @@ -123,7 +123,7 @@ public class Deobfuscator val = new Mappings(); } m_mappings = val; - m_renamer = new Renamer( m_ancestries, m_mappings ); + m_renamer = new Renamer( m_jarIndex, m_mappings ); // update decompiler options m_settings.setTypeLoader( new TranslatingTypeLoader( @@ -135,7 +135,7 @@ public class Deobfuscator public Translator getTranslator( TranslationDirection direction ) { - return m_mappings.getTranslator( m_ancestries, direction ); + return m_mappings.getTranslator( m_jarIndex.getAncestries(), direction ); } public void getSeparatedClasses( List obfClasses, List deobfClasses ) diff --git a/src/cuchaz/enigma/analysis/Ancestries.java b/src/cuchaz/enigma/analysis/Ancestries.java index e6c8bbf1..83c239cd 100644 --- a/src/cuchaz/enigma/analysis/Ancestries.java +++ b/src/cuchaz/enigma/analysis/Ancestries.java @@ -10,110 +10,27 @@ ******************************************************************************/ package cuchaz.enigma.analysis; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; import java.io.Serializable; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import javassist.ByteArrayClassPath; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.NotFoundException; import javassist.bytecode.Descriptor; -import javassist.bytecode.MethodInfo; -import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Translator; public class Ancestries implements Serializable { private static final long serialVersionUID = 738687982126844179L; private Map m_superclasses; - private Multimap m_methodImplementations; public Ancestries( ) { m_superclasses = Maps.newHashMap(); - m_methodImplementations = HashMultimap.create(); } - @SuppressWarnings( "unchecked" ) - public void readFromJar( InputStream in ) - throws IOException - { - ClassPool classPool = new ClassPool(); - - ZipInputStream zin = new ZipInputStream( in ); - ZipEntry entry; - while( ( entry = zin.getNextEntry() ) != null ) - { - // filter out non-classes - if( entry.isDirectory() || !entry.getName().endsWith( ".class" ) ) - { - continue; - } - - // read the class into a buffer - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] buf = new byte[Constants.KiB]; - int totalNumBytesRead = 0; - while( zin.available() > 0 ) - { - int numBytesRead = zin.read( buf ); - if( numBytesRead < 0 ) - { - break; - } - bos.write( buf, 0, numBytesRead ); - - // sanity checking - totalNumBytesRead += numBytesRead; - if( totalNumBytesRead > Constants.MiB ) - { - throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" ); - } - } - - // determine the class name (ie chop off the ".class") - String className = Descriptor.toJavaName( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) ); - - // get a javassist handle for the class - classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); - try - { - CtClass c = classPool.get( className ); - addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); - addMethodImplementations( c.getName(), (List)c.getClassFile().getMethods() ); - } - catch( NotFoundException ex ) - { - throw new Error( "Unable to load class: " + className ); - } - } - } - - private void addMethodImplementations( String name, List methods ) - { - for( MethodInfo method : methods ) - { - m_methodImplementations.put( name, getMethodKey( method.getName(), method.getDescriptor() ) ); - } - } - public void addSuperclass( String className, String superclassName ) { className = Descriptor.toJvmName( className ); @@ -165,71 +82,9 @@ public class Ancestries implements Serializable return subclasses; } - public boolean isMethodImplemented( MethodEntry methodEntry ) - { - return isMethodImplemented( methodEntry.getClassName(), methodEntry.getName(), methodEntry.getSignature() ); - } - - public boolean isMethodImplemented( String className, String methodName, String methodSignature ) - { - Collection implementations = m_methodImplementations.get( className ); - if( implementations == null ) - { - return false; - } - return implementations.contains( getMethodKey( methodName, methodSignature ) ); - } - - public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) - { - // get the root node - List ancestry = getAncestry( obfClassEntry.getName() ); - ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) ); - - // expand all children recursively - rootNode.load( this, true ); - - return rootNode; - } - - public MethodInheritanceTreeNode getMethodInheritance( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) - { - // travel to the ancestor implementation - String baseImplementationClassName = obfMethodEntry.getClassName(); - for( String ancestorClassName : getAncestry( obfMethodEntry.getClassName() ) ) - { - if( isMethodImplemented( ancestorClassName, obfMethodEntry.getName(), obfMethodEntry.getSignature() ) ) - { - baseImplementationClassName = ancestorClassName; - } - } - - // make a root node at the base - MethodEntry methodEntry = new MethodEntry( - new ClassEntry( baseImplementationClassName ), - obfMethodEntry.getName(), - obfMethodEntry.getSignature() - ); - MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( - deobfuscatingTranslator, - methodEntry, - isMethodImplemented( methodEntry ) - ); - - // expand the full tree - rootNode.load( this, true ); - - return rootNode; - } - private boolean isJre( String className ) { return className.startsWith( "java/" ) || className.startsWith( "javax/" ); } - - private String getMethodKey( String name, String signature ) - { - return name + signature; - } } diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java new file mode 100644 index 00000000..8a8384c6 --- /dev/null +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -0,0 +1,176 @@ +/******************************************************************************* + * 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.analysis; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +import javassist.ByteArrayClassPath; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.NotFoundException; +import javassist.bytecode.Descriptor; +import javassist.bytecode.MethodInfo; +import cuchaz.enigma.Constants; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.Translator; + +public class JarIndex +{ + private Ancestries m_ancestries; + private Multimap m_methodImplementations; + + public JarIndex( ) + { + m_ancestries = new Ancestries(); + m_methodImplementations = HashMultimap.create(); + } + + @SuppressWarnings( "unchecked" ) + public void indexJar( InputStream in ) + throws IOException + { + ClassPool classPool = new ClassPool(); + + ZipInputStream zin = new ZipInputStream( in ); + ZipEntry entry; + while( ( entry = zin.getNextEntry() ) != null ) + { + // filter out non-classes + if( entry.isDirectory() || !entry.getName().endsWith( ".class" ) ) + { + continue; + } + + // read the class into a buffer + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buf = new byte[Constants.KiB]; + int totalNumBytesRead = 0; + while( zin.available() > 0 ) + { + int numBytesRead = zin.read( buf ); + if( numBytesRead < 0 ) + { + break; + } + bos.write( buf, 0, numBytesRead ); + + // sanity checking + totalNumBytesRead += numBytesRead; + if( totalNumBytesRead > Constants.MiB ) + { + throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" ); + } + } + + // determine the class name (ie chop off the ".class") + String className = Descriptor.toJavaName( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) ); + + // get a javassist handle for the class + classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); + try + { + CtClass c = classPool.get( className ); + m_ancestries.addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); + addMethodImplementations( c.getName(), (List)c.getClassFile().getMethods() ); + } + catch( NotFoundException ex ) + { + throw new Error( "Unable to load class: " + className ); + } + } + } + + private void addMethodImplementations( String name, List methods ) + { + for( MethodInfo method : methods ) + { + m_methodImplementations.put( name, getMethodKey( method.getName(), method.getDescriptor() ) ); + } + } + + public Ancestries getAncestries( ) + { + return m_ancestries; + } + + public boolean isMethodImplemented( MethodEntry methodEntry ) + { + return isMethodImplemented( methodEntry.getClassName(), methodEntry.getName(), methodEntry.getSignature() ); + } + + public boolean isMethodImplemented( String className, String methodName, String methodSignature ) + { + Collection implementations = m_methodImplementations.get( className ); + if( implementations == null ) + { + return false; + } + return implementations.contains( getMethodKey( methodName, methodSignature ) ); + } + + + public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) + { + // get the root node + List ancestry = m_ancestries.getAncestry( obfClassEntry.getName() ); + ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) ); + + // expand all children recursively + rootNode.load( m_ancestries, true ); + + return rootNode; + } + + public MethodInheritanceTreeNode getMethodInheritance( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) + { + // travel to the ancestor implementation + String baseImplementationClassName = obfMethodEntry.getClassName(); + for( String ancestorClassName : m_ancestries.getAncestry( obfMethodEntry.getClassName() ) ) + { + if( isMethodImplemented( ancestorClassName, obfMethodEntry.getName(), obfMethodEntry.getSignature() ) ) + { + baseImplementationClassName = ancestorClassName; + } + } + + // make a root node at the base + MethodEntry methodEntry = new MethodEntry( + new ClassEntry( baseImplementationClassName ), + obfMethodEntry.getName(), + obfMethodEntry.getSignature() + ); + MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( + deobfuscatingTranslator, + methodEntry, + isMethodImplemented( methodEntry ) + ); + + // expand the full tree + rootNode.load( this, true ); + + return rootNode; + } + + private String getMethodKey( String name, String signature ) + { + return name + signature; + } +} diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index 1fecf489..a28a9f46 100644 --- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java @@ -79,11 +79,11 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode } } - public void load( Ancestries ancestries, boolean recurse ) + public void load( JarIndex index, boolean recurse ) { // get all the child nodes List nodes = Lists.newArrayList(); - for( String subclassName : ancestries.getSubclasses( m_entry.getClassName() ) ) + for( String subclassName : index.getAncestries().getSubclasses( m_entry.getClassName() ) ) { MethodEntry methodEntry = new MethodEntry( new ClassEntry( subclassName ), @@ -93,7 +93,7 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode nodes.add( new MethodInheritanceTreeNode( m_deobfuscatingTranslator, methodEntry, - ancestries.isMethodImplemented( subclassName, m_entry.getName(), m_entry.getSignature() ) + index.isMethodImplemented( subclassName, m_entry.getName(), m_entry.getSignature() ) ) ); } @@ -107,7 +107,7 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { for( MethodInheritanceTreeNode node : nodes ) { - node.load( ancestries, true ); + node.load( index, true ); } } } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 1946b4a3..880f001f 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -132,7 +132,7 @@ public class GuiController public ClassInheritanceTreeNode getClassInheritance( ClassEntry obfClassEntry ) { - ClassInheritanceTreeNode rootNode = m_deobfuscator.getAncestries().getClassInheritance( + ClassInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getClassInheritance( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), obfClassEntry ); @@ -141,7 +141,7 @@ public class GuiController public MethodInheritanceTreeNode getMethodInheritance( MethodEntry obfMethodEntry ) { - MethodInheritanceTreeNode rootNode = m_deobfuscator.getAncestries().getMethodInheritance( + MethodInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodInheritance( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), obfMethodEntry ); diff --git a/src/cuchaz/enigma/mapping/Renamer.java b/src/cuchaz/enigma/mapping/Renamer.java index 5a75c016..d372575e 100644 --- a/src/cuchaz/enigma/mapping/Renamer.java +++ b/src/cuchaz/enigma/mapping/Renamer.java @@ -15,17 +15,17 @@ import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.zip.GZIPOutputStream; -import cuchaz.enigma.analysis.Ancestries; +import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; public class Renamer { - private Ancestries m_ancestries; + private JarIndex m_index; private Mappings m_mappings; - public Renamer( Ancestries ancestries, Mappings mappings ) + public Renamer( JarIndex index, Mappings mappings ) { - m_ancestries = ancestries; + m_index = index; m_mappings = mappings; } @@ -61,7 +61,7 @@ public class Renamer { // get the method tree setMethodTreeName( - m_ancestries.getMethodInheritance( m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ), obf ), + m_index.getMethodInheritance( m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ), obf ), deobfName ); } @@ -90,7 +90,7 @@ public class Renamer classMapping = createClassMapping( obf.getClassEntry() ); } - String deobfSignature = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); + String deobfSignature = m_mappings.getTranslator( m_index.getAncestries(), 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 @@ -129,7 +129,7 @@ public class Renamer private void updateDeobfMethodSignatures( ) { - Translator translator = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ); + Translator translator = m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ); for( ClassMapping classMapping : m_mappings.m_classesByObf.values() ) { classMapping.updateDeobfMethodSignatures( translator ); -- cgit v1.2.3 From db1de7d32d8c6ef55627165448fd3f4f90802486 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 11 Aug 2014 23:19:32 -0400 Subject: fix keyboard shortcuts --- src/cuchaz/enigma/gui/Gui.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index db676777..3e8a18cb 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -260,9 +260,13 @@ public class Gui showInheritance(); break; - case KeyEvent.VK_O: + case KeyEvent.VK_N: openEntry(); break; + + case KeyEvent.VK_P: + m_controller.openPreviousEntry(); + break; } } } ); -- cgit v1.2.3 From 52bb7ba51ceaf65f40e5e3e2de9d1ac3f7fc9c2e Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 12 Aug 2014 00:24:11 -0400 Subject: got simple method call graph working! --- src/cuchaz/enigma/Deobfuscator.java | 34 +------ src/cuchaz/enigma/analysis/JarIndex.java | 101 ++++++++++++++++++--- .../enigma/analysis/MethodCallsTreeNode.java | 96 ++++++++++++++++++++ src/cuchaz/enigma/gui/Gui.java | 93 +++++++++++++++++-- src/cuchaz/enigma/gui/GuiController.java | 11 +++ 5 files changed, 284 insertions(+), 51 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/MethodCallsTreeNode.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index c35a4835..33eef08a 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -15,12 +15,9 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; -import java.util.Enumeration; import java.util.List; -import java.util.jar.JarEntry; import java.util.jar.JarFile; -import com.google.common.collect.Lists; import com.strobel.assembler.metadata.MetadataSystem; import com.strobel.assembler.metadata.TypeDefinition; import com.strobel.decompiler.DecompilerContext; @@ -53,7 +50,6 @@ public class Deobfuscator private JarIndex m_jarIndex; private Mappings m_mappings; private Renamer m_renamer; - private List m_obfClassNames; public Deobfuscator( File file ) throws IOException @@ -65,7 +61,7 @@ public class Deobfuscator InputStream jarIn = null; try { - m_jarIndex = new JarIndex(); + m_jarIndex = new JarIndex( m_jar ); jarIn = new FileInputStream( m_file ); m_jarIndex.indexJar( jarIn ); } @@ -74,26 +70,6 @@ public class Deobfuscator Util.closeQuietly( jarIn ); } - // get the obf class names - m_obfClassNames = Lists.newArrayList(); - { - Enumeration entries = m_jar.entries(); - while( entries.hasMoreElements() ) - { - JarEntry entry = entries.nextElement(); - - // skip everything but class files - if( !entry.getName().endsWith( ".class" ) ) - { - continue; - } - - // get the class name from the file - String className = entry.getName().substring( 0, entry.getName().length() - 6 ); - m_obfClassNames.add( className ); - } - } - // config the decompiler m_settings = DecompilerSettings.javaDefaults(); m_settings.setShowSyntheticMembers( true ); @@ -140,7 +116,7 @@ public class Deobfuscator public void getSeparatedClasses( List obfClasses, List deobfClasses ) { - for( String obfClassName : m_obfClassNames ) + for( String obfClassName : m_jarIndex.getObfClassNames() ) { // separate the classes ClassMapping classMapping = m_mappings.getClassByObf( obfClassName ); @@ -302,15 +278,15 @@ public class Deobfuscator if( obfEntry instanceof ClassEntry ) { // obf classes must be in the list - return m_obfClassNames.contains( obfEntry.getName() ); + return m_jarIndex.getObfClassNames().contains( obfEntry.getName() ); } else if( obfEntry instanceof FieldEntry ) { - return m_obfClassNames.contains( ((FieldEntry)obfEntry).getClassName() ); + return m_jarIndex.getObfClassNames().contains( ((FieldEntry)obfEntry).getClassName() ); } else if( obfEntry instanceof MethodEntry ) { - return m_obfClassNames.contains( ((MethodEntry)obfEntry).getClassName() ); + return m_jarIndex.getObfClassNames().contains( ((MethodEntry)obfEntry).getClassName() ); } else if( obfEntry instanceof ArgumentEntry ) { diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 8a8384c6..06b01736 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -14,19 +14,28 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Collection; +import java.util.Enumeration; import java.util.List; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; - import javassist.ByteArrayClassPath; +import javassist.CannotCompileException; import javassist.ClassPool; +import javassist.CtBehavior; import javassist.CtClass; import javassist.NotFoundException; import javassist.bytecode.Descriptor; -import javassist.bytecode.MethodInfo; +import javassist.expr.ExprEditor; +import javassist.expr.MethodCall; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; + import cuchaz.enigma.Constants; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.MethodEntry; @@ -34,16 +43,35 @@ import cuchaz.enigma.mapping.Translator; public class JarIndex { + private Set m_obfClassNames; private Ancestries m_ancestries; - private Multimap m_methodImplementations; + private Multimap m_methodImplementations; + private Multimap m_methodCalls; - public JarIndex( ) + public JarIndex( JarFile jar ) { + m_obfClassNames = Sets.newHashSet(); m_ancestries = new Ancestries(); m_methodImplementations = HashMultimap.create(); + m_methodCalls = HashMultimap.create(); + + // read the class names + Enumeration enumeration = jar.entries(); + while( enumeration.hasMoreElements() ) + { + JarEntry entry = enumeration.nextElement(); + + // filter out non-classes + if( entry.isDirectory() || !entry.getName().endsWith( ".class" ) ) + { + continue; + } + + String className = entry.getName().substring( 0, entry.getName().length() - 6 ); + m_obfClassNames.add( Descriptor.toJvmName( className ) ); + } } - @SuppressWarnings( "unchecked" ) public void indexJar( InputStream in ) throws IOException { @@ -89,7 +117,10 @@ public class JarIndex { CtClass c = classPool.get( className ); m_ancestries.addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); - addMethodImplementations( c.getName(), (List)c.getClassFile().getMethods() ); + for( CtBehavior behavior : c.getDeclaredBehaviors() ) + { + indexBehavior( behavior ); + } } catch( NotFoundException ex ) { @@ -98,14 +129,55 @@ public class JarIndex } } - private void addMethodImplementations( String name, List methods ) + private void indexBehavior( CtBehavior behavior ) { - for( MethodInfo method : methods ) + // get the method entry + String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); + final MethodEntry methodEntry = new MethodEntry( + new ClassEntry( className ), + behavior.getName(), + behavior.getSignature() + ); + + // index implementation + m_methodImplementations.put( className, methodEntry ); + + // index method calls + try + { + behavior.instrument( new ExprEditor( ) + { + @Override + public void edit( MethodCall call ) + { + // is this a jar class? + String className = Descriptor.toJvmName( call.getClassName() ); + if( !m_obfClassNames.contains( className ) ) + { + return; + } + + // make entry for the called method + MethodEntry calledMethodEntry = new MethodEntry( + new ClassEntry( className ), + call.getMethodName(), + call.getSignature() + ); + m_methodCalls.put( calledMethodEntry, methodEntry ); + } + } ); + } + catch( CannotCompileException ex ) { - m_methodImplementations.put( name, getMethodKey( method.getName(), method.getDescriptor() ) ); + throw new Error( ex ); } } + public Set getObfClassNames( ) + { + return m_obfClassNames; + } + public Ancestries getAncestries( ) { return m_ancestries; @@ -118,7 +190,7 @@ public class JarIndex public boolean isMethodImplemented( String className, String methodName, String methodSignature ) { - Collection implementations = m_methodImplementations.get( className ); + Collection implementations = m_methodImplementations.get( className ); if( implementations == null ) { return false; @@ -169,6 +241,11 @@ public class JarIndex return rootNode; } + public Collection getMethodCallers( MethodEntry methodEntry ) + { + return m_methodCalls.get( methodEntry ); + } + private String getMethodKey( String name, String signature ) { return name + signature; diff --git a/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java b/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java new file mode 100644 index 00000000..dedfb2e7 --- /dev/null +++ b/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * 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.analysis; + +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; + +import com.google.common.collect.Lists; + +import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.Translator; + +public class MethodCallsTreeNode extends DefaultMutableTreeNode +{ + private static final long serialVersionUID = -3658163700783307520L; + + private Translator m_deobfuscatingTranslator; + private MethodEntry m_entry; + + public MethodCallsTreeNode( Translator deobfuscatingTranslator, MethodEntry entry ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = entry; + } + + public MethodEntry getMethodEntry( ) + { + return m_entry; + } + + public String getDeobfClassName( ) + { + return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() ); + } + + public String getDeobfMethodName( ) + { + return m_deobfuscatingTranslator.translate( m_entry ); + } + + @Override + public String toString( ) + { + String className = getDeobfClassName(); + if( className == null ) + { + className = m_entry.getClassName(); + } + + String methodName = getDeobfMethodName(); + if( methodName == null ) + { + methodName = m_entry.getName(); + } + return className + "." + methodName + "()"; + } + + public void load( JarIndex index, boolean recurse ) + { + // get all the child nodes + List nodes = Lists.newArrayList(); + for( MethodEntry entry : index.getMethodCallers( m_entry ) ) + { + nodes.add( new MethodCallsTreeNode( m_deobfuscatingTranslator, entry ) ); + } + + // add them to this node + for( MethodCallsTreeNode node : nodes ) + { + this.add( node ); + } + + if( recurse ) + { + for( MethodCallsTreeNode node : nodes ) + { + // don't recurse into self + if( node.getMethodEntry().equals( m_entry ) ) + { + continue; + } + + node.load( index, true ); + } + } + } +} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 3e8a18cb..072fb3a5 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -67,6 +67,7 @@ import com.google.common.collect.Lists; import cuchaz.enigma.Constants; import cuchaz.enigma.analysis.ClassInheritanceTreeNode; +import cuchaz.enigma.analysis.MethodCallsTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ArgumentEntry; @@ -139,6 +140,8 @@ public class Gui private BoxHighlightPainter m_obfuscatedHighlightPainter; private BoxHighlightPainter m_deobfuscatedHighlightPainter; private JTree m_inheritanceTree; + private JTree m_callsTree; + private JTabbedPane m_tabs; // dynamic menu items private JMenuItem m_closeJarMenu; @@ -147,9 +150,10 @@ public class Gui private JMenuItem m_saveMappingsAsMenu; private JMenuItem m_closeMappingsMenu; private JMenuItem m_renameMenu; - private JMenuItem m_inheritanceMenu; + private JMenuItem m_showInheritanceMenu; private JMenuItem m_openEntryMenu; private JMenuItem m_openPreviousMenu; + private JMenuItem m_showCallsMenu; // state private EntryPair m_selectedEntryPair; @@ -267,6 +271,10 @@ public class Gui case KeyEvent.VK_P: m_controller.openPreviousEntry(); break; + + case KeyEvent.VK_C: + showCalls(); + break; } } } ); @@ -306,7 +314,22 @@ public class Gui menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_I, 0 ) ); menu.setEnabled( false ); popupMenu.add( menu ); - m_inheritanceMenu = menu; + m_showInheritanceMenu = menu; + } + { + JMenuItem menu = new JMenuItem( "Show Calls" ); + menu.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + showCalls(); + } + } ); + menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_C, 0 ) ); + menu.setEnabled( false ); + popupMenu.add( menu ); + m_showCallsMenu = menu; } { JMenuItem menu = new JMenuItem( "Go to Declaration" ); @@ -350,12 +373,13 @@ public class Gui if( event.getClickCount() == 2 ) { // get the selected node - Object node = m_inheritanceTree.getSelectionPath().getLastPathComponent(); - if( node == null ) + TreePath path = m_inheritanceTree.getSelectionPath(); + if( path == null ) { return; } + Object node = path.getLastPathComponent(); if( node instanceof ClassInheritanceTreeNode ) { m_controller.openEntry( new ClassEntry( ((ClassInheritanceTreeNode)node).getObfClassName() ) ); @@ -375,17 +399,47 @@ public class Gui inheritancePanel.setLayout( new BorderLayout() ); inheritancePanel.add( new JScrollPane( m_inheritanceTree ) ); + // init call panel + m_callsTree = new JTree(); + m_callsTree.setModel( null ); + m_callsTree.addMouseListener( new MouseAdapter( ) + { + @Override + public void mouseClicked( MouseEvent event ) + { + if( event.getClickCount() == 2 ) + { + // get the selected node + TreePath path = m_callsTree.getSelectionPath(); + if( path == null ) + { + return; + } + + Object node = path.getLastPathComponent(); + if( node instanceof MethodCallsTreeNode ) + { + m_controller.openEntry( ((MethodCallsTreeNode)node).getMethodEntry() ); + } + } + } + } ); + JPanel callPanel = new JPanel(); + callPanel.setLayout( new BorderLayout() ); + callPanel.add( new JScrollPane( m_callsTree ) ); + // layout controls JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); - splitLeft.setPreferredSize( new Dimension( 200, 0 ) ); + splitLeft.setPreferredSize( new Dimension( 250, 0 ) ); JPanel centerPanel = new JPanel(); centerPanel.setLayout( new BorderLayout() ); centerPanel.add( m_infoPanel, BorderLayout.NORTH ); centerPanel.add( sourceScroller, BorderLayout.CENTER ); - JTabbedPane tabbedPane = new JTabbedPane(); - tabbedPane.setPreferredSize( new Dimension( 200, 0 ) ); - tabbedPane.addTab( "Inheritance", inheritancePanel ); - JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, tabbedPane ); + m_tabs = new JTabbedPane(); + m_tabs.setPreferredSize( new Dimension( 250, 0 ) ); + m_tabs.addTab( "Inheritance", inheritancePanel ); + m_tabs.addTab( "Method Calls", callPanel ); + JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs ); splitRight.setResizeWeight( 1 ); // let the left side take all the slack splitRight.resetToPreferredSizes(); JSplitPane splitCenter = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, splitRight ); @@ -784,7 +838,8 @@ public class Gui showEntryPair( m_selectedEntryPair ); - m_inheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); + m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); + m_showCallsMenu.setEnabled( isMethodEntry ); m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry ); m_openPreviousMenu.setEnabled( m_controller.hasPreviousEntry() ); } @@ -879,6 +934,24 @@ public class Gui m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); } + m_tabs.setSelectedIndex( 0 ); + redraw(); + } + + private void showCalls( ) + { + if( m_selectedEntryPair == null ) + { + return; + } + + if( m_selectedEntryPair.obf instanceof MethodEntry ) + { + MethodCallsTreeNode node = m_controller.getMethodCalls( (MethodEntry)m_selectedEntryPair.obf ); + m_callsTree.setModel( new DefaultTreeModel( node ) ); + } + + m_tabs.setSelectedIndex( 1 ); redraw(); } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 880f001f..b54aeba3 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -21,6 +21,7 @@ import com.google.common.collect.Lists; import cuchaz.enigma.Deobfuscator; import cuchaz.enigma.analysis.ClassInheritanceTreeNode; +import cuchaz.enigma.analysis.MethodCallsTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.Token; @@ -148,6 +149,16 @@ public class GuiController return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); } + public MethodCallsTreeNode getMethodCalls( MethodEntry obfMethodEntry ) + { + MethodCallsTreeNode rootNode = new MethodCallsTreeNode( + m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + obfMethodEntry + ); + rootNode.load( m_deobfuscator.getJarIndex(), true ); + return rootNode; + } + public void rename( Entry obfEntry, String newName ) { m_deobfuscator.rename( obfEntry, newName ); -- cgit v1.2.3 From cc74d0e62cfdcf14c5918234f69d587d264807ed Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 13 Aug 2014 00:22:12 -0400 Subject: added support for field access searches added proper detection/handling for constructors --- src/cuchaz/enigma/Deobfuscator.java | 30 +++++- src/cuchaz/enigma/analysis/FieldCallsTreeNode.java | 82 +++++++++++++++ src/cuchaz/enigma/analysis/JarIndex.java | 107 +++++++++++++++---- .../enigma/analysis/MethodCallsTreeNode.java | 114 +++++++++++++++------ src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 5 +- src/cuchaz/enigma/gui/Gui.java | 60 ++++++++--- src/cuchaz/enigma/gui/GuiController.java | 38 ++++++- src/cuchaz/enigma/mapping/ConstructorEntry.java | 94 +++++++++++++++++ src/cuchaz/enigma/mapping/Translator.java | 8 ++ 9 files changed, 460 insertions(+), 78 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/FieldCallsTreeNode.java create mode 100644 src/cuchaz/enigma/mapping/ConstructorEntry.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 33eef08a..770172e3 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -34,6 +34,7 @@ import cuchaz.enigma.analysis.SourceIndexVisitor; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ClassMapping; +import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.Mappings; @@ -185,6 +186,10 @@ public class Deobfuscator { m_renamer.setMethodTreeName( (MethodEntry)obfEntry, newName ); } + else if( obfEntry instanceof ConstructorEntry ) + { + m_renamer.setClassName( obfEntry.getClassEntry(), newName ); + } else if( obfEntry instanceof ArgumentEntry ) { m_renamer.setArgumentName( (ArgumentEntry)obfEntry, newName ); @@ -210,6 +215,10 @@ public class Deobfuscator { return translator.translateEntry( (MethodEntry)deobfEntry ); } + else if( deobfEntry instanceof ConstructorEntry ) + { + return translator.translateEntry( (ConstructorEntry)deobfEntry ); + } else if( deobfEntry instanceof ArgumentEntry ) { return translator.translateEntry( (ArgumentEntry)deobfEntry ); @@ -235,6 +244,10 @@ public class Deobfuscator { return translator.translateEntry( (MethodEntry)obfEntry ); } + else if( obfEntry instanceof ConstructorEntry ) + { + return translator.translateEntry( (ConstructorEntry)obfEntry ); + } else if( obfEntry instanceof ArgumentEntry ) { return translator.translateEntry( (ArgumentEntry)obfEntry ); @@ -263,6 +276,11 @@ public class Deobfuscator String deobfName = translator.translate( (MethodEntry)obfEntry ); return deobfName != null && !deobfName.equals( obfEntry.getName() ); } + else if( obfEntry instanceof ConstructorEntry ) + { + String deobfName = translator.translate( obfEntry.getClassEntry() ); + return deobfName != null && !deobfName.equals( obfEntry.getClassName() ); + } else if( obfEntry instanceof ArgumentEntry ) { return translator.translate( (ArgumentEntry)obfEntry ) != null; @@ -282,16 +300,20 @@ public class Deobfuscator } else if( obfEntry instanceof FieldEntry ) { - return m_jarIndex.getObfClassNames().contains( ((FieldEntry)obfEntry).getClassName() ); + return m_jarIndex.getObfClassNames().contains( obfEntry.getClassName() ); } else if( obfEntry instanceof MethodEntry ) { - return m_jarIndex.getObfClassNames().contains( ((MethodEntry)obfEntry).getClassName() ); + return m_jarIndex.getObfClassNames().contains( obfEntry.getClassName() ); + } + else if( obfEntry instanceof ConstructorEntry ) + { + return m_jarIndex.getObfClassNames().contains( obfEntry.getClassName() ); } else if( obfEntry instanceof ArgumentEntry ) { - // arguments only appear in method delcarations - // since we only show declrations for obf classes, these are always obfuscated + // arguments only appear in method declarations + // since we only show declarations for obf classes, these are always obfuscated return true; } diff --git a/src/cuchaz/enigma/analysis/FieldCallsTreeNode.java b/src/cuchaz/enigma/analysis/FieldCallsTreeNode.java new file mode 100644 index 00000000..0427b3be --- /dev/null +++ b/src/cuchaz/enigma/analysis/FieldCallsTreeNode.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * 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.analysis; + +import javax.swing.tree.DefaultMutableTreeNode; + +import cuchaz.enigma.mapping.ConstructorEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.Translator; + +public class FieldCallsTreeNode extends DefaultMutableTreeNode +{ + private static final long serialVersionUID = -7934108091928699835L; + + private Translator m_deobfuscatingTranslator; + private FieldEntry m_entry; + + public FieldCallsTreeNode( Translator deobfuscatingTranslator, FieldEntry fieldEntry ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = fieldEntry; + } + + public FieldEntry getFieldEntry( ) + { + return m_entry; + } + + @Override + public String toString( ) + { + String className = m_deobfuscatingTranslator.translateClass( m_entry.getClassName() ); + if( className == null ) + { + className = m_entry.getClassName(); + } + + String targetName = m_deobfuscatingTranslator.translate( m_entry ); + if( targetName == null ) + { + targetName = m_entry.getName(); + } + return className + "." + targetName; + } + + public void load( JarIndex index, boolean recurse ) + { + // get all the child nodes + for( Entry entry : index.getFieldCallers( m_entry ) ) + { + if( entry instanceof MethodEntry ) + { + add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (MethodEntry)entry ) ); + } + else if( entry instanceof ConstructorEntry ) + { + add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (ConstructorEntry)entry ) ); + } + } + + if( recurse && children != null ) + { + for( Object node : children ) + { + if( node instanceof MethodCallsTreeNode ) + { + ((MethodCallsTreeNode)node).load( index, true ); + } + } + } + } +} diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 06b01736..96bddc17 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -27,17 +27,26 @@ import javassist.CannotCompileException; import javassist.ClassPool; import javassist.CtBehavior; import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtMethod; import javassist.NotFoundException; import javassist.bytecode.Descriptor; +import javassist.expr.ConstructorCall; import javassist.expr.ExprEditor; +import javassist.expr.FieldAccess; import javassist.expr.MethodCall; +import javassist.expr.NewExpr; import com.google.common.collect.HashMultimap; +import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import cuchaz.enigma.Constants; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.Translator; @@ -46,7 +55,8 @@ public class JarIndex private Set m_obfClassNames; private Ancestries m_ancestries; private Multimap m_methodImplementations; - private Multimap m_methodCalls; + private Multimap m_methodCalls; + private Multimap m_fieldCalls; public JarIndex( JarFile jar ) { @@ -54,6 +64,7 @@ public class JarIndex m_ancestries = new Ancestries(); m_methodImplementations = HashMultimap.create(); m_methodCalls = HashMultimap.create(); + m_fieldCalls = HashMultimap.create(); // read the class names Enumeration enumeration = jar.entries(); @@ -133,14 +144,30 @@ public class JarIndex { // get the method entry String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); - final MethodEntry methodEntry = new MethodEntry( - new ClassEntry( className ), - behavior.getName(), - behavior.getSignature() - ); - - // index implementation - m_methodImplementations.put( className, methodEntry ); + final Entry thisEntry; + if( behavior instanceof CtMethod ) + { + MethodEntry methodEntry = new MethodEntry( + new ClassEntry( className ), + behavior.getName(), + behavior.getSignature() + ); + thisEntry = methodEntry; + + // index implementation + m_methodImplementations.put( className, methodEntry ); + } + else if( behavior instanceof CtConstructor ) + { + thisEntry = new ConstructorEntry( + new ClassEntry( className ), + behavior.getSignature() + ); + } + else + { + throw new IllegalArgumentException( "behavior must be a method or a constructor!" ); + } // index method calls try @@ -150,20 +177,53 @@ public class JarIndex @Override public void edit( MethodCall call ) { - // is this a jar class? String className = Descriptor.toJvmName( call.getClassName() ); - if( !m_obfClassNames.contains( className ) ) - { - return; - } - - // make entry for the called method MethodEntry calledMethodEntry = new MethodEntry( new ClassEntry( className ), call.getMethodName(), call.getSignature() ); - m_methodCalls.put( calledMethodEntry, methodEntry ); + m_methodCalls.put( calledMethodEntry, thisEntry ); + } + + @Override + public void edit( FieldAccess call ) + { + String className = Descriptor.toJvmName( call.getClassName() ); + FieldEntry calledFieldEntry = new FieldEntry( + new ClassEntry( className ), + call.getFieldName() + ); + m_fieldCalls.put( calledFieldEntry, thisEntry ); + } + + @Override + public void edit( ConstructorCall call ) + { + String className = Descriptor.toJvmName( call.getClassName() ); + ConstructorEntry calledConstructorEntry = new ConstructorEntry( + new ClassEntry( className ), + call.getSignature() + ); + m_methodCalls.put( calledConstructorEntry, thisEntry ); + } + + @Override + public void edit( NewExpr call ) + { + String className = Descriptor.toJvmName( call.getClassName() ); + ConstructorEntry calledConstructorEntry = new ConstructorEntry( + new ClassEntry( className ), + call.getSignature() + ); + + // TEMP + if( className.equals( "bgw" ) ) + { + System.out.println( calledConstructorEntry + " called by " + thisEntry ); + } + + m_methodCalls.put( calledConstructorEntry, thisEntry ); } } ); } @@ -202,7 +262,9 @@ public class JarIndex public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) { // get the root node - List ancestry = m_ancestries.getAncestry( obfClassEntry.getName() ); + List ancestry = Lists.newArrayList(); + ancestry.add( obfClassEntry.getName() ); + ancestry.addAll( m_ancestries.getAncestry( obfClassEntry.getName() ) ); ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) ); // expand all children recursively @@ -241,9 +303,14 @@ public class JarIndex return rootNode; } - public Collection getMethodCallers( MethodEntry methodEntry ) + public Collection getFieldCallers( FieldEntry fieldEntry ) + { + return m_fieldCalls.get( fieldEntry ); + } + + public Collection getMethodCallers( Entry entry ) { - return m_methodCalls.get( methodEntry ); + return m_methodCalls.get( entry ); } private String getMethodKey( String name, String signature ) diff --git a/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java b/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java index dedfb2e7..b5cf4c33 100644 --- a/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java @@ -10,12 +10,15 @@ ******************************************************************************/ package cuchaz.enigma.analysis; -import java.util.List; +import java.util.Set; import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeNode; -import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import cuchaz.enigma.mapping.ConstructorEntry; +import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.Translator; @@ -24,72 +27,117 @@ public class MethodCallsTreeNode extends DefaultMutableTreeNode private static final long serialVersionUID = -3658163700783307520L; private Translator m_deobfuscatingTranslator; - private MethodEntry m_entry; + private MethodEntry m_methodEntry; + private ConstructorEntry m_constructorEntry; public MethodCallsTreeNode( Translator deobfuscatingTranslator, MethodEntry entry ) { m_deobfuscatingTranslator = deobfuscatingTranslator; - m_entry = entry; + m_methodEntry = entry; + m_constructorEntry = null; + } + + public MethodCallsTreeNode( Translator deobfuscatingTranslator, ConstructorEntry entry ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_methodEntry = null; + m_constructorEntry = entry; } public MethodEntry getMethodEntry( ) { - return m_entry; + return m_methodEntry; } - public String getDeobfClassName( ) + public ConstructorEntry getConstructorEntry( ) { - return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() ); + return m_constructorEntry; } - public String getDeobfMethodName( ) + public Entry getEntry( ) { - return m_deobfuscatingTranslator.translate( m_entry ); + if( m_methodEntry != null ) + { + return m_methodEntry; + } + else if( m_constructorEntry != null ) + { + return m_constructorEntry; + } + throw new Error( "Illegal state!" ); } @Override public String toString( ) { - String className = getDeobfClassName(); - if( className == null ) + if( m_methodEntry != null ) { - className = m_entry.getClassName(); + String className = m_deobfuscatingTranslator.translateClass( m_methodEntry.getClassName() ); + if( className == null ) + { + className = m_methodEntry.getClassName(); + } + + String methodName = m_deobfuscatingTranslator.translate( m_methodEntry ); + if( methodName == null ) + { + methodName = m_methodEntry.getName(); + } + return className + "." + methodName + "()"; } - - String methodName = getDeobfMethodName(); - if( methodName == null ) + else if( m_constructorEntry != null ) { - methodName = m_entry.getName(); + String className = m_deobfuscatingTranslator.translateClass( m_constructorEntry.getClassName() ); + if( className == null ) + { + className = m_constructorEntry.getClassName(); + } + return className + "()"; } - return className + "." + methodName + "()"; + throw new Error( "Illegal state!" ); } public void load( JarIndex index, boolean recurse ) { // get all the child nodes - List nodes = Lists.newArrayList(); - for( MethodEntry entry : index.getMethodCallers( m_entry ) ) + for( Entry entry : index.getMethodCallers( getEntry() ) ) { - nodes.add( new MethodCallsTreeNode( m_deobfuscatingTranslator, entry ) ); - } - - // add them to this node - for( MethodCallsTreeNode node : nodes ) - { - this.add( node ); + if( entry instanceof MethodEntry ) + { + add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (MethodEntry)entry ) ); + } + else if( entry instanceof ConstructorEntry ) + { + add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (ConstructorEntry)entry ) ); + } } - if( recurse ) + if( recurse && children != null ) { - for( MethodCallsTreeNode node : nodes ) + for( Object child : children ) { - // don't recurse into self - if( node.getMethodEntry().equals( m_entry ) ) + if( child instanceof MethodCallsTreeNode ) { - continue; + MethodCallsTreeNode node = (MethodCallsTreeNode)child; + + // don't recurse into ancestor + Set ancestors = Sets.newHashSet(); + TreeNode n = (TreeNode)node; + while( n.getParent() != null ) + { + n = n.getParent(); + if( n instanceof MethodCallsTreeNode ) + { + ancestors.add( ((MethodCallsTreeNode)n).getEntry() ); + } + } + if( ancestors.contains( node.getEntry() ) ) + { + continue; + } + + node.load( index, true ); } - - node.load( index, true ); } } } diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java index 0ba5996c..6c14ee99 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java @@ -93,6 +93,7 @@ import com.strobel.decompiler.patterns.Pattern; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MethodEntry; @@ -158,7 +159,9 @@ public class SourceIndexVisitor implements IAstVisitor public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) { MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); - index.add( node.getNameToken(), new ClassEntry( def.getDeclaringType().getInternalName() ) ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, def.getSignature() ); + index.addDeclaration( node.getNameToken(), constructorEntry ); return recurse( node, index ); } diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 072fb3a5..1d2d3ab1 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -67,11 +67,13 @@ import com.google.common.collect.Lists; import cuchaz.enigma.Constants; import cuchaz.enigma.analysis.ClassInheritanceTreeNode; +import cuchaz.enigma.analysis.FieldCallsTreeNode; import cuchaz.enigma.analysis.MethodCallsTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.EntryPair; import cuchaz.enigma.mapping.FieldEntry; @@ -419,7 +421,7 @@ public class Gui Object node = path.getLastPathComponent(); if( node instanceof MethodCallsTreeNode ) { - m_controller.openEntry( ((MethodCallsTreeNode)node).getMethodEntry() ); + m_controller.openEntry( ((MethodCallsTreeNode)node).getEntry() ); } } } @@ -438,7 +440,7 @@ public class Gui m_tabs = new JTabbedPane(); m_tabs.setPreferredSize( new Dimension( 250, 0 ) ); m_tabs.addTab( "Inheritance", inheritancePanel ); - m_tabs.addTab( "Method Calls", callPanel ); + m_tabs.addTab( "Call Graph", callPanel ); JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs ); splitRight.setResizeWeight( 1 ); // let the left side take all the slack splitRight.resetToPreferredSizes(); @@ -770,6 +772,10 @@ public class Gui { showMethodEntryPair( (EntryPair)pair ); } + else if( pair.deobf instanceof ConstructorEntry ) + { + showConstructorEntryPair( (EntryPair)pair ); + } else if( pair.deobf instanceof ArgumentEntry ) { showArgumentEntryPair( (EntryPair)pair ); @@ -800,6 +806,12 @@ public class Gui addNameValue( m_infoPanel, "Signature", pair.deobf.getSignature() ); } + private void showConstructorEntryPair( EntryPair pair ) + { + addNameValue( m_infoPanel, "Constructor", pair.deobf.getClassEntry().getName() ); + addNameValue( m_infoPanel, "Signature", pair.deobf.getSignature() ); + } + private void showArgumentEntryPair( EntryPair pair ) { addNameValue( m_infoPanel, "Argument", pair.deobf.getName() ); @@ -815,7 +827,7 @@ public class Gui container.add( panel ); JLabel label = new JLabel( name + ":", JLabel.RIGHT ); - label.setPreferredSize( new Dimension( 80, label.getPreferredSize().height ) ); + label.setPreferredSize( new Dimension( 100, label.getPreferredSize().height ) ); panel.add( label ); panel.add( unboldLabel( new JLabel( value, JLabel.LEFT ) ) ); @@ -824,23 +836,27 @@ public class Gui private void onCaretMove( int pos ) { Token token = m_controller.getToken( pos ); - m_renameMenu.setEnabled( token != null ); - if( token == null ) - { - clearEntryPair(); - return; - } + boolean isToken = token != null; m_selectedEntryPair = m_controller.getEntryPair( token ); - boolean isClassEntry = m_selectedEntryPair.obf instanceof ClassEntry; - boolean isFieldEntry = m_selectedEntryPair.obf instanceof FieldEntry; - boolean isMethodEntry = m_selectedEntryPair.obf instanceof MethodEntry; + boolean isClassEntry = isToken && m_selectedEntryPair.obf instanceof ClassEntry; + boolean isFieldEntry = isToken && m_selectedEntryPair.obf instanceof FieldEntry; + boolean isMethodEntry = isToken && m_selectedEntryPair.obf instanceof MethodEntry; + boolean isConstructorEntry = isToken && m_selectedEntryPair.obf instanceof ConstructorEntry; - showEntryPair( m_selectedEntryPair ); + if( isToken ) + { + showEntryPair( m_selectedEntryPair ); + } + else + { + clearEntryPair(); + } - m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); - m_showCallsMenu.setEnabled( isMethodEntry ); - m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry ); + m_renameMenu.setEnabled( isToken ); + m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry || isConstructorEntry ); + m_showCallsMenu.setEnabled( isFieldEntry || isMethodEntry || isConstructorEntry ); + m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); m_openPreviousMenu.setEnabled( m_controller.hasPreviousEntry() ); } @@ -945,11 +961,21 @@ public class Gui return; } - if( m_selectedEntryPair.obf instanceof MethodEntry ) + if( m_selectedEntryPair.obf instanceof FieldEntry ) + { + FieldCallsTreeNode node = m_controller.getFieldCalls( (FieldEntry)m_selectedEntryPair.obf ); + m_callsTree.setModel( new DefaultTreeModel( node ) ); + } + else if( m_selectedEntryPair.obf instanceof MethodEntry ) { MethodCallsTreeNode node = m_controller.getMethodCalls( (MethodEntry)m_selectedEntryPair.obf ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } + else if( m_selectedEntryPair.obf instanceof ConstructorEntry ) + { + MethodCallsTreeNode node = m_controller.getMethodCalls( (ConstructorEntry)m_selectedEntryPair.obf ); + m_callsTree.setModel( new DefaultTreeModel( node ) ); + } m_tabs.setSelectedIndex( 1 ); redraw(); diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index b54aeba3..534b0cc5 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -21,13 +21,16 @@ import com.google.common.collect.Lists; import cuchaz.enigma.Deobfuscator; import cuchaz.enigma.analysis.ClassInheritanceTreeNode; +import cuchaz.enigma.analysis.FieldCallsTreeNode; import cuchaz.enigma.analysis.MethodCallsTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.EntryPair; +import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MappingsReader; import cuchaz.enigma.mapping.MappingsWriter; import cuchaz.enigma.mapping.MethodEntry; @@ -118,6 +121,10 @@ public class GuiController } Entry deobfEntry = m_index.getEntry( token ); + if( deobfEntry == null ) + { + return null; + } return new EntryPair( m_deobfuscator.obfuscateEntry( deobfEntry ), deobfEntry ); } @@ -149,16 +156,41 @@ public class GuiController return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); } - public MethodCallsTreeNode getMethodCalls( MethodEntry obfMethodEntry ) + public FieldCallsTreeNode getFieldCalls( FieldEntry obfFieldEntry ) { - MethodCallsTreeNode rootNode = new MethodCallsTreeNode( + FieldCallsTreeNode rootNode = new FieldCallsTreeNode( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), - obfMethodEntry + obfFieldEntry ); rootNode.load( m_deobfuscator.getJarIndex(), true ); return rootNode; } + public MethodCallsTreeNode getMethodCalls( Entry obfEntry ) + { + MethodCallsTreeNode rootNode; + if( obfEntry instanceof MethodEntry ) + { + rootNode = new MethodCallsTreeNode( + m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + (MethodEntry)obfEntry + ); + } + else if( obfEntry instanceof ConstructorEntry ) + { + rootNode = new MethodCallsTreeNode( + m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + (ConstructorEntry)obfEntry + ); + } + else + { + throw new IllegalArgumentException( "entry must be a MethodEntry or a ConstructorEntry!" ); + } + rootNode.load( m_deobfuscator.getJarIndex(), true ); + return rootNode; + } + public void rename( Entry obfEntry, String newName ) { m_deobfuscator.rename( obfEntry, newName ); diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java new file mode 100644 index 00000000..e0fa7cf6 --- /dev/null +++ b/src/cuchaz/enigma/mapping/ConstructorEntry.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * 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 cuchaz.enigma.Util; + +public class ConstructorEntry implements Entry, Serializable +{ + private static final long serialVersionUID = -868346075317366758L; + + private ClassEntry m_classEntry; + private String m_signature; + + public ConstructorEntry( ClassEntry classEntry, String signature ) + { + if( classEntry == null ) + { + throw new IllegalArgumentException( "Class cannot be null!" ); + } + if( signature == null ) + { + throw new IllegalArgumentException( "Method signature cannot be null!" ); + } + + m_classEntry = classEntry; + m_signature = signature; + } + + public ConstructorEntry( ConstructorEntry other ) + { + m_classEntry = new ClassEntry( other.m_classEntry ); + m_signature = other.m_signature; + } + + @Override + public ClassEntry getClassEntry( ) + { + return m_classEntry; + } + + @Override + public String getName( ) + { + return m_classEntry.getName(); + } + + public String getSignature( ) + { + return m_signature; + } + + @Override + public String getClassName( ) + { + return m_classEntry.getName(); + } + + @Override + public int hashCode( ) + { + return Util.combineHashesOrdered( m_classEntry, m_signature ); + } + + @Override + public boolean equals( Object other ) + { + if( other instanceof ConstructorEntry ) + { + return equals( (ConstructorEntry)other ); + } + return false; + } + + public boolean equals( ConstructorEntry other ) + { + return m_classEntry.equals( other.m_classEntry ) && m_signature.equals( other.m_signature ); + } + + @Override + public String toString( ) + { + return m_classEntry.getName() + m_signature; + } +} diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index 02565c94..50433214 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -135,6 +135,14 @@ public class Translator ); } + public ConstructorEntry translateEntry( ConstructorEntry in ) + { + return new ConstructorEntry( + translateEntry( in.getClassEntry() ), + translateSignature( in.getSignature() ) + ); + } + public String translate( ArgumentEntry in ) { for( String className : getSelfAndAncestors( in.getClassName() ) ) -- cgit v1.2.3 From a7f865f1b7b790be4d4e53e0d24b5c18b3ceb1f8 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 14 Aug 2014 00:04:24 -0400 Subject: fixed javac compile errors --- src/cuchaz/enigma/gui/Gui.java | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 1d2d3ab1..3b67a329 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -158,7 +158,7 @@ public class Gui private JMenuItem m_showCallsMenu; // state - private EntryPair m_selectedEntryPair; + private EntryPair m_selectedEntryPair; private JFileChooser m_jarFileChooser; private JFileChooser m_mappingsFileChooser; @@ -749,7 +749,7 @@ public class Gui } @SuppressWarnings( "unchecked" ) - private void showEntryPair( EntryPair pair ) + private void showEntryPair( EntryPair pair ) { if( pair == null ) { @@ -762,23 +762,23 @@ public class Gui m_infoPanel.removeAll(); if( pair.deobf instanceof ClassEntry ) { - showClassEntryPair( (EntryPair)pair ); + showClassEntryPair( (EntryPair)pair ); } else if( pair.deobf instanceof FieldEntry ) { - showFieldEntryPair( (EntryPair)pair ); + showFieldEntryPair( (EntryPair)pair ); } else if( pair.deobf instanceof MethodEntry ) { - showMethodEntryPair( (EntryPair)pair ); + showMethodEntryPair( (EntryPair)pair ); } else if( pair.deobf instanceof ConstructorEntry ) { - showConstructorEntryPair( (EntryPair)pair ); + showConstructorEntryPair( (EntryPair)pair ); } else if( pair.deobf instanceof ArgumentEntry ) { - showArgumentEntryPair( (EntryPair)pair ); + showArgumentEntryPair( (EntryPair)pair ); } else { @@ -788,31 +788,31 @@ public class Gui redraw(); } - private void showClassEntryPair( EntryPair pair ) + private void showClassEntryPair( EntryPair pair ) { addNameValue( m_infoPanel, "Class", pair.deobf.getName() ); } - private void showFieldEntryPair( EntryPair pair ) + private void showFieldEntryPair( EntryPair pair ) { addNameValue( m_infoPanel, "Field", pair.deobf.getName() ); addNameValue( m_infoPanel, "Class", pair.deobf.getClassEntry().getName() ); } - private void showMethodEntryPair( EntryPair pair ) + private void showMethodEntryPair( EntryPair pair ) { addNameValue( m_infoPanel, "Method", pair.deobf.getName() ); addNameValue( m_infoPanel, "Class", pair.deobf.getClassEntry().getName() ); addNameValue( m_infoPanel, "Signature", pair.deobf.getSignature() ); } - private void showConstructorEntryPair( EntryPair pair ) + private void showConstructorEntryPair( EntryPair pair ) { addNameValue( m_infoPanel, "Constructor", pair.deobf.getClassEntry().getName() ); addNameValue( m_infoPanel, "Signature", pair.deobf.getSignature() ); } - private void showArgumentEntryPair( EntryPair pair ) + private void showArgumentEntryPair( EntryPair pair ) { addNameValue( m_infoPanel, "Argument", pair.deobf.getName() ); addNameValue( m_infoPanel, "Class", pair.deobf.getClassEntry().getName() ); -- cgit v1.2.3 From a7c1b0e8fa8866b40e693f3999acf23fa0eb41da Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 14 Aug 2014 00:05:02 -0400 Subject: updated license info, version, added readme --- src/cuchaz/enigma/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java index a8c4f44c..72275628 100644 --- a/src/cuchaz/enigma/Constants.java +++ b/src/cuchaz/enigma/Constants.java @@ -14,7 +14,7 @@ package cuchaz.enigma; public class Constants { public static final String Name = "Enigma"; - public static final String Version = "0.1"; + public static final String Version = "0.1 beta"; 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 -- cgit v1.2.3 From 06162e8d1627ac0d7a6cca79f3b5b4482fbcd37f Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 14 Aug 2014 00:33:28 -0400 Subject: remove old debug messages --- src/cuchaz/enigma/analysis/JarIndex.java | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 96bddc17..a0aa2955 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -216,13 +216,6 @@ public class JarIndex new ClassEntry( className ), call.getSignature() ); - - // TEMP - if( className.equals( "bgw" ) ) - { - System.out.println( calledConstructorEntry + " called by " + thisEntry ); - } - m_methodCalls.put( calledConstructorEntry, thisEntry ); } } ); -- cgit v1.2.3 From 580fbf899accb4181c1ca1e41abbcc2b7404c870 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 14 Aug 2014 00:46:16 -0400 Subject: fixed bug with method inheritance detection --- src/cuchaz/enigma/analysis/JarIndex.java | 22 ++++++++-------------- .../enigma/analysis/MethodInheritanceTreeNode.java | 2 +- 2 files changed, 9 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index a0aa2955..845be600 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -238,19 +238,13 @@ public class JarIndex public boolean isMethodImplemented( MethodEntry methodEntry ) { - return isMethodImplemented( methodEntry.getClassName(), methodEntry.getName(), methodEntry.getSignature() ); - } - - public boolean isMethodImplemented( String className, String methodName, String methodSignature ) - { - Collection implementations = m_methodImplementations.get( className ); + Collection implementations = m_methodImplementations.get( methodEntry.getClassName() ); if( implementations == null ) { return false; } - return implementations.contains( getMethodKey( methodName, methodSignature ) ); + return implementations.contains( methodEntry ); } - public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) { @@ -272,7 +266,12 @@ public class JarIndex String baseImplementationClassName = obfMethodEntry.getClassName(); for( String ancestorClassName : m_ancestries.getAncestry( obfMethodEntry.getClassName() ) ) { - if( isMethodImplemented( ancestorClassName, obfMethodEntry.getName(), obfMethodEntry.getSignature() ) ) + MethodEntry ancestorMethodEntry = new MethodEntry( + new ClassEntry( ancestorClassName ), + obfMethodEntry.getName(), + obfMethodEntry.getSignature() + ); + if( isMethodImplemented( ancestorMethodEntry ) ) { baseImplementationClassName = ancestorClassName; } @@ -305,9 +304,4 @@ public class JarIndex { return m_methodCalls.get( entry ); } - - private String getMethodKey( String name, String signature ) - { - return name + signature; - } } diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index a28a9f46..73f9714c 100644 --- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java @@ -93,7 +93,7 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode nodes.add( new MethodInheritanceTreeNode( m_deobfuscatingTranslator, methodEntry, - index.isMethodImplemented( subclassName, m_entry.getName(), m_entry.getSignature() ) + index.isMethodImplemented( methodEntry ) ) ); } -- cgit v1.2.3 From 37467e4a7b5e05e4da413a1e06e597fa806b72e4 Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 15 Aug 2014 01:43:48 -0400 Subject: trying to get inner/anonymous classes working... I have a working heuristic in place to detect anonymous classes, but I can't seem to get Procyon to decompile them correctly. I'm writing the InnerClasses attribute and translating all the inner class names, but there must be something else I'm missing... --- src/cuchaz/enigma/Deobfuscator.java | 18 +-- src/cuchaz/enigma/TranslatingTypeLoader.java | 86 ++++++++--- src/cuchaz/enigma/analysis/JarClassIterator.java | 134 ++++++++++++++++ src/cuchaz/enigma/analysis/JarIndex.java | 187 ++++++++++++++--------- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 79 ++++++++++ 5 files changed, 396 insertions(+), 108 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/JarClassIterator.java create mode 100644 src/cuchaz/enigma/bytecode/InnerClassWriter.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 770172e3..127a0d98 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -11,9 +11,7 @@ package cuchaz.enigma; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.io.StringWriter; import java.util.List; import java.util.jar.JarFile; @@ -58,18 +56,9 @@ public class Deobfuscator m_file = file; m_jar = new JarFile( m_file ); - // build the ancestries - InputStream jarIn = null; - try - { - m_jarIndex = new JarIndex( m_jar ); - jarIn = new FileInputStream( m_file ); - m_jarIndex.indexJar( jarIn ); - } - finally - { - Util.closeQuietly( jarIn ); - } + // build the jar index + m_jarIndex = new JarIndex(); + m_jarIndex.indexJar( m_jar ); // config the decompiler m_settings = DecompilerSettings.javaDefaults(); @@ -105,6 +94,7 @@ public class Deobfuscator // update decompiler options m_settings.setTypeLoader( new TranslatingTypeLoader( m_jar, + m_jarIndex, getTranslator( TranslationDirection.Obfuscating ), getTranslator( TranslationDirection.Deobfuscating ) ) ); diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index f5112e0f..fdfcea0f 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -17,42 +17,77 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import javassist.ByteArrayClassPath; +import javassist.CannotCompileException; import javassist.ClassPool; import javassist.CtClass; +import javassist.NotFoundException; import javassist.bytecode.Descriptor; import com.strobel.assembler.metadata.Buffer; import com.strobel.assembler.metadata.ITypeLoader; +import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.bytecode.ClassTranslator; +import cuchaz.enigma.bytecode.InnerClassWriter; import cuchaz.enigma.bytecode.MethodParameterWriter; import cuchaz.enigma.mapping.Translator; public class TranslatingTypeLoader implements ITypeLoader { private JarFile m_jar; + private JarIndex m_jarIndex; private Translator m_obfuscatingTranslator; private Translator m_deobfuscatingTranslator; - public TranslatingTypeLoader( JarFile jar, Translator obfuscatingTranslator, Translator deobfuscatingTranslator ) + public TranslatingTypeLoader( JarFile jar, JarIndex jarIndex, Translator obfuscatingTranslator, Translator deobfuscatingTranslator ) { m_jar = jar; + m_jarIndex = jarIndex; m_obfuscatingTranslator = obfuscatingTranslator; m_deobfuscatingTranslator = deobfuscatingTranslator; } @Override - public boolean tryLoadType( String name, Buffer out ) + public boolean tryLoadType( String deobfClassName, Buffer out ) { - // is this a deobufscated class name? - String obfName = m_obfuscatingTranslator.translateClass( name ); - if( obfName != null ) + // TEMP + if( !deobfClassName.startsWith( "java" ) && !deobfClassName.startsWith( "org" ) ) { - // point to the obfuscated class - name = obfName; + System.out.println( "Looking for: " + deobfClassName ); } - JarEntry entry = m_jar.getJarEntry( name + ".class" ); + // what class file should we actually load? + String obfClassName = m_obfuscatingTranslator.translateClass( deobfClassName ); + if( obfClassName == null ) + { + obfClassName = deobfClassName; + } + String classFileName = obfClassName; + + // is this a properly-referenced inner class? + boolean isInnerClass = deobfClassName.indexOf( '$' ) >= 0; + if( isInnerClass ) + { + // get just the bare inner class name + String[] parts = deobfClassName.split( "\\$" ); + String deobfClassFileName = parts[parts.length - 1]; + + // make sure the bare inner class name is obfuscated + classFileName = m_obfuscatingTranslator.translateClass( deobfClassFileName ); + if( classFileName == null ) + { + classFileName = deobfClassFileName; + } + } + + // TEMP + if( !deobfClassName.startsWith( "java" ) && !deobfClassName.startsWith( "org" ) ) + { + System.out.println( "\tLooking at class file: " + classFileName ); + } + + // get the jar entry + JarEntry entry = m_jar.getJarEntry( classFileName + ".class" ); if( entry == null ) { return false; @@ -73,32 +108,43 @@ public class TranslatingTypeLoader implements ITypeLoader } data.write( buf, 0, bytesRead ); } + data.close(); + in.close(); buf = data.toByteArray(); - // translate the class - String javaName = Descriptor.toJavaName( name ); + // load the javassist handle to the class + String javaClassFileName = Descriptor.toJavaName( classFileName ); ClassPool classPool = new ClassPool(); - classPool.insertClassPath( new ByteArrayClassPath( javaName, buf ) ); - try + classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, buf ) ); + CtClass c = classPool.get( javaClassFileName ); + + if( isInnerClass ) { - CtClass c = classPool.get( javaName ); - new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); - new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); - buf = c.toBytecode(); + // rename the class to what procyon expects + c.setName( deobfClassName ); } - catch( Exception ex ) + else { - throw new Error( ex ); + // maybe it's an outer class + new InnerClassWriter( m_deobfuscatingTranslator, m_jarIndex ).writeInnerClasses( c ); } - // pass it along to the decompiler + new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); + new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); + + assert( Descriptor.toJvmName( c.getName() ).equals( deobfClassName ) ); + assert( c.getClassFile().getName().equals( deobfClassName ) ); + + buf = c.toBytecode(); + + // pass the transformed class along to the decompiler out.reset( buf.length ); System.arraycopy( buf, 0, out.array(), out.position(), buf.length ); out.position( 0 ); return true; } - catch( IOException ex ) + catch( IOException | NotFoundException | CannotCompileException ex ) { throw new Error( ex ); } diff --git a/src/cuchaz/enigma/analysis/JarClassIterator.java b/src/cuchaz/enigma/analysis/JarClassIterator.java new file mode 100644 index 00000000..cf6df805 --- /dev/null +++ b/src/cuchaz/enigma/analysis/JarClassIterator.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * 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.analysis; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import javassist.ByteArrayClassPath; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.NotFoundException; +import javassist.bytecode.Descriptor; + +import com.beust.jcommander.internal.Lists; + +import cuchaz.enigma.Constants; + +public class JarClassIterator implements Iterator +{ + private JarFile m_jar; + private Iterator m_iter; + + public JarClassIterator( JarFile jar ) + { + this( jar, getClassEntries( jar ) ); + } + + public JarClassIterator( JarFile jar, List entries ) + { + m_jar = jar; + m_iter = entries.iterator(); + } + + @Override + public boolean hasNext( ) + { + return m_iter.hasNext(); + } + + @Override + public CtClass next( ) + { + JarEntry entry = m_iter.next(); + try + { + // read the class into a buffer + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buf = new byte[Constants.KiB]; + int totalNumBytesRead = 0; + InputStream in = m_jar.getInputStream( entry ); + while( in.available() > 0 ) + { + int numBytesRead = in.read( buf ); + if( numBytesRead < 0 ) + { + break; + } + bos.write( buf, 0, numBytesRead ); + + // sanity checking + totalNumBytesRead += numBytesRead; + if( totalNumBytesRead > Constants.MiB ) + { + throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" ); + } + } + + // determine the class name (ie chop off the ".class") + String className = Descriptor.toJavaName( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) ); + + // get a javassist handle for the class + ClassPool classPool = new ClassPool(); + classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); + return classPool.get( className ); + } + catch( IOException ex ) + { + throw new Error( "Unable to read class: " + entry.getName() ); + } + catch( NotFoundException ex ) + { + throw new Error( "Unable to load class: " + entry.getName() ); + } + } + + @Override + public void remove( ) + { + throw new UnsupportedOperationException(); + } + + public static List getClassEntries( JarFile jar ) + { + List classes = Lists.newArrayList(); + Enumeration entries = jar.entries(); + while( entries.hasMoreElements() ) + { + JarEntry entry = entries.nextElement(); + + // is this a class file? + if( !entry.isDirectory() && entry.getName().endsWith( ".class" ) ) + { + classes.add( entry ); + } + } + return classes; + } + + public static Iterable classes( final JarFile jar ) + { + return new Iterable( ) + { + @Override + public Iterator iterator( ) + { + return new JarClassIterator( jar ); + } + }; + } +} diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 845be600..9962bfaa 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -10,27 +10,21 @@ ******************************************************************************/ package cuchaz.enigma.analysis; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; import java.util.Collection; -import java.util.Enumeration; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import javassist.ByteArrayClassPath; import javassist.CannotCompileException; -import javassist.ClassPool; import javassist.CtBehavior; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtMethod; -import javassist.NotFoundException; +import javassist.bytecode.AccessFlag; import javassist.bytecode.Descriptor; +import javassist.bytecode.FieldInfo; import javassist.expr.ConstructorCall; import javassist.expr.ExprEditor; import javassist.expr.FieldAccess; @@ -39,10 +33,10 @@ import javassist.expr.NewExpr; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; -import cuchaz.enigma.Constants; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; @@ -57,89 +51,52 @@ public class JarIndex private Multimap m_methodImplementations; private Multimap m_methodCalls; private Multimap m_fieldCalls; + private Multimap m_innerClasses; + private Map m_outerClasses; - public JarIndex( JarFile jar ) + public JarIndex( ) { m_obfClassNames = Sets.newHashSet(); m_ancestries = new Ancestries(); m_methodImplementations = HashMultimap.create(); m_methodCalls = HashMultimap.create(); m_fieldCalls = HashMultimap.create(); - - // read the class names - Enumeration enumeration = jar.entries(); - while( enumeration.hasMoreElements() ) + m_innerClasses = HashMultimap.create(); + m_outerClasses = Maps.newHashMap(); + } + + public void indexJar( JarFile jar ) + { + // pass 1: read the class names + for( JarEntry entry : JarClassIterator.getClassEntries( jar ) ) { - JarEntry entry = enumeration.nextElement(); - - // filter out non-classes - if( entry.isDirectory() || !entry.getName().endsWith( ".class" ) ) - { - continue; - } - String className = entry.getName().substring( 0, entry.getName().length() - 6 ); m_obfClassNames.add( Descriptor.toJvmName( className ) ); } - } - - public void indexJar( InputStream in ) - throws IOException - { - ClassPool classPool = new ClassPool(); - ZipInputStream zin = new ZipInputStream( in ); - ZipEntry entry; - while( ( entry = zin.getNextEntry() ) != null ) + // pass 2: index the types, methods + for( CtClass c : JarClassIterator.classes( jar ) ) { - // filter out non-classes - if( entry.isDirectory() || !entry.getName().endsWith( ".class" ) ) + m_ancestries.addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); + for( CtBehavior behavior : c.getDeclaredBehaviors() ) { - continue; + indexBehavior( behavior ); } - - // read the class into a buffer - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] buf = new byte[Constants.KiB]; - int totalNumBytesRead = 0; - while( zin.available() > 0 ) - { - int numBytesRead = zin.read( buf ); - if( numBytesRead < 0 ) - { - break; - } - bos.write( buf, 0, numBytesRead ); - - // sanity checking - totalNumBytesRead += numBytesRead; - if( totalNumBytesRead > Constants.MiB ) - { - throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" ); - } - } - - // determine the class name (ie chop off the ".class") - String className = Descriptor.toJavaName( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) ); - - // get a javassist handle for the class - classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); - try - { - CtClass c = classPool.get( className ); - m_ancestries.addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); - for( CtBehavior behavior : c.getDeclaredBehaviors() ) - { - indexBehavior( behavior ); - } - } - catch( NotFoundException ex ) + } + + // pass 2: index inner classes + for( CtClass c : JarClassIterator.classes( jar ) ) + { + String outerClassName = isInnerClass( c ); + if( outerClassName != null ) { - throw new Error( "Unable to load class: " + className ); + String innerClassName = Descriptor.toJvmName( c.getName() ); + m_innerClasses.put( outerClassName, innerClassName ); + m_outerClasses.put( innerClassName, outerClassName ); } } } - + private void indexBehavior( CtBehavior behavior ) { // get the method entry @@ -226,6 +183,78 @@ public class JarIndex } } + @SuppressWarnings( "unchecked" ) + private String isInnerClass( CtClass c ) + { + String innerClassName = Descriptor.toJvmName( c.getName() ); + + // first, is this an anonymous class? + // for anonymous classes: + // the outer class is always a synthetic field + // there's at least one constructor with the type of the synthetic field as an argument + // this constructor is called exactly once by the class of the synthetic field + + for( FieldInfo field : (List)c.getClassFile().getFields() ) + { + boolean isSynthetic = (field.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; + if( !isSynthetic ) + { + continue; + } + + // skip non-class types + if( !field.getDescriptor().startsWith( "L" ) ) + { + continue; + } + + // get the outer class from the field type + String outerClassName = Descriptor.toJvmName( Descriptor.toClassName( field.getDescriptor() ) ); + + // look for a constructor where this type is the first parameter + CtConstructor targetConstructor = null; + for( CtConstructor constructor : c.getDeclaredConstructors() ) + { + String signature = Descriptor.getParamDescriptor( constructor.getMethodInfo().getDescriptor() ); + if( Descriptor.numOfParameters( signature ) < 1 ) + { + continue; + } + + // match the first parameter to the outer class + Descriptor.Iterator iter = new Descriptor.Iterator( signature ); + int pos = iter.next(); + if( iter.isParameter() && signature.charAt( pos ) == 'L' ) + { + String argumentDesc = signature.substring( pos, signature.indexOf(';', pos) + 1 ); + String argumentClassName = Descriptor.toJvmName( Descriptor.toClassName( argumentDesc ) ); + if( argumentClassName.equals( outerClassName ) ) + { + // is this constructor called exactly once? + ConstructorEntry constructorEntry = new ConstructorEntry( + new ClassEntry( innerClassName ), + constructor.getMethodInfo().getDescriptor() + ); + if( this.getMethodCallers( constructorEntry ).size() == 1 ) + { + targetConstructor = constructor; + break; + } + } + } + } + if( targetConstructor == null ) + { + continue; + } + + // yeah, this is an inner class + return outerClassName; + } + + return null; + } + public Set getObfClassNames( ) { return m_obfClassNames; @@ -304,4 +333,14 @@ public class JarIndex { return m_methodCalls.get( entry ); } + + public Collection getInnerClasses( String obfOuterClassName ) + { + return m_innerClasses.get( obfOuterClassName ); + } + + public String getOuterClass( String obfInnerClassName ) + { + return m_outerClasses.get( obfInnerClassName ); + } } diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java new file mode 100644 index 00000000..d4abe4ea --- /dev/null +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * 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.util.Collection; + +import javassist.CtClass; +import javassist.bytecode.AccessFlag; +import javassist.bytecode.Descriptor; +import javassist.bytecode.InnerClassesAttribute; +import cuchaz.enigma.analysis.JarIndex; +import cuchaz.enigma.mapping.Translator; + +public class InnerClassWriter +{ + private Translator m_deobfuscatingTranslator; + private JarIndex m_jarIndex; + + public InnerClassWriter( Translator deobfuscatingTranslator, JarIndex jarIndex ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_jarIndex = jarIndex; + } + + public void writeInnerClasses( CtClass c ) + { + // is this an outer class with inner classes? + String obfOuterClassName = Descriptor.toJvmName( c.getName() ); + Collection obfInnerClassNames = m_jarIndex.getInnerClasses( obfOuterClassName ); + if( obfInnerClassNames != null && !obfInnerClassNames.isEmpty() ) + { + writeInnerClasses( c, obfInnerClassNames ); + } + } + + private void writeInnerClasses( CtClass c, Collection obfInnerClassNames ) + { + String obfOuterClassName = Descriptor.toJvmName( c.getName() ); + InnerClassesAttribute attr = new InnerClassesAttribute( c.getClassFile().getConstPool() ); + c.getClassFile().addAttribute( attr ); + for( String obfInnerClassName : obfInnerClassNames ) + { + // deobfuscate the class names + String deobfOuterClassName = m_deobfuscatingTranslator.translateClass( obfOuterClassName ); + if( deobfOuterClassName == null ) + { + deobfOuterClassName = obfOuterClassName; + } + String deobfInnerClassName = m_deobfuscatingTranslator.translateClass( obfInnerClassName ); + if( deobfInnerClassName == null ) + { + deobfInnerClassName = obfInnerClassName; + } + + // update the attribute + String deobfOuterInnerClassName = deobfOuterClassName + "$" + deobfInnerClassName; + attr.append( + deobfOuterInnerClassName, + deobfOuterClassName, + deobfInnerClassName, + c.getClassFile().getAccessFlags() & ~AccessFlag.SUPER + ); + + // make sure the outer class references only the new inner class names + c.replaceClassName( obfInnerClassName, deobfOuterInnerClassName ); + + // TEMP + System.out.println( "\tInner " + obfInnerClassName + " -> " + deobfOuterInnerClassName ); + } + } +} -- cgit v1.2.3 From 6c4440ac1133bfaa7871d1049d174528a289ef30 Mon Sep 17 00:00:00 2001 From: hg Date: Sun, 17 Aug 2014 10:56:17 -0400 Subject: added support for automatic reconstruction of inner and anonymous classes also added class to restore bridge method flags taken out by the obfuscator --- src/cuchaz/enigma/Deobfuscator.java | 51 +++---- src/cuchaz/enigma/TranslatingTypeLoader.java | 56 ++------ src/cuchaz/enigma/analysis/Ancestries.java | 20 +++ src/cuchaz/enigma/analysis/BridgeFixer.java | 91 ++++++++++++ src/cuchaz/enigma/analysis/JarIndex.java | 155 ++++++++++++++++++--- src/cuchaz/enigma/analysis/SourceIndex.java | 31 +++-- src/cuchaz/enigma/analysis/TreeDumpVisitor.java | 45 +++++- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 64 ++++++--- src/cuchaz/enigma/gui/Gui.java | 16 ++- src/cuchaz/enigma/gui/GuiController.java | 5 +- src/cuchaz/enigma/mapping/ClassEntry.java | 28 ++++ src/cuchaz/enigma/mapping/ClassMapping.java | 97 +++++++++++-- .../enigma/mapping/MappingParseException.java | 31 +++++ src/cuchaz/enigma/mapping/MappingsReader.java | 76 +++++++--- src/cuchaz/enigma/mapping/MappingsWriter.java | 40 ++++-- src/cuchaz/enigma/mapping/Renamer.java | 64 ++++----- src/cuchaz/enigma/mapping/Translator.java | 104 +++++++++----- 17 files changed, 743 insertions(+), 231 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/BridgeFixer.java create mode 100644 src/cuchaz/enigma/mapping/MappingParseException.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 127a0d98..9a0ec132 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -62,7 +62,6 @@ public class Deobfuscator // config the decompiler m_settings = DecompilerSettings.javaDefaults(); - m_settings.setShowSyntheticMembers( true ); // init mappings setMappings( new Mappings() ); @@ -109,9 +108,15 @@ public class Deobfuscator { for( String obfClassName : m_jarIndex.getObfClassNames() ) { + // skip inner classes + if( m_jarIndex.getOuterClass( obfClassName ) != null ) + { + continue; + } + // separate the classes ClassMapping classMapping = m_mappings.getClassByObf( obfClassName ); - if( classMapping != null ) + if( classMapping != null && !classMapping.getObfName().equals( classMapping.getDeobfName() ) ) { deobfClasses.add( classMapping.getDeobfName() ); } @@ -151,6 +156,7 @@ public class Deobfuscator // render the AST into source StringWriter buf = new StringWriter(); root.acceptVisitor( new InsertParenthesesVisitor(), null ); + //root.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); root.acceptVisitor( new JavaOutputVisitor( new PlainTextOutput( buf ), m_settings ), null ); // build the source index @@ -281,33 +287,30 @@ public class Deobfuscator } } - public boolean entryIsObfuscatedIdenfitier( Entry obfEntry ) + public boolean isObfuscatedIdentifier( Entry obfEntry ) { if( obfEntry instanceof ClassEntry ) { - // obf classes must be in the list - return m_jarIndex.getObfClassNames().contains( obfEntry.getName() ); - } - else if( obfEntry instanceof FieldEntry ) - { - return m_jarIndex.getObfClassNames().contains( obfEntry.getClassName() ); - } - else if( obfEntry instanceof MethodEntry ) - { - return m_jarIndex.getObfClassNames().contains( obfEntry.getClassName() ); - } - else if( obfEntry instanceof ConstructorEntry ) - { - return m_jarIndex.getObfClassNames().contains( obfEntry.getClassName() ); + if( obfEntry.getName().indexOf( '$' ) >= 0 ) + { + String[] parts = obfEntry.getName().split( "\\$" ); + assert( parts.length == 2 ); // not supporting recursively-nested classes + String outerClassName = parts[0]; + String innerClassName = parts[1]; + + // both classes must be in the list + return m_jarIndex.getObfClassNames().contains( outerClassName ) + && m_jarIndex.getObfClassNames().contains( innerClassName ); + } + else + { + // class must be in the list + return m_jarIndex.getObfClassNames().contains( obfEntry.getName() ); + } } - else if( obfEntry instanceof ArgumentEntry ) + else { - // arguments only appear in method declarations - // since we only show declarations for obf classes, these are always obfuscated - return true; + return isObfuscatedIdentifier( obfEntry.getClassEntry() ); } - - // assume everything else is not obfuscated - return false; } } diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index fdfcea0f..c1d96ae3 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -26,6 +26,7 @@ import javassist.bytecode.Descriptor; import com.strobel.assembler.metadata.Buffer; import com.strobel.assembler.metadata.ITypeLoader; +import cuchaz.enigma.analysis.BridgeFixer; import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.bytecode.ClassTranslator; import cuchaz.enigma.bytecode.InnerClassWriter; @@ -50,12 +51,6 @@ public class TranslatingTypeLoader implements ITypeLoader @Override public boolean tryLoadType( String deobfClassName, Buffer out ) { - // TEMP - if( !deobfClassName.startsWith( "java" ) && !deobfClassName.startsWith( "org" ) ) - { - System.out.println( "Looking for: " + deobfClassName ); - } - // what class file should we actually load? String obfClassName = m_obfuscatingTranslator.translateClass( deobfClassName ); if( obfClassName == null ) @@ -64,26 +59,12 @@ public class TranslatingTypeLoader implements ITypeLoader } String classFileName = obfClassName; - // is this a properly-referenced inner class? - boolean isInnerClass = deobfClassName.indexOf( '$' ) >= 0; - if( isInnerClass ) - { - // get just the bare inner class name - String[] parts = deobfClassName.split( "\\$" ); - String deobfClassFileName = parts[parts.length - 1]; - - // make sure the bare inner class name is obfuscated - classFileName = m_obfuscatingTranslator.translateClass( deobfClassFileName ); - if( classFileName == null ) - { - classFileName = deobfClassFileName; - } - } - - // TEMP - if( !deobfClassName.startsWith( "java" ) && !deobfClassName.startsWith( "org" ) ) + // is this an inner class? + if( obfClassName.indexOf( '$' ) >= 0 ) { - System.out.println( "\tLooking at class file: " + classFileName ); + // the file name is the bare inner class name + String[] parts = obfClassName.split( "\\$" ); + classFileName = parts[parts.length - 1]; } // get the jar entry @@ -118,26 +99,20 @@ public class TranslatingTypeLoader implements ITypeLoader classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, buf ) ); CtClass c = classPool.get( javaClassFileName ); - if( isInnerClass ) - { - // rename the class to what procyon expects - c.setName( deobfClassName ); - } - else - { - // maybe it's an outer class - new InnerClassWriter( m_deobfuscatingTranslator, m_jarIndex ).writeInnerClasses( c ); - } - + // do all kinds of deobfuscating transformations on the class + new InnerClassWriter( m_deobfuscatingTranslator, m_jarIndex ).write( c ); + new BridgeFixer().fixBridges( c ); new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); - assert( Descriptor.toJvmName( c.getName() ).equals( deobfClassName ) ); - assert( c.getClassFile().getName().equals( deobfClassName ) ); - - buf = c.toBytecode(); + // sanity checking + assert( Descriptor.toJvmName( c.getName() ).equals( deobfClassName ) ) + : String.format( "%s is not %s", Descriptor.toJvmName( c.getName() ), deobfClassName ); + assert( Descriptor.toJvmName( c.getClassFile().getName() ).equals( deobfClassName ) ) + : String.format( "%s is not %s", Descriptor.toJvmName( c.getClassFile().getName() ), deobfClassName ); // pass the transformed class along to the decompiler + buf = c.toBytecode(); out.reset( buf.length ); System.arraycopy( buf, 0, out.array(), out.position(), buf.length ); out.position( 0 ); @@ -149,5 +124,4 @@ public class TranslatingTypeLoader implements ITypeLoader throw new Error( ex ); } } - } diff --git a/src/cuchaz/enigma/analysis/Ancestries.java b/src/cuchaz/enigma/analysis/Ancestries.java index 83c239cd..b9d8cbf4 100644 --- a/src/cuchaz/enigma/analysis/Ancestries.java +++ b/src/cuchaz/enigma/analysis/Ancestries.java @@ -47,6 +47,26 @@ public class Ancestries implements Serializable } } + public void renameClasses( Map renames ) + { + Map newSuperclasses = Maps.newHashMap(); + for( Map.Entry entry : m_superclasses.entrySet() ) + { + String subclass = renames.get( entry.getKey() ); + if( subclass == null ) + { + subclass = entry.getKey(); + } + String superclass = renames.get( entry.getValue() ); + if( superclass == null ) + { + superclass = entry.getValue(); + } + newSuperclasses.put( subclass, superclass ); + } + m_superclasses = newSuperclasses; + } + public String getSuperclassName( String className ) { return m_superclasses.get( className ); diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java new file mode 100644 index 00000000..db441d2b --- /dev/null +++ b/src/cuchaz/enigma/analysis/BridgeFixer.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * 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.analysis; + +import java.util.List; + +import javassist.CannotCompileException; +import javassist.CtClass; +import javassist.CtMethod; +import javassist.NotFoundException; +import javassist.bytecode.AccessFlag; +import javassist.expr.ExprEditor; +import javassist.expr.MethodCall; + +import com.beust.jcommander.internal.Lists; + +public class BridgeFixer +{ + public void fixBridges( CtClass c ) + { + // bridge methods are scrubbed and marked as synthetic methods by the obfuscator + // need to figure out which synthetics are bridge methods and restore them + for( CtMethod method : c.getDeclaredMethods() ) + { + // skip non-synthetic methods + if( ( method.getModifiers() & AccessFlag.SYNTHETIC ) == 0 ) + { + continue; + } + + CtMethod bridgedMethod = getBridgedMethod( method ); + if( bridgedMethod != null ) + { + bridgedMethod.setName( method.getName() ); + method.setModifiers( method.getModifiers() | AccessFlag.BRIDGE ); + } + } + } + + private CtMethod getBridgedMethod( CtMethod method ) + { + // bridge methods just call another method, cast it to the return type, and return the result + // let's see if we can detect this scenario + + // get all the called methods + final List methodCalls = Lists.newArrayList(); + try + { + method.instrument( new ExprEditor( ) + { + @Override + public void edit( MethodCall call ) + { + methodCalls.add( call ); + } + } ); + } + catch( CannotCompileException ex ) + { + // this is stupid... we're not even compiling anything + throw new Error( ex ); + } + + // is there just one? + if( methodCalls.size() != 1 ) + { + return null; + } + MethodCall call = methodCalls.get( 0 ); + + try + { + // we have a bridge method! + return call.getMethod(); + } + catch( NotFoundException ex ) + { + // can't find the type? not a bridge method + ex.printStackTrace( System.err ); + return null; + } + } +} diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 9962bfaa..34e8986f 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -10,7 +10,9 @@ ******************************************************************************/ package cuchaz.enigma.analysis; +import java.util.AbstractMap; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -37,6 +39,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; +import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; @@ -53,6 +56,7 @@ public class JarIndex private Multimap m_fieldCalls; private Multimap m_innerClasses; private Map m_outerClasses; + private Set m_anonymousClasses; public JarIndex( ) { @@ -63,6 +67,7 @@ public class JarIndex m_fieldCalls = HashMultimap.create(); m_innerClasses = HashMultimap.create(); m_outerClasses = Maps.newHashMap(); + m_anonymousClasses = Sets.newHashSet(); } public void indexJar( JarFile jar ) @@ -84,7 +89,7 @@ public class JarIndex } } - // pass 2: index inner classes + // pass 2: index inner classes and anonymous classes for( CtClass c : JarClassIterator.classes( jar ) ) { String outerClassName = isInnerClass( c ); @@ -93,8 +98,21 @@ public class JarIndex String innerClassName = Descriptor.toJvmName( c.getName() ); m_innerClasses.put( outerClassName, innerClassName ); m_outerClasses.put( innerClassName, outerClassName ); + + if( isAnonymousClass( c, outerClassName ) ) + { + m_anonymousClasses.add( innerClassName ); + } } } + + // step 3: update other indicies with inner class info + Map renames = Maps.newHashMap(); + for( Map.Entry entry : m_outerClasses.entrySet() ) + { + renames.put( entry.getKey(), entry.getValue() + "$" + entry.getKey() ); + } + renameClasses( renames ); } private void indexBehavior( CtBehavior behavior ) @@ -186,14 +204,10 @@ public class JarIndex @SuppressWarnings( "unchecked" ) private String isInnerClass( CtClass c ) { - String innerClassName = Descriptor.toJvmName( c.getName() ); - - // first, is this an anonymous class? - // for anonymous classes: + // inner classes: // the outer class is always a synthetic field // there's at least one constructor with the type of the synthetic field as an argument - // this constructor is called exactly once by the class of the synthetic field - + for( FieldInfo field : (List)c.getClassFile().getFields() ) { boolean isSynthetic = (field.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; @@ -230,16 +244,8 @@ public class JarIndex String argumentClassName = Descriptor.toJvmName( Descriptor.toClassName( argumentDesc ) ); if( argumentClassName.equals( outerClassName ) ) { - // is this constructor called exactly once? - ConstructorEntry constructorEntry = new ConstructorEntry( - new ClassEntry( innerClassName ), - constructor.getMethodInfo().getDescriptor() - ); - if( this.getMethodCallers( constructorEntry ).size() == 1 ) - { - targetConstructor = constructor; - break; - } + targetConstructor = constructor; + break; } } } @@ -255,6 +261,30 @@ public class JarIndex return null; } + private boolean isAnonymousClass( CtClass c, String outerClassName ) + { + String innerClassName = Descriptor.toJvmName( c.getName() ); + + // anonymous classes: + // have only one constructor + // it's called exactly once by the outer class + // type of inner class not referenced anywhere in outer class + + // is there exactly one constructor? + if( c.getDeclaredConstructors().length != 1 ) + { + return false; + } + CtConstructor constructor = c.getDeclaredConstructors()[0]; + + // is this constructor called exactly once? + ConstructorEntry constructorEntry = new ConstructorEntry( + new ClassEntry( innerClassName ), + constructor.getMethodInfo().getDescriptor() + ); + return getMethodCallers( constructorEntry ).size() == 1; + } + public Set getObfClassNames( ) { return m_obfClassNames; @@ -343,4 +373,95 @@ public class JarIndex { return m_outerClasses.get( obfInnerClassName ); } + + public boolean isAnonymousClass( String obfInnerClassName ) + { + return m_anonymousClasses.contains( obfInnerClassName ); + } + + private void renameClasses( Map renames ) + { + m_ancestries.renameClasses( renames ); + renameMultimap( renames, m_methodImplementations ); + renameMultimap( renames, m_methodCalls ); + renameMultimap( renames, m_fieldCalls ); + } + + private void renameMultimap( Map renames, Multimap map ) + { + // for each key/value pair... + Set> entriesToAdd = Sets.newHashSet(); + Iterator> iter = map.entries().iterator(); + while( iter.hasNext() ) + { + Map.Entry entry = iter.next(); + iter.remove(); + entriesToAdd.add( new AbstractMap.SimpleEntry( + renameEntry( renames, entry.getKey() ), + renameEntry( renames, entry.getValue() ) + ) ); + } + for( Map.Entry entry : entriesToAdd ) + { + map.put( entry.getKey(), entry.getValue() ); + } + } + + @SuppressWarnings( "unchecked" ) + private T renameEntry( Map renames, T entry ) + { + if( entry instanceof String ) + { + String stringEntry = (String)entry; + if( renames.containsKey( stringEntry ) ) + { + return (T)renames.get( stringEntry ); + } + } + else if( entry instanceof ClassEntry ) + { + ClassEntry classEntry = (ClassEntry)entry; + return (T)new ClassEntry( renameEntry( renames, classEntry.getClassName() ) ); + } + else if( entry instanceof FieldEntry ) + { + FieldEntry fieldEntry = (FieldEntry)entry; + return (T)new FieldEntry( + renameEntry( renames, fieldEntry.getClassEntry() ), + fieldEntry.getName() + ); + } + else if( entry instanceof ConstructorEntry ) + { + ConstructorEntry constructorEntry = (ConstructorEntry)entry; + return (T)new ConstructorEntry( + renameEntry( renames, constructorEntry.getClassEntry() ), + constructorEntry.getSignature() + ); + } + else if( entry instanceof MethodEntry ) + { + MethodEntry methodEntry = (MethodEntry)entry; + return (T)new MethodEntry( + renameEntry( renames, methodEntry.getClassEntry() ), + methodEntry.getName(), + methodEntry.getSignature() + ); + } + else if( entry instanceof ArgumentEntry ) + { + ArgumentEntry argumentEntry = (ArgumentEntry)entry; + return (T)new ArgumentEntry( + renameEntry( renames, argumentEntry.getMethodEntry() ), + argumentEntry.getIndex(), + argumentEntry.getName() + ); + } + else + { + throw new Error( "Not an entry: " + entry ); + } + + return entry; + } } diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 531f3e04..645a71da 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -17,7 +17,7 @@ import java.util.TreeMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.strobel.decompiler.languages.Region; -import com.strobel.decompiler.languages.java.ast.AstNode; +import com.strobel.decompiler.languages.java.ast.Identifier; import cuchaz.enigma.mapping.Entry; @@ -51,19 +51,27 @@ public class SourceIndex return m_source; } - public Token getToken( AstNode node ) + public Token getToken( Identifier node ) { // get a token for this node's region Region region = node.getRegion(); if( region.getBeginLine() == 0 || region.getEndLine() == 0 ) { - throw new IllegalArgumentException( "Invalid region: " + region ); + System.err.println( "WARNING: " + node.getNodeType() + " node has invalid region: " + region ); + return null; } Token token = new Token( toPos( region.getBeginLine(), region.getBeginColumn() ), toPos( region.getEndLine(), region.getEndColumn() ) ); + // for tokens representing inner classes, make sure we only get the simple name + int pos = node.getName().lastIndexOf( '$' ); + if( pos >= 0 ) + { + token.end -= pos + 1; + } + // HACKHACK: sometimes node regions are off by one // I think this is a bug in Procyon, but it's easy to work around if( !Character.isJavaIdentifierStart( m_source.charAt( token.start ) ) ) @@ -79,16 +87,23 @@ public class SourceIndex return token; } - public void add( AstNode node, Entry deobfEntry ) + public void add( Identifier node, Entry deobfEntry ) { - m_tokens.put( getToken( node ), deobfEntry ); + Token token = getToken( node ); + if( token != null ) + { + m_tokens.put( token, deobfEntry ); + } } - public void addDeclaration( AstNode node, Entry deobfEntry ) + public void addDeclaration( Identifier node, Entry deobfEntry ) { Token token = getToken( node ); - m_tokens.put( token, deobfEntry ); - m_declarations.put( deobfEntry, token ); + if( token != null ) + { + m_tokens.put( token, deobfEntry ); + m_declarations.put( deobfEntry, token ); + } } public Token getToken( int pos ) diff --git a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java index 05d0e6be..ac3e92db 100644 --- a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java +++ b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java @@ -10,6 +10,11 @@ ******************************************************************************/ package cuchaz.enigma.analysis; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; + import com.strobel.componentmodel.Key; import com.strobel.decompiler.languages.java.ast.Annotation; import com.strobel.decompiler.languages.java.ast.AnonymousObjectCreationExpression; @@ -87,10 +92,42 @@ import com.strobel.decompiler.patterns.Pattern; public class TreeDumpVisitor implements IAstVisitor { + private File m_file; + private Writer m_out; + + public TreeDumpVisitor( File file ) + { + m_file = file; + m_out = null; + } + + @Override + public Void visitCompilationUnit( CompilationUnit node, Void ignored ) + { + try + { + m_out = new FileWriter( m_file ); + recurse( node, ignored ); + m_out.close(); + return null; + } + catch( IOException ex ) + { + throw new Error( ex ); + } + } + private Void recurse( AstNode node, Void ignored ) { // show the tree - System.out.println( getIndent( node ) + node.getClass().getSimpleName() + dumpUserData( node ) + " " + node.getRegion() ); + try + { + m_out.write( getIndent( node ) + node.getClass().getSimpleName() + dumpUserData( node ) + " " + node.getRegion() + "\n" ); + } + catch( IOException ex ) + { + throw new Error( ex ); + } // recurse for( final AstNode child : node.getChildren() ) @@ -378,12 +415,6 @@ public class TreeDumpVisitor implements IAstVisitor return recurse( node, ignored ); } - @Override - public Void visitCompilationUnit( CompilationUnit node, Void ignored ) - { - return recurse( node, ignored ); - } - @Override public Void visitPackageDeclaration( PackageDeclaration node, Void ignored ) { diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java index d4abe4ea..b0e33ac2 100644 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -14,6 +14,7 @@ import java.util.Collection; import javassist.CtClass; import javassist.bytecode.AccessFlag; +import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; import javassist.bytecode.InnerClassesAttribute; import cuchaz.enigma.analysis.JarIndex; @@ -29,21 +30,33 @@ public class InnerClassWriter m_deobfuscatingTranslator = deobfuscatingTranslator; m_jarIndex = jarIndex; } - - public void writeInnerClasses( CtClass c ) + + public void write( CtClass c ) { - // is this an outer class with inner classes? - String obfOuterClassName = Descriptor.toJvmName( c.getName() ); + // get the outer class name + String obfClassName = Descriptor.toJvmName( c.getName() ); + String obfOuterClassName = m_jarIndex.getOuterClass( obfClassName ); + if( obfOuterClassName == null ) + { + // this is an outer class + obfOuterClassName = obfClassName; + } + else + { + // this is an inner class, rename it to outer$inner + c.setName( obfOuterClassName + "$" + obfClassName ); + } + + // write the inner classes if needed Collection obfInnerClassNames = m_jarIndex.getInnerClasses( obfOuterClassName ); - if( obfInnerClassNames != null && !obfInnerClassNames.isEmpty() ) + if( obfInnerClassNames != null ) { - writeInnerClasses( c, obfInnerClassNames ); + writeInnerClasses( c, obfOuterClassName, obfInnerClassNames ); } } - - private void writeInnerClasses( CtClass c, Collection obfInnerClassNames ) + + private void writeInnerClasses( CtClass c, String obfOuterClassName, Collection obfInnerClassNames ) { - String obfOuterClassName = Descriptor.toJvmName( c.getName() ); InnerClassesAttribute attr = new InnerClassesAttribute( c.getClassFile().getConstPool() ); c.getClassFile().addAttribute( attr ); for( String obfInnerClassName : obfInnerClassNames ) @@ -54,26 +67,37 @@ public class InnerClassWriter { deobfOuterClassName = obfOuterClassName; } - String deobfInnerClassName = m_deobfuscatingTranslator.translateClass( obfInnerClassName ); - if( deobfInnerClassName == null ) + String obfOuterInnerClassName = obfOuterClassName + "$" + obfInnerClassName; + String deobfOuterInnerClassName = m_deobfuscatingTranslator.translateClass( obfOuterInnerClassName ); + if( deobfOuterInnerClassName == null ) + { + deobfOuterInnerClassName = obfOuterInnerClassName; + } + String deobfInnerClassName = deobfOuterInnerClassName.substring( deobfOuterInnerClassName.lastIndexOf( '$' ) + 1 ); + + // here's what the JVM spec says about the InnerClasses attribute + // append( inner, outer of inner if inner is member of outer 0 ow, name after $ if inner not anonymous 0 ow, flags ); + + // update the attribute with this inner class + ConstPool constPool = c.getClassFile().getConstPool(); + int innerClassIndex = constPool.addClassInfo( deobfOuterInnerClassName ); + int outerClassIndex = 0; + int innerClassSimpleNameIndex = 0; + if( !m_jarIndex.isAnonymousClass( obfInnerClassName ) ) { - deobfInnerClassName = obfInnerClassName; + outerClassIndex = constPool.addClassInfo( deobfOuterClassName ); + innerClassSimpleNameIndex = constPool.addUtf8Info( deobfInnerClassName ); } - // update the attribute - String deobfOuterInnerClassName = deobfOuterClassName + "$" + deobfInnerClassName; attr.append( - deobfOuterInnerClassName, - deobfOuterClassName, - deobfInnerClassName, + innerClassIndex, + outerClassIndex, + innerClassSimpleNameIndex, c.getClassFile().getAccessFlags() & ~AccessFlag.SUPER ); // make sure the outer class references only the new inner class names c.replaceClassName( obfInnerClassName, deobfOuterInnerClassName ); - - // TEMP - System.out.println( "\tInner " + obfInnerClassName + " -> " + deobfOuterInnerClassName ); } } } diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 3b67a329..9ed6dd86 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -78,6 +78,7 @@ import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.EntryPair; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.IllegalNameException; +import cuchaz.enigma.mapping.MappingParseException; import cuchaz.enigma.mapping.MethodEntry; public class Gui @@ -508,6 +509,10 @@ public class Gui { throw new Error( ex ); } + catch( MappingParseException ex ) + { + JOptionPane.showMessageDialog( m_frame, ex.getMessage() ); + } } } } ); @@ -862,9 +867,17 @@ public class Gui private void startRename( ) { + // get the class name + String className = m_selectedEntryPair.deobf.getName(); + int pos = className.lastIndexOf( '$' ); + if( pos >= 0 ) + { + className = className.substring( pos + 1 ); + } + // init the text box final JTextField text = new JTextField(); - text.setText( m_selectedEntryPair.deobf.getName() ); + text.setText( className ); text.setPreferredSize( new Dimension( 360, text.getPreferredSize().height ) ); text.addKeyListener( new KeyAdapter( ) { @@ -905,6 +918,7 @@ public class Gui } catch( IllegalNameException ex ) { + ex.printStackTrace( System.err ); text.setBorder( BorderFactory.createLineBorder( Color.red, 1 ) ); } return; diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 534b0cc5..ffeb99aa 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -31,6 +31,7 @@ import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.EntryPair; import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MappingParseException; import cuchaz.enigma.mapping.MappingsReader; import cuchaz.enigma.mapping.MappingsWriter; import cuchaz.enigma.mapping.MethodEntry; @@ -75,7 +76,7 @@ public class GuiController } public void openMappings( File file ) - throws IOException + throws IOException, MappingParseException { FileReader in = new FileReader( file ); m_deobfuscator.setMappings( new MappingsReader().read( in ) ); @@ -135,7 +136,7 @@ public class GuiController public boolean entryIsObfuscatedIdenfitier( Entry deobfEntry ) { - return m_deobfuscator.entryIsObfuscatedIdenfitier( m_deobfuscator.obfuscateEntry( deobfEntry ) ); + return m_deobfuscator.isObfuscatedIdentifier( m_deobfuscator.obfuscateEntry( deobfEntry ) ); } public ClassInheritanceTreeNode getClassInheritance( ClassEntry obfClassEntry ) diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index 738e8e3b..dad6da90 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -82,4 +82,32 @@ public class ClassEntry implements Entry, Serializable { return m_name; } + + public boolean isInnerClass( ) + { + return m_name.lastIndexOf( '$' ) >= 0; + } + + public String getOuterClassName( ) + { + if( isInnerClass() ) + { + return m_name.substring( 0, m_name.lastIndexOf( '$' ) ); + } + return m_name; + } + + public String getInnerClassName( ) + { + if( !isInnerClass() ) + { + throw new Error( "This is not an inner class!" ); + } + return m_name.substring( m_name.lastIndexOf( '$' ) + 1 ); + } + + public ClassEntry getOuterClassEntry( ) + { + return new ClassEntry( getOuterClassName() ); + } } diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index c6826f31..c7f930c6 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -21,6 +21,8 @@ public class ClassMapping implements Serializable, Comparable private String m_obfName; private String m_deobfName; + private Map m_innerClassesByObf; + private Map m_innerClassesByDeobf; private Map m_fieldsByObf; private Map m_fieldsByDeobf; private Map m_methodsByObf; @@ -31,6 +33,8 @@ public class ClassMapping implements Serializable, Comparable { m_obfName = obfName; m_deobfName = NameValidator.validateClassName( deobfName ); + m_innerClassesByObf = Maps.newHashMap(); + m_innerClassesByDeobf = Maps.newHashMap(); m_fieldsByObf = Maps.newHashMap(); m_fieldsByDeobf = Maps.newHashMap(); m_methodsByObf = Maps.newHashMap(); @@ -51,6 +55,72 @@ public class ClassMapping implements Serializable, Comparable m_deobfName = NameValidator.validateClassName( val ); } + //// INNER CLASSES //////// + + public Iterable innerClasses( ) + { + assert( m_innerClassesByObf.size() == m_innerClassesByDeobf.size() ); + return m_innerClassesByObf.values(); + } + + protected void addInnerClassMapping( ClassMapping classMapping ) + { + m_innerClassesByObf.put( classMapping.getObfName(), classMapping ); + m_innerClassesByDeobf.put( classMapping.getDeobfName(), classMapping ); + } + + public ClassMapping getOrCreateInnerClass( String obfName ) + { + ClassMapping classMapping = m_innerClassesByObf.get( obfName ); + if( classMapping == null ) + { + classMapping = new ClassMapping( obfName, obfName ); + m_innerClassesByObf.put( obfName, classMapping ); + m_innerClassesByDeobf.put( obfName, classMapping ); + } + return classMapping; + } + + public ClassMapping getInnerClassByObf( String obfName ) + { + return m_innerClassesByObf.get( obfName ); + } + + public ClassMapping getInnerClassByDeobf( String deobfName ) + { + return m_innerClassesByDeobf.get( deobfName ); + } + + public String getObfInnerClassName( String deobfName ) + { + ClassMapping classMapping = m_innerClassesByDeobf.get( deobfName ); + if( classMapping != null ) + { + return classMapping.getObfName(); + } + return null; + } + + public String getDeobfInnerClassName( String obfName ) + { + ClassMapping classMapping = m_innerClassesByObf.get( obfName ); + if( classMapping != null ) + { + return classMapping.getDeobfName(); + } + return null; + } + + public void setInnerClassName( String obfName, String deobfName ) + { + ClassMapping classMapping = getOrCreateInnerClass( obfName ); + m_innerClassesByDeobf.remove( classMapping.getDeobfName() ); + classMapping.setDeobfName( deobfName ); + m_innerClassesByDeobf.put( deobfName, classMapping ); + } + + //// FIELDS //////// + public Iterable fields( ) { assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() ); @@ -62,18 +132,7 @@ public class ClassMapping implements Serializable, Comparable 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 ) { @@ -110,6 +169,20 @@ public class ClassMapping implements Serializable, Comparable m_fieldsByDeobf.put( deobfName, fieldMapping ); } + //// METHODS //////// + + 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 MethodMapping getMethodByObf( String obfName, String signature ) { return m_methodsByObf.get( getMethodKey( obfName, signature ) ); @@ -155,6 +228,8 @@ public class ClassMapping implements Serializable, Comparable } } + //// ARGUMENTS //////// + public void setArgumentName( String obfMethodName, String obfMethodSignature, int argumentIndex, String argumentName ) { MethodMapping methodIndex = m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) ); diff --git a/src/cuchaz/enigma/mapping/MappingParseException.java b/src/cuchaz/enigma/mapping/MappingParseException.java new file mode 100644 index 00000000..4fcc1f18 --- /dev/null +++ b/src/cuchaz/enigma/mapping/MappingParseException.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * 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 MappingParseException extends Exception +{ + private static final long serialVersionUID = -5487280332892507236L; + + private int m_line; + private String m_message; + + public MappingParseException( int line, String message ) + { + m_line = line; + m_message = message; + } + + @Override + public String getMessage( ) + { + return "Line " + m_line + ": " + m_message; + } +} diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java index b0394090..4cebb3a4 100644 --- a/src/cuchaz/enigma/mapping/MappingsReader.java +++ b/src/cuchaz/enigma/mapping/MappingsReader.java @@ -13,25 +13,27 @@ package cuchaz.enigma.mapping; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; +import java.util.Deque; import java.util.NoSuchElementException; import java.util.Scanner; +import com.google.common.collect.Queues; + import cuchaz.enigma.Util; public class MappingsReader { public Mappings read( Reader in ) - throws IOException + throws IOException, MappingParseException { return read( new BufferedReader( in ) ); } public Mappings read( BufferedReader in ) - throws IOException + throws IOException, MappingParseException { Mappings mappings = new Mappings(); - ClassMapping classMapping = null; - MethodMapping methodMapping = null; + Deque mappingStack = Queues.newArrayDeque(); int lineNumber = 0; String line = null; @@ -47,12 +49,28 @@ public class MappingsReader } // skip blank lines - line = line.trim(); - if( line.length() <= 0 ) + if( line.trim().length() <= 0 ) { continue; } + // get the indent of this line + int indent = 0; + for( int i=0; i> List sorted( Iterable classes ) @@ -86,4 +92,14 @@ public class MappingsWriter Collections.sort( out ); return out; } + + private String getIndent( int depth ) + { + StringBuilder buf = new StringBuilder(); + for( int i=0; i m_classes; + public Map m_classes; private Ancestries m_ancestries; protected Translator( TranslationDirection direction, Map classes, Ancestries ancestries ) @@ -30,22 +30,42 @@ public class Translator m_ancestries = ancestries; } - public String translate( ClassEntry in ) + public String translateClass( String className ) { - return translateClass( in.getName() ); + return translate( new ClassEntry( className ) ); } - public String translateClass( String in ) + public String translate( ClassEntry in ) { - ClassMapping classIndex = m_classes.get( in ); - if( classIndex != null ) + ClassMapping classMapping = m_classes.get( in.getOuterClassName() ); + if( classMapping != null ) { - return m_direction.choose( - classIndex.getDeobfName(), - classIndex.getObfName() - ); + if( in.isInnerClass() ) + { + // look for the inner class + String translatedInnerClassName = m_direction.choose( + classMapping.getDeobfInnerClassName( in.getInnerClassName() ), + classMapping.getObfInnerClassName( in.getInnerClassName() ) + ); + if( translatedInnerClassName != null ) + { + // return outer$inner + String translatedOuterClassName = m_direction.choose( + classMapping.getDeobfName(), + classMapping.getObfName() + ); + return translatedOuterClassName + "$" + translatedInnerClassName; + } + } + else + { + // just return outer + return m_direction.choose( + classMapping.getDeobfName(), + classMapping.getObfName() + ); + } } - return null; } @@ -64,21 +84,20 @@ public class Translator for( String className : getSelfAndAncestors( in.getClassName() ) ) { // look for the class - ClassMapping classIndex = m_classes.get( className ); - if( classIndex != null ) + ClassMapping classMapping = findClassMapping( new ClassEntry( className ) ); + if( classMapping != null ) { // look for the field - String deobfName = m_direction.choose( - classIndex.getDeobfFieldName( in.getName() ), - classIndex.getObfFieldName( in.getName() ) + String translatedName = m_direction.choose( + classMapping.getDeobfFieldName( in.getName() ), + classMapping.getObfFieldName( in.getName() ) ); - if( deobfName != null ) + if( translatedName != null ) { - return deobfName; + return translatedName; } } } - return null; } @@ -99,20 +118,20 @@ public class Translator { for( String className : getSelfAndAncestors( in.getClassName() ) ) { - // look for the class - ClassMapping classIndex = m_classes.get( className ); - if( classIndex != null ) + // look for class + ClassMapping classMapping = findClassMapping( new ClassEntry( className ) ); + if( classMapping != null ) { // look for the method - MethodMapping methodIndex = m_direction.choose( - classIndex.getMethodByObf( in.getName(), in.getSignature() ), - classIndex.getMethodByDeobf( in.getName(), in.getSignature() ) + MethodMapping methodMapping = m_direction.choose( + classMapping.getMethodByObf( in.getName(), in.getSignature() ), + classMapping.getMethodByDeobf( in.getName(), in.getSignature() ) ); - if( methodIndex != null ) + if( methodMapping != null ) { return m_direction.choose( - methodIndex.getDeobfName(), - methodIndex.getObfName() + methodMapping.getDeobfName(), + methodMapping.getObfName() ); } } @@ -148,19 +167,19 @@ public class Translator for( String className : getSelfAndAncestors( in.getClassName() ) ) { // look for the class - ClassMapping classIndex = m_classes.get( className ); - if( classIndex != null ) + ClassMapping classMapping = findClassMapping( new ClassEntry( className ) ); + if( classMapping != null ) { // look for the method - MethodMapping methodIndex = m_direction.choose( - classIndex.getMethodByObf( in.getMethodName(), in.getMethodSignature() ), - classIndex.getMethodByDeobf( in.getMethodName(), in.getMethodSignature() ) + MethodMapping methodMapping = m_direction.choose( + classMapping.getMethodByObf( in.getMethodName(), in.getMethodSignature() ), + classMapping.getMethodByDeobf( in.getMethodName(), in.getMethodSignature() ) ); - if( methodIndex != null ) + if( methodMapping != null ) { return m_direction.choose( - methodIndex.getDeobfArgumentName( in.getIndex() ), - methodIndex.getObfArgumentName( in.getIndex() ) + methodMapping.getDeobfArgumentName( in.getIndex() ), + methodMapping.getObfArgumentName( in.getIndex() ) ); } } @@ -207,4 +226,17 @@ public class Translator ancestry.addAll( m_ancestries.getAncestry( className ) ); return ancestry; } + + private ClassMapping findClassMapping( ClassEntry classEntry ) + { + ClassMapping classMapping = m_classes.get( classEntry.getOuterClassName() ); + if( classMapping != null && classEntry.isInnerClass() ) + { + classMapping = m_direction.choose( + classMapping.getInnerClassByObf( classEntry.getInnerClassName() ), + classMapping.getInnerClassByDeobf( classEntry.getInnerClassName() ) + ); + } + return classMapping; + } } -- cgit v1.2.3 From 34c1e8e64ec4575527a19fb4cb0640c57da784db Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 18 Aug 2014 00:55:30 -0400 Subject: crap-ton of bug fixes for inner classes --- src/cuchaz/enigma/Deobfuscator.java | 2 + src/cuchaz/enigma/Main.java | 4 + src/cuchaz/enigma/TranslatingTypeLoader.java | 103 +++++++++--- src/cuchaz/enigma/Util.java | 20 +++ src/cuchaz/enigma/analysis/BridgeFixer.java | 2 + src/cuchaz/enigma/analysis/JarIndex.java | 195 ++++++++++++++++++----- src/cuchaz/enigma/bytecode/BytecodeTools.java | 57 +++++++ src/cuchaz/enigma/bytecode/ClassTranslator.java | 53 ++++-- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 42 +++-- src/cuchaz/enigma/mapping/Translator.java | 16 +- 10 files changed, 392 insertions(+), 102 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 9a0ec132..323aa2ed 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -62,6 +62,8 @@ public class Deobfuscator // config the decompiler m_settings = DecompilerSettings.javaDefaults(); + // DEBUG + //m_settings.setShowSyntheticMembers( true ); // init mappings setMappings( new Mappings() ); diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index 6a300ed6..20d73c29 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -13,6 +13,7 @@ package cuchaz.enigma; import java.io.File; import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.mapping.ClassEntry; public class Main { @@ -30,6 +31,9 @@ public class Main { gui.getController().openMappings( getFile( args[1] ) ); } + + // DEBUG + //gui.getController().openEntry( new ClassEntry( "bah$bag" ) ); // bah,bag } private static File getFile( String path ) diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index c1d96ae3..ae27f374 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -13,6 +13,7 @@ package cuchaz.enigma; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -23,6 +24,7 @@ import javassist.CtClass; import javassist.NotFoundException; import javassist.bytecode.Descriptor; +import com.beust.jcommander.internal.Maps; import com.strobel.assembler.metadata.Buffer; import com.strobel.assembler.metadata.ITypeLoader; @@ -31,6 +33,7 @@ import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.bytecode.ClassTranslator; import cuchaz.enigma.bytecode.InnerClassWriter; import cuchaz.enigma.bytecode.MethodParameterWriter; +import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.Translator; public class TranslatingTypeLoader implements ITypeLoader @@ -39,6 +42,7 @@ public class TranslatingTypeLoader implements ITypeLoader private JarIndex m_jarIndex; private Translator m_obfuscatingTranslator; private Translator m_deobfuscatingTranslator; + private Map m_cache; public TranslatingTypeLoader( JarFile jar, JarIndex jarIndex, Translator obfuscatingTranslator, Translator deobfuscatingTranslator ) { @@ -46,32 +50,71 @@ public class TranslatingTypeLoader implements ITypeLoader m_jarIndex = jarIndex; m_obfuscatingTranslator = obfuscatingTranslator; m_deobfuscatingTranslator = deobfuscatingTranslator; + m_cache = Maps.newHashMap(); } @Override public boolean tryLoadType( String deobfClassName, Buffer out ) + { + // check the cache + byte[] data; + if( m_cache.containsKey( deobfClassName ) ) + { + data = m_cache.get( deobfClassName ); + } + else + { + data = loadType( deobfClassName ); + m_cache.put( deobfClassName, data ); + } + + if( data == null ) + { + return false; + } + + // send the class to the decompiler + out.reset( data.length ); + System.arraycopy( data, 0, out.array(), out.position(), data.length ); + out.position( 0 ); + return true; + } + + private byte[] loadType( String deobfClassName ) { // what class file should we actually load? - String obfClassName = m_obfuscatingTranslator.translateClass( deobfClassName ); - if( obfClassName == null ) + ClassEntry deobfClassEntry = new ClassEntry( deobfClassName ); + ClassEntry obfClassEntry = m_obfuscatingTranslator.translateEntry( deobfClassEntry ); + + // is this an inner class referenced directly? + if( m_jarIndex.getOuterClass( obfClassEntry.getName() ) != null ) { - obfClassName = deobfClassName; + // this class doesn't really exist. Reference it by outer$inner instead + System.err.println( String.format( "WARNING: class %s referenced by bare inner name", deobfClassName ) ); + return null; } - String classFileName = obfClassName; - // is this an inner class? - if( obfClassName.indexOf( '$' ) >= 0 ) + /* DEBUG + if( !Arrays.asList( "java", "org", "io" ).contains( deobfClassName.split( "/" )[0] ) ) { - // the file name is the bare inner class name - String[] parts = obfClassName.split( "\\$" ); - classFileName = parts[parts.length - 1]; + System.out.println( String.format( "Looking for %s (%s)", deobfClassEntry.getName(), obfClassEntry.getName() ) ); } + */ // get the jar entry + String classFileName; + if( obfClassEntry.isInnerClass() ) + { + classFileName = obfClassEntry.getInnerClassName(); + } + else + { + classFileName = obfClassEntry.getOuterClassName(); + } JarEntry entry = m_jar.getJarEntry( classFileName + ".class" ); if( entry == null ) { - return false; + return null; } try @@ -93,35 +136,49 @@ public class TranslatingTypeLoader implements ITypeLoader in.close(); buf = data.toByteArray(); - // load the javassist handle to the class + // load the javassist handle to the raw class String javaClassFileName = Descriptor.toJavaName( classFileName ); ClassPool classPool = new ClassPool(); classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, buf ) ); CtClass c = classPool.get( javaClassFileName ); + // reconstruct inner classes + new InnerClassWriter( m_jarIndex ).write( c ); + + // re-get the javassist handle since we changed class names + String javaClassReconstructedName = Descriptor.toJavaName( obfClassEntry.getName() ); + classPool = new ClassPool(); + classPool.insertClassPath( new ByteArrayClassPath( javaClassReconstructedName, c.toBytecode() ) ); + c = classPool.get( javaClassReconstructedName ); + + // check that the file is correct after inner class reconstruction (ie cause Javassist to fail fast if something is wrong) + assertClassName( c, obfClassEntry ); + // do all kinds of deobfuscating transformations on the class - new InnerClassWriter( m_deobfuscatingTranslator, m_jarIndex ).write( c ); new BridgeFixer().fixBridges( c ); new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); // sanity checking - assert( Descriptor.toJvmName( c.getName() ).equals( deobfClassName ) ) - : String.format( "%s is not %s", Descriptor.toJvmName( c.getName() ), deobfClassName ); - assert( Descriptor.toJvmName( c.getClassFile().getName() ).equals( deobfClassName ) ) - : String.format( "%s is not %s", Descriptor.toJvmName( c.getClassFile().getName() ), deobfClassName ); - - // pass the transformed class along to the decompiler - buf = c.toBytecode(); - out.reset( buf.length ); - System.arraycopy( buf, 0, out.array(), out.position(), buf.length ); - out.position( 0 ); + assertClassName( c, deobfClassEntry ); - return true; + // we have a transformed class! + return c.toBytecode(); } catch( IOException | NotFoundException | CannotCompileException ex ) { throw new Error( ex ); } } + + private void assertClassName( CtClass c, ClassEntry obfClassEntry ) + { + String name1 = Descriptor.toJvmName( c.getName() ); + assert( name1.equals( obfClassEntry.getName() ) ) + : String.format( "Looking for %s, instead found %s", obfClassEntry.getName(), name1 ); + + String name2 = Descriptor.toJvmName( c.getClassFile().getName() ); + assert( name2.equals( obfClassEntry.getName() ) ) + : String.format( "Looking for %s, instead found %s", obfClassEntry.getName(), name2 ); + } } diff --git a/src/cuchaz/enigma/Util.java b/src/cuchaz/enigma/Util.java index 84927fd9..3686ef02 100644 --- a/src/cuchaz/enigma/Util.java +++ b/src/cuchaz/enigma/Util.java @@ -12,6 +12,8 @@ package cuchaz.enigma; import java.awt.Desktop; import java.io.Closeable; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -19,6 +21,10 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.jar.JarFile; +import javassist.CannotCompileException; +import javassist.CtClass; +import javassist.bytecode.Descriptor; + import com.google.common.io.CharStreams; @@ -106,4 +112,18 @@ public class Util } } } + + public static void writeClass( CtClass c ) + { + String name = Descriptor.toJavaName( c.getName() ); + File file = new File( name + ".class" ); + try( FileOutputStream out = new FileOutputStream( file ) ) + { + out.write( c.toBytecode() ); + } + catch( IOException | CannotCompileException ex ) + { + throw new Error( ex ); + } + } } diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java index db441d2b..ee90f513 100644 --- a/src/cuchaz/enigma/analysis/BridgeFixer.java +++ b/src/cuchaz/enigma/analysis/BridgeFixer.java @@ -41,6 +41,8 @@ public class BridgeFixer { bridgedMethod.setName( method.getName() ); method.setModifiers( method.getModifiers() | AccessFlag.BRIDGE ); + + // TODO: rename all references to this method? } } } diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 34e8986f..7d68c357 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -10,6 +10,7 @@ ******************************************************************************/ package cuchaz.enigma.analysis; +import java.lang.reflect.Modifier; import java.util.AbstractMap; import java.util.Collection; import java.util.Iterator; @@ -92,8 +93,8 @@ public class JarIndex // pass 2: index inner classes and anonymous classes for( CtClass c : JarClassIterator.classes( jar ) ) { - String outerClassName = isInnerClass( c ); - if( outerClassName != null ) + String outerClassName = findOuterClass( c ); + if( outerClassName != null )// /* TEMP */ && false ) { String innerClassName = Descriptor.toJvmName( c.getName() ); m_innerClasses.put( outerClassName, innerClassName ); @@ -102,6 +103,14 @@ public class JarIndex if( isAnonymousClass( c, outerClassName ) ) { m_anonymousClasses.add( innerClassName ); + + // DEBUG + System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); + } + else + { + // DEBUG + System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); } } } @@ -175,6 +184,10 @@ public class JarIndex @Override public void edit( ConstructorCall call ) { + boolean isSuper = call.getMethodName().equals( "super" ); + // TODO: make method reference class, update method calls tree to use Invocation instances + // this might end up being a big refactor... =( + String className = Descriptor.toJvmName( call.getClassName() ); ConstructorEntry calledConstructorEntry = new ConstructorEntry( new ClassEntry( className ), @@ -201,75 +214,168 @@ public class JarIndex } } - @SuppressWarnings( "unchecked" ) - private String isInnerClass( CtClass c ) + private String findOuterClass( CtClass c ) { // inner classes: - // the outer class is always a synthetic field - // there's at least one constructor with the type of the synthetic field as an argument - - for( FieldInfo field : (List)c.getClassFile().getFields() ) + // have constructors that can (illegally) set synthetic fields + // the outer class is the only class that calls constructors + + // use the synthetic fields to find the synthetic constructors + for( CtConstructor constructor : c.getDeclaredConstructors() ) { - boolean isSynthetic = (field.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; - if( !isSynthetic ) + if( !isIllegalConstructor( constructor ) ) { continue; } - // skip non-class types - if( !field.getDescriptor().startsWith( "L" ) ) + // who calls this constructor? + Set callerClasses = Sets.newHashSet(); + ConstructorEntry constructorEntry = new ConstructorEntry( + new ClassEntry( Descriptor.toJvmName( c.getName() ) ), + constructor.getMethodInfo().getDescriptor() + ); + for( Entry callerEntry : getMethodCallers( constructorEntry ) ) { - continue; + callerClasses.add( callerEntry.getClassEntry() ); } - // get the outer class from the field type - String outerClassName = Descriptor.toJvmName( Descriptor.toClassName( field.getDescriptor() ) ); - - // look for a constructor where this type is the first parameter - CtConstructor targetConstructor = null; - for( CtConstructor constructor : c.getDeclaredConstructors() ) + // is this called by exactly one class? + if( callerClasses.size() == 1 ) + { + return callerClasses.iterator().next().getName(); + } + else if( callerClasses.size() > 1 ) + { + // TEMP + System.out.println( "WARNING: Illegal class called by more than one class!" + callerClasses ); + } + } + + return null; + } + + @SuppressWarnings( "unchecked" ) + private boolean isIllegalConstructor( CtConstructor constructor ) + { + // illegal constructors only set synthetic member fields, then call super() + String className = constructor.getDeclaringClass().getName(); + + // collect all the field accesses, constructor calls, and method calls + final List illegalFieldWrites = Lists.newArrayList(); + final List constructorCalls = Lists.newArrayList(); + final List methodCalls = Lists.newArrayList(); + try + { + constructor.instrument( new ExprEditor( ) { - String signature = Descriptor.getParamDescriptor( constructor.getMethodInfo().getDescriptor() ); - if( Descriptor.numOfParameters( signature ) < 1 ) + @Override + public void edit( FieldAccess fieldAccess ) { - continue; + if( fieldAccess.isWriter() && constructorCalls.isEmpty() ) + { + illegalFieldWrites.add( fieldAccess ); + } } - // match the first parameter to the outer class - Descriptor.Iterator iter = new Descriptor.Iterator( signature ); - int pos = iter.next(); - if( iter.isParameter() && signature.charAt( pos ) == 'L' ) + @Override + public void edit( ConstructorCall constructorCall ) { - String argumentDesc = signature.substring( pos, signature.indexOf(';', pos) + 1 ); - String argumentClassName = Descriptor.toJvmName( Descriptor.toClassName( argumentDesc ) ); - if( argumentClassName.equals( outerClassName ) ) - { - targetConstructor = constructor; - break; - } + constructorCalls.add( constructorCall ); + } + + @Override + public void edit( MethodCall methodCall ) + { + methodCalls.add( methodCall ); } + } ); + } + catch( CannotCompileException ex ) + { + // we're not compiling anything... this is stupid + throw new Error( ex ); + } + + // method calls are not allowed + if( !methodCalls.isEmpty() ) + { + return false; + } + + // is there only one constructor call? + if( constructorCalls.size() != 1 ) + { + return false; + } + + // is the call to super? + ConstructorCall constructorCall = constructorCalls.get( 0 ); + if( !constructorCall.getMethodName().equals( "super" ) ) + { + return false; + } + + // are there any illegal field writes? + if( illegalFieldWrites.isEmpty() ) + { + return false; + } + + // are all the writes to synthetic fields? + for( FieldAccess fieldWrite : illegalFieldWrites ) + { + // all illegal writes have to be to the local class + if( !fieldWrite.getClassName().equals( className ) ) + { + System.err.println( String.format( "WARNING: illegal write to non-member field %s.%s", fieldWrite.getClassName(), fieldWrite.getFieldName() ) ); + return false; } - if( targetConstructor == null ) + + // find the field + FieldInfo fieldInfo = null; + for( FieldInfo info : (List)constructor.getDeclaringClass().getClassFile().getFields() ) { - continue; + if( info.getName().equals( fieldWrite.getFieldName() ) ) + { + fieldInfo = info; + break; + } + } + if( fieldInfo == null ) + { + // field is in a superclass or something, can't be a local synthetic member + return false; } - // yeah, this is an inner class - return outerClassName; + // is this field synthetic? + boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; + if( !isSynthetic ) + { + System.err.println( String.format( "WARNING: illegal write to non synthetic field %s.%s", className, fieldInfo.getName() ) ); + return false; + } } - return null; + // we passed all the tests! + return true; } - + private boolean isAnonymousClass( CtClass c, String outerClassName ) { String innerClassName = Descriptor.toJvmName( c.getName() ); // anonymous classes: + // can't be abstract // have only one constructor // it's called exactly once by the outer class // type of inner class not referenced anywhere in outer class + // is absract? + if( Modifier.isAbstract( c.getModifiers() ) ) + { + return false; + } + // is there exactly one constructor? if( c.getDeclaredConstructors().length != 1 ) { @@ -282,7 +388,16 @@ public class JarIndex new ClassEntry( innerClassName ), constructor.getMethodInfo().getDescriptor() ); - return getMethodCallers( constructorEntry ).size() == 1; + if( getMethodCallers( constructorEntry ).size() != 1 ) + { + return false; + } + + // TODO: check outer class doesn't reference type + // except this is hard because we can't just load the outer class now + // we'd have to pre-index those references in the JarIndex + + return true; } public Set getObfClassNames( ) diff --git a/src/cuchaz/enigma/bytecode/BytecodeTools.java b/src/cuchaz/enigma/bytecode/BytecodeTools.java index 664350ea..0de9bd6b 100644 --- a/src/cuchaz/enigma/bytecode/BytecodeTools.java +++ b/src/cuchaz/enigma/bytecode/BytecodeTools.java @@ -15,6 +15,7 @@ import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.List; import java.util.Map; import java.util.Set; @@ -25,6 +26,7 @@ import javassist.bytecode.CodeAttribute; import javassist.bytecode.ConstPool; import javassist.bytecode.ExceptionTable; +import com.beust.jcommander.internal.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -266,4 +268,59 @@ public class BytecodeTools ); } } + + public static List getParameterTypes( String signature ) + { + List types = Lists.newArrayList(); + for( int i=0; i 0 ) + { + type = "[" + type; + } + types.add( type ); + } + return types; + } } diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index 3b5beeb2..9ce06a58 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java @@ -10,7 +10,6 @@ ******************************************************************************/ package cuchaz.enigma.bytecode; -import java.util.HashSet; import java.util.Set; import javassist.ClassMap; @@ -20,6 +19,10 @@ import javassist.CtField; import javassist.CtMethod; import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; +import javassist.bytecode.InnerClassesAttribute; + +import com.beust.jcommander.internal.Sets; + import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MethodEntry; @@ -133,25 +136,47 @@ public class ClassTranslator // translate all the class names referenced in the code // the above code only changed method/field/reference names and types, but not the class names themselves - Set classNames = getAllClassNames( c ); + Set classEntries = getAllClassEntries( c ); ClassMap map = new ClassMap(); - for( String className : classNames ) + for( ClassEntry obfClassEntry : classEntries ) { - String translatedName = m_translator.translateClass( className ); - if( translatedName != null ) - { - map.put( className, translatedName ); - } + map.put( obfClassEntry.getName(), m_translator.translateEntry( obfClassEntry ).getName() ); } - if( !map.isEmpty() ) + c.replaceClassName( map ); + + // translate the names in the InnerClasses attribute + InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute( InnerClassesAttribute.tag ); + if( attr != null ) { - c.replaceClassName( map ); + for( int i=0; i ATTR: %s,%s,%s", + obfClassEntry, deobfClassEntry, + attr.outerClass( i ), + attr.innerClass( i ), + attr.innerName( i ) + ) ); + */ + } } } - private Set getAllClassNames( CtClass c ) + private Set getAllClassEntries( CtClass c ) { - final Set names = new HashSet(); + final Set entries = Sets.newHashSet(); ClassMap map = new ClassMap( ) { @Override @@ -159,13 +184,13 @@ public class ClassTranslator { if( obj instanceof String ) { - names.add( (String)obj ); + entries.add( new ClassEntry( (String)obj ) ); } return null; } private static final long serialVersionUID = -202160293602070641L; }; c.replaceClassName( map ); - return names; + return entries; } } diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java index b0e33ac2..c412b1aa 100644 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -18,16 +18,14 @@ import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; import javassist.bytecode.InnerClassesAttribute; import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.mapping.Translator; +import cuchaz.enigma.mapping.ClassEntry; public class InnerClassWriter { - private Translator m_deobfuscatingTranslator; private JarIndex m_jarIndex; - public InnerClassWriter( Translator deobfuscatingTranslator, JarIndex jarIndex ) + public InnerClassWriter( JarIndex jarIndex ) { - m_deobfuscatingTranslator = deobfuscatingTranslator; m_jarIndex = jarIndex; } @@ -44,7 +42,8 @@ public class InnerClassWriter else { // this is an inner class, rename it to outer$inner - c.setName( obfOuterClassName + "$" + obfClassName ); + ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfClassName ); + c.setName( obfClassEntry.getName() ); } // write the inner classes if needed @@ -62,31 +61,20 @@ public class InnerClassWriter for( String obfInnerClassName : obfInnerClassNames ) { // deobfuscate the class names - String deobfOuterClassName = m_deobfuscatingTranslator.translateClass( obfOuterClassName ); - if( deobfOuterClassName == null ) - { - deobfOuterClassName = obfOuterClassName; - } - String obfOuterInnerClassName = obfOuterClassName + "$" + obfInnerClassName; - String deobfOuterInnerClassName = m_deobfuscatingTranslator.translateClass( obfOuterInnerClassName ); - if( deobfOuterInnerClassName == null ) - { - deobfOuterInnerClassName = obfOuterInnerClassName; - } - String deobfInnerClassName = deobfOuterInnerClassName.substring( deobfOuterInnerClassName.lastIndexOf( '$' ) + 1 ); - + ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfInnerClassName ); + // here's what the JVM spec says about the InnerClasses attribute // append( inner, outer of inner if inner is member of outer 0 ow, name after $ if inner not anonymous 0 ow, flags ); // update the attribute with this inner class ConstPool constPool = c.getClassFile().getConstPool(); - int innerClassIndex = constPool.addClassInfo( deobfOuterInnerClassName ); + int innerClassIndex = constPool.addClassInfo( obfClassEntry.getName() ); int outerClassIndex = 0; int innerClassSimpleNameIndex = 0; if( !m_jarIndex.isAnonymousClass( obfInnerClassName ) ) { - outerClassIndex = constPool.addClassInfo( deobfOuterClassName ); - innerClassSimpleNameIndex = constPool.addUtf8Info( deobfInnerClassName ); + outerClassIndex = constPool.addClassInfo( obfClassEntry.getOuterClassName() ); + innerClassSimpleNameIndex = constPool.addUtf8Info( obfClassEntry.getInnerClassName() ); } attr.append( @@ -96,8 +84,18 @@ public class InnerClassWriter c.getClassFile().getAccessFlags() & ~AccessFlag.SUPER ); + /* DEBUG + System.out.println( String.format( "\tOBF: %s -> ATTR: %s,%s,%s (replace %s with %s)", + obfClassEntry, + attr.outerClass( attr.tableLength() - 1 ), + attr.innerClass( attr.tableLength() - 1 ), + attr.innerName( attr.tableLength() - 1 ), + obfInnerClassName, obfClassEntry.getName() + ) ); + */ + // make sure the outer class references only the new inner class names - c.replaceClassName( obfInnerClassName, deobfOuterInnerClassName ); + c.replaceClassName( obfInnerClassName, obfClassEntry.getName() ); } } } diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index 76f45cd6..fc41f945 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -72,11 +72,21 @@ public class Translator public ClassEntry translateEntry( ClassEntry in ) { String name = translate( in ); - if( name == null ) + if( name != null ) + { + return new ClassEntry( name ); + } + + if( in.isInnerClass() ) { - return in; + // just translate the outer class name + String outerClassName = translate( in.getOuterClassEntry() ); + if( outerClassName != null ) + { + return new ClassEntry( outerClassName + "$" + in.getInnerClassName() ); + } } - return new ClassEntry( name ); + return in; } public String translate( FieldEntry in ) -- cgit v1.2.3 From fb94b7b01070c176f096d2a6e43c495ebea80bbe Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 18 Aug 2014 00:57:14 -0400 Subject: packaged v0.2 beta! --- src/cuchaz/enigma/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java index 72275628..0b431c71 100644 --- a/src/cuchaz/enigma/Constants.java +++ b/src/cuchaz/enigma/Constants.java @@ -14,7 +14,7 @@ package cuchaz.enigma; public class Constants { public static final String Name = "Enigma"; - public static final String Version = "0.1 beta"; + public static final String Version = "0.2 beta"; 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 -- cgit v1.2.3 From 58fe3a4ec77507345bc2a96857b04534bcb845a7 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 18 Aug 2014 22:09:24 -0400 Subject: fixed type caching after rename allowed enums constants to be renamable --- src/cuchaz/enigma/Deobfuscator.java | 13 ++++++++++--- src/cuchaz/enigma/TranslatingTypeLoader.java | 5 +++++ src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 18 ++++++++++++------ src/cuchaz/enigma/gui/GuiController.java | 9 ++++++++- 4 files changed, 35 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 323aa2ed..293e1c2f 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -29,6 +29,7 @@ import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; +import cuchaz.enigma.analysis.TreeDumpVisitor; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ClassMapping; @@ -49,6 +50,7 @@ public class Deobfuscator private JarIndex m_jarIndex; private Mappings m_mappings; private Renamer m_renamer; + private TranslatingTypeLoader m_typeLoader; public Deobfuscator( File file ) throws IOException @@ -93,12 +95,13 @@ public class Deobfuscator m_renamer = new Renamer( m_jarIndex, m_mappings ); // update decompiler options - m_settings.setTypeLoader( new TranslatingTypeLoader( + m_typeLoader = new TranslatingTypeLoader( m_jar, m_jarIndex, getTranslator( TranslationDirection.Obfuscating ), getTranslator( TranslationDirection.Deobfuscating ) - ) ); + ); + m_settings.setTypeLoader( m_typeLoader ); } public Translator getTranslator( TranslationDirection direction ) @@ -158,7 +161,8 @@ public class Deobfuscator // render the AST into source StringWriter buf = new StringWriter(); root.acceptVisitor( new InsertParenthesesVisitor(), null ); - //root.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); + // DEBUG + root.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); root.acceptVisitor( new JavaOutputVisitor( new PlainTextOutput( buf ), m_settings ), null ); // build the source index @@ -196,6 +200,9 @@ public class Deobfuscator { throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); } + + // clear the type loader cache + m_typeLoader.clearCache(); } public Entry obfuscateEntry( Entry deobfEntry ) diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index ae27f374..cc863646 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -53,6 +53,11 @@ public class TranslatingTypeLoader implements ITypeLoader m_cache = Maps.newHashMap(); } + public void clearCache( ) + { + m_cache.clear(); + } + @Override public boolean tryLoadType( String deobfClassName, Buffer out ) { diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java index 6c14ee99..f31eb1a8 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java @@ -201,6 +201,18 @@ public class SourceIndexVisitor implements IAstVisitor return recurse( node, index ); } + @Override + public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) + { + // treat enum declarations as field declarations + FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); + index.addDeclaration( node.getNameToken(), fieldEntry ); + + return recurse( node, index ); + } + private Void recurse( AstNode node, SourceIndex index ) { for( final AstNode child : node.getChildren() ) @@ -560,12 +572,6 @@ public class SourceIndexVisitor implements IAstVisitor return recurse( node, index ); } - @Override - public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) - { - return recurse( node, index ); - } - @Override public Void visitAssertStatement( AssertStatement node, SourceIndex index ) { diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index ffeb99aa..f305e341 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -272,7 +272,14 @@ public class GuiController m_gui.setSource( m_index.getSource() ); if( obfEntryToShow != null ) { - m_gui.showToken( m_index.getDeclarationToken( m_deobfuscator.deobfuscateEntry( obfEntryToShow ) ) ); + Entry deobfEntryToShow = m_deobfuscator.deobfuscateEntry( obfEntryToShow ); + Token token = m_index.getDeclarationToken( deobfEntryToShow ); + if( token == null ) + { + // TEMP + System.out.println( "WARNING: can't find token for " + obfEntryToShow + " -> " + deobfEntryToShow ); + } + m_gui.showToken( token ); } // set the highlighted tokens -- cgit v1.2.3 From c4e35f2d516ade27e8e1a863b4bc356f182f43c2 Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 19 Aug 2014 00:25:32 -0400 Subject: started new reference navigation system --- .../enigma/analysis/BehaviorReferenceTreeNode.java | 105 +++++++++++++++ src/cuchaz/enigma/analysis/EntryReference.java | 28 ++++ src/cuchaz/enigma/analysis/FieldCallsTreeNode.java | 82 ------------ .../enigma/analysis/FieldReferenceTreeNode.java | 92 +++++++++++++ src/cuchaz/enigma/analysis/JarIndex.java | 141 +++++++++++++------- .../enigma/analysis/MethodCallsTreeNode.java | 144 --------------------- src/cuchaz/enigma/analysis/ReferenceTreeNode.java | 19 +++ src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 20 ++- src/cuchaz/enigma/analysis/TreeDumpVisitor.java | 11 +- src/cuchaz/enigma/gui/Gui.java | 46 ++++--- src/cuchaz/enigma/gui/GuiController.java | 65 +++++----- src/cuchaz/enigma/mapping/BehaviorEntry.java | 6 + src/cuchaz/enigma/mapping/ConstructorEntry.java | 3 +- src/cuchaz/enigma/mapping/MethodEntry.java | 3 +- src/cuchaz/enigma/mapping/Translator.java | 13 ++ 15 files changed, 441 insertions(+), 337 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java create mode 100644 src/cuchaz/enigma/analysis/EntryReference.java delete mode 100644 src/cuchaz/enigma/analysis/FieldCallsTreeNode.java create mode 100644 src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java delete mode 100644 src/cuchaz/enigma/analysis/MethodCallsTreeNode.java create mode 100644 src/cuchaz/enigma/analysis/ReferenceTreeNode.java create mode 100644 src/cuchaz/enigma/mapping/BehaviorEntry.java (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java new file mode 100644 index 00000000..158aad71 --- /dev/null +++ b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * 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.analysis; + +import java.util.Set; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeNode; + +import com.google.common.collect.Sets; + +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.Translator; + +public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode +{ + private static final long serialVersionUID = -3658163700783307520L; + + private Translator m_deobfuscatingTranslator; + private BehaviorEntry m_entry; + private EntryReference m_reference; + + public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, BehaviorEntry entry ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = entry; + m_reference = null; + } + + public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = reference.entry; + m_reference = reference; + } + + @Override + public BehaviorEntry getEntry( ) + { + return m_entry; + } + + @Override + public EntryReference getReference( ) + { + return m_reference; + } + + @Override + public String toString( ) + { + if( m_reference != null ) + { + return m_deobfuscatingTranslator.translateEntry( m_reference.caller ).toString(); + } + return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); + } + + public void load( JarIndex index, boolean recurse ) + { + // get all the child nodes + for( EntryReference reference : index.getBehaviorReferences( m_entry ) ) + { + add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); + } + + if( recurse && children != null ) + { + for( Object child : children ) + { + if( child instanceof BehaviorReferenceTreeNode ) + { + BehaviorReferenceTreeNode node = (BehaviorReferenceTreeNode)child; + + // don't recurse into ancestor + Set ancestors = Sets.newHashSet(); + TreeNode n = (TreeNode)node; + while( n.getParent() != null ) + { + n = n.getParent(); + if( n instanceof BehaviorReferenceTreeNode ) + { + ancestors.add( ((BehaviorReferenceTreeNode)n).getEntry() ); + } + } + if( ancestors.contains( node.getEntry() ) ) + { + continue; + } + + node.load( index, true ); + } + } + } + } +} diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java new file mode 100644 index 00000000..f462210a --- /dev/null +++ b/src/cuchaz/enigma/analysis/EntryReference.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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.analysis; + +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.Entry; + +public class EntryReference +{ + public T entry; + public BehaviorEntry caller; + public int pos; + + public EntryReference( T entry, BehaviorEntry caller, int pos ) + { + this.entry = entry; + this.caller = caller; + this.pos = pos; + } +} diff --git a/src/cuchaz/enigma/analysis/FieldCallsTreeNode.java b/src/cuchaz/enigma/analysis/FieldCallsTreeNode.java deleted file mode 100644 index 0427b3be..00000000 --- a/src/cuchaz/enigma/analysis/FieldCallsTreeNode.java +++ /dev/null @@ -1,82 +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.analysis; - -import javax.swing.tree.DefaultMutableTreeNode; - -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Translator; - -public class FieldCallsTreeNode extends DefaultMutableTreeNode -{ - private static final long serialVersionUID = -7934108091928699835L; - - private Translator m_deobfuscatingTranslator; - private FieldEntry m_entry; - - public FieldCallsTreeNode( Translator deobfuscatingTranslator, FieldEntry fieldEntry ) - { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_entry = fieldEntry; - } - - public FieldEntry getFieldEntry( ) - { - return m_entry; - } - - @Override - public String toString( ) - { - String className = m_deobfuscatingTranslator.translateClass( m_entry.getClassName() ); - if( className == null ) - { - className = m_entry.getClassName(); - } - - String targetName = m_deobfuscatingTranslator.translate( m_entry ); - if( targetName == null ) - { - targetName = m_entry.getName(); - } - return className + "." + targetName; - } - - public void load( JarIndex index, boolean recurse ) - { - // get all the child nodes - for( Entry entry : index.getFieldCallers( m_entry ) ) - { - if( entry instanceof MethodEntry ) - { - add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (MethodEntry)entry ) ); - } - else if( entry instanceof ConstructorEntry ) - { - add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (ConstructorEntry)entry ) ); - } - } - - if( recurse && children != null ) - { - for( Object node : children ) - { - if( node instanceof MethodCallsTreeNode ) - { - ((MethodCallsTreeNode)node).load( index, true ); - } - } - } - } -} diff --git a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java new file mode 100644 index 00000000..dd552d68 --- /dev/null +++ b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * 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.analysis; + +import javax.swing.tree.DefaultMutableTreeNode; + +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.Translator; + +public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode +{ + private static final long serialVersionUID = -7934108091928699835L; + + private Translator m_deobfuscatingTranslator; + private FieldEntry m_entry; + private EntryReference m_reference; + + public FieldReferenceTreeNode( Translator deobfuscatingTranslator, FieldEntry entry ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = entry; + m_reference = null; + } + + private FieldReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = reference.entry; + m_reference = reference; + } + + @Override + public FieldEntry getEntry( ) + { + return m_entry; + } + + @Override + public EntryReference getReference( ) + { + return m_reference; + } + + @Override + public String toString( ) + { + if( m_reference != null ) + { + return m_deobfuscatingTranslator.translateEntry( m_reference.caller ).toString(); + } + return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); + } + + public void load( JarIndex index, boolean recurse ) + { + // get all the child nodes + if( m_reference == null ) + { + for( EntryReference reference : index.getFieldReferences( m_entry ) ) + { + add( new FieldReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); + } + } + else + { + for( EntryReference reference : index.getBehaviorReferences( m_reference.caller ) ) + { + add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); + } + } + + if( recurse && children != null ) + { + for( Object node : children ) + { + if( node instanceof BehaviorReferenceTreeNode ) + { + ((BehaviorReferenceTreeNode)node).load( index, true ); + } + } + } + } +} diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 7d68c357..f1c29c5b 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -35,12 +35,15 @@ import javassist.expr.MethodCall; import javassist.expr.NewExpr; import com.google.common.collect.HashMultimap; +import com.google.common.collect.HashMultiset; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import com.google.common.collect.Multiset; import com.google.common.collect.Sets; import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; @@ -53,8 +56,8 @@ public class JarIndex private Set m_obfClassNames; private Ancestries m_ancestries; private Multimap m_methodImplementations; - private Multimap m_methodCalls; - private Multimap m_fieldCalls; + private Multimap> m_behaviorReferences; + private Multimap> m_fieldReferences; private Multimap m_innerClasses; private Map m_outerClasses; private Set m_anonymousClasses; @@ -64,8 +67,8 @@ public class JarIndex m_obfClassNames = Sets.newHashSet(); m_ancestries = new Ancestries(); m_methodImplementations = HashMultimap.create(); - m_methodCalls = HashMultimap.create(); - m_fieldCalls = HashMultimap.create(); + m_behaviorReferences = HashMultimap.create(); + m_fieldReferences = HashMultimap.create(); m_innerClasses = HashMultimap.create(); m_outerClasses = Maps.newHashMap(); m_anonymousClasses = Sets.newHashSet(); @@ -128,7 +131,7 @@ public class JarIndex { // get the method entry String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); - final Entry thisEntry; + final BehaviorEntry thisEntry; if( behavior instanceof CtMethod ) { MethodEntry methodEntry = new MethodEntry( @@ -156,6 +159,7 @@ public class JarIndex // index method calls try { + final Multiset callNumbers = HashMultiset.create(); behavior.instrument( new ExprEditor( ) { @Override @@ -167,7 +171,13 @@ public class JarIndex call.getMethodName(), call.getSignature() ); - m_methodCalls.put( calledMethodEntry, thisEntry ); + callNumbers.add( calledMethodEntry ); + EntryReference reference = new EntryReference( + calledMethodEntry, + thisEntry, + callNumbers.count( calledMethodEntry ) - 1 + ); + m_behaviorReferences.put( calledMethodEntry, reference ); } @Override @@ -178,22 +188,33 @@ public class JarIndex new ClassEntry( className ), call.getFieldName() ); - m_fieldCalls.put( calledFieldEntry, thisEntry ); + callNumbers.add( calledFieldEntry ); + EntryReference reference = new EntryReference( + calledFieldEntry, + thisEntry, + callNumbers.count( calledFieldEntry ) - 1 + ); + m_fieldReferences.put( calledFieldEntry, reference ); } @Override public void edit( ConstructorCall call ) { + // TODO: save isSuper in the reference somehow boolean isSuper = call.getMethodName().equals( "super" ); - // TODO: make method reference class, update method calls tree to use Invocation instances - // this might end up being a big refactor... =( String className = Descriptor.toJvmName( call.getClassName() ); ConstructorEntry calledConstructorEntry = new ConstructorEntry( new ClassEntry( className ), call.getSignature() ); - m_methodCalls.put( calledConstructorEntry, thisEntry ); + callNumbers.add( calledConstructorEntry ); + EntryReference reference = new EntryReference( + calledConstructorEntry, + thisEntry, + callNumbers.count( calledConstructorEntry ) - 1 + ); + m_behaviorReferences.put( calledConstructorEntry, reference ); } @Override @@ -204,7 +225,13 @@ public class JarIndex new ClassEntry( className ), call.getSignature() ); - m_methodCalls.put( calledConstructorEntry, thisEntry ); + callNumbers.add( calledConstructorEntry ); + EntryReference reference = new EntryReference( + calledConstructorEntry, + thisEntry, + callNumbers.count( calledConstructorEntry ) - 1 + ); + m_behaviorReferences.put( calledConstructorEntry, reference ); } } ); } @@ -234,9 +261,9 @@ public class JarIndex new ClassEntry( Descriptor.toJvmName( c.getName() ) ), constructor.getMethodInfo().getDescriptor() ); - for( Entry callerEntry : getMethodCallers( constructorEntry ) ) + for( EntryReference reference : getBehaviorReferences( constructorEntry ) ) { - callerClasses.add( callerEntry.getClassEntry() ); + callerClasses.add( reference.caller.getClassEntry() ); } // is this called by exactly one class? @@ -388,7 +415,7 @@ public class JarIndex new ClassEntry( innerClassName ), constructor.getMethodInfo().getDescriptor() ); - if( getMethodCallers( constructorEntry ).size() != 1 ) + if( getBehaviorReferences( constructorEntry ).size() != 1 ) { return false; } @@ -469,14 +496,26 @@ public class JarIndex return rootNode; } - public Collection getFieldCallers( FieldEntry fieldEntry ) + @SuppressWarnings( "unchecked" ) + public Collection> getFieldReferences( FieldEntry fieldEntry ) { - return m_fieldCalls.get( fieldEntry ); + List> references = Lists.newArrayList(); + for( EntryReference reference : m_fieldReferences.get( fieldEntry ) ) + { + references.add( (EntryReference)reference ); + } + return references; } - public Collection getMethodCallers( Entry entry ) + @SuppressWarnings( "unchecked" ) + public Collection> getBehaviorReferences( BehaviorEntry behaviorEntry ) { - return m_methodCalls.get( entry ); + List> references = Lists.newArrayList(); + for( EntryReference reference : m_behaviorReferences.get( behaviorEntry ) ) + { + references.add( (EntryReference)reference ); + } + return references; } public Collection getInnerClasses( String obfOuterClassName ) @@ -498,85 +537,91 @@ public class JarIndex { m_ancestries.renameClasses( renames ); renameMultimap( renames, m_methodImplementations ); - renameMultimap( renames, m_methodCalls ); - renameMultimap( renames, m_fieldCalls ); + renameMultimap( renames, m_behaviorReferences ); + renameMultimap( renames, m_fieldReferences ); } - private void renameMultimap( Map renames, Multimap map ) + private void renameMultimap( Map renames, Multimap map ) { // for each key/value pair... - Set> entriesToAdd = Sets.newHashSet(); - Iterator> iter = map.entries().iterator(); + Set> entriesToAdd = Sets.newHashSet(); + Iterator> iter = map.entries().iterator(); while( iter.hasNext() ) { - Map.Entry entry = iter.next(); + Map.Entry entry = iter.next(); iter.remove(); - entriesToAdd.add( new AbstractMap.SimpleEntry( - renameEntry( renames, entry.getKey() ), - renameEntry( renames, entry.getValue() ) + entriesToAdd.add( new AbstractMap.SimpleEntry( + renameThing( renames, entry.getKey() ), + renameThing( renames, entry.getValue() ) ) ); } - for( Map.Entry entry : entriesToAdd ) + for( Map.Entry entry : entriesToAdd ) { map.put( entry.getKey(), entry.getValue() ); } } @SuppressWarnings( "unchecked" ) - private T renameEntry( Map renames, T entry ) + private T renameThing( Map renames, T thing ) { - if( entry instanceof String ) + if( thing instanceof String ) { - String stringEntry = (String)entry; + String stringEntry = (String)thing; if( renames.containsKey( stringEntry ) ) { return (T)renames.get( stringEntry ); } } - else if( entry instanceof ClassEntry ) + else if( thing instanceof ClassEntry ) { - ClassEntry classEntry = (ClassEntry)entry; - return (T)new ClassEntry( renameEntry( renames, classEntry.getClassName() ) ); + ClassEntry classEntry = (ClassEntry)thing; + return (T)new ClassEntry( renameThing( renames, classEntry.getClassName() ) ); } - else if( entry instanceof FieldEntry ) + else if( thing instanceof FieldEntry ) { - FieldEntry fieldEntry = (FieldEntry)entry; + FieldEntry fieldEntry = (FieldEntry)thing; return (T)new FieldEntry( - renameEntry( renames, fieldEntry.getClassEntry() ), + renameThing( renames, fieldEntry.getClassEntry() ), fieldEntry.getName() ); } - else if( entry instanceof ConstructorEntry ) + else if( thing instanceof ConstructorEntry ) { - ConstructorEntry constructorEntry = (ConstructorEntry)entry; + ConstructorEntry constructorEntry = (ConstructorEntry)thing; return (T)new ConstructorEntry( - renameEntry( renames, constructorEntry.getClassEntry() ), + renameThing( renames, constructorEntry.getClassEntry() ), constructorEntry.getSignature() ); } - else if( entry instanceof MethodEntry ) + else if( thing instanceof MethodEntry ) { - MethodEntry methodEntry = (MethodEntry)entry; + MethodEntry methodEntry = (MethodEntry)thing; return (T)new MethodEntry( - renameEntry( renames, methodEntry.getClassEntry() ), + renameThing( renames, methodEntry.getClassEntry() ), methodEntry.getName(), methodEntry.getSignature() ); } - else if( entry instanceof ArgumentEntry ) + else if( thing instanceof ArgumentEntry ) { - ArgumentEntry argumentEntry = (ArgumentEntry)entry; + ArgumentEntry argumentEntry = (ArgumentEntry)thing; return (T)new ArgumentEntry( - renameEntry( renames, argumentEntry.getMethodEntry() ), + renameThing( renames, argumentEntry.getMethodEntry() ), argumentEntry.getIndex(), argumentEntry.getName() ); } + else if( thing instanceof EntryReference ) + { + EntryReference reference = (EntryReference)thing; + reference.entry = renameThing( renames, reference.entry ); + return thing; + } else { - throw new Error( "Not an entry: " + entry ); + throw new Error( "Not an entry: " + thing ); } - return entry; + return thing; } } diff --git a/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java b/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java deleted file mode 100644 index b5cf4c33..00000000 --- a/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java +++ /dev/null @@ -1,144 +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.analysis; - -import java.util.Set; - -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.TreeNode; - -import com.google.common.collect.Sets; - -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Translator; - -public class MethodCallsTreeNode extends DefaultMutableTreeNode -{ - private static final long serialVersionUID = -3658163700783307520L; - - private Translator m_deobfuscatingTranslator; - private MethodEntry m_methodEntry; - private ConstructorEntry m_constructorEntry; - - public MethodCallsTreeNode( Translator deobfuscatingTranslator, MethodEntry entry ) - { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_methodEntry = entry; - m_constructorEntry = null; - } - - public MethodCallsTreeNode( Translator deobfuscatingTranslator, ConstructorEntry entry ) - { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_methodEntry = null; - m_constructorEntry = entry; - } - - public MethodEntry getMethodEntry( ) - { - return m_methodEntry; - } - - public ConstructorEntry getConstructorEntry( ) - { - return m_constructorEntry; - } - - public Entry getEntry( ) - { - if( m_methodEntry != null ) - { - return m_methodEntry; - } - else if( m_constructorEntry != null ) - { - return m_constructorEntry; - } - throw new Error( "Illegal state!" ); - } - - @Override - public String toString( ) - { - if( m_methodEntry != null ) - { - String className = m_deobfuscatingTranslator.translateClass( m_methodEntry.getClassName() ); - if( className == null ) - { - className = m_methodEntry.getClassName(); - } - - String methodName = m_deobfuscatingTranslator.translate( m_methodEntry ); - if( methodName == null ) - { - methodName = m_methodEntry.getName(); - } - return className + "." + methodName + "()"; - } - else if( m_constructorEntry != null ) - { - String className = m_deobfuscatingTranslator.translateClass( m_constructorEntry.getClassName() ); - if( className == null ) - { - className = m_constructorEntry.getClassName(); - } - return className + "()"; - } - throw new Error( "Illegal state!" ); - } - - public void load( JarIndex index, boolean recurse ) - { - // get all the child nodes - for( Entry entry : index.getMethodCallers( getEntry() ) ) - { - if( entry instanceof MethodEntry ) - { - add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (MethodEntry)entry ) ); - } - else if( entry instanceof ConstructorEntry ) - { - add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (ConstructorEntry)entry ) ); - } - } - - if( recurse && children != null ) - { - for( Object child : children ) - { - if( child instanceof MethodCallsTreeNode ) - { - MethodCallsTreeNode node = (MethodCallsTreeNode)child; - - // don't recurse into ancestor - Set ancestors = Sets.newHashSet(); - TreeNode n = (TreeNode)node; - while( n.getParent() != null ) - { - n = n.getParent(); - if( n instanceof MethodCallsTreeNode ) - { - ancestors.add( ((MethodCallsTreeNode)n).getEntry() ); - } - } - if( ancestors.contains( node.getEntry() ) ) - { - continue; - } - - node.load( index, true ); - } - } - } - } -} diff --git a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java new file mode 100644 index 00000000..08ae39d9 --- /dev/null +++ b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * 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.analysis; + +import cuchaz.enigma.mapping.Entry; + +public interface ReferenceTreeNode +{ + T getEntry(); + EntryReference getReference(); +} diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java index f31eb1a8..841d1767 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java @@ -213,6 +213,20 @@ public class SourceIndexVisitor implements IAstVisitor return recurse( node, index ); } + @Override + public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) + { + MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + if( ref != null ) + { + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); + index.add( node.getIdentifierToken(), fieldEntry ); + } + + return recurse( node, index ); + } + private Void recurse( AstNode node, SourceIndex index ) { for( final AstNode child : node.getChildren() ) @@ -476,12 +490,6 @@ public class SourceIndexVisitor implements IAstVisitor return recurse( node, index ); } - @Override - public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - @Override public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, SourceIndex index ) { diff --git a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java index ac3e92db..12febefd 100644 --- a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java +++ b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java @@ -122,7 +122,7 @@ public class TreeDumpVisitor implements IAstVisitor // show the tree try { - m_out.write( getIndent( node ) + node.getClass().getSimpleName() + dumpUserData( node ) + " " + node.getRegion() + "\n" ); + m_out.write( getIndent( node ) + node.getClass().getSimpleName() + " " + getText( node ) + " " + dumpUserData( node ) + " " + node.getRegion() + "\n" ); } catch( IOException ex ) { @@ -137,6 +137,15 @@ public class TreeDumpVisitor implements IAstVisitor return null; } + private String getText( AstNode node ) + { + if( node instanceof Identifier ) + { + return "\"" + node.getText() + "\""; + } + return ""; + } + private String dumpUserData( AstNode node ) { StringBuilder buf = new StringBuilder(); diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 9ed6dd86..43a0cdad 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -66,10 +66,11 @@ import jsyntaxpane.DefaultSyntaxKit; import com.google.common.collect.Lists; import cuchaz.enigma.Constants; +import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; import cuchaz.enigma.analysis.ClassInheritanceTreeNode; -import cuchaz.enigma.analysis.FieldCallsTreeNode; -import cuchaz.enigma.analysis.MethodCallsTreeNode; +import cuchaz.enigma.analysis.FieldReferenceTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; +import cuchaz.enigma.analysis.ReferenceTreeNode; import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; @@ -191,7 +192,7 @@ public class Gui String selected = m_obfClasses.getSelectedValue(); if( selected != null ) { - m_controller.openEntry( new ClassEntry( selected ) ); + m_controller.openDeclaration( new ClassEntry( selected ) ); } } } @@ -217,7 +218,7 @@ public class Gui String selected = m_deobfClasses.getSelectedValue(); if( selected != null ) { - m_controller.openEntry( new ClassEntry( selected ) ); + m_controller.openDeclaration( new ClassEntry( selected ) ); } } } @@ -268,11 +269,11 @@ public class Gui break; case KeyEvent.VK_N: - openEntry(); + openDeclaration(); break; case KeyEvent.VK_P: - m_controller.openPreviousEntry(); + m_controller.openPreviousLocation(); break; case KeyEvent.VK_C: @@ -341,7 +342,7 @@ public class Gui @Override public void actionPerformed( ActionEvent event ) { - openEntry(); + openDeclaration(); } } ); menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_N, 0 ) ); @@ -356,7 +357,7 @@ public class Gui @Override public void actionPerformed( ActionEvent event ) { - m_controller.openPreviousEntry(); + m_controller.openPreviousLocation(); } } ); menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_P, 0 ) ); @@ -385,14 +386,14 @@ public class Gui Object node = path.getLastPathComponent(); if( node instanceof ClassInheritanceTreeNode ) { - m_controller.openEntry( new ClassEntry( ((ClassInheritanceTreeNode)node).getObfClassName() ) ); + m_controller.openDeclaration( new ClassEntry( ((ClassInheritanceTreeNode)node).getObfClassName() ) ); } else if( node instanceof MethodInheritanceTreeNode ) { MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode)node; if( methodNode.isImplemented() ) { - m_controller.openEntry( methodNode.getMethodEntry() ); + m_controller.openDeclaration( methodNode.getMethodEntry() ); } } } @@ -407,6 +408,7 @@ public class Gui m_callsTree.setModel( null ); m_callsTree.addMouseListener( new MouseAdapter( ) { + @SuppressWarnings( "unchecked" ) @Override public void mouseClicked( MouseEvent event ) { @@ -420,9 +422,17 @@ public class Gui } Object node = path.getLastPathComponent(); - if( node instanceof MethodCallsTreeNode ) + if( node instanceof ReferenceTreeNode ) { - m_controller.openEntry( ((MethodCallsTreeNode)node).getEntry() ); + ReferenceTreeNode referenceNode = ((ReferenceTreeNode)node); + if( referenceNode.getReference() != null ) + { + m_controller.openReference( referenceNode.getReference() ); + } + else + { + m_controller.openDeclaration( referenceNode.getEntry() ); + } } } } @@ -862,7 +872,7 @@ public class Gui m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry || isConstructorEntry ); m_showCallsMenu.setEnabled( isFieldEntry || isMethodEntry || isConstructorEntry ); m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); - m_openPreviousMenu.setEnabled( m_controller.hasPreviousEntry() ); + m_openPreviousMenu.setEnabled( m_controller.hasPreviousLocation() ); } private void startRename( ) @@ -977,17 +987,17 @@ public class Gui if( m_selectedEntryPair.obf instanceof FieldEntry ) { - FieldCallsTreeNode node = m_controller.getFieldCalls( (FieldEntry)m_selectedEntryPair.obf ); + FieldReferenceTreeNode node = m_controller.getFieldReferences( (FieldEntry)m_selectedEntryPair.obf ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } else if( m_selectedEntryPair.obf instanceof MethodEntry ) { - MethodCallsTreeNode node = m_controller.getMethodCalls( (MethodEntry)m_selectedEntryPair.obf ); + BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (MethodEntry)m_selectedEntryPair.obf ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } else if( m_selectedEntryPair.obf instanceof ConstructorEntry ) { - MethodCallsTreeNode node = m_controller.getMethodCalls( (ConstructorEntry)m_selectedEntryPair.obf ); + BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (ConstructorEntry)m_selectedEntryPair.obf ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } @@ -1009,13 +1019,13 @@ public class Gui return new TreePath( nodes.toArray() ); } - private void openEntry( ) + private void openDeclaration( ) { if( m_selectedEntryPair == null ) { return; } - m_controller.openEntry( m_selectedEntryPair.obf ); + m_controller.openDeclaration( m_selectedEntryPair.obf ); } private void close( ) diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index f305e341..f80bec7e 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -20,14 +20,15 @@ import java.util.Stack; import com.google.common.collect.Lists; import cuchaz.enigma.Deobfuscator; +import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; import cuchaz.enigma.analysis.ClassInheritanceTreeNode; -import cuchaz.enigma.analysis.FieldCallsTreeNode; -import cuchaz.enigma.analysis.MethodCallsTreeNode; +import cuchaz.enigma.analysis.EntryReference; +import cuchaz.enigma.analysis.FieldReferenceTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.Token; +import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.EntryPair; import cuchaz.enigma.mapping.FieldEntry; @@ -44,7 +45,7 @@ public class GuiController private SourceIndex m_index; private ClassEntry m_currentClass; private boolean m_isDirty; - private Stack m_entryStack; + private Stack m_locationStack; // TODO: make a location class, can be either Entry or EntryReference public GuiController( Gui gui ) { @@ -53,7 +54,7 @@ public class GuiController m_index = null; m_currentClass = null; m_isDirty = false; - m_entryStack = new Stack(); + m_locationStack = new Stack(); } public boolean isDirty( ) @@ -157,9 +158,9 @@ public class GuiController return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); } - public FieldCallsTreeNode getFieldCalls( FieldEntry obfFieldEntry ) + public FieldReferenceTreeNode getFieldReferences( FieldEntry obfFieldEntry ) { - FieldCallsTreeNode rootNode = new FieldCallsTreeNode( + FieldReferenceTreeNode rootNode = new FieldReferenceTreeNode( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), obfFieldEntry ); @@ -167,27 +168,12 @@ public class GuiController return rootNode; } - public MethodCallsTreeNode getMethodCalls( Entry obfEntry ) + public BehaviorReferenceTreeNode getMethodReferences( BehaviorEntry obfEntry ) { - MethodCallsTreeNode rootNode; - if( obfEntry instanceof MethodEntry ) - { - rootNode = new MethodCallsTreeNode( - m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), - (MethodEntry)obfEntry - ); - } - else if( obfEntry instanceof ConstructorEntry ) - { - rootNode = new MethodCallsTreeNode( - m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), - (ConstructorEntry)obfEntry - ); - } - else - { - throw new IllegalArgumentException( "entry must be a MethodEntry or a ConstructorEntry!" ); - } + BehaviorReferenceTreeNode rootNode = new BehaviorReferenceTreeNode( + m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + obfEntry + ); rootNode.load( m_deobfuscator.getJarIndex(), true ); return rootNode; } @@ -200,7 +186,7 @@ public class GuiController refreshCurrentClass( obfEntry ); } - public void openEntry( Entry entry ) + public void openDeclaration( Entry entry ) { // go to the entry Entry obfEntry = m_deobfuscator.obfuscateEntry( entry ); @@ -214,25 +200,32 @@ public class GuiController m_gui.showToken( m_index.getDeclarationToken( m_deobfuscator.deobfuscateEntry( obfEntry ) ) ); } - if( m_entryStack.isEmpty() || !m_entryStack.peek().equals( obfEntry ) ) + if( m_locationStack.isEmpty() || !m_locationStack.peek().equals( obfEntry ) ) { // update the stack - m_entryStack.push( obfEntry ); + m_locationStack.push( obfEntry ); } } - public void openPreviousEntry( ) + public void openReference( EntryReference reference ) + { + // TODO: find out how to load the n-th reference in a caller + // TEMP: just go to the caller for now + openDeclaration( reference.caller ); + } + + public void openPreviousLocation( ) { - if( hasPreviousEntry() ) + if( hasPreviousLocation() ) { - m_entryStack.pop(); - openEntry( m_entryStack.peek() ); + m_locationStack.pop(); + openDeclaration( m_locationStack.peek() ); } } - public boolean hasPreviousEntry( ) + public boolean hasPreviousLocation( ) { - return m_entryStack.size() > 1; + return m_locationStack.size() > 1; } private void refreshClasses( ) diff --git a/src/cuchaz/enigma/mapping/BehaviorEntry.java b/src/cuchaz/enigma/mapping/BehaviorEntry.java new file mode 100644 index 00000000..99fdd28d --- /dev/null +++ b/src/cuchaz/enigma/mapping/BehaviorEntry.java @@ -0,0 +1,6 @@ +package cuchaz.enigma.mapping; + +public interface BehaviorEntry extends Entry +{ + public String getSignature(); +} diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java index e0fa7cf6..0f7dab68 100644 --- a/src/cuchaz/enigma/mapping/ConstructorEntry.java +++ b/src/cuchaz/enigma/mapping/ConstructorEntry.java @@ -14,7 +14,7 @@ import java.io.Serializable; import cuchaz.enigma.Util; -public class ConstructorEntry implements Entry, Serializable +public class ConstructorEntry implements BehaviorEntry, Serializable { private static final long serialVersionUID = -868346075317366758L; @@ -54,6 +54,7 @@ public class ConstructorEntry implements Entry, Serializable return m_classEntry.getName(); } + @Override public String getSignature( ) { return m_signature; diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index b4b9c9bf..a311e636 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -14,7 +14,7 @@ import java.io.Serializable; import cuchaz.enigma.Util; -public class MethodEntry implements Entry, Serializable +public class MethodEntry implements BehaviorEntry, Serializable { private static final long serialVersionUID = 4770915224467247458L; @@ -68,6 +68,7 @@ public class MethodEntry implements Entry, Serializable return m_name; } + @Override public String getSignature( ) { return m_signature; diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index fc41f945..a1230db3 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -172,6 +172,19 @@ public class Translator ); } + public BehaviorEntry translateEntry( BehaviorEntry in ) + { + if( in instanceof MethodEntry ) + { + return translateEntry( (MethodEntry)in ); + } + else if( in instanceof ConstructorEntry ) + { + return translateEntry( (ConstructorEntry)in ); + } + throw new Error( "Wrong entry type!" ); + } + public String translate( ArgumentEntry in ) { for( String className : getSelfAndAncestors( in.getClassName() ) ) -- cgit v1.2.3 From a85529d1ce6ec533809575ec84572de855464b36 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 20 Aug 2014 01:21:52 -0400 Subject: finished reference navigation system. Still need to debug and polish it, but the basic idea seems to work. =) --- src/cuchaz/enigma/Deobfuscator.java | 105 ++-- src/cuchaz/enigma/Main.java | 1 - .../enigma/analysis/BehaviorReferenceTreeNode.java | 12 +- src/cuchaz/enigma/analysis/EntryReference.java | 89 ++- .../enigma/analysis/FieldReferenceTreeNode.java | 14 +- src/cuchaz/enigma/analysis/JarIndex.java | 43 +- src/cuchaz/enigma/analysis/ReferenceTreeNode.java | 6 +- src/cuchaz/enigma/analysis/SourceIndex.java | 51 +- .../analysis/SourceIndexBehaviorVisitor.java | 142 +++++ .../enigma/analysis/SourceIndexClassVisitor.java | 114 ++++ src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 600 --------------------- src/cuchaz/enigma/analysis/Token.java | 6 + src/cuchaz/enigma/gui/Gui.java | 158 +++--- src/cuchaz/enigma/gui/GuiController.java | 106 ++-- src/cuchaz/enigma/mapping/Translator.java | 28 + 15 files changed, 633 insertions(+), 842 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java create mode 100644 src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java delete mode 100644 src/cuchaz/enigma/analysis/SourceIndexVisitor.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 293e1c2f..34e6033b 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -26,6 +26,7 @@ import com.strobel.decompiler.languages.java.ast.AstBuilder; import com.strobel.decompiler.languages.java.ast.CompilationUnit; import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; +import cuchaz.enigma.analysis.EntryReference; import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; @@ -169,98 +170,92 @@ public class Deobfuscator SourceIndex index = new SourceIndex( buf.toString() ); root.acceptVisitor( new SourceIndexVisitor(), index ); - return index; - } - - // NOTE: these methods are a bit messy... oh well - - public void rename( Entry obfEntry, String newName ) - { - if( obfEntry instanceof ClassEntry ) + /* DEBUG + for( Token token : index.referenceTokens() ) { - m_renamer.setClassName( (ClassEntry)obfEntry, newName ); - } - else if( obfEntry instanceof FieldEntry ) - { - m_renamer.setFieldName( (FieldEntry)obfEntry, newName ); - } - else if( obfEntry instanceof MethodEntry ) - { - m_renamer.setMethodTreeName( (MethodEntry)obfEntry, newName ); - } - else if( obfEntry instanceof ConstructorEntry ) - { - m_renamer.setClassName( obfEntry.getClassEntry(), newName ); - } - else if( obfEntry instanceof ArgumentEntry ) - { - m_renamer.setArgumentName( (ArgumentEntry)obfEntry, newName ); - } - else - { - throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); + EntryReference reference = index.getDeobfReference( token ); + System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); } + */ - // clear the type loader cache - m_typeLoader.clearCache(); + return index; } public Entry obfuscateEntry( Entry deobfEntry ) { - Translator translator = getTranslator( TranslationDirection.Obfuscating ); - if( deobfEntry instanceof ClassEntry ) - { - return translator.translateEntry( (ClassEntry)deobfEntry ); - } - else if( deobfEntry instanceof FieldEntry ) - { - return translator.translateEntry( (FieldEntry)deobfEntry ); - } - else if( deobfEntry instanceof MethodEntry ) + if( deobfEntry == null ) { - return translator.translateEntry( (MethodEntry)deobfEntry ); + return null; } - else if( deobfEntry instanceof ConstructorEntry ) + return getTranslator( TranslationDirection.Obfuscating ).translateEntry( deobfEntry ); + } + + public Entry deobfuscateEntry( Entry obfEntry ) + { + if( obfEntry == null ) { - return translator.translateEntry( (ConstructorEntry)deobfEntry ); + return null; } - else if( deobfEntry instanceof ArgumentEntry ) + return getTranslator( TranslationDirection.Deobfuscating ).translateEntry( obfEntry ); + } + + public EntryReference obfuscateReference( EntryReference deobfReference ) + { + if( deobfReference == null ) { - return translator.translateEntry( (ArgumentEntry)deobfEntry ); + return null; } - else + return new EntryReference( + obfuscateEntry( deobfReference.entry ), + obfuscateEntry( deobfReference.context ), + deobfReference.pos + ); + } + + public EntryReference deobfuscateReference( EntryReference obfReference ) + { + if( obfReference == null ) { - throw new Error( "Unknown entry type: " + deobfEntry.getClass().getName() ); + return null; } + return new EntryReference( + deobfuscateEntry( obfReference.entry ), + deobfuscateEntry( obfReference.context ), + obfReference.pos + ); } - public Entry deobfuscateEntry( Entry obfEntry ) + // NOTE: these methods are a bit messy... oh well + + public void rename( Entry obfEntry, String newName ) { - Translator translator = getTranslator( TranslationDirection.Deobfuscating ); if( obfEntry instanceof ClassEntry ) { - return translator.translateEntry( (ClassEntry)obfEntry ); + m_renamer.setClassName( (ClassEntry)obfEntry, newName ); } else if( obfEntry instanceof FieldEntry ) { - return translator.translateEntry( (FieldEntry)obfEntry ); + m_renamer.setFieldName( (FieldEntry)obfEntry, newName ); } else if( obfEntry instanceof MethodEntry ) { - return translator.translateEntry( (MethodEntry)obfEntry ); + m_renamer.setMethodTreeName( (MethodEntry)obfEntry, newName ); } else if( obfEntry instanceof ConstructorEntry ) { - return translator.translateEntry( (ConstructorEntry)obfEntry ); + m_renamer.setClassName( obfEntry.getClassEntry(), newName ); } else if( obfEntry instanceof ArgumentEntry ) { - return translator.translateEntry( (ArgumentEntry)obfEntry ); + m_renamer.setArgumentName( (ArgumentEntry)obfEntry, newName ); } else { throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); } + + // clear the type loader cache + m_typeLoader.clearCache(); } public boolean hasMapping( Entry obfEntry ) diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index 20d73c29..7d38bd62 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -13,7 +13,6 @@ package cuchaz.enigma; import java.io.File; import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.mapping.ClassEntry; public class Main { diff --git a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java index 158aad71..0f7e7f71 100644 --- a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java @@ -21,13 +21,13 @@ import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.Translator; -public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode +public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode { private static final long serialVersionUID = -3658163700783307520L; private Translator m_deobfuscatingTranslator; private BehaviorEntry m_entry; - private EntryReference m_reference; + private EntryReference m_reference; public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, BehaviorEntry entry ) { @@ -36,7 +36,7 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements m_reference = null; } - public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) + public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) { m_deobfuscatingTranslator = deobfuscatingTranslator; m_entry = reference.entry; @@ -50,7 +50,7 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements } @Override - public EntryReference getReference( ) + public EntryReference getReference( ) { return m_reference; } @@ -60,7 +60,7 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements { if( m_reference != null ) { - return m_deobfuscatingTranslator.translateEntry( m_reference.caller ).toString(); + return m_deobfuscatingTranslator.translateEntry( m_reference.context ).toString(); } return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); } @@ -68,7 +68,7 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements public void load( JarIndex index, boolean recurse ) { // get all the child nodes - for( EntryReference reference : index.getBehaviorReferences( m_entry ) ) + for( EntryReference reference : index.getBehaviorReferences( m_entry ) ) { add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); } diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java index f462210a..869e08c1 100644 --- a/src/cuchaz/enigma/analysis/EntryReference.java +++ b/src/cuchaz/enigma/analysis/EntryReference.java @@ -10,19 +10,96 @@ ******************************************************************************/ package cuchaz.enigma.analysis; -import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.Util; +import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.Entry; -public class EntryReference +public class EntryReference { - public T entry; - public BehaviorEntry caller; + public E entry; + public C context; public int pos; - public EntryReference( T entry, BehaviorEntry caller, int pos ) + public EntryReference( E entry ) { + this( entry, null, -1 ); + } + + public EntryReference( E entry, C context, int pos ) + { + if( entry == null ) + { + throw new IllegalArgumentException( "Entry cannot be null!" ); + } + this.entry = entry; - this.caller = caller; + this.context = context; this.pos = pos; } + + public ClassEntry getClassEntry( ) + { + if( context != null ) + { + return context.getClassEntry(); + } + return entry.getClassEntry(); + } + + @Override + public int hashCode( ) + { + if( context != null ) + { + return Util.combineHashesOrdered( entry.hashCode(), context.hashCode(), Integer.valueOf( pos ).hashCode() ); + } + return entry.hashCode(); + } + + @Override + public boolean equals( Object other ) + { + if( other instanceof EntryReference ) + { + return equals( (EntryReference)other ); + } + return false; + } + + public boolean equals( EntryReference other ) + { + // check entry first + boolean isEntrySame = entry.equals( other.entry ); + if( !isEntrySame ) + { + return false; + } + + // check caller + if( context == null && other.context == null ) + { + return true; + } + else if( context != null && other.context != null ) + { + return context.equals( other.context ) && pos == other.pos; + } + return false; + } + + @Override + public String toString( ) + { + StringBuilder buf = new StringBuilder(); + buf.append( entry ); + if( context != null ) + { + buf.append( " called from " ); + buf.append( context ); + buf.append( " (" ); + buf.append( pos ); + buf.append( ")" ); + } + return buf.toString(); + } } diff --git a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java index dd552d68..645e6821 100644 --- a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java @@ -16,13 +16,13 @@ import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.Translator; -public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode +public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode { private static final long serialVersionUID = -7934108091928699835L; private Translator m_deobfuscatingTranslator; private FieldEntry m_entry; - private EntryReference m_reference; + private EntryReference m_reference; public FieldReferenceTreeNode( Translator deobfuscatingTranslator, FieldEntry entry ) { @@ -31,7 +31,7 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re m_reference = null; } - private FieldReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) + private FieldReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) { m_deobfuscatingTranslator = deobfuscatingTranslator; m_entry = reference.entry; @@ -45,7 +45,7 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re } @Override - public EntryReference getReference( ) + public EntryReference getReference( ) { return m_reference; } @@ -55,7 +55,7 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re { if( m_reference != null ) { - return m_deobfuscatingTranslator.translateEntry( m_reference.caller ).toString(); + return m_deobfuscatingTranslator.translateEntry( m_reference.context ).toString(); } return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); } @@ -65,14 +65,14 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re // get all the child nodes if( m_reference == null ) { - for( EntryReference reference : index.getFieldReferences( m_entry ) ) + for( EntryReference reference : index.getFieldReferences( m_entry ) ) { add( new FieldReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); } } else { - for( EntryReference reference : index.getBehaviorReferences( m_reference.caller ) ) + for( EntryReference reference : index.getBehaviorReferences( m_reference.context ) ) { add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); } diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index f1c29c5b..f408d930 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -56,8 +56,8 @@ public class JarIndex private Set m_obfClassNames; private Ancestries m_ancestries; private Multimap m_methodImplementations; - private Multimap> m_behaviorReferences; - private Multimap> m_fieldReferences; + private Multimap> m_behaviorReferences; + private Multimap> m_fieldReferences; private Multimap m_innerClasses; private Map m_outerClasses; private Set m_anonymousClasses; @@ -108,12 +108,12 @@ public class JarIndex m_anonymousClasses.add( innerClassName ); // DEBUG - System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); + //System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); } else { // DEBUG - System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); + //System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); } } } @@ -172,7 +172,7 @@ public class JarIndex call.getSignature() ); callNumbers.add( calledMethodEntry ); - EntryReference reference = new EntryReference( + EntryReference reference = new EntryReference( calledMethodEntry, thisEntry, callNumbers.count( calledMethodEntry ) - 1 @@ -189,7 +189,7 @@ public class JarIndex call.getFieldName() ); callNumbers.add( calledFieldEntry ); - EntryReference reference = new EntryReference( + EntryReference reference = new EntryReference( calledFieldEntry, thisEntry, callNumbers.count( calledFieldEntry ) - 1 @@ -209,7 +209,7 @@ public class JarIndex call.getSignature() ); callNumbers.add( calledConstructorEntry ); - EntryReference reference = new EntryReference( + EntryReference reference = new EntryReference( calledConstructorEntry, thisEntry, callNumbers.count( calledConstructorEntry ) - 1 @@ -226,7 +226,7 @@ public class JarIndex call.getSignature() ); callNumbers.add( calledConstructorEntry ); - EntryReference reference = new EntryReference( + EntryReference reference = new EntryReference( calledConstructorEntry, thisEntry, callNumbers.count( calledConstructorEntry ) - 1 @@ -261,9 +261,9 @@ public class JarIndex new ClassEntry( Descriptor.toJvmName( c.getName() ) ), constructor.getMethodInfo().getDescriptor() ); - for( EntryReference reference : getBehaviorReferences( constructorEntry ) ) + for( EntryReference reference : getBehaviorReferences( constructorEntry ) ) { - callerClasses.add( reference.caller.getClassEntry() ); + callerClasses.add( reference.context.getClassEntry() ); } // is this called by exactly one class? @@ -496,26 +496,14 @@ public class JarIndex return rootNode; } - @SuppressWarnings( "unchecked" ) - public Collection> getFieldReferences( FieldEntry fieldEntry ) + public Collection> getFieldReferences( FieldEntry fieldEntry ) { - List> references = Lists.newArrayList(); - for( EntryReference reference : m_fieldReferences.get( fieldEntry ) ) - { - references.add( (EntryReference)reference ); - } - return references; + return m_fieldReferences.get( fieldEntry ); } - @SuppressWarnings( "unchecked" ) - public Collection> getBehaviorReferences( BehaviorEntry behaviorEntry ) + public Collection> getBehaviorReferences( BehaviorEntry behaviorEntry ) { - List> references = Lists.newArrayList(); - for( EntryReference reference : m_behaviorReferences.get( behaviorEntry ) ) - { - references.add( (EntryReference)reference ); - } - return references; + return m_behaviorReferences.get( behaviorEntry ); } public Collection getInnerClasses( String obfOuterClassName ) @@ -613,8 +601,9 @@ public class JarIndex } else if( thing instanceof EntryReference ) { - EntryReference reference = (EntryReference)thing; + EntryReference reference = (EntryReference)thing; reference.entry = renameThing( renames, reference.entry ); + reference.context = renameThing( renames, reference.context ); return thing; } else diff --git a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java index 08ae39d9..e0a0a747 100644 --- a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java @@ -12,8 +12,8 @@ package cuchaz.enigma.analysis; import cuchaz.enigma.mapping.Entry; -public interface ReferenceTreeNode +public interface ReferenceTreeNode { - T getEntry(); - EntryReference getReference(); + E getEntry(); + EntryReference getReference(); } diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 645a71da..bf890e30 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -10,6 +10,7 @@ ******************************************************************************/ package cuchaz.enigma.analysis; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -24,15 +25,17 @@ import cuchaz.enigma.mapping.Entry; public class SourceIndex { private String m_source; - private TreeMap m_tokens; - private Map m_declarations; + private TreeMap> m_tokenToReference; + private HashMap,Token> m_referenceToToken; + private Map m_declarationToToken; private List m_lineOffsets; public SourceIndex( String source ) { m_source = source; - m_tokens = Maps.newTreeMap(); - m_declarations = Maps.newHashMap(); + m_tokenToReference = Maps.newTreeMap(); + m_referenceToToken = Maps.newHashMap(); + m_declarationToToken = Maps.newHashMap(); m_lineOffsets = Lists.newArrayList(); // count the lines @@ -87,12 +90,13 @@ public class SourceIndex return token; } - public void add( Identifier node, Entry deobfEntry ) + public void addReference( Identifier node, EntryReference deobfReference ) { Token token = getToken( node ); if( token != null ) { - m_tokens.put( token, deobfEntry ); + m_tokenToReference.put( token, deobfReference ); + m_referenceToToken.put( deobfReference, token ); } } @@ -101,19 +105,16 @@ public class SourceIndex Token token = getToken( node ); if( token != null ) { - m_tokens.put( token, deobfEntry ); - m_declarations.put( deobfEntry, token ); + EntryReference reference = new EntryReference( deobfEntry ); + m_tokenToReference.put( token, reference ); + m_referenceToToken.put( reference, token ); + m_declarationToToken.put( deobfEntry, token ); } } - public Token getToken( int pos ) + public Token getReferenceToken( int pos ) { - Map.Entry mapEntry = m_tokens.floorEntry( new Token( pos, pos ) ); - if( mapEntry == null ) - { - return null; - } - Token token = mapEntry.getKey(); + Token token = m_tokenToReference.floorKey( new Token( pos, pos ) ); if( token.contains( pos ) ) { return token; @@ -121,23 +122,33 @@ public class SourceIndex return null; } - public Entry getEntry( Token token ) + public Token getReferenceToken( EntryReference deobfReference ) + { + return m_referenceToToken.get( deobfReference ); + } + + public EntryReference getDeobfReference( Token token ) { if( token == null ) { return null; } - return m_tokens.get( token ); + return m_tokenToReference.get( token ); + } + + public Iterable referenceTokens( ) + { + return m_tokenToReference.keySet(); } - public Iterable tokens( ) + public Iterable declarationTokens( ) { - return m_tokens.keySet(); + return m_declarationToToken.values(); } public Token getDeclarationToken( Entry deobfEntry ) { - return m_declarations.get( deobfEntry ); + return m_declarationToToken.get( deobfEntry ); } private int toPos( int line, int col ) diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java new file mode 100644 index 00000000..d3386c51 --- /dev/null +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * 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.analysis; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.strobel.assembler.metadata.MemberReference; +import com.strobel.assembler.metadata.MethodDefinition; +import com.strobel.assembler.metadata.ParameterDefinition; +import com.strobel.assembler.metadata.TypeReference; +import com.strobel.decompiler.languages.TextLocation; +import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; +import com.strobel.decompiler.languages.java.ast.IdentifierExpression; +import com.strobel.decompiler.languages.java.ast.InvocationExpression; +import com.strobel.decompiler.languages.java.ast.Keys; +import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; +import com.strobel.decompiler.languages.java.ast.MethodDeclaration; +import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; +import com.strobel.decompiler.languages.java.ast.SimpleType; + +import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; + +public class SourceIndexBehaviorVisitor extends SourceIndexVisitor +{ + private BehaviorEntry m_behaviorEntry; + private Multiset m_indices; + + public SourceIndexBehaviorVisitor( BehaviorEntry behaviorEntry ) + { + m_behaviorEntry = behaviorEntry; + m_indices = HashMultiset.create(); + } + + @Override + public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) + { + MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + MethodEntry methodEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); + if( node.getTarget() instanceof MemberReferenceExpression ) + { + m_indices.add( methodEntry ); + index.addReference( + ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(), + new EntryReference( methodEntry, m_behaviorEntry, m_indices.count( methodEntry ) ) + ); + } + + return recurse( node, index ); + } + + @Override + public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index ) + { + MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + if( ref != null ) + { + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); + m_indices.add( fieldEntry ); + index.addReference( + node.getMemberNameToken(), + new EntryReference( fieldEntry, m_behaviorEntry, m_indices.count( fieldEntry ) ) + ); + } + + return recurse( node, index ); + } + + @Override + public Void visitSimpleType( SimpleType node, SourceIndex index ) + { + TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); + if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) + { + ClassEntry classEntry = new ClassEntry( ref.getInternalName() ); + m_indices.add( classEntry ); + index.addReference( + node.getIdentifierToken(), + new EntryReference( classEntry, m_behaviorEntry, m_indices.count( classEntry ) ) + ); + } + + return recurse( node, index ); + } + + @Override + public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) + { + ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + MethodDefinition methodDef = (MethodDefinition)def.getMethod(); + MethodEntry methodEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); + ArgumentEntry argumentEntry = new ArgumentEntry( methodEntry, def.getPosition(), def.getName() ); + index.addDeclaration( node.getNameToken(), argumentEntry ); + + return recurse( node, index ); + } + + @Override + public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) + { + MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + if( ref != null ) + { + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); + m_indices.add( fieldEntry ); + index.addReference( + node.getIdentifierToken(), + new EntryReference( fieldEntry, m_behaviorEntry, m_indices.count( fieldEntry ) ) + ); + } + + return recurse( node, index ); + } +} diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java new file mode 100644 index 00000000..2d4c0f57 --- /dev/null +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * 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.analysis; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.strobel.assembler.metadata.FieldDefinition; +import com.strobel.assembler.metadata.MethodDefinition; +import com.strobel.assembler.metadata.TypeReference; +import com.strobel.decompiler.languages.TextLocation; +import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; +import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; +import com.strobel.decompiler.languages.java.ast.FieldDeclaration; +import com.strobel.decompiler.languages.java.ast.Keys; +import com.strobel.decompiler.languages.java.ast.MethodDeclaration; +import com.strobel.decompiler.languages.java.ast.SimpleType; +import com.strobel.decompiler.languages.java.ast.TypeDeclaration; +import com.strobel.decompiler.languages.java.ast.VariableInitializer; + +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; + +public class SourceIndexClassVisitor extends SourceIndexVisitor +{ + private ClassEntry m_classEntry; + private Multiset m_indices; + + public SourceIndexClassVisitor( ClassEntry classEntry ) + { + m_classEntry = classEntry; + m_indices = HashMultiset.create(); + } + + @Override + public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitSimpleType( SimpleType node, SourceIndex index ) + { + TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); + if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) + { + ClassEntry classEntry = new ClassEntry( ref.getInternalName() ); + index.addReference( + node.getIdentifierToken(), + new EntryReference( classEntry, m_classEntry, m_indices.count( classEntry ) ) + ); + } + + return recurse( node, index ); + } + + @Override + public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) + { + MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + MethodEntry methodEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() ); + index.addDeclaration( node.getNameToken(), methodEntry ); + //if( !def.getName().equals( "" ) ) + + return node.acceptVisitor( new SourceIndexBehaviorVisitor( methodEntry ), index ); + } + + @Override + public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) + { + MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, def.getSignature() ); + index.addDeclaration( node.getNameToken(), constructorEntry ); + + return recurse( node, index ); + } + + @Override + public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) + { + FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); + assert( node.getVariables().size() == 1 ); + VariableInitializer variable = node.getVariables().firstOrNullObject(); + index.addDeclaration( variable.getNameToken(), fieldEntry ); + + return recurse( node, index ); + } + + @Override + public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) + { + // treat enum declarations as field declarations + FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); + index.addDeclaration( node.getNameToken(), fieldEntry ); + + return recurse( node, index ); + } +} diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java deleted file mode 100644 index 841d1767..00000000 --- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ /dev/null @@ -1,600 +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.analysis; - -import com.strobel.assembler.metadata.FieldDefinition; -import com.strobel.assembler.metadata.MemberReference; -import com.strobel.assembler.metadata.MethodDefinition; -import com.strobel.assembler.metadata.ParameterDefinition; -import com.strobel.assembler.metadata.TypeDefinition; -import com.strobel.assembler.metadata.TypeReference; -import com.strobel.decompiler.languages.TextLocation; -import com.strobel.decompiler.languages.java.ast.Annotation; -import com.strobel.decompiler.languages.java.ast.AnonymousObjectCreationExpression; -import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression; -import com.strobel.decompiler.languages.java.ast.ArrayInitializerExpression; -import com.strobel.decompiler.languages.java.ast.ArraySpecifier; -import com.strobel.decompiler.languages.java.ast.AssertStatement; -import com.strobel.decompiler.languages.java.ast.AssignmentExpression; -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.BinaryOperatorExpression; -import com.strobel.decompiler.languages.java.ast.BlockStatement; -import com.strobel.decompiler.languages.java.ast.BreakStatement; -import com.strobel.decompiler.languages.java.ast.CaseLabel; -import com.strobel.decompiler.languages.java.ast.CastExpression; -import com.strobel.decompiler.languages.java.ast.CatchClause; -import com.strobel.decompiler.languages.java.ast.ClassOfExpression; -import com.strobel.decompiler.languages.java.ast.Comment; -import com.strobel.decompiler.languages.java.ast.CompilationUnit; -import com.strobel.decompiler.languages.java.ast.ComposedType; -import com.strobel.decompiler.languages.java.ast.ConditionalExpression; -import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; -import com.strobel.decompiler.languages.java.ast.ContinueStatement; -import com.strobel.decompiler.languages.java.ast.DoWhileStatement; -import com.strobel.decompiler.languages.java.ast.EmptyStatement; -import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; -import com.strobel.decompiler.languages.java.ast.ExpressionStatement; -import com.strobel.decompiler.languages.java.ast.FieldDeclaration; -import com.strobel.decompiler.languages.java.ast.ForEachStatement; -import com.strobel.decompiler.languages.java.ast.ForStatement; -import com.strobel.decompiler.languages.java.ast.GotoStatement; -import com.strobel.decompiler.languages.java.ast.IAstVisitor; -import com.strobel.decompiler.languages.java.ast.Identifier; -import com.strobel.decompiler.languages.java.ast.IdentifierExpression; -import com.strobel.decompiler.languages.java.ast.IfElseStatement; -import com.strobel.decompiler.languages.java.ast.ImportDeclaration; -import com.strobel.decompiler.languages.java.ast.IndexerExpression; -import com.strobel.decompiler.languages.java.ast.InstanceInitializer; -import com.strobel.decompiler.languages.java.ast.InstanceOfExpression; -import com.strobel.decompiler.languages.java.ast.InvocationExpression; -import com.strobel.decompiler.languages.java.ast.JavaTokenNode; -import com.strobel.decompiler.languages.java.ast.Keys; -import com.strobel.decompiler.languages.java.ast.LabelStatement; -import com.strobel.decompiler.languages.java.ast.LabeledStatement; -import com.strobel.decompiler.languages.java.ast.LambdaExpression; -import com.strobel.decompiler.languages.java.ast.LocalTypeDeclarationStatement; -import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; -import com.strobel.decompiler.languages.java.ast.MethodDeclaration; -import com.strobel.decompiler.languages.java.ast.MethodGroupExpression; -import com.strobel.decompiler.languages.java.ast.NewLineNode; -import com.strobel.decompiler.languages.java.ast.NullReferenceExpression; -import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; -import com.strobel.decompiler.languages.java.ast.PackageDeclaration; -import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; -import com.strobel.decompiler.languages.java.ast.ParenthesizedExpression; -import com.strobel.decompiler.languages.java.ast.PrimitiveExpression; -import com.strobel.decompiler.languages.java.ast.ReturnStatement; -import com.strobel.decompiler.languages.java.ast.SimpleType; -import com.strobel.decompiler.languages.java.ast.SuperReferenceExpression; -import com.strobel.decompiler.languages.java.ast.SwitchSection; -import com.strobel.decompiler.languages.java.ast.SwitchStatement; -import com.strobel.decompiler.languages.java.ast.SynchronizedStatement; -import com.strobel.decompiler.languages.java.ast.TextNode; -import com.strobel.decompiler.languages.java.ast.ThisReferenceExpression; -import com.strobel.decompiler.languages.java.ast.ThrowStatement; -import com.strobel.decompiler.languages.java.ast.TryCatchStatement; -import com.strobel.decompiler.languages.java.ast.TypeDeclaration; -import com.strobel.decompiler.languages.java.ast.TypeParameterDeclaration; -import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression; -import com.strobel.decompiler.languages.java.ast.UnaryOperatorExpression; -import com.strobel.decompiler.languages.java.ast.VariableDeclarationStatement; -import com.strobel.decompiler.languages.java.ast.VariableInitializer; -import com.strobel.decompiler.languages.java.ast.WhileStatement; -import com.strobel.decompiler.languages.java.ast.WildcardType; -import com.strobel.decompiler.patterns.Pattern; - -import cuchaz.enigma.mapping.ArgumentEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.MethodEntry; - -public class SourceIndexVisitor implements IAstVisitor -{ - @Override - public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) - { - MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); - ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); - MethodEntry methodEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); - if( node.getTarget() instanceof MemberReferenceExpression ) - { - index.add( ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(), methodEntry ); - } - - return recurse( node, index ); - } - - @Override - public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index ) - { - MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); - if( ref != null ) - { - ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); - FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); - index.add( node.getMemberNameToken(), fieldEntry ); - } - - return recurse( node, index ); - } - - @Override - public Void visitSimpleType( SimpleType node, SourceIndex index ) - { - TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); - if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) - { - index.add( node.getIdentifierToken(), new ClassEntry( ref.getInternalName() ) ); - } - - return recurse( node, index ); - } - - @Override - public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) - { - MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); - - // static initializers don't have identifier tokens - if( !def.getName().equals( "" ) ) - { - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - MethodEntry methodEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() ); - index.addDeclaration( node.getNameToken(), methodEntry ); - } - - return recurse( node, index ); - } - - @Override - public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) - { - MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, def.getSignature() ); - index.addDeclaration( node.getNameToken(), constructorEntry ); - - return recurse( node, index ); - } - - @Override - public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) - { - ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - MethodDefinition methodDef = (MethodDefinition)def.getMethod(); - MethodEntry methodEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); - ArgumentEntry argumentEntry = new ArgumentEntry( methodEntry, def.getPosition(), def.getName() ); - index.addDeclaration( node.getNameToken(), argumentEntry ); - - return recurse( node, index ); - } - - @Override - public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) - { - FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); - assert( node.getVariables().size() == 1 ); - VariableInitializer variable = node.getVariables().firstOrNullObject(); - index.addDeclaration( variable.getNameToken(), fieldEntry ); - - return recurse( node, index ); - } - - @Override - public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) - { - TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); - index.addDeclaration( node.getNameToken(), new ClassEntry( def.getInternalName() ) ); - - return recurse( node, index ); - } - - @Override - public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) - { - // treat enum declarations as field declarations - FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); - index.addDeclaration( node.getNameToken(), fieldEntry ); - - return recurse( node, index ); - } - - @Override - public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) - { - MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); - if( ref != null ) - { - ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); - FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); - index.add( node.getIdentifierToken(), fieldEntry ); - } - - return recurse( node, index ); - } - - private Void recurse( AstNode node, SourceIndex index ) - { - for( final AstNode child : node.getChildren() ) - { - child.acceptVisitor( this, index ); - } - return null; - } - - // OVERRIDES WE DON'T CARE ABOUT - - @Override - public Void visitComment( Comment node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitPatternPlaceholder( AstNode node, Pattern pattern, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitTypeReference( TypeReferenceExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitJavaTokenNode( JavaTokenNode node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitIdentifier( Identifier node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitNullReferenceExpression( NullReferenceExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitThisReferenceExpression( ThisReferenceExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitSuperReferenceExpression( SuperReferenceExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitClassOfExpression( ClassOfExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitBlockStatement( BlockStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitExpressionStatement( ExpressionStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitBreakStatement( BreakStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitContinueStatement( ContinueStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitDoWhileStatement( DoWhileStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitEmptyStatement( EmptyStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitIfElseStatement( IfElseStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitLabelStatement( LabelStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitLabeledStatement( LabeledStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitReturnStatement( ReturnStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitSwitchStatement( SwitchStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitSwitchSection( SwitchSection node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitCaseLabel( CaseLabel node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitThrowStatement( ThrowStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitCatchClause( CatchClause node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitAnnotation( Annotation node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitNewLine( NewLineNode node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitVariableDeclaration( VariableDeclarationStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitVariableInitializer( VariableInitializer node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitText( TextNode node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitImportDeclaration( ImportDeclaration node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitInitializerBlock( InstanceInitializer node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitCompilationUnit( CompilationUnit node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitPackageDeclaration( PackageDeclaration node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitArraySpecifier( ArraySpecifier node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitComposedType( ComposedType node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitWhileStatement( WhileStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitPrimitiveExpression( PrimitiveExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitCastExpression( CastExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitBinaryOperatorExpression( BinaryOperatorExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitInstanceOfExpression( InstanceOfExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitIndexerExpression( IndexerExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitConditionalExpression( ConditionalExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitArrayInitializerExpression( ArrayInitializerExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitObjectCreationExpression( ObjectCreationExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitArrayCreationExpression( ArrayCreationExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitAssignmentExpression( AssignmentExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitForStatement( ForStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitForEachStatement( ForEachStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitTryCatchStatement( TryCatchStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitGotoStatement( GotoStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitParenthesizedExpression( ParenthesizedExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitSynchronizedStatement( SynchronizedStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitAnonymousObjectCreationExpression( AnonymousObjectCreationExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitWildcardType( WildcardType node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitMethodGroupExpression( MethodGroupExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitAssertStatement( AssertStatement node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitLambdaExpression( LambdaExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - - @Override - public Void visitLocalTypeDeclarationStatement( LocalTypeDeclarationStatement node, SourceIndex index ) - { - return recurse( node, index ); - } -} diff --git a/src/cuchaz/enigma/analysis/Token.java b/src/cuchaz/enigma/analysis/Token.java index 74023e32..d0f2b70b 100644 --- a/src/cuchaz/enigma/analysis/Token.java +++ b/src/cuchaz/enigma/analysis/Token.java @@ -46,4 +46,10 @@ public class Token implements Comparable { return start == other.start && end == other.end; } + + @Override + public String toString( ) + { + return String.format( "[%d,%d]", start, end ); + } } diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 43a0cdad..341c1493 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -68,6 +68,7 @@ import com.google.common.collect.Lists; import cuchaz.enigma.Constants; import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; import cuchaz.enigma.analysis.ClassInheritanceTreeNode; +import cuchaz.enigma.analysis.EntryReference; import cuchaz.enigma.analysis.FieldReferenceTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.ReferenceTreeNode; @@ -76,7 +77,6 @@ import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.EntryPair; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.IllegalNameException; import cuchaz.enigma.mapping.MappingParseException; @@ -160,7 +160,7 @@ public class Gui private JMenuItem m_showCallsMenu; // state - private EntryPair m_selectedEntryPair; + private EntryReference m_reference; private JFileChooser m_jarFileChooser; private JFileChooser m_mappingsFileChooser; @@ -192,6 +192,10 @@ public class Gui String selected = m_obfClasses.getSelectedValue(); if( selected != null ) { + if( m_reference != null ) + { + m_controller.savePreviousReference( m_reference ); + } m_controller.openDeclaration( new ClassEntry( selected ) ); } } @@ -218,6 +222,10 @@ public class Gui String selected = m_deobfClasses.getSelectedValue(); if( selected != null ) { + if( m_reference != null ) + { + m_controller.savePreviousReference( m_reference ); + } m_controller.openDeclaration( new ClassEntry( selected ) ); } } @@ -234,7 +242,7 @@ public class Gui m_infoPanel.setLayout( new GridLayout( 4, 1, 0, 0 ) ); m_infoPanel.setPreferredSize( new Dimension( 0, 100 ) ); m_infoPanel.setBorder( BorderFactory.createTitledBorder( "Identifier Info" ) ); - clearEntryPair(); + clearReference(); // init editor DefaultSyntaxKit.initKit(); @@ -273,7 +281,7 @@ public class Gui break; case KeyEvent.VK_P: - m_controller.openPreviousLocation(); + m_controller.openPreviousReference(); break; case KeyEvent.VK_C: @@ -357,7 +365,7 @@ public class Gui @Override public void actionPerformed( ActionEvent event ) { - m_controller.openPreviousLocation(); + m_controller.openPreviousReference(); } } ); menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_P, 0 ) ); @@ -386,6 +394,10 @@ public class Gui Object node = path.getLastPathComponent(); if( node instanceof ClassInheritanceTreeNode ) { + if( m_reference != null ) + { + m_controller.savePreviousReference( m_reference ); + } m_controller.openDeclaration( new ClassEntry( ((ClassInheritanceTreeNode)node).getObfClassName() ) ); } else if( node instanceof MethodInheritanceTreeNode ) @@ -393,6 +405,10 @@ public class Gui MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode)node; if( methodNode.isImplemented() ) { + if( m_reference != null ) + { + m_controller.savePreviousReference( m_reference ); + } m_controller.openDeclaration( methodNode.getMethodEntry() ); } } @@ -424,7 +440,11 @@ public class Gui Object node = path.getLastPathComponent(); if( node instanceof ReferenceTreeNode ) { - ReferenceTreeNode referenceNode = ((ReferenceTreeNode)node); + if( m_reference != null ) + { + m_controller.savePreviousReference( m_reference ); + } + ReferenceTreeNode referenceNode = ((ReferenceTreeNode)node); if( referenceNode.getReference() != null ) { m_controller.openReference( referenceNode.getReference() ); @@ -715,6 +735,10 @@ public class Gui public void showToken( Token token ) { + if( token == null ) + { + throw new IllegalArgumentException( "Token cannot be null!" ); + } m_editor.setCaretPosition( token.start ); m_editor.grabFocus(); } @@ -752,7 +776,7 @@ public class Gui } } - private void clearEntryPair( ) + private void clearReference( ) { m_infoPanel.removeAll(); JLabel label = new JLabel( "No identifier selected" ); @@ -763,76 +787,75 @@ public class Gui redraw(); } - @SuppressWarnings( "unchecked" ) - private void showEntryPair( EntryPair pair ) + private void showReference( EntryReference reference ) { - if( pair == null ) + if( reference == null ) { - clearEntryPair(); + clearReference(); return; } - m_selectedEntryPair = pair; + m_reference = reference; m_infoPanel.removeAll(); - if( pair.deobf instanceof ClassEntry ) + if( reference.entry instanceof ClassEntry ) { - showClassEntryPair( (EntryPair)pair ); + showClassEntry( (ClassEntry)m_reference.entry ); } - else if( pair.deobf instanceof FieldEntry ) + else if( m_reference.entry instanceof FieldEntry ) { - showFieldEntryPair( (EntryPair)pair ); + showFieldEntry( (FieldEntry)m_reference.entry ); } - else if( pair.deobf instanceof MethodEntry ) + else if( m_reference.entry instanceof MethodEntry ) { - showMethodEntryPair( (EntryPair)pair ); + showMethodEntry( (MethodEntry)m_reference.entry ); } - else if( pair.deobf instanceof ConstructorEntry ) + else if( m_reference.entry instanceof ConstructorEntry ) { - showConstructorEntryPair( (EntryPair)pair ); + showConstructorEntry( (ConstructorEntry)m_reference.entry ); } - else if( pair.deobf instanceof ArgumentEntry ) + else if( m_reference.entry instanceof ArgumentEntry ) { - showArgumentEntryPair( (EntryPair)pair ); + showArgumentEntry( (ArgumentEntry)m_reference.entry ); } else { - throw new Error( "Unknown entry type: " + pair.deobf.getClass().getName() ); + throw new Error( "Unknown entry type: " + m_reference.entry.getClass().getName() ); } redraw(); } - private void showClassEntryPair( EntryPair pair ) + private void showClassEntry( ClassEntry entry ) { - addNameValue( m_infoPanel, "Class", pair.deobf.getName() ); + addNameValue( m_infoPanel, "Class", entry.getName() ); } - private void showFieldEntryPair( EntryPair pair ) + private void showFieldEntry( FieldEntry entry ) { - addNameValue( m_infoPanel, "Field", pair.deobf.getName() ); - addNameValue( m_infoPanel, "Class", pair.deobf.getClassEntry().getName() ); + addNameValue( m_infoPanel, "Field", entry.getName() ); + addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); } - private void showMethodEntryPair( EntryPair pair ) + private void showMethodEntry( MethodEntry entry ) { - addNameValue( m_infoPanel, "Method", pair.deobf.getName() ); - addNameValue( m_infoPanel, "Class", pair.deobf.getClassEntry().getName() ); - addNameValue( m_infoPanel, "Signature", pair.deobf.getSignature() ); + addNameValue( m_infoPanel, "Method", entry.getName() ); + addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); + addNameValue( m_infoPanel, "Signature", entry.getSignature() ); } - private void showConstructorEntryPair( EntryPair pair ) + private void showConstructorEntry( ConstructorEntry entry ) { - addNameValue( m_infoPanel, "Constructor", pair.deobf.getClassEntry().getName() ); - addNameValue( m_infoPanel, "Signature", pair.deobf.getSignature() ); + addNameValue( m_infoPanel, "Constructor", entry.getClassEntry().getName() ); + addNameValue( m_infoPanel, "Signature", entry.getSignature() ); } - private void showArgumentEntryPair( EntryPair pair ) + private void showArgumentEntry( ArgumentEntry entry ) { - addNameValue( m_infoPanel, "Argument", pair.deobf.getName() ); - addNameValue( m_infoPanel, "Class", pair.deobf.getClassEntry().getName() ); - addNameValue( m_infoPanel, "Method", pair.deobf.getMethodEntry().getName() ); - addNameValue( m_infoPanel, "Index", Integer.toString( pair.deobf.getIndex() ) ); + addNameValue( m_infoPanel, "Argument", entry.getName() ); + addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); + addNameValue( m_infoPanel, "Method", entry.getMethodEntry().getName() ); + addNameValue( m_infoPanel, "Index", Integer.toString( entry.getIndex() ) ); } private void addNameValue( JPanel container, String name, String value ) @@ -853,19 +876,19 @@ public class Gui Token token = m_controller.getToken( pos ); boolean isToken = token != null; - m_selectedEntryPair = m_controller.getEntryPair( token ); - boolean isClassEntry = isToken && m_selectedEntryPair.obf instanceof ClassEntry; - boolean isFieldEntry = isToken && m_selectedEntryPair.obf instanceof FieldEntry; - boolean isMethodEntry = isToken && m_selectedEntryPair.obf instanceof MethodEntry; - boolean isConstructorEntry = isToken && m_selectedEntryPair.obf instanceof ConstructorEntry; + m_reference = m_controller.getDeobfReference( token ); + boolean isClassEntry = isToken && m_reference.entry instanceof ClassEntry; + boolean isFieldEntry = isToken && m_reference.entry instanceof FieldEntry; + boolean isMethodEntry = isToken && m_reference.entry instanceof MethodEntry; + boolean isConstructorEntry = isToken && m_reference.entry instanceof ConstructorEntry; if( isToken ) { - showEntryPair( m_selectedEntryPair ); + showReference( m_reference ); } else { - clearEntryPair(); + clearReference(); } m_renameMenu.setEnabled( isToken ); @@ -878,11 +901,11 @@ public class Gui private void startRename( ) { // get the class name - String className = m_selectedEntryPair.deobf.getName(); - int pos = className.lastIndexOf( '$' ); - if( pos >= 0 ) + ClassEntry classEntry = m_reference.entry.getClassEntry(); + String className = classEntry.getName(); + if( classEntry.isInnerClass() ) { - className = className.substring( pos + 1 ); + className = classEntry.getInnerClassName(); } // init the text box @@ -924,7 +947,7 @@ public class Gui { try { - m_controller.rename( m_selectedEntryPair.obf, newName ); + m_controller.rename( m_reference, newName ); } catch( IllegalNameException ex ) { @@ -937,7 +960,7 @@ public class Gui // abort the rename JPanel panel = (JPanel)m_infoPanel.getComponent( 0 ); panel.remove( panel.getComponentCount() - 1 ); - panel.add( unboldLabel( new JLabel( m_selectedEntryPair.deobf.getName(), JLabel.LEFT ) ) ); + panel.add( unboldLabel( new JLabel( m_reference.entry.getName(), JLabel.LEFT ) ) ); m_editor.grabFocus(); @@ -946,15 +969,15 @@ public class Gui private void showInheritance( ) { - if( m_selectedEntryPair == null ) + if( m_reference == null ) { return; } - if( m_selectedEntryPair.obf instanceof ClassEntry ) + if( m_reference.entry instanceof ClassEntry ) { // get the class inheritance - ClassInheritanceTreeNode classNode = m_controller.getClassInheritance( (ClassEntry)m_selectedEntryPair.obf ); + ClassInheritanceTreeNode classNode = m_controller.getClassInheritance( (ClassEntry)m_reference.entry ); // show the tree at the root TreePath path = getPathToRoot( classNode ); @@ -962,10 +985,10 @@ public class Gui m_inheritanceTree.expandPath( path ); m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); } - else if( m_selectedEntryPair.obf instanceof MethodEntry ) + else if( m_reference.entry instanceof MethodEntry ) { // get the method inheritance - MethodInheritanceTreeNode classNode = m_controller.getMethodInheritance( (MethodEntry)m_selectedEntryPair.obf ); + MethodInheritanceTreeNode classNode = m_controller.getMethodInheritance( (MethodEntry)m_reference.entry ); // show the tree at the root TreePath path = getPathToRoot( classNode ); @@ -980,24 +1003,24 @@ public class Gui private void showCalls( ) { - if( m_selectedEntryPair == null ) + if( m_reference == null ) { return; } - if( m_selectedEntryPair.obf instanceof FieldEntry ) + if( m_reference.entry instanceof FieldEntry ) { - FieldReferenceTreeNode node = m_controller.getFieldReferences( (FieldEntry)m_selectedEntryPair.obf ); + FieldReferenceTreeNode node = m_controller.getFieldReferences( (FieldEntry)m_reference.entry ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } - else if( m_selectedEntryPair.obf instanceof MethodEntry ) + else if( m_reference.entry instanceof MethodEntry ) { - BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (MethodEntry)m_selectedEntryPair.obf ); + BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (MethodEntry)m_reference.entry ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } - else if( m_selectedEntryPair.obf instanceof ConstructorEntry ) + else if( m_reference.entry instanceof ConstructorEntry ) { - BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (ConstructorEntry)m_selectedEntryPair.obf ); + BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (ConstructorEntry)m_reference.entry ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } @@ -1021,11 +1044,12 @@ public class Gui private void openDeclaration( ) { - if( m_selectedEntryPair == null ) + if( m_reference == null ) { return; } - m_controller.openDeclaration( m_selectedEntryPair.obf ); + m_controller.savePreviousReference( m_reference ); + m_controller.openDeclaration( m_reference.entry ); } private void close( ) diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index f80bec7e..dfa25576 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -14,10 +14,11 @@ import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.util.Deque; import java.util.List; -import java.util.Stack; import com.google.common.collect.Lists; +import com.google.common.collect.Queues; import cuchaz.enigma.Deobfuscator; import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; @@ -30,7 +31,6 @@ import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.EntryPair; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MappingParseException; import cuchaz.enigma.mapping.MappingsReader; @@ -43,18 +43,18 @@ public class GuiController private Deobfuscator m_deobfuscator; private Gui m_gui; private SourceIndex m_index; - private ClassEntry m_currentClass; + private ClassEntry m_currentObfClass; private boolean m_isDirty; - private Stack m_locationStack; // TODO: make a location class, can be either Entry or EntryReference + private Deque> m_referenceStack; // TODO: make a location class, can be either Entry or EntryReference public GuiController( Gui gui ) { m_gui = gui; m_deobfuscator = null; m_index = null; - m_currentClass = null; + m_currentObfClass = null; m_isDirty = false; - m_locationStack = new Stack(); + m_referenceStack = Queues.newArrayDeque(); } public boolean isDirty( ) @@ -112,22 +112,16 @@ public class GuiController return null; } - return m_index.getToken( pos ); + return m_index.getReferenceToken( pos ); } - public EntryPair getEntryPair( Token token ) + public EntryReference getDeobfReference( Token token ) { if( m_index == null ) { return null; } - - Entry deobfEntry = m_index.getEntry( token ); - if( deobfEntry == null ) - { - return null; - } - return new EntryPair( m_deobfuscator.obfuscateEntry( deobfEntry ), deobfEntry ); + return m_index.getDeobfReference( token ); } public boolean entryHasMapping( Entry deobfEntry ) @@ -178,54 +172,63 @@ public class GuiController return rootNode; } - public void rename( Entry obfEntry, String newName ) + public void rename( EntryReference deobfReference, String newName ) { - m_deobfuscator.rename( obfEntry, newName ); + EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); + m_deobfuscator.rename( obfReference.entry, newName ); m_isDirty = true; refreshClasses(); - refreshCurrentClass( obfEntry ); + refreshCurrentClass( obfReference ); } public void openDeclaration( Entry entry ) { - // go to the entry - Entry obfEntry = m_deobfuscator.obfuscateEntry( entry ); - if( m_currentClass == null || !m_currentClass.equals( obfEntry.getClassEntry() ) ) + if( entry == null ) { - m_currentClass = new ClassEntry( obfEntry.getClassEntry() ); - deobfuscate( m_currentClass, obfEntry ); + throw new IllegalArgumentException( "Entry cannot be null!" ); } - else + openReference( new EntryReference( entry ) ); + } + + public void openReference( EntryReference deobfReference ) + { + if( deobfReference == null ) { - m_gui.showToken( m_index.getDeclarationToken( m_deobfuscator.deobfuscateEntry( obfEntry ) ) ); + throw new IllegalArgumentException( "Reference cannot be null!" ); } - if( m_locationStack.isEmpty() || !m_locationStack.peek().equals( obfEntry ) ) + // get the reference target class + EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); + ClassEntry obfClassEntry = obfReference.getClassEntry().getOuterClassEntry(); + if( m_currentObfClass == null || !m_currentObfClass.equals( obfClassEntry ) ) + { + // deobfuscate the class, then navigate to the reference + m_currentObfClass = obfClassEntry; + deobfuscate( m_currentObfClass, obfReference ); + } + else { - // update the stack - m_locationStack.push( obfEntry ); + // the class file is already open, just navigate to the reference + m_gui.showToken( m_index.getReferenceToken( deobfReference ) ); } } - public void openReference( EntryReference reference ) + public void savePreviousReference( EntryReference deobfReference ) { - // TODO: find out how to load the n-th reference in a caller - // TEMP: just go to the caller for now - openDeclaration( reference.caller ); + m_referenceStack.push( m_deobfuscator.obfuscateReference( deobfReference ) ); } - public void openPreviousLocation( ) + public void openPreviousReference( ) { if( hasPreviousLocation() ) { - m_locationStack.pop(); - openDeclaration( m_locationStack.peek() ); + openReference( m_deobfuscator.deobfuscateReference( m_referenceStack.pop() ) ); } } public boolean hasPreviousLocation( ) { - return m_locationStack.size() > 1; + return !m_referenceStack.isEmpty(); } private void refreshClasses( ) @@ -242,15 +245,15 @@ public class GuiController refreshCurrentClass( null ); } - private void refreshCurrentClass( Entry obfEntryToShow ) + private void refreshCurrentClass( EntryReference obfReferenceToShow ) { - if( m_currentClass != null ) + if( m_currentObfClass != null ) { - deobfuscate( m_currentClass, obfEntryToShow ); + deobfuscate( m_currentObfClass, obfReferenceToShow ); } } - private void deobfuscate( final ClassEntry classEntry, final Entry obfEntryToShow ) + private void deobfuscate( final ClassEntry classEntry, final EntryReference obfReferenceToShow ) { m_gui.setSource( "(deobfuscating...)" ); @@ -263,29 +266,32 @@ public class GuiController // decompile,deobfuscate the bytecode m_index = m_deobfuscator.getSource( classEntry.getClassName() ); m_gui.setSource( m_index.getSource() ); - if( obfEntryToShow != null ) + if( obfReferenceToShow != null ) { - Entry deobfEntryToShow = m_deobfuscator.deobfuscateEntry( obfEntryToShow ); - Token token = m_index.getDeclarationToken( deobfEntryToShow ); + EntryReference deobfReferenceToShow = m_deobfuscator.deobfuscateReference( obfReferenceToShow ); + Token token = m_index.getReferenceToken( deobfReferenceToShow ); if( token == null ) { - // TEMP - System.out.println( "WARNING: can't find token for " + obfEntryToShow + " -> " + deobfEntryToShow ); + // DEBUG + System.out.println( "WARNING: can't find token for " + obfReferenceToShow + " -> " + deobfReferenceToShow ); + } + else + { + m_gui.showToken( token ); } - m_gui.showToken( token ); } // set the highlighted tokens List obfuscatedTokens = Lists.newArrayList(); List deobfuscatedTokens = Lists.newArrayList(); - for( Token token : m_index.tokens() ) + for( Token token : m_index.referenceTokens() ) { - Entry entry = m_index.getEntry( token ); - if( entryHasMapping( entry ) ) + EntryReference reference = m_index.getDeobfReference( token ); + if( entryHasMapping( reference.entry ) ) { deobfuscatedTokens.add( token ); } - else if( entryIsObfuscatedIdenfitier( entry ) ) + else if( entryIsObfuscatedIdenfitier( reference.entry ) ) { obfuscatedTokens.add( token ); } diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index a1230db3..e34c31bf 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -30,6 +30,34 @@ public class Translator m_ancestries = ancestries; } + public Entry translateEntry( Entry entry ) + { + if( entry instanceof ClassEntry ) + { + return translateEntry( (ClassEntry)entry ); + } + else if( entry instanceof FieldEntry ) + { + return translateEntry( (FieldEntry)entry ); + } + else if( entry instanceof MethodEntry ) + { + return translateEntry( (MethodEntry)entry ); + } + else if( entry instanceof ConstructorEntry ) + { + return translateEntry( (ConstructorEntry)entry ); + } + else if( entry instanceof ArgumentEntry ) + { + return translateEntry( (ArgumentEntry)entry ); + } + else + { + throw new Error( "Unknown entry type: " + entry.getClass().getName() ); + } + } + public String translateClass( String className ) { return translate( new ClassEntry( className ) ); -- cgit v1.2.3 From fbeb2b73ab51f3244454a63893fee6d847fd859d Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 20 Aug 2014 01:22:38 -0400 Subject: missed a file --- src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 524 +++++++++++++++++++++ 1 file changed, 524 insertions(+) create mode 100644 src/cuchaz/enigma/analysis/SourceIndexVisitor.java (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java new file mode 100644 index 00000000..4e98989e --- /dev/null +++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java @@ -0,0 +1,524 @@ +/******************************************************************************* + * 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.analysis; + +import com.strobel.assembler.metadata.TypeDefinition; +import com.strobel.decompiler.languages.java.ast.Annotation; +import com.strobel.decompiler.languages.java.ast.AnonymousObjectCreationExpression; +import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression; +import com.strobel.decompiler.languages.java.ast.ArrayInitializerExpression; +import com.strobel.decompiler.languages.java.ast.ArraySpecifier; +import com.strobel.decompiler.languages.java.ast.AssertStatement; +import com.strobel.decompiler.languages.java.ast.AssignmentExpression; +import com.strobel.decompiler.languages.java.ast.AstNode; +import com.strobel.decompiler.languages.java.ast.BinaryOperatorExpression; +import com.strobel.decompiler.languages.java.ast.BlockStatement; +import com.strobel.decompiler.languages.java.ast.BreakStatement; +import com.strobel.decompiler.languages.java.ast.CaseLabel; +import com.strobel.decompiler.languages.java.ast.CastExpression; +import com.strobel.decompiler.languages.java.ast.CatchClause; +import com.strobel.decompiler.languages.java.ast.ClassOfExpression; +import com.strobel.decompiler.languages.java.ast.Comment; +import com.strobel.decompiler.languages.java.ast.CompilationUnit; +import com.strobel.decompiler.languages.java.ast.ComposedType; +import com.strobel.decompiler.languages.java.ast.ConditionalExpression; +import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; +import com.strobel.decompiler.languages.java.ast.ContinueStatement; +import com.strobel.decompiler.languages.java.ast.DoWhileStatement; +import com.strobel.decompiler.languages.java.ast.EmptyStatement; +import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; +import com.strobel.decompiler.languages.java.ast.ExpressionStatement; +import com.strobel.decompiler.languages.java.ast.FieldDeclaration; +import com.strobel.decompiler.languages.java.ast.ForEachStatement; +import com.strobel.decompiler.languages.java.ast.ForStatement; +import com.strobel.decompiler.languages.java.ast.GotoStatement; +import com.strobel.decompiler.languages.java.ast.IAstVisitor; +import com.strobel.decompiler.languages.java.ast.Identifier; +import com.strobel.decompiler.languages.java.ast.IdentifierExpression; +import com.strobel.decompiler.languages.java.ast.IfElseStatement; +import com.strobel.decompiler.languages.java.ast.ImportDeclaration; +import com.strobel.decompiler.languages.java.ast.IndexerExpression; +import com.strobel.decompiler.languages.java.ast.InstanceInitializer; +import com.strobel.decompiler.languages.java.ast.InstanceOfExpression; +import com.strobel.decompiler.languages.java.ast.InvocationExpression; +import com.strobel.decompiler.languages.java.ast.JavaTokenNode; +import com.strobel.decompiler.languages.java.ast.Keys; +import com.strobel.decompiler.languages.java.ast.LabelStatement; +import com.strobel.decompiler.languages.java.ast.LabeledStatement; +import com.strobel.decompiler.languages.java.ast.LambdaExpression; +import com.strobel.decompiler.languages.java.ast.LocalTypeDeclarationStatement; +import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; +import com.strobel.decompiler.languages.java.ast.MethodDeclaration; +import com.strobel.decompiler.languages.java.ast.MethodGroupExpression; +import com.strobel.decompiler.languages.java.ast.NewLineNode; +import com.strobel.decompiler.languages.java.ast.NullReferenceExpression; +import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; +import com.strobel.decompiler.languages.java.ast.PackageDeclaration; +import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; +import com.strobel.decompiler.languages.java.ast.ParenthesizedExpression; +import com.strobel.decompiler.languages.java.ast.PrimitiveExpression; +import com.strobel.decompiler.languages.java.ast.ReturnStatement; +import com.strobel.decompiler.languages.java.ast.SimpleType; +import com.strobel.decompiler.languages.java.ast.SuperReferenceExpression; +import com.strobel.decompiler.languages.java.ast.SwitchSection; +import com.strobel.decompiler.languages.java.ast.SwitchStatement; +import com.strobel.decompiler.languages.java.ast.SynchronizedStatement; +import com.strobel.decompiler.languages.java.ast.TextNode; +import com.strobel.decompiler.languages.java.ast.ThisReferenceExpression; +import com.strobel.decompiler.languages.java.ast.ThrowStatement; +import com.strobel.decompiler.languages.java.ast.TryCatchStatement; +import com.strobel.decompiler.languages.java.ast.TypeDeclaration; +import com.strobel.decompiler.languages.java.ast.TypeParameterDeclaration; +import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression; +import com.strobel.decompiler.languages.java.ast.UnaryOperatorExpression; +import com.strobel.decompiler.languages.java.ast.VariableDeclarationStatement; +import com.strobel.decompiler.languages.java.ast.VariableInitializer; +import com.strobel.decompiler.languages.java.ast.WhileStatement; +import com.strobel.decompiler.languages.java.ast.WildcardType; +import com.strobel.decompiler.patterns.Pattern; + +import cuchaz.enigma.mapping.ClassEntry; + +public class SourceIndexVisitor implements IAstVisitor +{ + @Override + public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) + { + TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getInternalName() ); + index.addDeclaration( node.getNameToken(), classEntry ); + + return node.acceptVisitor( new SourceIndexClassVisitor( classEntry ), index ); + } + + protected Void recurse( AstNode node, SourceIndex index ) + { + for( final AstNode child : node.getChildren() ) + { + child.acceptVisitor( this, index ); + } + return null; + } + + @Override + public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitSimpleType( SimpleType node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitComment( Comment node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitPatternPlaceholder( AstNode node, Pattern pattern, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitTypeReference( TypeReferenceExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitJavaTokenNode( JavaTokenNode node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitIdentifier( Identifier node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitNullReferenceExpression( NullReferenceExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitThisReferenceExpression( ThisReferenceExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitSuperReferenceExpression( SuperReferenceExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitClassOfExpression( ClassOfExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitBlockStatement( BlockStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitExpressionStatement( ExpressionStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitBreakStatement( BreakStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitContinueStatement( ContinueStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitDoWhileStatement( DoWhileStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitEmptyStatement( EmptyStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitIfElseStatement( IfElseStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitLabelStatement( LabelStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitLabeledStatement( LabeledStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitReturnStatement( ReturnStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitSwitchStatement( SwitchStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitSwitchSection( SwitchSection node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitCaseLabel( CaseLabel node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitThrowStatement( ThrowStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitCatchClause( CatchClause node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitAnnotation( Annotation node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitNewLine( NewLineNode node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitVariableDeclaration( VariableDeclarationStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitVariableInitializer( VariableInitializer node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitText( TextNode node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitImportDeclaration( ImportDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitInitializerBlock( InstanceInitializer node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitCompilationUnit( CompilationUnit node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitPackageDeclaration( PackageDeclaration node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitArraySpecifier( ArraySpecifier node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitComposedType( ComposedType node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitWhileStatement( WhileStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitPrimitiveExpression( PrimitiveExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitCastExpression( CastExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitBinaryOperatorExpression( BinaryOperatorExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitInstanceOfExpression( InstanceOfExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitIndexerExpression( IndexerExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitConditionalExpression( ConditionalExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitArrayInitializerExpression( ArrayInitializerExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitObjectCreationExpression( ObjectCreationExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitArrayCreationExpression( ArrayCreationExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitAssignmentExpression( AssignmentExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitForStatement( ForStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitForEachStatement( ForEachStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitTryCatchStatement( TryCatchStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitGotoStatement( GotoStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitParenthesizedExpression( ParenthesizedExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitSynchronizedStatement( SynchronizedStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitAnonymousObjectCreationExpression( AnonymousObjectCreationExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitWildcardType( WildcardType node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitMethodGroupExpression( MethodGroupExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitAssertStatement( AssertStatement node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitLambdaExpression( LambdaExpression node, SourceIndex index ) + { + return recurse( node, index ); + } + + @Override + public Void visitLocalTypeDeclarationStatement( LocalTypeDeclarationStatement node, SourceIndex index ) + { + return recurse( node, index ); + } +} -- cgit v1.2.3 From bdb61cf849c67f7da6a0bb7c047b506d8462058f Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 20 Aug 2014 22:30:12 -0400 Subject: fixed recognition of inner class tokens fixed recognition of reference tokens in constructors --- src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index 2d4c0f57..52570886 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -14,6 +14,7 @@ import com.google.common.collect.HashMultiset; import com.google.common.collect.Multiset; import com.strobel.assembler.metadata.FieldDefinition; import com.strobel.assembler.metadata.MethodDefinition; +import com.strobel.assembler.metadata.TypeDefinition; import com.strobel.assembler.metadata.TypeReference; import com.strobel.decompiler.languages.TextLocation; import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; @@ -45,6 +46,16 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor @Override public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) { + // is this this class, or a subtype? + TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getInternalName() ); + if( !classEntry.equals( m_classEntry ) ) + { + // it's a sub-type, recurse + index.addDeclaration( node.getNameToken(), classEntry ); + return node.acceptVisitor( new SourceIndexClassVisitor( classEntry ), index ); + } + return recurse( node, index ); } @@ -84,7 +95,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, def.getSignature() ); index.addDeclaration( node.getNameToken(), constructorEntry ); - return recurse( node, index ); + return node.acceptVisitor( new SourceIndexBehaviorVisitor( constructorEntry ), index ); } @Override -- cgit v1.2.3 From 237b2ed2a6b6f537cdbdf9fc9c6d0c7743f34375 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 21 Aug 2014 01:10:37 -0400 Subject: fixed call graph searching added system to navigate multiple tokens for the same entry in a behavior --- src/cuchaz/enigma/Deobfuscator.java | 18 +++--- src/cuchaz/enigma/analysis/EntryReference.java | 13 ++-- src/cuchaz/enigma/analysis/JarIndex.java | 30 ++++----- src/cuchaz/enigma/analysis/SourceIndex.java | 37 +++++++++-- .../analysis/SourceIndexBehaviorVisitor.java | 16 ++--- .../enigma/analysis/SourceIndexClassVisitor.java | 23 ++++--- src/cuchaz/enigma/gui/Gui.java | 53 +++++++++++---- src/cuchaz/enigma/gui/GuiController.java | 75 ++++++++++++++-------- src/cuchaz/enigma/gui/ReadableToken.java | 38 +++++++++++ src/cuchaz/enigma/gui/TokenListCellRenderer.java | 40 ++++++++++++ src/cuchaz/enigma/mapping/ConstructorEntry.java | 54 +++++++++++++--- src/cuchaz/enigma/mapping/Translator.java | 28 +++++--- 12 files changed, 302 insertions(+), 123 deletions(-) create mode 100644 src/cuchaz/enigma/gui/ReadableToken.java create mode 100644 src/cuchaz/enigma/gui/TokenListCellRenderer.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 34e6033b..a5feaa9f 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -181,7 +181,7 @@ public class Deobfuscator return index; } - public Entry obfuscateEntry( Entry deobfEntry ) + public T obfuscateEntry( T deobfEntry ) { if( deobfEntry == null ) { @@ -190,7 +190,7 @@ public class Deobfuscator return getTranslator( TranslationDirection.Obfuscating ).translateEntry( deobfEntry ); } - public Entry deobfuscateEntry( Entry obfEntry ) + public T deobfuscateEntry( T obfEntry ) { if( obfEntry == null ) { @@ -199,29 +199,27 @@ public class Deobfuscator return getTranslator( TranslationDirection.Deobfuscating ).translateEntry( obfEntry ); } - public EntryReference obfuscateReference( EntryReference deobfReference ) + public EntryReference obfuscateReference( EntryReference deobfReference ) { if( deobfReference == null ) { return null; } - return new EntryReference( + return new EntryReference( obfuscateEntry( deobfReference.entry ), - obfuscateEntry( deobfReference.context ), - deobfReference.pos + obfuscateEntry( deobfReference.context ) ); } - public EntryReference deobfuscateReference( EntryReference obfReference ) + public EntryReference deobfuscateReference( EntryReference obfReference ) { if( obfReference == null ) { return null; } - return new EntryReference( + return new EntryReference( deobfuscateEntry( obfReference.entry ), - deobfuscateEntry( obfReference.context ), - obfReference.pos + deobfuscateEntry( obfReference.context ) ); } diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java index 869e08c1..768c1132 100644 --- a/src/cuchaz/enigma/analysis/EntryReference.java +++ b/src/cuchaz/enigma/analysis/EntryReference.java @@ -18,14 +18,13 @@ public class EntryReference { public E entry; public C context; - public int pos; public EntryReference( E entry ) { - this( entry, null, -1 ); + this( entry, null ); } - public EntryReference( E entry, C context, int pos ) + public EntryReference( E entry, C context ) { if( entry == null ) { @@ -34,7 +33,6 @@ public class EntryReference this.entry = entry; this.context = context; - this.pos = pos; } public ClassEntry getClassEntry( ) @@ -51,7 +49,7 @@ public class EntryReference { if( context != null ) { - return Util.combineHashesOrdered( entry.hashCode(), context.hashCode(), Integer.valueOf( pos ).hashCode() ); + return Util.combineHashesOrdered( entry.hashCode(), context.hashCode() ); } return entry.hashCode(); } @@ -82,7 +80,7 @@ public class EntryReference } else if( context != null && other.context != null ) { - return context.equals( other.context ) && pos == other.pos; + return context.equals( other.context ); } return false; } @@ -96,9 +94,6 @@ public class EntryReference { buf.append( " called from " ); buf.append( context ); - buf.append( " (" ); - buf.append( pos ); - buf.append( ")" ); } return buf.toString(); } diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index f408d930..315a2864 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -146,10 +146,15 @@ public class JarIndex } else if( behavior instanceof CtConstructor ) { - thisEntry = new ConstructorEntry( - new ClassEntry( className ), - behavior.getSignature() - ); + boolean isStatic = behavior.getName().equals( "" ); + if( isStatic ) + { + thisEntry = new ConstructorEntry( new ClassEntry( className ) ); + } + else + { + thisEntry = new ConstructorEntry( new ClassEntry( className ), behavior.getSignature() ); + } } else { @@ -159,7 +164,6 @@ public class JarIndex // index method calls try { - final Multiset callNumbers = HashMultiset.create(); behavior.instrument( new ExprEditor( ) { @Override @@ -171,11 +175,9 @@ public class JarIndex call.getMethodName(), call.getSignature() ); - callNumbers.add( calledMethodEntry ); EntryReference reference = new EntryReference( calledMethodEntry, - thisEntry, - callNumbers.count( calledMethodEntry ) - 1 + thisEntry ); m_behaviorReferences.put( calledMethodEntry, reference ); } @@ -188,11 +190,9 @@ public class JarIndex new ClassEntry( className ), call.getFieldName() ); - callNumbers.add( calledFieldEntry ); EntryReference reference = new EntryReference( calledFieldEntry, - thisEntry, - callNumbers.count( calledFieldEntry ) - 1 + thisEntry ); m_fieldReferences.put( calledFieldEntry, reference ); } @@ -208,11 +208,9 @@ public class JarIndex new ClassEntry( className ), call.getSignature() ); - callNumbers.add( calledConstructorEntry ); EntryReference reference = new EntryReference( calledConstructorEntry, - thisEntry, - callNumbers.count( calledConstructorEntry ) - 1 + thisEntry ); m_behaviorReferences.put( calledConstructorEntry, reference ); } @@ -225,11 +223,9 @@ public class JarIndex new ClassEntry( className ), call.getSignature() ); - callNumbers.add( calledConstructorEntry ); EntryReference reference = new EntryReference( calledConstructorEntry, - thisEntry, - callNumbers.count( calledConstructorEntry ) - 1 + thisEntry ); m_behaviorReferences.put( calledConstructorEntry, reference ); } diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index bf890e30..960ec36f 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -10,13 +10,15 @@ ******************************************************************************/ package cuchaz.enigma.analysis; -import java.util.HashMap; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.TreeMap; +import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import com.strobel.decompiler.languages.Region; import com.strobel.decompiler.languages.java.ast.Identifier; @@ -26,7 +28,7 @@ public class SourceIndex { private String m_source; private TreeMap> m_tokenToReference; - private HashMap,Token> m_referenceToToken; + private Multimap,Token> m_referenceToTokens; private Map m_declarationToToken; private List m_lineOffsets; @@ -34,7 +36,7 @@ public class SourceIndex { m_source = source; m_tokenToReference = Maps.newTreeMap(); - m_referenceToToken = Maps.newHashMap(); + m_referenceToTokens = HashMultimap.create(); m_declarationToToken = Maps.newHashMap(); m_lineOffsets = Lists.newArrayList(); @@ -96,7 +98,7 @@ public class SourceIndex if( token != null ) { m_tokenToReference.put( token, deobfReference ); - m_referenceToToken.put( deobfReference, token ); + m_referenceToTokens.put( deobfReference, token ); } } @@ -107,7 +109,7 @@ public class SourceIndex { EntryReference reference = new EntryReference( deobfEntry ); m_tokenToReference.put( token, reference ); - m_referenceToToken.put( reference, token ); + m_referenceToTokens.put( reference, token ); m_declarationToToken.put( deobfEntry, token ); } } @@ -122,9 +124,9 @@ public class SourceIndex return null; } - public Token getReferenceToken( EntryReference deobfReference ) + public Collection getReferenceTokens( EntryReference deobfReference ) { - return m_referenceToToken.get( deobfReference ); + return m_referenceToTokens.get( deobfReference ); } public EntryReference getDeobfReference( Token token ) @@ -151,6 +153,27 @@ public class SourceIndex return m_declarationToToken.get( deobfEntry ); } + public int getLineNumber( int pos ) + { + // line number is 1-based + int line = 0; + for( Integer offset : m_lineOffsets ) + { + if( offset > pos ) + { + break; + } + line++; + } + return line; + } + + public int getColumnNumber( int pos ) + { + // column number is 1-based + return pos - m_lineOffsets.get( getLineNumber( pos ) - 1 ) + 1; + } + private int toPos( int line, int col ) { // line and col are 1-based diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index d3386c51..a9438588 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -10,8 +10,6 @@ ******************************************************************************/ package cuchaz.enigma.analysis; -import com.google.common.collect.HashMultiset; -import com.google.common.collect.Multiset; import com.strobel.assembler.metadata.MemberReference; import com.strobel.assembler.metadata.MethodDefinition; import com.strobel.assembler.metadata.ParameterDefinition; @@ -36,12 +34,10 @@ import cuchaz.enigma.mapping.MethodEntry; public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { private BehaviorEntry m_behaviorEntry; - private Multiset m_indices; public SourceIndexBehaviorVisitor( BehaviorEntry behaviorEntry ) { m_behaviorEntry = behaviorEntry; - m_indices = HashMultiset.create(); } @Override @@ -64,10 +60,9 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor MethodEntry methodEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); if( node.getTarget() instanceof MemberReferenceExpression ) { - m_indices.add( methodEntry ); index.addReference( ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(), - new EntryReference( methodEntry, m_behaviorEntry, m_indices.count( methodEntry ) ) + new EntryReference( methodEntry, m_behaviorEntry ) ); } @@ -82,10 +77,9 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); - m_indices.add( fieldEntry ); index.addReference( node.getMemberNameToken(), - new EntryReference( fieldEntry, m_behaviorEntry, m_indices.count( fieldEntry ) ) + new EntryReference( fieldEntry, m_behaviorEntry ) ); } @@ -99,10 +93,9 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) { ClassEntry classEntry = new ClassEntry( ref.getInternalName() ); - m_indices.add( classEntry ); index.addReference( node.getIdentifierToken(), - new EntryReference( classEntry, m_behaviorEntry, m_indices.count( classEntry ) ) + new EntryReference( classEntry, m_behaviorEntry ) ); } @@ -130,10 +123,9 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); - m_indices.add( fieldEntry ); index.addReference( node.getIdentifierToken(), - new EntryReference( fieldEntry, m_behaviorEntry, m_indices.count( fieldEntry ) ) + new EntryReference( fieldEntry, m_behaviorEntry ) ); } diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index 52570886..a1c82711 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -10,8 +10,6 @@ ******************************************************************************/ package cuchaz.enigma.analysis; -import com.google.common.collect.HashMultiset; -import com.google.common.collect.Multiset; import com.strobel.assembler.metadata.FieldDefinition; import com.strobel.assembler.metadata.MethodDefinition; import com.strobel.assembler.metadata.TypeDefinition; @@ -26,6 +24,7 @@ import com.strobel.decompiler.languages.java.ast.SimpleType; import com.strobel.decompiler.languages.java.ast.TypeDeclaration; import com.strobel.decompiler.languages.java.ast.VariableInitializer; +import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; @@ -35,12 +34,10 @@ import cuchaz.enigma.mapping.MethodEntry; public class SourceIndexClassVisitor extends SourceIndexVisitor { private ClassEntry m_classEntry; - private Multiset m_indices; public SourceIndexClassVisitor( ClassEntry classEntry ) { m_classEntry = classEntry; - m_indices = HashMultiset.create(); } @Override @@ -68,7 +65,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor ClassEntry classEntry = new ClassEntry( ref.getInternalName() ); index.addReference( node.getIdentifierToken(), - new EntryReference( classEntry, m_classEntry, m_indices.count( classEntry ) ) + new EntryReference( classEntry, m_classEntry ) ); } @@ -80,11 +77,17 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - MethodEntry methodEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() ); - index.addDeclaration( node.getNameToken(), methodEntry ); - //if( !def.getName().equals( "" ) ) - - return node.acceptVisitor( new SourceIndexBehaviorVisitor( methodEntry ), index ); + BehaviorEntry behaviorEntry; + if( def.getName().equals( "" ) ) + { + behaviorEntry = new ConstructorEntry( classEntry ); + } + else + { + behaviorEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() ); + } + index.addDeclaration( node.getNameToken(), behaviorEntry ); + return node.acceptVisitor( new SourceIndexBehaviorVisitor( behaviorEntry ), index ); } @Override diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 341c1493..a5471a74 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -28,6 +28,7 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -145,6 +146,7 @@ public class Gui private BoxHighlightPainter m_deobfuscatedHighlightPainter; private JTree m_inheritanceTree; private JTree m_callsTree; + private JList m_tokens; private JTabbedPane m_tabs; // dynamic menu items @@ -457,9 +459,29 @@ public class Gui } } } ); - JPanel callPanel = new JPanel(); - callPanel.setLayout( new BorderLayout() ); - callPanel.add( new JScrollPane( m_callsTree ) ); + m_tokens = new JList(); + m_tokens.setCellRenderer( new TokenListCellRenderer( m_controller ) ); + m_tokens.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); + m_tokens.setLayoutOrientation( JList.VERTICAL ); + m_tokens.addMouseListener( new MouseAdapter() + { + @Override + public void mouseClicked( MouseEvent event ) + { + if( event.getClickCount() == 2 ) + { + Token selected = m_tokens.getSelectedValue(); + if( selected != null ) + { + showToken( selected ); + } + } + } + } ); + m_tokens.setPreferredSize( new Dimension( 0, 200 ) ); + JSplitPane callPanel = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, new JScrollPane( m_callsTree ), new JScrollPane( m_tokens ) ); + callPanel.setResizeWeight( 1 ); // let the top side take all the slack + callPanel.resetToPreferredSizes(); // layout controls JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); @@ -743,6 +765,21 @@ public class Gui m_editor.grabFocus(); } + public void showTokens( Collection tokens ) + { + Vector sortedTokens = new Vector( tokens ); + Collections.sort( sortedTokens ); + if( sortedTokens.size() > 1 ) + { + // sort the tokens and update the tokens panel + m_tokens.setListData( sortedTokens ); + m_tokens.setSelectedIndex( 0 ); + } + + // show the first token + showToken( sortedTokens.get( 0 ) ); + } + public void setHighlightedTokens( Iterable obfuscatedTokens, Iterable deobfuscatedTokens ) { // remove any old highlighters @@ -900,17 +937,9 @@ public class Gui private void startRename( ) { - // get the class name - ClassEntry classEntry = m_reference.entry.getClassEntry(); - String className = classEntry.getName(); - if( classEntry.isInnerClass() ) - { - className = classEntry.getInnerClassName(); - } - // init the text box final JTextField text = new JTextField(); - text.setText( className ); + text.setText( m_reference.entry.getName() ); text.setPreferredSize( new Dimension( 360, text.getPreferredSize().height ) ); text.addKeyListener( new KeyAdapter( ) { diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index dfa25576..a35db056 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -14,6 +14,7 @@ import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.util.Collection; import java.util.Deque; import java.util.List; @@ -45,7 +46,7 @@ public class GuiController private SourceIndex m_index; private ClassEntry m_currentObfClass; private boolean m_isDirty; - private Deque> m_referenceStack; // TODO: make a location class, can be either Entry or EntryReference + private Deque> m_referenceStack; public GuiController( Gui gui ) { @@ -111,7 +112,6 @@ public class GuiController { return null; } - return m_index.getReferenceToken( pos ); } @@ -124,6 +124,19 @@ public class GuiController return m_index.getDeobfReference( token ); } + public ReadableToken getReadableToken( Token token ) + { + if( m_index == null ) + { + return null; + } + return new ReadableToken( + m_index.getLineNumber( token.start ), + m_index.getColumnNumber( token.start ), + m_index.getColumnNumber( token.end ) + ); + } + public boolean entryHasMapping( Entry deobfEntry ) { return m_deobfuscator.hasMapping( m_deobfuscator.obfuscateEntry( deobfEntry ) ); @@ -134,8 +147,9 @@ public class GuiController return m_deobfuscator.isObfuscatedIdentifier( m_deobfuscator.obfuscateEntry( deobfEntry ) ); } - public ClassInheritanceTreeNode getClassInheritance( ClassEntry obfClassEntry ) + public ClassInheritanceTreeNode getClassInheritance( ClassEntry deobfClassEntry ) { + ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry( deobfClassEntry ); ClassInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getClassInheritance( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), obfClassEntry @@ -143,8 +157,9 @@ public class GuiController return ClassInheritanceTreeNode.findNode( rootNode, obfClassEntry ); } - public MethodInheritanceTreeNode getMethodInheritance( MethodEntry obfMethodEntry ) + public MethodInheritanceTreeNode getMethodInheritance( MethodEntry deobfMethodEntry ) { + MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry( deobfMethodEntry ); MethodInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodInheritance( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), obfMethodEntry @@ -152,8 +167,9 @@ public class GuiController return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); } - public FieldReferenceTreeNode getFieldReferences( FieldEntry obfFieldEntry ) + public FieldReferenceTreeNode getFieldReferences( FieldEntry deobfFieldEntry ) { + FieldEntry obfFieldEntry = m_deobfuscator.obfuscateEntry( deobfFieldEntry ); FieldReferenceTreeNode rootNode = new FieldReferenceTreeNode( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), obfFieldEntry @@ -162,11 +178,12 @@ public class GuiController return rootNode; } - public BehaviorReferenceTreeNode getMethodReferences( BehaviorEntry obfEntry ) + public BehaviorReferenceTreeNode getMethodReferences( BehaviorEntry deobfBehaviorEntry ) { + BehaviorEntry obfBehaviorEntry = m_deobfuscator.obfuscateEntry( deobfBehaviorEntry ); BehaviorReferenceTreeNode rootNode = new BehaviorReferenceTreeNode( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), - obfEntry + obfBehaviorEntry ); rootNode.load( m_deobfuscator.getJarIndex(), true ); return rootNode; @@ -181,13 +198,13 @@ public class GuiController refreshCurrentClass( obfReference ); } - public void openDeclaration( Entry entry ) + public void openDeclaration( Entry deobfEntry ) { - if( entry == null ) + if( deobfEntry == null ) { throw new IllegalArgumentException( "Entry cannot be null!" ); } - openReference( new EntryReference( entry ) ); + openReference( new EntryReference( deobfEntry ) ); } public void openReference( EntryReference deobfReference ) @@ -208,8 +225,22 @@ public class GuiController } else { - // the class file is already open, just navigate to the reference - m_gui.showToken( m_index.getReferenceToken( deobfReference ) ); + showReference( obfReference ); + } + } + + private void showReference( EntryReference obfReference ) + { + EntryReference deobfReference = m_deobfuscator.deobfuscateReference( obfReference ); + Collection tokens = m_index.getReferenceTokens( deobfReference ); + if( tokens.isEmpty() ) + { + // DEBUG + System.err.println( String.format( "WARNING: no tokens found for %s in %s", deobfReference, m_currentObfClass ) ); + } + else + { + m_gui.showTokens( tokens ); } } @@ -245,15 +276,15 @@ public class GuiController refreshCurrentClass( null ); } - private void refreshCurrentClass( EntryReference obfReferenceToShow ) + private void refreshCurrentClass( EntryReference obfReference ) { if( m_currentObfClass != null ) { - deobfuscate( m_currentObfClass, obfReferenceToShow ); + deobfuscate( m_currentObfClass, obfReference ); } } - private void deobfuscate( final ClassEntry classEntry, final EntryReference obfReferenceToShow ) + private void deobfuscate( final ClassEntry classEntry, final EntryReference obfReference ) { m_gui.setSource( "(deobfuscating...)" ); @@ -266,19 +297,9 @@ public class GuiController // decompile,deobfuscate the bytecode m_index = m_deobfuscator.getSource( classEntry.getClassName() ); m_gui.setSource( m_index.getSource() ); - if( obfReferenceToShow != null ) + if( obfReference != null ) { - EntryReference deobfReferenceToShow = m_deobfuscator.deobfuscateReference( obfReferenceToShow ); - Token token = m_index.getReferenceToken( deobfReferenceToShow ); - if( token == null ) - { - // DEBUG - System.out.println( "WARNING: can't find token for " + obfReferenceToShow + " -> " + deobfReferenceToShow ); - } - else - { - m_gui.showToken( token ); - } + showReference( obfReference ); } // set the highlighted tokens diff --git a/src/cuchaz/enigma/gui/ReadableToken.java b/src/cuchaz/enigma/gui/ReadableToken.java new file mode 100644 index 00000000..3f430453 --- /dev/null +++ b/src/cuchaz/enigma/gui/ReadableToken.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.gui; + +public class ReadableToken +{ + public int line; + public int startColumn; + public int endColumn; + + public ReadableToken( int line, int startColumn, int endColumn ) + { + this.line = line; + this.startColumn = startColumn; + this.endColumn = endColumn; + } + + @Override + public String toString( ) + { + StringBuilder buf = new StringBuilder(); + buf.append( "line " ); + buf.append( line ); + buf.append( " columns " ); + buf.append( startColumn ); + buf.append( "-" ); + buf.append( endColumn ); + return buf.toString(); + } +} diff --git a/src/cuchaz/enigma/gui/TokenListCellRenderer.java b/src/cuchaz/enigma/gui/TokenListCellRenderer.java new file mode 100644 index 00000000..9247c066 --- /dev/null +++ b/src/cuchaz/enigma/gui/TokenListCellRenderer.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.gui; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +import cuchaz.enigma.analysis.Token; + +public class TokenListCellRenderer implements ListCellRenderer +{ + private GuiController m_controller; + private DefaultListCellRenderer m_defaultRenderer; + + public TokenListCellRenderer( GuiController controller ) + { + m_controller = controller; + m_defaultRenderer = new DefaultListCellRenderer(); + } + + @Override + public Component getListCellRendererComponent( JList list, Token token, int index, boolean isSelected, boolean hasFocus ) + { + JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, token, index, isSelected, hasFocus ); + label.setText( m_controller.getReadableToken( token ).toString() ); + return label; + } +} diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java index 0f7dab68..ad029e1c 100644 --- a/src/cuchaz/enigma/mapping/ConstructorEntry.java +++ b/src/cuchaz/enigma/mapping/ConstructorEntry.java @@ -21,16 +21,17 @@ public class ConstructorEntry implements BehaviorEntry, Serializable private ClassEntry m_classEntry; private String m_signature; + public ConstructorEntry( ClassEntry classEntry ) + { + this( classEntry, null ); + } + public ConstructorEntry( ClassEntry classEntry, String signature ) { if( classEntry == null ) { throw new IllegalArgumentException( "Class cannot be null!" ); } - if( signature == null ) - { - throw new IllegalArgumentException( "Method signature cannot be null!" ); - } m_classEntry = classEntry; m_signature = signature; @@ -47,11 +48,20 @@ public class ConstructorEntry implements BehaviorEntry, Serializable { return m_classEntry; } - + @Override public String getName( ) { - return m_classEntry.getName(); + if( isStatic() ) + { + return ""; + } + return ""; + } + + public boolean isStatic( ) + { + return m_signature == null; } @Override @@ -69,7 +79,14 @@ public class ConstructorEntry implements BehaviorEntry, Serializable @Override public int hashCode( ) { - return Util.combineHashesOrdered( m_classEntry, m_signature ); + if( isStatic() ) + { + return Util.combineHashesOrdered( m_classEntry ); + } + else + { + return Util.combineHashesOrdered( m_classEntry, m_signature ); + } } @Override @@ -84,12 +101,31 @@ public class ConstructorEntry implements BehaviorEntry, Serializable public boolean equals( ConstructorEntry other ) { - return m_classEntry.equals( other.m_classEntry ) && m_signature.equals( other.m_signature ); + if( isStatic() != other.isStatic() ) + { + return false; + } + + if( isStatic() ) + { + return m_classEntry.equals( other.m_classEntry ); + } + else + { + return m_classEntry.equals( other.m_classEntry ) && m_signature.equals( other.m_signature ); + } } @Override public String toString( ) { - return m_classEntry.getName() + m_signature; + if( isStatic() ) + { + return m_classEntry.getName() + "." + getName(); + } + else + { + return m_classEntry.getName() + "." + getName() + m_signature; + } } } diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index e34c31bf..a671c275 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -30,27 +30,28 @@ public class Translator m_ancestries = ancestries; } - public Entry translateEntry( Entry entry ) + @SuppressWarnings( "unchecked" ) + public T translateEntry( T entry ) { if( entry instanceof ClassEntry ) { - return translateEntry( (ClassEntry)entry ); + return (T)translateEntry( (ClassEntry)entry ); } else if( entry instanceof FieldEntry ) { - return translateEntry( (FieldEntry)entry ); + return (T)translateEntry( (FieldEntry)entry ); } else if( entry instanceof MethodEntry ) { - return translateEntry( (MethodEntry)entry ); + return (T)translateEntry( (MethodEntry)entry ); } else if( entry instanceof ConstructorEntry ) { - return translateEntry( (ConstructorEntry)entry ); + return (T)translateEntry( (ConstructorEntry)entry ); } else if( entry instanceof ArgumentEntry ) { - return translateEntry( (ArgumentEntry)entry ); + return (T)translateEntry( (ArgumentEntry)entry ); } else { @@ -194,10 +195,17 @@ public class Translator public ConstructorEntry translateEntry( ConstructorEntry in ) { - return new ConstructorEntry( - translateEntry( in.getClassEntry() ), - translateSignature( in.getSignature() ) - ); + if( in.isStatic() ) + { + return new ConstructorEntry( translateEntry( in.getClassEntry() ) ); + } + else + { + return new ConstructorEntry( + translateEntry( in.getClassEntry() ), + translateSignature( in.getSignature() ) + ); + } } public BehaviorEntry translateEntry( BehaviorEntry in ) -- cgit v1.2.3 From 79e8b7ea7ed27d65582d1c399a78e540d0f42895 Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 22 Aug 2014 00:37:31 -0400 Subject: fixed constructor references in call graph searches clear reference list when opening single reference (instead of list of references) --- src/cuchaz/enigma/Deobfuscator.java | 3 +-- src/cuchaz/enigma/analysis/BridgeFixer.java | 1 - .../enigma/analysis/SourceIndexBehaviorVisitor.java | 21 ++++++++++++++++++++- src/cuchaz/enigma/gui/Gui.java | 5 +++++ 4 files changed, 26 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index a5feaa9f..38f7af56 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -30,7 +30,6 @@ import cuchaz.enigma.analysis.EntryReference; import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; -import cuchaz.enigma.analysis.TreeDumpVisitor; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ClassMapping; @@ -163,7 +162,7 @@ public class Deobfuscator StringWriter buf = new StringWriter(); root.acceptVisitor( new InsertParenthesesVisitor(), null ); // DEBUG - root.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); + //root.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); root.acceptVisitor( new JavaOutputVisitor( new PlainTextOutput( buf ), m_settings ), null ); // build the source index diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java index ee90f513..f13f68f4 100644 --- a/src/cuchaz/enigma/analysis/BridgeFixer.java +++ b/src/cuchaz/enigma/analysis/BridgeFixer.java @@ -86,7 +86,6 @@ public class BridgeFixer catch( NotFoundException ex ) { // can't find the type? not a bridge method - ex.printStackTrace( System.err ); return null; } } diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index a9438588..ab505528 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -21,12 +21,14 @@ import com.strobel.decompiler.languages.java.ast.InvocationExpression; import com.strobel.decompiler.languages.java.ast.Keys; import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; import com.strobel.decompiler.languages.java.ast.MethodDeclaration; +import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; import com.strobel.decompiler.languages.java.ast.SimpleType; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MethodEntry; @@ -57,9 +59,9 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); - MethodEntry methodEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); if( node.getTarget() instanceof MemberReferenceExpression ) { + MethodEntry methodEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); index.addReference( ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(), new EntryReference( methodEntry, m_behaviorEntry ) @@ -131,4 +133,21 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor return recurse( node, index ); } + + @Override + public Void visitObjectCreationExpression( ObjectCreationExpression node, SourceIndex index ) + { + MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, ref.getSignature() ); + if( node.getType() instanceof SimpleType ) + { + index.addReference( + ((SimpleType)node.getType()).getIdentifierToken(), + new EntryReference( constructorEntry, m_behaviorEntry ) + ); + } + + return recurse( node, index ); + } } diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index a5471a74..cd0fac76 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -479,6 +479,7 @@ public class Gui } } ); m_tokens.setPreferredSize( new Dimension( 0, 200 ) ); + m_tokens.setMinimumSize( new Dimension( 0, 200 ) ); JSplitPane callPanel = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, new JScrollPane( m_callsTree ), new JScrollPane( m_tokens ) ); callPanel.setResizeWeight( 1 ); // let the top side take all the slack callPanel.resetToPreferredSizes(); @@ -775,6 +776,10 @@ public class Gui m_tokens.setListData( sortedTokens ); m_tokens.setSelectedIndex( 0 ); } + else + { + m_tokens.setListData( new Vector() ); + } // show the first token showToken( sortedTokens.get( 0 ) ); -- cgit v1.2.3 From 32b7ea70ff20d3584f8021e598141c20c2200398 Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 22 Aug 2014 01:25:52 -0400 Subject: added show token effects --- src/cuchaz/enigma/analysis/SourceIndex.java | 2 +- src/cuchaz/enigma/gui/BoxHighlightPainter.java | 23 +++++--- src/cuchaz/enigma/gui/Gui.java | 61 ++++++++++++++++++++-- .../enigma/gui/SelectionHighlightPainter.java | 35 +++++++++++++ 4 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 src/cuchaz/enigma/gui/SelectionHighlightPainter.java (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 960ec36f..1a5a80d6 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -117,7 +117,7 @@ public class SourceIndex public Token getReferenceToken( int pos ) { Token token = m_tokenToReference.floorKey( new Token( pos, pos ) ); - if( token.contains( pos ) ) + if( token != null && token.contains( pos ) ) { return token; } diff --git a/src/cuchaz/enigma/gui/BoxHighlightPainter.java b/src/cuchaz/enigma/gui/BoxHighlightPainter.java index b9474ff8..2c118340 100644 --- a/src/cuchaz/enigma/gui/BoxHighlightPainter.java +++ b/src/cuchaz/enigma/gui/BoxHighlightPainter.java @@ -32,11 +32,24 @@ public abstract class BoxHighlightPainter implements Highlighter.HighlightPainte @Override public void paint( Graphics g, int start, int end, Shape shape, JTextComponent text ) + { + Rectangle bounds = getBounds( text, start, end ); + + // fill the area + g.setColor( m_fillColor ); + g.fillRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); + + // draw a box around the area + g.setColor( m_borderColor ); + g.drawRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); + } + + protected static Rectangle getBounds( JTextComponent text, int start, int end ) { try { // determine the bounds of the text - Rectangle bounds = text.getUI().modelToView( text, start ).union( text.getUI().modelToView( text, end ) ); + Rectangle bounds = text.modelToView( start ).union( text.modelToView( end ) ); // adjust the box so it looks nice bounds.x -= 2; @@ -44,13 +57,7 @@ public abstract class BoxHighlightPainter implements Highlighter.HighlightPainte bounds.y += 1; bounds.height -= 2; - // fill the area - g.setColor( m_fillColor ); - g.fillRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); - - // draw a box around the area - g.setColor( m_borderColor ); - g.drawRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); + return bounds; } catch( BadLocationException ex ) { diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index cd0fac76..914359b4 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -17,6 +17,7 @@ import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridLayout; +import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; @@ -53,6 +54,7 @@ import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; +import javax.swing.Timer; import javax.swing.WindowConstants; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; @@ -142,8 +144,9 @@ public class Gui private JList m_deobfClasses; private JEditorPane m_editor; private JPanel m_infoPanel; - private BoxHighlightPainter m_obfuscatedHighlightPainter; - private BoxHighlightPainter m_deobfuscatedHighlightPainter; + private ObfuscatedHighlightPainter m_obfuscatedHighlightPainter; + private DeobfuscatedHighlightPainter m_deobfuscatedHighlightPainter; + private SelectionHighlightPainter m_selectionHighlightPainter; private JTree m_inheritanceTree; private JTree m_callsTree; private JList m_tokens; @@ -250,6 +253,7 @@ public class Gui DefaultSyntaxKit.initKit(); m_obfuscatedHighlightPainter = new ObfuscatedHighlightPainter(); m_deobfuscatedHighlightPainter = new DeobfuscatedHighlightPainter(); + m_selectionHighlightPainter = new SelectionHighlightPainter(); m_editor = new JEditorPane(); m_editor.setEditable( false ); m_editor.setCaret( new BrowserCaret() ); @@ -756,14 +760,64 @@ public class Gui m_editor.setText( source ); } - public void showToken( Token token ) + public void showToken( final Token token ) { if( token == null ) { throw new IllegalArgumentException( "Token cannot be null!" ); } + + // set the caret position to the token m_editor.setCaretPosition( token.start ); m_editor.grabFocus(); + + try + { + // make sure the token is visible in the scroll window + Rectangle start = m_editor.modelToView( token.start ); + Rectangle end = m_editor.modelToView( token.end ); + Rectangle show = start.union( end ); + show.grow( 0, start.height*6 ); + m_editor.scrollRectToVisible( show ); + } + catch( BadLocationException ex ) + { + throw new Error( ex ); + } + + // highlight the token momentarily + final Timer timer = new Timer( 200, new ActionListener( ) + { + private int m_counter = 0; + private Object m_highlight = null; + + @Override + public void actionPerformed( ActionEvent event ) + { + if( m_counter % 2 == 0 ) + { + try + { + m_highlight = m_editor.getHighlighter().addHighlight( token.start, token.end, m_selectionHighlightPainter ); + } + catch( BadLocationException ex ) + { + // don't care + } + } + else if( m_highlight != null ) + { + m_editor.getHighlighter().removeHighlight( m_highlight ); + } + + if( m_counter++ > 6 ) + { + Timer timer = (Timer)event.getSource(); + timer.stop(); + } + } + } ); + timer.start(); } public void showTokens( Collection tokens ) @@ -790,6 +844,7 @@ public class Gui // remove any old highlighters m_editor.getHighlighter().removeAllHighlights(); + // color things based on the index if( obfuscatedTokens != null ) { diff --git a/src/cuchaz/enigma/gui/SelectionHighlightPainter.java b/src/cuchaz/enigma/gui/SelectionHighlightPainter.java new file mode 100644 index 00000000..35f94518 --- /dev/null +++ b/src/cuchaz/enigma/gui/SelectionHighlightPainter.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.gui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; + +import javax.swing.text.Highlighter; +import javax.swing.text.JTextComponent; + +public class SelectionHighlightPainter implements Highlighter.HighlightPainter +{ + @Override + public void paint( Graphics g, int start, int end, Shape shape, JTextComponent text ) + { + // draw a thick border + Graphics2D g2d = (Graphics2D)g; + Rectangle bounds = BoxHighlightPainter.getBounds( text, start, end ); + g2d.setColor( Color.black ); + g2d.setStroke( new BasicStroke( 2.0f ) ); + g2d.drawRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); + } +} -- cgit v1.2.3 From b4b9f296e9bcdbfcabb1cf49885a1747ce094c61 Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 22 Aug 2014 01:41:41 -0400 Subject: fixed recursion of field reference nodes tweaked scroll into view for showing tokens --- src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java | 4 ++++ src/cuchaz/enigma/gui/BoxHighlightPainter.java | 3 ++- src/cuchaz/enigma/gui/Gui.java | 16 +++++++++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java index 645e6821..94d0da7e 100644 --- a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java @@ -86,6 +86,10 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re { ((BehaviorReferenceTreeNode)node).load( index, true ); } + else if( node instanceof FieldReferenceTreeNode ) + { + ((FieldReferenceTreeNode)node).load( index, true ); + } } } } diff --git a/src/cuchaz/enigma/gui/BoxHighlightPainter.java b/src/cuchaz/enigma/gui/BoxHighlightPainter.java index 2c118340..30b2b021 100644 --- a/src/cuchaz/enigma/gui/BoxHighlightPainter.java +++ b/src/cuchaz/enigma/gui/BoxHighlightPainter.java @@ -61,7 +61,8 @@ public abstract class BoxHighlightPainter implements Highlighter.HighlightPainte } catch( BadLocationException ex ) { - throw new Error( ex ); + // don't care... just return something + return new Rectangle( 0, 0, 0, 0 ); } } } diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 914359b4..dd82b8e0 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -54,6 +54,7 @@ import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.WindowConstants; import javax.swing.event.CaretEvent; @@ -776,9 +777,16 @@ public class Gui // make sure the token is visible in the scroll window Rectangle start = m_editor.modelToView( token.start ); Rectangle end = m_editor.modelToView( token.end ); - Rectangle show = start.union( end ); - show.grow( 0, start.height*6 ); - m_editor.scrollRectToVisible( show ); + final Rectangle show = start.union( end ); + show.grow( start.width*10, start.height*6 ); + SwingUtilities.invokeLater( new Runnable( ) + { + @Override + public void run( ) + { + m_editor.scrollRectToVisible( show ); + } + } ); } catch( BadLocationException ex ) { @@ -818,6 +826,8 @@ public class Gui } } ); timer.start(); + + redraw(); } public void showTokens( Collection tokens ) -- cgit v1.2.3 From d9294b6e114303f7fbd461ff8b4d6fd7e1db4762 Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 22 Aug 2014 01:45:42 -0400 Subject: packaged for 0.3 beta --- src/cuchaz/enigma/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java index 0b431c71..7ae778dd 100644 --- a/src/cuchaz/enigma/Constants.java +++ b/src/cuchaz/enigma/Constants.java @@ -14,7 +14,7 @@ package cuchaz.enigma; public class Constants { public static final String Name = "Enigma"; - public static final String Version = "0.2 beta"; + public static final String Version = "0.3 beta"; 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 -- cgit v1.2.3 From a700b403d790c23989da524c934f0185b87c7b32 Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 23 Aug 2014 16:20:15 -0400 Subject: added export command with progress bar --- src/cuchaz/enigma/Deobfuscator.java | 78 +++++++++++++++++++++++---- src/cuchaz/enigma/gui/Gui.java | 38 +++++++++---- src/cuchaz/enigma/gui/GuiController.java | 26 ++++++++- src/cuchaz/enigma/gui/GuiTricks.java | 25 +++++++++ src/cuchaz/enigma/gui/ProgressDialog.java | 89 +++++++++++++++++++++++++++++++ 5 files changed, 233 insertions(+), 23 deletions(-) create mode 100644 src/cuchaz/enigma/gui/GuiTricks.java create mode 100644 src/cuchaz/enigma/gui/ProgressDialog.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 38f7af56..5d87ad0a 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -11,6 +11,7 @@ package cuchaz.enigma; import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; import java.util.List; @@ -44,6 +45,12 @@ import cuchaz.enigma.mapping.Translator; public class Deobfuscator { + public interface ProgressListener + { + void init( int totalWork ); + void onProgress( int numDone, String message ); + } + private File m_file; private JarFile m_jar; private DecompilerSettings m_settings; @@ -137,7 +144,7 @@ public class Deobfuscator } } - public SourceIndex getSource( String className ) + public CompilationUnit getSourceTree( String className ) { // is this class deobfuscated? // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out @@ -156,19 +163,18 @@ public class Deobfuscator AstBuilder builder = new AstBuilder( context ); builder.addType( resolvedType ); builder.runTransformations( null ); - CompilationUnit root = builder.getCompilationUnit(); + return builder.getCompilationUnit(); + } + + public SourceIndex getSourceIndex( CompilationUnit sourceTree, String source ) + { + // build the source index + SourceIndex index = new SourceIndex( source ); + sourceTree.acceptVisitor( new SourceIndexVisitor(), index ); - // render the AST into source - StringWriter buf = new StringWriter(); - root.acceptVisitor( new InsertParenthesesVisitor(), null ); // DEBUG //root.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); - root.acceptVisitor( new JavaOutputVisitor( new PlainTextOutput( buf ), m_settings ), null ); - - // build the source index - SourceIndex index = new SourceIndex( buf.toString() ); - root.acceptVisitor( new SourceIndexVisitor(), index ); - + /* DEBUG for( Token token : index.referenceTokens() ) { @@ -180,6 +186,56 @@ public class Deobfuscator return index; } + public String getSource( CompilationUnit sourceTree ) + { + // render the AST into source + StringWriter buf = new StringWriter(); + sourceTree.acceptVisitor( new InsertParenthesesVisitor(), null ); + sourceTree.acceptVisitor( new JavaOutputVisitor( new PlainTextOutput( buf ), m_settings ), null ); + return buf.toString(); + } + + public void writeSources( File dirOut, ProgressListener progress ) + throws IOException + { + int numClasses = m_jarIndex.getObfClassNames().size(); + if( progress != null ) + { + progress.init( numClasses ); + } + int i = 0; + + // DEOBFUSCATE ALL THE THINGS!! @_@ + for( String obfClassName : m_jarIndex.getObfClassNames() ) + { + // skip inner classes + if( m_jarIndex.getOuterClass( obfClassName ) != null ) + { + continue; + } + + ClassEntry deobfClassEntry = deobfuscateEntry( new ClassEntry( obfClassName ) ); + if( progress != null ) + { + progress.onProgress( i++, deobfClassEntry.toString() ); + } + + // get the source + String source = getSource( getSourceTree( obfClassName ) ); + + // write the file + File file = new File( dirOut, deobfClassEntry.getName().replace( '.', '/' ) + ".java" ); + file.getParentFile().mkdirs(); + try( FileWriter out = new FileWriter( file ) ) + { + out.write( source ); + } + } + + // done! + progress.onProgress( numClasses, "Done!" ); + } + public T obfuscateEntry( T deobfEntry ) { if( deobfEntry == null ) diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index dd82b8e0..febdfd43 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -15,7 +15,6 @@ import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.FlowLayout; -import java.awt.Font; import java.awt.GridLayout; import java.awt.Rectangle; import java.awt.event.ActionEvent; @@ -169,6 +168,7 @@ public class Gui private EntryReference m_reference; private JFileChooser m_jarFileChooser; private JFileChooser m_mappingsFileChooser; + private JFileChooser m_exportFileChooser; public Gui( ) { @@ -177,6 +177,8 @@ public class Gui // init file choosers m_jarFileChooser = new JFileChooser(); m_mappingsFileChooser = new JFileChooser(); + m_exportFileChooser = new JFileChooser(); + m_exportFileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); // init frame m_frame = new JFrame( Constants.Name ); @@ -636,6 +638,22 @@ public class Gui m_closeMappingsMenu = item; } menu.addSeparator(); + { + JMenuItem item = new JMenuItem( "Export..." ); + menu.add( item ); + item.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + if( m_exportFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) + { + m_controller.export( m_exportFileChooser.getSelectedFile() ); + } + } + } ); + } + menu.addSeparator(); { JMenuItem item = new JMenuItem( "Exit" ); menu.add( item ); @@ -686,6 +704,11 @@ public class Gui m_frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); } + public JFrame getFrame( ) + { + return m_frame; + } + public GuiController getController( ) { return m_controller; @@ -887,7 +910,7 @@ public class Gui { m_infoPanel.removeAll(); JLabel label = new JLabel( "No identifier selected" ); - unboldLabel( label ); + GuiTricks.unboldLabel( label ); label.setHorizontalAlignment( JLabel.CENTER ); m_infoPanel.add( label ); @@ -975,7 +998,7 @@ public class Gui label.setPreferredSize( new Dimension( 100, label.getPreferredSize().height ) ); panel.add( label ); - panel.add( unboldLabel( new JLabel( value, JLabel.LEFT ) ) ); + panel.add( GuiTricks.unboldLabel( new JLabel( value, JLabel.LEFT ) ) ); } private void onCaretMove( int pos ) @@ -1059,7 +1082,7 @@ public class Gui // abort the rename JPanel panel = (JPanel)m_infoPanel.getComponent( 0 ); panel.remove( panel.getComponentCount() - 1 ); - panel.add( unboldLabel( new JLabel( m_reference.entry.getName(), JLabel.LEFT ) ) ); + panel.add( GuiTricks.unboldLabel( new JLabel( m_reference.entry.getName(), JLabel.LEFT ) ) ); m_editor.grabFocus(); @@ -1203,13 +1226,6 @@ public class Gui } } - private JLabel unboldLabel( JLabel label ) - { - Font font = label.getFont(); - label.setFont( font.deriveFont( font.getStyle() & ~Font.BOLD ) ); - return label; - } - private void redraw( ) { m_frame.validate(); diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index a35db056..cf4f002e 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -20,6 +20,7 @@ import java.util.List; import com.google.common.collect.Lists; import com.google.common.collect.Queues; +import com.strobel.decompiler.languages.java.ast.CompilationUnit; import cuchaz.enigma.Deobfuscator; import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; @@ -106,6 +107,27 @@ public class GuiController refreshCurrentClass(); } + public void export( final File dirOut ) + { + new Thread( ) + { + @Override + public void run( ) + { + try + { + ProgressDialog progress = new ProgressDialog( m_gui.getFrame() ); + m_deobfuscator.writeSources( dirOut, progress ); + progress.close(); + } + catch( IOException ex ) + { + throw new Error( ex ); + } + } + }.start(); + } + public Token getToken( int pos ) { if( m_index == null ) @@ -295,7 +317,9 @@ public class GuiController public void run( ) { // decompile,deobfuscate the bytecode - m_index = m_deobfuscator.getSource( classEntry.getClassName() ); + CompilationUnit sourceTree = m_deobfuscator.getSourceTree( classEntry.getClassName() ); + String source = m_deobfuscator.getSource( sourceTree ); + m_index = m_deobfuscator.getSourceIndex( sourceTree, source ); m_gui.setSource( m_index.getSource() ); if( obfReference != null ) { diff --git a/src/cuchaz/enigma/gui/GuiTricks.java b/src/cuchaz/enigma/gui/GuiTricks.java new file mode 100644 index 00000000..c79f4329 --- /dev/null +++ b/src/cuchaz/enigma/gui/GuiTricks.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * 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.Font; + +import javax.swing.JLabel; + +public class GuiTricks +{ + public static JLabel unboldLabel( JLabel label ) + { + Font font = label.getFont(); + label.setFont( font.deriveFont( font.getStyle() & ~Font.BOLD ) ); + return label; + } +} diff --git a/src/cuchaz/enigma/gui/ProgressDialog.java b/src/cuchaz/enigma/gui/ProgressDialog.java new file mode 100644 index 00000000..40ac6a69 --- /dev/null +++ b/src/cuchaz/enigma/gui/ProgressDialog.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * 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.BorderLayout; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; + +import javax.swing.BorderFactory; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.WindowConstants; + +import cuchaz.enigma.Constants; +import cuchaz.enigma.Deobfuscator.ProgressListener; + +public class ProgressDialog implements ProgressListener +{ + private JFrame m_frame; + private JLabel m_text; + private JProgressBar m_progress; + + public ProgressDialog( JFrame parent ) + { + // init frame + m_frame = new JFrame( Constants.Name + " - Export" ); + final Container pane = m_frame.getContentPane(); + FlowLayout layout = new FlowLayout(); + layout.setAlignment( FlowLayout.LEFT ); + pane.setLayout( layout ); + + pane.add( new JLabel( "Decompiling classes..." ) ); + + // set up the progress bar + JPanel panel = new JPanel(); + pane.add( panel ); + panel.setLayout( new BorderLayout() ); + m_text = GuiTricks.unboldLabel( new JLabel() ); + m_progress = new JProgressBar(); + m_text.setBorder( BorderFactory.createEmptyBorder( 0, 0, 10, 0 ) ); + panel.add( m_text, BorderLayout.NORTH ); + panel.add( m_progress, BorderLayout.CENTER ); + panel.setPreferredSize( new Dimension( 360, 50 ) ); + + // show the frame + pane.doLayout(); + m_frame.setSize( 400, 120 ); + m_frame.setResizable( false ); + m_frame.setLocationRelativeTo( parent ); + m_frame.setVisible( true ); + m_frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); + } + + public void close( ) + { + m_frame.dispose(); + } + + @Override + public void init( int totalWork ) + { + m_text.setText( "Decompiling " + totalWork + " classes..." ); + m_progress.setMinimum( 0 ); + m_progress.setMaximum( totalWork ); + m_progress.setValue( 0 ); + } + + @Override + public void onProgress( int numDone, String message ) + { + m_text.setText( message ); + m_progress.setValue( numDone ); + + // update the frame + m_frame.validate(); + m_frame.repaint(); + } +} -- cgit v1.2.3 From 8fa1741b621644ef84a9395a4c395d4ff3a89207 Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 23 Aug 2014 23:43:31 -0400 Subject: moved all classes from the default package into a package called "default" so they can be properly imported by other classes --- src/cuchaz/enigma/Deobfuscator.java | 49 ++++----- src/cuchaz/enigma/TranslatingTypeLoader.java | 19 +++- src/cuchaz/enigma/analysis/JarClassIterator.java | 45 ++++---- src/cuchaz/enigma/analysis/JarIndex.java | 40 ++++--- src/cuchaz/enigma/bytecode/ClassRenamer.java | 115 +++++++++++++++++++++ src/cuchaz/enigma/bytecode/ClassTranslator.java | 64 ++---------- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 6 +- src/cuchaz/enigma/gui/Gui.java | 3 +- src/cuchaz/enigma/gui/GuiController.java | 9 +- src/cuchaz/enigma/gui/GuiTricks.java | 18 ++++ src/cuchaz/enigma/mapping/ClassEntry.java | 25 +++++ .../enigma/mapping/IllegalNameException.java | 22 +++- src/cuchaz/enigma/mapping/NameValidator.java | 8 +- 13 files changed, 298 insertions(+), 125 deletions(-) create mode 100644 src/cuchaz/enigma/bytecode/ClassRenamer.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 5d87ad0a..ee414fa2 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -17,6 +17,8 @@ import java.io.StringWriter; import java.util.List; import java.util.jar.JarFile; +import javassist.bytecode.Descriptor; + import com.strobel.assembler.metadata.MetadataSystem; import com.strobel.assembler.metadata.TypeDefinition; import com.strobel.decompiler.DecompilerContext; @@ -118,28 +120,30 @@ public class Deobfuscator public void getSeparatedClasses( List obfClasses, List deobfClasses ) { - for( String obfClassName : m_jarIndex.getObfClassNames() ) + for( ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries() ) { // skip inner classes - if( m_jarIndex.getOuterClass( obfClassName ) != null ) + if( m_jarIndex.getOuterClass( obfClassEntry.getName() ) != null ) { continue; } // separate the classes - ClassMapping classMapping = m_mappings.getClassByObf( obfClassName ); - if( classMapping != null && !classMapping.getObfName().equals( classMapping.getDeobfName() ) ) + ClassEntry deobfClassEntry = deobfuscateEntry( obfClassEntry ); + if( !deobfClassEntry.equals( obfClassEntry ) ) { - deobfClasses.add( classMapping.getDeobfName() ); + // if the class has a mapping, clearly it's deobfuscated + deobfClasses.add( deobfClassEntry.getName() ); } - else if( obfClassName.indexOf( '/' ) >= 0 ) + else if( !obfClassEntry.getPackageName().equals( "default" ) ) { - // this class is in a package and therefore is not obfuscated - deobfClasses.add( obfClassName ); + // also call it deobufscated if it's not in the "default" package + deobfClasses.add( obfClassEntry.getName() ); } else { - obfClasses.add( obfClassName ); + // otherwise, assume it's still obfuscated + obfClasses.add( obfClassEntry.getName() ); } } } @@ -198,7 +202,7 @@ public class Deobfuscator public void writeSources( File dirOut, ProgressListener progress ) throws IOException { - int numClasses = m_jarIndex.getObfClassNames().size(); + int numClasses = m_jarIndex.getObfClassEntries().size(); if( progress != null ) { progress.init( numClasses ); @@ -206,22 +210,22 @@ public class Deobfuscator int i = 0; // DEOBFUSCATE ALL THE THINGS!! @_@ - for( String obfClassName : m_jarIndex.getObfClassNames() ) + for( ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries() ) { // skip inner classes - if( m_jarIndex.getOuterClass( obfClassName ) != null ) + if( obfClassEntry.isInnerClass() ) { continue; } - ClassEntry deobfClassEntry = deobfuscateEntry( new ClassEntry( obfClassName ) ); + ClassEntry deobfClassEntry = deobfuscateEntry( new ClassEntry( obfClassEntry ) ); if( progress != null ) { progress.onProgress( i++, deobfClassEntry.toString() ); } // get the source - String source = getSource( getSourceTree( obfClassName ) ); + String source = getSource( getSourceTree( obfClassEntry.getName() ) ); // write the file File file = new File( dirOut, deobfClassEntry.getName().replace( '.', '/' ) + ".java" ); @@ -284,7 +288,7 @@ public class Deobfuscator { if( obfEntry instanceof ClassEntry ) { - m_renamer.setClassName( (ClassEntry)obfEntry, newName ); + m_renamer.setClassName( (ClassEntry)obfEntry, Descriptor.toJvmName( newName ) ); } else if( obfEntry instanceof FieldEntry ) { @@ -348,21 +352,18 @@ public class Deobfuscator { if( obfEntry instanceof ClassEntry ) { - if( obfEntry.getName().indexOf( '$' ) >= 0 ) + ClassEntry obfClassEntry = (ClassEntry)obfEntry; + if( obfClassEntry.isInnerClass() ) { - String[] parts = obfEntry.getName().split( "\\$" ); - assert( parts.length == 2 ); // not supporting recursively-nested classes - String outerClassName = parts[0]; - String innerClassName = parts[1]; - // both classes must be in the list - return m_jarIndex.getObfClassNames().contains( outerClassName ) - && m_jarIndex.getObfClassNames().contains( innerClassName ); + return m_jarIndex.getObfClassEntries().contains( obfClassEntry.getOuterClassEntry() ) + && m_jarIndex.getObfClassEntries().contains( obfClassEntry.getInnerClassName() ); + // TODO: make sure this works for the inner class!! } else { // class must be in the list - return m_jarIndex.getObfClassNames().contains( obfEntry.getName() ); + return m_jarIndex.getObfClassEntries().contains( obfEntry ); } } else diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index cc863646..e7e941a9 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -13,6 +13,7 @@ package cuchaz.enigma; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -30,6 +31,7 @@ import com.strobel.assembler.metadata.ITypeLoader; import cuchaz.enigma.analysis.BridgeFixer; import cuchaz.enigma.analysis.JarIndex; +import cuchaz.enigma.bytecode.ClassRenamer; import cuchaz.enigma.bytecode.ClassTranslator; import cuchaz.enigma.bytecode.InnerClassWriter; import cuchaz.enigma.bytecode.MethodParameterWriter; @@ -99,22 +101,29 @@ public class TranslatingTypeLoader implements ITypeLoader return null; } - /* DEBUG + // DEBUG if( !Arrays.asList( "java", "org", "io" ).contains( deobfClassName.split( "/" )[0] ) ) { System.out.println( String.format( "Looking for %s (%s)", deobfClassEntry.getName(), obfClassEntry.getName() ) ); } - */ + // // get the jar entry String classFileName; if( obfClassEntry.isInnerClass() ) { + // use just the inner class simple name for inner classes classFileName = obfClassEntry.getInnerClassName(); } + else if( obfClassEntry.getPackageName().equals( "default" ) ) + { + // use the outer class simple name for classes in the "default" package + classFileName = obfClassEntry.getSimpleName(); + } else { - classFileName = obfClassEntry.getOuterClassName(); + // otherwise, just use the class name (ie for classes in packages) + classFileName = obfClassEntry.getName(); } JarEntry entry = m_jar.getJarEntry( classFileName + ".class" ); if( entry == null ) @@ -147,6 +156,10 @@ public class TranslatingTypeLoader implements ITypeLoader classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, buf ) ); CtClass c = classPool.get( javaClassFileName ); + // we moved a lot of classes out of the default package into the "default" package + // make sure all the class references are consistent + ClassRenamer.moveAllClassesOutOfDefaultPackage( c, "default" ); + // reconstruct inner classes new InnerClassWriter( m_jarIndex ).write( c ); diff --git a/src/cuchaz/enigma/analysis/JarClassIterator.java b/src/cuchaz/enigma/analysis/JarClassIterator.java index cf6df805..6c9f1245 100644 --- a/src/cuchaz/enigma/analysis/JarClassIterator.java +++ b/src/cuchaz/enigma/analysis/JarClassIterator.java @@ -28,6 +28,7 @@ import javassist.bytecode.Descriptor; import com.beust.jcommander.internal.Lists; import cuchaz.enigma.Constants; +import cuchaz.enigma.mapping.ClassEntry; public class JarClassIterator implements Iterator { @@ -35,14 +36,23 @@ public class JarClassIterator implements Iterator private Iterator m_iter; public JarClassIterator( JarFile jar ) - { - this( jar, getClassEntries( jar ) ); - } - - public JarClassIterator( JarFile jar, List entries ) { m_jar = jar; - m_iter = entries.iterator(); + + // get the jar entries that correspond to classes + List classEntries = Lists.newArrayList(); + Enumeration entries = m_jar.entries(); + while( entries.hasMoreElements() ) + { + JarEntry entry = entries.nextElement(); + + // is this a class file? + if( entry.getName().endsWith( ".class" ) ) + { + classEntries.add( entry ); + } + } + m_iter = classEntries.iterator(); } @Override @@ -79,19 +89,13 @@ public class JarClassIterator implements Iterator } } - // determine the class name (ie chop off the ".class") - String className = Descriptor.toJavaName( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) ); - // get a javassist handle for the class + String className = Descriptor.toJavaName( getClassEntry( entry ).getName() ); ClassPool classPool = new ClassPool(); classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); return classPool.get( className ); } - catch( IOException ex ) - { - throw new Error( "Unable to read class: " + entry.getName() ); - } - catch( NotFoundException ex ) + catch( IOException | NotFoundException ex ) { throw new Error( "Unable to load class: " + entry.getName() ); } @@ -103,9 +107,9 @@ public class JarClassIterator implements Iterator throw new UnsupportedOperationException(); } - public static List getClassEntries( JarFile jar ) + public static List getClassEntries( JarFile jar ) { - List classes = Lists.newArrayList(); + List classEntries = Lists.newArrayList(); Enumeration entries = jar.entries(); while( entries.hasMoreElements() ) { @@ -114,10 +118,10 @@ public class JarClassIterator implements Iterator // is this a class file? if( !entry.isDirectory() && entry.getName().endsWith( ".class" ) ) { - classes.add( entry ); + classEntries.add( getClassEntry( entry ) ); } } - return classes; + return classEntries; } public static Iterable classes( final JarFile jar ) @@ -131,4 +135,9 @@ public class JarClassIterator implements Iterator } }; } + + private static ClassEntry getClassEntry( JarEntry entry ) + { + return new ClassEntry( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) ); + } } diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 315a2864..cdaca372 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -17,7 +17,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.jar.JarEntry; import java.util.jar.JarFile; import javassist.CannotCompileException; @@ -35,13 +34,12 @@ import javassist.expr.MethodCall; import javassist.expr.NewExpr; import com.google.common.collect.HashMultimap; -import com.google.common.collect.HashMultiset; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; -import com.google.common.collect.Multiset; import com.google.common.collect.Sets; +import cuchaz.enigma.bytecode.ClassRenamer; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; @@ -53,7 +51,7 @@ import cuchaz.enigma.mapping.Translator; public class JarIndex { - private Set m_obfClassNames; + private Set m_obfClassEntries; private Ancestries m_ancestries; private Multimap m_methodImplementations; private Multimap> m_behaviorReferences; @@ -64,7 +62,7 @@ public class JarIndex public JarIndex( ) { - m_obfClassNames = Sets.newHashSet(); + m_obfClassEntries = Sets.newHashSet(); m_ancestries = new Ancestries(); m_methodImplementations = HashMultimap.create(); m_behaviorReferences = HashMultimap.create(); @@ -77,15 +75,20 @@ public class JarIndex public void indexJar( JarFile jar ) { // pass 1: read the class names - for( JarEntry entry : JarClassIterator.getClassEntries( jar ) ) + for( ClassEntry classEntry : JarClassIterator.getClassEntries( jar ) ) { - String className = entry.getName().substring( 0, entry.getName().length() - 6 ); - m_obfClassNames.add( Descriptor.toJvmName( className ) ); + if( classEntry.isInDefaultPackage() ) + { + // move out of default package + classEntry = new ClassEntry( "default/" + classEntry.getName() ); + } + m_obfClassEntries.add( classEntry ); } // pass 2: index the types, methods for( CtClass c : JarClassIterator.classes( jar ) ) { + fixClass( c ); m_ancestries.addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); for( CtBehavior behavior : c.getDeclaredBehaviors() ) { @@ -96,8 +99,10 @@ public class JarIndex // pass 2: index inner classes and anonymous classes for( CtClass c : JarClassIterator.classes( jar ) ) { + fixClass( c ); + String outerClassName = findOuterClass( c ); - if( outerClassName != null )// /* TEMP */ && false ) + if( outerClassName != null ) { String innerClassName = Descriptor.toJvmName( c.getName() ); m_innerClasses.put( outerClassName, innerClassName ); @@ -127,6 +132,17 @@ public class JarIndex renameClasses( renames ); } + private void fixClass( CtClass c ) + { + ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); + if( classEntry.isInDefaultPackage() ) + { + // move class out of default package + classEntry = new ClassEntry( "default/" + classEntry.getName() ); + ClassRenamer.moveAllClassesOutOfDefaultPackage( c, "default" ); + } + } + private void indexBehavior( CtBehavior behavior ) { // get the method entry @@ -270,7 +286,7 @@ public class JarIndex else if( callerClasses.size() > 1 ) { // TEMP - System.out.println( "WARNING: Illegal class called by more than one class!" + callerClasses ); + System.out.println( "WARNING: Illegal constructor called by more than one class!" + callerClasses ); } } @@ -423,9 +439,9 @@ public class JarIndex return true; } - public Set getObfClassNames( ) + public Set getObfClassEntries( ) { - return m_obfClassNames; + return m_obfClassEntries; } public Ancestries getAncestries( ) diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java new file mode 100644 index 00000000..cba58617 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * 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.util.Map; +import java.util.Set; + +import javassist.ClassMap; +import javassist.CtClass; +import javassist.bytecode.ConstPool; +import javassist.bytecode.Descriptor; +import javassist.bytecode.InnerClassesAttribute; + +import com.beust.jcommander.internal.Sets; +import com.google.common.collect.Maps; + +import cuchaz.enigma.mapping.ClassEntry; + +public class ClassRenamer +{ + public static void renameClasses( CtClass c, Map map ) + { + // build the map used by javassist + ClassMap nameMap = new ClassMap(); + for( Map.Entry entry : map.entrySet() ) + { + nameMap.put( entry.getKey().getName(), entry.getValue().getName() ); + } + c.replaceClassName( nameMap ); + + // translate the names in the InnerClasses attribute + ConstPool constants = c.getClassFile().getConstPool(); + InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute( InnerClassesAttribute.tag ); + if( attr != null ) + { + for( int i=0; i ATTR: %s,%s,%s", + obfClassEntry, deobfClassEntry, + attr.outerClass( i ), + attr.innerClass( i ), + attr.innerName( i ) + ) ); + */ + } + } + } + + public static Set getAllClassEntries( CtClass c ) + { + // get the classes that javassist knows about + final Set entries = Sets.newHashSet(); + ClassMap map = new ClassMap( ) + { + @Override + public Object get( Object obj ) + { + if( obj instanceof String ) + { + entries.add( new ClassEntry( (String)obj ) ); + } + return null; + } + private static final long serialVersionUID = -202160293602070641L; + }; + c.replaceClassName( map ); + + // also check InnerClassesAttribute + InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute( InnerClassesAttribute.tag ); + if( attr != null ) + { + for( int i=0; i map = Maps.newHashMap(); + for( ClassEntry classEntry : ClassRenamer.getAllClassEntries( c ) ) + { + if( classEntry.isInDefaultPackage() ) + { + map.put( classEntry, new ClassEntry( newPackageName + "/" + classEntry.getName() ) ); + } + } + ClassRenamer.renameClasses( c, map ); + } +} diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index 9ce06a58..885b45fe 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java @@ -10,18 +10,16 @@ ******************************************************************************/ package cuchaz.enigma.bytecode; -import java.util.Set; +import java.util.Map; -import javassist.ClassMap; import javassist.CtBehavior; import javassist.CtClass; import javassist.CtField; import javassist.CtMethod; import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; -import javassist.bytecode.InnerClassesAttribute; -import com.beust.jcommander.internal.Sets; +import com.beust.jcommander.internal.Maps; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.FieldEntry; @@ -136,61 +134,11 @@ public class ClassTranslator // translate all the class names referenced in the code // the above code only changed method/field/reference names and types, but not the class names themselves - Set classEntries = getAllClassEntries( c ); - ClassMap map = new ClassMap(); - for( ClassEntry obfClassEntry : classEntries ) + Map map = Maps.newHashMap(); + for( ClassEntry obfClassEntry : ClassRenamer.getAllClassEntries( c ) ) { - map.put( obfClassEntry.getName(), m_translator.translateEntry( obfClassEntry ).getName() ); + map.put( obfClassEntry, m_translator.translateEntry( obfClassEntry ) ); } - c.replaceClassName( map ); - - // translate the names in the InnerClasses attribute - InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute( InnerClassesAttribute.tag ); - if( attr != null ) - { - for( int i=0; i ATTR: %s,%s,%s", - obfClassEntry, deobfClassEntry, - attr.outerClass( i ), - attr.innerClass( i ), - attr.innerName( i ) - ) ); - */ - } - } - } - - private Set getAllClassEntries( CtClass c ) - { - final Set entries = Sets.newHashSet(); - ClassMap map = new ClassMap( ) - { - @Override - public Object get( Object obj ) - { - if( obj instanceof String ) - { - entries.add( new ClassEntry( (String)obj ) ); - } - return null; - } - private static final long serialVersionUID = -202160293602070641L; - }; - c.replaceClassName( map ); - return entries; + ClassRenamer.renameClasses( c, map ); } } diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java index c412b1aa..2fb5fe0f 100644 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -42,7 +42,7 @@ public class InnerClassWriter else { // this is an inner class, rename it to outer$inner - ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfClassName ); + ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + new ClassEntry( obfClassName ).getSimpleName() ); c.setName( obfClassEntry.getName() ); } @@ -60,8 +60,8 @@ public class InnerClassWriter c.getClassFile().addAttribute( attr ); for( String obfInnerClassName : obfInnerClassNames ) { - // deobfuscate the class names - ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfInnerClassName ); + // get the new inner class name + ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + new ClassEntry( obfInnerClassName ).getSimpleName() ); // here's what the JVM spec says about the InnerClasses attribute // append( inner, outer of inner if inner is member of outer 0 ow, name after $ if inner not anonymous 0 ow, flags ); diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index febdfd43..4e636064 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -1073,8 +1073,9 @@ public class Gui } catch( IllegalNameException ex ) { - ex.printStackTrace( System.err ); text.setBorder( BorderFactory.createLineBorder( Color.red, 1 ) ); + text.setToolTipText( ex.getReason() ); + GuiTricks.showToolTipNow( text ); } return; } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index cf4f002e..90bce520 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -114,16 +114,19 @@ public class GuiController @Override public void run( ) { + ProgressDialog progress = new ProgressDialog( m_gui.getFrame() ); try { - ProgressDialog progress = new ProgressDialog( m_gui.getFrame() ); m_deobfuscator.writeSources( dirOut, progress ); - progress.close(); } - catch( IOException ex ) + catch( Exception ex ) { throw new Error( ex ); } + finally + { + progress.close(); + } } }.start(); } diff --git a/src/cuchaz/enigma/gui/GuiTricks.java b/src/cuchaz/enigma/gui/GuiTricks.java index c79f4329..9b889ef4 100644 --- a/src/cuchaz/enigma/gui/GuiTricks.java +++ b/src/cuchaz/enigma/gui/GuiTricks.java @@ -11,8 +11,11 @@ package cuchaz.enigma.gui; import java.awt.Font; +import java.awt.event.MouseEvent; +import javax.swing.JComponent; import javax.swing.JLabel; +import javax.swing.ToolTipManager; public class GuiTricks { @@ -22,4 +25,19 @@ public class GuiTricks label.setFont( font.deriveFont( font.getStyle() & ~Font.BOLD ) ); return label; } + + public static void showToolTipNow( JComponent component ) + { + // HACKHACK: trick the tooltip manager into showing the tooltip right now + ToolTipManager manager = ToolTipManager.sharedInstance(); + int oldDelay = manager.getInitialDelay(); + manager.setInitialDelay( 0 ); + manager.mouseMoved( new MouseEvent( + component, + MouseEvent.MOUSE_MOVED, + System.currentTimeMillis(), + 0, 0, 0, 0, false + ) ); + manager.setInitialDelay( oldDelay ); + } } diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index dad6da90..fdb7c2c5 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -110,4 +110,29 @@ public class ClassEntry implements Entry, Serializable { return new ClassEntry( getOuterClassName() ); } + + public boolean isInDefaultPackage( ) + { + return m_name.indexOf( '/' ) < 0; + } + + public String getPackageName( ) + { + int pos = m_name.lastIndexOf( '/' ); + if( pos > 0 ) + { + return m_name.substring( 0, pos ); + } + return null; + } + + public String getSimpleName( ) + { + int pos = m_name.lastIndexOf( '/' ); + if( pos > 0 ) + { + return m_name.substring( pos + 1 ); + } + return m_name; + } } diff --git a/src/cuchaz/enigma/mapping/IllegalNameException.java b/src/cuchaz/enigma/mapping/IllegalNameException.java index 560e5d93..830f05c4 100644 --- a/src/cuchaz/enigma/mapping/IllegalNameException.java +++ b/src/cuchaz/enigma/mapping/IllegalNameException.java @@ -15,15 +15,35 @@ public class IllegalNameException extends RuntimeException private static final long serialVersionUID = -2279910052561114323L; private String m_name; + private String m_reason; public IllegalNameException( String name ) + { + this( name, null ); + } + + public IllegalNameException( String name, String reason ) { m_name = name; + m_reason = reason; + } + + public String getReason( ) + { + return m_reason; } @Override public String getMessage( ) { - return "Illegal name: " + m_name; + StringBuilder buf = new StringBuilder(); + buf.append( "Illegal name: " ); + buf.append( m_name ); + if( m_reason != null ) + { + buf.append( " because " ); + buf.append( m_reason ); + } + return buf.toString(); } } diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java index a8421fa5..6df893fb 100644 --- a/src/cuchaz/enigma/mapping/NameValidator.java +++ b/src/cuchaz/enigma/mapping/NameValidator.java @@ -59,7 +59,11 @@ public class NameValidator { if( name == null || !ClassPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) { - throw new IllegalNameException( name ); + throw new IllegalNameException( name, "This doesn't look like a legal class name" ); + } + if( new ClassEntry( name ).getPackageName() == null ) + { + throw new IllegalNameException( name, "Classes must be in a package" ); } return Descriptor.toJvmName( name ); } @@ -68,7 +72,7 @@ public class NameValidator { if( name == null || !IdentifierPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) { - throw new IllegalNameException( name ); + throw new IllegalNameException( name, "This doesn't look like a legal identifier" ); } return name; } -- cgit v1.2.3 From 486152b09706d9b64e83c18b508e960ad809f0e0 Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 23 Aug 2014 23:47:18 -0400 Subject: MappingsReader will convert old classnames in the default package to the "default" package --- src/cuchaz/enigma/mapping/MappingsReader.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java index 4cebb3a4..d64bcaae 100644 --- a/src/cuchaz/enigma/mapping/MappingsReader.java +++ b/src/cuchaz/enigma/mapping/MappingsReader.java @@ -150,9 +150,22 @@ public class MappingsReader private ClassMapping readClass( Scanner scanner ) { - return new ClassMapping( scanner.next(), scanner.next() ); + return new ClassMapping( + moveOutOfDefaultPackage( scanner.next(), "default" ), + moveOutOfDefaultPackage( scanner.next(), "default" ) + ); } + private String moveOutOfDefaultPackage( String className, String newPackageName ) + { + ClassEntry classEntry = new ClassEntry( className ); + if( classEntry.isInDefaultPackage() ) + { + return newPackageName + "/" + classEntry.getName(); + } + return className; + } + private FieldMapping readField( Scanner scanner ) { return new FieldMapping( scanner.next(), scanner.next() ); -- cgit v1.2.3 From 7c04d2753e21b3b9b7dea53a7511494e8a2804aa Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 24 Aug 2014 00:08:37 -0400 Subject: duh! We can't put classes in a package called "default" "default" is a java reserved word use "none" instead --- src/cuchaz/enigma/Constants.java | 1 + src/cuchaz/enigma/Deobfuscator.java | 6 +++--- src/cuchaz/enigma/Main.java | 2 +- src/cuchaz/enigma/TranslatingTypeLoader.java | 8 ++++---- src/cuchaz/enigma/analysis/JarIndex.java | 7 ++++--- src/cuchaz/enigma/mapping/MappingsReader.java | 5 +++-- 6 files changed, 16 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java index 7ae778dd..1aa9e146 100644 --- a/src/cuchaz/enigma/Constants.java +++ b/src/cuchaz/enigma/Constants.java @@ -18,4 +18,5 @@ public class Constants 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 + public static final String NonePackage = "none"; } diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index ee414fa2..cfd28429 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -135,9 +135,9 @@ public class Deobfuscator // if the class has a mapping, clearly it's deobfuscated deobfClasses.add( deobfClassEntry.getName() ); } - else if( !obfClassEntry.getPackageName().equals( "default" ) ) + else if( !obfClassEntry.getPackageName().equals( Constants.NonePackage ) ) { - // also call it deobufscated if it's not in the "default" package + // also call it deobufscated if it's not in the none package deobfClasses.add( obfClassEntry.getName() ); } else @@ -213,7 +213,7 @@ public class Deobfuscator for( ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries() ) { // skip inner classes - if( obfClassEntry.isInnerClass() ) + if( m_jarIndex.getOuterClass( obfClassEntry.getName() ) != null ) { continue; } diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index 7d38bd62..c1547193 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -32,7 +32,7 @@ public class Main } // DEBUG - //gui.getController().openEntry( new ClassEntry( "bah$bag" ) ); // bah,bag + //gui.getController().openDeclaration( new ClassEntry( "none/aay" ) ); } private static File getFile( String path ) diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index e7e941a9..162858de 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -115,9 +115,9 @@ public class TranslatingTypeLoader implements ITypeLoader // use just the inner class simple name for inner classes classFileName = obfClassEntry.getInnerClassName(); } - else if( obfClassEntry.getPackageName().equals( "default" ) ) + else if( obfClassEntry.getPackageName().equals( Constants.NonePackage ) ) { - // use the outer class simple name for classes in the "default" package + // use the outer class simple name for classes in the none package classFileName = obfClassEntry.getSimpleName(); } else @@ -156,9 +156,9 @@ public class TranslatingTypeLoader implements ITypeLoader classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, buf ) ); CtClass c = classPool.get( javaClassFileName ); - // we moved a lot of classes out of the default package into the "default" package + // we moved a lot of classes out of the default package into the none package // make sure all the class references are consistent - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, "default" ); + ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); // reconstruct inner classes new InnerClassWriter( m_jarIndex ).write( c ); diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index cdaca372..2c4dec48 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -39,6 +39,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; +import cuchaz.enigma.Constants; import cuchaz.enigma.bytecode.ClassRenamer; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; @@ -80,7 +81,7 @@ public class JarIndex if( classEntry.isInDefaultPackage() ) { // move out of default package - classEntry = new ClassEntry( "default/" + classEntry.getName() ); + classEntry = new ClassEntry( Constants.NonePackage + "/" + classEntry.getName() ); } m_obfClassEntries.add( classEntry ); } @@ -138,8 +139,8 @@ public class JarIndex if( classEntry.isInDefaultPackage() ) { // move class out of default package - classEntry = new ClassEntry( "default/" + classEntry.getName() ); - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, "default" ); + classEntry = new ClassEntry( Constants.NonePackage + "/" + classEntry.getName() ); + ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); } } diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java index d64bcaae..5570721f 100644 --- a/src/cuchaz/enigma/mapping/MappingsReader.java +++ b/src/cuchaz/enigma/mapping/MappingsReader.java @@ -19,6 +19,7 @@ import java.util.Scanner; import com.google.common.collect.Queues; +import cuchaz.enigma.Constants; import cuchaz.enigma.Util; public class MappingsReader @@ -151,8 +152,8 @@ public class MappingsReader private ClassMapping readClass( Scanner scanner ) { return new ClassMapping( - moveOutOfDefaultPackage( scanner.next(), "default" ), - moveOutOfDefaultPackage( scanner.next(), "default" ) + moveOutOfDefaultPackage( scanner.next(), Constants.NonePackage ), + moveOutOfDefaultPackage( scanner.next(), Constants.NonePackage ) ); } -- cgit v1.2.3 From 9c28492b717b866c6b70fe1ef4552eac66857f25 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 24 Aug 2014 16:35:38 -0400 Subject: minor bug fixes --- src/cuchaz/enigma/Deobfuscator.java | 1 + src/cuchaz/enigma/Main.java | 2 +- src/cuchaz/enigma/TranslatingTypeLoader.java | 6 +++++- src/cuchaz/enigma/bytecode/ClassRenamer.java | 4 ++++ 4 files changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index cfd28429..0bc4a043 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -73,6 +73,7 @@ public class Deobfuscator // config the decompiler m_settings = DecompilerSettings.javaDefaults(); + m_settings.setForceExplicitImports( true ); // DEBUG //m_settings.setShowSyntheticMembers( true ); diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index c1547193..fe4d6e34 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -32,7 +32,7 @@ public class Main } // DEBUG - //gui.getController().openDeclaration( new ClassEntry( "none/aay" ) ); + //gui.getController().openDeclaration( new ClassEntry( "none/bgl" ) ); } private static File getFile( String path ) diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 162858de..763d767c 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -27,6 +27,7 @@ import javassist.bytecode.Descriptor; import com.beust.jcommander.internal.Maps; import com.strobel.assembler.metadata.Buffer; +import com.strobel.assembler.metadata.ClasspathTypeLoader; import com.strobel.assembler.metadata.ITypeLoader; import cuchaz.enigma.analysis.BridgeFixer; @@ -45,6 +46,7 @@ public class TranslatingTypeLoader implements ITypeLoader private Translator m_obfuscatingTranslator; private Translator m_deobfuscatingTranslator; private Map m_cache; + private ClasspathTypeLoader m_defaultTypeLoader; public TranslatingTypeLoader( JarFile jar, JarIndex jarIndex, Translator obfuscatingTranslator, Translator deobfuscatingTranslator ) { @@ -53,6 +55,7 @@ public class TranslatingTypeLoader implements ITypeLoader m_obfuscatingTranslator = obfuscatingTranslator; m_deobfuscatingTranslator = deobfuscatingTranslator; m_cache = Maps.newHashMap(); + m_defaultTypeLoader = new ClasspathTypeLoader(); } public void clearCache( ) @@ -77,7 +80,8 @@ public class TranslatingTypeLoader implements ITypeLoader if( data == null ) { - return false; + // chain to default type loader + return m_defaultTypeLoader.tryLoadType( deobfClassName, out ); } // send the class to the decompiler diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java index cba58617..f3a8c0ef 100644 --- a/src/cuchaz/enigma/bytecode/ClassRenamer.java +++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java @@ -45,6 +45,10 @@ public class ClassRenamer { ClassEntry inClassEntry = new ClassEntry( Descriptor.toJvmName( attr.innerClass( i ) ) ); ClassEntry outClassEntry = map.get( inClassEntry ); + if( outClassEntry == null ) + { + continue; + } attr.setInnerClassIndex( i, constants.addClassInfo( outClassEntry.getName() ) ); if( attr.outerClassIndex( i ) != 0 ) { -- cgit v1.2.3 From 2e97f24a658aa897313cb7cf92ed2e4b4a986bfc Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 25 Aug 2014 00:04:47 -0400 Subject: fixed issue with bridge methods so source export has fewer compile errors. =) --- src/cuchaz/enigma/Deobfuscator.java | 6 + src/cuchaz/enigma/Main.java | 3 +- src/cuchaz/enigma/TranslatingTypeLoader.java | 2 +- src/cuchaz/enigma/analysis/BridgeFixer.java | 92 -------------- src/cuchaz/enigma/analysis/JarIndex.java | 172 ++++++++++++++++++++++++--- 5 files changed, 163 insertions(+), 112 deletions(-) delete mode 100644 src/cuchaz/enigma/analysis/BridgeFixer.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 0bc4a043..8a516b18 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -219,6 +219,12 @@ public class Deobfuscator continue; } + // TEMP: skip the classes that won't decompile because of a procyon bug + if( obfClassEntry.getName().equals( "none/bgl" ) ) + { + continue; + } + ClassEntry deobfClassEntry = deobfuscateEntry( new ClassEntry( obfClassEntry ) ); if( progress != null ) { diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index fe4d6e34..c69b8907 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -13,6 +13,7 @@ package cuchaz.enigma; import java.io.File; import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.mapping.ClassEntry; public class Main { @@ -32,7 +33,7 @@ public class Main } // DEBUG - //gui.getController().openDeclaration( new ClassEntry( "none/bgl" ) ); + gui.getController().openDeclaration( new ClassEntry( "none/bsp" ) ); } private static File getFile( String path ) diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 763d767c..83f0baa4 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -177,7 +177,7 @@ public class TranslatingTypeLoader implements ITypeLoader assertClassName( c, obfClassEntry ); // do all kinds of deobfuscating transformations on the class - new BridgeFixer().fixBridges( c ); + new BridgeFixer( m_jarIndex ).fixBridges( c ); new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java deleted file mode 100644 index f13f68f4..00000000 --- a/src/cuchaz/enigma/analysis/BridgeFixer.java +++ /dev/null @@ -1,92 +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.analysis; - -import java.util.List; - -import javassist.CannotCompileException; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.NotFoundException; -import javassist.bytecode.AccessFlag; -import javassist.expr.ExprEditor; -import javassist.expr.MethodCall; - -import com.beust.jcommander.internal.Lists; - -public class BridgeFixer -{ - public void fixBridges( CtClass c ) - { - // bridge methods are scrubbed and marked as synthetic methods by the obfuscator - // need to figure out which synthetics are bridge methods and restore them - for( CtMethod method : c.getDeclaredMethods() ) - { - // skip non-synthetic methods - if( ( method.getModifiers() & AccessFlag.SYNTHETIC ) == 0 ) - { - continue; - } - - CtMethod bridgedMethod = getBridgedMethod( method ); - if( bridgedMethod != null ) - { - bridgedMethod.setName( method.getName() ); - method.setModifiers( method.getModifiers() | AccessFlag.BRIDGE ); - - // TODO: rename all references to this method? - } - } - } - - private CtMethod getBridgedMethod( CtMethod method ) - { - // bridge methods just call another method, cast it to the return type, and return the result - // let's see if we can detect this scenario - - // get all the called methods - final List methodCalls = Lists.newArrayList(); - try - { - method.instrument( new ExprEditor( ) - { - @Override - public void edit( MethodCall call ) - { - methodCalls.add( call ); - } - } ); - } - catch( CannotCompileException ex ) - { - // this is stupid... we're not even compiling anything - throw new Error( ex ); - } - - // is there just one? - if( methodCalls.size() != 1 ) - { - return null; - } - MethodCall call = methodCalls.get( 0 ); - - try - { - // we have a bridge method! - return call.getMethod(); - } - catch( NotFoundException ex ) - { - // can't find the type? not a bridge method - return null; - } - } -} diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 2c4dec48..cb7508e1 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -24,6 +24,7 @@ import javassist.CtBehavior; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtMethod; +import javassist.NotFoundException; import javassist.bytecode.AccessFlag; import javassist.bytecode.Descriptor; import javassist.bytecode.FieldInfo; @@ -60,6 +61,7 @@ public class JarIndex private Multimap m_innerClasses; private Map m_outerClasses; private Set m_anonymousClasses; + private Map m_bridgeMethods; public JarIndex( ) { @@ -71,11 +73,12 @@ public class JarIndex m_innerClasses = HashMultimap.create(); m_outerClasses = Maps.newHashMap(); m_anonymousClasses = Sets.newHashSet(); + m_bridgeMethods = Maps.newHashMap(); } public void indexJar( JarFile jar ) { - // pass 1: read the class names + // step 1: read the class names for( ClassEntry classEntry : JarClassIterator.getClassEntries( jar ) ) { if( classEntry.isInDefaultPackage() ) @@ -86,7 +89,7 @@ public class JarIndex m_obfClassEntries.add( classEntry ); } - // pass 2: index the types, methods + // step 2: index the types, methods for( CtClass c : JarClassIterator.classes( jar ) ) { fixClass( c ); @@ -97,7 +100,7 @@ public class JarIndex } } - // pass 2: index inner classes and anonymous classes + // step 3: index inner classes and anonymous classes for( CtClass c : JarClassIterator.classes( jar ) ) { fixClass( c ); @@ -124,13 +127,16 @@ public class JarIndex } } - // step 3: update other indicies with inner class info + // step 4: update other indices with inner class info Map renames = Maps.newHashMap(); for( Map.Entry entry : m_outerClasses.entrySet() ) { renames.put( entry.getKey(), entry.getValue() + "$" + entry.getKey() ); } renameClasses( renames ); + + // step 5: update other indices with bridge method info + renameMethods( m_bridgeMethods ); } private void fixClass( CtClass c ) @@ -160,6 +166,18 @@ public class JarIndex // index implementation m_methodImplementations.put( className, methodEntry ); + + // look for bridge methods + CtMethod bridgedMethod = getBridgedMethod( (CtMethod)behavior ); + if( bridgedMethod != null ) + { + MethodEntry bridgedMethodEntry = new MethodEntry( + new ClassEntry( className ), + bridgedMethod.getName(), + bridgedMethod.getSignature() + ); + m_bridgeMethods.put( bridgedMethodEntry, methodEntry ); + } } else if( behavior instanceof CtConstructor ) { @@ -254,6 +272,56 @@ public class JarIndex } } + + private CtMethod getBridgedMethod( CtMethod method ) + { + // bridge methods just call another method, cast it to the return type, and return the result + // let's see if we can detect this scenario + + // skip non-synthetic methods + if( ( method.getModifiers() & AccessFlag.SYNTHETIC ) == 0 ) + { + return null; + } + + // get all the called methods + final List methodCalls = Lists.newArrayList(); + try + { + method.instrument( new ExprEditor( ) + { + @Override + public void edit( MethodCall call ) + { + methodCalls.add( call ); + } + } ); + } + catch( CannotCompileException ex ) + { + // this is stupid... we're not even compiling anything + throw new Error( ex ); + } + + // is there just one? + if( methodCalls.size() != 1 ) + { + return null; + } + MethodCall call = methodCalls.get( 0 ); + + try + { + // we have a bridge method! + return call.getMethod(); + } + catch( NotFoundException ex ) + { + // can't find the type? not a bridge method + return null; + } + } + private String findOuterClass( CtClass c ) { // inner classes: @@ -534,15 +602,27 @@ public class JarIndex return m_anonymousClasses.contains( obfInnerClassName ); } + public MethodEntry getBridgeMethod( MethodEntry methodEntry ) + { + return m_bridgeMethods.get( methodEntry ); + } + private void renameClasses( Map renames ) { m_ancestries.renameClasses( renames ); - renameMultimap( renames, m_methodImplementations ); - renameMultimap( renames, m_behaviorReferences ); - renameMultimap( renames, m_fieldReferences ); + renameClassesInMultimap( renames, m_methodImplementations ); + renameClassesInMultimap( renames, m_behaviorReferences ); + renameClassesInMultimap( renames, m_fieldReferences ); + } + + private void renameMethods( Map renames ) + { + renameMethodsInMultimap( renames, m_methodImplementations ); + renameMethodsInMultimap( renames, m_behaviorReferences ); + renameMethodsInMultimap( renames, m_fieldReferences ); } - private void renameMultimap( Map renames, Multimap map ) + private void renameClassesInMultimap( Map renames, Multimap map ) { // for each key/value pair... Set> entriesToAdd = Sets.newHashSet(); @@ -552,8 +632,8 @@ public class JarIndex Map.Entry entry = iter.next(); iter.remove(); entriesToAdd.add( new AbstractMap.SimpleEntry( - renameThing( renames, entry.getKey() ), - renameThing( renames, entry.getValue() ) + renameClassesInThing( renames, entry.getKey() ), + renameClassesInThing( renames, entry.getValue() ) ) ); } for( Map.Entry entry : entriesToAdd ) @@ -563,7 +643,7 @@ public class JarIndex } @SuppressWarnings( "unchecked" ) - private T renameThing( Map renames, T thing ) + private T renameClassesInThing( Map renames, T thing ) { if( thing instanceof String ) { @@ -576,13 +656,13 @@ public class JarIndex else if( thing instanceof ClassEntry ) { ClassEntry classEntry = (ClassEntry)thing; - return (T)new ClassEntry( renameThing( renames, classEntry.getClassName() ) ); + return (T)new ClassEntry( renameClassesInThing( renames, classEntry.getClassName() ) ); } else if( thing instanceof FieldEntry ) { FieldEntry fieldEntry = (FieldEntry)thing; return (T)new FieldEntry( - renameThing( renames, fieldEntry.getClassEntry() ), + renameClassesInThing( renames, fieldEntry.getClassEntry() ), fieldEntry.getName() ); } @@ -590,7 +670,7 @@ public class JarIndex { ConstructorEntry constructorEntry = (ConstructorEntry)thing; return (T)new ConstructorEntry( - renameThing( renames, constructorEntry.getClassEntry() ), + renameClassesInThing( renames, constructorEntry.getClassEntry() ), constructorEntry.getSignature() ); } @@ -598,7 +678,7 @@ public class JarIndex { MethodEntry methodEntry = (MethodEntry)thing; return (T)new MethodEntry( - renameThing( renames, methodEntry.getClassEntry() ), + renameClassesInThing( renames, methodEntry.getClassEntry() ), methodEntry.getName(), methodEntry.getSignature() ); @@ -607,7 +687,7 @@ public class JarIndex { ArgumentEntry argumentEntry = (ArgumentEntry)thing; return (T)new ArgumentEntry( - renameThing( renames, argumentEntry.getMethodEntry() ), + renameClassesInThing( renames, argumentEntry.getMethodEntry() ), argumentEntry.getIndex(), argumentEntry.getName() ); @@ -615,8 +695,8 @@ public class JarIndex else if( thing instanceof EntryReference ) { EntryReference reference = (EntryReference)thing; - reference.entry = renameThing( renames, reference.entry ); - reference.context = renameThing( renames, reference.context ); + reference.entry = renameClassesInThing( renames, reference.entry ); + reference.context = renameClassesInThing( renames, reference.context ); return thing; } else @@ -626,4 +706,60 @@ public class JarIndex return thing; } + + private void renameMethodsInMultimap( Map renames, Multimap map ) + { + // for each key/value pair... + Set> entriesToAdd = Sets.newHashSet(); + Iterator> iter = map.entries().iterator(); + while( iter.hasNext() ) + { + Map.Entry entry = iter.next(); + iter.remove(); + entriesToAdd.add( new AbstractMap.SimpleEntry( + renameMethodsInThing( renames, entry.getKey() ), + renameMethodsInThing( renames, entry.getValue() ) + ) ); + } + for( Map.Entry entry : entriesToAdd ) + { + map.put( entry.getKey(), entry.getValue() ); + } + } + + @SuppressWarnings( "unchecked" ) + private T renameMethodsInThing( Map renames, T thing ) + { + if( thing instanceof MethodEntry ) + { + MethodEntry methodEntry = (MethodEntry)thing; + MethodEntry newMethodEntry = renames.get( methodEntry ); + if( newMethodEntry != null ) + { + return (T)new MethodEntry( + methodEntry.getClassEntry(), + newMethodEntry.getName(), + methodEntry.getSignature() + ); + } + return thing; + } + else if( thing instanceof ArgumentEntry ) + { + ArgumentEntry argumentEntry = (ArgumentEntry)thing; + return (T)new ArgumentEntry( + renameMethodsInThing( renames, argumentEntry.getMethodEntry() ), + argumentEntry.getIndex(), + argumentEntry.getName() + ); + } + else if( thing instanceof EntryReference ) + { + EntryReference reference = (EntryReference)thing; + reference.entry = renameMethodsInThing( renames, reference.entry ); + reference.context = renameMethodsInThing( renames, reference.context ); + return thing; + } + return thing; + } } -- cgit v1.2.3 From 5b35c2241ef6872bb76750b581f60d6060e40ee0 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 25 Aug 2014 00:05:18 -0400 Subject: silly mercurial. You should commit this file... --- src/cuchaz/enigma/analysis/BridgeFixer.java | 77 +++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/cuchaz/enigma/analysis/BridgeFixer.java (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java new file mode 100644 index 00000000..aeaf871a --- /dev/null +++ b/src/cuchaz/enigma/analysis/BridgeFixer.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * 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.analysis; + +import javassist.CtClass; +import javassist.CtMethod; +import javassist.bytecode.ConstPool; +import javassist.bytecode.Descriptor; +import cuchaz.enigma.bytecode.ConstPoolEditor; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.MethodEntry; + +public class BridgeFixer +{ + private JarIndex m_index; + + public BridgeFixer( JarIndex index ) + { + m_index = index; + } + + public void fixBridges( CtClass c ) + { + // rename declared methods + for( CtMethod method : c.getDeclaredMethods() ) + { + // get the method entry + MethodEntry methodEntry = new MethodEntry( + new ClassEntry( Descriptor.toJvmName( c.getName() ) ), + method.getName(), + method.getSignature() + ); + MethodEntry bridgeMethodEntry = m_index.getBridgeMethod( methodEntry ); + if( bridgeMethodEntry != null ) + { + // fix this bridged method + method.setName( bridgeMethodEntry.getName() ); + } + } + + // rename method references + // translate all the field and method references in the code by editing the constant pool + ConstPool constants = c.getClassFile().getConstPool(); + ConstPoolEditor editor = new ConstPoolEditor( constants ); + for( int i=1; i +{ + public static class CheckCast + { + public String className; + public MethodEntry prevMethodEntry; + + public CheckCast( String className, MethodEntry prevMethodEntry ) + { + this.className = className; + this.prevMethodEntry = prevMethodEntry; + } + } + + private ConstPool m_constants; + private CodeAttribute m_attribute; + private CodeIterator m_iter; + private CheckCast m_next; + + public CheckCastIterator( CodeAttribute codeAttribute ) + throws BadBytecode + { + m_constants = codeAttribute.getConstPool(); + m_attribute = codeAttribute; + m_iter = m_attribute.iterator(); + + m_next = getNext(); + } + + @Override + public boolean hasNext( ) + { + return m_next != null; + } + + @Override + public CheckCast next( ) + { + CheckCast out = m_next; + try + { + m_next = getNext(); + } + catch( BadBytecode ex ) + { + throw new Error( ex ); + } + return out; + } + + @Override + public void remove( ) + { + throw new UnsupportedOperationException(); + } + + private CheckCast getNext( ) + throws BadBytecode + { + int prevPos = 0; + while( m_iter.hasNext() ) + { + int pos = m_iter.next(); + int opcode = m_iter.byteAt( pos ); + switch( opcode ) + { + case Opcode.CHECKCAST: + + // get the type of this op code (next two bytes are a classinfo index) + MethodEntry prevMethodEntry = getMethodEntry( prevPos ); + if( prevMethodEntry != null ) + { + return new CheckCast( + m_constants.getClassInfo( m_iter.s16bitAt( pos + 1 ) ), + prevMethodEntry + ); + } + break; + } + prevPos = pos; + } + return null; + } + + private MethodEntry getMethodEntry( int pos ) + { + switch( m_iter.byteAt( pos ) ) + { + case Opcode.INVOKEVIRTUAL: + case Opcode.INVOKESTATIC: + case Opcode.INVOKEDYNAMIC: + case Opcode.INVOKESPECIAL: + { + int index = m_iter.s16bitAt( pos + 1 ); + return new MethodEntry( + new ClassEntry( Descriptor.toJvmName( m_constants.getMethodrefClassName( index ) ) ), + m_constants.getMethodrefName( index ), + m_constants.getMethodrefType( index ) + ); + } + + case Opcode.INVOKEINTERFACE: + { + int index = m_iter.s16bitAt( pos + 1 ); + return new MethodEntry( + new ClassEntry( Descriptor.toJvmName( m_constants.getInterfaceMethodrefClassName( index ) ) ), + m_constants.getInterfaceMethodrefName( index ), + m_constants.getInterfaceMethodrefType( index ) + ); + } + } + return null; + } + + public Iterable casts( ) + { + return new Iterable( ) + { + @Override + public Iterator iterator( ) + { + return CheckCastIterator.this; + } + }; + } +} -- cgit v1.2.3 From 5f44aac70f59898197c2a7625b74f901c3b31106 Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 26 Aug 2014 00:27:44 -0400 Subject: implemented proper support for interfaces --- src/cuchaz/enigma/TranslatingTypeLoader.java | 5 +- src/cuchaz/enigma/analysis/Ancestries.java | 89 +++++++++++++++++ .../analysis/ClassImplementationsTreeNode.java | 92 +++++++++++++++++ src/cuchaz/enigma/analysis/JarIndex.java | 107 ++++++++++++++++++-- .../analysis/MethodImplementationsTreeNode.java | 111 +++++++++++++++++++++ src/cuchaz/enigma/gui/Gui.java | 104 ++++++++++++++++++- src/cuchaz/enigma/gui/GuiController.java | 25 +++++ src/cuchaz/enigma/mapping/Renamer.java | 21 +--- 8 files changed, 524 insertions(+), 30 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java create mode 100644 src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java (limited to 'src') diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 83f0baa4..1e0e95a2 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -13,7 +13,6 @@ package cuchaz.enigma; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.Arrays; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -105,12 +104,12 @@ public class TranslatingTypeLoader implements ITypeLoader return null; } - // DEBUG + /* DEBUG if( !Arrays.asList( "java", "org", "io" ).contains( deobfClassName.split( "/" )[0] ) ) { System.out.println( String.format( "Looking for %s (%s)", deobfClassEntry.getName(), obfClassEntry.getName() ) ); } - // + */ // get the jar entry String classFileName; diff --git a/src/cuchaz/enigma/analysis/Ancestries.java b/src/cuchaz/enigma/analysis/Ancestries.java index b9d8cbf4..97241084 100644 --- a/src/cuchaz/enigma/analysis/Ancestries.java +++ b/src/cuchaz/enigma/analysis/Ancestries.java @@ -11,24 +11,32 @@ package cuchaz.enigma.analysis; import java.io.Serializable; +import java.util.AbstractMap; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import javassist.bytecode.Descriptor; +import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; public class Ancestries implements Serializable { private static final long serialVersionUID = 738687982126844179L; private Map m_superclasses; + private Multimap m_interfaces; public Ancestries( ) { m_superclasses = Maps.newHashMap(); + m_interfaces = HashMultimap.create(); } public void addSuperclass( String className, String superclassName ) @@ -47,8 +55,25 @@ public class Ancestries implements Serializable } } + public void addInterface( String className, String interfaceName ) + { + className = Descriptor.toJvmName( className ); + interfaceName = Descriptor.toJvmName( interfaceName ); + + if( className.equals( interfaceName ) ) + { + throw new IllegalArgumentException( "Class cannot be its own interface! " + className ); + } + + if( !isJre( className ) && !isJre( interfaceName ) ) + { + m_interfaces.put( className, interfaceName ); + } + } + public void renameClasses( Map renames ) { + // rename superclasses Map newSuperclasses = Maps.newHashMap(); for( Map.Entry entry : m_superclasses.entrySet() ) { @@ -65,6 +90,28 @@ public class Ancestries implements Serializable newSuperclasses.put( subclass, superclass ); } m_superclasses = newSuperclasses; + + // rename interfaces + Set> entriesToAdd = Sets.newHashSet(); + for( Map.Entry entry : m_interfaces.entries() ) + { + String className = renames.get( entry.getKey() ); + if( className == null ) + { + className = entry.getKey(); + } + String interfaceName = renames.get( entry.getValue() ); + if( interfaceName == null ) + { + interfaceName = entry.getValue(); + } + entriesToAdd.add( new AbstractMap.SimpleEntry( className, interfaceName ) ); + } + m_interfaces.clear(); + for( Map.Entry entry : entriesToAdd ) + { + m_interfaces.put( entry.getKey(), entry.getValue() ); + } } public String getSuperclassName( String className ) @@ -86,6 +133,17 @@ public class Ancestries implements Serializable return ancestors; } + public Set getInterfaces( String className ) + { + Set interfaceNames = new HashSet(); + interfaceNames.addAll( m_interfaces.get( className ) ); + for( String ancestor : getAncestry( className ) ) + { + interfaceNames.addAll( m_interfaces.get( ancestor ) ); + } + return interfaceNames; + } + public List getSubclasses( String className ) { // linear search is fast enough for now @@ -102,6 +160,37 @@ public class Ancestries implements Serializable return subclasses; } + public Set getImplementingClasses( String targetInterfaceName ) + { + // linear search is fast enough for now + Set classNames = Sets.newHashSet(); + for( Map.Entry entry : m_interfaces.entries() ) + { + String className = entry.getKey(); + String interfaceName = entry.getValue(); + if( interfaceName.equals( targetInterfaceName ) ) + { + classNames.add( className ); + collectSubclasses( classNames, className ); + } + } + return classNames; + } + + public boolean isInterface( String className ) + { + return m_interfaces.containsValue( className ); + } + + private void collectSubclasses( Set classNames, String className ) + { + for( String subclassName : getSubclasses( className ) ) + { + classNames.add( subclassName ); + collectSubclasses( classNames, subclassName ); + } + } + private boolean isJre( String className ) { return className.startsWith( "java/" ) diff --git a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java new file mode 100644 index 00000000..98648305 --- /dev/null +++ b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * 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.analysis; + +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; + +import com.google.common.collect.Lists; + +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.Translator; + +public class ClassImplementationsTreeNode extends DefaultMutableTreeNode +{ + private static final long serialVersionUID = 3112703459157851912L; + + private Translator m_deobfuscatingTranslator; + private ClassEntry m_entry; + + public ClassImplementationsTreeNode( Translator deobfuscatingTranslator, ClassEntry entry ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = entry; + } + + public ClassEntry getClassEntry( ) + { + return m_entry; + } + + public String getDeobfClassName( ) + { + return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() ); + } + + @Override + public String toString( ) + { + String className = getDeobfClassName(); + if( className == null ) + { + className = m_entry.getClassName(); + } + return className; + } + + public void load( Ancestries ancestries ) + { + // get all method implementations + List nodes = Lists.newArrayList(); + for( String implementingClassName : ancestries.getImplementingClasses( m_entry.getClassName() ) ) + { + nodes.add( new ClassImplementationsTreeNode( m_deobfuscatingTranslator, new ClassEntry( implementingClassName ) ) ); + } + + // add them to this node + for( ClassImplementationsTreeNode node : nodes ) + { + this.add( node ); + } + } + + public static ClassImplementationsTreeNode findNode( ClassImplementationsTreeNode node, MethodEntry entry ) + { + // is this the node? + if( node.m_entry.equals( entry ) ) + { + return node; + } + + // recurse + for( int i=0; i 1 ) { - // TEMP System.out.println( "WARNING: Illegal constructor called by more than one class!" + callerClasses ); } } @@ -542,6 +546,13 @@ public class JarIndex return rootNode; } + public ClassImplementationsTreeNode getClassImplementations( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) + { + ClassImplementationsTreeNode node = new ClassImplementationsTreeNode( deobfuscatingTranslator, obfClassEntry ); + node.load( m_ancestries ); + return node; + } + public MethodInheritanceTreeNode getMethodInheritance( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) { // travel to the ancestor implementation @@ -577,6 +588,90 @@ public class JarIndex return rootNode; } + public MethodImplementationsTreeNode getMethodImplementations( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) + { + MethodEntry interfaceMethodEntry; + + // is this method on an interface? + if( m_ancestries.isInterface( obfMethodEntry.getClassName() ) ) + { + interfaceMethodEntry = obfMethodEntry; + } + else + { + // get the interface class + List methodInterfaces = Lists.newArrayList(); + for( String interfaceName : m_ancestries.getInterfaces( obfMethodEntry.getClassName() ) ) + { + // is this method defined in this interface? + MethodEntry methodInterface = new MethodEntry( + new ClassEntry( interfaceName ), + obfMethodEntry.getName(), + obfMethodEntry.getSignature() + ); + if( isMethodImplemented( methodInterface ) ) + { + methodInterfaces.add( methodInterface ); + } + } + if( methodInterfaces.isEmpty() ) + { + return null; + } + if( methodInterfaces.size() > 1 ) + { + throw new Error( "Too many interfaces define this method! This is not yet supported by Enigma!" ); + } + interfaceMethodEntry = methodInterfaces.get( 0 ); + } + + MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode( deobfuscatingTranslator, interfaceMethodEntry ); + rootNode.load( this ); + return rootNode; + } + + public Set getRelatedMethodImplementations( MethodEntry obfMethodEntry ) + { + Set methodEntries = Sets.newHashSet(); + getRelatedMethodImplementations( methodEntries, getMethodInheritance( null, obfMethodEntry ) ); + return methodEntries; + } + + private void getRelatedMethodImplementations( Set methodEntries, MethodInheritanceTreeNode node ) + { + MethodEntry methodEntry = node.getMethodEntry(); + if( isMethodImplemented( methodEntry ) ) + { + // collect the entry + methodEntries.add( methodEntry ); + } + + // look at interface methods too + getRelatedMethodImplementations( methodEntries, getMethodImplementations( null, methodEntry ) ); + + // recurse + for( int i=0; i methodEntries, MethodImplementationsTreeNode node ) + { + MethodEntry methodEntry = node.getMethodEntry(); + if( isMethodImplemented( methodEntry ) ) + { + // collect the entry + methodEntries.add( methodEntry ); + } + + // recurse + for( int i=0; i> getFieldReferences( FieldEntry fieldEntry ) { return m_fieldReferences.get( fieldEntry ); @@ -626,16 +721,14 @@ public class JarIndex { // for each key/value pair... Set> entriesToAdd = Sets.newHashSet(); - Iterator> iter = map.entries().iterator(); - while( iter.hasNext() ) + for( Map.Entry entry : map.entries() ) { - Map.Entry entry = iter.next(); - iter.remove(); entriesToAdd.add( new AbstractMap.SimpleEntry( renameClassesInThing( renames, entry.getKey() ), renameClassesInThing( renames, entry.getValue() ) ) ); } + map.clear(); for( Map.Entry entry : entriesToAdd ) { map.put( entry.getKey(), entry.getValue() ); @@ -761,5 +854,5 @@ public class JarIndex return thing; } return thing; - } + } } diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java new file mode 100644 index 00000000..b529f3f6 --- /dev/null +++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * 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.analysis; + +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; + +import com.google.common.collect.Lists; + +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.Translator; + +public class MethodImplementationsTreeNode extends DefaultMutableTreeNode +{ + private static final long serialVersionUID = 3781080657461899915L; + + private Translator m_deobfuscatingTranslator; + private MethodEntry m_entry; + + public MethodImplementationsTreeNode( Translator deobfuscatingTranslator, MethodEntry entry ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = entry; + } + + public MethodEntry getMethodEntry( ) + { + return m_entry; + } + + public String getDeobfClassName( ) + { + return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() ); + } + + public String getDeobfMethodName( ) + { + return m_deobfuscatingTranslator.translate( m_entry ); + } + + @Override + public String toString( ) + { + String className = getDeobfClassName(); + if( className == null ) + { + className = m_entry.getClassName(); + } + + String methodName = getDeobfMethodName(); + if( methodName == null ) + { + methodName = m_entry.getName(); + } + return className + "." + methodName + "()"; + } + + public void load( JarIndex index ) + { + // get all method implementations + List nodes = Lists.newArrayList(); + for( String implementingClassName : index.getAncestries().getImplementingClasses( m_entry.getClassName() ) ) + { + MethodEntry methodEntry = new MethodEntry( + new ClassEntry( implementingClassName ), + m_entry.getName(), + m_entry.getSignature() + ); + if( index.isMethodImplemented( methodEntry ) ) + { + nodes.add( new MethodImplementationsTreeNode( m_deobfuscatingTranslator, methodEntry ) ); + } + } + + // add them to this node + for( MethodImplementationsTreeNode node : nodes ) + { + this.add( node ); + } + } + + public static MethodImplementationsTreeNode findNode( MethodImplementationsTreeNode node, MethodEntry entry ) + { + // is this the node? + if( node.getMethodEntry().equals( entry ) ) + { + return node; + } + + // recurse + for( int i=0; i m_tokens; private JTabbedPane m_tabs; @@ -163,6 +166,7 @@ public class Gui private JMenuItem m_openEntryMenu; private JMenuItem m_openPreviousMenu; private JMenuItem m_showCallsMenu; + private JMenuItem m_showImplementationsMenu; // state private EntryReference m_reference; @@ -285,6 +289,10 @@ public class Gui showInheritance(); break; + case KeyEvent.VK_M: + showImplementations(); + break; + case KeyEvent.VK_N: openDeclaration(); break; @@ -337,6 +345,21 @@ public class Gui popupMenu.add( menu ); m_showInheritanceMenu = menu; } + { + JMenuItem menu = new JMenuItem( "Show Implementations" ); + menu.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + showImplementations(); + } + } ); + menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_M, 0 ) ); + menu.setEnabled( false ); + popupMenu.add( menu ); + m_showImplementationsMenu = menu; + } { JMenuItem menu = new JMenuItem( "Show Calls" ); menu.addActionListener( new ActionListener( ) @@ -428,6 +451,41 @@ public class Gui inheritancePanel.setLayout( new BorderLayout() ); inheritancePanel.add( new JScrollPane( m_inheritanceTree ) ); + // init implementations panel + m_implementationsTree = new JTree(); + m_implementationsTree.setModel( null ); + m_implementationsTree.addMouseListener( new MouseAdapter( ) + { + @Override + public void mouseClicked( MouseEvent event ) + { + if( event.getClickCount() == 2 ) + { + // get the selected node + TreePath path = m_implementationsTree.getSelectionPath(); + if( path == null ) + { + return; + } + + Object node = path.getLastPathComponent(); + if( node instanceof ClassImplementationsTreeNode ) + { + ClassImplementationsTreeNode classNode = (ClassImplementationsTreeNode)node; + m_controller.openDeclaration( classNode.getClassEntry() ); + } + else if( node instanceof MethodImplementationsTreeNode ) + { + MethodImplementationsTreeNode methodNode = (MethodImplementationsTreeNode)node; + m_controller.openDeclaration( methodNode.getMethodEntry() ); + } + } + } + } ); + JPanel implementationsPanel = new JPanel(); + implementationsPanel.setLayout( new BorderLayout() ); + implementationsPanel.add( new JScrollPane( m_implementationsTree ) ); + // init call panel m_callsTree = new JTree(); m_callsTree.setModel( null ); @@ -501,6 +559,7 @@ public class Gui m_tabs = new JTabbedPane(); m_tabs.setPreferredSize( new Dimension( 250, 0 ) ); m_tabs.addTab( "Inheritance", inheritancePanel ); + m_tabs.addTab( "Implementations", implementationsPanel ); m_tabs.addTab( "Call Graph", callPanel ); JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs ); splitRight.setResizeWeight( 1 ); // let the left side take all the slack @@ -1023,6 +1082,7 @@ public class Gui m_renameMenu.setEnabled( isToken ); m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry || isConstructorEntry ); + m_showImplementationsMenu.setEnabled( isClassEntry || isMethodEntry ); m_showCallsMenu.setEnabled( isFieldEntry || isMethodEntry || isConstructorEntry ); m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); m_openPreviousMenu.setEnabled( m_controller.hasPreviousLocation() ); @@ -1097,6 +1157,8 @@ public class Gui return; } + m_inheritanceTree.setModel( null ); + if( m_reference.entry instanceof ClassEntry ) { // get the class inheritance @@ -1124,6 +1186,46 @@ public class Gui redraw(); } + private void showImplementations( ) + { + if( m_reference == null ) + { + return; + } + + m_implementationsTree.setModel( null ); + + if( m_reference.entry instanceof ClassEntry ) + { + // get the class implementations + ClassImplementationsTreeNode node = m_controller.getClassImplementations( (ClassEntry)m_reference.entry ); + if( node != null ) + { + // show the tree at the root + TreePath path = getPathToRoot( node ); + m_implementationsTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); + m_implementationsTree.expandPath( path ); + m_implementationsTree.setSelectionRow( m_implementationsTree.getRowForPath( path ) ); + } + } + else if( m_reference.entry instanceof MethodEntry ) + { + // get the method implementations + MethodImplementationsTreeNode node = m_controller.getMethodImplementations( (MethodEntry)m_reference.entry ); + if( node != null ) + { + // show the tree at the root + TreePath path = getPathToRoot( node ); + m_implementationsTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); + m_implementationsTree.expandPath( path ); + m_implementationsTree.setSelectionRow( m_implementationsTree.getRowForPath( path ) ); + } + } + + m_tabs.setSelectedIndex( 1 ); + redraw(); + } + private void showCalls( ) { if( m_reference == null ) @@ -1147,7 +1249,7 @@ public class Gui m_callsTree.setModel( new DefaultTreeModel( node ) ); } - m_tabs.setSelectedIndex( 1 ); + m_tabs.setSelectedIndex( 2 ); redraw(); } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 90bce520..bd79e480 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -24,9 +24,11 @@ import com.strobel.decompiler.languages.java.ast.CompilationUnit; import cuchaz.enigma.Deobfuscator; import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; +import cuchaz.enigma.analysis.ClassImplementationsTreeNode; import cuchaz.enigma.analysis.ClassInheritanceTreeNode; import cuchaz.enigma.analysis.EntryReference; import cuchaz.enigma.analysis.FieldReferenceTreeNode; +import cuchaz.enigma.analysis.MethodImplementationsTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.Token; @@ -182,6 +184,15 @@ public class GuiController return ClassInheritanceTreeNode.findNode( rootNode, obfClassEntry ); } + public ClassImplementationsTreeNode getClassImplementations( ClassEntry deobfClassEntry ) + { + ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry( deobfClassEntry ); + return m_deobfuscator.getJarIndex().getClassImplementations( + m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + obfClassEntry + ); + } + public MethodInheritanceTreeNode getMethodInheritance( MethodEntry deobfMethodEntry ) { MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry( deobfMethodEntry ); @@ -192,6 +203,20 @@ public class GuiController return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); } + public MethodImplementationsTreeNode getMethodImplementations( MethodEntry deobfMethodEntry ) + { + MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry( deobfMethodEntry ); + MethodImplementationsTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodImplementations( + m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + obfMethodEntry + ); + if( rootNode == null ) + { + return null; + } + return MethodImplementationsTreeNode.findNode( rootNode, obfMethodEntry ); + } + public FieldReferenceTreeNode getFieldReferences( FieldEntry deobfFieldEntry ) { FieldEntry obfFieldEntry = m_deobfuscator.obfuscateEntry( deobfFieldEntry ); diff --git a/src/cuchaz/enigma/mapping/Renamer.java b/src/cuchaz/enigma/mapping/Renamer.java index 0bb8dc12..79cbd30d 100644 --- a/src/cuchaz/enigma/mapping/Renamer.java +++ b/src/cuchaz/enigma/mapping/Renamer.java @@ -16,7 +16,6 @@ import java.io.OutputStream; import java.util.zip.GZIPOutputStream; import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.analysis.MethodInheritanceTreeNode; public class Renamer { @@ -57,25 +56,9 @@ public class Renamer public void setMethodTreeName( MethodEntry obf, String deobfName ) { - // get the method tree - setMethodTreeName( - m_index.getMethodInheritance( m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ), obf ), - deobfName - ); - } - - private void setMethodTreeName( MethodInheritanceTreeNode node, String deobfName ) - { - if( node.isImplemented() ) - { - // apply the name here - setMethodName( node.getMethodEntry(), deobfName ); - } - - // recurse - for( int i=0; i renames = Maps.newHashMap(); for( Map.Entry entry : m_outerClasses.entrySet() ) { - renames.put( entry.getKey(), entry.getValue() + "$" + entry.getKey() ); + renames.put( entry.getKey(), entry.getValue() + "$" + new ClassEntry( entry.getKey() ).getSimpleName() ); } renameClasses( renames ); diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index fdb7c2c5..f87ddc1d 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -25,12 +25,17 @@ public class ClassEntry implements Entry, Serializable { throw new IllegalArgumentException( "Class name cannot be null!" ); } - if( className.contains( "." ) ) + if( className.indexOf( '.' ) >= 0 ) { throw new IllegalArgumentException( "Class name must be in JVM format. ie, path/to/package/class$inner" ); } m_name = className; + + if( isInnerClass() && getInnerClassName().indexOf( '/' ) >= 0 ) + { + throw new IllegalArgumentException( "Inner cast must not have a package: " + getInnerClassName() ); + } } public ClassEntry( ClassEntry other ) -- cgit v1.2.3 From 310f3f54f4f537c61b8c864467aa63f98af7b1c6 Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 26 Aug 2014 23:56:55 -0400 Subject: packaged as v0.4 beta --- src/cuchaz/enigma/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java index 1aa9e146..6f6ab315 100644 --- a/src/cuchaz/enigma/Constants.java +++ b/src/cuchaz/enigma/Constants.java @@ -14,7 +14,7 @@ package cuchaz.enigma; public class Constants { public static final String Name = "Enigma"; - public static final String Version = "0.3 beta"; + public static final String Version = "0.4 beta"; 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 -- cgit v1.2.3 From 88d6d655a022b8125355409bd88535da756e5c99 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 27 Aug 2014 00:57:06 -0400 Subject: add more checking to catch duplicate mappings on load implemented more stable sort order for methods repackaged as v0.4.1beta --- src/cuchaz/enigma/Constants.java | 2 +- src/cuchaz/enigma/Main.java | 3 +-- src/cuchaz/enigma/mapping/ClassMapping.java | 25 ++++++++++++++++++++++--- src/cuchaz/enigma/mapping/Mappings.java | 9 +++++++++ src/cuchaz/enigma/mapping/MethodMapping.java | 2 +- 5 files changed, 34 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java index 6f6ab315..e407dbd8 100644 --- a/src/cuchaz/enigma/Constants.java +++ b/src/cuchaz/enigma/Constants.java @@ -14,7 +14,7 @@ package cuchaz.enigma; public class Constants { public static final String Name = "Enigma"; - public static final String Version = "0.4 beta"; + public static final String Version = "0.4.1 beta"; 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/Main.java b/src/cuchaz/enigma/Main.java index c69b8907..bbee9024 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -13,7 +13,6 @@ package cuchaz.enigma; import java.io.File; import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.mapping.ClassEntry; public class Main { @@ -33,7 +32,7 @@ public class Main } // DEBUG - gui.getController().openDeclaration( new ClassEntry( "none/bsp" ) ); + //gui.getController().openDeclaration( new ClassEntry( "none/bsp" ) ); } private static File getFile( String path ) diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index c7f930c6..59365129 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -129,10 +129,18 @@ public class ClassMapping implements Serializable, Comparable protected void addFieldMapping( FieldMapping fieldMapping ) { + if( m_fieldsByObf.containsKey( fieldMapping.getObfName() ) ) + { + throw new Error( "Already have mapping for " + m_obfName + "." + fieldMapping.getObfName() ); + } + if( m_fieldsByDeobf.containsKey( fieldMapping.getDeobfName() ) ) + { + throw new Error( "Already have mapping for " + m_deobfName + "." + fieldMapping.getDeobfName() ); + } m_fieldsByObf.put( fieldMapping.getObfName(), fieldMapping ); m_fieldsByDeobf.put( fieldMapping.getDeobfName(), fieldMapping ); + assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() ); } - public String getObfFieldName( String deobfName ) { @@ -179,8 +187,19 @@ public class ClassMapping implements Serializable, Comparable protected void addMethodMapping( MethodMapping methodMapping ) { - m_methodsByObf.put( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ), methodMapping ); - m_methodsByDeobf.put( getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ), methodMapping ); + String obfKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ); + String deobfKey = getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ); + if( m_methodsByObf.containsKey( obfKey ) ) + { + throw new Error( "Already have mapping for " + m_obfName + "." + obfKey ); + } + if( m_methodsByDeobf.containsKey( deobfKey ) ) + { + throw new Error( "Already have mapping for " + m_deobfName + "." + deobfKey ); + } + m_methodsByObf.put( obfKey, methodMapping ); + m_methodsByDeobf.put( deobfKey, methodMapping ); + assert( m_methodsByObf.size() == m_methodsByDeobf.size() ); } public MethodMapping getMethodByObf( String obfName, String signature ) diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index c7cb6a67..f3b8fad1 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -70,8 +70,17 @@ public class Mappings implements Serializable protected void addClassMapping( ClassMapping classMapping ) { + if( m_classesByObf.containsKey( classMapping.getObfName() ) ) + { + throw new Error( "Already have mapping for " + classMapping.getObfName() ); + } + if( m_classesByDeobf.containsKey( classMapping.getDeobfName() ) ) + { + throw new Error( "Already have mapping for " + classMapping.getDeobfName() ); + } m_classesByObf.put( classMapping.getObfName(), classMapping ); m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ); + assert( m_classesByObf.size() == m_classesByDeobf.size() ); } public ClassMapping getClassByObf( ClassEntry entry ) diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java index 7857ea7e..6e6bec46 100644 --- a/src/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/cuchaz/enigma/mapping/MethodMapping.java @@ -137,6 +137,6 @@ public class MethodMapping implements Serializable, Comparable @Override public int compareTo( MethodMapping other ) { - return m_obfName.compareTo( other.m_obfName ); + return ( m_obfName + m_obfSignature ).compareTo( ( other.m_obfName + other.m_obfSignature ) ); } } -- cgit v1.2.3 From 392f63d073f78e0abb488ead6e3f458a7bb0f818 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 28 Aug 2014 00:56:31 -0400 Subject: fixed issue with method signatures in default package repackaged for 0.4.2 beta --- src/cuchaz/enigma/Constants.java | 2 +- src/cuchaz/enigma/mapping/MappingsReader.java | 30 +++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java index e407dbd8..c8631429 100644 --- a/src/cuchaz/enigma/Constants.java +++ b/src/cuchaz/enigma/Constants.java @@ -14,7 +14,7 @@ package cuchaz.enigma; public class Constants { public static final String Name = "Enigma"; - public static final String Version = "0.4.1 beta"; + public static final String Version = "0.4.2 beta"; 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/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java index 5570721f..9f42b42c 100644 --- a/src/cuchaz/enigma/mapping/MappingsReader.java +++ b/src/cuchaz/enigma/mapping/MappingsReader.java @@ -21,6 +21,7 @@ import com.google.common.collect.Queues; import cuchaz.enigma.Constants; import cuchaz.enigma.Util; +import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class MappingsReader { @@ -152,12 +153,12 @@ public class MappingsReader private ClassMapping readClass( Scanner scanner ) { return new ClassMapping( - moveOutOfDefaultPackage( scanner.next(), Constants.NonePackage ), - moveOutOfDefaultPackage( scanner.next(), Constants.NonePackage ) + moveClassOutOfDefaultPackage( scanner.next(), Constants.NonePackage ), + moveClassOutOfDefaultPackage( scanner.next(), Constants.NonePackage ) ); } - private String moveOutOfDefaultPackage( String className, String newPackageName ) + private String moveClassOutOfDefaultPackage( String className, String newPackageName ) { ClassEntry classEntry = new ClassEntry( className ); if( classEntry.isInDefaultPackage() ) @@ -174,6 +175,27 @@ public class MappingsReader private MethodMapping readMethod( Scanner scanner ) { - return new MethodMapping( scanner.next(), scanner.next(), scanner.next(), scanner.next() ); + return new MethodMapping( + scanner.next(), scanner.next(), + moveSignatureOutOfDefaultPackage( scanner.next(), Constants.NonePackage ), + moveSignatureOutOfDefaultPackage( scanner.next(), Constants.NonePackage ) + ); + } + + private String moveSignatureOutOfDefaultPackage( String signature, final String newPackageName ) + { + return SignatureUpdater.update( signature, new ClassNameUpdater( ) + { + @Override + public String update( String className ) + { + ClassEntry classEntry = new ClassEntry( className ); + if( classEntry.isInDefaultPackage() ) + { + return newPackageName + "/" + className; + } + return className; + } + } ); } } -- cgit v1.2.3 From deb2775d35f5a6d2b464782242e6b30c37279124 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 28 Aug 2014 10:12:24 -0400 Subject: added checks to find buggy mappings --- src/cuchaz/enigma/Deobfuscator.java | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 8a516b18..cc1465a2 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -41,6 +41,7 @@ import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.Mappings; import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.MethodMapping; import cuchaz.enigma.mapping.Renamer; import cuchaz.enigma.mapping.TranslationDirection; import cuchaz.enigma.mapping.Translator; @@ -101,6 +102,37 @@ public class Deobfuscator { val = new Mappings(); } + + // make sure all the mappings match the classes in the jar + for( ClassMapping classMapping : val.classes() ) + { + ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); + if( !m_jarIndex.getObfClassEntries().contains( classEntry ) ) + { + throw new Error( "Class " + classEntry + " not found in Jar!" ); + } + + // and method implementations + for( MethodMapping methodMapping : classMapping.methods() ) + { + if( methodMapping.getObfName().startsWith( "<" ) ) + { + // skip constructors and static initializers + continue; + } + + MethodEntry methodEntry = new MethodEntry( + classEntry, + methodMapping.getObfName(), + methodMapping.getObfSignature() + ); + if( !m_jarIndex.isMethodImplemented( methodEntry ) ) + { + throw new Error( "Method " + methodEntry + " not found in Jar!" ); + } + } + } + m_mappings = val; m_renamer = new Renamer( m_jarIndex, m_mappings ); -- cgit v1.2.3 From 3301d00ab1df7a0f88985d143787f9f3c2283e38 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 28 Aug 2014 10:43:48 -0400 Subject: added crash reporter --- src/cuchaz/enigma/gui/CrashDialog.java | 107 +++++++++++++++++++++++++++++++++ src/cuchaz/enigma/gui/Gui.java | 22 +++++-- 2 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 src/cuchaz/enigma/gui/CrashDialog.java (limited to 'src') diff --git a/src/cuchaz/enigma/gui/CrashDialog.java b/src/cuchaz/enigma/gui/CrashDialog.java new file mode 100644 index 00000000..501080ec --- /dev/null +++ b/src/cuchaz/enigma/gui/CrashDialog.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * 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.BorderLayout; +import java.awt.Container; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.WindowConstants; + +import cuchaz.enigma.Constants; + +public class CrashDialog +{ + private static CrashDialog m_instance = null; + + private JFrame m_frame; + private JTextArea m_text; + + private CrashDialog( JFrame parent ) + { + // init frame + m_frame = new JFrame( Constants.Name + " - Crash Report" ); + final Container pane = m_frame.getContentPane(); + pane.setLayout( new BorderLayout() ); + + JLabel label = new JLabel( Constants.Name + " has crashed! =(" ); + label.setBorder( BorderFactory.createEmptyBorder( 10, 10, 10, 10 ) ); + pane.add( label, BorderLayout.NORTH ); + + // report panel + m_text = new JTextArea(); + m_text.setTabSize( 2 ); + pane.add( new JScrollPane( m_text ), BorderLayout.CENTER ); + + // buttons panel + JPanel buttonsPanel = new JPanel(); + FlowLayout buttonsLayout = new FlowLayout(); + buttonsLayout.setAlignment( FlowLayout.RIGHT ); + buttonsPanel.setLayout( buttonsLayout ); + JButton ignoreButton = new JButton( "Ignore" ); + ignoreButton.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + // close (hide) the dialog + m_frame.setVisible( false ); + } + } ); + buttonsPanel.add( ignoreButton ); + JButton exitButton = new JButton( "Exit" ); + exitButton.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + // exit enigma + System.exit( 1 ); + } + } ); + buttonsPanel.add( exitButton ); + pane.add( buttonsPanel, BorderLayout.SOUTH ); + + // show the frame + m_frame.setSize( 600, 400 ); + m_frame.setLocationRelativeTo( parent ); + m_frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); + } + + public static void init( JFrame parent ) + { + m_instance = new CrashDialog( parent ); + } + + public static void show( Throwable ex ) + { + // get the error report + StringWriter buf = new StringWriter(); + ex.printStackTrace( new PrintWriter( buf ) ); + String report = buf.toString(); + + // show it! + m_instance.m_text.setText( report ); + m_instance.m_frame.doLayout(); + m_instance.m_frame.setVisible( true ); + } +} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 3dcb4e24..e357382a 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -28,6 +28,7 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; +import java.lang.Thread.UncaughtExceptionHandler; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -176,6 +177,22 @@ public class Gui public Gui( ) { + // init frame + m_frame = new JFrame( Constants.Name ); + final Container pane = m_frame.getContentPane(); + pane.setLayout( new BorderLayout() ); + + // install a global exception handler to the event thread + CrashDialog.init( m_frame ); + Thread.setDefaultUncaughtExceptionHandler( new UncaughtExceptionHandler( ) + { + @Override + public void uncaughtException( Thread thread, Throwable ex ) + { + CrashDialog.show( ex ); + } + } ); + m_controller = new GuiController( this ); // init file choosers @@ -184,11 +201,6 @@ public class Gui m_exportFileChooser = new JFileChooser(); m_exportFileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); - // init frame - m_frame = new JFrame( Constants.Name ); - final Container pane = m_frame.getContentPane(); - pane.setLayout( new BorderLayout() ); - // init obfuscated classes list m_obfClasses = new JList(); m_obfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); -- cgit v1.2.3 From c1d64214212b43b43ea6a69a3b88eda8ac0e5006 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 28 Aug 2014 17:14:38 -0400 Subject: fixed minor spelling error --- src/cuchaz/enigma/gui/Gui.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index e357382a..3ee8ade0 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -696,7 +696,7 @@ public class Gui m_saveMappingsAsMenu = item; } { - JMenuItem item = new JMenuItem( "Close Mapppings" ); + JMenuItem item = new JMenuItem( "Close Mappings" ); menu.add( item ); item.addActionListener( new ActionListener( ) { -- cgit v1.2.3 From 029f65d110279288f4cad7fb7cfaa33efd0f207d Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 28 Aug 2014 19:34:17 -0400 Subject: Show public/protected/private access on field/method/constructor references --- src/cuchaz/enigma/analysis/Access.java | 51 ++++++++++++++++++++++ .../enigma/analysis/BehaviorReferenceTreeNode.java | 8 ++-- .../enigma/analysis/FieldReferenceTreeNode.java | 12 ++--- src/cuchaz/enigma/analysis/JarIndex.java | 31 +++++++++++-- src/cuchaz/enigma/gui/Gui.java | 1 + 5 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/Access.java (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/Access.java b/src/cuchaz/enigma/analysis/Access.java new file mode 100644 index 00000000..e35bb21b --- /dev/null +++ b/src/cuchaz/enigma/analysis/Access.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * 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.analysis; + +import java.lang.reflect.Modifier; + +import javassist.CtBehavior; +import javassist.CtField; + +public enum Access +{ + Public, + Protected, + Private; + + public static Access get( CtBehavior behavior ) + { + return get( behavior.getModifiers() ); + } + + public static Access get( CtField field ) + { + return get( field.getModifiers() ); + } + + public static Access get( int modifiers ) + { + if( Modifier.isPublic( modifiers ) ) + { + return Public; + } + else if( Modifier.isProtected( modifiers ) ) + { + return Protected; + } + else if( Modifier.isPrivate( modifiers ) ) + { + return Private; + } + // assume public by default + return Public; + } +} \ No newline at end of file diff --git a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java index 0f7e7f71..20f1d472 100644 --- a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java @@ -28,6 +28,7 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements private Translator m_deobfuscatingTranslator; private BehaviorEntry m_entry; private EntryReference m_reference; + private Access m_access; public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, BehaviorEntry entry ) { @@ -36,11 +37,12 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements m_reference = null; } - public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) + public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference, Access access ) { m_deobfuscatingTranslator = deobfuscatingTranslator; m_entry = reference.entry; m_reference = reference; + m_access = access; } @Override @@ -60,7 +62,7 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements { if( m_reference != null ) { - return m_deobfuscatingTranslator.translateEntry( m_reference.context ).toString(); + return String.format( "%s (%s)", m_deobfuscatingTranslator.translateEntry( m_reference.context ), m_access ); } return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); } @@ -70,7 +72,7 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements // get all the child nodes for( EntryReference reference : index.getBehaviorReferences( m_entry ) ) { - add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); + add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference, index.getAccess( m_entry ) ) ); } if( recurse && children != null ) diff --git a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java index 94d0da7e..2652f64a 100644 --- a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java @@ -23,7 +23,8 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re private Translator m_deobfuscatingTranslator; private FieldEntry m_entry; private EntryReference m_reference; - + private Access m_access; + public FieldReferenceTreeNode( Translator deobfuscatingTranslator, FieldEntry entry ) { m_deobfuscatingTranslator = deobfuscatingTranslator; @@ -31,11 +32,12 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re m_reference = null; } - private FieldReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) + private FieldReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference, Access access ) { m_deobfuscatingTranslator = deobfuscatingTranslator; m_entry = reference.entry; m_reference = reference; + m_access = access; } @Override @@ -55,7 +57,7 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re { if( m_reference != null ) { - return m_deobfuscatingTranslator.translateEntry( m_reference.context ).toString(); + return String.format( "%s (%s)", m_deobfuscatingTranslator.translateEntry( m_reference.context ), m_access ); } return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); } @@ -67,14 +69,14 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re { for( EntryReference reference : index.getFieldReferences( m_entry ) ) { - add( new FieldReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); + add( new FieldReferenceTreeNode( m_deobfuscatingTranslator, reference, index.getAccess( m_entry ) ) ); } } else { for( EntryReference reference : index.getBehaviorReferences( m_reference.context ) ) { - add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); + add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference, index.getAccess( m_reference.context ) ) ); } } diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 947453ef..deacf16d 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -23,6 +23,7 @@ import javassist.CannotCompileException; import javassist.CtBehavior; import javassist.CtClass; import javassist.CtConstructor; +import javassist.CtField; import javassist.CtMethod; import javassist.NotFoundException; import javassist.bytecode.AccessFlag; @@ -55,6 +56,7 @@ public class JarIndex { private Set m_obfClassEntries; private Ancestries m_ancestries; + private Map m_access; private Multimap m_methodImplementations; private Multimap> m_behaviorReferences; private Multimap> m_fieldReferences; @@ -67,6 +69,7 @@ public class JarIndex { m_obfClassEntries = Sets.newHashSet(); m_ancestries = new Ancestries(); + m_access = Maps.newHashMap(); m_methodImplementations = HashMultimap.create(); m_behaviorReferences = HashMultimap.create(); m_fieldReferences = HashMultimap.create(); @@ -89,7 +92,24 @@ public class JarIndex m_obfClassEntries.add( classEntry ); } - // step 2: index the types, methods + // step 2: index method/field access + for( CtClass c : JarClassIterator.classes( jar ) ) + { + fixClass( c ); + ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); + for( CtField field : c.getDeclaredFields() ) + { + FieldEntry fieldEntry = new FieldEntry( classEntry, field.getName() ); + m_access.put( fieldEntry, Access.get( field ) ); + } + for( CtBehavior behavior : c.getDeclaredBehaviors() ) + { + MethodEntry methodEntry = new MethodEntry( classEntry, behavior.getName(), behavior.getSignature() ); + m_access.put( methodEntry, Access.get( behavior ) ); + } + } + + // step 3: index the types, methods for( CtClass c : JarClassIterator.classes( jar ) ) { fixClass( c ); @@ -105,7 +125,7 @@ public class JarIndex } } - // step 3: index inner classes and anonymous classes + // step 4: index inner classes and anonymous classes for( CtClass c : JarClassIterator.classes( jar ) ) { fixClass( c ); @@ -132,7 +152,7 @@ public class JarIndex } } - // step 4: update other indices with inner class info + // step 5: update other indices with inner class info Map renames = Maps.newHashMap(); for( Map.Entry entry : m_outerClasses.entrySet() ) { @@ -522,6 +542,11 @@ public class JarIndex return m_ancestries; } + public Access getAccess( Entry entry ) + { + return m_access.get( entry ); + } + public boolean isMethodImplemented( MethodEntry methodEntry ) { Collection implementations = m_methodImplementations.get( methodEntry.getClassName() ); diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 3ee8ade0..ec0f842a 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -189,6 +189,7 @@ public class Gui @Override public void uncaughtException( Thread thread, Throwable ex ) { + ex.printStackTrace( System.err ); CrashDialog.show( ex ); } } ); -- cgit v1.2.3 From 81767097df4a119489ae8cbd9c5d8265f54daf7b Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 29 Aug 2014 01:18:10 -0400 Subject: started on mapping converter tool so we can update to newer Minecraft jars --- src/cuchaz/enigma/Util.java | 6 + src/cuchaz/enigma/convert/ClassIdentity.java | 255 +++++++++++++++++++++++++++ src/cuchaz/enigma/convert/ClassMapper.java | 73 ++++++++ 3 files changed, 334 insertions(+) create mode 100644 src/cuchaz/enigma/convert/ClassIdentity.java create mode 100644 src/cuchaz/enigma/convert/ClassMapper.java (limited to 'src') diff --git a/src/cuchaz/enigma/Util.java b/src/cuchaz/enigma/Util.java index 3686ef02..678de546 100644 --- a/src/cuchaz/enigma/Util.java +++ b/src/cuchaz/enigma/Util.java @@ -19,6 +19,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.URI; import java.net.URISyntaxException; +import java.util.Arrays; import java.util.jar.JarFile; import javassist.CannotCompileException; @@ -31,6 +32,11 @@ import com.google.common.io.CharStreams; public class Util { public static int combineHashesOrdered( Object ... objs ) + { + return combineHashesOrdered( Arrays.asList( objs ) ); + } + + public static int combineHashesOrdered( Iterable objs ) { final int prime = 67; int result = 1; diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java new file mode 100644 index 00000000..aecf7fcb --- /dev/null +++ b/src/cuchaz/enigma/convert/ClassIdentity.java @@ -0,0 +1,255 @@ +/******************************************************************************* + * 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.convert; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javassist.CtBehavior; +import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtField; +import javassist.CtMethod; +import javassist.bytecode.BadBytecode; +import javassist.bytecode.CodeIterator; +import javassist.bytecode.ConstPool; +import javassist.bytecode.Descriptor; +import javassist.bytecode.Opcode; + +import com.beust.jcommander.internal.Maps; +import com.beust.jcommander.internal.Sets; +import com.google.common.collect.Lists; + +import cuchaz.enigma.Util; +import cuchaz.enigma.bytecode.ConstPoolEditor; +import cuchaz.enigma.bytecode.InfoType; +import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.SignatureUpdater; +import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; + +public class ClassIdentity +{ + private ClassEntry m_classEntry; + private Set m_fields; + private Set m_methods; + private Set m_constructors; + private String m_staticInitializer; + + public ClassIdentity( CtClass c ) + { + m_classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); + m_fields = Sets.newHashSet(); + for( CtField field : c.getDeclaredFields() ) + { + m_fields.add( scrubSignature( scrubSignature( field.getSignature() ) ) ); + } + m_methods = Sets.newHashSet(); + for( CtMethod method : c.getDeclaredMethods() ) + { + m_methods.add( scrubSignature( method.getSignature() ) + "0x" + getBehaviorSignature( method ) ); + } + m_constructors = Sets.newHashSet(); + for( CtConstructor constructor : c.getDeclaredConstructors() ) + { + m_constructors.add( scrubSignature( constructor.getSignature() ) + "0x" + getBehaviorSignature( constructor ) ); + } + m_staticInitializer = ""; + if( c.getClassInitializer() != null ) + { + m_staticInitializer = getBehaviorSignature( c.getClassInitializer() ); + } + } + + public ClassEntry getClassEntry( ) + { + return m_classEntry; + } + + @Override + public String toString( ) + { + StringBuilder buf = new StringBuilder(); + buf.append( "class: " ); + buf.append( hashCode() ); + buf.append( "\n" ); + for( String field : m_fields ) + { + buf.append( "\tfield " ); + buf.append( field ); + buf.append( "\n" ); + } + for( String method : m_methods ) + { + buf.append( "\tmethod " ); + buf.append( method ); + buf.append( "\n" ); + } + for( String constructor : m_constructors ) + { + buf.append( "\tconstructor " ); + buf.append( constructor ); + buf.append( "\n" ); + } + if( m_staticInitializer.length() > 0 ) + { + buf.append( "\tinitializer " ); + buf.append( m_staticInitializer ); + buf.append( "\n" ); + } + return buf.toString(); + } + + private String scrubSignature( String signature ) + { + return SignatureUpdater.update( signature, new ClassNameUpdater( ) + { + private Map m_classNames = Maps.newHashMap(); + + @Override + public String update( String className ) + { + // does the class have a package? + if( className.indexOf( '/' ) >= 0 ) + { + return className; + } + + if( !m_classNames.containsKey( className ) ) + { + m_classNames.put( className, getNewClassName() ); + } + return m_classNames.get( className ); + } + + private String getNewClassName( ) + { + return String.format( "C%03d", m_classNames.size() ); + } + } ); + } + + private String getBehaviorSignature( CtBehavior behavior ) + { + try + { + // does this method have an implementation? + if( behavior.getMethodInfo().getCodeAttribute() == null ) + { + return "(none)"; + } + + // compute the hash from the opcodes + ConstPool constants = behavior.getMethodInfo().getConstPool(); + ConstPoolEditor editor = new ConstPoolEditor( constants ); + MessageDigest digest = MessageDigest.getInstance( "MD5" ); + CodeIterator iter = behavior.getMethodInfo().getCodeAttribute().iterator(); + while( iter.hasNext() ) + { + int pos = iter.next(); + + // update the hash with the opcode + int opcode = iter.byteAt( pos ); + digest.update( (byte)opcode ); + + // is there a constant value here? + int constIndex = -1; + switch( opcode ) + { + case Opcode.LDC: + constIndex = iter.byteAt( pos + 1 ); + break; + + case Opcode.LDC_W: + constIndex = ( iter.byteAt( pos + 1 ) << 8 ) | iter.byteAt( pos + 2 ); + break; + + case Opcode.LDC2_W: + constIndex = ( iter.byteAt( pos + 1 ) << 8 ) | iter.byteAt( pos + 2 ); + break; + } + + if( constIndex >= 0 ) + { + // update the hash with the constant value + ConstInfoAccessor item = editor.getItem( constIndex ); + if( item.getType() == InfoType.StringInfo ) + { + String val = constants.getStringInfo( constIndex ); + try + { + digest.update( val.getBytes( "UTF8" ) ); + } + catch( UnsupportedEncodingException ex ) + { + throw new Error( ex ); + } + } + } + } + + // convert the hash to a hex string + return toHex( digest.digest() ); + } + catch( BadBytecode | NoSuchAlgorithmException ex ) + { + throw new Error( ex ); + } + } + + private String toHex( byte[] bytes ) + { + // function taken from: + // http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java + final char[] hexArray = "0123456789ABCDEF".toCharArray(); + char[] hexChars = new char[bytes.length * 2]; + for( int j = 0; j < bytes.length; j++ ) + { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; + } + return new String( hexChars ); + } + + @Override + public boolean equals( Object other ) + { + if( other instanceof ClassIdentity ) + { + return equals( (ClassIdentity)other ); + } + return false; + } + + public boolean equals( ClassIdentity other ) + { + return m_fields.equals( other.m_fields ) + && m_methods.equals( other.m_methods ) + && m_constructors.equals( other.m_constructors ) + && m_staticInitializer.equals( other.m_staticInitializer ); + } + + @Override + public int hashCode( ) + { + List objs = Lists.newArrayList(); + objs.addAll( m_fields ); + objs.addAll( m_methods ); + objs.addAll( m_constructors ); + objs.add( m_staticInitializer ); + return Util.combineHashesOrdered( objs ); + } +} diff --git a/src/cuchaz/enigma/convert/ClassMapper.java b/src/cuchaz/enigma/convert/ClassMapper.java new file mode 100644 index 00000000..a0d5a3f1 --- /dev/null +++ b/src/cuchaz/enigma/convert/ClassMapper.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * 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.convert; + +import java.io.File; +import java.io.IOException; +import java.util.jar.JarFile; + +import javassist.CtClass; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; + +import cuchaz.enigma.analysis.JarClassIterator; + +public class ClassMapper +{ + public static void main( String[] args ) + throws IOException + { + // TEMP + JarFile fromJar = new JarFile( new File( "input/1.8-pre1.jar" ) ); + JarFile toJar = new JarFile( new File( "input/1.8-pre2.jar" ) ); + + new ClassMapper( fromJar, toJar ); + } + + public ClassMapper( JarFile a, JarFile b ) + { + int numAClasses = JarClassIterator.getClassEntries( a ).size(); + int numBClasses = JarClassIterator.getClassEntries( b ).size(); + + // TEMP + System.out.println( "A classes: " + numAClasses ); + System.out.println( "B classes: " + numBClasses ); + + // compute the a classes + Multiset aclasses = HashMultiset.create(); + for( CtClass c : JarClassIterator.classes( a ) ) + { + ClassIdentity aclass = new ClassIdentity( c ); + aclasses.add( aclass ); + } + + int numMatches = 0; + + // match the b classes to the a classes + for( CtClass c : JarClassIterator.classes( b ) ) + { + ClassIdentity bclass = new ClassIdentity( c ); + if( aclasses.contains( bclass ) ) + { + numMatches++; + } + + // TEMP + //System.out.println( bclass ); + } + + // TEMP + System.out.println( String.format( "Class matches: %d/%d (missing %d)", + numMatches, aclasses.size(), aclasses.size() - numMatches + ) ); + } +} -- cgit v1.2.3 From 5ba8046f37b6998625a6ef4d61879950dbccfc4e Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 29 Aug 2014 15:41:30 -0400 Subject: working on version conversion --- src/cuchaz/enigma/Main.java | 2 +- src/cuchaz/enigma/convert/ClassMapper.java | 111 +++++++++++++++++++++-------- 2 files changed, 82 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index bbee9024..bbd734c6 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -32,7 +32,7 @@ public class Main } // DEBUG - //gui.getController().openDeclaration( new ClassEntry( "none/bsp" ) ); + //gui.getController().openDeclaration( new ClassEntry( "none/bub" ) ); } private static File getFile( String path ) diff --git a/src/cuchaz/enigma/convert/ClassMapper.java b/src/cuchaz/enigma/convert/ClassMapper.java index a0d5a3f1..5a16a1cb 100644 --- a/src/cuchaz/enigma/convert/ClassMapper.java +++ b/src/cuchaz/enigma/convert/ClassMapper.java @@ -12,17 +12,31 @@ package cuchaz.enigma.convert; import java.io.File; import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.jar.JarFile; import javassist.CtClass; -import com.google.common.collect.HashMultiset; -import com.google.common.collect.Multiset; +import com.beust.jcommander.internal.Lists; +import com.beust.jcommander.internal.Maps; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; import cuchaz.enigma.analysis.JarClassIterator; +import cuchaz.enigma.mapping.ClassEntry; public class ClassMapper { + private int m_numSourceClasses; + private int m_numDestClasses; + private Multimap m_sourceClasses; + private Multimap m_destClasses; + private List m_unmatchedSourceClasses; + private List m_unmatchedDestClasses; + private Map m_sourceKeyIndex; + public static void main( String[] args ) throws IOException { @@ -30,44 +44,81 @@ public class ClassMapper JarFile fromJar = new JarFile( new File( "input/1.8-pre1.jar" ) ); JarFile toJar = new JarFile( new File( "input/1.8-pre2.jar" ) ); - new ClassMapper( fromJar, toJar ); + ClassMapper mapper = new ClassMapper( fromJar, toJar ); + System.out.println( String.format( "Mapped %d/%d source classes (%d unmatched) to %d/%d dest classes (%d unmatched)", + mapper.m_sourceClasses.size(), mapper.m_numSourceClasses, mapper.m_unmatchedSourceClasses.size(), + mapper.m_destClasses.size(), mapper.m_numDestClasses, mapper.m_unmatchedDestClasses.size() + ) ); } - public ClassMapper( JarFile a, JarFile b ) + public ClassMapper( JarFile sourceJar, JarFile destJar ) { - int numAClasses = JarClassIterator.getClassEntries( a ).size(); - int numBClasses = JarClassIterator.getClassEntries( b ).size(); - - // TEMP - System.out.println( "A classes: " + numAClasses ); - System.out.println( "B classes: " + numBClasses ); + m_numSourceClasses = JarClassIterator.getClassEntries( sourceJar ).size(); + m_numDestClasses = JarClassIterator.getClassEntries( destJar ).size(); - // compute the a classes - Multiset aclasses = HashMultiset.create(); - for( CtClass c : JarClassIterator.classes( a ) ) + // compute identities for the source classes + m_sourceClasses = ArrayListMultimap.create(); + m_sourceKeyIndex = Maps.newHashMap(); + for( CtClass c : JarClassIterator.classes( sourceJar ) ) { - ClassIdentity aclass = new ClassIdentity( c ); - aclasses.add( aclass ); + ClassIdentity sourceClass = new ClassIdentity( c ); + m_sourceClasses.put( sourceClass, sourceClass ); + m_sourceKeyIndex.put( sourceClass.getClassEntry(), sourceClass ); } - int numMatches = 0; - - // match the b classes to the a classes - for( CtClass c : JarClassIterator.classes( b ) ) + // match the dest classes to the source classes + m_destClasses = ArrayListMultimap.create(); + m_unmatchedDestClasses = Lists.newArrayList(); + for( CtClass c : JarClassIterator.classes( destJar ) ) { - ClassIdentity bclass = new ClassIdentity( c ); - if( aclasses.contains( bclass ) ) + ClassIdentity destClass = new ClassIdentity( c ); + Collection matchedSourceClasses = m_sourceClasses.get( destClass ); + if( matchedSourceClasses.isEmpty() ) + { + // unmatched dest class + m_unmatchedDestClasses.add( destClass ); + } + else { - numMatches++; + ClassIdentity sourceClass = matchedSourceClasses.iterator().next(); + m_destClasses.put( sourceClass, destClass ); } - - // TEMP - //System.out.println( bclass ); } - - // TEMP - System.out.println( String.format( "Class matches: %d/%d (missing %d)", - numMatches, aclasses.size(), aclasses.size() - numMatches - ) ); + + // get unmatched source classes + m_unmatchedSourceClasses = Lists.newArrayList(); + for( ClassIdentity sourceClass : m_sourceClasses.keySet() ) + { + Collection matchedSourceClasses = m_sourceClasses.get( sourceClass ); + Collection matchedDestClasses = m_destClasses.get( sourceClass ); + if( matchedDestClasses.isEmpty() ) + { + m_unmatchedSourceClasses.add( sourceClass ); + } + else if( matchedDestClasses.size() > 1 ) + { + // warn about identity collisions + System.err.println( String.format( "WARNING: identity collision:\n\tSource: %s\n\t Dest: %s", + getClassEntries( matchedSourceClasses ), + getClassEntries( matchedDestClasses ) + ) ); + } + } + } + + public Map.Entry,Collection> getMapping( ClassEntry sourceEntry ) + { + // TODO + return null; + } + + private Collection getClassEntries( Collection classes ) + { + List entries = Lists.newArrayList(); + for( ClassIdentity c : classes ) + { + entries.add( c.getClassEntry() ); + } + return entries; } } -- cgit v1.2.3 From e43fac9f55cfeebacd869352bfb090b7d8d063c1 Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 30 Aug 2014 11:41:17 -0400 Subject: got a decent class matcher working --- src/cuchaz/enigma/TranslatingTypeLoader.java | 27 +++ src/cuchaz/enigma/analysis/JarClassIterator.java | 72 ++++--- src/cuchaz/enigma/analysis/JarIndex.java | 34 +-- src/cuchaz/enigma/bytecode/ClassRenamer.java | 35 ++++ src/cuchaz/enigma/convert/ClassIdentity.java | 255 ++++++++++++++++++++--- src/cuchaz/enigma/convert/ClassMapper.java | 202 +++++++++++------- src/cuchaz/enigma/convert/ClassMatching.java | 184 ++++++++++++++++ src/cuchaz/enigma/convert/ClassNamer.java | 75 +++++++ src/cuchaz/enigma/mapping/Translator.java | 9 + 9 files changed, 748 insertions(+), 145 deletions(-) create mode 100644 src/cuchaz/enigma/convert/ClassMatching.java create mode 100644 src/cuchaz/enigma/convert/ClassNamer.java (limited to 'src') diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 1e0e95a2..e70093eb 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -47,6 +47,11 @@ public class TranslatingTypeLoader implements ITypeLoader private Map m_cache; private ClasspathTypeLoader m_defaultTypeLoader; + public TranslatingTypeLoader( JarFile jar, JarIndex jarIndex ) + { + this( jar, jarIndex, new Translator(), new Translator() ); + } + public TranslatingTypeLoader( JarFile jar, JarIndex jarIndex, Translator obfuscatingTranslator, Translator deobfuscatingTranslator ) { m_jar = jar; @@ -90,6 +95,28 @@ public class TranslatingTypeLoader implements ITypeLoader return true; } + public CtClass loadClass( String deobfClassName ) + { + byte[] data = loadType( deobfClassName ); + if( data == null ) + { + return null; + } + + // return a javassist handle for the class + String javaClassFileName = Descriptor.toJavaName( deobfClassName ); + ClassPool classPool = new ClassPool(); + classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, data ) ); + try + { + return classPool.get( javaClassFileName ); + } + catch( NotFoundException ex ) + { + throw new Error( ex ); + } + } + private byte[] loadType( String deobfClassName ) { // what class file should we actually load? diff --git a/src/cuchaz/enigma/analysis/JarClassIterator.java b/src/cuchaz/enigma/analysis/JarClassIterator.java index 6c9f1245..10ae8052 100644 --- a/src/cuchaz/enigma/analysis/JarClassIterator.java +++ b/src/cuchaz/enigma/analysis/JarClassIterator.java @@ -67,33 +67,7 @@ public class JarClassIterator implements Iterator JarEntry entry = m_iter.next(); try { - // read the class into a buffer - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] buf = new byte[Constants.KiB]; - int totalNumBytesRead = 0; - InputStream in = m_jar.getInputStream( entry ); - while( in.available() > 0 ) - { - int numBytesRead = in.read( buf ); - if( numBytesRead < 0 ) - { - break; - } - bos.write( buf, 0, numBytesRead ); - - // sanity checking - totalNumBytesRead += numBytesRead; - if( totalNumBytesRead > Constants.MiB ) - { - throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" ); - } - } - - // get a javassist handle for the class - String className = Descriptor.toJavaName( getClassEntry( entry ).getName() ); - ClassPool classPool = new ClassPool(); - classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); - return classPool.get( className ); + return getClass( m_jar, entry ); } catch( IOException | NotFoundException ex ) { @@ -136,6 +110,50 @@ public class JarClassIterator implements Iterator }; } + public static CtClass getClass( JarFile jar, ClassEntry classEntry ) + { + try + { + return getClass( jar, new JarEntry( classEntry.getName() + ".class" ) ); + } + catch( IOException | NotFoundException ex ) + { + throw new Error( "Unable to load class: " + classEntry.getName() ); + } + } + + private static CtClass getClass( JarFile jar, JarEntry entry ) + throws IOException, NotFoundException + { + // read the class into a buffer + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buf = new byte[Constants.KiB]; + int totalNumBytesRead = 0; + InputStream in = jar.getInputStream( entry ); + while( in.available() > 0 ) + { + int numBytesRead = in.read( buf ); + if( numBytesRead < 0 ) + { + break; + } + bos.write( buf, 0, numBytesRead ); + + // sanity checking + totalNumBytesRead += numBytesRead; + if( totalNumBytesRead > Constants.MiB ) + { + throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" ); + } + } + + // get a javassist handle for the class + String className = Descriptor.toJavaName( getClassEntry( entry ).getName() ); + ClassPool classPool = new ClassPool(); + classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); + return classPool.get( className ); + } + private static ClassEntry getClassEntry( JarEntry entry ) { return new ClassEntry( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) ); diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index deacf16d..b479b69e 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -95,7 +95,7 @@ public class JarIndex // step 2: index method/field access for( CtClass c : JarClassIterator.classes( jar ) ) { - fixClass( c ); + ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); for( CtField field : c.getDeclaredFields() ) { @@ -112,7 +112,7 @@ public class JarIndex // step 3: index the types, methods for( CtClass c : JarClassIterator.classes( jar ) ) { - fixClass( c ); + ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); String className = Descriptor.toJvmName( c.getName() ); m_ancestries.addSuperclass( className, Descriptor.toJvmName( c.getClassFile().getSuperclass() ) ); for( String interfaceName : c.getClassFile().getInterfaces() ) @@ -128,8 +128,7 @@ public class JarIndex // step 4: index inner classes and anonymous classes for( CtClass c : JarClassIterator.classes( jar ) ) { - fixClass( c ); - + ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); String outerClassName = findOuterClass( c ); if( outerClassName != null ) { @@ -164,17 +163,6 @@ public class JarIndex renameMethods( m_bridgeMethods ); } - private void fixClass( CtClass c ) - { - ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); - if( classEntry.isInDefaultPackage() ) - { - // move class out of default package - classEntry = new ClassEntry( Constants.NonePackage + "/" + classEntry.getName() ); - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); - } - } - private void indexBehavior( CtBehavior behavior ) { // get the method entry @@ -729,6 +717,22 @@ public class JarIndex private void renameClasses( Map renames ) { + // rename class entries + Set obfClassEntries = Sets.newHashSet(); + for( ClassEntry classEntry : m_obfClassEntries ) + { + if( renames.containsKey( classEntry.getName() ) ) + { + obfClassEntries.add( new ClassEntry( renames.get( classEntry.getName() ) ) ); + } + else + { + obfClassEntries.add( classEntry ); + } + } + m_obfClassEntries = obfClassEntries; + + // rename others m_ancestries.renameClasses( renames ); renameClassesInMultimap( renames, m_methodImplementations ); renameClassesInMultimap( renames, m_behaviorReferences ); diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java index f3a8c0ef..efe22a18 100644 --- a/src/cuchaz/enigma/bytecode/ClassRenamer.java +++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java @@ -14,6 +14,7 @@ import java.util.Map; import java.util.Set; import javassist.ClassMap; +import javassist.CtBehavior; import javassist.CtClass; import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; @@ -23,6 +24,8 @@ import com.beust.jcommander.internal.Sets; import com.google.common.collect.Maps; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.SignatureUpdater; +import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class ClassRenamer { @@ -115,5 +118,37 @@ public class ClassRenamer } } ClassRenamer.renameClasses( c, map ); + + // TEMP + for( ClassEntry classEntry : ClassRenamer.getAllClassEntries( c ) ) + { + if( classEntry.isInDefaultPackage() ) + { + throw new Error( "!!! " + classEntry ); + } + } + + // TEMP + for( CtBehavior behavior : c.getDeclaredBehaviors() ) + { + if( behavior.getSignature() == null ) + { + continue; + } + + SignatureUpdater.update( behavior.getSignature(), new ClassNameUpdater( ) + { + @Override + public String update( String className ) + { + ClassEntry classEntry = new ClassEntry( className ); + if( classEntry.isInDefaultPackage() ) + { + throw new Error( "!!! " + className ); + } + return className; + } + } ); + } } } diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java index aecf7fcb..0a3a4497 100644 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ b/src/cuchaz/enigma/convert/ClassIdentity.java @@ -13,10 +13,12 @@ package cuchaz.enigma.convert; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Set; +import javassist.CannotCompileException; import javassist.CtBehavior; import javassist.CtClass; import javassist.CtConstructor; @@ -27,34 +29,58 @@ import javassist.bytecode.CodeIterator; import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; import javassist.bytecode.Opcode; +import javassist.expr.ConstructorCall; +import javassist.expr.ExprEditor; +import javassist.expr.FieldAccess; +import javassist.expr.MethodCall; +import javassist.expr.NewExpr; import com.beust.jcommander.internal.Maps; import com.beust.jcommander.internal.Sets; import com.google.common.collect.Lists; +import cuchaz.enigma.Constants; import cuchaz.enigma.Util; +import cuchaz.enigma.analysis.ClassImplementationsTreeNode; +import cuchaz.enigma.analysis.EntryReference; +import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.bytecode.ConstPoolEditor; import cuchaz.enigma.bytecode.InfoType; import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; +import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; +import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.SignatureUpdater; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class ClassIdentity { private ClassEntry m_classEntry; + private SidedClassNamer m_namer; private Set m_fields; private Set m_methods; private Set m_constructors; private String m_staticInitializer; + private String m_extends; + private Set m_implements; + private Set m_implementations; + private Set m_references; - public ClassIdentity( CtClass c ) + public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences ) { + m_namer = namer; + + // stuff from the bytecode + m_classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); m_fields = Sets.newHashSet(); for( CtField field : c.getDeclaredFields() ) { - m_fields.add( scrubSignature( scrubSignature( field.getSignature() ) ) ); + m_fields.add( scrubSignature( field.getSignature() ) ); } m_methods = Sets.newHashSet(); for( CtMethod method : c.getDeclaredMethods() ) @@ -71,6 +97,73 @@ public class ClassIdentity { m_staticInitializer = getBehaviorSignature( c.getClassInitializer() ); } + m_extends = ""; + if( c.getClassFile().getSuperclass() != null ) + { + m_extends = scrubClassName( c.getClassFile().getSuperclass() ); + } + m_implements = Sets.newHashSet(); + for( String interfaceName : c.getClassFile().getInterfaces() ) + { + m_implements.add( scrubClassName( interfaceName ) ); + } + + // stuff from the jar index + + m_implementations = Sets.newHashSet(); + @SuppressWarnings( "unchecked" ) + Enumeration implementations = index.getClassImplementations( null, m_classEntry ).children(); + while( implementations.hasMoreElements() ) + { + ClassImplementationsTreeNode node = implementations.nextElement(); + m_implementations.add( scrubClassName( node.getClassEntry().getName() ) ); + } + + m_references = Sets.newHashSet(); + if( useReferences ) + { + for( CtField field : c.getDeclaredFields() ) + { + FieldEntry fieldEntry = new FieldEntry( m_classEntry, field.getName() ); + for( EntryReference reference : index.getFieldReferences( fieldEntry ) ) + { + addReference( reference ); + } + } + for( CtMethod method : c.getDeclaredMethods() ) + { + MethodEntry methodEntry = new MethodEntry( m_classEntry, method.getName(), method.getSignature() ); + for( EntryReference reference : index.getBehaviorReferences( methodEntry ) ) + { + addReference( reference ); + } + } + for( CtConstructor constructor : c.getDeclaredConstructors() ) + { + ConstructorEntry constructorEntry = new ConstructorEntry( m_classEntry, constructor.getSignature() ); + for( EntryReference reference : index.getBehaviorReferences( constructorEntry ) ) + { + addReference( reference ); + } + } + } + } + + private void addReference( EntryReference reference ) + { + if( reference.context.getSignature() != null ) + { + m_references.add( String.format( "%s_%s", + scrubClassName( reference.context.getClassName() ), + scrubSignature( reference.context.getSignature() ) + ) ); + } + else + { + m_references.add( String.format( "%s_", + scrubClassName( reference.context.getClassName() ) + ) ); + } } public ClassEntry getClassEntry( ) @@ -109,9 +202,38 @@ public class ClassIdentity buf.append( m_staticInitializer ); buf.append( "\n" ); } + if( m_extends.length() > 0 ) + { + buf.append( "\textends " ); + buf.append( m_extends ); + buf.append( "\n" ); + } + for( String interfaceName : m_implements ) + { + buf.append( "\timplements " ); + buf.append( interfaceName ); + buf.append( "\n" ); + } + for( String implementation : m_implementations ) + { + buf.append( "\timplemented by " ); + buf.append( implementation ); + buf.append( "\n" ); + } + for( String reference : m_references ) + { + buf.append( "\treference " ); + buf.append( reference ); + buf.append( "\n" ); + } return buf.toString(); } + private String scrubClassName( String className ) + { + return scrubSignature( "L" + Descriptor.toJvmName( className ) + ";" ); + } + private String scrubSignature( String signature ) { return SignatureUpdater.update( signature, new ClassNameUpdater( ) @@ -121,12 +243,30 @@ public class ClassIdentity @Override public String update( String className ) { - // does the class have a package? - if( className.indexOf( '/' ) >= 0 ) + // classes not in the none package can be passed through + ClassEntry classEntry = new ClassEntry( className ); + if( !classEntry.getPackageName().equals( Constants.NonePackage ) ) { return className; } + // is this class ourself? + if( className.equals( m_classEntry.getName() ) ) + { + return "CSelf"; + } + + // try the namer + if( m_namer != null ) + { + String newName = m_namer.getName( className ); + if( newName != null ) + { + return newName; + } + } + + // otherwise, use local naming if( !m_classNames.containsKey( className ) ) { m_classNames.put( className, getNewClassName() ); @@ -141,6 +281,11 @@ public class ClassIdentity } ); } + private boolean isClassMatchedUniquely( String className ) + { + return m_namer != null && m_namer.getName( Descriptor.toJvmName( className ) ) != null; + } + private String getBehaviorSignature( CtBehavior behavior ) { try @@ -153,8 +298,7 @@ public class ClassIdentity // compute the hash from the opcodes ConstPool constants = behavior.getMethodInfo().getConstPool(); - ConstPoolEditor editor = new ConstPoolEditor( constants ); - MessageDigest digest = MessageDigest.getInstance( "MD5" ); + final MessageDigest digest = MessageDigest.getInstance( "MD5" ); CodeIterator iter = behavior.getMethodInfo().getCodeAttribute().iterator(); while( iter.hasNext() ) { @@ -164,46 +308,91 @@ public class ClassIdentity int opcode = iter.byteAt( pos ); digest.update( (byte)opcode ); - // is there a constant value here? - int constIndex = -1; switch( opcode ) { case Opcode.LDC: - constIndex = iter.byteAt( pos + 1 ); + { + int constIndex = iter.byteAt( pos + 1 ); + updateHashWithConstant( digest, constants, constIndex ); + } break; case Opcode.LDC_W: - constIndex = ( iter.byteAt( pos + 1 ) << 8 ) | iter.byteAt( pos + 2 ); - break; - case Opcode.LDC2_W: - constIndex = ( iter.byteAt( pos + 1 ) << 8 ) | iter.byteAt( pos + 2 ); + { + int constIndex = ( iter.byteAt( pos + 1 ) << 8 ) | iter.byteAt( pos + 2 ); + updateHashWithConstant( digest, constants, constIndex ); + } break; } + } + + // update hash with method and field accesses + behavior.instrument( new ExprEditor( ) + { + @Override + public void edit( MethodCall call ) + { + updateHashWithString( digest, scrubClassName( call.getClassName() ) ); + updateHashWithString( digest, scrubSignature( call.getSignature() ) ); + if( isClassMatchedUniquely( call.getClassName() ) ) + { + updateHashWithString( digest, call.getMethodName() ); + } + } - if( constIndex >= 0 ) + @Override + public void edit( FieldAccess access ) { - // update the hash with the constant value - ConstInfoAccessor item = editor.getItem( constIndex ); - if( item.getType() == InfoType.StringInfo ) + updateHashWithString( digest, scrubClassName( access.getClassName() ) ); + updateHashWithString( digest, scrubSignature( access.getSignature() ) ); + if( isClassMatchedUniquely( access.getClassName() ) ) { - String val = constants.getStringInfo( constIndex ); - try - { - digest.update( val.getBytes( "UTF8" ) ); - } - catch( UnsupportedEncodingException ex ) - { - throw new Error( ex ); - } + updateHashWithString( digest, access.getFieldName() ); } } - } + + @Override + public void edit( ConstructorCall call ) + { + updateHashWithString( digest, scrubClassName( call.getClassName() ) ); + updateHashWithString( digest, scrubSignature( call.getSignature() ) ); + } + + @Override + public void edit( NewExpr expr ) + { + updateHashWithString( digest, scrubClassName( expr.getClassName() ) ); + } + } ); // convert the hash to a hex string return toHex( digest.digest() ); } - catch( BadBytecode | NoSuchAlgorithmException ex ) + catch( BadBytecode | NoSuchAlgorithmException | CannotCompileException ex ) + { + throw new Error( ex ); + } + } + + private void updateHashWithConstant( MessageDigest digest, ConstPool constants, int index ) + { + ConstPoolEditor editor = new ConstPoolEditor( constants ); + ConstInfoAccessor item = editor.getItem( index ); + if( item.getType() == InfoType.StringInfo ) + { + updateHashWithString( digest, constants.getStringInfo( index ) ); + } + // TODO: other constants + } + + private void updateHashWithString( MessageDigest digest, String val ) + { + try + { + digest.update( val.getBytes( "UTF8" ) ); + } + catch( UnsupportedEncodingException ex ) { throw new Error( ex ); } @@ -239,7 +428,11 @@ public class ClassIdentity return m_fields.equals( other.m_fields ) && m_methods.equals( other.m_methods ) && m_constructors.equals( other.m_constructors ) - && m_staticInitializer.equals( other.m_staticInitializer ); + && m_staticInitializer.equals( other.m_staticInitializer ) + && m_extends.equals( other.m_extends ) + && m_implements.equals( other.m_implements ) + && m_implementations.equals( other.m_implementations ) + && m_references.equals( other.m_references ); } @Override @@ -250,6 +443,10 @@ public class ClassIdentity objs.addAll( m_methods ); objs.addAll( m_constructors ); objs.add( m_staticInitializer ); + objs.add( m_extends ); + objs.addAll( m_implements ); + objs.addAll( m_implementations ); + objs.addAll( m_references ); return Util.combineHashesOrdered( objs ); } } diff --git a/src/cuchaz/enigma/convert/ClassMapper.java b/src/cuchaz/enigma/convert/ClassMapper.java index 5a16a1cb..fe48c505 100644 --- a/src/cuchaz/enigma/convert/ClassMapper.java +++ b/src/cuchaz/enigma/convert/ClassMapper.java @@ -12,31 +12,20 @@ package cuchaz.enigma.convert; import java.io.File; import java.io.IOException; -import java.util.Collection; +import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.jar.JarFile; import javassist.CtClass; - -import com.beust.jcommander.internal.Lists; -import com.beust.jcommander.internal.Maps; -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Multimap; - -import cuchaz.enigma.analysis.JarClassIterator; +import cuchaz.enigma.TranslatingTypeLoader; +import cuchaz.enigma.analysis.JarIndex; +import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; import cuchaz.enigma.mapping.ClassEntry; public class ClassMapper { - private int m_numSourceClasses; - private int m_numDestClasses; - private Multimap m_sourceClasses; - private Multimap m_destClasses; - private List m_unmatchedSourceClasses; - private List m_unmatchedDestClasses; - private Map m_sourceKeyIndex; - public static void main( String[] args ) throws IOException { @@ -44,81 +33,146 @@ public class ClassMapper JarFile fromJar = new JarFile( new File( "input/1.8-pre1.jar" ) ); JarFile toJar = new JarFile( new File( "input/1.8-pre2.jar" ) ); - ClassMapper mapper = new ClassMapper( fromJar, toJar ); - System.out.println( String.format( "Mapped %d/%d source classes (%d unmatched) to %d/%d dest classes (%d unmatched)", - mapper.m_sourceClasses.size(), mapper.m_numSourceClasses, mapper.m_unmatchedSourceClasses.size(), - mapper.m_destClasses.size(), mapper.m_numDestClasses, mapper.m_unmatchedDestClasses.size() - ) ); + // compute the matching + ClassMatching matching = ClassMapper.computeMatching( fromJar, toJar ); + + // TODO: use the matching to convert the mappings } - public ClassMapper( JarFile sourceJar, JarFile destJar ) + public static ClassMatching computeMatching( JarFile sourceJar, JarFile destJar ) { - m_numSourceClasses = JarClassIterator.getClassEntries( sourceJar ).size(); - m_numDestClasses = JarClassIterator.getClassEntries( destJar ).size(); + // index jars + System.out.println( "Indexing source jar..." ); + JarIndex sourceIndex = new JarIndex(); + sourceIndex.indexJar( sourceJar ); + System.out.println( "Indexing dest jar..." ); + JarIndex destIndex = new JarIndex(); + destIndex.indexJar( destJar ); - // compute identities for the source classes - m_sourceClasses = ArrayListMultimap.create(); - m_sourceKeyIndex = Maps.newHashMap(); - for( CtClass c : JarClassIterator.classes( sourceJar ) ) - { - ClassIdentity sourceClass = new ClassIdentity( c ); - m_sourceClasses.put( sourceClass, sourceClass ); - m_sourceKeyIndex.put( sourceClass.getClassEntry(), sourceClass ); - } + System.out.println( "Computing matching..." ); - // match the dest classes to the source classes - m_destClasses = ArrayListMultimap.create(); - m_unmatchedDestClasses = Lists.newArrayList(); - for( CtClass c : JarClassIterator.classes( destJar ) ) + TranslatingTypeLoader sourceLoader = new TranslatingTypeLoader( sourceJar, sourceIndex ); + TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex ); + + ClassMatching matching = null; + for( boolean useReferences : Arrays.asList( false, true ) ) { - ClassIdentity destClass = new ClassIdentity( c ); - Collection matchedSourceClasses = m_sourceClasses.get( destClass ); - if( matchedSourceClasses.isEmpty() ) - { - // unmatched dest class - m_unmatchedDestClasses.add( destClass ); - } - else + int numMatches = 0; + do { - ClassIdentity sourceClass = matchedSourceClasses.iterator().next(); - m_destClasses.put( sourceClass, destClass ); + SidedClassNamer sourceNamer = null; + SidedClassNamer destNamer = null; + if( matching != null ) + { + // build a class namer + ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); + sourceNamer = namer.getSourceNamer(); + destNamer = namer.getDestNamer(); + + // note the number of matches + numMatches = matching.getUniqueMatches().size(); + } + + // get the entries left to match + Set sourceClassEntries = sourceIndex.getObfClassEntries(); + Set destClassEntries = destIndex.getObfClassEntries(); + if( matching != null ) + { + sourceClassEntries.clear(); + destClassEntries.clear(); + for( Map.Entry,List> entry : matching.getAmbiguousMatches().entrySet() ) + { + for( ClassIdentity c : entry.getKey() ) + { + sourceClassEntries.add( c.getClassEntry() ); + matching.removeSource( c ); + } + for( ClassIdentity c : entry.getValue() ) + { + destClassEntries.add( c.getClassEntry() ); + matching.removeDest( c ); + } + } + for( ClassIdentity c : matching.getUnmatchedSourceClasses() ) + { + sourceClassEntries.add( c.getClassEntry() ); + matching.removeSource( c ); + } + for( ClassIdentity c : matching.getUnmatchedDestClasses() ) + { + destClassEntries.add( c.getClassEntry() ); + matching.removeDest( c ); + } + } + else + { + matching = new ClassMatching(); + } + + // compute a matching for the classes + for( ClassEntry classEntry : sourceClassEntries ) + { + CtClass c = sourceLoader.loadClass( classEntry.getName() ); + ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences ); + matching.addSource( sourceClass ); + } + for( ClassEntry classEntry : destClassEntries ) + { + CtClass c = destLoader.loadClass( classEntry.getName() ); + ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences ); + matching.matchDestClass( destClass ); + } + + // TEMP + System.out.println( matching ); } + while( matching.getUniqueMatches().size() - numMatches > 0 ); } - - // get unmatched source classes - m_unmatchedSourceClasses = Lists.newArrayList(); - for( ClassIdentity sourceClass : m_sourceClasses.keySet() ) + + /* DEBUG: show some ambiguous matches + List,List>> ambiguousMatches = new ArrayList,List>>( matching.getAmbiguousMatches().entrySet() ); + Collections.sort( ambiguousMatches, new Comparator,List>>( ) { - Collection matchedSourceClasses = m_sourceClasses.get( sourceClass ); - Collection matchedDestClasses = m_destClasses.get( sourceClass ); - if( matchedDestClasses.isEmpty() ) + @Override + public int compare( Map.Entry,List> a, Map.Entry,List> b ) { - m_unmatchedSourceClasses.add( sourceClass ); + String aName = a.getKey().get( 0 ).getClassEntry().getName(); + String bName = b.getKey().get( 0 ).getClassEntry().getName(); + return aName.compareTo( bName ); } - else if( matchedDestClasses.size() > 1 ) + } ); + for( Map.Entry,List> entry : ambiguousMatches ) + { + for( ClassIdentity c : entry.getKey() ) { - // warn about identity collisions - System.err.println( String.format( "WARNING: identity collision:\n\tSource: %s\n\t Dest: %s", - getClassEntries( matchedSourceClasses ), - getClassEntries( matchedDestClasses ) - ) ); + System.out.print( c.getClassEntry().getName() + " " ); } + System.out.println(); + } + Map.Entry,List> entry = ambiguousMatches.get( 7 ); + for( ClassIdentity c : entry.getKey() ) + { + System.out.println( c ); } + for( ClassIdentity c : entry.getKey() ) + { + System.out.println( decompile( sourceLoader, c.getClassEntry() ) ); + } + */ + + return matching; } - public Map.Entry,Collection> getMapping( ClassEntry sourceEntry ) + /* DEBUG + private static String decompile( TranslatingTypeLoader loader, ClassEntry classEntry ) { - // TODO - return null; - } - - private Collection getClassEntries( Collection classes ) - { - List entries = Lists.newArrayList(); - for( ClassIdentity c : classes ) - { - entries.add( c.getClassEntry() ); - } - return entries; + PlainTextOutput output = new PlainTextOutput(); + DecompilerSettings settings = DecompilerSettings.javaDefaults(); + settings.setForceExplicitImports( true ); + settings.setShowSyntheticMembers( true ); + settings.setTypeLoader( loader ); + Decompiler.decompile( classEntry.getName(), output, settings ); + return output.toString(); } + */ } diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java new file mode 100644 index 00000000..fea84386 --- /dev/null +++ b/src/cuchaz/enigma/convert/ClassMatching.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * 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.convert; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import com.beust.jcommander.internal.Lists; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.Multimap; + +public class ClassMatching +{ + private Multimap m_sourceClasses; + private Multimap m_matchedDestClasses; + private List m_unmatchedDestClasses; + + public ClassMatching( ) + { + m_sourceClasses = ArrayListMultimap.create(); + m_matchedDestClasses = ArrayListMultimap.create(); + m_unmatchedDestClasses = Lists.newArrayList(); + } + + public void addSource( ClassIdentity c ) + { + m_sourceClasses.put( c, c ); + } + + public void matchDestClass( ClassIdentity destClass ) + { + Collection matchedSourceClasses = m_sourceClasses.get( destClass ); + if( matchedSourceClasses.isEmpty() ) + { + // no match + m_unmatchedDestClasses.add( destClass ); + } + else + { + // found a match + m_matchedDestClasses.put( destClass, destClass ); + + // DEBUG + ClassIdentity sourceClass = matchedSourceClasses.iterator().next(); + assert( sourceClass.hashCode() == destClass.hashCode() ); + assert( sourceClass.equals( destClass ) ); + } + } + + public void removeSource( ClassIdentity sourceClass ) + { + m_sourceClasses.remove( sourceClass, sourceClass ); + } + + public void removeDest( ClassIdentity destClass ) + { + m_matchedDestClasses.remove( destClass, destClass ); + m_unmatchedDestClasses.remove( destClass ); + } + + public List getSourceClasses( ) + { + return new ArrayList( m_sourceClasses.values() ); + } + + public List getDestClasses( ) + { + List classes = Lists.newArrayList(); + classes.addAll( m_matchedDestClasses.values() ); + classes.addAll( m_unmatchedDestClasses ); + return classes; + } + + public BiMap getUniqueMatches( ) + { + BiMap uniqueMatches = HashBiMap.create(); + for( ClassIdentity sourceClass : m_sourceClasses.keySet() ) + { + Collection matchedSourceClasses = m_sourceClasses.get( sourceClass ); + Collection matchedDestClasses = m_matchedDestClasses.get( sourceClass ); + if( matchedSourceClasses.size() == 1 && matchedDestClasses.size() == 1 ) + { + ClassIdentity matchedSourceClass = matchedSourceClasses.iterator().next(); + ClassIdentity matchedDestClass = matchedSourceClasses.iterator().next(); + uniqueMatches.put( matchedSourceClass, matchedDestClass ); + } + } + return uniqueMatches; + } + + public BiMap,List> getAmbiguousMatches( ) + { + BiMap,List> ambiguousMatches = HashBiMap.create(); + for( ClassIdentity sourceClass : m_sourceClasses.keySet() ) + { + Collection matchedSourceClasses = m_sourceClasses.get( sourceClass ); + Collection matchedDestClasses = m_matchedDestClasses.get( sourceClass ); + if( matchedSourceClasses.size() > 1 && matchedDestClasses.size() > 1 ) + { + ambiguousMatches.put( + new ArrayList( matchedSourceClasses ), + new ArrayList( matchedDestClasses ) + ); + } + } + return ambiguousMatches; + } + + public int getNumAmbiguousSourceMatches( ) + { + int num = 0; + for( Map.Entry,List> entry : getAmbiguousMatches().entrySet() ) + { + num += entry.getKey().size(); + } + return num; + } + + public int getNumAmbiguousDestMatches( ) + { + int num = 0; + for( Map.Entry,List> entry : getAmbiguousMatches().entrySet() ) + { + num += entry.getValue().size(); + } + return num; + } + + public List getUnmatchedSourceClasses( ) + { + List classes = Lists.newArrayList(); + for( ClassIdentity sourceClass : getSourceClasses() ) + { + if( m_matchedDestClasses.get( sourceClass ).isEmpty() ) + { + classes.add( sourceClass ); + } + } + return classes; + } + + public List getUnmatchedDestClasses( ) + { + return new ArrayList( m_unmatchedDestClasses ); + } + + @Override + public String toString( ) + { + StringBuilder buf = new StringBuilder(); + + buf.append( "Source classes: " ); + buf.append( getSourceClasses().size() ); + buf.append( "\n\tUnique: " ); + buf.append( getUniqueMatches().size() ); + buf.append( "\n\tAmbiguous: " ); + buf.append( getNumAmbiguousSourceMatches() ); + buf.append( "\n\tUnmatched: " ); + buf.append( getUnmatchedSourceClasses().size() ); + + buf.append( "\nDest classes: " ); + buf.append( getDestClasses().size() ); + buf.append( "\n\tUnique: " ); + buf.append( getUniqueMatches().size() ); + buf.append( "\n\tAmbiguous: " ); + buf.append( getNumAmbiguousDestMatches() ); + buf.append( "\n\tUnmatched: " ); + buf.append( getUnmatchedDestClasses().size() ); + + return buf.toString(); + } +} diff --git a/src/cuchaz/enigma/convert/ClassNamer.java b/src/cuchaz/enigma/convert/ClassNamer.java new file mode 100644 index 00000000..1cd96657 --- /dev/null +++ b/src/cuchaz/enigma/convert/ClassNamer.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.convert; + +import java.util.Map; + +import com.beust.jcommander.internal.Maps; +import com.google.common.collect.BiMap; + +public class ClassNamer +{ + public interface SidedClassNamer + { + String getName( String name ); + } + + private Map m_sourceNames; + private Map m_destNames; + + public ClassNamer( BiMap mappings ) + { + // convert the identity mappings to name maps + m_sourceNames = Maps.newHashMap(); + m_destNames = Maps.newHashMap(); + int i = 0; + for( Map.Entry entry : mappings.entrySet() ) + { + String name = String.format( "M%04d", i++ ); + m_sourceNames.put( entry.getKey().getClassEntry().getName(), name ); + m_destNames.put( entry.getValue().getClassEntry().getName(), name ); + } + } + + public String getSourceName( String name ) + { + return m_sourceNames.get( name ); + } + + public String getDestName( String name ) + { + return m_destNames.get( name ); + } + + public SidedClassNamer getSourceNamer( ) + { + return new SidedClassNamer( ) + { + @Override + public String getName( String name ) + { + return getSourceName( name ); + } + }; + } + + public SidedClassNamer getDestNamer( ) + { + return new SidedClassNamer( ) + { + @Override + public String getName( String name ) + { + return getDestName( name ); + } + }; + } +} diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index a671c275..23bf0951 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -14,6 +14,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import com.beust.jcommander.internal.Maps; + import cuchaz.enigma.analysis.Ancestries; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; @@ -23,6 +25,13 @@ public class Translator public Map m_classes; private Ancestries m_ancestries; + public Translator( ) + { + m_direction = null; + m_classes = Maps.newHashMap(); + m_ancestries = new Ancestries(); + } + protected Translator( TranslationDirection direction, Map classes, Ancestries ancestries ) { m_direction = direction; -- cgit v1.2.3 From 63172120a39a315e29bc38ea6634741797b3dcab Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 30 Aug 2014 14:14:54 -0400 Subject: finished class matching for now, need to work on class member matching --- src/cuchaz/enigma/convert/ClassIdentity.java | 40 ++++- src/cuchaz/enigma/convert/ClassMapper.java | 229 ++++++++++++++++++++------- src/cuchaz/enigma/convert/ClassMatching.java | 33 ++++ src/cuchaz/enigma/mapping/ClassMapping.java | 29 ++++ src/cuchaz/enigma/mapping/Mappings.java | 25 +++ src/cuchaz/enigma/mapping/MethodMapping.java | 20 +++ 6 files changed, 319 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java index 0a3a4497..980f31f5 100644 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ b/src/cuchaz/enigma/convert/ClassIdentity.java @@ -60,6 +60,7 @@ import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class ClassIdentity { private ClassEntry m_classEntry; + private String m_rawName; private SidedClassNamer m_namer; private Set m_fields; private Set m_methods; @@ -70,13 +71,18 @@ public class ClassIdentity private Set m_implementations; private Set m_references; - public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences ) + public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences, boolean useRawNames ) { m_namer = namer; // stuff from the bytecode m_classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); + m_rawName = ""; + if( useRawNames ) + { + m_rawName = m_classEntry.getName(); + } m_fields = Sets.newHashSet(); for( CtField field : c.getDeclaredFields() ) { @@ -176,8 +182,16 @@ public class ClassIdentity { StringBuilder buf = new StringBuilder(); buf.append( "class: " ); + buf.append( m_classEntry.getName() ); + buf.append( " " ); buf.append( hashCode() ); buf.append( "\n" ); + if( m_rawName.length() > 0 ) + { + buf.append( "\traw name: " ); + buf.append( m_rawName ); + buf.append( "\n" ); + } for( String field : m_fields ) { buf.append( "\tfield " ); @@ -425,7 +439,8 @@ public class ClassIdentity public boolean equals( ClassIdentity other ) { - return m_fields.equals( other.m_fields ) + return m_rawName.equals( other.m_rawName ) + && m_fields.equals( other.m_fields ) && m_methods.equals( other.m_methods ) && m_constructors.equals( other.m_constructors ) && m_staticInitializer.equals( other.m_staticInitializer ) @@ -439,6 +454,7 @@ public class ClassIdentity public int hashCode( ) { List objs = Lists.newArrayList(); + objs.add( m_rawName ); objs.addAll( m_fields ); objs.addAll( m_methods ); objs.addAll( m_constructors ); @@ -449,4 +465,24 @@ public class ClassIdentity objs.addAll( m_references ); return Util.combineHashesOrdered( objs ); } + + public int getMatchScore( ClassIdentity other ) + { + return getNumMatches( m_fields, other.m_fields ) + + getNumMatches( m_methods, other.m_methods ) + + getNumMatches( m_constructors, other.m_constructors ); + } + + private int getNumMatches( Set a, Set b ) + { + int numMatches = 0; + for( String val : a ) + { + if( b.contains( val ) ) + { + numMatches++; + } + } + return numMatches; + } } diff --git a/src/cuchaz/enigma/convert/ClassMapper.java b/src/cuchaz/enigma/convert/ClassMapper.java index fe48c505..fd6ab922 100644 --- a/src/cuchaz/enigma/convert/ClassMapper.java +++ b/src/cuchaz/enigma/convert/ClassMapper.java @@ -11,32 +11,130 @@ package cuchaz.enigma.convert; import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import java.util.jar.JarFile; import javassist.CtClass; + +import com.beust.jcommander.internal.Sets; +import com.google.common.collect.Maps; + +import cuchaz.enigma.Constants; import cuchaz.enigma.TranslatingTypeLoader; import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ClassMapping; +import cuchaz.enigma.mapping.MappingParseException; +import cuchaz.enigma.mapping.Mappings; +import cuchaz.enigma.mapping.MappingsReader; +import cuchaz.enigma.mapping.MappingsWriter; public class ClassMapper { public static void main( String[] args ) - throws IOException + throws IOException, MappingParseException { // TEMP JarFile fromJar = new JarFile( new File( "input/1.8-pre1.jar" ) ); - JarFile toJar = new JarFile( new File( "input/1.8-pre2.jar" ) ); + JarFile toJar = new JarFile( new File( "input/1.8-pre3.jar" ) ); + File inMappingsFile = new File( "../minecraft-mappings/1.8-pre.mappings" ); + File outMappingsFile = new File( "../minecraft-mappings/1.8-pre3.mappings" ); // compute the matching ClassMatching matching = ClassMapper.computeMatching( fromJar, toJar ); - // TODO: use the matching to convert the mappings + // use the matching to convert the mappings + Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) ); + Map>> conversionMap = matching.getConversionMap(); + Map finalConversion = Maps.newHashMap(); + Set unmatchedSourceClasses = Sets.newHashSet(); + for( ClassMapping classMapping : mappings.classes() ) + { + // is there a match for this class? + Map.Entry> entry = conversionMap.get( classMapping.getObfName() ); + ClassIdentity sourceClass = entry.getKey(); + List matches = entry.getValue(); + + if( matches.isEmpty() ) + { + // no match! =( + System.out.println( "No exact match for source class " + classMapping.getObfName() ); + + // find the closest classes + TreeMap scoredMatches = Maps.newTreeMap( Collections.reverseOrder() ); + for( ClassIdentity c : matching.getUnmatchedDestClasses() ) + { + scoredMatches.put( sourceClass.getMatchScore( c ), c ); + } + Iterator> iter = scoredMatches.entrySet().iterator(); + for( int i=0; i<10 && iter.hasNext(); i++ ) + { + Map.Entry score = iter.next(); + System.out.println( String.format( "\tScore: %3d %s", score.getKey(), score.getValue().getClassEntry().getName() ) ); + } + + // does the best match have a non-zero score and the same name? + Map.Entry bestMatch = scoredMatches.firstEntry(); + if( bestMatch.getKey() > 0 && bestMatch.getValue().getClassEntry().equals( sourceClass.getClassEntry() ) ) + { + // use it + System.out.println( "\tAutomatically choosing likely match: " + bestMatch.getValue().getClassEntry().getName() ); + addFinalConversion( finalConversion, sourceClass, bestMatch.getValue() ); + } + else + { + unmatchedSourceClasses.add( classMapping.getObfName() ); + } + } + if( matches.size() == 1 ) + { + // unique match! We're good to go! + addFinalConversion( finalConversion, sourceClass, matches.get( 0 ) ); + } + else if( matches.size() > 1 ) + { + // too many matches! =( + unmatchedSourceClasses.add( classMapping.getObfName() ); + } + } + + // remove (and warn about) unmatched classes + if( !unmatchedSourceClasses.isEmpty() ) + { + System.err.println( "WARNING: there were unmatched classes!" ); + for( String className : unmatchedSourceClasses ) + { + System.err.println( "\t" + className ); + mappings.removeClassByObfName( className ); + } + System.err.println( "Mappings for these classes have been removed." ); + } + + // show the class name changes + for( Map.Entry entry : finalConversion.entrySet() ) + { + if( !entry.getKey().equals( entry.getValue() ) ) + { + System.out.println( String.format( "Class change: %s -> %s", entry.getKey(), entry.getValue() ) ); + } + } + + // do the final conversion + mappings.renameObfClasses( finalConversion ); + FileWriter writer = new FileWriter( outMappingsFile ); + new MappingsWriter().write( writer, mappings ); + writer.close(); + System.out.println( "Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath() ); } public static ClassMatching computeMatching( JarFile sourceJar, JarFile destJar ) @@ -55,78 +153,81 @@ public class ClassMapper TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex ); ClassMatching matching = null; - for( boolean useReferences : Arrays.asList( false, true ) ) + for( boolean useRawNames : Arrays.asList( false, true ) ) { - int numMatches = 0; - do + for( boolean useReferences : Arrays.asList( false, true ) ) { - SidedClassNamer sourceNamer = null; - SidedClassNamer destNamer = null; - if( matching != null ) + int numMatches = 0; + do { - // build a class namer - ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); - sourceNamer = namer.getSourceNamer(); - destNamer = namer.getDestNamer(); + SidedClassNamer sourceNamer = null; + SidedClassNamer destNamer = null; + if( matching != null ) + { + // build a class namer + ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); + sourceNamer = namer.getSourceNamer(); + destNamer = namer.getDestNamer(); + + // note the number of matches + numMatches = matching.getUniqueMatches().size(); + } - // note the number of matches - numMatches = matching.getUniqueMatches().size(); - } - - // get the entries left to match - Set sourceClassEntries = sourceIndex.getObfClassEntries(); - Set destClassEntries = destIndex.getObfClassEntries(); - if( matching != null ) - { - sourceClassEntries.clear(); - destClassEntries.clear(); - for( Map.Entry,List> entry : matching.getAmbiguousMatches().entrySet() ) + // get the entries left to match + Set sourceClassEntries = sourceIndex.getObfClassEntries(); + Set destClassEntries = destIndex.getObfClassEntries(); + if( matching != null ) { - for( ClassIdentity c : entry.getKey() ) + sourceClassEntries.clear(); + destClassEntries.clear(); + for( Map.Entry,List> entry : matching.getAmbiguousMatches().entrySet() ) + { + for( ClassIdentity c : entry.getKey() ) + { + sourceClassEntries.add( c.getClassEntry() ); + matching.removeSource( c ); + } + for( ClassIdentity c : entry.getValue() ) + { + destClassEntries.add( c.getClassEntry() ); + matching.removeDest( c ); + } + } + for( ClassIdentity c : matching.getUnmatchedSourceClasses() ) { sourceClassEntries.add( c.getClassEntry() ); matching.removeSource( c ); } - for( ClassIdentity c : entry.getValue() ) + for( ClassIdentity c : matching.getUnmatchedDestClasses() ) { destClassEntries.add( c.getClassEntry() ); matching.removeDest( c ); } } - for( ClassIdentity c : matching.getUnmatchedSourceClasses() ) + else { - sourceClassEntries.add( c.getClassEntry() ); - matching.removeSource( c ); + matching = new ClassMatching(); } - for( ClassIdentity c : matching.getUnmatchedDestClasses() ) + + // compute a matching for the classes + for( ClassEntry classEntry : sourceClassEntries ) { - destClassEntries.add( c.getClassEntry() ); - matching.removeDest( c ); + CtClass c = sourceLoader.loadClass( classEntry.getName() ); + ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences, useRawNames ); + matching.addSource( sourceClass ); } + for( ClassEntry classEntry : destClassEntries ) + { + CtClass c = destLoader.loadClass( classEntry.getName() ); + ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences, useRawNames ); + matching.matchDestClass( destClass ); + } + + // TEMP + System.out.println( matching ); } - else - { - matching = new ClassMatching(); - } - - // compute a matching for the classes - for( ClassEntry classEntry : sourceClassEntries ) - { - CtClass c = sourceLoader.loadClass( classEntry.getName() ); - ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences ); - matching.addSource( sourceClass ); - } - for( ClassEntry classEntry : destClassEntries ) - { - CtClass c = destLoader.loadClass( classEntry.getName() ); - ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences ); - matching.matchDestClass( destClass ); - } - - // TEMP - System.out.println( matching ); + while( matching.getUniqueMatches().size() - numMatches > 0 ); } - while( matching.getUniqueMatches().size() - numMatches > 0 ); } /* DEBUG: show some ambiguous matches @@ -163,6 +264,24 @@ public class ClassMapper return matching; } + private static void addFinalConversion( Map finalConversion, ClassIdentity sourceClass, ClassIdentity destClass ) + { + // flatten inner classes since these are all obf classes in the none package + String sourceClassName = sourceClass.getClassEntry().getName(); + if( sourceClass.getClassEntry().isInnerClass() ) + { + sourceClassName = Constants.NonePackage + "/" + sourceClass.getClassEntry().getInnerClassName(); + } + + String destClassName = destClass.getClassEntry().getName(); + if( destClass.getClassEntry().isInnerClass() ) + { + destClassName = Constants.NonePackage + "/" + destClass.getClassEntry().getInnerClassName(); + } + + finalConversion.put( sourceClassName, destClassName ); + } + /* DEBUG private static String decompile( TranslatingTypeLoader loader, ClassEntry classEntry ) { diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java index fea84386..4e9fe398 100644 --- a/src/cuchaz/enigma/convert/ClassMatching.java +++ b/src/cuchaz/enigma/convert/ClassMatching.java @@ -10,12 +10,15 @@ ******************************************************************************/ package cuchaz.enigma.convert; +import java.util.AbstractMap; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import com.beust.jcommander.internal.Lists; +import com.beust.jcommander.internal.Maps; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; @@ -156,6 +159,36 @@ public class ClassMatching return new ArrayList( m_unmatchedDestClasses ); } + public Map>> getConversionMap( ) + { + Map>> conversion = Maps.newHashMap(); + for( Map.Entry entry : getUniqueMatches().entrySet() ) + { + conversion.put( + entry.getKey().getClassEntry().getName(), + new AbstractMap.SimpleEntry>( entry.getKey(), Arrays.asList( entry.getValue() ) ) + ); + } + for( Map.Entry,List> entry : getAmbiguousMatches().entrySet() ) + { + for( ClassIdentity sourceClass : entry.getKey() ) + { + conversion.put( + sourceClass.getClassEntry().getName(), + new AbstractMap.SimpleEntry>( sourceClass, entry.getValue() ) + ); + } + } + for( ClassIdentity sourceClass : getUnmatchedSourceClasses() ) + { + conversion.put( + sourceClass.getClassEntry().getName(), + new AbstractMap.SimpleEntry>( sourceClass, new ArrayList() ) + ); + } + return conversion; + } + @Override public String toString( ) { diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index 59365129..095cb385 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -11,6 +11,7 @@ package cuchaz.enigma.mapping; import java.io.Serializable; +import java.util.ArrayList; import java.util.Map; import com.google.common.collect.Maps; @@ -299,4 +300,32 @@ public class ClassMapping implements Serializable, Comparable { return m_obfName.compareTo( other.m_obfName ); } + + public void renameObfClasses( Map nameMap ) + { + // rename self + { + String newName = nameMap.get( m_obfName ); + if( newName != null ) + { + m_obfName = newName; + } + } + + // rename inner classes + for( ClassMapping classMapping : new ArrayList( m_innerClassesByObf.values() ) ) + { + m_innerClassesByObf.remove( classMapping.getObfName() ); + classMapping.renameObfClasses( nameMap ); + m_innerClassesByObf.put( classMapping.getObfName(), classMapping ); + } + + // rename method signatures + for( MethodMapping methodMapping : new ArrayList( m_methodsByObf.values() ) ) + { + m_methodsByObf.remove( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ) ); + methodMapping.renameObfClasses( nameMap ); + m_methodsByObf.put( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ), methodMapping ); + } + } } diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index f3b8fad1..70bea25f 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.Serializable; +import java.util.ArrayList; import java.util.Map; import java.util.zip.GZIPInputStream; @@ -136,4 +137,28 @@ public class Mappings implements Serializable } return buf.toString(); } + + public void renameObfClasses( Map nameMap ) + { + for( ClassMapping classMapping : new ArrayList( m_classesByObf.values() ) ) + { + String newName = nameMap.get( classMapping.getObfName() ); + if( newName != null ) + { + m_classesByObf.remove( classMapping.getObfName() ); + classMapping.renameObfClasses( nameMap ); + m_classesByObf.put( classMapping.getObfName(), classMapping ); + } + } + } + + public void removeClassByObfName( String obfName ) + { + ClassMapping classMapping = m_classesByObf.get( obfName ); + if( classMapping != null ) + { + m_classesByObf.remove( classMapping.getObfName() ); + m_classesByDeobf.remove( classMapping.getDeobfName() ); + } + } } diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java index 6e6bec46..fe4e29b2 100644 --- a/src/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/cuchaz/enigma/mapping/MethodMapping.java @@ -14,6 +14,8 @@ import java.io.Serializable; import java.util.Map; import java.util.TreeMap; +import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; + public class MethodMapping implements Serializable, Comparable { private static final long serialVersionUID = -4409570216084263978L; @@ -139,4 +141,22 @@ public class MethodMapping implements Serializable, Comparable { return ( m_obfName + m_obfSignature ).compareTo( ( other.m_obfName + other.m_obfSignature ) ); } + + public void renameObfClasses( final Map nameMap ) + { + // rename obf classes in the signature + m_obfSignature = SignatureUpdater.update( m_obfSignature, new ClassNameUpdater( ) + { + @Override + public String update( String className ) + { + String newName = nameMap.get( className ); + if( newName != null ) + { + return newName; + } + return className; + } + } ); + } } -- cgit v1.2.3 From 59c592673635e989fd0785d41d51d7c3dd17cc0b Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 30 Aug 2014 16:31:31 -0400 Subject: debugging class matcher... almost got it! --- src/cuchaz/enigma/Deobfuscator.java | 2 +- src/cuchaz/enigma/analysis/JarIndex.java | 57 ++-- src/cuchaz/enigma/convert/ClassIdentity.java | 40 +-- src/cuchaz/enigma/convert/ClassMapper.java | 297 -------------------- src/cuchaz/enigma/convert/ClassMatcher.java | 398 +++++++++++++++++++++++++++ src/cuchaz/enigma/convert/ClassMatching.java | 2 +- src/cuchaz/enigma/mapping/Mappings.java | 7 + 7 files changed, 461 insertions(+), 342 deletions(-) delete mode 100644 src/cuchaz/enigma/convert/ClassMapper.java create mode 100644 src/cuchaz/enigma/convert/ClassMatcher.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index cc1465a2..9a78f38d 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -70,7 +70,7 @@ public class Deobfuscator // build the jar index m_jarIndex = new JarIndex(); - m_jarIndex.indexJar( m_jar ); + m_jarIndex.indexJar( m_jar, true ); // config the decompiler m_settings = DecompilerSettings.javaDefaults(); diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index b479b69e..4279dedd 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -79,7 +79,7 @@ public class JarIndex m_bridgeMethods = Maps.newHashMap(); } - public void indexJar( JarFile jar ) + public void indexJar( JarFile jar, boolean buildInnerClasses ) { // step 1: read the class names for( ClassEntry classEntry : JarClassIterator.getClassEntries( jar ) ) @@ -125,40 +125,43 @@ public class JarIndex } } - // step 4: index inner classes and anonymous classes - for( CtClass c : JarClassIterator.classes( jar ) ) + if( buildInnerClasses ) { - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); - String outerClassName = findOuterClass( c ); - if( outerClassName != null ) + // step 4: index inner classes and anonymous classes + for( CtClass c : JarClassIterator.classes( jar ) ) { - String innerClassName = Descriptor.toJvmName( c.getName() ); - m_innerClasses.put( outerClassName, innerClassName ); - m_outerClasses.put( innerClassName, outerClassName ); - - if( isAnonymousClass( c, outerClassName ) ) + ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); + String outerClassName = findOuterClass( c ); + if( outerClassName != null ) { - m_anonymousClasses.add( innerClassName ); + String innerClassName = Descriptor.toJvmName( c.getName() ); + m_innerClasses.put( outerClassName, innerClassName ); + m_outerClasses.put( innerClassName, outerClassName ); - // DEBUG - //System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); - } - else - { - // DEBUG - //System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); + if( isAnonymousClass( c, outerClassName ) ) + { + m_anonymousClasses.add( innerClassName ); + + // DEBUG + //System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); + } + else + { + // DEBUG + //System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); + } } } + + // step 5: update other indices with inner class info + Map renames = Maps.newHashMap(); + for( Map.Entry entry : m_outerClasses.entrySet() ) + { + renames.put( entry.getKey(), entry.getValue() + "$" + new ClassEntry( entry.getKey() ).getSimpleName() ); + } + renameClasses( renames ); } - // step 5: update other indices with inner class info - Map renames = Maps.newHashMap(); - for( Map.Entry entry : m_outerClasses.entrySet() ) - { - renames.put( entry.getKey(), entry.getValue() + "$" + new ClassEntry( entry.getKey() ).getSimpleName() ); - } - renameClasses( renames ); - // step 5: update other indices with bridge method info renameMethods( m_bridgeMethods ); } diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java index 980f31f5..8de71288 100644 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ b/src/cuchaz/enigma/convert/ClassIdentity.java @@ -16,7 +16,6 @@ import java.security.NoSuchAlgorithmException; import java.util.Enumeration; import java.util.List; import java.util.Map; -import java.util.Set; import javassist.CannotCompileException; import javassist.CtBehavior; @@ -36,8 +35,9 @@ import javassist.expr.MethodCall; import javassist.expr.NewExpr; import com.beust.jcommander.internal.Maps; -import com.beust.jcommander.internal.Sets; +import com.google.common.collect.HashMultiset; import com.google.common.collect.Lists; +import com.google.common.collect.Multiset; import cuchaz.enigma.Constants; import cuchaz.enigma.Util; @@ -62,14 +62,14 @@ public class ClassIdentity private ClassEntry m_classEntry; private String m_rawName; private SidedClassNamer m_namer; - private Set m_fields; - private Set m_methods; - private Set m_constructors; + private Multiset m_fields; + private Multiset m_methods; + private Multiset m_constructors; private String m_staticInitializer; private String m_extends; - private Set m_implements; - private Set m_implementations; - private Set m_references; + private Multiset m_implements; + private Multiset m_implementations; + private Multiset m_references; public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences, boolean useRawNames ) { @@ -83,17 +83,17 @@ public class ClassIdentity { m_rawName = m_classEntry.getName(); } - m_fields = Sets.newHashSet(); + m_fields = HashMultiset.create(); for( CtField field : c.getDeclaredFields() ) { m_fields.add( scrubSignature( field.getSignature() ) ); } - m_methods = Sets.newHashSet(); + m_methods = HashMultiset.create(); for( CtMethod method : c.getDeclaredMethods() ) { m_methods.add( scrubSignature( method.getSignature() ) + "0x" + getBehaviorSignature( method ) ); } - m_constructors = Sets.newHashSet(); + m_constructors = HashMultiset.create(); for( CtConstructor constructor : c.getDeclaredConstructors() ) { m_constructors.add( scrubSignature( constructor.getSignature() ) + "0x" + getBehaviorSignature( constructor ) ); @@ -108,7 +108,7 @@ public class ClassIdentity { m_extends = scrubClassName( c.getClassFile().getSuperclass() ); } - m_implements = Sets.newHashSet(); + m_implements = HashMultiset.create(); for( String interfaceName : c.getClassFile().getInterfaces() ) { m_implements.add( scrubClassName( interfaceName ) ); @@ -116,7 +116,7 @@ public class ClassIdentity // stuff from the jar index - m_implementations = Sets.newHashSet(); + m_implementations = HashMultiset.create(); @SuppressWarnings( "unchecked" ) Enumeration implementations = index.getClassImplementations( null, m_classEntry ).children(); while( implementations.hasMoreElements() ) @@ -125,7 +125,7 @@ public class ClassIdentity m_implementations.add( scrubClassName( node.getClassEntry().getName() ) ); } - m_references = Sets.newHashSet(); + m_references = HashMultiset.create(); if( useReferences ) { for( CtField field : c.getDeclaredFields() ) @@ -154,7 +154,7 @@ public class ClassIdentity } } } - + private void addReference( EntryReference reference ) { if( reference.context.getSignature() != null ) @@ -473,7 +473,15 @@ public class ClassIdentity + getNumMatches( m_constructors, other.m_constructors ); } - private int getNumMatches( Set a, Set b ) + public boolean matches( CtClass c ) + { + // just compare declaration counts + return m_fields.size() == c.getDeclaredFields().length + && m_methods.size() == c.getDeclaredMethods().length + && m_constructors.size() == c.getDeclaredConstructors().length; + } + + private int getNumMatches( Multiset a, Multiset b ) { int numMatches = 0; for( String val : a ) diff --git a/src/cuchaz/enigma/convert/ClassMapper.java b/src/cuchaz/enigma/convert/ClassMapper.java deleted file mode 100644 index fd6ab922..00000000 --- a/src/cuchaz/enigma/convert/ClassMapper.java +++ /dev/null @@ -1,297 +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.convert; - -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.jar.JarFile; - -import javassist.CtClass; - -import com.beust.jcommander.internal.Sets; -import com.google.common.collect.Maps; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.TranslatingTypeLoader; -import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ClassMapping; -import cuchaz.enigma.mapping.MappingParseException; -import cuchaz.enigma.mapping.Mappings; -import cuchaz.enigma.mapping.MappingsReader; -import cuchaz.enigma.mapping.MappingsWriter; - -public class ClassMapper -{ - public static void main( String[] args ) - throws IOException, MappingParseException - { - // TEMP - JarFile fromJar = new JarFile( new File( "input/1.8-pre1.jar" ) ); - JarFile toJar = new JarFile( new File( "input/1.8-pre3.jar" ) ); - File inMappingsFile = new File( "../minecraft-mappings/1.8-pre.mappings" ); - File outMappingsFile = new File( "../minecraft-mappings/1.8-pre3.mappings" ); - - // compute the matching - ClassMatching matching = ClassMapper.computeMatching( fromJar, toJar ); - - // use the matching to convert the mappings - Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) ); - Map>> conversionMap = matching.getConversionMap(); - Map finalConversion = Maps.newHashMap(); - Set unmatchedSourceClasses = Sets.newHashSet(); - for( ClassMapping classMapping : mappings.classes() ) - { - // is there a match for this class? - Map.Entry> entry = conversionMap.get( classMapping.getObfName() ); - ClassIdentity sourceClass = entry.getKey(); - List matches = entry.getValue(); - - if( matches.isEmpty() ) - { - // no match! =( - System.out.println( "No exact match for source class " + classMapping.getObfName() ); - - // find the closest classes - TreeMap scoredMatches = Maps.newTreeMap( Collections.reverseOrder() ); - for( ClassIdentity c : matching.getUnmatchedDestClasses() ) - { - scoredMatches.put( sourceClass.getMatchScore( c ), c ); - } - Iterator> iter = scoredMatches.entrySet().iterator(); - for( int i=0; i<10 && iter.hasNext(); i++ ) - { - Map.Entry score = iter.next(); - System.out.println( String.format( "\tScore: %3d %s", score.getKey(), score.getValue().getClassEntry().getName() ) ); - } - - // does the best match have a non-zero score and the same name? - Map.Entry bestMatch = scoredMatches.firstEntry(); - if( bestMatch.getKey() > 0 && bestMatch.getValue().getClassEntry().equals( sourceClass.getClassEntry() ) ) - { - // use it - System.out.println( "\tAutomatically choosing likely match: " + bestMatch.getValue().getClassEntry().getName() ); - addFinalConversion( finalConversion, sourceClass, bestMatch.getValue() ); - } - else - { - unmatchedSourceClasses.add( classMapping.getObfName() ); - } - } - if( matches.size() == 1 ) - { - // unique match! We're good to go! - addFinalConversion( finalConversion, sourceClass, matches.get( 0 ) ); - } - else if( matches.size() > 1 ) - { - // too many matches! =( - unmatchedSourceClasses.add( classMapping.getObfName() ); - } - } - - // remove (and warn about) unmatched classes - if( !unmatchedSourceClasses.isEmpty() ) - { - System.err.println( "WARNING: there were unmatched classes!" ); - for( String className : unmatchedSourceClasses ) - { - System.err.println( "\t" + className ); - mappings.removeClassByObfName( className ); - } - System.err.println( "Mappings for these classes have been removed." ); - } - - // show the class name changes - for( Map.Entry entry : finalConversion.entrySet() ) - { - if( !entry.getKey().equals( entry.getValue() ) ) - { - System.out.println( String.format( "Class change: %s -> %s", entry.getKey(), entry.getValue() ) ); - } - } - - // do the final conversion - mappings.renameObfClasses( finalConversion ); - FileWriter writer = new FileWriter( outMappingsFile ); - new MappingsWriter().write( writer, mappings ); - writer.close(); - System.out.println( "Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath() ); - } - - public static ClassMatching computeMatching( JarFile sourceJar, JarFile destJar ) - { - // index jars - System.out.println( "Indexing source jar..." ); - JarIndex sourceIndex = new JarIndex(); - sourceIndex.indexJar( sourceJar ); - System.out.println( "Indexing dest jar..." ); - JarIndex destIndex = new JarIndex(); - destIndex.indexJar( destJar ); - - System.out.println( "Computing matching..." ); - - TranslatingTypeLoader sourceLoader = new TranslatingTypeLoader( sourceJar, sourceIndex ); - TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex ); - - ClassMatching matching = null; - for( boolean useRawNames : Arrays.asList( false, true ) ) - { - for( boolean useReferences : Arrays.asList( false, true ) ) - { - int numMatches = 0; - do - { - SidedClassNamer sourceNamer = null; - SidedClassNamer destNamer = null; - if( matching != null ) - { - // build a class namer - ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); - sourceNamer = namer.getSourceNamer(); - destNamer = namer.getDestNamer(); - - // note the number of matches - numMatches = matching.getUniqueMatches().size(); - } - - // get the entries left to match - Set sourceClassEntries = sourceIndex.getObfClassEntries(); - Set destClassEntries = destIndex.getObfClassEntries(); - if( matching != null ) - { - sourceClassEntries.clear(); - destClassEntries.clear(); - for( Map.Entry,List> entry : matching.getAmbiguousMatches().entrySet() ) - { - for( ClassIdentity c : entry.getKey() ) - { - sourceClassEntries.add( c.getClassEntry() ); - matching.removeSource( c ); - } - for( ClassIdentity c : entry.getValue() ) - { - destClassEntries.add( c.getClassEntry() ); - matching.removeDest( c ); - } - } - for( ClassIdentity c : matching.getUnmatchedSourceClasses() ) - { - sourceClassEntries.add( c.getClassEntry() ); - matching.removeSource( c ); - } - for( ClassIdentity c : matching.getUnmatchedDestClasses() ) - { - destClassEntries.add( c.getClassEntry() ); - matching.removeDest( c ); - } - } - else - { - matching = new ClassMatching(); - } - - // compute a matching for the classes - for( ClassEntry classEntry : sourceClassEntries ) - { - CtClass c = sourceLoader.loadClass( classEntry.getName() ); - ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences, useRawNames ); - matching.addSource( sourceClass ); - } - for( ClassEntry classEntry : destClassEntries ) - { - CtClass c = destLoader.loadClass( classEntry.getName() ); - ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences, useRawNames ); - matching.matchDestClass( destClass ); - } - - // TEMP - System.out.println( matching ); - } - while( matching.getUniqueMatches().size() - numMatches > 0 ); - } - } - - /* DEBUG: show some ambiguous matches - List,List>> ambiguousMatches = new ArrayList,List>>( matching.getAmbiguousMatches().entrySet() ); - Collections.sort( ambiguousMatches, new Comparator,List>>( ) - { - @Override - public int compare( Map.Entry,List> a, Map.Entry,List> b ) - { - String aName = a.getKey().get( 0 ).getClassEntry().getName(); - String bName = b.getKey().get( 0 ).getClassEntry().getName(); - return aName.compareTo( bName ); - } - } ); - for( Map.Entry,List> entry : ambiguousMatches ) - { - for( ClassIdentity c : entry.getKey() ) - { - System.out.print( c.getClassEntry().getName() + " " ); - } - System.out.println(); - } - Map.Entry,List> entry = ambiguousMatches.get( 7 ); - for( ClassIdentity c : entry.getKey() ) - { - System.out.println( c ); - } - for( ClassIdentity c : entry.getKey() ) - { - System.out.println( decompile( sourceLoader, c.getClassEntry() ) ); - } - */ - - return matching; - } - - private static void addFinalConversion( Map finalConversion, ClassIdentity sourceClass, ClassIdentity destClass ) - { - // flatten inner classes since these are all obf classes in the none package - String sourceClassName = sourceClass.getClassEntry().getName(); - if( sourceClass.getClassEntry().isInnerClass() ) - { - sourceClassName = Constants.NonePackage + "/" + sourceClass.getClassEntry().getInnerClassName(); - } - - String destClassName = destClass.getClassEntry().getName(); - if( destClass.getClassEntry().isInnerClass() ) - { - destClassName = Constants.NonePackage + "/" + destClass.getClassEntry().getInnerClassName(); - } - - finalConversion.put( sourceClassName, destClassName ); - } - - /* DEBUG - private static String decompile( TranslatingTypeLoader loader, ClassEntry classEntry ) - { - PlainTextOutput output = new PlainTextOutput(); - DecompilerSettings settings = DecompilerSettings.javaDefaults(); - settings.setForceExplicitImports( true ); - settings.setShowSyntheticMembers( true ); - settings.setTypeLoader( loader ); - Decompiler.decompile( classEntry.getName(), output, settings ); - return output.toString(); - } - */ -} diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java new file mode 100644 index 00000000..ac07a5bd --- /dev/null +++ b/src/cuchaz/enigma/convert/ClassMatcher.java @@ -0,0 +1,398 @@ +/******************************************************************************* + * 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.convert; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.jar.JarFile; + +import javassist.CtBehavior; +import javassist.CtClass; + +import com.beust.jcommander.internal.Lists; +import com.beust.jcommander.internal.Sets; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.Maps; + +import cuchaz.enigma.TranslatingTypeLoader; +import cuchaz.enigma.analysis.JarIndex; +import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ClassMapping; +import cuchaz.enigma.mapping.MappingParseException; +import cuchaz.enigma.mapping.Mappings; +import cuchaz.enigma.mapping.MappingsReader; +import cuchaz.enigma.mapping.MappingsWriter; +import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.MethodMapping; + +public class ClassMatcher +{ + public static void main( String[] args ) + throws IOException, MappingParseException + { + // TEMP + JarFile sourceJar = new JarFile( new File( "input/1.8-pre1.jar" ) ); + JarFile destJar = new JarFile( new File( "input/1.8-pre2.jar" ) ); + File inMappingsFile = new File( "../minecraft-mappings/1.8-pre.mappings" ); + File outMappingsFile = new File( "../minecraft-mappings/1.8-pre2.mappings" ); + + // do the conversion + Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) ); + convertMappings( sourceJar, destJar, mappings ); + + // write out the convert mappings + FileWriter writer = new FileWriter( outMappingsFile ); + new MappingsWriter().write( writer, mappings ); + writer.close(); + System.out.println( "Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath() ); + } + + private static void convertMappings( JarFile sourceJar, JarFile destJar, Mappings mappings ) + { + // index jars + System.out.println( "Indexing source jar..." ); + JarIndex sourceIndex = new JarIndex(); + sourceIndex.indexJar( sourceJar, false ); + System.out.println( "Indexing dest jar..." ); + JarIndex destIndex = new JarIndex(); + destIndex.indexJar( destJar, false ); + TranslatingTypeLoader sourceLoader = new TranslatingTypeLoader( sourceJar, sourceIndex ); + TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex ); + + // compute the matching + ClassMatching matching = ClassMatcher.computeMatching( sourceIndex, sourceLoader, destIndex, destLoader ); + + // start the class conversion map with the unique and ambiguous matchings + Map>> conversionMap = matching.getConversionMap(); + + // probabilistically match the unmatched source classes + for( ClassIdentity sourceClass : new ArrayList( matching.getUnmatchedSourceClasses() ) ) + { + System.out.println( "No exact match for source class " + sourceClass.getClassEntry() ); + + // find the closest classes + TreeMap scoredMatches = Maps.newTreeMap( Collections.reverseOrder() ); + for( ClassIdentity c : matching.getUnmatchedDestClasses() ) + { + scoredMatches.put( sourceClass.getMatchScore( c ), c ); + } + Iterator> iter = scoredMatches.entrySet().iterator(); + for( int i=0; i<10 && iter.hasNext(); i++ ) + { + Map.Entry score = iter.next(); + System.out.println( String.format( "\tScore: %3d %s", score.getKey(), score.getValue().getClassEntry().getName() ) ); + } + + // does the best match have a non-zero score and the same name? + Map.Entry bestMatch = scoredMatches.firstEntry(); + if( bestMatch.getKey() > 0 && bestMatch.getValue().getClassEntry().equals( sourceClass.getClassEntry() ) ) + { + // use it + System.out.println( "\tAutomatically choosing likely match: " + bestMatch.getValue().getClassEntry().getName() ); + conversionMap.put( + sourceClass.getClassEntry().getName(), + new AbstractMap.SimpleEntry>( sourceClass, Arrays.asList( bestMatch.getValue() ) ) + ); + } + } + + // use the matching to convert the mappings + BiMap classConversion = HashBiMap.create(); + Set unmatchedSourceClasses = Sets.newHashSet(); + for( String className : mappings.getAllObfClassNames() ) + { + // is there a match for this class? + Map.Entry> entry = conversionMap.get( className ); + ClassIdentity sourceClass = entry.getKey(); + List matches = entry.getValue(); + + if( matches.isEmpty() ) + { + // no match! =( + unmatchedSourceClasses.add( className ); + } + else if( matches.size() == 1 ) + { + // unique match! We're good to go! + classConversion.put( + sourceClass.getClassEntry().getName(), + matches.get( 0 ).getClassEntry().getName() + ); + } + else if( matches.size() > 1 ) + { + // too many matches! =( + unmatchedSourceClasses.add( className ); + } + } + + // remove (and warn about) unmatched classes + if( !unmatchedSourceClasses.isEmpty() ) + { + System.err.println( "WARNING: there were unmatched classes!" ); + for( String className : unmatchedSourceClasses ) + { + System.err.println( "\t" + className ); + mappings.removeClassByObfName( className ); + } + System.err.println( "Mappings for these classes have been removed." ); + } + + // show the class name changes + for( Map.Entry entry : classConversion.entrySet() ) + { + if( !entry.getKey().equals( entry.getValue() ) ) + { + System.out.println( String.format( "Class change: %s -> %s", entry.getKey(), entry.getValue() ) ); + /* DEBUG + System.out.println( String.format( "\n%s\n%s", + new ClassIdentity( sourceLoader.loadClass( entry.getKey() ), null, sourceIndex, false, false ), + new ClassIdentity( destLoader.loadClass( entry.getValue() ), null, destIndex, false, false ) + ) ); + */ + } + } + + // TEMP: show some classes + for( String className : Arrays.asList( "none/em", "none/ej", "none/en" ) ) + { + System.out.println( String.format( "check: %s -> %s", className, classConversion.get( className ) ) ); + } + + // convert the classes + mappings.renameObfClasses( classConversion ); + + // look for method matches + System.out.println( "Matching methods..." ); + for( ClassMapping classMapping : mappings.classes() ) + { + ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); + for( MethodMapping methodMapping : classMapping.methods() ) + { + // skip constructors + if( methodMapping.getObfName().equals( "" ) ) + { + continue; + } + + MethodEntry methodEntry = new MethodEntry( + classEntry, + methodMapping.getObfName(), + methodMapping.getObfSignature() + ); + if( !destIndex.isMethodImplemented( methodEntry ) ) + { + System.err.println( "WARNING: method doesn't match: " + methodEntry ); + + // show the available methods + System.err.println( "\tAvailable dest methods:" ); + CtClass c = destLoader.loadClass( classMapping.getObfName() ); + for( CtBehavior behavior : c.getDeclaredBehaviors() ) + { + MethodEntry declaredMethodEntry = new MethodEntry( + new ClassEntry( classMapping.getObfName() ), + behavior.getName(), + behavior.getSignature() + ); + System.err.println( "\t\t" + declaredMethodEntry ); + } + + System.err.println( "\tAvailable source methods:" ); + c = sourceLoader.loadClass( classConversion.inverse().get( classMapping.getObfName() ) ); + for( CtBehavior behavior : c.getDeclaredBehaviors() ) + { + MethodEntry declaredMethodEntry = new MethodEntry( + new ClassEntry( classMapping.getObfName() ), + behavior.getName(), + behavior.getSignature() + ); + System.err.println( "\t\t" + declaredMethodEntry ); + } + } + } + } + } + + public static ClassMatching computeMatching( JarIndex sourceIndex, TranslatingTypeLoader sourceLoader, JarIndex destIndex, TranslatingTypeLoader destLoader ) + { + System.out.println( "Matching classes..." ); + ClassMatching matching = null; + for( boolean useRawNames : Arrays.asList( false/*, true*/ ) ) + { + for( boolean useReferences : Arrays.asList( false, true ) ) + { + int numMatches = 0; + do + { + SidedClassNamer sourceNamer = null; + SidedClassNamer destNamer = null; + if( matching != null ) + { + // build a class namer + ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); + sourceNamer = namer.getSourceNamer(); + destNamer = namer.getDestNamer(); + + // note the number of matches + numMatches = matching.getUniqueMatches().size(); + } + + // get the entries left to match + Set sourceClassEntries = sourceIndex.getObfClassEntries(); + Set destClassEntries = destIndex.getObfClassEntries(); + if( matching != null ) + { + sourceClassEntries.clear(); + destClassEntries.clear(); + for( Map.Entry,List> entry : matching.getAmbiguousMatches().entrySet() ) + { + for( ClassIdentity c : entry.getKey() ) + { + sourceClassEntries.add( c.getClassEntry() ); + matching.removeSource( c ); + } + for( ClassIdentity c : entry.getValue() ) + { + destClassEntries.add( c.getClassEntry() ); + matching.removeDest( c ); + } + } + for( ClassIdentity c : matching.getUnmatchedSourceClasses() ) + { + sourceClassEntries.add( c.getClassEntry() ); + matching.removeSource( c ); + } + for( ClassIdentity c : matching.getUnmatchedDestClasses() ) + { + destClassEntries.add( c.getClassEntry() ); + matching.removeDest( c ); + } + } + else + { + matching = new ClassMatching(); + } + + // compute a matching for the classes + for( ClassEntry classEntry : sourceClassEntries ) + { + CtClass c = sourceLoader.loadClass( classEntry.getName() ); + ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences, useRawNames ); + matching.addSource( sourceClass ); + } + for( ClassEntry classEntry : destClassEntries ) + { + CtClass c = destLoader.loadClass( classEntry.getName() ); + ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences, useRawNames ); + matching.matchDestClass( destClass ); + } + + // TEMP + System.out.println( matching ); + } + while( matching.getUniqueMatches().size() - numMatches > 0 ); + } + } + + // DEBUG: check the class matches + System.out.println( "Checking class matches..." ); + for( Map.Entry entry : matching.getUniqueMatches().entrySet() ) + { + // check source + ClassIdentity sourceClass = entry.getKey(); + CtClass sourceC = sourceLoader.loadClass( sourceClass.getClassEntry().getName() ); + assert( sourceC != null ) + : "Unable to load source class " + sourceClass.getClassEntry(); + assert( sourceClass.matches( sourceC ) ) + : "Source " + sourceClass + " doesn't match " + new ClassIdentity( sourceC, null, sourceIndex, false, false ); + + // check dest + ClassIdentity destClass = entry.getValue(); + CtClass destC = destLoader.loadClass( destClass.getClassEntry().getName() ); + assert( destC != null ) + : "Unable to load dest class " + destClass.getClassEntry(); + assert( destClass.matches( destC ) ) + : "Dest " + destClass + " doesn't match " + new ClassIdentity( destC, null, destIndex, false, false ); + } + + // warn about the ambiguous matchings + List,List>> ambiguousMatches = new ArrayList,List>>( matching.getAmbiguousMatches().entrySet() ); + Collections.sort( ambiguousMatches, new Comparator,List>>( ) + { + @Override + public int compare( Map.Entry,List> a, Map.Entry,List> b ) + { + String aName = a.getKey().get( 0 ).getClassEntry().getName(); + String bName = b.getKey().get( 0 ).getClassEntry().getName(); + return aName.compareTo( bName ); + } + } ); + for( Map.Entry,List> entry : ambiguousMatches ) + { + System.out.println( "Ambiguous matching:" ); + System.out.println( "\tSource: " + getClassNames( entry.getKey() ) ); + System.out.println( "\tDest: " + getClassNames( entry.getValue() ) ); + } + + /* DEBUG + Map.Entry,List> entry = ambiguousMatches.get( 7 ); + for( ClassIdentity c : entry.getKey() ) + { + System.out.println( c ); + } + for( ClassIdentity c : entry.getKey() ) + { + System.out.println( decompile( sourceLoader, c.getClassEntry() ) ); + } + */ + + return matching; + } + + private static List getClassNames( Collection classes ) + { + List out = Lists.newArrayList(); + for( ClassIdentity c : classes ) + { + out.add( c.getClassEntry().getName() ); + } + Collections.sort( out ); + return out; + } + + /* DEBUG + private static String decompile( TranslatingTypeLoader loader, ClassEntry classEntry ) + { + PlainTextOutput output = new PlainTextOutput(); + DecompilerSettings settings = DecompilerSettings.javaDefaults(); + settings.setForceExplicitImports( true ); + settings.setShowSyntheticMembers( true ); + settings.setTypeLoader( loader ); + Decompiler.decompile( classEntry.getName(), output, settings ); + return output.toString(); + } + */ +} diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java index 4e9fe398..ef5a7d8a 100644 --- a/src/cuchaz/enigma/convert/ClassMatching.java +++ b/src/cuchaz/enigma/convert/ClassMatching.java @@ -96,7 +96,7 @@ public class ClassMatching if( matchedSourceClasses.size() == 1 && matchedDestClasses.size() == 1 ) { ClassIdentity matchedSourceClass = matchedSourceClasses.iterator().next(); - ClassIdentity matchedDestClass = matchedSourceClasses.iterator().next(); + ClassIdentity matchedDestClass = matchedDestClasses.iterator().next(); uniqueMatches.put( matchedSourceClass, matchedDestClass ); } } diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 70bea25f..c92f8de0 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -15,6 +15,7 @@ import java.io.InputStream; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.zip.GZIPInputStream; @@ -161,4 +162,10 @@ public class Mappings implements Serializable m_classesByDeobf.remove( classMapping.getDeobfName() ); } } + + public List getAllObfClassNames( ) + { + // TODO: implement this + return null; + } } -- cgit v1.2.3 From d3fc0b55515e81ae1b10fa16129f05b0241271f0 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 31 Aug 2014 14:41:24 -0400 Subject: fixed lots of bugs in the mappings converter. It's finally ready. =) --- src/cuchaz/enigma/convert/ClassIdentity.java | 23 +-- src/cuchaz/enigma/convert/ClassMatcher.java | 260 ++++++++++++++++----------- src/cuchaz/enigma/convert/ClassMatching.java | 26 +-- src/cuchaz/enigma/mapping/Mappings.java | 29 ++- 4 files changed, 194 insertions(+), 144 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java index 8de71288..bd2824b3 100644 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ b/src/cuchaz/enigma/convert/ClassIdentity.java @@ -60,7 +60,6 @@ import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class ClassIdentity { private ClassEntry m_classEntry; - private String m_rawName; private SidedClassNamer m_namer; private Multiset m_fields; private Multiset m_methods; @@ -71,18 +70,13 @@ public class ClassIdentity private Multiset m_implementations; private Multiset m_references; - public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences, boolean useRawNames ) + public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences ) { m_namer = namer; // stuff from the bytecode m_classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); - m_rawName = ""; - if( useRawNames ) - { - m_rawName = m_classEntry.getName(); - } m_fields = HashMultiset.create(); for( CtField field : c.getDeclaredFields() ) { @@ -186,12 +180,6 @@ public class ClassIdentity buf.append( " " ); buf.append( hashCode() ); buf.append( "\n" ); - if( m_rawName.length() > 0 ) - { - buf.append( "\traw name: " ); - buf.append( m_rawName ); - buf.append( "\n" ); - } for( String field : m_fields ) { buf.append( "\tfield " ); @@ -439,8 +427,7 @@ public class ClassIdentity public boolean equals( ClassIdentity other ) { - return m_rawName.equals( other.m_rawName ) - && m_fields.equals( other.m_fields ) + return m_fields.equals( other.m_fields ) && m_methods.equals( other.m_methods ) && m_constructors.equals( other.m_constructors ) && m_staticInitializer.equals( other.m_staticInitializer ) @@ -454,7 +441,6 @@ public class ClassIdentity public int hashCode( ) { List objs = Lists.newArrayList(); - objs.add( m_rawName ); objs.addAll( m_fields ); objs.addAll( m_methods ); objs.addAll( m_constructors ); @@ -473,6 +459,11 @@ public class ClassIdentity + getNumMatches( m_constructors, other.m_constructors ); } + public int getMaxMatchScore( ) + { + return m_fields.size() + m_methods.size() + m_constructors.size(); + } + public boolean matches( CtClass c ) { // just compare declaration counts diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java index ac07a5bd..b551da25 100644 --- a/src/cuchaz/enigma/convert/ClassMatcher.java +++ b/src/cuchaz/enigma/convert/ClassMatcher.java @@ -14,17 +14,14 @@ import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; -import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TreeMap; import java.util.jar.JarFile; import javassist.CtBehavior; @@ -32,9 +29,11 @@ import javassist.CtClass; import com.beust.jcommander.internal.Lists; import com.beust.jcommander.internal.Sets; +import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import cuchaz.enigma.TranslatingTypeLoader; import cuchaz.enigma.analysis.JarIndex; @@ -55,22 +54,28 @@ public class ClassMatcher { // TEMP JarFile sourceJar = new JarFile( new File( "input/1.8-pre1.jar" ) ); - JarFile destJar = new JarFile( new File( "input/1.8-pre2.jar" ) ); + JarFile destJar = new JarFile( new File( "input/1.8-pre3.jar" ) ); File inMappingsFile = new File( "../minecraft-mappings/1.8-pre.mappings" ); - File outMappingsFile = new File( "../minecraft-mappings/1.8-pre2.mappings" ); + File outMappingsFile = new File( "../minecraft-mappings/1.8-pre3.mappings" ); + + // define a matching to use when the automated system cannot find a match + Map fallbackMatching = Maps.newHashMap(); + fallbackMatching.put( "none/ayb", "none/ayb" ); + fallbackMatching.put( "none/ayd", "none/ayd" ); + fallbackMatching.put( "none/bgk", "none/bgk" ); // do the conversion Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) ); - convertMappings( sourceJar, destJar, mappings ); + convertMappings( sourceJar, destJar, mappings, fallbackMatching ); - // write out the convert mappings + // write out the converted mappings FileWriter writer = new FileWriter( outMappingsFile ); new MappingsWriter().write( writer, mappings ); writer.close(); System.out.println( "Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath() ); } - private static void convertMappings( JarFile sourceJar, JarFile destJar, Mappings mappings ) + private static void convertMappings( JarFile sourceJar, JarFile destJar, Mappings mappings, Map fallbackMatching ) { // index jars System.out.println( "Indexing source jar..." ); @@ -83,58 +88,77 @@ public class ClassMatcher TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex ); // compute the matching - ClassMatching matching = ClassMatcher.computeMatching( sourceIndex, sourceLoader, destIndex, destLoader ); + ClassMatching matching = computeMatching( sourceIndex, sourceLoader, destIndex, destLoader ); // start the class conversion map with the unique and ambiguous matchings Map>> conversionMap = matching.getConversionMap(); - // probabilistically match the unmatched source classes - for( ClassIdentity sourceClass : new ArrayList( matching.getUnmatchedSourceClasses() ) ) + // get all the obf class names used in the mappings + Set usedClassNames = mappings.getAllObfClassNames(); + Set allClassNames = Sets.newHashSet(); + for( ClassEntry classEntry : sourceIndex.getObfClassEntries() ) + { + allClassNames.add( classEntry.getName() ); + } + usedClassNames.retainAll( allClassNames ); + + // probabilistically match the non-uniquely-matched source classes + for( Map.Entry> entry : conversionMap.values() ) { + ClassIdentity sourceClass = entry.getKey(); + List destClasses = entry.getValue(); + + // skip classes that are uniquely matched + if( destClasses.size() == 1 ) + { + continue; + } + + // skip classes that aren't used in the mappings + if( !usedClassNames.contains( sourceClass.getClassEntry().getName() ) ) + { + continue; + } + System.out.println( "No exact match for source class " + sourceClass.getClassEntry() ); // find the closest classes - TreeMap scoredMatches = Maps.newTreeMap( Collections.reverseOrder() ); - for( ClassIdentity c : matching.getUnmatchedDestClasses() ) + Multimap scoredMatches = ArrayListMultimap.create(); + for( ClassIdentity c : destClasses ) { scoredMatches.put( sourceClass.getMatchScore( c ), c ); } - Iterator> iter = scoredMatches.entrySet().iterator(); - for( int i=0; i<10 && iter.hasNext(); i++ ) - { - Map.Entry score = iter.next(); - System.out.println( String.format( "\tScore: %3d %s", score.getKey(), score.getValue().getClassEntry().getName() ) ); - } + List scores = new ArrayList( scoredMatches.keySet() ); + Collections.sort( scores, Collections.reverseOrder() ); + printScoredMatches( sourceClass.getMaxMatchScore(), scores, scoredMatches ); // does the best match have a non-zero score and the same name? - Map.Entry bestMatch = scoredMatches.firstEntry(); - if( bestMatch.getKey() > 0 && bestMatch.getValue().getClassEntry().equals( sourceClass.getClassEntry() ) ) + int bestScore = scores.get( 0 ); + Collection bestMatches = scoredMatches.get( bestScore ); + if( bestScore > 0 && bestMatches.size() == 1 ) { - // use it - System.out.println( "\tAutomatically choosing likely match: " + bestMatch.getValue().getClassEntry().getName() ); - conversionMap.put( - sourceClass.getClassEntry().getName(), - new AbstractMap.SimpleEntry>( sourceClass, Arrays.asList( bestMatch.getValue() ) ) - ); + ClassIdentity bestMatch = bestMatches.iterator().next(); + if( bestMatch.getClassEntry().equals( sourceClass.getClassEntry() ) ) + { + // use it + System.out.println( "\tAutomatically choosing likely match: " + bestMatch.getClassEntry().getName() ); + destClasses.clear(); + destClasses.add( bestMatch ); + } } } // use the matching to convert the mappings BiMap classConversion = HashBiMap.create(); Set unmatchedSourceClasses = Sets.newHashSet(); - for( String className : mappings.getAllObfClassNames() ) + for( String className : usedClassNames ) { // is there a match for this class? Map.Entry> entry = conversionMap.get( className ); ClassIdentity sourceClass = entry.getKey(); List matches = entry.getValue(); - if( matches.isEmpty() ) - { - // no match! =( - unmatchedSourceClasses.add( className ); - } - else if( matches.size() == 1 ) + if( matches.size() == 1 ) { // unique match! We're good to go! classConversion.put( @@ -142,10 +166,21 @@ public class ClassMatcher matches.get( 0 ).getClassEntry().getName() ); } - else if( matches.size() > 1 ) + else { - // too many matches! =( - unmatchedSourceClasses.add( className ); + // no match, check the fallback matching + String fallbackMatch = fallbackMatching.get( className ); + if( fallbackMatch != null ) + { + classConversion.put( + sourceClass.getClassEntry().getName(), + fallbackMatch + ); + } + else + { + unmatchedSourceClasses.add( className ); + } } } @@ -176,17 +211,11 @@ public class ClassMatcher } } - // TEMP: show some classes - for( String className : Arrays.asList( "none/em", "none/ej", "none/en" ) ) - { - System.out.println( String.format( "check: %s -> %s", className, classConversion.get( className ) ) ); - } - - // convert the classes + // convert the mappings mappings.renameObfClasses( classConversion ); - // look for method matches - System.out.println( "Matching methods..." ); + // check the method matches + System.out.println( "Checking methods..." ); for( ClassMapping classMapping : mappings.classes() ) { ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); @@ -234,91 +263,93 @@ public class ClassMatcher } } } + + System.out.println( "Done!" ); } public static ClassMatching computeMatching( JarIndex sourceIndex, TranslatingTypeLoader sourceLoader, JarIndex destIndex, TranslatingTypeLoader destLoader ) { System.out.println( "Matching classes..." ); ClassMatching matching = null; - for( boolean useRawNames : Arrays.asList( false/*, true*/ ) ) + for( boolean useReferences : Arrays.asList( false, true ) ) { - for( boolean useReferences : Arrays.asList( false, true ) ) + int numMatches = 0; + do { - int numMatches = 0; - do + SidedClassNamer sourceNamer = null; + SidedClassNamer destNamer = null; + if( matching != null ) { - SidedClassNamer sourceNamer = null; - SidedClassNamer destNamer = null; - if( matching != null ) - { - // build a class namer - ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); - sourceNamer = namer.getSourceNamer(); - destNamer = namer.getDestNamer(); - - // note the number of matches - numMatches = matching.getUniqueMatches().size(); - } + // build a class namer + ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); + sourceNamer = namer.getSourceNamer(); + destNamer = namer.getDestNamer(); - // get the entries left to match - Set sourceClassEntries = sourceIndex.getObfClassEntries(); - Set destClassEntries = destIndex.getObfClassEntries(); - if( matching != null ) + // note the number of matches + numMatches = matching.getUniqueMatches().size(); + } + + // get the entries left to match + Set sourceClassEntries = Sets.newHashSet(); + Set destClassEntries = Sets.newHashSet(); + if( matching == null ) + { + sourceClassEntries.addAll( sourceIndex.getObfClassEntries() ); + destClassEntries.addAll( destIndex.getObfClassEntries() ); + matching = new ClassMatching(); + } + else + { + for( Map.Entry,List> entry : matching.getAmbiguousMatches().entrySet() ) { - sourceClassEntries.clear(); - destClassEntries.clear(); - for( Map.Entry,List> entry : matching.getAmbiguousMatches().entrySet() ) - { - for( ClassIdentity c : entry.getKey() ) - { - sourceClassEntries.add( c.getClassEntry() ); - matching.removeSource( c ); - } - for( ClassIdentity c : entry.getValue() ) - { - destClassEntries.add( c.getClassEntry() ); - matching.removeDest( c ); - } - } - for( ClassIdentity c : matching.getUnmatchedSourceClasses() ) + for( ClassIdentity c : entry.getKey() ) { sourceClassEntries.add( c.getClassEntry() ); matching.removeSource( c ); } - for( ClassIdentity c : matching.getUnmatchedDestClasses() ) + for( ClassIdentity c : entry.getValue() ) { destClassEntries.add( c.getClassEntry() ); matching.removeDest( c ); } } - else + for( ClassIdentity c : matching.getUnmatchedSourceClasses() ) { - matching = new ClassMatching(); + sourceClassEntries.add( c.getClassEntry() ); + matching.removeSource( c ); } - - // compute a matching for the classes - for( ClassEntry classEntry : sourceClassEntries ) - { - CtClass c = sourceLoader.loadClass( classEntry.getName() ); - ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences, useRawNames ); - matching.addSource( sourceClass ); - } - for( ClassEntry classEntry : destClassEntries ) + for( ClassIdentity c : matching.getUnmatchedDestClasses() ) { - CtClass c = destLoader.loadClass( classEntry.getName() ); - ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences, useRawNames ); - matching.matchDestClass( destClass ); + destClassEntries.add( c.getClassEntry() ); + matching.removeDest( c ); } - - // TEMP - System.out.println( matching ); } - while( matching.getUniqueMatches().size() - numMatches > 0 ); + + // compute a matching for the classes + for( ClassEntry classEntry : sourceClassEntries ) + { + CtClass c = sourceLoader.loadClass( classEntry.getName() ); + ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences ); + matching.addSource( sourceClass ); + } + for( ClassEntry classEntry : destClassEntries ) + { + CtClass c = destLoader.loadClass( classEntry.getName() ); + ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences ); + matching.matchDestClass( destClass ); + } + + // TEMP + System.out.println( matching ); } + while( matching.getUniqueMatches().size() - numMatches > 0 ); } - // DEBUG: check the class matches + // check the class matches System.out.println( "Checking class matches..." ); + ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); + SidedClassNamer sourceNamer = namer.getSourceNamer(); + SidedClassNamer destNamer = namer.getDestNamer(); for( Map.Entry entry : matching.getUniqueMatches().entrySet() ) { // check source @@ -327,7 +358,7 @@ public class ClassMatcher assert( sourceC != null ) : "Unable to load source class " + sourceClass.getClassEntry(); assert( sourceClass.matches( sourceC ) ) - : "Source " + sourceClass + " doesn't match " + new ClassIdentity( sourceC, null, sourceIndex, false, false ); + : "Source " + sourceClass + " doesn't match " + new ClassIdentity( sourceC, sourceNamer, sourceIndex, false ); // check dest ClassIdentity destClass = entry.getValue(); @@ -335,7 +366,7 @@ public class ClassMatcher assert( destC != null ) : "Unable to load dest class " + destClass.getClassEntry(); assert( destClass.matches( destC ) ) - : "Dest " + destClass + " doesn't match " + new ClassIdentity( destC, null, destIndex, false, false ); + : "Dest " + destClass + " doesn't match " + new ClassIdentity( destC, destNamer, destIndex, false ); } // warn about the ambiguous matchings @@ -372,6 +403,27 @@ public class ClassMatcher return matching; } + private static void printScoredMatches( int maxScore, List scores, Multimap scoredMatches ) + { + int numScoredMatchesShown = 0; + for( int score : scores ) + { + for( ClassIdentity scoredMatch : scoredMatches.get( score ) ) + { + System.out.println( String.format( "\tScore: %3d %3.0f%% %s", + score, + 100.0*score/maxScore, + scoredMatch.getClassEntry().getName() + ) ); + + if( numScoredMatchesShown++ > 10 ) + { + return; + } + } + } + } + private static List getClassNames( Collection classes ) { List out = Lists.newArrayList(); diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java index ef5a7d8a..6ce8c887 100644 --- a/src/cuchaz/enigma/convert/ClassMatching.java +++ b/src/cuchaz/enigma/convert/ClassMatching.java @@ -183,7 +183,7 @@ public class ClassMatching { conversion.put( sourceClass.getClassEntry().getName(), - new AbstractMap.SimpleEntry>( sourceClass, new ArrayList() ) + new AbstractMap.SimpleEntry>( sourceClass, getUnmatchedDestClasses() ) ); } return conversion; @@ -193,25 +193,11 @@ public class ClassMatching public String toString( ) { StringBuilder buf = new StringBuilder(); - - buf.append( "Source classes: " ); - buf.append( getSourceClasses().size() ); - buf.append( "\n\tUnique: " ); - buf.append( getUniqueMatches().size() ); - buf.append( "\n\tAmbiguous: " ); - buf.append( getNumAmbiguousSourceMatches() ); - buf.append( "\n\tUnmatched: " ); - buf.append( getUnmatchedSourceClasses().size() ); - - buf.append( "\nDest classes: " ); - buf.append( getDestClasses().size() ); - buf.append( "\n\tUnique: " ); - buf.append( getUniqueMatches().size() ); - buf.append( "\n\tAmbiguous: " ); - buf.append( getNumAmbiguousDestMatches() ); - buf.append( "\n\tUnmatched: " ); - buf.append( getUnmatchedDestClasses().size() ); - + buf.append( String.format( "%12s%8s%8s\n", "", "Source", "Dest" ) ); + buf.append( String.format( "%12s%8d%8d\n", "Classes", getSourceClasses().size(), getDestClasses().size() ) ); + buf.append( String.format( "%12s%8d%8d\n", "Unique", getUniqueMatches().size(), getUniqueMatches().size() ) ); + buf.append( String.format( "%12s%8d%8d\n", "Ambiguous", getNumAmbiguousSourceMatches(), getNumAmbiguousDestMatches() ) ); + buf.append( String.format( "%12s%8d%8d\n", "Unmatched", getUnmatchedSourceClasses().size(), getUnmatchedDestClasses().size() ) ); return buf.toString(); } } diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index c92f8de0..4b47d160 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -15,15 +15,17 @@ import java.io.InputStream; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.ArrayList; -import java.util.List; import java.util.Map; +import java.util.Set; import java.util.zip.GZIPInputStream; +import com.beust.jcommander.internal.Sets; import com.google.common.collect.Maps; import cuchaz.enigma.Util; import cuchaz.enigma.analysis.Ancestries; import cuchaz.enigma.analysis.DeobfuscatedAncestries; +import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class Mappings implements Serializable { @@ -163,9 +165,28 @@ public class Mappings implements Serializable } } - public List getAllObfClassNames( ) + public Set getAllObfClassNames( ) { - // TODO: implement this - return null; + final Set classNames = Sets.newHashSet(); + for( ClassMapping classMapping : classes() ) + { + // add the class name + classNames.add( classMapping.getObfName() ); + + // add classes from method signatures + for( MethodMapping methodMapping : classMapping.methods() ) + { + SignatureUpdater.update( methodMapping.getObfSignature(), new ClassNameUpdater( ) + { + @Override + public String update( String className ) + { + classNames.add( className ); + return className; + } + } ); + } + } + return classNames; } } -- cgit v1.2.3 From 4e9c52d5fc5d23e8a77857e712654596203acb31 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 31 Aug 2014 16:14:45 -0400 Subject: fixed mapping conversion bug with class rename order --- src/cuchaz/enigma/convert/ClassMatcher.java | 83 ++++++++++++++++++++-------- src/cuchaz/enigma/convert/ClassMatching.java | 2 +- src/cuchaz/enigma/mapping/ClassMapping.java | 36 +++++++----- src/cuchaz/enigma/mapping/Mappings.java | 28 +++------- src/cuchaz/enigma/mapping/MethodMapping.java | 16 ++++-- 5 files changed, 103 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java index b551da25..0821bd3a 100644 --- a/src/cuchaz/enigma/convert/ClassMatcher.java +++ b/src/cuchaz/enigma/convert/ClassMatcher.java @@ -19,6 +19,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -89,9 +91,7 @@ public class ClassMatcher // compute the matching ClassMatching matching = computeMatching( sourceIndex, sourceLoader, destIndex, destLoader ); - - // start the class conversion map with the unique and ambiguous matchings - Map>> conversionMap = matching.getConversionMap(); + Map>> matchingIndex = matching.getIndex(); // get all the obf class names used in the mappings Set usedClassNames = mappings.getAllObfClassNames(); @@ -101,9 +101,10 @@ public class ClassMatcher allClassNames.add( classEntry.getName() ); } usedClassNames.retainAll( allClassNames ); + System.out.println( "Used " + usedClassNames.size() + " classes in the mappings" ); // probabilistically match the non-uniquely-matched source classes - for( Map.Entry> entry : conversionMap.values() ) + for( Map.Entry> entry : matchingIndex.values() ) { ClassIdentity sourceClass = entry.getKey(); List destClasses = entry.getValue(); @@ -148,20 +149,20 @@ public class ClassMatcher } } - // use the matching to convert the mappings - BiMap classConversion = HashBiMap.create(); - Set unmatchedSourceClasses = Sets.newHashSet(); + // group the matching into unique and non-unique matches + BiMap matchedClassNames = HashBiMap.create(); + Set unmatchedSourceClassNames = Sets.newHashSet(); for( String className : usedClassNames ) { // is there a match for this class? - Map.Entry> entry = conversionMap.get( className ); + Map.Entry> entry = matchingIndex.get( className ); ClassIdentity sourceClass = entry.getKey(); List matches = entry.getValue(); if( matches.size() == 1 ) { // unique match! We're good to go! - classConversion.put( + matchedClassNames.put( sourceClass.getClassEntry().getName(), matches.get( 0 ).getClassEntry().getName() ); @@ -172,35 +173,36 @@ public class ClassMatcher String fallbackMatch = fallbackMatching.get( className ); if( fallbackMatch != null ) { - classConversion.put( + matchedClassNames.put( sourceClass.getClassEntry().getName(), fallbackMatch ); } else { - unmatchedSourceClasses.add( className ); + unmatchedSourceClassNames.add( className ); } } } - // remove (and warn about) unmatched classes - if( !unmatchedSourceClasses.isEmpty() ) + // report unmatched classes + if( !unmatchedSourceClassNames.isEmpty() ) { - System.err.println( "WARNING: there were unmatched classes!" ); - for( String className : unmatchedSourceClasses ) + System.err.println( "ERROR: there were unmatched classes!" ); + for( String className : unmatchedSourceClassNames ) { System.err.println( "\t" + className ); - mappings.removeClassByObfName( className ); } - System.err.println( "Mappings for these classes have been removed." ); + return; } - // show the class name changes - for( Map.Entry entry : classConversion.entrySet() ) + // get the class name changes from the matched class names + Map classChanges = Maps.newHashMap(); + for( Map.Entry entry : matchedClassNames.entrySet() ) { if( !entry.getKey().equals( entry.getValue() ) ) { + classChanges.put( entry.getKey(), entry.getValue() ); System.out.println( String.format( "Class change: %s -> %s", entry.getKey(), entry.getValue() ) ); /* DEBUG System.out.println( String.format( "\n%s\n%s", @@ -211,8 +213,45 @@ public class ClassMatcher } } - // convert the mappings - mappings.renameObfClasses( classConversion ); + // sort the changes so classes are renamed in the correct order + // ie. if we have the mappings a->b, b->c, we have to apply b->c before a->b + LinkedHashMap orderedClassChanges = Maps.newLinkedHashMap(); + int numChangesLeft = classChanges.size(); + while( !classChanges.isEmpty() ) + { + Iterator> iter = classChanges.entrySet().iterator(); + while( iter.hasNext() ) + { + Map.Entry entry = iter.next(); + if( classChanges.get( entry.getValue() ) == null ) + { + orderedClassChanges.put( entry.getKey(), entry.getValue() ); + iter.remove(); + } + } + + // did we remove any changes? + if( numChangesLeft - classChanges.size() > 0 ) + { + // keep going + numChangesLeft = classChanges.size(); + } + else + { + // can't sort anymore. There must be a loop + break; + } + } + if( classChanges.size() > 0 ) + { + throw new Error( String.format( "Unable to sort %d/%d class changes!", classChanges.size(), matchedClassNames.size() ) ); + } + + // convert the mappings in the correct class order + for( Map.Entry entry : orderedClassChanges.entrySet() ) + { + mappings.renameObfClass( entry.getKey(), entry.getValue() ); + } // check the method matches System.out.println( "Checking methods..." ); @@ -250,7 +289,7 @@ public class ClassMatcher } System.err.println( "\tAvailable source methods:" ); - c = sourceLoader.loadClass( classConversion.inverse().get( classMapping.getObfName() ) ); + c = sourceLoader.loadClass( matchedClassNames.inverse().get( classMapping.getObfName() ) ); for( CtBehavior behavior : c.getDeclaredBehaviors() ) { MethodEntry declaredMethodEntry = new MethodEntry( diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java index 6ce8c887..5511902d 100644 --- a/src/cuchaz/enigma/convert/ClassMatching.java +++ b/src/cuchaz/enigma/convert/ClassMatching.java @@ -159,7 +159,7 @@ public class ClassMatching return new ArrayList( m_unmatchedDestClasses ); } - public Map>> getConversionMap( ) + public Map>> getIndex( ) { Map>> conversion = Maps.newHashMap(); for( Map.Entry entry : getUniqueMatches().entrySet() ) diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index 095cb385..1219e7ca 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -301,31 +301,37 @@ public class ClassMapping implements Serializable, Comparable return m_obfName.compareTo( other.m_obfName ); } - public void renameObfClasses( Map nameMap ) + public boolean renameObfClass( String oldObfClassName, String newObfClassName ) { - // rename self + // rename inner classes + for( ClassMapping innerClassMapping : new ArrayList( m_innerClassesByObf.values() ) ) { - String newName = nameMap.get( m_obfName ); - if( newName != null ) + if( innerClassMapping.renameObfClass( oldObfClassName, newObfClassName ) ) { - m_obfName = newName; + m_innerClassesByObf.remove( oldObfClassName ); + m_innerClassesByObf.put( newObfClassName, innerClassMapping ); + assert( m_innerClassesByObf.size() == m_innerClassesByDeobf.size() ); } } - // rename inner classes - for( ClassMapping classMapping : new ArrayList( m_innerClassesByObf.values() ) ) + // rename method signatures + for( MethodMapping methodMapping : new ArrayList( m_methodsByObf.values() ) ) { - m_innerClassesByObf.remove( classMapping.getObfName() ); - classMapping.renameObfClasses( nameMap ); - m_innerClassesByObf.put( classMapping.getObfName(), classMapping ); + String oldMethodKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ); + if( methodMapping.renameObfClass( oldObfClassName, newObfClassName ) ) + { + m_methodsByObf.remove( oldMethodKey ); + m_methodsByObf.put( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ), methodMapping ); + assert( m_methodsByObf.size() == m_methodsByDeobf.size() ); + } } - // rename method signatures - for( MethodMapping methodMapping : new ArrayList( m_methodsByObf.values() ) ) + if( m_obfName.equals( oldObfClassName ) ) { - m_methodsByObf.remove( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ) ); - methodMapping.renameObfClasses( nameMap ); - m_methodsByObf.put( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ), methodMapping ); + // rename this class + m_obfName = newObfClassName; + return true; } + return false; } } diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 4b47d160..0b03abb0 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -15,6 +15,7 @@ import java.io.InputStream; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.zip.GZIPInputStream; @@ -66,7 +67,7 @@ public class Mappings implements Serializable } } - public Iterable classes( ) + public Collection classes( ) { assert( m_classesByObf.size() == m_classesByDeobf.size() ); return m_classesByObf.values(); @@ -141,30 +142,19 @@ public class Mappings implements Serializable return buf.toString(); } - public void renameObfClasses( Map nameMap ) + public void renameObfClass( String oldObfName, String newObfName ) { - for( ClassMapping classMapping : new ArrayList( m_classesByObf.values() ) ) + for( ClassMapping classMapping : new ArrayList( classes() ) ) { - String newName = nameMap.get( classMapping.getObfName() ); - if( newName != null ) + if( classMapping.renameObfClass( oldObfName, newObfName ) ) { - m_classesByObf.remove( classMapping.getObfName() ); - classMapping.renameObfClasses( nameMap ); - m_classesByObf.put( classMapping.getObfName(), classMapping ); + m_classesByObf.remove( oldObfName ); + m_classesByObf.put( newObfName, classMapping ); + assert( m_classesByObf.size() == m_classesByDeobf.size() ); } } } - - public void removeClassByObfName( String obfName ) - { - ClassMapping classMapping = m_classesByObf.get( obfName ); - if( classMapping != null ) - { - m_classesByObf.remove( classMapping.getObfName() ); - m_classesByDeobf.remove( classMapping.getDeobfName() ); - } - } - + public Set getAllObfClassNames( ) { final Set classNames = Sets.newHashSet(); diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java index fe4e29b2..b0f7ba84 100644 --- a/src/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/cuchaz/enigma/mapping/MethodMapping.java @@ -142,21 +142,27 @@ public class MethodMapping implements Serializable, Comparable return ( m_obfName + m_obfSignature ).compareTo( ( other.m_obfName + other.m_obfSignature ) ); } - public void renameObfClasses( final Map nameMap ) + public boolean renameObfClass( final String oldObfClassName, final String newObfClassName ) { // rename obf classes in the signature - m_obfSignature = SignatureUpdater.update( m_obfSignature, new ClassNameUpdater( ) + String newSignature = SignatureUpdater.update( m_obfSignature, new ClassNameUpdater( ) { @Override public String update( String className ) { - String newName = nameMap.get( className ); - if( newName != null ) + if( className.equals( oldObfClassName ) ) { - return newName; + return newObfClassName; } return className; } } ); + + if( newSignature != m_obfSignature ) + { + m_obfSignature = newSignature; + return true; + } + return false; } } -- cgit v1.2.3 From 5ba0b71cae99d99a4ef359ebccbb97ceda9c5083 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 31 Aug 2014 17:53:05 -0400 Subject: added simple loading screen for jars --- src/cuchaz/enigma/gui/Gui.java | 53 +++++++++++++++++++++++++------- src/cuchaz/enigma/gui/GuiController.java | 5 +-- 2 files changed, 45 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index ec0f842a..46395ac2 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -146,6 +146,8 @@ public class Gui private JList m_obfClasses; private JList m_deobfClasses; private JEditorPane m_editor; + private JPanel m_classesPanel; + private JSplitPane m_splitClasses; private JPanel m_infoPanel; private ObfuscatedHighlightPainter m_obfuscatedHighlightPainter; private DeobfuscatedHighlightPainter m_deobfuscatedHighlightPainter; @@ -262,6 +264,12 @@ public class Gui deobfPanel.add( new JLabel( "De-obfuscated Classes" ), BorderLayout.NORTH ); deobfPanel.add( deobfScroller, BorderLayout.CENTER ); + // set up classes panel (don't add the splitter yet) + m_splitClasses = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); + m_classesPanel = new JPanel(); + m_classesPanel.setLayout( new BorderLayout() ); + m_classesPanel.setPreferredSize( new Dimension( 250, 0 ) ); + // init info panel m_infoPanel = new JPanel(); m_infoPanel.setLayout( new GridLayout( 4, 1, 0, 0 ) ); @@ -563,8 +571,6 @@ public class Gui callPanel.resetToPreferredSizes(); // layout controls - JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); - splitLeft.setPreferredSize( new Dimension( 250, 0 ) ); JPanel centerPanel = new JPanel(); centerPanel.setLayout( new BorderLayout() ); centerPanel.add( m_infoPanel, BorderLayout.NORTH ); @@ -577,7 +583,7 @@ public class Gui JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs ); splitRight.setResizeWeight( 1 ); // let the left side take all the slack splitRight.resetToPreferredSizes(); - JSplitPane splitCenter = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, splitRight ); + JSplitPane splitCenter = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, m_classesPanel, splitRight ); splitCenter.setResizeWeight( 0 ); // let the right side take all the slack pane.add( splitCenter, BorderLayout.CENTER ); @@ -597,14 +603,22 @@ public class Gui { if( m_jarFileChooser.showOpenDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) { - try - { - m_controller.openJar( m_jarFileChooser.getSelectedFile() ); - } - catch( IOException ex ) + // load the jar in a separate thread + new Thread( ) { - throw new Error( ex ); - } + @Override + public void run( ) + { + try + { + m_controller.openJar( m_jarFileChooser.getSelectedFile() ); + } + catch( IOException ex ) + { + throw new Error( ex ); + } + } + }.start(); } } } ); @@ -786,10 +800,22 @@ public class Gui return m_controller; } - public void onOpenJar( String jarName ) + public void onStartOpenJar( ) + { + m_classesPanel.removeAll(); + JPanel panel = new JPanel(); + panel.setLayout( new FlowLayout() ); + panel.add( new JLabel( "Loading..." ) ); + m_classesPanel.add( panel ); + redraw(); + } + + public void onFinishOpenJar( String jarName ) { // update gui m_frame.setTitle( Constants.Name + " - " + jarName ); + m_classesPanel.removeAll(); + m_classesPanel.add( m_splitClasses ); setSource( null ); // update menu @@ -798,6 +824,8 @@ public class Gui m_saveMappingsMenu.setEnabled( false ); m_saveMappingsAsMenu.setEnabled( true ); m_closeMappingsMenu.setEnabled( true ); + + redraw(); } public void onCloseJar( ) @@ -807,6 +835,7 @@ public class Gui setObfClasses( null ); setDeobfClasses( null ); setSource( null ); + m_classesPanel.removeAll(); // update menu m_closeJarMenu.setEnabled( false ); @@ -814,6 +843,8 @@ public class Gui m_saveMappingsMenu.setEnabled( false ); m_saveMappingsAsMenu.setEnabled( false ); m_closeMappingsMenu.setEnabled( false ); + + redraw(); } public void setObfClasses( List obfClasses ) diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index bd79e480..28794836 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -66,11 +66,12 @@ public class GuiController return m_isDirty; } - public void openJar( File file ) + public void openJar( final File file ) throws IOException { + m_gui.onStartOpenJar(); m_deobfuscator = new Deobfuscator( file ); - m_gui.onOpenJar( m_deobfuscator.getJarName() ); + m_gui.onFinishOpenJar( m_deobfuscator.getJarName() ); refreshClasses(); } -- cgit v1.2.3 From 30f552a3b31b4234d3a63375b6c939826b015ece Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 31 Aug 2014 21:19:57 -0400 Subject: fixed crash finding related method implementations when method doesn't implement interface --- src/cuchaz/enigma/analysis/JarIndex.java | 6 +++++- src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 4279dedd..fc19e7bc 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -663,7 +663,11 @@ public class JarIndex } // look at interface methods too - getRelatedMethodImplementations( methodEntries, getMethodImplementations( null, methodEntry ) ); + MethodImplementationsTreeNode implementations = getMethodImplementations( null, methodEntry ); + if( implementations != null ) + { + getRelatedMethodImplementations( methodEntries, implementations ); + } // recurse for( int i=0; i } return false; } + + public boolean containsDeobfField( String name ) + { + return m_fieldsByDeobf.containsKey( name ); + } + + public boolean containsDeobfMethod( String name, String signature ) + { + return m_methodsByDeobf.containsKey( getMethodKey( name, signature ) ); + } + + public boolean containsArgument( MethodEntry obfMethodEntry, String name ) + { + MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfMethodEntry.getName(), obfMethodEntry.getSignature() ) ); + if( methodMapping != null ) + { + return methodMapping.containsArgument( name ); + } + return false; + } } diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 0b03abb0..378d4c0a 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -179,4 +179,39 @@ public class Mappings implements Serializable } return classNames; } + + public boolean containsDeobfClass( String deobfName ) + { + return m_classesByDeobf.containsKey( deobfName ); + } + + public boolean containsDeobfField( ClassEntry obfClassEntry, String deobfName ) + { + ClassMapping classMapping = m_classesByObf.get( obfClassEntry.getName() ); + if( classMapping != null ) + { + return classMapping.containsDeobfField( deobfName ); + } + return false; + } + + public boolean containsDeobfMethod( ClassEntry obfClassEntry, String deobfName, String deobfSignature ) + { + ClassMapping classMapping = m_classesByObf.get( obfClassEntry.getName() ); + if( classMapping != null ) + { + return classMapping.containsDeobfMethod( deobfName, deobfSignature ); + } + return false; + } + + public boolean containsArgument( MethodEntry obfMethodEntry, String name ) + { + ClassMapping classMapping = m_classesByObf.get( obfMethodEntry.getClassName() ); + if( classMapping != null ) + { + return classMapping.containsArgument( obfMethodEntry, name ); + } + return false; + } } diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java index b0f7ba84..bf83bd21 100644 --- a/src/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/cuchaz/enigma/mapping/MethodMapping.java @@ -165,4 +165,16 @@ public class MethodMapping implements Serializable, Comparable } return false; } + + public boolean containsArgument( String name ) + { + for( ArgumentMapping argumentMapping : m_arguments.values() ) + { + if( argumentMapping.getName().equals( name ) ) + { + return true; + } + } + return false; + } } diff --git a/src/cuchaz/enigma/mapping/Renamer.java b/src/cuchaz/enigma/mapping/Renamer.java index 79cbd30d..15d9af4d 100644 --- a/src/cuchaz/enigma/mapping/Renamer.java +++ b/src/cuchaz/enigma/mapping/Renamer.java @@ -13,6 +13,7 @@ package cuchaz.enigma.mapping; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.OutputStream; +import java.util.Set; import java.util.zip.GZIPOutputStream; import cuchaz.enigma.analysis.JarIndex; @@ -31,6 +32,12 @@ public class Renamer public void setClassName( ClassEntry obf, String deobfName ) { deobfName = NameValidator.validateClassName( deobfName ); + ClassEntry targetEntry = new ClassEntry( deobfName ); + if( m_mappings.containsDeobfClass( deobfName ) || m_index.containsObfClass( targetEntry ) ) + { + throw new IllegalNameException( deobfName, "There is already a class with that name" ); + } + ClassMapping classMapping = getOrCreateClassMapping( obf ); if( obf.isInnerClass() ) @@ -50,13 +57,32 @@ public class Renamer public void setFieldName( FieldEntry obf, String deobfName ) { deobfName = NameValidator.validateFieldName( deobfName ); + FieldEntry targetEntry = new FieldEntry( obf.getClassEntry(), deobfName ); + if( m_mappings.containsDeobfField( obf.getClassEntry(), deobfName ) || m_index.containsObfField( targetEntry ) ) + { + throw new IllegalNameException( deobfName, "There is already a field with that name" ); + } + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); classMapping.setFieldName( obf.getName(), deobfName ); } public void setMethodTreeName( MethodEntry obf, String deobfName ) { - for( MethodEntry entry : m_index.getRelatedMethodImplementations( obf ) ) + Set implementations = m_index.getRelatedMethodImplementations( obf ); + + deobfName = NameValidator.validateMethodName( deobfName ); + for( MethodEntry entry : implementations ) + { + MethodEntry targetEntry = new MethodEntry( entry.getClassEntry(), deobfName, entry.getSignature() ); + if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) + { + String className = m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ).translateClass( entry.getClassName() ); + throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + className ); + } + } + + for( MethodEntry entry : implementations ) { setMethodName( entry, deobfName ); } @@ -65,6 +91,13 @@ public class Renamer public void setMethodName( MethodEntry obf, String deobfName ) { deobfName = NameValidator.validateMethodName( deobfName ); + MethodEntry targetEntry = new MethodEntry( obf.getClassEntry(), deobfName, obf.getSignature() ); + if( m_mappings.containsDeobfMethod( obf.getClassEntry(), deobfName, obf.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) + { + String className = m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ).translateClass( obf.getClassName() ); + throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + className ); + } + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); String deobfSignature = m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); classMapping.setMethodNameAndSignature( obf.getName(), obf.getSignature(), deobfName, deobfSignature ); @@ -73,6 +106,12 @@ public class Renamer public void setArgumentName( ArgumentEntry obf, String deobfName ) { deobfName = NameValidator.validateArgumentName( deobfName ); + // NOTE: don't need to check arguments for name collisions with names determined by Procyon + if( m_mappings.containsArgument( obf.getMethodEntry(), deobfName ) ) + { + throw new IllegalNameException( deobfName, "There is already an argument with that name" ); + } + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); classMapping.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName ); } -- cgit v1.2.3 From a146283291d5529eb9363b2fbc6fd5e643dee85a Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 1 Sep 2014 20:40:11 -0400 Subject: made obfuscated/deobfuscated class selector a bit easier to use --- src/cuchaz/enigma/Deobfuscator.java | 10 +- src/cuchaz/enigma/gui/ClassSelector.java | 181 +++++++++++++++++++++ src/cuchaz/enigma/gui/ClassSelectorClassNode.java | 38 +++++ .../enigma/gui/ClassSelectorPackageNode.java | 36 ++++ src/cuchaz/enigma/gui/Gui.java | 126 +++----------- src/cuchaz/enigma/gui/GuiController.java | 4 +- 6 files changed, 282 insertions(+), 113 deletions(-) create mode 100644 src/cuchaz/enigma/gui/ClassSelector.java create mode 100644 src/cuchaz/enigma/gui/ClassSelectorClassNode.java create mode 100644 src/cuchaz/enigma/gui/ClassSelectorPackageNode.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 9a78f38d..49aa1ff6 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -151,12 +151,12 @@ public class Deobfuscator return m_mappings.getTranslator( m_jarIndex.getAncestries(), direction ); } - public void getSeparatedClasses( List obfClasses, List deobfClasses ) + public void getSeparatedClasses( List obfClasses, List deobfClasses ) { for( ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries() ) { // skip inner classes - if( m_jarIndex.getOuterClass( obfClassEntry.getName() ) != null ) + if( obfClassEntry.isInnerClass() ) { continue; } @@ -166,17 +166,17 @@ public class Deobfuscator if( !deobfClassEntry.equals( obfClassEntry ) ) { // if the class has a mapping, clearly it's deobfuscated - deobfClasses.add( deobfClassEntry.getName() ); + deobfClasses.add( deobfClassEntry ); } else if( !obfClassEntry.getPackageName().equals( Constants.NonePackage ) ) { // also call it deobufscated if it's not in the none package - deobfClasses.add( obfClassEntry.getName() ); + deobfClasses.add( obfClassEntry ); } else { // otherwise, assume it's still obfuscated - obfClasses.add( obfClassEntry.getName() ); + obfClasses.add( obfClassEntry ); } } } diff --git a/src/cuchaz/enigma/gui/ClassSelector.java b/src/cuchaz/enigma/gui/ClassSelector.java new file mode 100644 index 00000000..338ad805 --- /dev/null +++ b/src/cuchaz/enigma/gui/ClassSelector.java @@ -0,0 +1,181 @@ +package cuchaz.enigma.gui; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreePath; + +import com.beust.jcommander.internal.Lists; +import com.beust.jcommander.internal.Maps; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; + +import cuchaz.enigma.mapping.ClassEntry; + +public class ClassSelector extends JTree +{ + private static final long serialVersionUID = -7632046902384775977L; + + public interface ClassSelectionListener + { + void onSelectClass( ClassEntry classEntry ); + } + + public static Comparator ObfuscatedClassEntryComparator; + public static Comparator DeobfuscatedClassEntryComparator; + + static + { + ObfuscatedClassEntryComparator = new Comparator( ) + { + @Override + public int compare( ClassEntry a, ClassEntry b ) + { + if( a.getName().length() != b.getName().length() ) + { + return a.getName().length() - b.getName().length(); + } + return a.getName().compareTo( b.getName() ); + } + }; + + DeobfuscatedClassEntryComparator = new Comparator( ) + { + @Override + public int compare( ClassEntry a, ClassEntry b ) + { + return a.getName().compareTo( b.getName() ); + } + }; + } + + private ClassSelectionListener m_listener; + private Comparator m_comparator; + + public ClassSelector( Comparator comparator ) + { + m_comparator = comparator; + + // configure the tree control + setRootVisible( false ); + setShowsRootHandles( false ); + setModel( null ); + + // hook events + addMouseListener( new MouseAdapter() + { + @Override + public void mouseClicked( MouseEvent event ) + { + if( m_listener != null && event.getClickCount() == 2 ) + { + // get the selected node + TreePath path = getSelectionPath(); + if( path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode ) + { + ClassSelectorClassNode node = (ClassSelectorClassNode)path.getLastPathComponent(); + m_listener.onSelectClass( node.getClassEntry() ); + } + } + } + } ); + + // init defaults + m_listener = null; + } + + public void setListener( ClassSelectionListener val ) + { + m_listener = val; + } + + public void setClasses( Collection classEntries ) + { + if( classEntries == null ) + { + setModel( null ); + return; + } + + // build the package names + Map packages = Maps.newHashMap(); + for( ClassEntry classEntry : classEntries ) + { + packages.put( classEntry.getPackageName(), null ); + } + + // sort the packages + List sortedPackageNames = Lists.newArrayList( packages.keySet() ); + Collections.sort( sortedPackageNames, new Comparator( ) + { + @Override + public int compare( String a, String b ) + { + // I can never keep this rule straight when writing these damn things... + // a < b => -1, a == b => 0, a > b => +1 + + String[] aparts = a.split( "/" ); + String[] bparts = b.split( "/" ); + for( int i=0; true; i++ ) + { + if( i >= aparts.length ) + { + return -1; + } + else if( i >= bparts.length ) + { + return 1; + } + + int result = aparts[i].compareTo( bparts[i] ); + if( result != 0 ) + { + return result; + } + } + } + } ); + + // create the root node and the package nodes + DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + for( String packageName : sortedPackageNames ) + { + ClassSelectorPackageNode node = new ClassSelectorPackageNode( packageName ); + packages.put( packageName, node ); + root.add( node ); + } + + // put the classes into packages + Multimap packagedClassEntries = ArrayListMultimap.create(); + for( ClassEntry classEntry : classEntries ) + { + packagedClassEntries.put( classEntry.getPackageName(), classEntry ); + } + + // build the class nodes + for( String packageName : packagedClassEntries.keySet() ) + { + // sort the class entries + List classEntriesInPackage = Lists.newArrayList( packagedClassEntries.get( packageName ) ); + Collections.sort( classEntriesInPackage, m_comparator ); + + // create the nodes in order + for( ClassEntry classEntry : classEntriesInPackage ) + { + ClassSelectorPackageNode node = packages.get( packageName ); + node.add( new ClassSelectorClassNode( classEntry ) ); + } + } + + // finally, update the tree control + setModel( new DefaultTreeModel( root ) ); + } +} diff --git a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java new file mode 100644 index 00000000..cffa7952 --- /dev/null +++ b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.gui; + +import javax.swing.tree.DefaultMutableTreeNode; + +import cuchaz.enigma.mapping.ClassEntry; + +public class ClassSelectorClassNode extends DefaultMutableTreeNode +{ + private static final long serialVersionUID = -8956754339813257380L; + + private ClassEntry m_classEntry; + + public ClassSelectorClassNode( ClassEntry classEntry ) + { + m_classEntry = classEntry; + } + + public ClassEntry getClassEntry( ) + { + return m_classEntry; + } + + @Override + public String toString( ) + { + return m_classEntry.getSimpleName(); + } +} diff --git a/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java b/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java new file mode 100644 index 00000000..ad88fb44 --- /dev/null +++ b/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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 javax.swing.tree.DefaultMutableTreeNode; + +public class ClassSelectorPackageNode extends DefaultMutableTreeNode +{ + private static final long serialVersionUID = -3730868701219548043L; + + private String m_packageName; + + public ClassSelectorPackageNode( String packageName ) + { + m_packageName = packageName; + } + + public String getPackageName( ) + { + return m_packageName; + } + + @Override + public String toString( ) + { + return m_packageName; + } +} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 46395ac2..8ae16f42 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -31,7 +31,6 @@ import java.io.IOException; import java.lang.Thread.UncaughtExceptionHandler; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Vector; @@ -79,6 +78,7 @@ import cuchaz.enigma.analysis.MethodImplementationsTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.ReferenceTreeNode; import cuchaz.enigma.analysis.Token; +import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; @@ -90,61 +90,12 @@ import cuchaz.enigma.mapping.MethodEntry; public class Gui { - private static Comparator m_obfClassSorter; - private static Comparator m_deobfClassSorter; - - static - { - m_obfClassSorter = new Comparator( ) - { - @Override - public int compare( String a, String b ) - { - if( a.length() != b.length() ) - { - return a.length() - b.length(); - } - return a.compareTo( b ); - } - }; - - m_deobfClassSorter = new Comparator( ) - { - @Override - public int compare( String a, String b ) - { - // I can never keep this rule straight when writing these damn things... - // a < b => -1, a == b => 0, a > b => +1 - - String[] aparts = a.split( "\\." ); - String[] bparts = b.split( "\\." ); - for( int i=0; true; i++ ) - { - if( i >= aparts.length ) - { - return -1; - } - else if( i >= bparts.length ) - { - return 1; - } - - int result = aparts[i].compareTo( bparts[i] ); - if( result != 0 ) - { - return result; - } - } - } - }; - } - private GuiController m_controller; // controls private JFrame m_frame; - private JList m_obfClasses; - private JList m_deobfClasses; + private ClassSelector m_obfClasses; + private ClassSelector m_deobfClasses; private JEditorPane m_editor; private JPanel m_classesPanel; private JSplitPane m_splitClasses; @@ -205,27 +156,17 @@ public class Gui m_exportFileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); // init obfuscated classes list - m_obfClasses = new JList(); - m_obfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); - m_obfClasses.setLayoutOrientation( JList.VERTICAL ); - m_obfClasses.setCellRenderer( new ClassListCellRenderer() ); - m_obfClasses.addMouseListener( new MouseAdapter() + m_obfClasses = new ClassSelector( ClassSelector.ObfuscatedClassEntryComparator ); + m_obfClasses.setListener( new ClassSelectionListener( ) { @Override - public void mouseClicked( MouseEvent event ) + public void onSelectClass( ClassEntry classEntry ) { - if( event.getClickCount() == 2 ) + if( m_reference != null ) { - String selected = m_obfClasses.getSelectedValue(); - if( selected != null ) - { - if( m_reference != null ) - { - m_controller.savePreviousReference( m_reference ); - } - m_controller.openDeclaration( new ClassEntry( selected ) ); - } + m_controller.savePreviousReference( m_reference ); } + m_controller.openDeclaration( classEntry ); } } ); JScrollPane obfScroller = new JScrollPane( m_obfClasses ); @@ -235,27 +176,17 @@ public class Gui obfPanel.add( obfScroller, BorderLayout.CENTER ); // init deobfuscated classes list - m_deobfClasses = new JList(); - m_deobfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); - m_deobfClasses.setLayoutOrientation( JList.VERTICAL ); - m_deobfClasses.setCellRenderer( new ClassListCellRenderer() ); - m_deobfClasses.addMouseListener( new MouseAdapter() + m_deobfClasses = new ClassSelector( ClassSelector.DeobfuscatedClassEntryComparator ); + m_deobfClasses.setListener( new ClassSelectionListener( ) { @Override - public void mouseClicked( MouseEvent event ) + public void onSelectClass( ClassEntry classEntry ) { - if( event.getClickCount() == 2 ) + if( m_reference != null ) { - String selected = m_deobfClasses.getSelectedValue(); - if( selected != null ) - { - if( m_reference != null ) - { - m_controller.savePreviousReference( m_reference ); - } - m_controller.openDeclaration( new ClassEntry( selected ) ); - } + m_controller.savePreviousReference( m_reference ); } + m_controller.openDeclaration( classEntry ); } } ); JScrollPane deobfScroller = new JScrollPane( m_deobfClasses ); @@ -266,6 +197,7 @@ public class Gui // set up classes panel (don't add the splitter yet) m_splitClasses = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); + m_splitClasses.setResizeWeight( 0.3 ); m_classesPanel = new JPanel(); m_classesPanel.setLayout( new BorderLayout() ); m_classesPanel.setPreferredSize( new Dimension( 250, 0 ) ); @@ -847,32 +779,14 @@ public class Gui redraw(); } - public void setObfClasses( List obfClasses ) + public void setObfClasses( Collection obfClasses ) { - if( obfClasses != null ) - { - Vector sortedClasses = new Vector( obfClasses ); - Collections.sort( sortedClasses, m_obfClassSorter ); - m_obfClasses.setListData( sortedClasses ); - } - else - { - m_obfClasses.setListData( new Vector() ); - } + m_obfClasses.setClasses( obfClasses ); } - public void setDeobfClasses( List deobfClasses ) + public void setDeobfClasses( Collection deobfClasses ) { - if( deobfClasses != null ) - { - Vector sortedClasses = new Vector( deobfClasses ); - Collections.sort( sortedClasses, m_deobfClassSorter ); - m_deobfClasses.setListData( sortedClasses ); - } - else - { - m_deobfClasses.setListData( new Vector() ); - } + m_deobfClasses.setClasses( deobfClasses ); } public void setMappingsFile( File file ) diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 28794836..c0fb2e40 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -315,8 +315,8 @@ public class GuiController private void refreshClasses( ) { - List obfClasses = Lists.newArrayList(); - List deobfClasses = Lists.newArrayList(); + List obfClasses = Lists.newArrayList(); + List deobfClasses = Lists.newArrayList(); m_deobfuscator.getSeparatedClasses( obfClasses, deobfClasses ); m_gui.setObfClasses( obfClasses ); m_gui.setDeobfClasses( deobfClasses ); -- cgit v1.2.3 From 0939bdc88702e5d6ba3f99e054e87bdd7cc573e4 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 1 Sep 2014 20:44:18 -0400 Subject: added copyright notice --- src/cuchaz/enigma/gui/ClassSelector.java | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/ClassSelector.java b/src/cuchaz/enigma/gui/ClassSelector.java index 338ad805..c0f7f3c5 100644 --- a/src/cuchaz/enigma/gui/ClassSelector.java +++ b/src/cuchaz/enigma/gui/ClassSelector.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.event.MouseAdapter; -- cgit v1.2.3 From 360bbd1c2fca8cbd575907b7d930a8072fccb0c2 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 1 Sep 2014 22:52:07 -0400 Subject: refactored jar,translation index. fixed bug with field renaming when fields are shadowed by subclasses --- src/cuchaz/enigma/Deobfuscator.java | 43 ++-- src/cuchaz/enigma/analysis/Ancestries.java | 199 ----------------- .../analysis/ClassImplementationsTreeNode.java | 4 +- .../enigma/analysis/ClassInheritanceTreeNode.java | 4 +- .../enigma/analysis/DeobfuscatedAncestries.java | 59 ----- src/cuchaz/enigma/analysis/EntryRenamer.java | 199 +++++++++++++++++ src/cuchaz/enigma/analysis/JarIndex.java | 240 ++++++--------------- .../analysis/MethodImplementationsTreeNode.java | 2 +- .../enigma/analysis/MethodInheritanceTreeNode.java | 2 +- src/cuchaz/enigma/analysis/TranslationIndex.java | 126 +++++++++++ src/cuchaz/enigma/mapping/Mappings.java | 22 +- src/cuchaz/enigma/mapping/MappingsRenamer.java | 164 ++++++++++++++ src/cuchaz/enigma/mapping/Renamer.java | 160 -------------- src/cuchaz/enigma/mapping/Translator.java | 21 +- 14 files changed, 617 insertions(+), 628 deletions(-) delete mode 100644 src/cuchaz/enigma/analysis/Ancestries.java delete mode 100644 src/cuchaz/enigma/analysis/DeobfuscatedAncestries.java create mode 100644 src/cuchaz/enigma/analysis/EntryRenamer.java create mode 100644 src/cuchaz/enigma/analysis/TranslationIndex.java create mode 100644 src/cuchaz/enigma/mapping/MappingsRenamer.java delete mode 100644 src/cuchaz/enigma/mapping/Renamer.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 49aa1ff6..0356f923 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -15,10 +15,12 @@ import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; import java.util.List; +import java.util.Map; import java.util.jar.JarFile; import javassist.bytecode.Descriptor; +import com.google.common.collect.Maps; import com.strobel.assembler.metadata.MetadataSystem; import com.strobel.assembler.metadata.TypeDefinition; import com.strobel.decompiler.DecompilerContext; @@ -42,7 +44,7 @@ import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.Mappings; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.MethodMapping; -import cuchaz.enigma.mapping.Renamer; +import cuchaz.enigma.mapping.MappingsRenamer; import cuchaz.enigma.mapping.TranslationDirection; import cuchaz.enigma.mapping.Translator; @@ -59,8 +61,8 @@ public class Deobfuscator private DecompilerSettings m_settings; private JarIndex m_jarIndex; private Mappings m_mappings; - private Renamer m_renamer; - private TranslatingTypeLoader m_typeLoader; + private MappingsRenamer m_renamer; + private Map m_translatorCache; public Deobfuscator( File file ) throws IOException @@ -78,6 +80,9 @@ public class Deobfuscator // DEBUG //m_settings.setShowSyntheticMembers( true ); + // init defaults + m_translatorCache = Maps.newTreeMap(); + // init mappings setMappings( new Mappings() ); } @@ -134,21 +139,19 @@ public class Deobfuscator } m_mappings = val; - m_renamer = new Renamer( m_jarIndex, m_mappings ); - - // update decompiler options - m_typeLoader = new TranslatingTypeLoader( - m_jar, - m_jarIndex, - getTranslator( TranslationDirection.Obfuscating ), - getTranslator( TranslationDirection.Deobfuscating ) - ); - m_settings.setTypeLoader( m_typeLoader ); + m_renamer = new MappingsRenamer( m_jarIndex, m_mappings ); + m_translatorCache.clear(); } public Translator getTranslator( TranslationDirection direction ) { - return m_mappings.getTranslator( m_jarIndex.getAncestries(), direction ); + Translator translator = m_translatorCache.get( direction ); + if( translator == null ) + { + translator = m_mappings.getTranslator( m_jarIndex.getTranslationIndex(), direction ); + m_translatorCache.put( direction, translator ); + } + return translator; } public void getSeparatedClasses( List obfClasses, List deobfClasses ) @@ -192,6 +195,14 @@ public class Deobfuscator className = classMapping.getDeobfName(); } + // set the type loader + m_settings.setTypeLoader( new TranslatingTypeLoader( + m_jar, + m_jarIndex, + getTranslator( TranslationDirection.Obfuscating ), + getTranslator( TranslationDirection.Deobfuscating ) + ) ); + // decompile it! TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( className ).resolve(); DecompilerContext context = new DecompilerContext(); @@ -350,8 +361,8 @@ public class Deobfuscator throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); } - // clear the type loader cache - m_typeLoader.clearCache(); + // clear caches + m_translatorCache.clear(); } public boolean hasMapping( Entry obfEntry ) diff --git a/src/cuchaz/enigma/analysis/Ancestries.java b/src/cuchaz/enigma/analysis/Ancestries.java deleted file mode 100644 index 97241084..00000000 --- a/src/cuchaz/enigma/analysis/Ancestries.java +++ /dev/null @@ -1,199 +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.analysis; - -import java.io.Serializable; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javassist.bytecode.Descriptor; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; - -public class Ancestries implements Serializable -{ - private static final long serialVersionUID = 738687982126844179L; - - private Map m_superclasses; - private Multimap m_interfaces; - - public Ancestries( ) - { - m_superclasses = Maps.newHashMap(); - m_interfaces = HashMultimap.create(); - } - - public void addSuperclass( String className, String superclassName ) - { - className = Descriptor.toJvmName( className ); - superclassName = Descriptor.toJvmName( superclassName ); - - if( className.equals( superclassName ) ) - { - throw new IllegalArgumentException( "Class cannot be its own superclass! " + className ); - } - - if( !isJre( className ) && !isJre( superclassName ) ) - { - m_superclasses.put( className, superclassName ); - } - } - - public void addInterface( String className, String interfaceName ) - { - className = Descriptor.toJvmName( className ); - interfaceName = Descriptor.toJvmName( interfaceName ); - - if( className.equals( interfaceName ) ) - { - throw new IllegalArgumentException( "Class cannot be its own interface! " + className ); - } - - if( !isJre( className ) && !isJre( interfaceName ) ) - { - m_interfaces.put( className, interfaceName ); - } - } - - public void renameClasses( Map renames ) - { - // rename superclasses - Map newSuperclasses = Maps.newHashMap(); - for( Map.Entry entry : m_superclasses.entrySet() ) - { - String subclass = renames.get( entry.getKey() ); - if( subclass == null ) - { - subclass = entry.getKey(); - } - String superclass = renames.get( entry.getValue() ); - if( superclass == null ) - { - superclass = entry.getValue(); - } - newSuperclasses.put( subclass, superclass ); - } - m_superclasses = newSuperclasses; - - // rename interfaces - Set> entriesToAdd = Sets.newHashSet(); - for( Map.Entry entry : m_interfaces.entries() ) - { - String className = renames.get( entry.getKey() ); - if( className == null ) - { - className = entry.getKey(); - } - String interfaceName = renames.get( entry.getValue() ); - if( interfaceName == null ) - { - interfaceName = entry.getValue(); - } - entriesToAdd.add( new AbstractMap.SimpleEntry( className, interfaceName ) ); - } - m_interfaces.clear(); - for( Map.Entry entry : entriesToAdd ) - { - m_interfaces.put( entry.getKey(), entry.getValue() ); - } - } - - public String getSuperclassName( String className ) - { - return m_superclasses.get( className ); - } - - public List getAncestry( String className ) - { - List ancestors = new ArrayList(); - while( className != null ) - { - className = getSuperclassName( className ); - if( className != null ) - { - ancestors.add( className ); - } - } - return ancestors; - } - - public Set getInterfaces( String className ) - { - Set interfaceNames = new HashSet(); - interfaceNames.addAll( m_interfaces.get( className ) ); - for( String ancestor : getAncestry( className ) ) - { - interfaceNames.addAll( m_interfaces.get( ancestor ) ); - } - return interfaceNames; - } - - public List getSubclasses( String className ) - { - // linear search is fast enough for now - List subclasses = Lists.newArrayList(); - for( Map.Entry entry : m_superclasses.entrySet() ) - { - String subclass = entry.getKey(); - String superclass = entry.getValue(); - if( className.equals( superclass ) ) - { - subclasses.add( subclass ); - } - } - return subclasses; - } - - public Set getImplementingClasses( String targetInterfaceName ) - { - // linear search is fast enough for now - Set classNames = Sets.newHashSet(); - for( Map.Entry entry : m_interfaces.entries() ) - { - String className = entry.getKey(); - String interfaceName = entry.getValue(); - if( interfaceName.equals( targetInterfaceName ) ) - { - classNames.add( className ); - collectSubclasses( classNames, className ); - } - } - return classNames; - } - - public boolean isInterface( String className ) - { - return m_interfaces.containsValue( className ); - } - - private void collectSubclasses( Set classNames, String className ) - { - for( String subclassName : getSubclasses( className ) ) - { - classNames.add( subclassName ); - collectSubclasses( classNames, subclassName ); - } - } - - private boolean isJre( String className ) - { - return className.startsWith( "java/" ) - || className.startsWith( "javax/" ); - } -} diff --git a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java index 98648305..4e9dd523 100644 --- a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java @@ -54,11 +54,11 @@ public class ClassImplementationsTreeNode extends DefaultMutableTreeNode return className; } - public void load( Ancestries ancestries ) + public void load( JarIndex index ) { // get all method implementations List nodes = Lists.newArrayList(); - for( String implementingClassName : ancestries.getImplementingClasses( m_entry.getClassName() ) ) + for( String implementingClassName : index.getImplementingClasses( m_entry.getClassName() ) ) { nodes.add( new ClassImplementationsTreeNode( m_deobfuscatingTranslator, new ClassEntry( implementingClassName ) ) ); } diff --git a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java index 2ed141ff..d3fc9dc8 100644 --- a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java @@ -53,11 +53,11 @@ public class ClassInheritanceTreeNode extends DefaultMutableTreeNode return m_obfClassName; } - public void load( Ancestries ancestries, boolean recurse ) + public void load( TranslationIndex ancestries, boolean recurse ) { // get all the child nodes List nodes = Lists.newArrayList(); - for( String subclassName : ancestries.getSubclasses( m_obfClassName ) ) + for( String subclassName : ancestries.getSubclassNames( m_obfClassName ) ) { nodes.add( new ClassInheritanceTreeNode( m_deobfuscatingTranslator, subclassName ) ); } diff --git a/src/cuchaz/enigma/analysis/DeobfuscatedAncestries.java b/src/cuchaz/enigma/analysis/DeobfuscatedAncestries.java deleted file mode 100644 index b14eca72..00000000 --- a/src/cuchaz/enigma/analysis/DeobfuscatedAncestries.java +++ /dev/null @@ -1,59 +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.analysis; - -import java.util.Map; - -import cuchaz.enigma.mapping.ClassMapping; - -public class DeobfuscatedAncestries extends Ancestries -{ - private static final long serialVersionUID = 8316248774892618324L; - - private Ancestries m_ancestries; - private Map m_classesByObf; - private Map m_classesByDeobf; - - public DeobfuscatedAncestries( Ancestries ancestries, Map classesByObf, Map classesByDeobf ) - { - m_ancestries = ancestries; - m_classesByObf = classesByObf; - m_classesByDeobf = classesByDeobf; - } - - @Override - public String getSuperclassName( String deobfClassName ) - { - // obfuscate the class name - ClassMapping classIndex = m_classesByDeobf.get( deobfClassName ); - if( classIndex == null ) - { - return null; - } - String obfClassName = classIndex.getObfName(); - - // get the superclass - String obfSuperclassName = m_ancestries.getSuperclassName( obfClassName ); - if( obfSuperclassName == null ) - { - return null; - } - - // deobfuscate the superclass name - classIndex = m_classesByObf.get( obfSuperclassName ); - if( classIndex == null ) - { - return null; - } - - return classIndex.getDeobfName(); - } -} diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java new file mode 100644 index 00000000..4b2c0b78 --- /dev/null +++ b/src/cuchaz/enigma/analysis/EntryRenamer.java @@ -0,0 +1,199 @@ +/******************************************************************************* + * 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.analysis; + +import java.util.AbstractMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.beust.jcommander.internal.Lists; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; + +import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; + +public class EntryRenamer +{ + public static void renameClassesInSet( Map renames, Set set ) + { + List entries = Lists.newArrayList(); + for( T val : set ) + { + entries.add( renameClassesInThing( renames, val ) ); + } + set.clear(); + set.addAll( entries ); + } + + public static void renameClassesInMap( Map renames, Map map ) + { + // for each key/value pair... + Set> entriesToAdd = Sets.newHashSet(); + for( Map.Entry entry : map.entrySet() ) + { + entriesToAdd.add( new AbstractMap.SimpleEntry( + renameClassesInThing( renames, entry.getKey() ), + renameClassesInThing( renames, entry.getValue() ) + ) ); + } + map.clear(); + for( Map.Entry entry : entriesToAdd ) + { + map.put( entry.getKey(), entry.getValue() ); + } + } + + public static void renameClassesInMultimap( Map renames, Multimap map ) + { + // for each key/value pair... + Set> entriesToAdd = Sets.newHashSet(); + for( Map.Entry entry : map.entries() ) + { + entriesToAdd.add( new AbstractMap.SimpleEntry( + renameClassesInThing( renames, entry.getKey() ), + renameClassesInThing( renames, entry.getValue() ) + ) ); + } + map.clear(); + for( Map.Entry entry : entriesToAdd ) + { + map.put( entry.getKey(), entry.getValue() ); + } + } + + public static void renameMethodsInMultimap( Map renames, Multimap map ) + { + // for each key/value pair... + Set> entriesToAdd = Sets.newHashSet(); + Iterator> iter = map.entries().iterator(); + while( iter.hasNext() ) + { + Map.Entry entry = iter.next(); + iter.remove(); + entriesToAdd.add( new AbstractMap.SimpleEntry( + renameMethodsInThing( renames, entry.getKey() ), + renameMethodsInThing( renames, entry.getValue() ) + ) ); + } + for( Map.Entry entry : entriesToAdd ) + { + map.put( entry.getKey(), entry.getValue() ); + } + } + + @SuppressWarnings( "unchecked" ) + public static T renameMethodsInThing( Map renames, T thing ) + { + if( thing instanceof MethodEntry ) + { + MethodEntry methodEntry = (MethodEntry)thing; + MethodEntry newMethodEntry = renames.get( methodEntry ); + if( newMethodEntry != null ) + { + return (T)new MethodEntry( + methodEntry.getClassEntry(), + newMethodEntry.getName(), + methodEntry.getSignature() + ); + } + return thing; + } + else if( thing instanceof ArgumentEntry ) + { + ArgumentEntry argumentEntry = (ArgumentEntry)thing; + return (T)new ArgumentEntry( + renameMethodsInThing( renames, argumentEntry.getMethodEntry() ), + argumentEntry.getIndex(), + argumentEntry.getName() + ); + } + else if( thing instanceof EntryReference ) + { + EntryReference reference = (EntryReference)thing; + reference.entry = renameMethodsInThing( renames, reference.entry ); + reference.context = renameMethodsInThing( renames, reference.context ); + return thing; + } + return thing; + } + + @SuppressWarnings( "unchecked" ) + public static T renameClassesInThing( Map renames, T thing ) + { + if( thing instanceof String ) + { + String stringEntry = (String)thing; + if( renames.containsKey( stringEntry ) ) + { + return (T)renames.get( stringEntry ); + } + } + else if( thing instanceof ClassEntry ) + { + ClassEntry classEntry = (ClassEntry)thing; + return (T)new ClassEntry( renameClassesInThing( renames, classEntry.getClassName() ) ); + } + else if( thing instanceof FieldEntry ) + { + FieldEntry fieldEntry = (FieldEntry)thing; + return (T)new FieldEntry( + renameClassesInThing( renames, fieldEntry.getClassEntry() ), + fieldEntry.getName() + ); + } + else if( thing instanceof ConstructorEntry ) + { + ConstructorEntry constructorEntry = (ConstructorEntry)thing; + return (T)new ConstructorEntry( + renameClassesInThing( renames, constructorEntry.getClassEntry() ), + constructorEntry.getSignature() + ); + } + else if( thing instanceof MethodEntry ) + { + MethodEntry methodEntry = (MethodEntry)thing; + return (T)new MethodEntry( + renameClassesInThing( renames, methodEntry.getClassEntry() ), + methodEntry.getName(), + methodEntry.getSignature() + ); + } + else if( thing instanceof ArgumentEntry ) + { + ArgumentEntry argumentEntry = (ArgumentEntry)thing; + return (T)new ArgumentEntry( + renameClassesInThing( renames, argumentEntry.getMethodEntry() ), + argumentEntry.getIndex(), + argumentEntry.getName() + ); + } + else if( thing instanceof EntryReference ) + { + EntryReference reference = (EntryReference)thing; + reference.entry = renameClassesInThing( renames, reference.entry ); + reference.context = renameClassesInThing( renames, reference.context ); + return thing; + } + else + { + throw new Error( "Not an entry: " + thing ); + } + + return thing; + } +} diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index e7c92bea..a8ac0013 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -11,9 +11,8 @@ package cuchaz.enigma.analysis; import java.lang.reflect.Modifier; -import java.util.AbstractMap; import java.util.Collection; -import java.util.Iterator; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -43,7 +42,6 @@ import com.google.common.collect.Sets; import cuchaz.enigma.Constants; import cuchaz.enigma.bytecode.ClassRenamer; -import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; @@ -55,7 +53,8 @@ import cuchaz.enigma.mapping.Translator; public class JarIndex { private Set m_obfClassEntries; - private Ancestries m_ancestries; + private TranslationIndex m_translationIndex; + private Multimap m_interfaces; private Map m_access; private Multimap m_methodImplementations; private Multimap> m_behaviorReferences; @@ -68,7 +67,8 @@ public class JarIndex public JarIndex( ) { m_obfClassEntries = Sets.newHashSet(); - m_ancestries = new Ancestries(); + m_translationIndex = new TranslationIndex(); + m_interfaces = HashMultimap.create(); m_access = Maps.newHashMap(); m_methodImplementations = HashMultimap.create(); m_behaviorReferences = HashMultimap.create(); @@ -109,15 +109,25 @@ public class JarIndex } } - // step 3: index the types, methods + // step 3: index extends, implements, fields, and methods for( CtClass c : JarClassIterator.classes( jar ) ) { ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); String className = Descriptor.toJvmName( c.getName() ); - m_ancestries.addSuperclass( className, Descriptor.toJvmName( c.getClassFile().getSuperclass() ) ); + m_translationIndex.addSuperclass( className, Descriptor.toJvmName( c.getClassFile().getSuperclass() ) ); for( String interfaceName : c.getClassFile().getInterfaces() ) { - m_ancestries.addInterface( className, Descriptor.toJvmName( interfaceName ) ); + className = Descriptor.toJvmName( className ); + interfaceName = Descriptor.toJvmName( interfaceName ); + if( className.equals( interfaceName ) ) + { + throw new IllegalArgumentException( "Class cannot be its own interface! " + className ); + } + m_interfaces.put( className, interfaceName ); + } + for( CtField field : c.getDeclaredFields() ) + { + indexField( field ); } for( CtBehavior behavior : c.getDeclaredBehaviors() ) { @@ -159,11 +169,24 @@ public class JarIndex { renames.put( entry.getKey(), entry.getValue() + "$" + new ClassEntry( entry.getKey() ).getSimpleName() ); } - renameClasses( renames ); + EntryRenamer.renameClassesInSet( renames, m_obfClassEntries ); + m_translationIndex.renameClasses( renames ); + EntryRenamer.renameClassesInMultimap( renames, m_interfaces ); + EntryRenamer.renameClassesInMultimap( renames, m_methodImplementations ); + EntryRenamer.renameClassesInMultimap( renames, m_behaviorReferences ); + EntryRenamer.renameClassesInMultimap( renames, m_fieldReferences ); } - // step 5: update other indices with bridge method info - renameMethods( m_bridgeMethods ); + // step 6: update other indices with bridge method info + EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_methodImplementations ); + EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_behaviorReferences ); + EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences ); + } + + private void indexField( CtField field ) + { + String className = Descriptor.toJvmName( field.getDeclaringClass().getName() ); + m_translationIndex.addField( className, field.getName() ); } private void indexBehavior( CtBehavior behavior ) @@ -528,9 +551,9 @@ public class JarIndex return m_obfClassEntries; } - public Ancestries getAncestries( ) + public TranslationIndex getTranslationIndex( ) { - return m_ancestries; + return m_translationIndex; } public Access getAccess( Entry entry ) @@ -553,11 +576,11 @@ public class JarIndex // get the root node List ancestry = Lists.newArrayList(); ancestry.add( obfClassEntry.getName() ); - ancestry.addAll( m_ancestries.getAncestry( obfClassEntry.getName() ) ); + ancestry.addAll( m_translationIndex.getAncestry( obfClassEntry.getName() ) ); ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) ); // expand all children recursively - rootNode.load( m_ancestries, true ); + rootNode.load( m_translationIndex, true ); return rootNode; } @@ -565,7 +588,7 @@ public class JarIndex public ClassImplementationsTreeNode getClassImplementations( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) { ClassImplementationsTreeNode node = new ClassImplementationsTreeNode( deobfuscatingTranslator, obfClassEntry ); - node.load( m_ancestries ); + node.load( this ); return node; } @@ -573,7 +596,7 @@ public class JarIndex { // travel to the ancestor implementation String baseImplementationClassName = obfMethodEntry.getClassName(); - for( String ancestorClassName : m_ancestries.getAncestry( obfMethodEntry.getClassName() ) ) + for( String ancestorClassName : m_translationIndex.getAncestry( obfMethodEntry.getClassName() ) ) { MethodEntry ancestorMethodEntry = new MethodEntry( new ClassEntry( ancestorClassName ), @@ -609,7 +632,7 @@ public class JarIndex MethodEntry interfaceMethodEntry; // is this method on an interface? - if( m_ancestries.isInterface( obfMethodEntry.getClassName() ) ) + if( isInterface( obfMethodEntry.getClassName() ) ) { interfaceMethodEntry = obfMethodEntry; } @@ -617,7 +640,7 @@ public class JarIndex { // get the interface class List methodInterfaces = Lists.newArrayList(); - for( String interfaceName : m_ancestries.getInterfaces( obfMethodEntry.getClassName() ) ) + for( String interfaceName : getInterfaces( obfMethodEntry.getClassName() ) ) { // is this method defined in this interface? MethodEntry methodInterface = new MethodEntry( @@ -717,181 +740,44 @@ public class JarIndex return m_anonymousClasses.contains( obfInnerClassName ); } - public MethodEntry getBridgeMethod( MethodEntry methodEntry ) - { - return m_bridgeMethods.get( methodEntry ); - } - - private void renameClasses( Map renames ) + public Set getInterfaces( String className ) { - // rename class entries - Set obfClassEntries = Sets.newHashSet(); - for( ClassEntry classEntry : m_obfClassEntries ) + Set interfaceNames = new HashSet(); + interfaceNames.addAll( m_interfaces.get( className ) ); + for( String ancestor : m_translationIndex.getAncestry( className ) ) { - if( renames.containsKey( classEntry.getName() ) ) - { - obfClassEntries.add( new ClassEntry( renames.get( classEntry.getName() ) ) ); - } - else - { - obfClassEntries.add( classEntry ); - } + interfaceNames.addAll( m_interfaces.get( ancestor ) ); } - m_obfClassEntries = obfClassEntries; - - // rename others - m_ancestries.renameClasses( renames ); - renameClassesInMultimap( renames, m_methodImplementations ); - renameClassesInMultimap( renames, m_behaviorReferences ); - renameClassesInMultimap( renames, m_fieldReferences ); + return interfaceNames; } - private void renameMethods( Map renames ) + public Set getImplementingClasses( String targetInterfaceName ) { - renameMethodsInMultimap( renames, m_methodImplementations ); - renameMethodsInMultimap( renames, m_behaviorReferences ); - renameMethodsInMultimap( renames, m_fieldReferences ); - } - - private void renameClassesInMultimap( Map renames, Multimap map ) - { - // for each key/value pair... - Set> entriesToAdd = Sets.newHashSet(); - for( Map.Entry entry : map.entries() ) + // linear search is fast enough for now + Set classNames = Sets.newHashSet(); + for( Map.Entry entry : m_interfaces.entries() ) { - entriesToAdd.add( new AbstractMap.SimpleEntry( - renameClassesInThing( renames, entry.getKey() ), - renameClassesInThing( renames, entry.getValue() ) - ) ); - } - map.clear(); - for( Map.Entry entry : entriesToAdd ) - { - map.put( entry.getKey(), entry.getValue() ); - } - } - - @SuppressWarnings( "unchecked" ) - private T renameClassesInThing( Map renames, T thing ) - { - if( thing instanceof String ) - { - String stringEntry = (String)thing; - if( renames.containsKey( stringEntry ) ) + String className = entry.getKey(); + String interfaceName = entry.getValue(); + if( interfaceName.equals( targetInterfaceName ) ) { - return (T)renames.get( stringEntry ); + classNames.add( className ); + m_translationIndex.getSubclassNamesRecursively( classNames, className ); } } - else if( thing instanceof ClassEntry ) - { - ClassEntry classEntry = (ClassEntry)thing; - return (T)new ClassEntry( renameClassesInThing( renames, classEntry.getClassName() ) ); - } - else if( thing instanceof FieldEntry ) - { - FieldEntry fieldEntry = (FieldEntry)thing; - return (T)new FieldEntry( - renameClassesInThing( renames, fieldEntry.getClassEntry() ), - fieldEntry.getName() - ); - } - else if( thing instanceof ConstructorEntry ) - { - ConstructorEntry constructorEntry = (ConstructorEntry)thing; - return (T)new ConstructorEntry( - renameClassesInThing( renames, constructorEntry.getClassEntry() ), - constructorEntry.getSignature() - ); - } - else if( thing instanceof MethodEntry ) - { - MethodEntry methodEntry = (MethodEntry)thing; - return (T)new MethodEntry( - renameClassesInThing( renames, methodEntry.getClassEntry() ), - methodEntry.getName(), - methodEntry.getSignature() - ); - } - else if( thing instanceof ArgumentEntry ) - { - ArgumentEntry argumentEntry = (ArgumentEntry)thing; - return (T)new ArgumentEntry( - renameClassesInThing( renames, argumentEntry.getMethodEntry() ), - argumentEntry.getIndex(), - argumentEntry.getName() - ); - } - else if( thing instanceof EntryReference ) - { - EntryReference reference = (EntryReference)thing; - reference.entry = renameClassesInThing( renames, reference.entry ); - reference.context = renameClassesInThing( renames, reference.context ); - return thing; - } - else - { - throw new Error( "Not an entry: " + thing ); - } - - return thing; + return classNames; } - private void renameMethodsInMultimap( Map renames, Multimap map ) + public boolean isInterface( String className ) { - // for each key/value pair... - Set> entriesToAdd = Sets.newHashSet(); - Iterator> iter = map.entries().iterator(); - while( iter.hasNext() ) - { - Map.Entry entry = iter.next(); - iter.remove(); - entriesToAdd.add( new AbstractMap.SimpleEntry( - renameMethodsInThing( renames, entry.getKey() ), - renameMethodsInThing( renames, entry.getValue() ) - ) ); - } - for( Map.Entry entry : entriesToAdd ) - { - map.put( entry.getKey(), entry.getValue() ); - } + return m_interfaces.containsValue( className ); } - @SuppressWarnings( "unchecked" ) - private T renameMethodsInThing( Map renames, T thing ) + public MethodEntry getBridgeMethod( MethodEntry methodEntry ) { - if( thing instanceof MethodEntry ) - { - MethodEntry methodEntry = (MethodEntry)thing; - MethodEntry newMethodEntry = renames.get( methodEntry ); - if( newMethodEntry != null ) - { - return (T)new MethodEntry( - methodEntry.getClassEntry(), - newMethodEntry.getName(), - methodEntry.getSignature() - ); - } - return thing; - } - else if( thing instanceof ArgumentEntry ) - { - ArgumentEntry argumentEntry = (ArgumentEntry)thing; - return (T)new ArgumentEntry( - renameMethodsInThing( renames, argumentEntry.getMethodEntry() ), - argumentEntry.getIndex(), - argumentEntry.getName() - ); - } - else if( thing instanceof EntryReference ) - { - EntryReference reference = (EntryReference)thing; - reference.entry = renameMethodsInThing( renames, reference.entry ); - reference.context = renameMethodsInThing( renames, reference.context ); - return thing; - } - return thing; + return m_bridgeMethods.get( methodEntry ); } - + public boolean containsObfClass( ClassEntry obfClassEntry ) { return m_obfClassEntries.contains( obfClassEntry ); diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java index b7434e84..8b9dd2d8 100644 --- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java @@ -74,7 +74,7 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { // get all method implementations List nodes = Lists.newArrayList(); - for( String implementingClassName : index.getAncestries().getImplementingClasses( m_entry.getClassName() ) ) + for( String implementingClassName : index.getImplementingClasses( m_entry.getClassName() ) ) { MethodEntry methodEntry = new MethodEntry( new ClassEntry( implementingClassName ), diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index 73f9714c..d77fd858 100644 --- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java @@ -83,7 +83,7 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { // get all the child nodes List nodes = Lists.newArrayList(); - for( String subclassName : index.getAncestries().getSubclasses( m_entry.getClassName() ) ) + for( String subclassName : index.getTranslationIndex().getSubclassNames( m_entry.getClassName() ) ) { MethodEntry methodEntry = new MethodEntry( new ClassEntry( subclassName ), diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java new file mode 100644 index 00000000..5311ec70 --- /dev/null +++ b/src/cuchaz/enigma/analysis/TranslationIndex.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * 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.analysis; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javassist.bytecode.Descriptor; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; + +public class TranslationIndex implements Serializable +{ + private static final long serialVersionUID = 738687982126844179L; + + private Map m_superclasses; + private Multimap m_fields; + + public TranslationIndex( ) + { + m_superclasses = Maps.newHashMap(); + m_fields = HashMultimap.create(); + } + + public TranslationIndex( TranslationIndex other ) + { + m_superclasses = Maps.newHashMap( other.m_superclasses ); + m_fields = HashMultimap.create( other.m_fields ); + } + + public void addSuperclass( String className, String superclassName ) + { + className = Descriptor.toJvmName( className ); + superclassName = Descriptor.toJvmName( superclassName ); + + if( className.equals( superclassName ) ) + { + throw new IllegalArgumentException( "Class cannot be its own superclass! " + className ); + } + + if( !isJre( className ) && !isJre( superclassName ) ) + { + m_superclasses.put( className, superclassName ); + } + } + + public void addField( String className, String fieldName ) + { + m_fields.put( className, fieldName ); + } + + public void renameClasses( Map renames ) + { + EntryRenamer.renameClassesInMap( renames, m_superclasses ); + EntryRenamer.renameClassesInMultimap( renames, m_fields ); + } + + public String getSuperclassName( String className ) + { + return m_superclasses.get( className ); + } + + public List getAncestry( String className ) + { + List ancestors = new ArrayList(); + while( className != null ) + { + className = getSuperclassName( className ); + if( className != null ) + { + ancestors.add( className ); + } + } + return ancestors; + } + + public List getSubclassNames( String className ) + { + // linear search is fast enough for now + List subclasses = Lists.newArrayList(); + for( Map.Entry entry : m_superclasses.entrySet() ) + { + String subclass = entry.getKey(); + String superclass = entry.getValue(); + if( className.equals( superclass ) ) + { + subclasses.add( subclass ); + } + } + return subclasses; + } + + public void getSubclassNamesRecursively( Set out, String className ) + { + for( String subclassName : getSubclassNames( className ) ) + { + out.add( subclassName ); + getSubclassNamesRecursively( out, subclassName ); + } + } + + public boolean containsField( String className, String fieldName ) + { + return m_fields.containsEntry( className, fieldName ); + } + + private boolean isJre( String className ) + { + return className.startsWith( "java/" ) + || className.startsWith( "javax/" ); + } +} diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 378d4c0a..f52094fd 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -24,8 +24,7 @@ import com.beust.jcommander.internal.Sets; import com.google.common.collect.Maps; import cuchaz.enigma.Util; -import cuchaz.enigma.analysis.Ancestries; -import cuchaz.enigma.analysis.DeobfuscatedAncestries; +import cuchaz.enigma.analysis.TranslationIndex; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class Mappings implements Serializable @@ -108,12 +107,27 @@ public class Mappings implements Serializable return m_classesByDeobf.get( deobfName ); } - public Translator getTranslator( Ancestries ancestries, TranslationDirection direction ) + public Translator getTranslator( TranslationIndex index, TranslationDirection direction ) { + if( direction == TranslationDirection.Obfuscating ) + { + // deobfuscate the index + index = new TranslationIndex( index ); + Map renames = Maps.newHashMap(); + for( ClassMapping classMapping : classes() ) + { + renames.put( classMapping.getObfName(), classMapping.getDeobfName() ); + for( ClassMapping innerClassMapping : classMapping.innerClasses() ) + { + renames.put( innerClassMapping.getObfName(), innerClassMapping.getDeobfName() ); + } + } + index.renameClasses( renames ); + } return new Translator( direction, direction.choose( m_classesByObf, m_classesByDeobf ), - direction.choose( ancestries, new DeobfuscatedAncestries( ancestries, m_classesByObf, m_classesByDeobf ) ) + index ); } diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java new file mode 100644 index 00000000..9d036d8f --- /dev/null +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -0,0 +1,164 @@ +/******************************************************************************* + * 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.Set; +import java.util.zip.GZIPOutputStream; + +import cuchaz.enigma.analysis.JarIndex; + +public class MappingsRenamer +{ + private JarIndex m_index; + private Mappings m_mappings; + + public MappingsRenamer( JarIndex index, Mappings mappings ) + { + m_index = index; + m_mappings = mappings; + } + + public void setClassName( ClassEntry obf, String deobfName ) + { + deobfName = NameValidator.validateClassName( deobfName ); + ClassEntry targetEntry = new ClassEntry( deobfName ); + if( m_mappings.containsDeobfClass( deobfName ) || m_index.containsObfClass( targetEntry ) ) + { + throw new IllegalNameException( deobfName, "There is already a class with that name" ); + } + + ClassMapping classMapping = getOrCreateClassMapping( obf ); + + if( obf.isInnerClass() ) + { + classMapping.setInnerClassName( obf.getInnerClassName(), deobfName ); + } + else + { + m_mappings.m_classesByDeobf.remove( classMapping.getDeobfName() ); + classMapping.setDeobfName( deobfName ); + m_mappings.m_classesByDeobf.put( deobfName, classMapping ); + } + + updateDeobfMethodSignatures(); + } + + public void setFieldName( FieldEntry obf, String deobfName ) + { + deobfName = NameValidator.validateFieldName( deobfName ); + FieldEntry targetEntry = new FieldEntry( obf.getClassEntry(), deobfName ); + if( m_mappings.containsDeobfField( obf.getClassEntry(), deobfName ) || m_index.containsObfField( targetEntry ) ) + { + throw new IllegalNameException( deobfName, "There is already a field with that name" ); + } + + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); + classMapping.setFieldName( obf.getName(), deobfName ); + } + + public void setMethodTreeName( MethodEntry obf, String deobfName ) + { + Set implementations = m_index.getRelatedMethodImplementations( obf ); + + deobfName = NameValidator.validateMethodName( deobfName ); + for( MethodEntry entry : implementations ) + { + MethodEntry targetEntry = new MethodEntry( entry.getClassEntry(), deobfName, entry.getSignature() ); + if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) + { + String deobfClassName = getTranslator( TranslationDirection.Deobfuscating ).translateClass( entry.getClassName() ); + throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName ); + } + } + + for( MethodEntry entry : implementations ) + { + setMethodName( entry, deobfName ); + } + } + + public void setMethodName( MethodEntry obf, String deobfName ) + { + deobfName = NameValidator.validateMethodName( deobfName ); + MethodEntry targetEntry = new MethodEntry( obf.getClassEntry(), deobfName, obf.getSignature() ); + if( m_mappings.containsDeobfMethod( obf.getClassEntry(), deobfName, obf.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) + { + String deobfClassName = getTranslator( TranslationDirection.Deobfuscating ).translateClass( obf.getClassName() ); + throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName ); + } + + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); + String deobfSignature = getTranslator( TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); + classMapping.setMethodNameAndSignature( obf.getName(), obf.getSignature(), deobfName, deobfSignature ); + } + + public void setArgumentName( ArgumentEntry obf, String deobfName ) + { + deobfName = NameValidator.validateArgumentName( deobfName ); + // NOTE: don't need to check arguments for name collisions with names determined by Procyon + if( m_mappings.containsArgument( obf.getMethodEntry(), deobfName ) ) + { + throw new IllegalNameException( deobfName, "There is already an argument with that name" ); + } + + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); + classMapping.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), 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 getOrCreateClassMapping( ClassEntry obfClassEntry ) + { + String obfClassName = obfClassEntry.getOuterClassName(); + ClassMapping classMapping = m_mappings.m_classesByObf.get( obfClassName ); + if( classMapping == null ) + { + classMapping = new ClassMapping( obfClassName, obfClassName ); + m_mappings.m_classesByObf.put( classMapping.getObfName(), classMapping ); + m_mappings.m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ); + } + return classMapping; + } + + private ClassMapping getOrCreateClassMappingOrInnerClassMapping( ClassEntry obfClassEntry ) + { + ClassMapping classMapping = getOrCreateClassMapping( obfClassEntry ); + if( obfClassEntry.isInnerClass() ) + { + classMapping = classMapping.getOrCreateInnerClass( obfClassEntry.getInnerClassName() ); + } + return classMapping; + } + + private void updateDeobfMethodSignatures( ) + { + for( ClassMapping classMapping : m_mappings.m_classesByObf.values() ) + { + classMapping.updateDeobfMethodSignatures( getTranslator( TranslationDirection.Deobfuscating ) ); + } + } + + private Translator getTranslator( TranslationDirection direction ) + { + return m_mappings.getTranslator( m_index.getTranslationIndex(), direction ); + } +} diff --git a/src/cuchaz/enigma/mapping/Renamer.java b/src/cuchaz/enigma/mapping/Renamer.java deleted file mode 100644 index 15d9af4d..00000000 --- a/src/cuchaz/enigma/mapping/Renamer.java +++ /dev/null @@ -1,160 +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.ObjectOutputStream; -import java.io.OutputStream; -import java.util.Set; -import java.util.zip.GZIPOutputStream; - -import cuchaz.enigma.analysis.JarIndex; - -public class Renamer -{ - private JarIndex m_index; - private Mappings m_mappings; - - public Renamer( JarIndex index, Mappings mappings ) - { - m_index = index; - m_mappings = mappings; - } - - public void setClassName( ClassEntry obf, String deobfName ) - { - deobfName = NameValidator.validateClassName( deobfName ); - ClassEntry targetEntry = new ClassEntry( deobfName ); - if( m_mappings.containsDeobfClass( deobfName ) || m_index.containsObfClass( targetEntry ) ) - { - throw new IllegalNameException( deobfName, "There is already a class with that name" ); - } - - ClassMapping classMapping = getOrCreateClassMapping( obf ); - - if( obf.isInnerClass() ) - { - classMapping.setInnerClassName( obf.getInnerClassName(), deobfName ); - } - else - { - m_mappings.m_classesByDeobf.remove( classMapping.getDeobfName() ); - classMapping.setDeobfName( deobfName ); - m_mappings.m_classesByDeobf.put( deobfName, classMapping ); - } - - updateDeobfMethodSignatures(); - } - - public void setFieldName( FieldEntry obf, String deobfName ) - { - deobfName = NameValidator.validateFieldName( deobfName ); - FieldEntry targetEntry = new FieldEntry( obf.getClassEntry(), deobfName ); - if( m_mappings.containsDeobfField( obf.getClassEntry(), deobfName ) || m_index.containsObfField( targetEntry ) ) - { - throw new IllegalNameException( deobfName, "There is already a field with that name" ); - } - - ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); - classMapping.setFieldName( obf.getName(), deobfName ); - } - - public void setMethodTreeName( MethodEntry obf, String deobfName ) - { - Set implementations = m_index.getRelatedMethodImplementations( obf ); - - deobfName = NameValidator.validateMethodName( deobfName ); - for( MethodEntry entry : implementations ) - { - MethodEntry targetEntry = new MethodEntry( entry.getClassEntry(), deobfName, entry.getSignature() ); - if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) - { - String className = m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ).translateClass( entry.getClassName() ); - throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + className ); - } - } - - for( MethodEntry entry : implementations ) - { - setMethodName( entry, deobfName ); - } - } - - public void setMethodName( MethodEntry obf, String deobfName ) - { - deobfName = NameValidator.validateMethodName( deobfName ); - MethodEntry targetEntry = new MethodEntry( obf.getClassEntry(), deobfName, obf.getSignature() ); - if( m_mappings.containsDeobfMethod( obf.getClassEntry(), deobfName, obf.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) - { - String className = m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ).translateClass( obf.getClassName() ); - throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + className ); - } - - ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); - String deobfSignature = m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); - classMapping.setMethodNameAndSignature( obf.getName(), obf.getSignature(), deobfName, deobfSignature ); - } - - public void setArgumentName( ArgumentEntry obf, String deobfName ) - { - deobfName = NameValidator.validateArgumentName( deobfName ); - // NOTE: don't need to check arguments for name collisions with names determined by Procyon - if( m_mappings.containsArgument( obf.getMethodEntry(), deobfName ) ) - { - throw new IllegalNameException( deobfName, "There is already an argument with that name" ); - } - - ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); - classMapping.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), 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 getOrCreateClassMapping( ClassEntry obfClassEntry ) - { - String obfClassName = obfClassEntry.getOuterClassName(); - ClassMapping classMapping = m_mappings.m_classesByObf.get( obfClassName ); - if( classMapping == null ) - { - classMapping = new ClassMapping( obfClassName, obfClassName ); - m_mappings.m_classesByObf.put( classMapping.getObfName(), classMapping ); - m_mappings.m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ); - } - return classMapping; - } - - private ClassMapping getOrCreateClassMappingOrInnerClassMapping( ClassEntry obfClassEntry ) - { - ClassMapping classMapping = getOrCreateClassMapping( obfClassEntry ); - if( obfClassEntry.isInnerClass() ) - { - classMapping = classMapping.getOrCreateInnerClass( obfClassEntry.getInnerClassName() ); - } - return classMapping; - } - - private void updateDeobfMethodSignatures( ) - { - Translator translator = m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ); - for( ClassMapping classMapping : m_mappings.m_classesByObf.values() ) - { - classMapping.updateDeobfMethodSignatures( translator ); - } - } -} diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index 23bf0951..f5aafdd1 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -16,27 +16,27 @@ import java.util.Map; import com.beust.jcommander.internal.Maps; -import cuchaz.enigma.analysis.Ancestries; +import cuchaz.enigma.analysis.TranslationIndex; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class Translator { private TranslationDirection m_direction; - public Map m_classes; - private Ancestries m_ancestries; + private Map m_classes; + private TranslationIndex m_index; public Translator( ) { m_direction = null; m_classes = Maps.newHashMap(); - m_ancestries = new Ancestries(); + m_index = new TranslationIndex(); } - protected Translator( TranslationDirection direction, Map classes, Ancestries ancestries ) + public Translator( TranslationDirection direction, Map classes, TranslationIndex index ) { m_direction = direction; m_classes = classes; - m_ancestries = ancestries; + m_index = index; } @SuppressWarnings( "unchecked" ) @@ -145,6 +145,13 @@ public class Translator return translatedName; } } + + // is the field implemented in this class? + if( m_index.containsField( className, in.getName() ) ) + { + // stop traversing the superclass chain + break; + } } return null; } @@ -291,7 +298,7 @@ public class Translator { List ancestry = new ArrayList(); ancestry.add( className ); - ancestry.addAll( m_ancestries.getAncestry( className ) ); + ancestry.addAll( m_index.getAncestry( className ) ); return ancestry; } -- cgit v1.2.3 From ddcbdd2a18cca1d3ad05ab8d20eacf98ba035874 Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 2 Sep 2014 00:34:57 -0400 Subject: fixed bug with export progress bar --- src/cuchaz/enigma/Deobfuscator.java | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 0356f923..d15c25f9 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -16,10 +16,12 @@ import java.io.IOException; import java.io.StringWriter; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.jar.JarFile; import javassist.bytecode.Descriptor; +import com.beust.jcommander.internal.Sets; import com.google.common.collect.Maps; import com.strobel.assembler.metadata.MetadataSystem; import com.strobel.assembler.metadata.TypeDefinition; @@ -42,9 +44,9 @@ import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.Mappings; +import cuchaz.enigma.mapping.MappingsRenamer; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.MethodMapping; -import cuchaz.enigma.mapping.MappingsRenamer; import cuchaz.enigma.mapping.TranslationDirection; import cuchaz.enigma.mapping.Translator; @@ -246,18 +248,12 @@ public class Deobfuscator public void writeSources( File dirOut, ProgressListener progress ) throws IOException { - int numClasses = m_jarIndex.getObfClassEntries().size(); - if( progress != null ) - { - progress.init( numClasses ); - } - int i = 0; - - // DEOBFUSCATE ALL THE THINGS!! @_@ + // get the classes to decompile + Set classEntries = Sets.newHashSet(); for( ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries() ) { // skip inner classes - if( m_jarIndex.getOuterClass( obfClassEntry.getName() ) != null ) + if( obfClassEntry.isInnerClass() ) { continue; } @@ -268,6 +264,18 @@ public class Deobfuscator continue; } + classEntries.add( obfClassEntry ); + } + + if( progress != null ) + { + progress.init( classEntries.size() ); + } + + // DEOBFUSCATE ALL THE THINGS!! @_@ + int i = 0; + for( ClassEntry obfClassEntry : classEntries ) + { ClassEntry deobfClassEntry = deobfuscateEntry( new ClassEntry( obfClassEntry ) ); if( progress != null ) { @@ -287,7 +295,7 @@ public class Deobfuscator } // done! - progress.onProgress( numClasses, "Done!" ); + progress.onProgress( classEntries.size(), "Done!" ); } public T obfuscateEntry( T deobfEntry ) -- cgit v1.2.3 From b5338883d271779c335842c07047d60136316167 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 3 Sep 2014 00:20:36 -0400 Subject: big refactor to better model class/method mappings with no deobf name --- src/cuchaz/enigma/Deobfuscator.java | 2 +- src/cuchaz/enigma/gui/GuiController.java | 2 + src/cuchaz/enigma/mapping/ClassMapping.java | 111 +++++++++++------- src/cuchaz/enigma/mapping/Mappings.java | 90 +++++++++----- src/cuchaz/enigma/mapping/MappingsReader.java | 155 ++++++++++++++----------- src/cuchaz/enigma/mapping/MappingsRenamer.java | 14 ++- src/cuchaz/enigma/mapping/MappingsWriter.java | 29 ++++- src/cuchaz/enigma/mapping/MethodMapping.java | 16 ++- src/cuchaz/enigma/mapping/NameValidator.java | 12 +- 9 files changed, 276 insertions(+), 155 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index d15c25f9..526534da 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -192,7 +192,7 @@ public class Deobfuscator // 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 ClassMapping classMapping = m_mappings.getClassByObf( className ); - if( classMapping != null ) + if( classMapping != null && classMapping.getDeobfName() != null ) { className = classMapping.getDeobfName(); } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index c0fb2e40..5057db2d 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -167,6 +167,8 @@ public class GuiController public boolean entryHasMapping( Entry deobfEntry ) { + // TEMP + System.out.println( deobfEntry + " -> " + m_deobfuscator.obfuscateEntry( deobfEntry ) ); return m_deobfuscator.hasMapping( m_deobfuscator.obfuscateEntry( deobfEntry ) ); } diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index 5faaf2a1..bce16cc5 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -29,7 +29,11 @@ public class ClassMapping implements Serializable, Comparable private Map m_methodsByObf; private Map m_methodsByDeobf; - // NOTE: this argument order is important for the MethodReader/MethodWriter + public ClassMapping( String obfName ) + { + this( obfName, null ); + } + public ClassMapping( String obfName, String deobfName ) { m_obfName = obfName; @@ -60,14 +64,19 @@ public class ClassMapping implements Serializable, Comparable public Iterable innerClasses( ) { - assert( m_innerClassesByObf.size() == m_innerClassesByDeobf.size() ); + assert( m_innerClassesByObf.size() >= m_innerClassesByDeobf.size() ); return m_innerClassesByObf.values(); } - protected void addInnerClassMapping( ClassMapping classMapping ) + public void addInnerClassMapping( ClassMapping classMapping ) { - m_innerClassesByObf.put( classMapping.getObfName(), classMapping ); - m_innerClassesByDeobf.put( classMapping.getDeobfName(), classMapping ); + boolean obfWasAdded = m_innerClassesByObf.put( classMapping.getObfName(), classMapping ) == null; + assert( obfWasAdded ); + if( classMapping.getDeobfName() != null ) + { + boolean deobfWasAdded = m_innerClassesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null; + assert( deobfWasAdded ); + } } public ClassMapping getOrCreateInnerClass( String obfName ) @@ -75,9 +84,9 @@ public class ClassMapping implements Serializable, Comparable ClassMapping classMapping = m_innerClassesByObf.get( obfName ); if( classMapping == null ) { - classMapping = new ClassMapping( obfName, obfName ); - m_innerClassesByObf.put( obfName, classMapping ); - m_innerClassesByDeobf.put( obfName, classMapping ); + classMapping = new ClassMapping( obfName ); + boolean wasAdded = m_innerClassesByObf.put( obfName, classMapping ) == null; + assert( wasAdded ); } return classMapping; } @@ -115,9 +124,11 @@ public class ClassMapping implements Serializable, Comparable public void setInnerClassName( String obfName, String deobfName ) { ClassMapping classMapping = getOrCreateInnerClass( obfName ); - m_innerClassesByDeobf.remove( classMapping.getDeobfName() ); + boolean wasRemoved = m_innerClassesByDeobf.remove( classMapping.getDeobfName() ) != null; + assert( wasRemoved ); classMapping.setDeobfName( deobfName ); - m_innerClassesByDeobf.put( deobfName, classMapping ); + boolean wasAdded = m_innerClassesByDeobf.put( deobfName, classMapping ) == null; + assert( wasAdded ); } //// FIELDS //////// @@ -128,7 +139,7 @@ public class ClassMapping implements Serializable, Comparable return m_fieldsByObf.values(); } - protected void addFieldMapping( FieldMapping fieldMapping ) + public void addFieldMapping( FieldMapping fieldMapping ) { if( m_fieldsByObf.containsKey( fieldMapping.getObfName() ) ) { @@ -138,8 +149,10 @@ public class ClassMapping implements Serializable, Comparable { throw new Error( "Already have mapping for " + m_deobfName + "." + fieldMapping.getDeobfName() ); } - m_fieldsByObf.put( fieldMapping.getObfName(), fieldMapping ); - m_fieldsByDeobf.put( fieldMapping.getDeobfName(), fieldMapping ); + boolean obfWasAdded = m_fieldsByObf.put( fieldMapping.getObfName(), fieldMapping ) == null; + assert( obfWasAdded ); + boolean deobfWasAdded = m_fieldsByDeobf.put( fieldMapping.getDeobfName(), fieldMapping ) == null; + assert( deobfWasAdded ); assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() ); } @@ -169,38 +182,47 @@ public class ClassMapping implements Serializable, Comparable if( fieldMapping == null ) { fieldMapping = new FieldMapping( obfName, deobfName ); - m_fieldsByObf.put( obfName, fieldMapping ); - m_fieldsByDeobf.put( deobfName, fieldMapping ); + boolean obfWasAdded = m_fieldsByObf.put( obfName, fieldMapping ) == null; + assert( obfWasAdded ); + } + else + { + boolean wasRemoved = m_fieldsByDeobf.remove( fieldMapping.getDeobfName() ) != null; + assert( wasRemoved ); } - - m_fieldsByDeobf.remove( fieldMapping.getDeobfName() ); fieldMapping.setDeobfName( deobfName ); - m_fieldsByDeobf.put( deobfName, fieldMapping ); + boolean wasAdded = m_fieldsByDeobf.put( deobfName, fieldMapping ) == null; + assert( wasAdded ); } //// METHODS //////// public Iterable methods( ) { - assert( m_methodsByObf.size() == m_methodsByDeobf.size() ); + assert( m_methodsByObf.size() >= m_methodsByDeobf.size() ); return m_methodsByObf.values(); } - protected void addMethodMapping( MethodMapping methodMapping ) + public void addMethodMapping( MethodMapping methodMapping ) { String obfKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ); - String deobfKey = getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ); if( m_methodsByObf.containsKey( obfKey ) ) { throw new Error( "Already have mapping for " + m_obfName + "." + obfKey ); } - if( m_methodsByDeobf.containsKey( deobfKey ) ) + boolean wasAdded = m_methodsByObf.put( obfKey, methodMapping ) == null; + assert( wasAdded ); + if( methodMapping.getDeobfName() != null ) { - throw new Error( "Already have mapping for " + m_deobfName + "." + deobfKey ); + String deobfKey = getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ); + if( m_methodsByDeobf.containsKey( deobfKey ) ) + { + throw new Error( "Already have mapping for " + m_deobfName + "." + deobfKey ); + } + boolean deobfWasAdded = m_methodsByDeobf.put( deobfKey, methodMapping ) == null; + assert( deobfWasAdded ); } - m_methodsByObf.put( obfKey, methodMapping ); - m_methodsByDeobf.put( deobfKey, methodMapping ); - assert( m_methodsByObf.size() == m_methodsByDeobf.size() ); + assert( m_methodsByObf.size() >= m_methodsByDeobf.size() ); } public MethodMapping getMethodByObf( String obfName, String signature ) @@ -231,13 +253,17 @@ public class ClassMapping implements Serializable, Comparable MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) ); if( methodMapping == null ) { - methodMapping = createMethodIndex( obfName, obfSignature ); + methodMapping = createMethodMapping( obfName, obfSignature ); + } + else + { + boolean wasRemoved = m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ) ) != null; + assert( wasRemoved ); } - - m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ) ); methodMapping.setDeobfName( deobfName ); methodMapping.setDeobfSignature( deobfSignature ); - m_methodsByDeobf.put( getMethodKey( deobfName, deobfSignature ), methodMapping ); + boolean wasAdded = m_methodsByDeobf.put( getMethodKey( deobfName, deobfSignature ), methodMapping ) == null; + assert( wasAdded ); } public void updateDeobfMethodSignatures( Translator translator ) @@ -255,17 +281,16 @@ public class ClassMapping implements Serializable, Comparable MethodMapping methodIndex = m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) ); if( methodIndex == null ) { - methodIndex = createMethodIndex( obfMethodName, obfMethodSignature ); + methodIndex = createMethodMapping( obfMethodName, obfMethodSignature ); } methodIndex.setArgumentName( argumentIndex, argumentName ); } - private MethodMapping createMethodIndex( String obfName, String obfSignature ) + private MethodMapping createMethodMapping( String obfName, String obfSignature ) { - MethodMapping methodMapping = new MethodMapping( obfName, obfName, obfSignature, obfSignature ); - String key = getMethodKey( obfName, obfSignature ); - m_methodsByObf.put( key, methodMapping ); - m_methodsByDeobf.put( key, methodMapping ); + MethodMapping methodMapping = new MethodMapping( obfName, obfSignature ); + boolean wasAdded = m_methodsByObf.put( getMethodKey( obfName, obfSignature ), methodMapping ) == null; + assert( wasAdded ); return methodMapping; } @@ -308,9 +333,10 @@ public class ClassMapping implements Serializable, Comparable { if( innerClassMapping.renameObfClass( oldObfClassName, newObfClassName ) ) { - m_innerClassesByObf.remove( oldObfClassName ); - m_innerClassesByObf.put( newObfClassName, innerClassMapping ); - assert( m_innerClassesByObf.size() == m_innerClassesByDeobf.size() ); + boolean wasRemoved = m_innerClassesByObf.remove( oldObfClassName ) != null; + assert( wasRemoved ); + boolean wasAdded = m_innerClassesByObf.put( newObfClassName, innerClassMapping ) == null; + assert( wasAdded ); } } @@ -320,9 +346,10 @@ public class ClassMapping implements Serializable, Comparable String oldMethodKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ); if( methodMapping.renameObfClass( oldObfClassName, newObfClassName ) ) { - m_methodsByObf.remove( oldMethodKey ); - m_methodsByObf.put( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ), methodMapping ); - assert( m_methodsByObf.size() == m_methodsByDeobf.size() ); + boolean wasRemoved = m_methodsByObf.remove( oldMethodKey ) != null; + assert( wasRemoved ); + boolean wasAdded = m_methodsByObf.put( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ), methodMapping ) == null; + assert( wasAdded ); } } diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index f52094fd..99cb85f0 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -47,7 +47,10 @@ public class Mappings implements Serializable for( ClassMapping classMapping : classes ) { m_classesByObf.put( classMapping.getObfName(), classMapping ); - m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ); + if( classMapping.getDeobfName() != null ) + { + m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ); + } } } @@ -68,23 +71,27 @@ public class Mappings implements Serializable public Collection classes( ) { - assert( m_classesByObf.size() == m_classesByDeobf.size() ); + assert( m_classesByObf.size() >= m_classesByDeobf.size() ); return m_classesByObf.values(); } - protected void addClassMapping( ClassMapping classMapping ) + public void addClassMapping( ClassMapping classMapping ) { if( m_classesByObf.containsKey( classMapping.getObfName() ) ) { throw new Error( "Already have mapping for " + classMapping.getObfName() ); } - if( m_classesByDeobf.containsKey( classMapping.getDeobfName() ) ) + boolean obfWasAdded = m_classesByObf.put( classMapping.getObfName(), classMapping ) == null; + assert( obfWasAdded ); + if( classMapping.getDeobfName() != null ) { - throw new Error( "Already have mapping for " + classMapping.getDeobfName() ); + if( m_classesByDeobf.containsKey( classMapping.getDeobfName() ) ) + { + throw new Error( "Already have mapping for " + classMapping.getDeobfName() ); + } + boolean deobfWasAdded = m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null; + assert( deobfWasAdded ); } - m_classesByObf.put( classMapping.getObfName(), classMapping ); - m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ); - assert( m_classesByObf.size() == m_classesByDeobf.size() ); } public ClassMapping getClassByObf( ClassEntry entry ) @@ -99,7 +106,7 @@ public class Mappings implements Serializable public ClassMapping getClassByDeobf( ClassEntry entry ) { - return getClassByObf( entry.getName() ); + return getClassByDeobf( entry.getName() ); } public ClassMapping getClassByDeobf( String deobfName ) @@ -109,26 +116,52 @@ public class Mappings implements Serializable public Translator getTranslator( TranslationIndex index, TranslationDirection direction ) { - if( direction == TranslationDirection.Obfuscating ) + switch( direction ) { - // deobfuscate the index - index = new TranslationIndex( index ); - Map renames = Maps.newHashMap(); - for( ClassMapping classMapping : classes() ) - { - renames.put( classMapping.getObfName(), classMapping.getDeobfName() ); - for( ClassMapping innerClassMapping : classMapping.innerClasses() ) + case Deobfuscating: + + return new Translator( direction, m_classesByObf, index ); + + case Obfuscating: + + // deobfuscate the index + index = new TranslationIndex( index ); + Map renames = Maps.newHashMap(); + for( ClassMapping classMapping : classes() ) { - renames.put( innerClassMapping.getObfName(), innerClassMapping.getDeobfName() ); + if( classMapping.getDeobfName() != null ) + { + renames.put( classMapping.getObfName(), classMapping.getDeobfName() ); + } + for( ClassMapping innerClassMapping : classMapping.innerClasses() ) + { + if( innerClassMapping.getDeobfName() != null ) + { + renames.put( innerClassMapping.getObfName(), innerClassMapping.getDeobfName() ); + } + } } - } - index.renameClasses( renames ); + index.renameClasses( renames ); + + // fill in the missing deobf class entries with obf entries + Map classes = Maps.newHashMap(); + for( ClassMapping classMapping : classes() ) + { + if( classMapping.getDeobfName() != null ) + { + classes.put( classMapping.getDeobfName(), classMapping ); + } + else + { + classes.put( classMapping.getObfName(), classMapping ); + } + } + + return new Translator( direction, classes, index ); + + default: + throw new Error( "Invalid translation direction!" ); } - return new Translator( - direction, - direction.choose( m_classesByObf, m_classesByDeobf ), - index - ); } public static Mappings newFromStream( InputStream in ) @@ -162,9 +195,10 @@ public class Mappings implements Serializable { if( classMapping.renameObfClass( oldObfName, newObfName ) ) { - m_classesByObf.remove( oldObfName ); - m_classesByObf.put( newObfName, classMapping ); - assert( m_classesByObf.size() == m_classesByDeobf.size() ); + boolean wasRemoved = m_classesByObf.remove( oldObfName ) != null; + assert( wasRemoved ); + boolean wasAdded = m_classesByObf.put( newObfName, classMapping ) == null; + assert( wasAdded ); } } } diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java index 9f42b42c..7888836e 100644 --- a/src/cuchaz/enigma/mapping/MappingsReader.java +++ b/src/cuchaz/enigma/mapping/MappingsReader.java @@ -14,13 +14,10 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.util.Deque; -import java.util.NoSuchElementException; -import java.util.Scanner; import com.google.common.collect.Queues; import cuchaz.enigma.Constants; -import cuchaz.enigma.Util; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class MappingsReader @@ -73,89 +70,99 @@ public class MappingsReader mappingStack.pop(); } - Scanner scanner = new Scanner( line ); + String[] parts = line.trim().split( "\\s" ); try { - while( scanner.hasNext() ) + // read the first token + String token = parts[0]; + + if( token.equalsIgnoreCase( "CLASS" ) ) { - // read the first token - String token = scanner.next(); - - if( token.equalsIgnoreCase( "CLASS" ) ) + ClassMapping classMapping = readClass( parts ); + if( indent == 0 ) { - ClassMapping classMapping = readClass( scanner ); - if( indent == 0 ) - { - // outer class - mappings.addClassMapping( classMapping ); - } - else if( indent == 1 ) - { - // inner class - if( !( mappingStack.getFirst() instanceof ClassMapping ) ) - { - throw new MappingParseException( lineNumber, "Unexpected CLASS entry here!" ); - } - ((ClassMapping)mappingStack.getFirst()).addInnerClassMapping( classMapping ); - } - else + // outer class + mappings.addClassMapping( classMapping ); + } + else if( indent == 1 ) + { + // inner class + if( !( mappingStack.getFirst() instanceof ClassMapping ) ) { throw new MappingParseException( lineNumber, "Unexpected CLASS entry here!" ); } - mappingStack.push( classMapping ); + ((ClassMapping)mappingStack.getFirst()).addInnerClassMapping( classMapping ); } - else if( token.equalsIgnoreCase( "FIELD" ) ) + else { - if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof ClassMapping) ) - { - throw new MappingParseException( lineNumber, "Unexpected FIELD entry here!" ); - } - ((ClassMapping)mappingStack.getFirst()).addFieldMapping( readField( scanner ) ); + throw new MappingParseException( lineNumber, "Unexpected CLASS entry here!" ); } - else if( token.equalsIgnoreCase( "METHOD" ) ) + mappingStack.push( classMapping ); + } + else if( token.equalsIgnoreCase( "FIELD" ) ) + { + if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof ClassMapping) ) { - if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof ClassMapping) ) - { - throw new MappingParseException( lineNumber, "Unexpected METHOD entry here!" ); - } - MethodMapping methodMapping = readMethod( scanner ); - ((ClassMapping)mappingStack.getFirst()).addMethodMapping( methodMapping ); - mappingStack.push( methodMapping ); + throw new MappingParseException( lineNumber, "Unexpected FIELD entry here!" ); } - else if( token.equalsIgnoreCase( "ARG" ) ) + ((ClassMapping)mappingStack.getFirst()).addFieldMapping( readField( parts ) ); + } + else if( token.equalsIgnoreCase( "METHOD" ) ) + { + if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof ClassMapping) ) { - if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof MethodMapping) ) - { - throw new MappingParseException( lineNumber, "Unexpected ARG entry here!" ); - } - ((MethodMapping)mappingStack.getFirst()).addArgumentMapping( readArgument( scanner ) ); + throw new MappingParseException( lineNumber, "Unexpected METHOD entry here!" ); + } + MethodMapping methodMapping = readMethod( parts ); + ((ClassMapping)mappingStack.getFirst()).addMethodMapping( methodMapping ); + mappingStack.push( methodMapping ); + } + else if( token.equalsIgnoreCase( "ARG" ) ) + { + if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof MethodMapping) ) + { + throw new MappingParseException( lineNumber, "Unexpected ARG entry here!" ); } + ((MethodMapping)mappingStack.getFirst()).addArgumentMapping( readArgument( parts ) ); } } - catch( NoSuchElementException ex ) + catch( ArrayIndexOutOfBoundsException | NumberFormatException ex ) { throw new MappingParseException( lineNumber, "Malformed line!" ); } - finally - { - Util.closeQuietly( scanner ); - } } return mappings; } - private ArgumentMapping readArgument( Scanner scanner ) + private ArgumentMapping readArgument( String[] parts ) { - return new ArgumentMapping( scanner.nextInt(), scanner.next() ); + return new ArgumentMapping( Integer.parseInt( parts[1] ), parts[2] ); } - private ClassMapping readClass( Scanner scanner ) + private ClassMapping readClass( String[] parts ) { - return new ClassMapping( - moveClassOutOfDefaultPackage( scanner.next(), Constants.NonePackage ), - moveClassOutOfDefaultPackage( scanner.next(), Constants.NonePackage ) - ); + if( parts.length == 2 ) + { + String obfName = parts[1]; + return new ClassMapping( moveClassOutOfDefaultPackage( obfName, Constants.NonePackage ) ); + } + else + { + String obfName = parts[1]; + String deobfName = parts[2]; + if( obfName.equals( deobfName ) ) + { + return new ClassMapping( moveClassOutOfDefaultPackage( obfName, Constants.NonePackage ) ); + } + else + { + return new ClassMapping( + moveClassOutOfDefaultPackage( parts[1], Constants.NonePackage ), + moveClassOutOfDefaultPackage( parts[2], Constants.NonePackage ) + ); + } + } } private String moveClassOutOfDefaultPackage( String className, String newPackageName ) @@ -168,18 +175,34 @@ public class MappingsReader return className; } - private FieldMapping readField( Scanner scanner ) + private FieldMapping readField( String[] parts ) { - return new FieldMapping( scanner.next(), scanner.next() ); + return new FieldMapping( parts[1], parts[2] ); } - private MethodMapping readMethod( Scanner scanner ) + private MethodMapping readMethod( String[] parts ) { - return new MethodMapping( - scanner.next(), scanner.next(), - moveSignatureOutOfDefaultPackage( scanner.next(), Constants.NonePackage ), - moveSignatureOutOfDefaultPackage( scanner.next(), Constants.NonePackage ) - ); + if( parts.length == 3 ) + { + String obfName = parts[1]; + String obfSignature = moveSignatureOutOfDefaultPackage( parts[2], Constants.NonePackage ); + return new MethodMapping( obfName, obfSignature ); + } + else + { + String obfName = parts[1]; + String deobfName = parts[2]; + String obfSignature = moveSignatureOutOfDefaultPackage( parts[3], Constants.NonePackage ); + String deobfSignature = moveSignatureOutOfDefaultPackage( parts[4], Constants.NonePackage ); + if( obfName.equals( deobfName ) ) + { + return new MethodMapping( obfName, obfSignature ); + } + else + { + return new MethodMapping( obfName, obfSignature, deobfName, deobfSignature ); + } + } } private String moveSignatureOutOfDefaultPackage( String signature, final String newPackageName ) diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index 9d036d8f..f84b2489 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -46,9 +46,11 @@ public class MappingsRenamer } else { - m_mappings.m_classesByDeobf.remove( classMapping.getDeobfName() ); + boolean wasRemoved = m_mappings.m_classesByDeobf.remove( classMapping.getDeobfName() ) != null; + assert( wasRemoved ); classMapping.setDeobfName( deobfName ); - m_mappings.m_classesByDeobf.put( deobfName, classMapping ); + boolean wasAdded = m_mappings.m_classesByDeobf.put( deobfName, classMapping ) == null; + assert( wasAdded ); } updateDeobfMethodSignatures(); @@ -132,9 +134,11 @@ public class MappingsRenamer ClassMapping classMapping = m_mappings.m_classesByObf.get( obfClassName ); if( classMapping == null ) { - classMapping = new ClassMapping( obfClassName, obfClassName ); - m_mappings.m_classesByObf.put( classMapping.getObfName(), classMapping ); - m_mappings.m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ); + classMapping = new ClassMapping( obfClassName ); + boolean obfWasAdded = m_mappings.m_classesByObf.put( classMapping.getObfName(), classMapping ) == null; + assert( obfWasAdded ); + boolean deobfWasAdded = m_mappings.m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null; + assert( deobfWasAdded ); } return classMapping; } diff --git a/src/cuchaz/enigma/mapping/MappingsWriter.java b/src/cuchaz/enigma/mapping/MappingsWriter.java index 62035713..ea6e6558 100644 --- a/src/cuchaz/enigma/mapping/MappingsWriter.java +++ b/src/cuchaz/enigma/mapping/MappingsWriter.java @@ -37,7 +37,14 @@ public class MappingsWriter private void write( PrintWriter out, ClassMapping classMapping, int depth ) throws IOException { - out.format( "%sCLASS %s %s\n", getIndent( depth ), classMapping.getObfName(), classMapping.getDeobfName() ); + if( classMapping.getDeobfName() == null ) + { + out.format( "%sCLASS %s\n", getIndent( depth ), classMapping.getObfName() ); + } + else + { + out.format( "%sCLASS %s %s\n", getIndent( depth ), classMapping.getObfName(), classMapping.getDeobfName() ); + } for( ClassMapping innerClassMapping : sorted( classMapping.innerClasses() ) ) { @@ -64,11 +71,21 @@ public class MappingsWriter private void write( PrintWriter out, MethodMapping methodMapping, int depth ) throws IOException { - out.format( "%sMETHOD %s %s %s %s\n", - getIndent( depth ), - methodMapping.getObfName(), methodMapping.getDeobfName(), - methodMapping.getObfSignature(), methodMapping.getDeobfSignature() - ); + if( methodMapping.getDeobfName() == null ) + { + out.format( "%sMETHOD %s %s\n", + getIndent( depth ), + methodMapping.getObfName(), methodMapping.getObfSignature() + ); + } + else + { + out.format( "%sMETHOD %s %s %s %s\n", + getIndent( depth ), + methodMapping.getObfName(), methodMapping.getDeobfName(), + methodMapping.getObfSignature(), methodMapping.getDeobfSignature() + ); + } for( ArgumentMapping argumentMapping : sorted( methodMapping.arguments() ) ) { diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java index bf83bd21..e59cb2eb 100644 --- a/src/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/cuchaz/enigma/mapping/MethodMapping.java @@ -26,8 +26,12 @@ public class MethodMapping implements Serializable, Comparable 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 ) + public MethodMapping( String obfName, String obfSignature ) + { + this( obfName, obfSignature, null, null ); + } + + public MethodMapping( String obfName, String obfSignature, String deobfName, String deobfSignature ) { m_obfName = obfName; m_deobfName = NameValidator.validateMethodName( deobfName ); @@ -69,9 +73,10 @@ public class MethodMapping implements Serializable, Comparable return m_arguments.values(); } - protected void addArgumentMapping( ArgumentMapping argumentMapping ) + public void addArgumentMapping( ArgumentMapping argumentMapping ) { - m_arguments.put( argumentMapping.getIndex(), argumentMapping ); + boolean wasAdded = m_arguments.put( argumentMapping.getIndex(), argumentMapping ) == null; + assert( wasAdded ); } public String getObfArgumentName( int index ) @@ -102,7 +107,8 @@ public class MethodMapping implements Serializable, Comparable if( argumentMapping == null ) { argumentMapping = new ArgumentMapping( index, name ); - m_arguments.put( index, argumentMapping ); + boolean wasAdded = m_arguments.put( index, argumentMapping ) == null; + assert( wasAdded ); } else { diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java index 6df893fb..9adf1ac1 100644 --- a/src/cuchaz/enigma/mapping/NameValidator.java +++ b/src/cuchaz/enigma/mapping/NameValidator.java @@ -57,7 +57,11 @@ public class NameValidator public static String validateClassName( String name ) { - if( name == null || !ClassPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) + if( name == null ) + { + return null; + } + if( !ClassPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) { throw new IllegalNameException( name, "This doesn't look like a legal class name" ); } @@ -70,7 +74,11 @@ public class NameValidator public static String validateFieldName( String name ) { - if( name == null || !IdentifierPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) + if( name == null ) + { + return null; + } + if( !IdentifierPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) { throw new IllegalNameException( name, "This doesn't look like a legal identifier" ); } -- cgit v1.2.3 From 3632307d9c5665edfca976e08931dc6cadf510a0 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 3 Sep 2014 00:29:48 -0400 Subject: fixed issue with method renaming --- src/cuchaz/enigma/gui/GuiController.java | 2 -- src/cuchaz/enigma/mapping/ClassMapping.java | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 5057db2d..c0fb2e40 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -167,8 +167,6 @@ public class GuiController public boolean entryHasMapping( Entry deobfEntry ) { - // TEMP - System.out.println( deobfEntry + " -> " + m_deobfuscator.obfuscateEntry( deobfEntry ) ); return m_deobfuscator.hasMapping( m_deobfuscator.obfuscateEntry( deobfEntry ) ); } diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index bce16cc5..6a89df7f 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -255,7 +255,7 @@ public class ClassMapping implements Serializable, Comparable { methodMapping = createMethodMapping( obfName, obfSignature ); } - else + else if( methodMapping.getDeobfName() != null ) { boolean wasRemoved = m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ) ) != null; assert( wasRemoved ); -- cgit v1.2.3 From 5bb9b46e729ba7953a48932d586bce6c30d813c4 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 3 Sep 2014 00:54:55 -0400 Subject: repackaged for 0.5 beta --- src/cuchaz/enigma/Constants.java | 2 +- src/cuchaz/enigma/convert/ClassMatcher.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java index c8631429..bf6ab846 100644 --- a/src/cuchaz/enigma/Constants.java +++ b/src/cuchaz/enigma/Constants.java @@ -14,7 +14,7 @@ package cuchaz.enigma; public class Constants { public static final String Name = "Enigma"; - public static final String Version = "0.4.2 beta"; + public static final String Version = "0.5 beta"; 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/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java index 0821bd3a..135d076d 100644 --- a/src/cuchaz/enigma/convert/ClassMatcher.java +++ b/src/cuchaz/enigma/convert/ClassMatcher.java @@ -55,16 +55,16 @@ public class ClassMatcher throws IOException, MappingParseException { // TEMP - JarFile sourceJar = new JarFile( new File( "input/1.8-pre1.jar" ) ); - JarFile destJar = new JarFile( new File( "input/1.8-pre3.jar" ) ); - File inMappingsFile = new File( "../minecraft-mappings/1.8-pre.mappings" ); - File outMappingsFile = new File( "../minecraft-mappings/1.8-pre3.mappings" ); + JarFile sourceJar = new JarFile( new File( "input/1.8-pre3.jar" ) ); + JarFile destJar = new JarFile( new File( "input/1.8.jar" ) ); + File inMappingsFile = new File( "../minecraft-mappings/1.8-pre3.mappings" ); + File outMappingsFile = new File( "../minecraft-mappings/1.8.mappings" ); // define a matching to use when the automated system cannot find a match Map fallbackMatching = Maps.newHashMap(); - fallbackMatching.put( "none/ayb", "none/ayb" ); + fallbackMatching.put( "none/ayb", "none/ayf" ); fallbackMatching.put( "none/ayd", "none/ayd" ); - fallbackMatching.put( "none/bgk", "none/bgk" ); + fallbackMatching.put( "none/bgk", "unknown/bgk" ); // do the conversion Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) ); -- cgit v1.2.3 From 1faf3bee250f75d8c13708ab875a881a5b9cb6ed Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 3 Sep 2014 23:56:11 -0400 Subject: removed deobfuscated method signatures from mappings They're too much work to maintain, and they're totally unnecessary! --- src/cuchaz/enigma/Deobfuscator.java | 5 ++++- src/cuchaz/enigma/mapping/ClassMapping.java | 17 ++++------------ src/cuchaz/enigma/mapping/MappingsReader.java | 3 +-- src/cuchaz/enigma/mapping/MappingsRenamer.java | 25 ++++++++---------------- src/cuchaz/enigma/mapping/MappingsWriter.java | 4 ++-- src/cuchaz/enigma/mapping/MethodMapping.java | 27 +++++++++++--------------- src/cuchaz/enigma/mapping/Translator.java | 4 ++-- 7 files changed, 32 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 526534da..8944eec7 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -1,5 +1,6 @@ /******************************************************************************* - * Copyright (c) 2014 Jeff Martin. + * 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 @@ -78,7 +79,9 @@ public class Deobfuscator // config the decompiler m_settings = DecompilerSettings.javaDefaults(); + m_settings.setMergeVariables( true ); m_settings.setForceExplicitImports( true ); + m_settings.setForceExplicitTypeArguments( true ); // DEBUG //m_settings.setShowSyntheticMembers( true ); diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index 6a89df7f..200d9ca2 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -214,7 +214,7 @@ public class ClassMapping implements Serializable, Comparable assert( wasAdded ); if( methodMapping.getDeobfName() != null ) { - String deobfKey = getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ); + String deobfKey = getMethodKey( methodMapping.getDeobfName(), methodMapping.getObfSignature() ); if( m_methodsByDeobf.containsKey( deobfKey ) ) { throw new Error( "Already have mapping for " + m_deobfName + "." + deobfKey ); @@ -248,7 +248,7 @@ public class ClassMapping implements Serializable, Comparable return name + signature; } - public void setMethodNameAndSignature( String obfName, String obfSignature, String deobfName, String deobfSignature ) + public void setMethodName( String obfName, String obfSignature, String deobfName ) { MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) ); if( methodMapping == null ) @@ -257,23 +257,14 @@ public class ClassMapping implements Serializable, Comparable } else if( methodMapping.getDeobfName() != null ) { - boolean wasRemoved = m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ) ) != null; + boolean wasRemoved = m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) ) != null; assert( wasRemoved ); } methodMapping.setDeobfName( deobfName ); - methodMapping.setDeobfSignature( deobfSignature ); - boolean wasAdded = m_methodsByDeobf.put( getMethodKey( deobfName, deobfSignature ), methodMapping ) == null; + boolean wasAdded = m_methodsByDeobf.put( getMethodKey( deobfName, obfSignature ), methodMapping ) == null; assert( wasAdded ); } - public void updateDeobfMethodSignatures( Translator translator ) - { - for( MethodMapping methodIndex : m_methodsByObf.values() ) - { - methodIndex.setDeobfSignature( translator.translateSignature( methodIndex.getObfSignature() ) ); - } - } - //// ARGUMENTS //////// public void setArgumentName( String obfMethodName, String obfMethodSignature, int argumentIndex, String argumentName ) diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java index 7888836e..5cbad59c 100644 --- a/src/cuchaz/enigma/mapping/MappingsReader.java +++ b/src/cuchaz/enigma/mapping/MappingsReader.java @@ -193,14 +193,13 @@ public class MappingsReader String obfName = parts[1]; String deobfName = parts[2]; String obfSignature = moveSignatureOutOfDefaultPackage( parts[3], Constants.NonePackage ); - String deobfSignature = moveSignatureOutOfDefaultPackage( parts[4], Constants.NonePackage ); if( obfName.equals( deobfName ) ) { return new MethodMapping( obfName, obfSignature ); } else { - return new MethodMapping( obfName, obfSignature, deobfName, deobfSignature ); + return new MethodMapping( obfName, obfSignature, deobfName ); } } } diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index f84b2489..49e7b5fd 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -46,14 +46,15 @@ public class MappingsRenamer } else { - boolean wasRemoved = m_mappings.m_classesByDeobf.remove( classMapping.getDeobfName() ) != null; - assert( wasRemoved ); + if( classMapping.getDeobfName() != null ) + { + boolean wasRemoved = m_mappings.m_classesByDeobf.remove( classMapping.getDeobfName() ) != null; + assert( wasRemoved ); + } classMapping.setDeobfName( deobfName ); boolean wasAdded = m_mappings.m_classesByDeobf.put( deobfName, classMapping ) == null; assert( wasAdded ); } - - updateDeobfMethodSignatures(); } public void setFieldName( FieldEntry obf, String deobfName ) @@ -76,7 +77,8 @@ public class MappingsRenamer deobfName = NameValidator.validateMethodName( deobfName ); for( MethodEntry entry : implementations ) { - MethodEntry targetEntry = new MethodEntry( entry.getClassEntry(), deobfName, entry.getSignature() ); + String deobfSignature = getTranslator( TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); + MethodEntry targetEntry = new MethodEntry( entry.getClassEntry(), deobfName, deobfSignature ); if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) { String deobfClassName = getTranslator( TranslationDirection.Deobfuscating ).translateClass( entry.getClassName() ); @@ -101,8 +103,7 @@ public class MappingsRenamer } ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); - String deobfSignature = getTranslator( TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); - classMapping.setMethodNameAndSignature( obf.getName(), obf.getSignature(), deobfName, deobfSignature ); + classMapping.setMethodName( obf.getName(), obf.getSignature(), deobfName ); } public void setArgumentName( ArgumentEntry obf, String deobfName ) @@ -137,8 +138,6 @@ public class MappingsRenamer classMapping = new ClassMapping( obfClassName ); boolean obfWasAdded = m_mappings.m_classesByObf.put( classMapping.getObfName(), classMapping ) == null; assert( obfWasAdded ); - boolean deobfWasAdded = m_mappings.m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null; - assert( deobfWasAdded ); } return classMapping; } @@ -153,14 +152,6 @@ public class MappingsRenamer return classMapping; } - private void updateDeobfMethodSignatures( ) - { - for( ClassMapping classMapping : m_mappings.m_classesByObf.values() ) - { - classMapping.updateDeobfMethodSignatures( getTranslator( TranslationDirection.Deobfuscating ) ); - } - } - private Translator getTranslator( TranslationDirection direction ) { return m_mappings.getTranslator( m_index.getTranslationIndex(), direction ); diff --git a/src/cuchaz/enigma/mapping/MappingsWriter.java b/src/cuchaz/enigma/mapping/MappingsWriter.java index ea6e6558..3c86dfc0 100644 --- a/src/cuchaz/enigma/mapping/MappingsWriter.java +++ b/src/cuchaz/enigma/mapping/MappingsWriter.java @@ -80,10 +80,10 @@ public class MappingsWriter } else { - out.format( "%sMETHOD %s %s %s %s\n", + out.format( "%sMETHOD %s %s %s\n", getIndent( depth ), methodMapping.getObfName(), methodMapping.getDeobfName(), - methodMapping.getObfSignature(), methodMapping.getDeobfSignature() + methodMapping.getObfSignature() ); } diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java index e59cb2eb..6210fd09 100644 --- a/src/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/cuchaz/enigma/mapping/MethodMapping.java @@ -23,20 +23,26 @@ public class MethodMapping implements Serializable, Comparable private String m_obfName; private String m_deobfName; private String m_obfSignature; - private String m_deobfSignature; private Map m_arguments; public MethodMapping( String obfName, String obfSignature ) { - this( obfName, obfSignature, null, null ); + this( obfName, obfSignature, null ); } - public MethodMapping( String obfName, String obfSignature, String deobfName, String deobfSignature ) + public MethodMapping( String obfName, String obfSignature, String deobfName ) { + if( obfName == null ) + { + throw new IllegalArgumentException( "obf name cannot be null!" ); + } + if( obfSignature == null ) + { + throw new IllegalArgumentException( "obf signature cannot be null!" ); + } m_obfName = obfName; m_deobfName = NameValidator.validateMethodName( deobfName ); m_obfSignature = obfSignature; - m_deobfSignature = deobfSignature; m_arguments = new TreeMap(); } @@ -59,15 +65,6 @@ public class MethodMapping implements Serializable, Comparable return m_obfSignature; } - public String getDeobfSignature( ) - { - return m_deobfSignature; - } - public void setDeobfSignature( String val ) - { - m_deobfSignature = val; - } - public Iterable arguments( ) { return m_arguments.values(); @@ -127,8 +124,6 @@ public class MethodMapping implements Serializable, Comparable 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() ) @@ -145,7 +140,7 @@ public class MethodMapping implements Serializable, Comparable @Override public int compareTo( MethodMapping other ) { - return ( m_obfName + m_obfSignature ).compareTo( ( other.m_obfName + other.m_obfSignature ) ); + return ( m_obfName + m_obfSignature ).compareTo( other.m_obfName + other.m_obfSignature ); } public boolean renameObfClass( final String oldObfClassName, final String newObfClassName ) diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index f5aafdd1..659ce9a2 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -180,7 +180,7 @@ public class Translator // look for the method MethodMapping methodMapping = m_direction.choose( classMapping.getMethodByObf( in.getName(), in.getSignature() ), - classMapping.getMethodByDeobf( in.getName(), in.getSignature() ) + classMapping.getMethodByDeobf( in.getName(), translateSignature( in.getSignature() ) ) ); if( methodMapping != null ) { @@ -248,7 +248,7 @@ public class Translator // look for the method MethodMapping methodMapping = m_direction.choose( classMapping.getMethodByObf( in.getMethodName(), in.getMethodSignature() ), - classMapping.getMethodByDeobf( in.getMethodName(), in.getMethodSignature() ) + classMapping.getMethodByDeobf( in.getMethodName(), translateSignature( in.getMethodSignature() ) ) ); if( methodMapping != null ) { -- cgit v1.2.3 From ce8b00f42d8e3de93ece15dc12db1813d745a2c9 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 4 Sep 2014 00:02:26 -0400 Subject: removed hack to avoid procyon loop --- src/cuchaz/enigma/Deobfuscator.java | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 8944eec7..0847049e 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -261,12 +261,6 @@ public class Deobfuscator continue; } - // TEMP: skip the classes that won't decompile because of a procyon bug - if( obfClassEntry.getName().equals( "none/bgl" ) ) - { - continue; - } - classEntries.add( obfClassEntry ); } -- cgit v1.2.3 From eeeaf6ec9e177fbffdd639f5b7e7e3d0f020ce9a Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 4 Sep 2014 00:08:07 -0400 Subject: fixed spelling error in error message (lol) --- src/cuchaz/enigma/mapping/ClassEntry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index f87ddc1d..f8477c92 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -34,7 +34,7 @@ public class ClassEntry implements Entry, Serializable if( isInnerClass() && getInnerClassName().indexOf( '/' ) >= 0 ) { - throw new IllegalArgumentException( "Inner cast must not have a package: " + getInnerClassName() ); + throw new IllegalArgumentException( "Inner class must not have a package: " + getInnerClassName() ); } } -- cgit v1.2.3 From 730238f3bab1c680424e0ac74178c33b15b43eb5 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 7 Sep 2014 22:30:28 -0400 Subject: added some basic tests for the deobufscator and the jar index --- src/cuchaz/enigma/analysis/JarIndex.java | 11 ++++++++--- src/cuchaz/enigma/convert/ClassIdentity.java | 14 +++++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index a8ac0013..b4096e9d 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -587,9 +587,14 @@ public class JarIndex public ClassImplementationsTreeNode getClassImplementations( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) { - ClassImplementationsTreeNode node = new ClassImplementationsTreeNode( deobfuscatingTranslator, obfClassEntry ); - node.load( this ); - return node; + // is this even an interface? + if( isInterface( obfClassEntry.getClassName() ) ) + { + ClassImplementationsTreeNode node = new ClassImplementationsTreeNode( deobfuscatingTranslator, obfClassEntry ); + node.load( this ); + return node; + } + return null; } public MethodInheritanceTreeNode getMethodInheritance( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java index bd2824b3..b3b043e5 100644 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ b/src/cuchaz/enigma/convert/ClassIdentity.java @@ -111,12 +111,16 @@ public class ClassIdentity // stuff from the jar index m_implementations = HashMultiset.create(); - @SuppressWarnings( "unchecked" ) - Enumeration implementations = index.getClassImplementations( null, m_classEntry ).children(); - while( implementations.hasMoreElements() ) + ClassImplementationsTreeNode implementationsNode = index.getClassImplementations( null, m_classEntry ); + if( implementationsNode != null ) { - ClassImplementationsTreeNode node = implementations.nextElement(); - m_implementations.add( scrubClassName( node.getClassEntry().getName() ) ); + @SuppressWarnings( "unchecked" ) + Enumeration implementations = implementationsNode.children(); + while( implementations.hasMoreElements() ) + { + ClassImplementationsTreeNode node = implementations.nextElement(); + m_implementations.add( scrubClassName( node.getClassEntry().getName() ) ); + } } m_references = HashMultiset.create(); -- cgit v1.2.3 From aa68099bb252dd1a1c275459f8babe537868bcaf Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 14 Sep 2014 19:06:55 -0400 Subject: fixed bug with method references pointing to wrong class --- src/cuchaz/enigma/analysis/JarIndex.java | 120 +++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index b4096e9d..f4843164 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -127,7 +127,7 @@ public class JarIndex } for( CtField field : c.getDeclaredFields() ) { - indexField( field ); + m_translationIndex.addField( className, field.getName() ); } for( CtBehavior behavior : c.getDeclaredBehaviors() ) { @@ -135,9 +135,19 @@ public class JarIndex } } + // step 4: index field, method, constructor references + for( CtClass c : JarClassIterator.classes( jar ) ) + { + ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); + for( CtBehavior behavior : c.getDeclaredBehaviors() ) + { + indexBehaviorReferences( behavior ); + } + } + if( buildInnerClasses ) { - // step 4: index inner classes and anonymous classes + // step 5: index inner classes and anonymous classes for( CtClass c : JarClassIterator.classes( jar ) ) { ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); @@ -163,7 +173,7 @@ public class JarIndex } } - // step 5: update other indices with inner class info + // step 6: update other indices with inner class info Map renames = Maps.newHashMap(); for( Map.Entry entry : m_outerClasses.entrySet() ) { @@ -183,25 +193,14 @@ public class JarIndex EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences ); } - private void indexField( CtField field ) - { - String className = Descriptor.toJvmName( field.getDeclaringClass().getName() ); - m_translationIndex.addField( className, field.getName() ); - } - private void indexBehavior( CtBehavior behavior ) { - // get the method entry + // get the behavior entry String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); - final BehaviorEntry thisEntry; - if( behavior instanceof CtMethod ) + final BehaviorEntry behaviorEntry = getBehaviorEntry( behavior ); + if( behaviorEntry instanceof MethodEntry ) { - MethodEntry methodEntry = new MethodEntry( - new ClassEntry( className ), - behavior.getName(), - behavior.getSignature() - ); - thisEntry = methodEntry; + MethodEntry methodEntry = (MethodEntry)behaviorEntry; // index implementation m_methodImplementations.put( className, methodEntry ); @@ -218,24 +217,13 @@ public class JarIndex m_bridgeMethods.put( bridgedMethodEntry, methodEntry ); } } - else if( behavior instanceof CtConstructor ) - { - boolean isStatic = behavior.getName().equals( "" ); - if( isStatic ) - { - thisEntry = new ConstructorEntry( new ClassEntry( className ) ); - } - else - { - thisEntry = new ConstructorEntry( new ClassEntry( className ), behavior.getSignature() ); - } - } - else - { - throw new IllegalArgumentException( "behavior must be a method or a constructor!" ); - } - + // looks like we don't care about constructors here + } + + private void indexBehaviorReferences( CtBehavior behavior ) + { // index method calls + final BehaviorEntry behaviorEntry = getBehaviorEntry( behavior ); try { behavior.instrument( new ExprEditor( ) @@ -249,9 +237,10 @@ public class JarIndex call.getMethodName(), call.getSignature() ); + calledMethodEntry = resolveMethodClass( calledMethodEntry ); EntryReference reference = new EntryReference( calledMethodEntry, - thisEntry + behaviorEntry ); m_behaviorReferences.put( calledMethodEntry, reference ); } @@ -266,7 +255,7 @@ public class JarIndex ); EntryReference reference = new EntryReference( calledFieldEntry, - thisEntry + behaviorEntry ); m_fieldReferences.put( calledFieldEntry, reference ); } @@ -284,7 +273,7 @@ public class JarIndex ); EntryReference reference = new EntryReference( calledConstructorEntry, - thisEntry + behaviorEntry ); m_behaviorReferences.put( calledConstructorEntry, reference ); } @@ -299,7 +288,7 @@ public class JarIndex ); EntryReference reference = new EntryReference( calledConstructorEntry, - thisEntry + behaviorEntry ); m_behaviorReferences.put( calledConstructorEntry, reference ); } @@ -311,6 +300,59 @@ public class JarIndex } } + private BehaviorEntry getBehaviorEntry( CtBehavior behavior ) + { + String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); + if( behavior instanceof CtMethod ) + { + return new MethodEntry( + new ClassEntry( className ), + behavior.getName(), + behavior.getSignature() + ); + } + else if( behavior instanceof CtConstructor ) + { + boolean isStatic = behavior.getName().equals( "" ); + if( isStatic ) + { + return new ConstructorEntry( new ClassEntry( className ) ); + } + else + { + return new ConstructorEntry( new ClassEntry( className ), behavior.getSignature() ); + } + } + else + { + throw new IllegalArgumentException( "behavior must be a method or a constructor!" ); + } + } + + private MethodEntry resolveMethodClass( MethodEntry methodEntry ) + { + // this entry could refer to a method on a class where the method is not actually implemented + // travel up the inheritance tree to find the closest implementation + while( !isMethodImplemented( methodEntry ) ) + { + // is there a parent class? + String superclassName = m_translationIndex.getSuperclassName( methodEntry.getClassName() ); + if( superclassName == null ) + { + // this is probably a method from a class in a library + // we can't trace the implementation up any higher unless we index the library + return methodEntry; + } + + // move up to the parent class + methodEntry = new MethodEntry( + new ClassEntry( superclassName ), + methodEntry.getName(), + methodEntry.getSignature() + ); + } + return methodEntry; + } private CtMethod getBridgedMethod( CtMethod method ) { -- cgit v1.2.3 From 72e918a5134c2bf747a476284bcfa1bd2ef2fa21 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 14 Sep 2014 23:56:43 -0400 Subject: added tests to check constructor tokens fixed a bug with constructor tokens too --- src/cuchaz/enigma/analysis/SourceIndex.java | 10 ++--- .../analysis/SourceIndexBehaviorVisitor.java | 51 +++++++++++++++++++--- .../enigma/analysis/SourceIndexClassVisitor.java | 1 - 3 files changed, 50 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 1a5a80d6..b777f9fd 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -20,7 +20,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.strobel.decompiler.languages.Region; -import com.strobel.decompiler.languages.java.ast.Identifier; +import com.strobel.decompiler.languages.java.ast.AstNode; import cuchaz.enigma.mapping.Entry; @@ -56,7 +56,7 @@ public class SourceIndex return m_source; } - public Token getToken( Identifier node ) + public Token getToken( AstNode node ) { // get a token for this node's region Region region = node.getRegion(); @@ -71,7 +71,7 @@ public class SourceIndex ); // for tokens representing inner classes, make sure we only get the simple name - int pos = node.getName().lastIndexOf( '$' ); + int pos = node.toString().lastIndexOf( '$' ); if( pos >= 0 ) { token.end -= pos + 1; @@ -92,7 +92,7 @@ public class SourceIndex return token; } - public void addReference( Identifier node, EntryReference deobfReference ) + public void addReference( AstNode node, EntryReference deobfReference ) { Token token = getToken( node ); if( token != null ) @@ -102,7 +102,7 @@ public class SourceIndex } } - public void addDeclaration( Identifier node, Entry deobfEntry ) + public void addDeclaration( AstNode node, Entry deobfEntry ) { Token token = getToken( node ); if( token != null ) diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index ab505528..a1dac4b5 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -12,9 +12,11 @@ package cuchaz.enigma.analysis; import com.strobel.assembler.metadata.MemberReference; import com.strobel.assembler.metadata.MethodDefinition; +import com.strobel.assembler.metadata.MethodReference; import com.strobel.assembler.metadata.ParameterDefinition; import com.strobel.assembler.metadata.TypeReference; import com.strobel.decompiler.languages.TextLocation; +import com.strobel.decompiler.languages.java.ast.AstNode; import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; import com.strobel.decompiler.languages.java.ast.IdentifierExpression; import com.strobel.decompiler.languages.java.ast.InvocationExpression; @@ -24,6 +26,8 @@ import com.strobel.decompiler.languages.java.ast.MethodDeclaration; import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; import com.strobel.decompiler.languages.java.ast.SimpleType; +import com.strobel.decompiler.languages.java.ast.SuperReferenceExpression; +import com.strobel.decompiler.languages.java.ast.ThisReferenceExpression; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; @@ -58,14 +62,49 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) { MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + + // get the behavior entry ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); - if( node.getTarget() instanceof MemberReferenceExpression ) + BehaviorEntry behaviorEntry = null; + if( ref instanceof MethodReference ) { - MethodEntry methodEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); - index.addReference( - ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(), - new EntryReference( methodEntry, m_behaviorEntry ) - ); + MethodReference methodRef = (MethodReference)ref; + if( methodRef.isConstructor() ) + { + behaviorEntry = new ConstructorEntry( classEntry, ref.getSignature() ); + } + else if( methodRef.isTypeInitializer() ) + { + behaviorEntry = new ConstructorEntry( classEntry ); + } + else + { + behaviorEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); + } + } + if( behaviorEntry != null ) + { + // get the node for the token + AstNode tokenNode = null; + if( node.getTarget() instanceof MemberReferenceExpression ) + { + tokenNode = ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(); + } + else if( node.getTarget() instanceof SuperReferenceExpression ) + { + tokenNode = node.getTarget(); + } + else if( node.getTarget() instanceof ThisReferenceExpression ) + { + tokenNode = node.getTarget(); + } + if( tokenNode != null ) + { + index.addReference( + tokenNode, + new EntryReference( behaviorEntry, m_behaviorEntry ) + ); + } } return recurse( node, index ); diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index a1c82711..b7897268 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -97,7 +97,6 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, def.getSignature() ); index.addDeclaration( node.getNameToken(), constructorEntry ); - return node.acceptVisitor( new SourceIndexBehaviorVisitor( constructorEntry ), index ); } -- cgit v1.2.3 From 17427430e81c27617ec3653c412697b5d2583915 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 15 Sep 2014 00:03:14 -0400 Subject: changed "Show Calls" menu to search for calls to the default constructor when used on a class token --- src/cuchaz/enigma/gui/Gui.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 8ae16f42..7fac02de 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -1041,7 +1041,7 @@ public class Gui m_renameMenu.setEnabled( isToken ); m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry || isConstructorEntry ); m_showImplementationsMenu.setEnabled( isClassEntry || isMethodEntry ); - m_showCallsMenu.setEnabled( isFieldEntry || isMethodEntry || isConstructorEntry ); + m_showCallsMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); m_openPreviousMenu.setEnabled( m_controller.hasPreviousLocation() ); } @@ -1191,7 +1191,14 @@ public class Gui return; } - if( m_reference.entry instanceof FieldEntry ) + if( m_reference.entry instanceof ClassEntry ) + { + // look for calls to the default constructor + // TODO: get a list of all the constructors and find calls to all of them + BehaviorReferenceTreeNode node = m_controller.getMethodReferences( new ConstructorEntry( (ClassEntry)m_reference.entry, "()V" ) ); + m_callsTree.setModel( new DefaultTreeModel( node ) ); + } + else if( m_reference.entry instanceof FieldEntry ) { FieldReferenceTreeNode node = m_controller.getFieldReferences( (FieldEntry)m_reference.entry ); m_callsTree.setModel( new DefaultTreeModel( node ) ); -- cgit v1.2.3 From c65a64fc89169456febc1b4c953dbcfbafdc5f0e Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 18 Sep 2014 00:17:43 -0400 Subject: added better error handling for source export added checks to make sure we don't try to decopmile classes outside of the jar --- src/cuchaz/enigma/Deobfuscator.java | 29 +++++++--- src/cuchaz/enigma/TranslatingTypeLoader.java | 8 ++- src/cuchaz/enigma/gui/Gui.java | 84 ++++++++++++++-------------- src/cuchaz/enigma/gui/GuiController.java | 13 ++++- 4 files changed, 80 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 0847049e..1178ed60 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -200,6 +200,12 @@ public class Deobfuscator className = classMapping.getDeobfName(); } + // is this class even in the jar? + if( !m_jarIndex.containsObfClass( new ClassEntry( className ) ) ) + { + return null; + } + // set the type loader m_settings.setTypeLoader( new TranslatingTypeLoader( m_jar, @@ -279,15 +285,22 @@ public class Deobfuscator progress.onProgress( i++, deobfClassEntry.toString() ); } - // get the source - String source = getSource( getSourceTree( obfClassEntry.getName() ) ); - - // write the file - File file = new File( dirOut, deobfClassEntry.getName().replace( '.', '/' ) + ".java" ); - file.getParentFile().mkdirs(); - try( FileWriter out = new FileWriter( file ) ) + try + { + // get the source + String source = getSource( getSourceTree( obfClassEntry.getName() ) ); + + // write the file + File file = new File( dirOut, deobfClassEntry.getName().replace( '.', '/' ) + ".java" ); + file.getParentFile().mkdirs(); + try( FileWriter out = new FileWriter( file ) ) + { + out.write( source ); + } + } + catch( Throwable t ) { - out.write( source ); + throw new Error( "Unable to deobfuscate class " + deobfClassEntry.toString() + " (" + obfClassEntry.toString() + ")", t ); } } diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index e70093eb..d321421a 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -124,10 +124,11 @@ public class TranslatingTypeLoader implements ITypeLoader ClassEntry obfClassEntry = m_obfuscatingTranslator.translateEntry( deobfClassEntry ); // is this an inner class referenced directly? - if( m_jarIndex.getOuterClass( obfClassEntry.getName() ) != null ) + String obfOuterClassName = m_jarIndex.getOuterClass( obfClassEntry.getName() ); + if( obfOuterClassName != null ) { // this class doesn't really exist. Reference it by outer$inner instead - System.err.println( String.format( "WARNING: class %s referenced by bare inner name", deobfClassName ) ); + System.err.println( String.format( "WARNING: class %s referenced by bare inner name instead of via outer class %s", deobfClassName, obfOuterClassName ) ); return null; } @@ -210,6 +211,9 @@ public class TranslatingTypeLoader implements ITypeLoader // sanity checking assertClassName( c, deobfClassEntry ); + // DEBUG + Util.writeClass( c ); + // we have a transformed class! return c.toBytecode(); } diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 7fac02de..1995cb80 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -162,11 +162,7 @@ public class Gui @Override public void onSelectClass( ClassEntry classEntry ) { - if( m_reference != null ) - { - m_controller.savePreviousReference( m_reference ); - } - m_controller.openDeclaration( classEntry ); + navigateTo( classEntry ); } } ); JScrollPane obfScroller = new JScrollPane( m_obfClasses ); @@ -182,11 +178,7 @@ public class Gui @Override public void onSelectClass( ClassEntry classEntry ) { - if( m_reference != null ) - { - m_controller.savePreviousReference( m_reference ); - } - m_controller.openDeclaration( classEntry ); + navigateTo( classEntry ); } } ); JScrollPane deobfScroller = new JScrollPane( m_deobfClasses ); @@ -247,7 +239,7 @@ public class Gui break; case KeyEvent.VK_N: - openDeclaration(); + navigateTo( m_reference.entry ); break; case KeyEvent.VK_P: @@ -335,7 +327,7 @@ public class Gui @Override public void actionPerformed( ActionEvent event ) { - openDeclaration(); + navigateTo( m_reference.entry ); } } ); menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_N, 0 ) ); @@ -379,22 +371,15 @@ public class Gui Object node = path.getLastPathComponent(); if( node instanceof ClassInheritanceTreeNode ) { - if( m_reference != null ) - { - m_controller.savePreviousReference( m_reference ); - } - m_controller.openDeclaration( new ClassEntry( ((ClassInheritanceTreeNode)node).getObfClassName() ) ); + ClassInheritanceTreeNode classNode = (ClassInheritanceTreeNode)node; + navigateTo( new ClassEntry( classNode.getObfClassName() ) ); } else if( node instanceof MethodInheritanceTreeNode ) { MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode)node; if( methodNode.isImplemented() ) { - if( m_reference != null ) - { - m_controller.savePreviousReference( m_reference ); - } - m_controller.openDeclaration( methodNode.getMethodEntry() ); + navigateTo( methodNode.getMethodEntry() ); } } } @@ -425,12 +410,12 @@ public class Gui if( node instanceof ClassImplementationsTreeNode ) { ClassImplementationsTreeNode classNode = (ClassImplementationsTreeNode)node; - m_controller.openDeclaration( classNode.getClassEntry() ); + navigateTo( classNode.getClassEntry() ); } else if( node instanceof MethodImplementationsTreeNode ) { MethodImplementationsTreeNode methodNode = (MethodImplementationsTreeNode)node; - m_controller.openDeclaration( methodNode.getMethodEntry() ); + navigateTo( methodNode.getMethodEntry() ); } } } @@ -460,18 +445,14 @@ public class Gui Object node = path.getLastPathComponent(); if( node instanceof ReferenceTreeNode ) { - if( m_reference != null ) - { - m_controller.savePreviousReference( m_reference ); - } ReferenceTreeNode referenceNode = ((ReferenceTreeNode)node); if( referenceNode.getReference() != null ) { - m_controller.openReference( referenceNode.getReference() ); + navigateTo( referenceNode.getReference() ); } else { - m_controller.openDeclaration( referenceNode.getEntry() ); + navigateTo( referenceNode.getEntry() ); } } } @@ -1028,6 +1009,7 @@ public class Gui boolean isFieldEntry = isToken && m_reference.entry instanceof FieldEntry; boolean isMethodEntry = isToken && m_reference.entry instanceof MethodEntry; boolean isConstructorEntry = isToken && m_reference.entry instanceof ConstructorEntry; + boolean isInJar = isToken && m_controller.entryIsInJar( m_reference.entry.getClassEntry() ); if( isToken ) { @@ -1038,14 +1020,42 @@ public class Gui clearReference(); } - m_renameMenu.setEnabled( isToken ); + m_renameMenu.setEnabled( isInJar && isToken ); m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry || isConstructorEntry ); m_showImplementationsMenu.setEnabled( isClassEntry || isMethodEntry ); m_showCallsMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); - m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); + m_openEntryMenu.setEnabled( isInJar && ( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ) ); m_openPreviousMenu.setEnabled( m_controller.hasPreviousLocation() ); } + private void navigateTo( Entry entry ) + { + if( !m_controller.entryIsInJar( entry ) ) + { + // entry is not in the jar. Ignore it + return; + } + if( m_reference != null ) + { + m_controller.savePreviousReference( m_reference ); + } + m_controller.openDeclaration( entry ); + } + + private void navigateTo( EntryReference reference ) + { + if( !m_controller.entryIsInJar( reference.getClassEntry() ) ) + { + // reference is not in the jar. Ignore it + return; + } + if( m_reference != null ) + { + m_controller.savePreviousReference( m_reference ); + } + m_controller.openReference( reference ); + } + private void startRename( ) { // init the text box @@ -1232,16 +1242,6 @@ public class Gui return new TreePath( nodes.toArray() ); } - private void openDeclaration( ) - { - if( m_reference == null ) - { - return; - } - m_controller.savePreviousReference( m_reference ); - m_controller.openDeclaration( m_reference.entry ); - } - private void close( ) { if( !m_controller.isDirty() ) diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index c0fb2e40..3f54ecd4 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -170,7 +170,7 @@ public class GuiController return m_deobfuscator.hasMapping( m_deobfuscator.obfuscateEntry( deobfEntry ) ); } - public boolean entryIsObfuscatedIdenfitier( Entry deobfEntry ) + public boolean entryIsInJar( Entry deobfEntry ) { return m_deobfuscator.isObfuscatedIdentifier( m_deobfuscator.obfuscateEntry( deobfEntry ) ); } @@ -268,6 +268,10 @@ public class GuiController // get the reference target class EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); ClassEntry obfClassEntry = obfReference.getClassEntry().getOuterClassEntry(); + if( !m_deobfuscator.isObfuscatedIdentifier( obfClassEntry ) ) + { + throw new IllegalArgumentException( "Entry must be in the jar!" ); + } if( m_currentObfClass == null || !m_currentObfClass.equals( obfClassEntry ) ) { // deobfuscate the class, then navigate to the reference @@ -347,6 +351,11 @@ public class GuiController { // decompile,deobfuscate the bytecode CompilationUnit sourceTree = m_deobfuscator.getSourceTree( classEntry.getClassName() ); + if( sourceTree == null ) + { + // decompilation of this class is not supported + return; + } String source = m_deobfuscator.getSource( sourceTree ); m_index = m_deobfuscator.getSourceIndex( sourceTree, source ); m_gui.setSource( m_index.getSource() ); @@ -365,7 +374,7 @@ public class GuiController { deobfuscatedTokens.add( token ); } - else if( entryIsObfuscatedIdenfitier( reference.entry ) ) + else if( entryIsInJar( reference.entry ) ) { obfuscatedTokens.add( token ); } -- cgit v1.2.3 From a628fb9396d10cfbeb03c88cb1c2c119ae202a21 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 18 Sep 2014 22:41:25 -0400 Subject: fixed crash with jar loading --- src/cuchaz/enigma/bytecode/ClassRenamer.java | 20 ++++++++++++++++++-- src/cuchaz/enigma/mapping/ClassEntry.java | 4 ++-- 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java index efe22a18..86a0433b 100644 --- a/src/cuchaz/enigma/bytecode/ClassRenamer.java +++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java @@ -74,7 +74,7 @@ public class ClassRenamer } } - public static Set getAllClassEntries( CtClass c ) + public static Set getAllClassEntries( final CtClass c ) { // get the classes that javassist knows about final Set entries = Sets.newHashSet(); @@ -85,7 +85,23 @@ public class ClassRenamer { if( obj instanceof String ) { - entries.add( new ClassEntry( (String)obj ) ); + String str = (String)obj; + + // javassist throws a lot of weird things at this map + // I either have to implement my on class scanner, or just try to filter out the weirdness + // I'm opting to filter out the weirdness for now + + // skip anything with generic arguments + if( str.indexOf( '<' ) >= 0 || str.indexOf( '>' ) >= 0 || str.indexOf( ';' ) >= 0 ) + { + return null; + } + + // convert path/to/class.inner to path/to/class$inner + str = str.replace( '.', '$' ); + + // remember everything else + entries.add( new ClassEntry( str ) ); } return null; } diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index f8477c92..c6faa506 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -27,14 +27,14 @@ public class ClassEntry implements Entry, Serializable } if( className.indexOf( '.' ) >= 0 ) { - throw new IllegalArgumentException( "Class name must be in JVM format. ie, path/to/package/class$inner" ); + throw new IllegalArgumentException( "Class name must be in JVM format. ie, path/to/package/class$inner : " + className ); } m_name = className; if( isInnerClass() && getInnerClassName().indexOf( '/' ) >= 0 ) { - throw new IllegalArgumentException( "Inner class must not have a package: " + getInnerClassName() ); + throw new IllegalArgumentException( "Inner class must not have a package: " + className ); } } -- cgit v1.2.3 From 725da3d2b3c4e4410ccbd661e83230b357428fab Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 18 Sep 2014 23:03:19 -0400 Subject: fixed issue with inner class detection --- src/cuchaz/enigma/analysis/JarIndex.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index f4843164..6c955bcd 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -417,12 +417,11 @@ public class JarIndex continue; } + ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); + ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getMethodInfo().getDescriptor() ); + // who calls this constructor? Set callerClasses = Sets.newHashSet(); - ConstructorEntry constructorEntry = new ConstructorEntry( - new ClassEntry( Descriptor.toJvmName( c.getName() ) ), - constructor.getMethodInfo().getDescriptor() - ); for( EntryReference reference : getBehaviorReferences( constructorEntry ) ) { callerClasses.add( reference.context.getClassEntry() ); @@ -431,7 +430,13 @@ public class JarIndex // is this called by exactly one class? if( callerClasses.size() == 1 ) { - return callerClasses.iterator().next().getName(); + ClassEntry callerClassEntry = callerClasses.iterator().next(); + + // does this class make sense as an outer class? + if( !callerClassEntry.equals( classEntry ) ) + { + return callerClassEntry.getName(); + } } else if( callerClasses.size() > 1 ) { -- cgit v1.2.3 From 7106c3a4b546aca645a19d40216185d6723409bc Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 20 Sep 2014 12:56:50 -0400 Subject: added warning message to the crash dialog about choosing exit --- src/cuchaz/enigma/gui/CrashDialog.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/CrashDialog.java b/src/cuchaz/enigma/gui/CrashDialog.java index 501080ec..0eb9830c 100644 --- a/src/cuchaz/enigma/gui/CrashDialog.java +++ b/src/cuchaz/enigma/gui/CrashDialog.java @@ -57,6 +57,7 @@ public class CrashDialog FlowLayout buttonsLayout = new FlowLayout(); buttonsLayout.setAlignment( FlowLayout.RIGHT ); buttonsPanel.setLayout( buttonsLayout ); + buttonsPanel.add( GuiTricks.unboldLabel( new JLabel( "If you choose exit, you will lose any unsaved work." ) ) ); JButton ignoreButton = new JButton( "Ignore" ); ignoreButton.addActionListener( new ActionListener( ) { -- cgit v1.2.3 From a8d0f97c270e32653aa246d7437478885077e24d Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 20 Sep 2014 17:11:25 -0400 Subject: cleaned up imports. I have no idea why Eclipse likes importing jcommander classes instead of guava classes, but it's annoyong! --- src/cuchaz/enigma/Deobfuscator.java | 2 +- src/cuchaz/enigma/TranslatingTypeLoader.java | 5 +++-- src/cuchaz/enigma/analysis/EntryRenamer.java | 2 +- src/cuchaz/enigma/analysis/JarClassIterator.java | 2 +- src/cuchaz/enigma/bytecode/BytecodeTools.java | 2 +- src/cuchaz/enigma/bytecode/ClassRenamer.java | 2 +- src/cuchaz/enigma/bytecode/ClassTranslator.java | 2 +- src/cuchaz/enigma/convert/ClassIdentity.java | 2 +- src/cuchaz/enigma/convert/ClassMatcher.java | 4 ++-- src/cuchaz/enigma/convert/ClassMatching.java | 4 ++-- src/cuchaz/enigma/convert/ClassNamer.java | 2 +- src/cuchaz/enigma/gui/ClassSelector.java | 4 ++-- src/cuchaz/enigma/mapping/Mappings.java | 2 +- src/cuchaz/enigma/mapping/Translator.java | 2 +- 14 files changed, 19 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 1178ed60..1d6f02c9 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -22,8 +22,8 @@ import java.util.jar.JarFile; import javassist.bytecode.Descriptor; -import com.beust.jcommander.internal.Sets; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.strobel.assembler.metadata.MetadataSystem; import com.strobel.assembler.metadata.TypeDefinition; import com.strobel.decompiler.DecompilerContext; diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index d321421a..8b969857 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -13,6 +13,7 @@ package cuchaz.enigma; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -24,7 +25,7 @@ import javassist.CtClass; import javassist.NotFoundException; import javassist.bytecode.Descriptor; -import com.beust.jcommander.internal.Maps; +import com.google.common.collect.Maps; import com.strobel.assembler.metadata.Buffer; import com.strobel.assembler.metadata.ClasspathTypeLoader; import com.strobel.assembler.metadata.ITypeLoader; @@ -212,7 +213,7 @@ public class TranslatingTypeLoader implements ITypeLoader assertClassName( c, deobfClassEntry ); // DEBUG - Util.writeClass( c ); + //Util.writeClass( c ); // we have a transformed class! return c.toBytecode(); diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java index 4b2c0b78..e9483caa 100644 --- a/src/cuchaz/enigma/analysis/EntryRenamer.java +++ b/src/cuchaz/enigma/analysis/EntryRenamer.java @@ -16,7 +16,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import com.beust.jcommander.internal.Lists; +import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; diff --git a/src/cuchaz/enigma/analysis/JarClassIterator.java b/src/cuchaz/enigma/analysis/JarClassIterator.java index 10ae8052..f65b8e79 100644 --- a/src/cuchaz/enigma/analysis/JarClassIterator.java +++ b/src/cuchaz/enigma/analysis/JarClassIterator.java @@ -25,7 +25,7 @@ import javassist.CtClass; import javassist.NotFoundException; import javassist.bytecode.Descriptor; -import com.beust.jcommander.internal.Lists; +import com.google.common.collect.Lists; import cuchaz.enigma.Constants; import cuchaz.enigma.mapping.ClassEntry; diff --git a/src/cuchaz/enigma/bytecode/BytecodeTools.java b/src/cuchaz/enigma/bytecode/BytecodeTools.java index 0de9bd6b..4407a904 100644 --- a/src/cuchaz/enigma/bytecode/BytecodeTools.java +++ b/src/cuchaz/enigma/bytecode/BytecodeTools.java @@ -26,7 +26,7 @@ import javassist.bytecode.CodeAttribute; import javassist.bytecode.ConstPool; import javassist.bytecode.ExceptionTable; -import com.beust.jcommander.internal.Lists; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java index 86a0433b..9f0845da 100644 --- a/src/cuchaz/enigma/bytecode/ClassRenamer.java +++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java @@ -20,8 +20,8 @@ import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; import javassist.bytecode.InnerClassesAttribute; -import com.beust.jcommander.internal.Sets; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.SignatureUpdater; diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index 885b45fe..88926928 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java @@ -19,7 +19,7 @@ import javassist.CtMethod; import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; -import com.beust.jcommander.internal.Maps; +import com.google.common.collect.Maps; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.FieldEntry; diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java index b3b043e5..1de345ff 100644 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ b/src/cuchaz/enigma/convert/ClassIdentity.java @@ -34,9 +34,9 @@ import javassist.expr.FieldAccess; import javassist.expr.MethodCall; import javassist.expr.NewExpr; -import com.beust.jcommander.internal.Maps; import com.google.common.collect.HashMultiset; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import cuchaz.enigma.Constants; diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java index 135d076d..eb7a31df 100644 --- a/src/cuchaz/enigma/convert/ClassMatcher.java +++ b/src/cuchaz/enigma/convert/ClassMatcher.java @@ -29,13 +29,13 @@ import java.util.jar.JarFile; import javassist.CtBehavior; import javassist.CtClass; -import com.beust.jcommander.internal.Lists; -import com.beust.jcommander.internal.Sets; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; import cuchaz.enigma.TranslatingTypeLoader; import cuchaz.enigma.analysis.JarIndex; diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java index 5511902d..e45c0e1a 100644 --- a/src/cuchaz/enigma/convert/ClassMatching.java +++ b/src/cuchaz/enigma/convert/ClassMatching.java @@ -17,11 +17,11 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import com.beust.jcommander.internal.Lists; -import com.beust.jcommander.internal.Maps; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Multimap; public class ClassMatching diff --git a/src/cuchaz/enigma/convert/ClassNamer.java b/src/cuchaz/enigma/convert/ClassNamer.java index 1cd96657..a01aec5c 100644 --- a/src/cuchaz/enigma/convert/ClassNamer.java +++ b/src/cuchaz/enigma/convert/ClassNamer.java @@ -12,8 +12,8 @@ package cuchaz.enigma.convert; import java.util.Map; -import com.beust.jcommander.internal.Maps; import com.google.common.collect.BiMap; +import com.google.common.collect.Maps; public class ClassNamer { diff --git a/src/cuchaz/enigma/gui/ClassSelector.java b/src/cuchaz/enigma/gui/ClassSelector.java index c0f7f3c5..8365def1 100644 --- a/src/cuchaz/enigma/gui/ClassSelector.java +++ b/src/cuchaz/enigma/gui/ClassSelector.java @@ -23,9 +23,9 @@ import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; -import com.beust.jcommander.internal.Lists; -import com.beust.jcommander.internal.Maps; import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import cuchaz.enigma.mapping.ClassEntry; diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 99cb85f0..f855f580 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -20,8 +20,8 @@ import java.util.Map; import java.util.Set; import java.util.zip.GZIPInputStream; -import com.beust.jcommander.internal.Sets; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import cuchaz.enigma.Util; import cuchaz.enigma.analysis.TranslationIndex; diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index 659ce9a2..b438e08d 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -14,7 +14,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import com.beust.jcommander.internal.Maps; +import com.google.common.collect.Maps; import cuchaz.enigma.analysis.TranslationIndex; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; -- cgit v1.2.3 From 0cf045308d25ab020fe23d1d000cb36635f83a75 Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 20 Sep 2014 17:15:33 -0400 Subject: avoid some unnecessary work with inner classes --- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java index 2fb5fe0f..5044e065 100644 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -48,7 +48,7 @@ public class InnerClassWriter // write the inner classes if needed Collection obfInnerClassNames = m_jarIndex.getInnerClasses( obfOuterClassName ); - if( obfInnerClassNames != null ) + if( obfInnerClassNames != null && !obfInnerClassNames.isEmpty() ) { writeInnerClasses( c, obfOuterClassName, obfInnerClassNames ); } -- cgit v1.2.3 From 57b53fc267aa606ee4d1bde5512632c82cbab9c5 Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 20 Sep 2014 21:44:50 -0400 Subject: added token highlighting for things outside of the jar --- src/cuchaz/enigma/analysis/SourceIndex.java | 3 ++- src/cuchaz/enigma/gui/BoxHighlightPainter.java | 7 +++++-- src/cuchaz/enigma/gui/Gui.java | 9 +++++++-- src/cuchaz/enigma/gui/GuiController.java | 7 ++++++- src/cuchaz/enigma/gui/OtherHighlightPainter.java | 22 ++++++++++++++++++++++ 5 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 src/cuchaz/enigma/gui/OtherHighlightPainter.java (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index b777f9fd..fb5cc655 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -77,7 +77,7 @@ public class SourceIndex token.end -= pos + 1; } - // HACKHACK: sometimes node regions are off by one + /* HACKHACK: sometimes node regions are off by one // I think this is a bug in Procyon, but it's easy to work around if( !Character.isJavaIdentifierStart( m_source.charAt( token.start ) ) ) { @@ -88,6 +88,7 @@ public class SourceIndex throw new IllegalArgumentException( "Region " + region + " does not describe valid token: '" + m_source.substring( token.start, token.end ) + "'" ); } } + */ return token; } diff --git a/src/cuchaz/enigma/gui/BoxHighlightPainter.java b/src/cuchaz/enigma/gui/BoxHighlightPainter.java index 30b2b021..df63f5a8 100644 --- a/src/cuchaz/enigma/gui/BoxHighlightPainter.java +++ b/src/cuchaz/enigma/gui/BoxHighlightPainter.java @@ -36,8 +36,11 @@ public abstract class BoxHighlightPainter implements Highlighter.HighlightPainte Rectangle bounds = getBounds( text, start, end ); // fill the area - g.setColor( m_fillColor ); - g.fillRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); + if( m_fillColor != null ) + { + g.setColor( m_fillColor ); + g.fillRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); + } // draw a box around the area g.setColor( m_borderColor ); diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 1995cb80..5eed728a 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -102,6 +102,7 @@ public class Gui private JPanel m_infoPanel; private ObfuscatedHighlightPainter m_obfuscatedHighlightPainter; private DeobfuscatedHighlightPainter m_deobfuscatedHighlightPainter; + private OtherHighlightPainter m_otherHighlightPainter; private SelectionHighlightPainter m_selectionHighlightPainter; private JTree m_inheritanceTree; private JTree m_implementationsTree; @@ -205,6 +206,7 @@ public class Gui DefaultSyntaxKit.initKit(); m_obfuscatedHighlightPainter = new ObfuscatedHighlightPainter(); m_deobfuscatedHighlightPainter = new DeobfuscatedHighlightPainter(); + m_otherHighlightPainter = new OtherHighlightPainter(); m_selectionHighlightPainter = new SelectionHighlightPainter(); m_editor = new JEditorPane(); m_editor.setEditable( false ); @@ -870,12 +872,11 @@ public class Gui showToken( sortedTokens.get( 0 ) ); } - public void setHighlightedTokens( Iterable obfuscatedTokens, Iterable deobfuscatedTokens ) + public void setHighlightedTokens( Iterable obfuscatedTokens, Iterable deobfuscatedTokens, Iterable otherTokens ) { // remove any old highlighters m_editor.getHighlighter().removeAllHighlights(); - // color things based on the index if( obfuscatedTokens != null ) { @@ -885,6 +886,10 @@ public class Gui { setHighlightedTokens( deobfuscatedTokens, m_deobfuscatedHighlightPainter ); } + if( otherTokens != null ) + { + setHighlightedTokens( otherTokens, m_otherHighlightPainter ); + } redraw(); } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 3f54ecd4..bbefe606 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -367,6 +367,7 @@ public class GuiController // set the highlighted tokens List obfuscatedTokens = Lists.newArrayList(); List deobfuscatedTokens = Lists.newArrayList(); + List otherTokens = Lists.newArrayList(); for( Token token : m_index.referenceTokens() ) { EntryReference reference = m_index.getDeobfReference( token ); @@ -378,8 +379,12 @@ public class GuiController { obfuscatedTokens.add( token ); } + else + { + otherTokens.add( token ); + } } - m_gui.setHighlightedTokens( obfuscatedTokens, deobfuscatedTokens ); + m_gui.setHighlightedTokens( obfuscatedTokens, deobfuscatedTokens, otherTokens ); } }.start(); } diff --git a/src/cuchaz/enigma/gui/OtherHighlightPainter.java b/src/cuchaz/enigma/gui/OtherHighlightPainter.java new file mode 100644 index 00000000..78de7325 --- /dev/null +++ b/src/cuchaz/enigma/gui/OtherHighlightPainter.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 OtherHighlightPainter extends BoxHighlightPainter +{ + public OtherHighlightPainter( ) + { + // grey + super( null, new Color( 180, 180, 180 ) ); + } +} -- cgit v1.2.3 From 84d3bd601094a733900260ad2bd0577cf65978ab Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 20 Sep 2014 21:45:32 -0400 Subject: removed workaround for procyon bug --- src/cuchaz/enigma/analysis/SourceIndex.java | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index fb5cc655..49451b90 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -77,19 +77,6 @@ public class SourceIndex token.end -= pos + 1; } - /* HACKHACK: sometimes node regions are off by one - // I think this is a bug in Procyon, but it's easy to work around - if( !Character.isJavaIdentifierStart( m_source.charAt( token.start ) ) ) - { - token.start++; - token.end++; - if( !Character.isJavaIdentifierStart( m_source.charAt( token.start ) ) ) - { - throw new IllegalArgumentException( "Region " + region + " does not describe valid token: '" + m_source.substring( token.start, token.end ) + "'" ); - } - } - */ - return token; } -- cgit v1.2.3 From 8409dea980fa03c06b180969c5e0696f7cb5474b Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 21 Sep 2014 00:32:03 -0400 Subject: started unit testing for inner/anonymous class detection --- src/cuchaz/enigma/analysis/JarIndex.java | 181 +++++++++++++++++------- src/cuchaz/enigma/mapping/SignatureUpdater.java | 18 +++ 2 files changed, 148 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 6c955bcd..43e2bf62 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -48,6 +48,7 @@ import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.SignatureUpdater; import cuchaz.enigma.mapping.Translator; public class JarIndex @@ -56,6 +57,7 @@ public class JarIndex private TranslationIndex m_translationIndex; private Multimap m_interfaces; private Map m_access; + private Map m_fieldClasses; private Multimap m_methodImplementations; private Multimap> m_behaviorReferences; private Multimap> m_fieldReferences; @@ -70,6 +72,7 @@ public class JarIndex m_translationIndex = new TranslationIndex(); m_interfaces = HashMultimap.create(); m_access = Maps.newHashMap(); + m_fieldClasses = Maps.newHashMap(); m_methodImplementations = HashMultimap.create(); m_behaviorReferences = HashMultimap.create(); m_fieldReferences = HashMultimap.create(); @@ -127,7 +130,7 @@ public class JarIndex } for( CtField field : c.getDeclaredFields() ) { - m_translationIndex.addField( className, field.getName() ); + indexField( field ); } for( CtBehavior behavior : c.getDeclaredBehaviors() ) { @@ -193,6 +196,22 @@ public class JarIndex EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences ); } + private void indexField( CtField field ) + { + // get the field entry + String className = Descriptor.toJvmName( field.getDeclaringClass().getName() ); + FieldEntry fieldEntry = new FieldEntry( new ClassEntry( className ), field.getName() ); + + m_translationIndex.addField( className, field.getName() ); + + // is the field a class type? + if( field.getSignature().startsWith( "L" ) ) + { + ClassEntry fieldTypeEntry = new ClassEntry( field.getSignature().substring( 1, field.getSignature().length() - 1 ) ); + m_fieldClasses.put( fieldEntry, fieldTypeEntry ); + } + } + private void indexBehavior( CtBehavior behavior ) { // get the behavior entry @@ -412,7 +431,8 @@ public class JarIndex // use the synthetic fields to find the synthetic constructors for( CtConstructor constructor : c.getDeclaredConstructors() ) { - if( !isIllegalConstructor( constructor ) ) + Set syntheticFieldTypes = Sets.newHashSet(); + if( !isIllegalConstructor( syntheticFieldTypes, constructor ) ) { continue; } @@ -420,27 +440,57 @@ public class JarIndex ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getMethodInfo().getDescriptor() ); + // look at the synthetic types to get candidates for the outer class + Set candidateOuterClasses = Sets.newHashSet(); + for( String type : syntheticFieldTypes ) + { + if( type.startsWith( "L" ) ) + { + candidateOuterClasses.add( new ClassEntry( type.substring( 1, type.length() - 1 ) ) ); + } + } + + // do we have an answer yet? + if( candidateOuterClasses.isEmpty() ) + { + continue; + } + else if( candidateOuterClasses.size() == 1 ) + { + ClassEntry outerClassEntry = candidateOuterClasses.iterator().next(); + + // does this class make sense as an outer class? + if( !outerClassEntry.equals( classEntry ) ) + { + return outerClassEntry.getName(); + } + } + // who calls this constructor? Set callerClasses = Sets.newHashSet(); for( EntryReference reference : getBehaviorReferences( constructorEntry ) ) { - callerClasses.add( reference.context.getClassEntry() ); + // is that one of our candidates? + if( candidateOuterClasses.contains( reference.context.getClassEntry() ) ) + { + callerClasses.add( reference.context.getClassEntry() ); + } } - // is this called by exactly one class? + // do we have an answer yet? if( callerClasses.size() == 1 ) { - ClassEntry callerClassEntry = callerClasses.iterator().next(); + ClassEntry outerClassEntry = callerClasses.iterator().next(); // does this class make sense as an outer class? - if( !callerClassEntry.equals( classEntry ) ) + if( !outerClassEntry.equals( classEntry ) ) { - return callerClassEntry.getName(); + return outerClassEntry.getName(); } } - else if( callerClasses.size() > 1 ) + else { - System.out.println( "WARNING: Illegal constructor called by more than one class!" + callerClasses ); + System.out.println( "WARNING: Unable to choose outer class among options: " + candidateOuterClasses ); } } @@ -448,7 +498,7 @@ public class JarIndex } @SuppressWarnings( "unchecked" ) - private boolean isIllegalConstructor( CtConstructor constructor ) + private boolean isIllegalConstructor( Set syntheticFieldTypes, CtConstructor constructor ) { // illegal constructors only set synthetic member fields, then call super() String className = constructor.getDeclaringClass().getName(); @@ -456,7 +506,6 @@ public class JarIndex // collect all the field accesses, constructor calls, and method calls final List illegalFieldWrites = Lists.newArrayList(); final List constructorCalls = Lists.newArrayList(); - final List methodCalls = Lists.newArrayList(); try { constructor.instrument( new ExprEditor( ) @@ -475,12 +524,6 @@ public class JarIndex { constructorCalls.add( constructorCall ); } - - @Override - public void edit( MethodCall methodCall ) - { - methodCalls.add( methodCall ); - } } ); } catch( CannotCompileException ex ) @@ -489,25 +532,6 @@ public class JarIndex throw new Error( ex ); } - // method calls are not allowed - if( !methodCalls.isEmpty() ) - { - return false; - } - - // is there only one constructor call? - if( constructorCalls.size() != 1 ) - { - return false; - } - - // is the call to super? - ConstructorCall constructorCall = constructorCalls.get( 0 ); - if( !constructorCall.getMethodName().equals( "super" ) ) - { - return false; - } - // are there any illegal field writes? if( illegalFieldWrites.isEmpty() ) { @@ -528,7 +552,7 @@ public class JarIndex FieldInfo fieldInfo = null; for( FieldInfo info : (List)constructor.getDeclaringClass().getClassFile().getFields() ) { - if( info.getName().equals( fieldWrite.getFieldName() ) ) + if( info.getName().equals( fieldWrite.getFieldName() ) && info.getDescriptor().equals( fieldWrite.getSignature() ) ) { fieldInfo = info; break; @@ -542,9 +566,13 @@ public class JarIndex // is this field synthetic? boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; - if( !isSynthetic ) + if( isSynthetic ) + { + syntheticFieldTypes.add( fieldInfo.getDescriptor() ); + } + else { - System.err.println( String.format( "WARNING: illegal write to non synthetic field %s.%s", className, fieldInfo.getName() ) ); + System.err.println( String.format( "WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName() ) ); return false; } } @@ -555,15 +583,15 @@ public class JarIndex private boolean isAnonymousClass( CtClass c, String outerClassName ) { - String innerClassName = Descriptor.toJvmName( c.getName() ); + ClassEntry innerClassEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); // anonymous classes: // can't be abstract // have only one constructor // it's called exactly once by the outer class - // type of inner class not referenced anywhere in outer class + // the type the instance is assigned to can't be this type - // is absract? + // is abstract? if( Modifier.isAbstract( c.getModifiers() ) ) { return false; @@ -577,22 +605,40 @@ public class JarIndex CtConstructor constructor = c.getDeclaredConstructors()[0]; // is this constructor called exactly once? - ConstructorEntry constructorEntry = new ConstructorEntry( - new ClassEntry( innerClassName ), - constructor.getMethodInfo().getDescriptor() - ); - if( getBehaviorReferences( constructorEntry ).size() != 1 ) + ConstructorEntry constructorEntry = new ConstructorEntry( innerClassEntry, constructor.getMethodInfo().getDescriptor() ); + Collection> references = getBehaviorReferences( constructorEntry ); + if( references.size() != 1 ) { return false; } - // TODO: check outer class doesn't reference type - // except this is hard because we can't just load the outer class now - // we'd have to pre-index those references in the JarIndex + // does the caller use this type? + BehaviorEntry caller = references.iterator().next().context; + for( FieldEntry fieldEntry : getReferencedFields( caller ) ) + { + ClassEntry fieldClass = getFieldClass( fieldEntry ); + if( fieldClass != null && fieldClass.equals( innerClassEntry ) ) + { + // caller references this type, so it can't be anonymous + return false; + } + } + for( BehaviorEntry behaviorEntry : getReferencedBehaviors( caller ) ) + { + // get the class types from the signature + for( String className : SignatureUpdater.getClasses( behaviorEntry.getSignature() ) ) + { + if( className.equals( innerClassEntry.getName() ) ) + { + // caller references this type, so it can't be anonymous + return false; + } + } + } return true; } - + public Set getObfClassEntries( ) { return m_obfClassEntries; @@ -608,6 +654,11 @@ public class JarIndex return m_access.get( entry ); } + public ClassEntry getFieldClass( FieldEntry fieldEntry ) + { + return m_fieldClasses.get( fieldEntry ); + } + public boolean isMethodImplemented( MethodEntry methodEntry ) { Collection implementations = m_methodImplementations.get( methodEntry.getClassName() ); @@ -772,11 +823,39 @@ public class JarIndex return m_fieldReferences.get( fieldEntry ); } + public Collection getReferencedFields( BehaviorEntry behaviorEntry ) + { + // linear search is fast enough for now + Set fieldEntries = Sets.newHashSet(); + for( EntryReference reference : m_fieldReferences.values() ) + { + if( reference.context == behaviorEntry ) + { + fieldEntries.add( reference.entry ); + } + } + return fieldEntries; + } + public Collection> getBehaviorReferences( BehaviorEntry behaviorEntry ) { return m_behaviorReferences.get( behaviorEntry ); } + public Collection getReferencedBehaviors( BehaviorEntry behaviorEntry ) + { + // linear search is fast enough for now + Set behaviorEntries = Sets.newHashSet(); + for( EntryReference reference : m_behaviorReferences.values() ) + { + if( reference.context == behaviorEntry ) + { + behaviorEntries.add( reference.entry ); + } + } + return behaviorEntries; + } + public Collection getInnerClasses( String obfOuterClassName ) { return m_innerClasses.get( obfOuterClassName ); diff --git a/src/cuchaz/enigma/mapping/SignatureUpdater.java b/src/cuchaz/enigma/mapping/SignatureUpdater.java index 4c0dbac1..528a7437 100644 --- a/src/cuchaz/enigma/mapping/SignatureUpdater.java +++ b/src/cuchaz/enigma/mapping/SignatureUpdater.java @@ -12,6 +12,9 @@ package cuchaz.enigma.mapping; import java.io.IOException; import java.io.StringReader; +import java.util.List; + +import com.beust.jcommander.internal.Lists; public class SignatureUpdater { @@ -84,4 +87,19 @@ public class SignatureUpdater return null; } + + public static List getClasses( String signature ) + { + final List classNames = Lists.newArrayList(); + update( signature, new ClassNameUpdater( ) + { + @Override + public String update( String className ) + { + classNames.add( className ); + return className; + } + } ); + return classNames; + } } -- cgit v1.2.3 From df06f4ddde5e255750edc4087cfba54823404909 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 21 Sep 2014 22:08:05 -0400 Subject: improved inner/anonymous class detection --- src/cuchaz/enigma/analysis/JarIndex.java | 95 ++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 43e2bf62..c36e9cb0 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -440,29 +440,17 @@ public class JarIndex ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getMethodInfo().getDescriptor() ); - // look at the synthetic types to get candidates for the outer class - Set candidateOuterClasses = Sets.newHashSet(); + // gather the classes from the illegally-set synthetic fields + Set illegallySetClasses = Sets.newHashSet(); for( String type : syntheticFieldTypes ) { if( type.startsWith( "L" ) ) { - candidateOuterClasses.add( new ClassEntry( type.substring( 1, type.length() - 1 ) ) ); - } - } - - // do we have an answer yet? - if( candidateOuterClasses.isEmpty() ) - { - continue; - } - else if( candidateOuterClasses.size() == 1 ) - { - ClassEntry outerClassEntry = candidateOuterClasses.iterator().next(); - - // does this class make sense as an outer class? - if( !outerClassEntry.equals( classEntry ) ) - { - return outerClassEntry.getName(); + ClassEntry outerClassEntry = new ClassEntry( type.substring( 1, type.length() - 1 ) ); + if( isSaneOuterClass( outerClassEntry, classEntry ) ) + { + illegallySetClasses.add( outerClassEntry ); + } } } @@ -470,33 +458,82 @@ public class JarIndex Set callerClasses = Sets.newHashSet(); for( EntryReference reference : getBehaviorReferences( constructorEntry ) ) { - // is that one of our candidates? - if( candidateOuterClasses.contains( reference.context.getClassEntry() ) ) + // make sure it's not a call to super + if( reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry ) + { + // is the entry a superclass of the context? + String calledClassName = reference.entry.getClassName(); + String callerSuperclassName = m_translationIndex.getSuperclassName( reference.context.getClassName() ); + if( callerSuperclassName != null && callerSuperclassName.equals( calledClassName ) ) + { + // it's a super call, skip + continue; + } + } + + if( isSaneOuterClass( reference.context.getClassEntry(), classEntry ) ) { - callerClasses.add( reference.context.getClassEntry() ); + callerClasses.add( reference.context.getClassEntry() ); } } // do we have an answer yet? - if( callerClasses.size() == 1 ) + if( callerClasses.isEmpty() ) { - ClassEntry outerClassEntry = callerClasses.iterator().next(); - - // does this class make sense as an outer class? - if( !outerClassEntry.equals( classEntry ) ) + if( illegallySetClasses.size() == 1 ) { - return outerClassEntry.getName(); + return illegallySetClasses.iterator().next().getName(); + } + else + { + System.out.println( String.format( "WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry ) ); } } else { - System.out.println( "WARNING: Unable to choose outer class among options: " + candidateOuterClasses ); + if( callerClasses.size() == 1 ) + { + return callerClasses.iterator().next().getName(); + } + else + { + // multiple callers, do the illegally set classes narrow it down? + Set intersection = Sets.newHashSet( callerClasses ); + intersection.retainAll( illegallySetClasses ); + if( intersection.size() == 1 ) + { + return intersection.iterator().next().getName(); + } + else + { + System.out.println( String.format( "WARNING: Unable to choose outer class for %s among options: %s", + classEntry, callerClasses + ) ); + } + } } } return null; } + private boolean isSaneOuterClass( ClassEntry outerClassEntry, ClassEntry innerClassEntry ) + { + // clearly this would be silly + if( outerClassEntry.equals( innerClassEntry ) ) + { + return false; + } + + // is the outer class in the jar? + if( !m_obfClassEntries.contains( outerClassEntry ) ) + { + return false; + } + + return true; + } + @SuppressWarnings( "unchecked" ) private boolean isIllegalConstructor( Set syntheticFieldTypes, CtConstructor constructor ) { -- cgit v1.2.3 From 24ed3dc06bc133e4f718acc4a691e905b081fb11 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 21 Sep 2014 23:21:34 -0400 Subject: fixed bugs with anonymous/inner classes --- src/cuchaz/enigma/Deobfuscator.java | 16 ++--------- src/cuchaz/enigma/analysis/JarIndex.java | 31 +++++++++++++--------- .../analysis/SourceIndexBehaviorVisitor.java | 17 +++++++----- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 14 ++++++++++ src/cuchaz/enigma/mapping/SignatureUpdater.java | 2 +- 5 files changed, 46 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 1d6f02c9..9c845325 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -232,7 +232,7 @@ public class Deobfuscator sourceTree.acceptVisitor( new SourceIndexVisitor(), index ); // DEBUG - //root.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); + //sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); /* DEBUG for( Token token : index.referenceTokens() ) @@ -420,19 +420,7 @@ public class Deobfuscator { if( obfEntry instanceof ClassEntry ) { - ClassEntry obfClassEntry = (ClassEntry)obfEntry; - if( obfClassEntry.isInnerClass() ) - { - // both classes must be in the list - return m_jarIndex.getObfClassEntries().contains( obfClassEntry.getOuterClassEntry() ) - && m_jarIndex.getObfClassEntries().contains( obfClassEntry.getInnerClassName() ); - // TODO: make sure this works for the inner class!! - } - else - { - // class must be in the list - return m_jarIndex.getObfClassEntries().contains( obfEntry ); - } + return m_jarIndex.getObfClassEntries().contains( obfEntry ); } else { diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index c36e9cb0..8ebce35e 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -63,7 +63,7 @@ public class JarIndex private Multimap> m_fieldReferences; private Multimap m_innerClasses; private Map m_outerClasses; - private Set m_anonymousClasses; + private Map m_anonymousClasses; private Map m_bridgeMethods; public JarIndex( ) @@ -78,7 +78,7 @@ public class JarIndex m_fieldReferences = HashMultimap.create(); m_innerClasses = HashMultimap.create(); m_outerClasses = Maps.newHashMap(); - m_anonymousClasses = Sets.newHashSet(); + m_anonymousClasses = Maps.newHashMap(); m_bridgeMethods = Maps.newHashMap(); } @@ -161,9 +161,10 @@ public class JarIndex m_innerClasses.put( outerClassName, innerClassName ); m_outerClasses.put( innerClassName, outerClassName ); - if( isAnonymousClass( c, outerClassName ) ) + BehaviorEntry enclosingBehavior = isAnonymousClass( c, outerClassName ); + if( enclosingBehavior != null ) { - m_anonymousClasses.add( innerClassName ); + m_anonymousClasses.put( innerClassName, enclosingBehavior ); // DEBUG //System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); @@ -188,6 +189,7 @@ public class JarIndex EntryRenamer.renameClassesInMultimap( renames, m_methodImplementations ); EntryRenamer.renameClassesInMultimap( renames, m_behaviorReferences ); EntryRenamer.renameClassesInMultimap( renames, m_fieldReferences ); + EntryRenamer.renameClassesInMap( renames, m_bridgeMethods ); } // step 6: update other indices with bridge method info @@ -618,7 +620,7 @@ public class JarIndex return true; } - private boolean isAnonymousClass( CtClass c, String outerClassName ) + private BehaviorEntry isAnonymousClass( CtClass c, String outerClassName ) { ClassEntry innerClassEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); @@ -631,13 +633,13 @@ public class JarIndex // is abstract? if( Modifier.isAbstract( c.getModifiers() ) ) { - return false; + return null; } // is there exactly one constructor? if( c.getDeclaredConstructors().length != 1 ) { - return false; + return null; } CtConstructor constructor = c.getDeclaredConstructors()[0]; @@ -646,7 +648,7 @@ public class JarIndex Collection> references = getBehaviorReferences( constructorEntry ); if( references.size() != 1 ) { - return false; + return null; } // does the caller use this type? @@ -657,7 +659,7 @@ public class JarIndex if( fieldClass != null && fieldClass.equals( innerClassEntry ) ) { // caller references this type, so it can't be anonymous - return false; + return null; } } for( BehaviorEntry behaviorEntry : getReferencedBehaviors( caller ) ) @@ -668,12 +670,12 @@ public class JarIndex if( className.equals( innerClassEntry.getName() ) ) { // caller references this type, so it can't be anonymous - return false; + return null; } } } - return true; + return caller; } public Set getObfClassEntries( ) @@ -905,7 +907,12 @@ public class JarIndex public boolean isAnonymousClass( String obfInnerClassName ) { - return m_anonymousClasses.contains( obfInnerClassName ); + return m_anonymousClasses.containsKey( obfInnerClassName ); + } + + public BehaviorEntry getAnonymousClassCaller( String obfInnerClassName ) + { + return m_anonymousClasses.get( obfInnerClassName ); } public Set getInterfaces( String className ) diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index a1dac4b5..6238b1e7 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -177,14 +177,17 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor public Void visitObjectCreationExpression( ObjectCreationExpression node, SourceIndex index ) { MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); - ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); - ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, ref.getSignature() ); - if( node.getType() instanceof SimpleType ) + if( ref != null ) { - index.addReference( - ((SimpleType)node.getType()).getIdentifierToken(), - new EntryReference( constructorEntry, m_behaviorEntry ) - ); + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, ref.getSignature() ); + if( node.getType() instanceof SimpleType ) + { + index.addReference( + ((SimpleType)node.getType()).getIdentifierToken(), + new EntryReference( constructorEntry, m_behaviorEntry ) + ); + } } return recurse( node, index ); diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java index 5044e065..f94a85d7 100644 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -16,8 +16,10 @@ import javassist.CtClass; import javassist.bytecode.AccessFlag; import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; +import javassist.bytecode.EnclosingMethodAttribute; import javassist.bytecode.InnerClassesAttribute; import cuchaz.enigma.analysis.JarIndex; +import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; public class InnerClassWriter @@ -44,6 +46,18 @@ public class InnerClassWriter // this is an inner class, rename it to outer$inner ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + new ClassEntry( obfClassName ).getSimpleName() ); c.setName( obfClassEntry.getName() ); + + BehaviorEntry caller = m_jarIndex.getAnonymousClassCaller( obfClassName ); + if( caller != null ) + { + // write the enclosing method attribute + c.getClassFile().addAttribute( new EnclosingMethodAttribute( + c.getClassFile().getConstPool(), + caller.getClassName(), + caller.getName(), + caller.getSignature() + ) ); + } } // write the inner classes if needed diff --git a/src/cuchaz/enigma/mapping/SignatureUpdater.java b/src/cuchaz/enigma/mapping/SignatureUpdater.java index 528a7437..d1216bde 100644 --- a/src/cuchaz/enigma/mapping/SignatureUpdater.java +++ b/src/cuchaz/enigma/mapping/SignatureUpdater.java @@ -14,7 +14,7 @@ import java.io.IOException; import java.io.StringReader; import java.util.List; -import com.beust.jcommander.internal.Lists; +import com.google.common.collect.Lists; public class SignatureUpdater { -- cgit v1.2.3 From 89c287f39f432385febf97779f51c45a6c3eb51b Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 22 Sep 2014 23:35:02 -0400 Subject: fix bug with anonymous classes in class initializers --- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java index f94a85d7..a0617925 100644 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -51,12 +51,22 @@ public class InnerClassWriter if( caller != null ) { // write the enclosing method attribute - c.getClassFile().addAttribute( new EnclosingMethodAttribute( - c.getClassFile().getConstPool(), - caller.getClassName(), - caller.getName(), - caller.getSignature() - ) ); + if( caller.getName().equals( "" ) ) + { + c.getClassFile().addAttribute( new EnclosingMethodAttribute( + c.getClassFile().getConstPool(), + caller.getClassName() + ) ); + } + else + { + c.getClassFile().addAttribute( new EnclosingMethodAttribute( + c.getClassFile().getConstPool(), + caller.getClassName(), + caller.getName(), + caller.getSignature() + ) ); + } } } -- cgit v1.2.3 From a09a23871abaf2f0c8c1636ee6dd2f9eaf2474b0 Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 23 Sep 2014 01:01:42 -0400 Subject: trying to figure out why some mappings to correspond to anything in the jar file... --- src/cuchaz/enigma/Deobfuscator.java | 102 ++++++++++++++++++++++----- src/cuchaz/enigma/analysis/EntryRenamer.java | 4 -- src/cuchaz/enigma/analysis/JarIndex.java | 14 ++-- src/cuchaz/enigma/mapping/ClassMapping.java | 22 ++++++ 4 files changed, 117 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 9c845325..03c35113 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -22,6 +22,7 @@ import java.util.jar.JarFile; import javassist.bytecode.Descriptor; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.strobel.assembler.metadata.MetadataSystem; @@ -44,6 +45,7 @@ import cuchaz.enigma.mapping.ClassMapping; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.FieldMapping; import cuchaz.enigma.mapping.Mappings; import cuchaz.enigma.mapping.MappingsRenamer; import cuchaz.enigma.mapping.MethodEntry; @@ -113,41 +115,107 @@ public class Deobfuscator val = new Mappings(); } - // make sure all the mappings match the classes in the jar + // look for any classes that got moved to inner classes + Map renames = Maps.newHashMap(); for( ClassMapping classMapping : val.classes() ) { - ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); - if( !m_jarIndex.getObfClassEntries().contains( classEntry ) ) + String outerClassName = m_jarIndex.getOuterClass( classMapping.getObfName() ); + if( outerClassName != null ) { - throw new Error( "Class " + classEntry + " not found in Jar!" ); + // build the composite class name + String newName = outerClassName + "$" + new ClassEntry( classMapping.getObfName() ).getSimpleName(); + + // add a rename + renames.put( classMapping.getObfName(), newName ); + + System.out.println( String.format( "Converted class mapping %s to %s", classMapping.getObfName(), newName ) ); } - - // and method implementations - for( MethodMapping methodMapping : classMapping.methods() ) + } + for( Map.Entry entry : renames.entrySet() ) + { + val.renameObfClass( entry.getKey(), entry.getValue() ); + } + + // drop mappings that don't match the jar + List unknownClasses = Lists.newArrayList(); + for( ClassMapping classMapping : val.classes() ) + { + checkClassMapping( unknownClasses, classMapping ); + } + if( !unknownClasses.isEmpty() ) + { + throw new Error( "Unable to find classes in jar: " + unknownClasses ); + } + + m_mappings = val; + m_renamer = new MappingsRenamer( m_jarIndex, m_mappings ); + m_translatorCache.clear(); + } + + private void checkClassMapping( List unknownClasses, ClassMapping classMapping ) + { + // check the class + ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); + String outerClassName = m_jarIndex.getOuterClass( classMapping.getObfName() ); + if( outerClassName != null ) + { + classEntry = new ClassEntry( outerClassName + "$" + classEntry.getSimpleName() ); + } + if( !m_jarIndex.getObfClassEntries().contains( classEntry ) ) + { + unknownClasses.add( classEntry ); + } + + // check the fields + for( FieldMapping fieldMapping : Lists.newArrayList( classMapping.fields() ) ) + { + FieldEntry fieldEntry = new FieldEntry( classEntry, fieldMapping.getObfName() ); + if( m_jarIndex.getAccess( fieldEntry ) == null ) + { + System.err.println( "WARNING: unable to find field " + fieldEntry + ". dropping mapping." ); + classMapping.removeFieldMapping( fieldMapping ); + } + } + + // check methods + for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) + { + if( methodMapping.getObfName().equals( "" ) ) + { + // skip static initializers + continue; + } + else if( methodMapping.getObfName().equals( "" ) ) { - if( methodMapping.getObfName().startsWith( "<" ) ) + ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, methodMapping.getObfSignature() ); + if( m_jarIndex.getAccess( constructorEntry ) == null ) { - // skip constructors and static initializers - continue; + System.err.println( "WARNING: unable to find constructor " + constructorEntry + ". dropping mapping." ); + classMapping.removeMethodMapping( methodMapping ); } - + } + else + { MethodEntry methodEntry = new MethodEntry( classEntry, methodMapping.getObfName(), methodMapping.getObfSignature() ); - if( !m_jarIndex.isMethodImplemented( methodEntry ) ) + if( m_jarIndex.getAccess( methodEntry ) == null ) { - throw new Error( "Method " + methodEntry + " not found in Jar!" ); + System.err.println( "WARNING: unable to find method " + methodEntry + ". dropping mapping." ); + classMapping.removeMethodMapping( methodMapping ); } } } - m_mappings = val; - m_renamer = new MappingsRenamer( m_jarIndex, m_mappings ); - m_translatorCache.clear(); + // check inner classes + for( ClassMapping innerClassMapping : classMapping.innerClasses() ) + { + checkClassMapping( unknownClasses, innerClassMapping ); + } } - + public Translator getTranslator( TranslationDirection direction ) { Translator translator = m_translatorCache.get( direction ); diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java index e9483caa..b82b2547 100644 --- a/src/cuchaz/enigma/analysis/EntryRenamer.java +++ b/src/cuchaz/enigma/analysis/EntryRenamer.java @@ -189,10 +189,6 @@ public class EntryRenamer reference.context = renameClassesInThing( renames, reference.context ); return thing; } - else - { - throw new Error( "Not an entry: " + thing ); - } return thing; } diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 8ebce35e..b51428a2 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -95,7 +95,7 @@ public class JarIndex m_obfClassEntries.add( classEntry ); } - // step 2: index method/field access + // step 2: index field/method/constructor access for( CtClass c : JarClassIterator.classes( jar ) ) { ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); @@ -105,10 +105,15 @@ public class JarIndex FieldEntry fieldEntry = new FieldEntry( classEntry, field.getName() ); m_access.put( fieldEntry, Access.get( field ) ); } - for( CtBehavior behavior : c.getDeclaredBehaviors() ) + for( CtMethod method : c.getDeclaredMethods() ) + { + MethodEntry methodEntry = new MethodEntry( classEntry, method.getName(), method.getSignature() ); + m_access.put( methodEntry, Access.get( method ) ); + } + for( CtConstructor constructor : c.getDeclaredConstructors() ) { - MethodEntry methodEntry = new MethodEntry( classEntry, behavior.getName(), behavior.getSignature() ); - m_access.put( methodEntry, Access.get( behavior ) ); + ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getSignature() ); + m_access.put( constructorEntry, Access.get( constructor ) ); } } @@ -190,6 +195,7 @@ public class JarIndex EntryRenamer.renameClassesInMultimap( renames, m_behaviorReferences ); EntryRenamer.renameClassesInMultimap( renames, m_fieldReferences ); EntryRenamer.renameClassesInMap( renames, m_bridgeMethods ); + EntryRenamer.renameClassesInMap( renames, m_access ); } // step 6: update other indices with bridge method info diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index 200d9ca2..88006cff 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -155,6 +155,17 @@ public class ClassMapping implements Serializable, Comparable assert( deobfWasAdded ); assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() ); } + + public void removeFieldMapping( FieldMapping fieldMapping ) + { + boolean obfWasRemoved = m_fieldsByObf.remove( fieldMapping.getObfName() ) != null; + assert( obfWasRemoved ); + if( fieldMapping.getDeobfName() != null ) + { + boolean deobfWasRemoved = m_fieldsByDeobf.remove( fieldMapping.getDeobfName() ) != null; + assert( deobfWasRemoved ); + } + } public String getObfFieldName( String deobfName ) { @@ -225,6 +236,17 @@ public class ClassMapping implements Serializable, Comparable assert( m_methodsByObf.size() >= m_methodsByDeobf.size() ); } + public void removeMethodMapping( MethodMapping methodMapping ) + { + boolean obfWasRemoved = m_methodsByObf.remove( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ) ) != null; + assert( obfWasRemoved ); + if( methodMapping.getDeobfName() != null ) + { + boolean deobfWasRemoved = m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) ) != null; + assert( deobfWasRemoved ); + } + } + public MethodMapping getMethodByObf( String obfName, String signature ) { return m_methodsByObf.get( getMethodKey( obfName, signature ) ); -- cgit v1.2.3 From 8776a8ba38123c822530e5f659c626c8db616217 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 24 Sep 2014 01:00:54 -0400 Subject: HOW DO I WRITE SO MANY BUGS?!? --- src/cuchaz/enigma/Deobfuscator.java | 102 ++++++++++++++++----- src/cuchaz/enigma/analysis/EntryRenamer.java | 4 +- src/cuchaz/enigma/analysis/JarIndex.java | 102 +++++++++++++++------ .../analysis/MethodImplementationsTreeNode.java | 2 +- .../enigma/analysis/MethodInheritanceTreeNode.java | 2 +- src/cuchaz/enigma/analysis/SourceIndex.java | 9 ++ .../analysis/SourceIndexBehaviorVisitor.java | 18 +++- .../enigma/bytecode/MethodParameterWriter.java | 22 ++++- src/cuchaz/enigma/convert/ClassMatcher.java | 6 +- src/cuchaz/enigma/gui/Gui.java | 16 ++-- src/cuchaz/enigma/gui/GuiController.java | 3 +- src/cuchaz/enigma/mapping/ArgumentEntry.java | 43 ++++++--- src/cuchaz/enigma/mapping/ClassEntry.java | 18 ++-- src/cuchaz/enigma/mapping/ClassMapping.java | 34 ++++--- src/cuchaz/enigma/mapping/ConstructorEntry.java | 12 +++ src/cuchaz/enigma/mapping/Entry.java | 1 + src/cuchaz/enigma/mapping/FieldEntry.java | 6 ++ src/cuchaz/enigma/mapping/Mappings.java | 6 +- src/cuchaz/enigma/mapping/MappingsRenamer.java | 32 ++++++- src/cuchaz/enigma/mapping/MethodEntry.java | 6 ++ src/cuchaz/enigma/mapping/Translator.java | 2 +- 21 files changed, 335 insertions(+), 111 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 03c35113..f7f74480 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -39,6 +39,7 @@ import cuchaz.enigma.analysis.EntryReference; import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; +import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ClassMapping; @@ -115,7 +116,7 @@ public class Deobfuscator val = new Mappings(); } - // look for any classes that got moved to inner classes + // pass 1: look for any classes that got moved to inner classes Map renames = Maps.newHashMap(); for( ClassMapping classMapping : val.classes() ) { @@ -136,6 +137,53 @@ public class Deobfuscator val.renameObfClass( entry.getKey(), entry.getValue() ); } + // pass 2: look for fields/methods that are actually declared in superclasses + MappingsRenamer renamer = new MappingsRenamer( m_jarIndex, val ); + for( ClassMapping classMapping : val.classes() ) + { + ClassEntry obfClassEntry = new ClassEntry( classMapping.getObfName() ); + + // fields + for( FieldMapping fieldMapping : Lists.newArrayList( classMapping.fields() ) ) + { + FieldEntry fieldEntry = new FieldEntry( obfClassEntry, fieldMapping.getObfName() ); + ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( fieldEntry ); + if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( fieldEntry.getClassEntry() ) ) + { + boolean wasMoved = renamer.moveFieldToObfClass( classMapping, fieldMapping, resolvedObfClassEntry ); + if( wasMoved ) + { + System.out.println( String.format( "Moved field %s to class %s", fieldEntry, resolvedObfClassEntry ) ); + } + else + { + System.err.println( String.format( "WARNING: Would move field %s to class %s but the field was already there. Dropping instead.", fieldEntry, resolvedObfClassEntry ) ); + } + } + } + + // methods + for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) + { + MethodEntry methodEntry = new MethodEntry( obfClassEntry, methodMapping.getObfName(), methodMapping.getObfSignature() ); + ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( methodEntry ); + if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( methodEntry.getClassEntry() ) ) + { + boolean wasMoved = renamer.moveMethodToObfClass( classMapping, methodMapping, resolvedObfClassEntry ); + if( wasMoved ) + { + System.out.println( String.format( "Moved method %s to class %s", methodEntry, resolvedObfClassEntry ) ); + } + else + { + System.err.println( String.format( "WARNING: Would move method %s to class %s but the method was already there. Dropping instead.", methodEntry, resolvedObfClassEntry ) ); + } + } + } + + // TODO: recurse to inner classes? + } + // drop mappings that don't match the jar List unknownClasses = Lists.newArrayList(); for( ClassMapping classMapping : val.classes() ) @@ -148,7 +196,7 @@ public class Deobfuscator } m_mappings = val; - m_renamer = new MappingsRenamer( m_jarIndex, m_mappings ); + m_renamer = renamer; m_translatorCache.clear(); } @@ -170,7 +218,7 @@ public class Deobfuscator for( FieldMapping fieldMapping : Lists.newArrayList( classMapping.fields() ) ) { FieldEntry fieldEntry = new FieldEntry( classEntry, fieldMapping.getObfName() ); - if( m_jarIndex.getAccess( fieldEntry ) == null ) + if( !m_jarIndex.containsObfField( fieldEntry ) ) { System.err.println( "WARNING: unable to find field " + fieldEntry + ". dropping mapping." ); classMapping.removeFieldMapping( fieldMapping ); @@ -188,7 +236,7 @@ public class Deobfuscator else if( methodMapping.getObfName().equals( "" ) ) { ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, methodMapping.getObfSignature() ); - if( m_jarIndex.getAccess( constructorEntry ) == null ) + if( !m_jarIndex.containsObfBehavior( constructorEntry ) ) { System.err.println( "WARNING: unable to find constructor " + constructorEntry + ". dropping mapping." ); classMapping.removeMethodMapping( methodMapping ); @@ -201,7 +249,7 @@ public class Deobfuscator methodMapping.getObfName(), methodMapping.getObfSignature() ); - if( m_jarIndex.getAccess( methodEntry ) == null ) + if( !m_jarIndex.containsObfBehavior( methodEntry ) ) { System.err.println( "WARNING: unable to find method " + methodEntry + ". dropping mapping." ); classMapping.removeMethodMapping( methodMapping ); @@ -257,19 +305,20 @@ public class Deobfuscator } } - public CompilationUnit getSourceTree( String className ) + public CompilationUnit getSourceTree( String obfClassName ) { // 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 - ClassMapping classMapping = m_mappings.getClassByObf( className ); + String lookupClassName = obfClassName; + ClassMapping classMapping = m_mappings.getClassByObf( obfClassName ); if( classMapping != null && classMapping.getDeobfName() != null ) { - className = classMapping.getDeobfName(); + lookupClassName = classMapping.getDeobfName(); } // is this class even in the jar? - if( !m_jarIndex.containsObfClass( new ClassEntry( className ) ) ) + if( !m_jarIndex.containsObfClass( new ClassEntry( obfClassName ) ) ) { return null; } @@ -283,7 +332,7 @@ public class Deobfuscator ) ); // decompile it! - TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( className ).resolve(); + TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( lookupClassName ).resolve(); DecompilerContext context = new DecompilerContext(); context.setCurrentType( resolvedType ); context.setSettings( m_settings ); @@ -302,13 +351,29 @@ public class Deobfuscator // DEBUG //sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); - /* DEBUG + // resolve all the classes in the source references for( Token token : index.referenceTokens() ) { - EntryReference reference = index.getDeobfReference( token ); - System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); + EntryReference deobfReference = index.getDeobfReference( token ); + + // get the obfuscated entry + Entry obfEntry = obfuscateEntry( deobfReference.entry ); + + // try to resolve the class + ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( obfEntry ); + if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( obfEntry.getClassEntry() ) ) + { + // change the class of the entry + obfEntry = obfEntry.cloneToNewClass( resolvedObfClassEntry ); + + // save the new deobfuscated reference + deobfReference.entry = deobfuscateEntry( obfEntry ); + index.replaceDeobfReference( token, deobfReference ); + } + + // DEBUG + //System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); } - */ return index; } @@ -486,13 +551,6 @@ public class Deobfuscator public boolean isObfuscatedIdentifier( Entry obfEntry ) { - if( obfEntry instanceof ClassEntry ) - { - return m_jarIndex.getObfClassEntries().contains( obfEntry ); - } - else - { - return isObfuscatedIdentifier( obfEntry.getClassEntry() ); - } + return m_jarIndex.containsObfEntry( obfEntry ); } } diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java index b82b2547..44e0220c 100644 --- a/src/cuchaz/enigma/analysis/EntryRenamer.java +++ b/src/cuchaz/enigma/analysis/EntryRenamer.java @@ -117,7 +117,7 @@ public class EntryRenamer { ArgumentEntry argumentEntry = (ArgumentEntry)thing; return (T)new ArgumentEntry( - renameMethodsInThing( renames, argumentEntry.getMethodEntry() ), + renameMethodsInThing( renames, argumentEntry.getBehaviorEntry() ), argumentEntry.getIndex(), argumentEntry.getName() ); @@ -177,7 +177,7 @@ public class EntryRenamer { ArgumentEntry argumentEntry = (ArgumentEntry)thing; return (T)new ArgumentEntry( - renameClassesInThing( renames, argumentEntry.getMethodEntry() ), + renameClassesInThing( renames, argumentEntry.getBehaviorEntry() ), argumentEntry.getIndex(), argumentEntry.getName() ); diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index b51428a2..9f309cec 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -42,6 +42,7 @@ import com.google.common.collect.Sets; import cuchaz.enigma.Constants; import cuchaz.enigma.bytecode.ClassRenamer; +import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; @@ -264,7 +265,15 @@ public class JarIndex call.getMethodName(), call.getSignature() ); - calledMethodEntry = resolveMethodClass( calledMethodEntry ); + ClassEntry resolvedClassEntry = resolveEntryClass( calledMethodEntry ); + if( resolvedClassEntry != null && !resolvedClassEntry.equals( calledMethodEntry.getClassEntry() ) ) + { + calledMethodEntry = new MethodEntry( + resolvedClassEntry, + call.getMethodName(), + call.getSignature() + ); + } EntryReference reference = new EntryReference( calledMethodEntry, behaviorEntry @@ -280,6 +289,14 @@ public class JarIndex new ClassEntry( className ), call.getFieldName() ); + ClassEntry resolvedClassEntry = resolveEntryClass( calledFieldEntry ); + if( resolvedClassEntry != null && !resolvedClassEntry.equals( calledFieldEntry.getClassEntry() ) ) + { + calledFieldEntry = new FieldEntry( + resolvedClassEntry, + call.getFieldName() + ); + } EntryReference reference = new EntryReference( calledFieldEntry, behaviorEntry @@ -355,30 +372,26 @@ public class JarIndex throw new IllegalArgumentException( "behavior must be a method or a constructor!" ); } } - - private MethodEntry resolveMethodClass( MethodEntry methodEntry ) + + public ClassEntry resolveEntryClass( Entry obfEntry ) { // this entry could refer to a method on a class where the method is not actually implemented // travel up the inheritance tree to find the closest implementation - while( !isMethodImplemented( methodEntry ) ) + while( !containsObfEntry( obfEntry ) ) { // is there a parent class? - String superclassName = m_translationIndex.getSuperclassName( methodEntry.getClassName() ); + String superclassName = m_translationIndex.getSuperclassName( obfEntry.getClassName() ); if( superclassName == null ) { // this is probably a method from a class in a library // we can't trace the implementation up any higher unless we index the library - return methodEntry; + return null; } // move up to the parent class - methodEntry = new MethodEntry( - new ClassEntry( superclassName ), - methodEntry.getName(), - methodEntry.getSignature() - ); + obfEntry = obfEntry.cloneToNewClass( new ClassEntry( superclassName ) ); } - return methodEntry; + return obfEntry.getClassEntry(); } private CtMethod getBridgedMethod( CtMethod method ) @@ -704,16 +717,6 @@ public class JarIndex return m_fieldClasses.get( fieldEntry ); } - public boolean isMethodImplemented( MethodEntry methodEntry ) - { - Collection implementations = m_methodImplementations.get( methodEntry.getClassName() ); - if( implementations == null ) - { - return false; - } - return implementations.contains( methodEntry ); - } - public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) { // get the root node @@ -751,7 +754,7 @@ public class JarIndex obfMethodEntry.getName(), obfMethodEntry.getSignature() ); - if( isMethodImplemented( ancestorMethodEntry ) ) + if( containsObfBehavior( ancestorMethodEntry ) ) { baseImplementationClassName = ancestorClassName; } @@ -766,7 +769,7 @@ public class JarIndex MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( deobfuscatingTranslator, methodEntry, - isMethodImplemented( methodEntry ) + containsObfBehavior( methodEntry ) ); // expand the full tree @@ -796,7 +799,7 @@ public class JarIndex obfMethodEntry.getName(), obfMethodEntry.getSignature() ); - if( isMethodImplemented( methodInterface ) ) + if( containsObfBehavior( methodInterface ) ) { methodInterfaces.add( methodInterface ); } @@ -827,7 +830,7 @@ public class JarIndex private void getRelatedMethodImplementations( Set methodEntries, MethodInheritanceTreeNode node ) { MethodEntry methodEntry = node.getMethodEntry(); - if( isMethodImplemented( methodEntry ) ) + if( containsObfBehavior( methodEntry ) ) { // collect the entry methodEntries.add( methodEntry ); @@ -850,7 +853,7 @@ public class JarIndex private void getRelatedMethodImplementations( Set methodEntries, MethodImplementationsTreeNode node ) { MethodEntry methodEntry = node.getMethodEntry(); - if( isMethodImplemented( methodEntry ) ) + if( containsObfBehavior( methodEntry ) ) { // collect the entry methodEntries.add( methodEntry ); @@ -969,8 +972,49 @@ public class JarIndex return m_access.containsKey( obfFieldEntry ); } - public boolean containsObfMethod( MethodEntry obfMethodEntry ) + public boolean containsObfBehavior( BehaviorEntry obfBehaviorEntry ) + { + return m_access.containsKey( obfBehaviorEntry ); + } + + public boolean containsObfArgument( ArgumentEntry obfArgumentEntry ) + { + // check the behavior + if( !containsObfBehavior( obfArgumentEntry.getBehaviorEntry() ) ) + { + return false; + } + + // check the argument + if( obfArgumentEntry.getIndex() >= Descriptor.numOfParameters( obfArgumentEntry.getBehaviorEntry().getSignature() ) ) + { + return false; + } + + return true; + } + + public boolean containsObfEntry( Entry obfEntry ) { - return m_access.containsKey( obfMethodEntry ); + if( obfEntry instanceof ClassEntry ) + { + return containsObfClass( (ClassEntry)obfEntry ); + } + else if( obfEntry instanceof FieldEntry ) + { + return containsObfField( (FieldEntry)obfEntry ); + } + else if( obfEntry instanceof BehaviorEntry ) + { + return containsObfBehavior( (BehaviorEntry)obfEntry ); + } + else if( obfEntry instanceof ArgumentEntry ) + { + return containsObfArgument( (ArgumentEntry)obfEntry ); + } + else + { + throw new Error( "Entry type not supported: " + obfEntry.getClass().getName() ); + } } } diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java index 8b9dd2d8..a050282b 100644 --- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java @@ -81,7 +81,7 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode m_entry.getName(), m_entry.getSignature() ); - if( index.isMethodImplemented( methodEntry ) ) + if( index.containsObfBehavior( methodEntry ) ) { nodes.add( new MethodImplementationsTreeNode( m_deobfuscatingTranslator, methodEntry ) ); } diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index d77fd858..bd919518 100644 --- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java @@ -93,7 +93,7 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode nodes.add( new MethodInheritanceTreeNode( m_deobfuscatingTranslator, methodEntry, - index.isMethodImplemented( methodEntry ) + index.containsObfBehavior( methodEntry ) ) ); } diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 49451b90..a5d1460f 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -126,6 +126,15 @@ public class SourceIndex return m_tokenToReference.get( token ); } + public void replaceDeobfReference( Token token, EntryReference newDeobfReference ) + { + EntryReference oldDeobfReference = m_tokenToReference.get( token ); + m_tokenToReference.put( token, newDeobfReference ); + Collection tokens = m_referenceToTokens.get( oldDeobfReference ); + m_referenceToTokens.removeAll( oldDeobfReference ); + m_referenceToTokens.putAll( newDeobfReference, tokens ); + } + public Iterable referenceTokens( ) { return m_tokenToReference.keySet(); diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index 6238b1e7..f307c11d 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -116,6 +116,12 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); if( ref != null ) { + // make sure this is actually a field + if( ref.getSignature().indexOf( '(' ) >= 0 ) + { + throw new Error( "Expected a field here! got " + ref ); + } + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); index.addReference( @@ -149,8 +155,16 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION ); ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); MethodDefinition methodDef = (MethodDefinition)def.getMethod(); - MethodEntry methodEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); - ArgumentEntry argumentEntry = new ArgumentEntry( methodEntry, def.getPosition(), def.getName() ); + BehaviorEntry behaviorEntry; + if( methodDef.isConstructor() ) + { + behaviorEntry = new ConstructorEntry( classEntry, methodDef.getSignature() ); + } + else + { + behaviorEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); + } + ArgumentEntry argumentEntry = new ArgumentEntry( behaviorEntry, def.getPosition(), def.getName() ); index.addDeclaration( node.getNameToken(), argumentEntry ); return recurse( node, index ); diff --git a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java index a8d3983f..adea7eae 100644 --- a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java +++ b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java @@ -15,9 +15,13 @@ import java.util.List; import javassist.CtBehavior; import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtMethod; import javassist.bytecode.Descriptor; import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.Translator; @@ -42,12 +46,26 @@ public class MethodParameterWriter continue; } + // get the behavior entry + BehaviorEntry behaviorEntry; + if( behavior instanceof CtMethod ) + { + behaviorEntry = new MethodEntry( classEntry, behavior.getMethodInfo().getName(), behavior.getSignature() ); + } + else if( behavior instanceof CtConstructor ) + { + behaviorEntry = new ConstructorEntry( classEntry, behavior.getSignature() ); + } + else + { + throw new Error( "Unsupported behavior type: " + behavior.getClass().getName() ); + } + // 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 fallbackMatching = Maps.newHashMap(); @@ -271,7 +271,7 @@ public class ClassMatcher methodMapping.getObfName(), methodMapping.getObfSignature() ); - if( !destIndex.isMethodImplemented( methodEntry ) ) + if( !destIndex.containsObfBehavior( methodEntry ) ) { System.err.println( "WARNING: method doesn't match: " + methodEntry ); diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 5eed728a..1f04aa35 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -229,27 +229,27 @@ public class Gui switch( event.getKeyCode() ) { case KeyEvent.VK_R: - startRename(); + m_renameMenu.doClick(); break; case KeyEvent.VK_I: - showInheritance(); + m_showInheritanceMenu.doClick(); break; case KeyEvent.VK_M: - showImplementations(); + m_showImplementationsMenu.doClick(); break; case KeyEvent.VK_N: - navigateTo( m_reference.entry ); + m_openEntryMenu.doClick(); break; case KeyEvent.VK_P: - m_controller.openPreviousReference(); + m_openPreviousMenu.doClick(); break; case KeyEvent.VK_C: - showCalls(); + m_showCallsMenu.doClick(); break; } } @@ -987,7 +987,7 @@ public class Gui { addNameValue( m_infoPanel, "Argument", entry.getName() ); addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); - addNameValue( m_infoPanel, "Method", entry.getMethodEntry().getName() ); + addNameValue( m_infoPanel, "Method", entry.getBehaviorEntry().getName() ); addNameValue( m_infoPanel, "Index", Integer.toString( entry.getIndex() ) ); } @@ -1014,7 +1014,7 @@ public class Gui boolean isFieldEntry = isToken && m_reference.entry instanceof FieldEntry; boolean isMethodEntry = isToken && m_reference.entry instanceof MethodEntry; boolean isConstructorEntry = isToken && m_reference.entry instanceof ConstructorEntry; - boolean isInJar = isToken && m_controller.entryIsInJar( m_reference.entry.getClassEntry() ); + boolean isInJar = isToken && m_controller.entryIsInJar( m_reference.entry ); if( isToken ) { diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index bbefe606..098e065d 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -270,7 +270,7 @@ public class GuiController ClassEntry obfClassEntry = obfReference.getClassEntry().getOuterClassEntry(); if( !m_deobfuscator.isObfuscatedIdentifier( obfClassEntry ) ) { - throw new IllegalArgumentException( "Entry must be in the jar!" ); + throw new IllegalArgumentException( "Obfuscated class " + obfClassEntry + " was not found in the jar!" ); } if( m_currentObfClass == null || !m_currentObfClass.equals( obfClassEntry ) ) { @@ -354,6 +354,7 @@ public class GuiController if( sourceTree == null ) { // decompilation of this class is not supported + m_gui.setSource("Unable to find class: " + classEntry); return; } String source = m_deobfuscator.getSource( sourceTree ); diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java index 27dcc41d..7ed3d328 100644 --- a/src/cuchaz/enigma/mapping/ArgumentEntry.java +++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java @@ -18,15 +18,15 @@ public class ArgumentEntry implements Entry, Serializable { private static final long serialVersionUID = 4472172468162696006L; - private MethodEntry m_methodEntry; + private BehaviorEntry m_behaviorEntry; private int m_index; private String m_name; - public ArgumentEntry( MethodEntry methodEntry, int index, String name ) + public ArgumentEntry( BehaviorEntry behaviorEntry, int index, String name ) { - if( methodEntry == null ) + if( behaviorEntry == null ) { - throw new IllegalArgumentException( "Method cannot be null!" ); + throw new IllegalArgumentException( "Behavior cannot be null!" ); } if( index < 0 ) { @@ -37,21 +37,28 @@ public class ArgumentEntry implements Entry, Serializable throw new IllegalArgumentException( "Argument name cannot be null!" ); } - m_methodEntry = methodEntry; + m_behaviorEntry = behaviorEntry; m_index = index; m_name = name; } public ArgumentEntry( ArgumentEntry other ) { - m_methodEntry = new MethodEntry( other.m_methodEntry ); + m_behaviorEntry = (BehaviorEntry)m_behaviorEntry.cloneToNewClass( getClassEntry() ); m_index = other.m_index; m_name = other.m_name; } - public MethodEntry getMethodEntry( ) + public ArgumentEntry( ArgumentEntry other, String newClassName ) { - return m_methodEntry; + m_behaviorEntry = (BehaviorEntry)other.m_behaviorEntry.cloneToNewClass( new ClassEntry( newClassName ) ); + m_index = other.m_index; + m_name = other.m_name; + } + + public BehaviorEntry getBehaviorEntry( ) + { + return m_behaviorEntry; } public int getIndex( ) @@ -68,29 +75,35 @@ public class ArgumentEntry implements Entry, Serializable @Override public ClassEntry getClassEntry( ) { - return m_methodEntry.getClassEntry(); + return m_behaviorEntry.getClassEntry(); } @Override public String getClassName( ) { - return m_methodEntry.getClassName(); + return m_behaviorEntry.getClassName(); + } + + @Override + public ArgumentEntry cloneToNewClass( ClassEntry classEntry ) + { + return new ArgumentEntry( this, classEntry.getName() ); } public String getMethodName( ) { - return m_methodEntry.getName(); + return m_behaviorEntry.getName(); } public String getMethodSignature( ) { - return m_methodEntry.getSignature(); + return m_behaviorEntry.getSignature(); } @Override public int hashCode( ) { - return Util.combineHashesOrdered( m_methodEntry, Integer.valueOf( m_index ).hashCode(), m_name.hashCode() ); + return Util.combineHashesOrdered( m_behaviorEntry, Integer.valueOf( m_index ).hashCode(), m_name.hashCode() ); } @Override @@ -105,7 +118,7 @@ public class ArgumentEntry implements Entry, Serializable public boolean equals( ArgumentEntry other ) { - return m_methodEntry.equals( other.m_methodEntry ) + return m_behaviorEntry.equals( other.m_behaviorEntry ) && m_index == other.m_index && m_name.equals( other.m_name ); } @@ -113,6 +126,6 @@ public class ArgumentEntry implements Entry, Serializable @Override public String toString( ) { - return m_methodEntry.toString() + "(" + m_index + ":" + m_name + ")"; + return m_behaviorEntry.toString() + "(" + m_index + ":" + m_name + ")"; } } diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index c6faa506..2c708f2a 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -43,12 +43,6 @@ public class ClassEntry implements Entry, Serializable m_name = other.m_name; } - @Override - public ClassEntry getClassEntry( ) - { - return this; - } - @Override public String getName( ) { @@ -61,6 +55,18 @@ public class ClassEntry implements Entry, Serializable return m_name; } + @Override + public ClassEntry getClassEntry( ) + { + return this; + } + + @Override + public ClassEntry cloneToNewClass( ClassEntry classEntry ) + { + return classEntry; + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index 88006cff..b551d71c 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -139,6 +139,16 @@ public class ClassMapping implements Serializable, Comparable return m_fieldsByObf.values(); } + public boolean containsObfField( String obfName ) + { + return m_fieldsByObf.containsKey( obfName ); + } + + public boolean containsDeobfField( String deobfName ) + { + return m_fieldsByDeobf.containsKey( deobfName ); + } + public void addFieldMapping( FieldMapping fieldMapping ) { if( m_fieldsByObf.containsKey( fieldMapping.getObfName() ) ) @@ -214,6 +224,16 @@ public class ClassMapping implements Serializable, Comparable return m_methodsByObf.values(); } + public boolean containsObfMethod( String obfName, String obfSignature ) + { + return m_methodsByObf.containsKey( getMethodKey( obfName, obfSignature ) ); + } + + public boolean containsDeobfMethod( String deobfName, String deobfSignature ) + { + return m_methodsByDeobf.containsKey( getMethodKey( deobfName, deobfSignature ) ); + } + public void addMethodMapping( MethodMapping methodMapping ) { String obfKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ); @@ -375,19 +395,9 @@ public class ClassMapping implements Serializable, Comparable return false; } - public boolean containsDeobfField( String name ) - { - return m_fieldsByDeobf.containsKey( name ); - } - - public boolean containsDeobfMethod( String name, String signature ) - { - return m_methodsByDeobf.containsKey( getMethodKey( name, signature ) ); - } - - public boolean containsArgument( MethodEntry obfMethodEntry, String name ) + public boolean containsArgument( BehaviorEntry obfBehaviorEntry, String name ) { - MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfMethodEntry.getName(), obfMethodEntry.getSignature() ) ); + MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature() ) ); if( methodMapping != null ) { return methodMapping.containsArgument( name ); diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java index ad029e1c..d99d1c35 100644 --- a/src/cuchaz/enigma/mapping/ConstructorEntry.java +++ b/src/cuchaz/enigma/mapping/ConstructorEntry.java @@ -43,6 +43,12 @@ public class ConstructorEntry implements BehaviorEntry, Serializable m_signature = other.m_signature; } + public ConstructorEntry( ConstructorEntry other, String newClassName ) + { + m_classEntry = new ClassEntry( newClassName ); + m_signature = other.m_signature; + } + @Override public ClassEntry getClassEntry( ) { @@ -76,6 +82,12 @@ public class ConstructorEntry implements BehaviorEntry, Serializable return m_classEntry.getName(); } + @Override + public ConstructorEntry cloneToNewClass( ClassEntry classEntry ) + { + return new ConstructorEntry( this, classEntry.getName() ); + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/mapping/Entry.java b/src/cuchaz/enigma/mapping/Entry.java index e1591f02..8524834c 100644 --- a/src/cuchaz/enigma/mapping/Entry.java +++ b/src/cuchaz/enigma/mapping/Entry.java @@ -15,4 +15,5 @@ public interface Entry String getName( ); String getClassName( ); ClassEntry getClassEntry( ); + Entry cloneToNewClass( ClassEntry classEntry ); } diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java index 435490bd..626af576 100644 --- a/src/cuchaz/enigma/mapping/FieldEntry.java +++ b/src/cuchaz/enigma/mapping/FieldEntry.java @@ -67,6 +67,12 @@ public class FieldEntry implements Entry, Serializable return m_classEntry.getName(); } + @Override + public FieldEntry cloneToNewClass( ClassEntry classEntry ) + { + return new FieldEntry( this, classEntry.getName() ); + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index f855f580..0b4e7f3c 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -253,12 +253,12 @@ public class Mappings implements Serializable return false; } - public boolean containsArgument( MethodEntry obfMethodEntry, String name ) + public boolean containsArgument( BehaviorEntry obfBehaviorEntry, String name ) { - ClassMapping classMapping = m_classesByObf.get( obfMethodEntry.getClassName() ); + ClassMapping classMapping = m_classesByObf.get( obfBehaviorEntry.getClassName() ); if( classMapping != null ) { - return classMapping.containsArgument( obfMethodEntry, name ); + return classMapping.containsArgument( obfBehaviorEntry, name ); } return false; } diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index 49e7b5fd..dcceefbd 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -79,7 +79,7 @@ public class MappingsRenamer { String deobfSignature = getTranslator( TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); MethodEntry targetEntry = new MethodEntry( entry.getClassEntry(), deobfName, deobfSignature ); - if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) + if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfBehavior( targetEntry ) ) { String deobfClassName = getTranslator( TranslationDirection.Deobfuscating ).translateClass( entry.getClassName() ); throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName ); @@ -96,7 +96,7 @@ public class MappingsRenamer { deobfName = NameValidator.validateMethodName( deobfName ); MethodEntry targetEntry = new MethodEntry( obf.getClassEntry(), deobfName, obf.getSignature() ); - if( m_mappings.containsDeobfMethod( obf.getClassEntry(), deobfName, obf.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) + if( m_mappings.containsDeobfMethod( obf.getClassEntry(), deobfName, obf.getSignature() ) || m_index.containsObfBehavior( targetEntry ) ) { String deobfClassName = getTranslator( TranslationDirection.Deobfuscating ).translateClass( obf.getClassName() ); throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName ); @@ -110,7 +110,7 @@ public class MappingsRenamer { deobfName = NameValidator.validateArgumentName( deobfName ); // NOTE: don't need to check arguments for name collisions with names determined by Procyon - if( m_mappings.containsArgument( obf.getMethodEntry(), deobfName ) ) + if( m_mappings.containsArgument( obf.getBehaviorEntry(), deobfName ) ) { throw new IllegalNameException( deobfName, "There is already an argument with that name" ); } @@ -119,6 +119,32 @@ public class MappingsRenamer classMapping.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName ); } + public boolean moveFieldToObfClass( ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass ) + { + classMapping.removeFieldMapping( fieldMapping ); + ClassMapping targetClassMapping = getOrCreateClassMapping( obfClass ); + if( !targetClassMapping.containsObfField( fieldMapping.getObfName() ) + && !targetClassMapping.containsDeobfField( fieldMapping.getDeobfName() ) ) + { + targetClassMapping.addFieldMapping( fieldMapping ); + return true; + } + return false; + } + + public boolean moveMethodToObfClass( ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass ) + { + classMapping.removeMethodMapping( methodMapping ); + ClassMapping targetClassMapping = getOrCreateClassMapping( obfClass ); + if( !targetClassMapping.containsObfMethod( methodMapping.getObfName(), methodMapping.getObfSignature() ) + && !targetClassMapping.containsDeobfMethod( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) ) + { + targetClassMapping.addMethodMapping( methodMapping ); + return true; + } + return false; + } + public void write( OutputStream out ) throws IOException { diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index a311e636..8adbfe9c 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -80,6 +80,12 @@ public class MethodEntry implements BehaviorEntry, Serializable return m_classEntry.getName(); } + @Override + public MethodEntry cloneToNewClass( ClassEntry classEntry ) + { + return new MethodEntry( this, classEntry.getName() ); + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index b438e08d..7904ef53 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -271,7 +271,7 @@ public class Translator name = in.getName(); } return new ArgumentEntry( - translateEntry( in.getMethodEntry() ), + translateEntry( in.getBehaviorEntry() ), in.getIndex(), name ); -- cgit v1.2.3 From 064fe6a628f23f21eb2c8f584215f439e54cfaec Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 24 Sep 2014 20:32:19 -0400 Subject: fixed in-jar detection for bridge-related methods --- src/cuchaz/enigma/Deobfuscator.java | 39 ++++------- src/cuchaz/enigma/analysis/BridgeFixer.java | 22 +++++-- src/cuchaz/enigma/analysis/EntryRenamer.java | 25 +++++-- src/cuchaz/enigma/analysis/JarIndex.java | 40 ++---------- .../enigma/analysis/SourceIndexClassVisitor.java | 12 +--- src/cuchaz/enigma/bytecode/ClassTranslator.java | 41 +++++------- src/cuchaz/enigma/mapping/BehaviorEntry.java | 12 +++- .../enigma/mapping/BehaviorEntryFactory.java | 76 ++++++++++++++++++++++ src/cuchaz/enigma/mapping/MethodEntry.java | 4 ++ src/cuchaz/enigma/mapping/MethodMapping.java | 5 ++ 10 files changed, 170 insertions(+), 106 deletions(-) create mode 100644 src/cuchaz/enigma/mapping/BehaviorEntryFactory.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index f7f74480..9a339176 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -41,6 +41,8 @@ import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ClassMapping; import cuchaz.enigma.mapping.ConstructorEntry; @@ -165,6 +167,12 @@ public class Deobfuscator // methods for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) { + // skip constructors + if( methodMapping.isConstructor() ) + { + continue; + } + MethodEntry methodEntry = new MethodEntry( obfClassEntry, methodMapping.getObfName(), methodMapping.getObfSignature() ); ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( methodEntry ); if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( methodEntry.getClassEntry() ) ) @@ -228,33 +236,12 @@ public class Deobfuscator // check methods for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) { - if( methodMapping.getObfName().equals( "" ) ) - { - // skip static initializers - continue; - } - else if( methodMapping.getObfName().equals( "" ) ) - { - ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, methodMapping.getObfSignature() ); - if( !m_jarIndex.containsObfBehavior( constructorEntry ) ) - { - System.err.println( "WARNING: unable to find constructor " + constructorEntry + ". dropping mapping." ); - classMapping.removeMethodMapping( methodMapping ); - } - } - else + BehaviorEntry obfBehaviorEntry = BehaviorEntryFactory.createObf( classEntry, methodMapping ); + if( !m_jarIndex.containsObfBehavior( obfBehaviorEntry ) ) { - MethodEntry methodEntry = new MethodEntry( - classEntry, - methodMapping.getObfName(), - methodMapping.getObfSignature() - ); - if( !m_jarIndex.containsObfBehavior( methodEntry ) ) - { - System.err.println( "WARNING: unable to find method " + methodEntry + ". dropping mapping." ); - classMapping.removeMethodMapping( methodMapping ); - } - } + System.err.println( "WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping." ); + classMapping.removeMethodMapping( methodMapping ); + } } // check inner classes diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java index aeaf871a..112b864a 100644 --- a/src/cuchaz/enigma/analysis/BridgeFixer.java +++ b/src/cuchaz/enigma/analysis/BridgeFixer.java @@ -15,6 +15,8 @@ import javassist.CtMethod; import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; import cuchaz.enigma.bytecode.ConstPoolEditor; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.MethodEntry; @@ -57,17 +59,23 @@ public class BridgeFixer case ConstPool.CONST_Methodref: case ConstPool.CONST_InterfaceMethodref: { - // translate the name and type - MethodEntry methodEntry = new MethodEntry( - new ClassEntry( Descriptor.toJvmName( editor.getMemberrefClassname( i ) ) ), + BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( + Descriptor.toJvmName( editor.getMemberrefClassname( i ) ), editor.getMemberrefName( i ), editor.getMemberrefType( i ) ); - MethodEntry bridgeMethodEntry = m_index.getBridgeMethod( methodEntry ); - if( bridgeMethodEntry != null ) + + if( behaviorEntry instanceof MethodEntry ) { - // FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT - editor.changeMemberrefNameAndType( i, bridgeMethodEntry.getName(), bridgeMethodEntry.getSignature() ); + MethodEntry methodEntry = (MethodEntry)behaviorEntry; + + // translate the name and type + MethodEntry bridgeMethodEntry = m_index.getBridgeMethod( methodEntry ); + if( bridgeMethodEntry != null ) + { + // FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT + editor.changeMemberrefNameAndType( i, bridgeMethodEntry.getName(), bridgeMethodEntry.getSignature() ); + } } } break; diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java index 44e0220c..2d59fe9d 100644 --- a/src/cuchaz/enigma/analysis/EntryRenamer.java +++ b/src/cuchaz/enigma/analysis/EntryRenamer.java @@ -11,7 +11,6 @@ package cuchaz.enigma.analysis; import java.util.AbstractMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -80,16 +79,32 @@ public class EntryRenamer { // for each key/value pair... Set> entriesToAdd = Sets.newHashSet(); - Iterator> iter = map.entries().iterator(); - while( iter.hasNext() ) + for( Map.Entry entry : map.entries() ) { - Map.Entry entry = iter.next(); - iter.remove(); entriesToAdd.add( new AbstractMap.SimpleEntry( renameMethodsInThing( renames, entry.getKey() ), renameMethodsInThing( renames, entry.getValue() ) ) ); } + map.clear(); + for( Map.Entry entry : entriesToAdd ) + { + map.put( entry.getKey(), entry.getValue() ); + } + } + + public static void renameMethodsInMap( Map renames, Map map ) + { + // for each key/value pair... + Set> entriesToAdd = Sets.newHashSet(); + for( Map.Entry entry : map.entrySet() ) + { + entriesToAdd.add( new AbstractMap.SimpleEntry( + renameMethodsInThing( renames, entry.getKey() ), + renameMethodsInThing( renames, entry.getValue() ) + ) ); + } + map.clear(); for( Map.Entry entry : entriesToAdd ) { map.put( entry.getKey(), entry.getValue() ); diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 9f309cec..a2f6bf34 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -44,6 +44,7 @@ import cuchaz.enigma.Constants; import cuchaz.enigma.bytecode.ClassRenamer; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; @@ -203,6 +204,7 @@ public class JarIndex EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_methodImplementations ); EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_behaviorReferences ); EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences ); + EntryRenamer.renameMethodsInMap( m_bridgeMethods, m_access ); } private void indexField( CtField field ) @@ -224,21 +226,20 @@ public class JarIndex private void indexBehavior( CtBehavior behavior ) { // get the behavior entry - String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); - final BehaviorEntry behaviorEntry = getBehaviorEntry( behavior ); + final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( behavior ); if( behaviorEntry instanceof MethodEntry ) { MethodEntry methodEntry = (MethodEntry)behaviorEntry; // index implementation - m_methodImplementations.put( className, methodEntry ); + m_methodImplementations.put( behaviorEntry.getClassName(), methodEntry ); // look for bridge methods CtMethod bridgedMethod = getBridgedMethod( (CtMethod)behavior ); if( bridgedMethod != null ) { MethodEntry bridgedMethodEntry = new MethodEntry( - new ClassEntry( className ), + behaviorEntry.getClassEntry(), bridgedMethod.getName(), bridgedMethod.getSignature() ); @@ -251,7 +252,7 @@ public class JarIndex private void indexBehaviorReferences( CtBehavior behavior ) { // index method calls - final BehaviorEntry behaviorEntry = getBehaviorEntry( behavior ); + final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( behavior ); try { behavior.instrument( new ExprEditor( ) @@ -344,35 +345,6 @@ public class JarIndex } } - private BehaviorEntry getBehaviorEntry( CtBehavior behavior ) - { - String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); - if( behavior instanceof CtMethod ) - { - return new MethodEntry( - new ClassEntry( className ), - behavior.getName(), - behavior.getSignature() - ); - } - else if( behavior instanceof CtConstructor ) - { - boolean isStatic = behavior.getName().equals( "" ); - if( isStatic ) - { - return new ConstructorEntry( new ClassEntry( className ) ); - } - else - { - return new ConstructorEntry( new ClassEntry( className ), behavior.getSignature() ); - } - } - else - { - throw new IllegalArgumentException( "behavior must be a method or a constructor!" ); - } - } - public ClassEntry resolveEntryClass( Entry obfEntry ) { // this entry could refer to a method on a class where the method is not actually implemented diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index b7897268..5d8a3833 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -25,11 +25,11 @@ import com.strobel.decompiler.languages.java.ast.TypeDeclaration; import com.strobel.decompiler.languages.java.ast.VariableInitializer; import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.MethodEntry; public class SourceIndexClassVisitor extends SourceIndexVisitor { @@ -77,15 +77,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - BehaviorEntry behaviorEntry; - if( def.getName().equals( "" ) ) - { - behaviorEntry = new ConstructorEntry( classEntry ); - } - else - { - behaviorEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() ); - } + BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( classEntry, def.getName(), def.getSignature() ); index.addDeclaration( node.getNameToken(), behaviorEntry ); return node.acceptVisitor( new SourceIndexBehaviorVisitor( behaviorEntry ), index ); } diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index 88926928..db28f21b 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java @@ -21,6 +21,8 @@ import javassist.bytecode.Descriptor; import com.google.common.collect.Maps; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MethodEntry; @@ -53,19 +55,15 @@ public class ClassTranslator new ClassEntry( Descriptor.toJvmName( constants.getFieldrefClassName( i ) ) ), constants.getFieldrefName( i ) ); - String translatedName = m_translator.translate( entry ); - if( translatedName == null ) - { - translatedName = entry.getName(); - } + FieldEntry translatedEntry = m_translator.translateEntry( entry ); // translate the type String type = constants.getFieldrefType( i ); String translatedType = m_translator.translateSignature( type ); - if( !entry.getName().equals( translatedName ) || !type.equals( translatedType ) ) + if( !entry.equals( translatedEntry ) || !type.equals( translatedType ) ) { - editor.changeMemberrefNameAndType( i, translatedName, translatedType ); + editor.changeMemberrefNameAndType( i, translatedEntry.getName(), translatedType ); } } break; @@ -74,21 +72,16 @@ public class ClassTranslator case ConstPool.CONST_InterfaceMethodref: { // translate the name and type - MethodEntry entry = new MethodEntry( - new ClassEntry( Descriptor.toJvmName( editor.getMemberrefClassname( i ) ) ), + BehaviorEntry entry = BehaviorEntryFactory.create( + Descriptor.toJvmName( editor.getMemberrefClassname( i ) ), editor.getMemberrefName( i ), editor.getMemberrefType( i ) ); - String translatedName = m_translator.translate( entry ); - if( translatedName == null ) - { - translatedName = entry.getName(); - } - String translatedSignature = m_translator.translateSignature( entry.getSignature() ); + BehaviorEntry translatedEntry = m_translator.translateEntry( entry ); - if( !entry.getName().equals( translatedName ) || !entry.getSignature().equals( translatedSignature ) ) + if( !entry.getName().equals( translatedEntry.getName() ) || !entry.getSignature().equals( translatedEntry.getSignature() ) ) { - editor.changeMemberrefNameAndType( i, translatedName, translatedSignature ); + editor.changeMemberrefNameAndType( i, translatedEntry.getName(), translatedEntry.getSignature() ); } } break; @@ -116,14 +109,16 @@ public class ClassTranslator // translate all the methods and constructors for( CtBehavior behavior : c.getDeclaredBehaviors() ) { - // translate the name - MethodEntry entry = new MethodEntry( classEntry, behavior.getName(), behavior.getSignature() ); - String translatedName = m_translator.translate( entry ); - if( translatedName != null ) + if( behavior instanceof CtMethod ) { - if( behavior instanceof CtMethod ) + CtMethod method = (CtMethod)behavior; + + // translate the name + MethodEntry entry = new MethodEntry( classEntry, method.getName(), method.getSignature() ); + String translatedName = m_translator.translate( entry ); + if( translatedName != null ) { - ((CtMethod)behavior).setName( translatedName ); + method.setName( translatedName ); } } diff --git a/src/cuchaz/enigma/mapping/BehaviorEntry.java b/src/cuchaz/enigma/mapping/BehaviorEntry.java index 99fdd28d..8fc4eaf0 100644 --- a/src/cuchaz/enigma/mapping/BehaviorEntry.java +++ b/src/cuchaz/enigma/mapping/BehaviorEntry.java @@ -1,6 +1,16 @@ +/******************************************************************************* + * 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 interface BehaviorEntry extends Entry { - public String getSignature(); + String getSignature(); } diff --git a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java new file mode 100644 index 00000000..d3cfb938 --- /dev/null +++ b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * 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 javassist.CtBehavior; +import javassist.CtConstructor; +import javassist.CtMethod; +import javassist.bytecode.Descriptor; + + +public class BehaviorEntryFactory +{ + public static BehaviorEntry create( String className, String name, String signature ) + { + return create( new ClassEntry( className ), name, signature ); + } + + public static BehaviorEntry create( ClassEntry classEntry, String name, String signature ) + { + if( name.equals( "" ) ) + { + return new ConstructorEntry( classEntry, signature ); + } + else if( name.equals( "" ) ) + { + return new ConstructorEntry( classEntry ); + } + else + { + return new MethodEntry( classEntry, name, signature ); + } + } + + public static BehaviorEntry create( CtBehavior behavior ) + { + String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); + if( behavior instanceof CtMethod ) + { + return create( className, behavior.getName(), behavior.getSignature() ); + } + else if( behavior instanceof CtConstructor ) + { + CtConstructor constructor = (CtConstructor)behavior; + if( constructor.isClassInitializer() ) + { + return create( className, "", null ); + } + else + { + return create( className, "", constructor.getSignature() ); + } + } + else + { + throw new IllegalArgumentException( "Unable to create BehaviorEntry from " + behavior ); + } + } + + public static BehaviorEntry createObf( ClassEntry classEntry, MethodMapping methodMapping ) + { + return create( classEntry, methodMapping.getObfName(), methodMapping.getObfSignature() ); + } + + public static BehaviorEntry createDeobf( ClassEntry classEntry, MethodMapping methodMapping ) + { + return create( classEntry, methodMapping.getDeobfName(), methodMapping.getObfSignature() ); + } +} diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index 8adbfe9c..dbc18855 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -36,6 +36,10 @@ public class MethodEntry implements BehaviorEntry, Serializable { throw new IllegalArgumentException( "Method signature cannot be null!" ); } + if( name.startsWith( "<" ) ) + { + throw new IllegalArgumentException( "Don't use MethodEntry for a constructor!" ); + } m_classEntry = classEntry; m_name = name; diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java index 6210fd09..b076fa33 100644 --- a/src/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/cuchaz/enigma/mapping/MethodMapping.java @@ -70,6 +70,11 @@ public class MethodMapping implements Serializable, Comparable return m_arguments.values(); } + public boolean isConstructor( ) + { + return m_obfName.startsWith( "<" ); + } + public void addArgumentMapping( ArgumentMapping argumentMapping ) { boolean wasAdded = m_arguments.put( argumentMapping.getIndex(), argumentMapping ) == null; -- cgit v1.2.3 From 2b2b82b2ff6a7907fc5209f4ea6e1c072eb9c28e Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 24 Sep 2014 23:02:07 -0400 Subject: changed warnings for mappings migration --- src/cuchaz/enigma/mapping/MappingsRenamer.java | 28 ++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index dcceefbd..182bbd19 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -123,11 +123,17 @@ public class MappingsRenamer { classMapping.removeFieldMapping( fieldMapping ); ClassMapping targetClassMapping = getOrCreateClassMapping( obfClass ); - if( !targetClassMapping.containsObfField( fieldMapping.getObfName() ) - && !targetClassMapping.containsDeobfField( fieldMapping.getDeobfName() ) ) + if( !targetClassMapping.containsObfField( fieldMapping.getObfName() ) ) { - targetClassMapping.addFieldMapping( fieldMapping ); - return true; + if( !targetClassMapping.containsDeobfField( fieldMapping.getDeobfName() ) ) + { + targetClassMapping.addFieldMapping( fieldMapping ); + return true; + } + else + { + System.err.println( "WARNING: deobf field was already there: " + obfClass + "." + fieldMapping.getDeobfName() ); + } } return false; } @@ -136,11 +142,17 @@ public class MappingsRenamer { classMapping.removeMethodMapping( methodMapping ); ClassMapping targetClassMapping = getOrCreateClassMapping( obfClass ); - if( !targetClassMapping.containsObfMethod( methodMapping.getObfName(), methodMapping.getObfSignature() ) - && !targetClassMapping.containsDeobfMethod( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) ) + if( !targetClassMapping.containsObfMethod( methodMapping.getObfName(), methodMapping.getObfSignature() ) ) { - targetClassMapping.addMethodMapping( methodMapping ); - return true; + if( !targetClassMapping.containsDeobfMethod( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) ) + { + targetClassMapping.addMethodMapping( methodMapping ); + return true; + } + else + { + System.err.println( "WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfSignature() ); + } } return false; } -- cgit v1.2.3 From 5bff7fee33756029579f0f544d6c74800a034fe2 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 25 Sep 2014 22:24:20 -0400 Subject: fixed invalid tokens issue --- src/cuchaz/enigma/analysis/SourceIndex.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index a5d1460f..38d10daa 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -62,13 +62,20 @@ public class SourceIndex Region region = node.getRegion(); if( region.getBeginLine() == 0 || region.getEndLine() == 0 ) { - System.err.println( "WARNING: " + node.getNodeType() + " node has invalid region: " + region ); + // DEBUG + //System.err.println( "WARNING: " + node.getNodeType() + " node has invalid region: " + region ); return null; } Token token = new Token( toPos( region.getBeginLine(), region.getBeginColumn() ), toPos( region.getEndLine(), region.getEndColumn() ) ); + if( token.start == 0 ) + { + // DEBUG + //System.err.println( "WARNING: " + node.getNodeType() + " node has invalid start: " + region ); + return null; + } // for tokens representing inner classes, make sure we only get the simple name int pos = node.toString().lastIndexOf( '$' ); -- cgit v1.2.3 From 575447097876b5cf3dfbae8fa1f6f749819e97b8 Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 26 Sep 2014 00:33:07 -0400 Subject: implemented mark-as-deobfuscated and reset-to-obfuscated --- src/cuchaz/enigma/Deobfuscator.java | 68 +++++++++++++++--- src/cuchaz/enigma/gui/Gui.java | 63 ++++++++++++++--- src/cuchaz/enigma/gui/GuiController.java | 18 +++++ src/cuchaz/enigma/mapping/ClassMapping.java | 62 ++++++++++++---- src/cuchaz/enigma/mapping/Mappings.java | 11 +++ src/cuchaz/enigma/mapping/MappingsRenamer.java | 97 ++++++++++++++++++++++++++ src/cuchaz/enigma/mapping/MethodMapping.java | 6 ++ 7 files changed, 296 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 9a339176..44845ba2 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -508,23 +508,19 @@ public class Deobfuscator Translator translator = getTranslator( TranslationDirection.Deobfuscating ); if( obfEntry instanceof ClassEntry ) { - String deobfName = translator.translate( (ClassEntry)obfEntry ); - return deobfName != null && !deobfName.equals( obfEntry.getName() ); + return translator.translate( (ClassEntry)obfEntry ) != null; } else if( obfEntry instanceof FieldEntry ) { - String deobfName = translator.translate( (FieldEntry)obfEntry ); - return deobfName != null && !deobfName.equals( obfEntry.getName() ); + return translator.translate( (FieldEntry)obfEntry ) != null; } else if( obfEntry instanceof MethodEntry ) { - String deobfName = translator.translate( (MethodEntry)obfEntry ); - return deobfName != null && !deobfName.equals( obfEntry.getName() ); + return translator.translate( (MethodEntry)obfEntry ) != null; } else if( obfEntry instanceof ConstructorEntry ) { - String deobfName = translator.translate( obfEntry.getClassEntry() ); - return deobfName != null && !deobfName.equals( obfEntry.getClassName() ); + return translator.translate( obfEntry.getClassEntry() ) != null; } else if( obfEntry instanceof ArgumentEntry ) { @@ -540,4 +536,60 @@ public class Deobfuscator { return m_jarIndex.containsObfEntry( obfEntry ); } + + public void removeMapping( Entry obfEntry ) + { + if( obfEntry instanceof ClassEntry ) + { + m_renamer.removeClassMapping( (ClassEntry)obfEntry ); + } + else if( obfEntry instanceof FieldEntry ) + { + m_renamer.removeFieldMapping( (FieldEntry)obfEntry ); + } + else if( obfEntry instanceof MethodEntry ) + { + m_renamer.removeMethodTreeMapping( (MethodEntry)obfEntry ); + } + else if( obfEntry instanceof ConstructorEntry ) + { + m_renamer.removeClassMapping( obfEntry.getClassEntry() ); + } + else if( obfEntry instanceof ArgumentEntry ) + { + m_renamer.removeArgumentMapping( (ArgumentEntry)obfEntry ); + } + else + { + throw new Error( "Unknown entry type: " + obfEntry ); + } + } + + public void markAsDeobfuscated( Entry obfEntry ) + { + if( obfEntry instanceof ClassEntry ) + { + m_renamer.markClassAsDeobfuscated( (ClassEntry)obfEntry ); + } + else if( obfEntry instanceof FieldEntry ) + { + m_renamer.markFieldAsDeobfuscated( (FieldEntry)obfEntry ); + } + else if( obfEntry instanceof MethodEntry ) + { + m_renamer.markMethodTreeAsDeobfuscated( (MethodEntry)obfEntry ); + } + else if( obfEntry instanceof ConstructorEntry ) + { + m_renamer.markClassAsDeobfuscated( obfEntry.getClassEntry() ); + } + else if( obfEntry instanceof ArgumentEntry ) + { + m_renamer.markArgumentAsDeobfuscated( (ArgumentEntry)obfEntry ); + } + else + { + throw new Error( "Unknown entry type: " + obfEntry ); + } + } } diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 1f04aa35..8bf6ce95 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -122,6 +122,7 @@ public class Gui private JMenuItem m_openPreviousMenu; private JMenuItem m_showCallsMenu; private JMenuItem m_showImplementationsMenu; + private JMenuItem m_toggleMappingMenu; // state private EntryReference m_reference; @@ -136,17 +137,20 @@ public class Gui final Container pane = m_frame.getContentPane(); pane.setLayout( new BorderLayout() ); - // install a global exception handler to the event thread - CrashDialog.init( m_frame ); - Thread.setDefaultUncaughtExceptionHandler( new UncaughtExceptionHandler( ) + if( Boolean.parseBoolean( System.getProperty( "enigma.catchExceptions", "true" ) ) ) { - @Override - public void uncaughtException( Thread thread, Throwable ex ) + // install a global exception handler to the event thread + CrashDialog.init( m_frame ); + Thread.setDefaultUncaughtExceptionHandler( new UncaughtExceptionHandler( ) { - ex.printStackTrace( System.err ); - CrashDialog.show( ex ); - } - } ); + @Override + public void uncaughtException( Thread thread, Throwable ex ) + { + ex.printStackTrace( System.err ); + CrashDialog.show( ex ); + } + } ); + } m_controller = new GuiController( this ); @@ -251,6 +255,10 @@ public class Gui case KeyEvent.VK_C: m_showCallsMenu.doClick(); break; + + case KeyEvent.VK_T: + m_toggleMappingMenu.doClick(); + break; } } } ); @@ -352,6 +360,21 @@ public class Gui popupMenu.add( menu ); m_openPreviousMenu = menu; } + { + JMenuItem menu = new JMenuItem( "Mark as deobfuscated" ); + menu.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + toggleMapping(); + } + } ); + menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_T, 0 ) ); + menu.setEnabled( false ); + popupMenu.add( menu ); + m_toggleMappingMenu = menu; + } // init inheritance panel m_inheritanceTree = new JTree(); @@ -1031,6 +1054,16 @@ public class Gui m_showCallsMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); m_openEntryMenu.setEnabled( isInJar && ( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ) ); m_openPreviousMenu.setEnabled( m_controller.hasPreviousLocation() ); + m_toggleMappingMenu.setEnabled( isInJar && isToken ); + + if( isToken && m_controller.entryHasMapping( m_reference.entry ) ) + { + m_toggleMappingMenu.setText( "Reset to obfuscated" ); + } + else + { + m_toggleMappingMenu.setText( "Mark as deobfuscated" ); + } } private void navigateTo( Entry entry ) @@ -1233,6 +1266,18 @@ public class Gui redraw(); } + private void toggleMapping() + { + if( m_controller.entryHasMapping( m_reference.entry ) ) + { + m_controller.removeMapping( m_reference ); + } + else + { + m_controller.markAsDeobfuscated( m_reference ); + } + } + private TreePath getPathToRoot( TreeNode node ) { List nodes = Lists.newArrayList(); diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 098e065d..3adaf91d 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -249,6 +249,24 @@ public class GuiController refreshCurrentClass( obfReference ); } + public void removeMapping( EntryReference deobfReference ) + { + EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); + m_deobfuscator.removeMapping( obfReference.entry ); + m_isDirty = true; + refreshClasses(); + refreshCurrentClass( obfReference ); + } + + public void markAsDeobfuscated( EntryReference deobfReference ) + { + EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); + m_deobfuscator.markAsDeobfuscated( obfReference.entry ); + m_isDirty = true; + refreshClasses(); + refreshCurrentClass( obfReference ); + } + public void openDeclaration( Entry deobfEntry ) { if( deobfEntry == null ) diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index b551d71c..88106dfa 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -79,6 +79,17 @@ public class ClassMapping implements Serializable, Comparable } } + public void removeInnerClassMapping( ClassMapping classMapping ) + { + boolean obfWasRemoved = m_innerClassesByObf.remove( classMapping.getObfName() ) != null; + assert( obfWasRemoved ); + if( classMapping.getDeobfName() != null ) + { + boolean deobfWasRemoved = m_innerClassesByDeobf.remove( classMapping.getDeobfName() ) != null; + assert( deobfWasRemoved ); + } + } + public ClassMapping getOrCreateInnerClass( String obfName ) { ClassMapping classMapping = m_innerClassesByObf.get( obfName ); @@ -124,11 +135,17 @@ public class ClassMapping implements Serializable, Comparable public void setInnerClassName( String obfName, String deobfName ) { ClassMapping classMapping = getOrCreateInnerClass( obfName ); - boolean wasRemoved = m_innerClassesByDeobf.remove( classMapping.getDeobfName() ) != null; - assert( wasRemoved ); + if( classMapping.getDeobfName() != null ) + { + boolean wasRemoved = m_innerClassesByDeobf.remove( classMapping.getDeobfName() ) != null; + assert( wasRemoved ); + } classMapping.setDeobfName( deobfName ); - boolean wasAdded = m_innerClassesByDeobf.put( deobfName, classMapping ) == null; - assert( wasAdded ); + if( deobfName != null ) + { + boolean wasAdded = m_innerClassesByDeobf.put( deobfName, classMapping ) == null; + assert( wasAdded ); + } } //// FIELDS //////// @@ -176,6 +193,16 @@ public class ClassMapping implements Serializable, Comparable assert( deobfWasRemoved ); } } + + public FieldMapping getFieldByObf( String obfName ) + { + return m_fieldsByObf.get( obfName ); + } + + public FieldMapping getFieldByDeobf( String deobfName ) + { + return m_fieldsByDeobf.get( deobfName ); + } public String getObfFieldName( String deobfName ) { @@ -212,8 +239,11 @@ public class ClassMapping implements Serializable, Comparable assert( wasRemoved ); } fieldMapping.setDeobfName( deobfName ); - boolean wasAdded = m_fieldsByDeobf.put( deobfName, fieldMapping ) == null; - assert( wasAdded ); + if( deobfName != null ) + { + boolean wasAdded = m_fieldsByDeobf.put( deobfName, fieldMapping ) == null; + assert( wasAdded ); + } } //// METHODS //////// @@ -303,20 +333,28 @@ public class ClassMapping implements Serializable, Comparable assert( wasRemoved ); } methodMapping.setDeobfName( deobfName ); - boolean wasAdded = m_methodsByDeobf.put( getMethodKey( deobfName, obfSignature ), methodMapping ) == null; - assert( wasAdded ); + if( deobfName != null ) + { + boolean wasAdded = m_methodsByDeobf.put( getMethodKey( deobfName, obfSignature ), methodMapping ) == null; + assert( wasAdded ); + } } //// ARGUMENTS //////// public void setArgumentName( String obfMethodName, String obfMethodSignature, int argumentIndex, String argumentName ) { - MethodMapping methodIndex = m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) ); - if( methodIndex == null ) + MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) ); + if( methodMapping == null ) { - methodIndex = createMethodMapping( obfMethodName, obfMethodSignature ); + methodMapping = createMethodMapping( obfMethodName, obfMethodSignature ); } - methodIndex.setArgumentName( argumentIndex, argumentName ); + methodMapping.setArgumentName( argumentIndex, argumentName ); + } + + public void removeArgumentName( String obfMethodName, String obfMethodSignature, int argumentIndex ) + { + m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) ).removeArgumentName( argumentIndex ); } private MethodMapping createMethodMapping( String obfName, String obfSignature ) diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 0b4e7f3c..45b41bcd 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -94,6 +94,17 @@ public class Mappings implements Serializable } } + public void removeClassMapping( ClassMapping classMapping ) + { + boolean obfWasRemoved = m_classesByObf.remove( classMapping.getObfName() ) != null; + assert( obfWasRemoved ); + if( classMapping.getDeobfName() != null ) + { + boolean deobfWasRemoved = m_classesByDeobf.remove( classMapping.getDeobfName() ) != null; + assert( deobfWasRemoved ); + } + } + public ClassMapping getClassByObf( ClassEntry entry ) { return getClassByObf( entry.getName() ); diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index 182bbd19..957b6d68 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -57,6 +57,36 @@ public class MappingsRenamer } } + public void removeClassMapping( ClassEntry obf ) + { + ClassMapping classMapping = getClassMapping( obf ); + if( obf.isInnerClass() ) + { + classMapping.setInnerClassName( obf.getName(), null ); + } + else + { + boolean wasRemoved = m_mappings.m_classesByDeobf.remove( classMapping.getDeobfName() ) != null; + assert( wasRemoved ); + classMapping.setDeobfName( null ); + } + } + + public void markClassAsDeobfuscated( ClassEntry obf ) + { + ClassMapping classMapping = getOrCreateClassMapping( obf ); + if( obf.isInnerClass() ) + { + classMapping.setInnerClassName( obf.getName(), obf.getName() ); + } + else + { + classMapping.setDeobfName( obf.getName() ); + boolean wasAdded = m_mappings.m_classesByDeobf.put( obf.getName(), classMapping ) == null; + assert( wasAdded ); + } + } + public void setFieldName( FieldEntry obf, String deobfName ) { deobfName = NameValidator.validateFieldName( deobfName ); @@ -70,6 +100,18 @@ public class MappingsRenamer classMapping.setFieldName( obf.getName(), deobfName ); } + public void removeFieldMapping( FieldEntry obf ) + { + ClassMapping classMapping = getClassMappingOrInnerClassMapping( obf.getClassEntry() ); + classMapping.setFieldName( obf.getName(), null ); + } + + public void markFieldAsDeobfuscated( FieldEntry obf ) + { + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); + classMapping.setFieldName( obf.getName(), obf.getName() ); + } + public void setMethodTreeName( MethodEntry obf, String deobfName ) { Set implementations = m_index.getRelatedMethodImplementations( obf ); @@ -106,6 +148,34 @@ public class MappingsRenamer classMapping.setMethodName( obf.getName(), obf.getSignature(), deobfName ); } + public void removeMethodTreeMapping( MethodEntry obf ) + { + for( MethodEntry implementation : m_index.getRelatedMethodImplementations( obf ) ) + { + removeMethodMapping( implementation ); + } + } + + public void removeMethodMapping( MethodEntry obf ) + { + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); + classMapping.setMethodName( obf.getName(), obf.getSignature(), null ); + } + + public void markMethodTreeAsDeobfuscated( MethodEntry obf ) + { + for( MethodEntry implementation : m_index.getRelatedMethodImplementations( obf ) ) + { + markMethodAsDeobfuscated( implementation ); + } + } + + public void markMethodAsDeobfuscated( MethodEntry obf ) + { + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); + classMapping.setMethodName( obf.getName(), obf.getSignature(), obf.getName() ); + } + public void setArgumentName( ArgumentEntry obf, String deobfName ) { deobfName = NameValidator.validateArgumentName( deobfName ); @@ -119,6 +189,18 @@ public class MappingsRenamer classMapping.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName ); } + public void removeArgumentMapping( ArgumentEntry obf ) + { + ClassMapping classMapping = getClassMappingOrInnerClassMapping( obf.getClassEntry() ); + classMapping.removeArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex() ); + } + + public void markArgumentAsDeobfuscated( ArgumentEntry obf ) + { + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); + classMapping.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName() ); + } + public boolean moveFieldToObfClass( ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass ) { classMapping.removeFieldMapping( fieldMapping ); @@ -167,6 +249,11 @@ public class MappingsRenamer gzipout.finish(); } + private ClassMapping getClassMapping( ClassEntry obfClassEntry ) + { + return m_mappings.m_classesByObf.get( obfClassEntry.getOuterClassName() ); + } + private ClassMapping getOrCreateClassMapping( ClassEntry obfClassEntry ) { String obfClassName = obfClassEntry.getOuterClassName(); @@ -180,6 +267,16 @@ public class MappingsRenamer return classMapping; } + private ClassMapping getClassMappingOrInnerClassMapping( ClassEntry obfClassEntry ) + { + ClassMapping classMapping = getClassMapping( obfClassEntry ); + if( obfClassEntry.isInDefaultPackage() ) + { + classMapping = classMapping.getInnerClassByObf( obfClassEntry.getInnerClassName() ); + } + return classMapping; + } + private ClassMapping getOrCreateClassMappingOrInnerClassMapping( ClassEntry obfClassEntry ) { ClassMapping classMapping = getOrCreateClassMapping( obfClassEntry ); diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java index b076fa33..c51b0110 100644 --- a/src/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/cuchaz/enigma/mapping/MethodMapping.java @@ -118,6 +118,12 @@ public class MethodMapping implements Serializable, Comparable } } + public void removeArgumentName( int index ) + { + boolean wasRemoved = m_arguments.remove( index ) != null; + assert( wasRemoved ); + } + @Override public String toString( ) { -- cgit v1.2.3 From cf3ffcee30083a71e68e3edb9ecbb936cc255992 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 28 Sep 2014 15:20:54 -0400 Subject: added proper support for renaming constructors --- src/cuchaz/enigma/Deobfuscator.java | 70 +++++++++++++--------- src/cuchaz/enigma/analysis/EntryReference.java | 43 +++++++++++-- src/cuchaz/enigma/analysis/JarIndex.java | 7 ++- src/cuchaz/enigma/analysis/SourceIndex.java | 29 ++++++--- .../analysis/SourceIndexBehaviorVisitor.java | 27 ++------- .../enigma/analysis/SourceIndexClassVisitor.java | 6 +- src/cuchaz/enigma/analysis/Token.java | 10 ++++ src/cuchaz/enigma/analysis/TreeDumpVisitor.java | 2 +- src/cuchaz/enigma/gui/Gui.java | 15 ++--- src/cuchaz/enigma/gui/GuiController.java | 34 +++++++---- 10 files changed, 155 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 44845ba2..ff83d21a 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -40,6 +40,7 @@ import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; import cuchaz.enigma.analysis.Token; +import cuchaz.enigma.analysis.TreeDumpVisitor; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.BehaviorEntryFactory; @@ -337,7 +338,7 @@ public class Deobfuscator // DEBUG //sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); - + // resolve all the classes in the source references for( Token token : index.referenceTokens() ) { @@ -454,7 +455,8 @@ public class Deobfuscator } return new EntryReference( obfuscateEntry( deobfReference.entry ), - obfuscateEntry( deobfReference.context ) + obfuscateEntry( deobfReference.context ), + deobfReference ); } @@ -466,75 +468,83 @@ public class Deobfuscator } return new EntryReference( deobfuscateEntry( obfReference.entry ), - deobfuscateEntry( obfReference.context ) + deobfuscateEntry( obfReference.context ), + obfReference ); } + public boolean isObfuscatedIdentifier( Entry obfEntry ) + { + return m_jarIndex.containsObfEntry( obfEntry ); + } + + public boolean isRenameable( EntryReference obfReference ) + { + return obfReference.isNamed() && isObfuscatedIdentifier( obfReference.getNameableEntry() ); + } + + // NOTE: these methods are a bit messy... oh well - public void rename( Entry obfEntry, String newName ) + public boolean hasDeobfuscatedName( Entry obfEntry ) { + Translator translator = getTranslator( TranslationDirection.Deobfuscating ); if( obfEntry instanceof ClassEntry ) { - m_renamer.setClassName( (ClassEntry)obfEntry, Descriptor.toJvmName( newName ) ); + return translator.translate( (ClassEntry)obfEntry ) != null; } else if( obfEntry instanceof FieldEntry ) { - m_renamer.setFieldName( (FieldEntry)obfEntry, newName ); + return translator.translate( (FieldEntry)obfEntry ) != null; } else if( obfEntry instanceof MethodEntry ) { - m_renamer.setMethodTreeName( (MethodEntry)obfEntry, newName ); + return translator.translate( (MethodEntry)obfEntry ) != null; } else if( obfEntry instanceof ConstructorEntry ) { - m_renamer.setClassName( obfEntry.getClassEntry(), newName ); + // constructors have no names + return false; } else if( obfEntry instanceof ArgumentEntry ) { - m_renamer.setArgumentName( (ArgumentEntry)obfEntry, newName ); + return translator.translate( (ArgumentEntry)obfEntry ) != null; } else { throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); } - - // clear caches - m_translatorCache.clear(); } - - public boolean hasMapping( Entry obfEntry ) + + public void rename( Entry obfEntry, String newName ) { - Translator translator = getTranslator( TranslationDirection.Deobfuscating ); if( obfEntry instanceof ClassEntry ) { - return translator.translate( (ClassEntry)obfEntry ) != null; + m_renamer.setClassName( (ClassEntry)obfEntry, Descriptor.toJvmName( newName ) ); } else if( obfEntry instanceof FieldEntry ) { - return translator.translate( (FieldEntry)obfEntry ) != null; + m_renamer.setFieldName( (FieldEntry)obfEntry, newName ); } else if( obfEntry instanceof MethodEntry ) { - return translator.translate( (MethodEntry)obfEntry ) != null; + m_renamer.setMethodTreeName( (MethodEntry)obfEntry, newName ); } else if( obfEntry instanceof ConstructorEntry ) { - return translator.translate( obfEntry.getClassEntry() ) != null; + throw new IllegalArgumentException( "Cannot rename constructors" ); } else if( obfEntry instanceof ArgumentEntry ) { - return translator.translate( (ArgumentEntry)obfEntry ) != null; + m_renamer.setArgumentName( (ArgumentEntry)obfEntry, newName ); } else { throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); } - } - - public boolean isObfuscatedIdentifier( Entry obfEntry ) - { - return m_jarIndex.containsObfEntry( obfEntry ); + + // clear caches + m_translatorCache.clear(); } public void removeMapping( Entry obfEntry ) @@ -553,7 +563,7 @@ public class Deobfuscator } else if( obfEntry instanceof ConstructorEntry ) { - m_renamer.removeClassMapping( obfEntry.getClassEntry() ); + throw new IllegalArgumentException( "Cannot rename constructors" ); } else if( obfEntry instanceof ArgumentEntry ) { @@ -563,6 +573,9 @@ public class Deobfuscator { throw new Error( "Unknown entry type: " + obfEntry ); } + + // clear caches + m_translatorCache.clear(); } public void markAsDeobfuscated( Entry obfEntry ) @@ -581,7 +594,7 @@ public class Deobfuscator } else if( obfEntry instanceof ConstructorEntry ) { - m_renamer.markClassAsDeobfuscated( obfEntry.getClassEntry() ); + throw new IllegalArgumentException( "Cannot rename constructors" ); } else if( obfEntry instanceof ArgumentEntry ) { @@ -591,5 +604,8 @@ public class Deobfuscator { throw new Error( "Unknown entry type: " + obfEntry ); } + + // clear caches + m_translatorCache.clear(); } } diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java index 768c1132..df977fb5 100644 --- a/src/cuchaz/enigma/analysis/EntryReference.java +++ b/src/cuchaz/enigma/analysis/EntryReference.java @@ -10,21 +10,28 @@ ******************************************************************************/ package cuchaz.enigma.analysis; +import java.util.Arrays; +import java.util.List; + import cuchaz.enigma.Util; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; public class EntryReference { + private static final List ConstructorNonNames = Arrays.asList( "this", "super" ); public E entry; public C context; - public EntryReference( E entry ) + private boolean m_isNamed; + + public EntryReference( E entry, String sourceName ) { - this( entry, null ); + this( entry, sourceName, null ); } - public EntryReference( E entry, C context ) + public EntryReference( E entry, String sourceName, C context ) { if( entry == null ) { @@ -33,9 +40,22 @@ public class EntryReference this.entry = entry; this.context = context; + + m_isNamed = sourceName != null && sourceName.length() > 0; + if( entry instanceof ConstructorEntry && ConstructorNonNames.contains( sourceName ) ) + { + m_isNamed = false; + } + } + + public EntryReference( E entry, C context, EntryReference other ) + { + this.entry = entry; + this.context = context; + m_isNamed = other.m_isNamed; } - public ClassEntry getClassEntry( ) + public ClassEntry getLocationClassEntry( ) { if( context != null ) { @@ -44,6 +64,21 @@ public class EntryReference return entry.getClassEntry(); } + public boolean isNamed( ) + { + return m_isNamed; + } + + public Entry getNameableEntry( ) + { + if( entry instanceof ConstructorEntry ) + { + // renaming a constructor really means renaming the class + return entry.getClassEntry(); + } + return entry; + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index a2f6bf34..604e4853 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -277,6 +277,7 @@ public class JarIndex } EntryReference reference = new EntryReference( calledMethodEntry, + call.getMethodName(), behaviorEntry ); m_behaviorReferences.put( calledMethodEntry, reference ); @@ -300,6 +301,7 @@ public class JarIndex } EntryReference reference = new EntryReference( calledFieldEntry, + call.getFieldName(), behaviorEntry ); m_fieldReferences.put( calledFieldEntry, reference ); @@ -308,9 +310,6 @@ public class JarIndex @Override public void edit( ConstructorCall call ) { - // TODO: save isSuper in the reference somehow - boolean isSuper = call.getMethodName().equals( "super" ); - String className = Descriptor.toJvmName( call.getClassName() ); ConstructorEntry calledConstructorEntry = new ConstructorEntry( new ClassEntry( className ), @@ -318,6 +317,7 @@ public class JarIndex ); EntryReference reference = new EntryReference( calledConstructorEntry, + call.getMethodName(), behaviorEntry ); m_behaviorReferences.put( calledConstructorEntry, reference ); @@ -333,6 +333,7 @@ public class JarIndex ); EntryReference reference = new EntryReference( calledConstructorEntry, + call.getClassName(), behaviorEntry ); m_behaviorReferences.put( calledConstructorEntry, reference ); diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 38d10daa..faae1a14 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -21,6 +21,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.strobel.decompiler.languages.Region; import com.strobel.decompiler.languages.java.ast.AstNode; +import com.strobel.decompiler.languages.java.ast.Identifier; import cuchaz.enigma.mapping.Entry; @@ -58,40 +59,54 @@ public class SourceIndex public Token getToken( AstNode node ) { + // get the text of the node + String name = ""; + if( node instanceof Identifier ) + { + name = ((Identifier)node).getName(); + } + // get a token for this node's region Region region = node.getRegion(); if( region.getBeginLine() == 0 || region.getEndLine() == 0 ) { // DEBUG - //System.err.println( "WARNING: " + node.getNodeType() + " node has invalid region: " + region ); + System.err.println( String.format( "WARNING: %s \"%s\" has invalid region: %s", node.getNodeType(), name, region ) ); return null; } Token token = new Token( toPos( region.getBeginLine(), region.getBeginColumn() ), - toPos( region.getEndLine(), region.getEndColumn() ) + toPos( region.getEndLine(), region.getEndColumn() ), + m_source ); if( token.start == 0 ) { // DEBUG - //System.err.println( "WARNING: " + node.getNodeType() + " node has invalid start: " + region ); + System.err.println( String.format( "WARNING: %s \"%s\" has invalid start: %s", node.getNodeType(), name, region ) ); return null; } + // DEBUG + //System.out.println( String.format( "%s \"%s\" region: %s", node.getNodeType(), name, region ) ); + + /* TODO: double check that we still need this // for tokens representing inner classes, make sure we only get the simple name - int pos = node.toString().lastIndexOf( '$' ); + int pos = node.getText().lastIndexOf( '$' ); if( pos >= 0 ) { token.end -= pos + 1; } + */ return token; } - public void addReference( AstNode node, EntryReference deobfReference ) + public void addReference( AstNode node, Entry deobfEntry, Entry deobfContext ) { Token token = getToken( node ); if( token != null ) { + EntryReference deobfReference = new EntryReference( deobfEntry, token.text, deobfContext ); m_tokenToReference.put( token, deobfReference ); m_referenceToTokens.put( deobfReference, token ); } @@ -102,7 +117,7 @@ public class SourceIndex Token token = getToken( node ); if( token != null ) { - EntryReference reference = new EntryReference( deobfEntry ); + EntryReference reference = new EntryReference( deobfEntry, token.text ); m_tokenToReference.put( token, reference ); m_referenceToTokens.put( reference, token ); m_declarationToToken.put( deobfEntry, token ); @@ -111,7 +126,7 @@ public class SourceIndex public Token getReferenceToken( int pos ) { - Token token = m_tokenToReference.floorKey( new Token( pos, pos ) ); + Token token = m_tokenToReference.floorKey( new Token( pos, pos, null ) ); if( token != null && token.contains( pos ) ) { return token; diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index f307c11d..b883087c 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -33,7 +33,6 @@ import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MethodEntry; @@ -100,10 +99,7 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor } if( tokenNode != null ) { - index.addReference( - tokenNode, - new EntryReference( behaviorEntry, m_behaviorEntry ) - ); + index.addReference( tokenNode, behaviorEntry, m_behaviorEntry ); } } @@ -124,10 +120,7 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); - index.addReference( - node.getMemberNameToken(), - new EntryReference( fieldEntry, m_behaviorEntry ) - ); + index.addReference( node.getMemberNameToken(), fieldEntry, m_behaviorEntry ); } return recurse( node, index ); @@ -140,10 +133,7 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) { ClassEntry classEntry = new ClassEntry( ref.getInternalName() ); - index.addReference( - node.getIdentifierToken(), - new EntryReference( classEntry, m_behaviorEntry ) - ); + index.addReference( node.getIdentifierToken(), classEntry, m_behaviorEntry ); } return recurse( node, index ); @@ -178,10 +168,7 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); - index.addReference( - node.getIdentifierToken(), - new EntryReference( fieldEntry, m_behaviorEntry ) - ); + index.addReference( node.getIdentifierToken(), fieldEntry, m_behaviorEntry ); } return recurse( node, index ); @@ -197,10 +184,8 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, ref.getSignature() ); if( node.getType() instanceof SimpleType ) { - index.addReference( - ((SimpleType)node.getType()).getIdentifierToken(), - new EntryReference( constructorEntry, m_behaviorEntry ) - ); + SimpleType simpleTypeNode = (SimpleType)node.getType(); + index.addReference( simpleTypeNode.getIdentifierToken(), constructorEntry, m_behaviorEntry ); } } diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index 5d8a3833..fc8cd665 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -28,7 +28,6 @@ import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; public class SourceIndexClassVisitor extends SourceIndexVisitor @@ -63,10 +62,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) { ClassEntry classEntry = new ClassEntry( ref.getInternalName() ); - index.addReference( - node.getIdentifierToken(), - new EntryReference( classEntry, m_classEntry ) - ); + index.addReference( node.getIdentifierToken(), classEntry, m_classEntry ); } return recurse( node, index ); diff --git a/src/cuchaz/enigma/analysis/Token.java b/src/cuchaz/enigma/analysis/Token.java index d0f2b70b..5e70db71 100644 --- a/src/cuchaz/enigma/analysis/Token.java +++ b/src/cuchaz/enigma/analysis/Token.java @@ -14,11 +14,21 @@ public class Token implements Comparable { public int start; public int end; + public String text; public Token( int start, int end ) + { + this( start, end, null ); + } + + public Token( int start, int end, String source ) { this.start = start; this.end = end; + if( source != null ) + { + this.text = source.substring( start, end ); + } } public boolean contains( int pos ) diff --git a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java index 12febefd..e6ecb10e 100644 --- a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java +++ b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java @@ -141,7 +141,7 @@ public class TreeDumpVisitor implements IAstVisitor { if( node instanceof Identifier ) { - return "\"" + node.getText() + "\""; + return "\"" + ((Identifier)node).getName() + "\""; } return ""; } diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 8bf6ce95..920bc0b9 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -1038,6 +1038,7 @@ public class Gui boolean isMethodEntry = isToken && m_reference.entry instanceof MethodEntry; boolean isConstructorEntry = isToken && m_reference.entry instanceof ConstructorEntry; boolean isInJar = isToken && m_controller.entryIsInJar( m_reference.entry ); + boolean isRenameable = isToken && m_controller.referenceIsRenameable( m_reference ); if( isToken ) { @@ -1048,15 +1049,15 @@ public class Gui clearReference(); } - m_renameMenu.setEnabled( isInJar && isToken ); + m_renameMenu.setEnabled( isRenameable && isToken ); m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry || isConstructorEntry ); m_showImplementationsMenu.setEnabled( isClassEntry || isMethodEntry ); m_showCallsMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); m_openEntryMenu.setEnabled( isInJar && ( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ) ); m_openPreviousMenu.setEnabled( m_controller.hasPreviousLocation() ); - m_toggleMappingMenu.setEnabled( isInJar && isToken ); + m_toggleMappingMenu.setEnabled( isRenameable && isToken ); - if( isToken && m_controller.entryHasMapping( m_reference.entry ) ) + if( isToken && m_controller.entryHasDeobfuscatedName( m_reference.entry ) ) { m_toggleMappingMenu.setText( "Reset to obfuscated" ); } @@ -1082,7 +1083,7 @@ public class Gui private void navigateTo( EntryReference reference ) { - if( !m_controller.entryIsInJar( reference.getClassEntry() ) ) + if( !m_controller.entryIsInJar( reference.getLocationClassEntry() ) ) { // reference is not in the jar. Ignore it return; @@ -1098,7 +1099,7 @@ public class Gui { // init the text box final JTextField text = new JTextField(); - text.setText( m_reference.entry.getName() ); + text.setText( m_reference.getNameableEntry().getName() ); text.setPreferredSize( new Dimension( 360, text.getPreferredSize().height ) ); text.addKeyListener( new KeyAdapter( ) { @@ -1149,7 +1150,7 @@ public class Gui // abort the rename JPanel panel = (JPanel)m_infoPanel.getComponent( 0 ); panel.remove( panel.getComponentCount() - 1 ); - panel.add( GuiTricks.unboldLabel( new JLabel( m_reference.entry.getName(), JLabel.LEFT ) ) ); + panel.add( GuiTricks.unboldLabel( new JLabel( m_reference.getNameableEntry().getName(), JLabel.LEFT ) ) ); m_editor.grabFocus(); @@ -1268,7 +1269,7 @@ public class Gui private void toggleMapping() { - if( m_controller.entryHasMapping( m_reference.entry ) ) + if( m_controller.entryHasDeobfuscatedName( m_reference.entry ) ) { m_controller.removeMapping( m_reference ); } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 3adaf91d..c7efbce6 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -165,9 +165,9 @@ public class GuiController ); } - public boolean entryHasMapping( Entry deobfEntry ) + public boolean entryHasDeobfuscatedName( Entry deobfEntry ) { - return m_deobfuscator.hasMapping( m_deobfuscator.obfuscateEntry( deobfEntry ) ); + return m_deobfuscator.hasDeobfuscatedName( m_deobfuscator.obfuscateEntry( deobfEntry ) ); } public boolean entryIsInJar( Entry deobfEntry ) @@ -175,6 +175,11 @@ public class GuiController return m_deobfuscator.isObfuscatedIdentifier( m_deobfuscator.obfuscateEntry( deobfEntry ) ); } + public boolean referenceIsRenameable( EntryReference deobfReference ) + { + return m_deobfuscator.isRenameable( m_deobfuscator.obfuscateReference( deobfReference ) ); + } + public ClassInheritanceTreeNode getClassInheritance( ClassEntry deobfClassEntry ) { ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry( deobfClassEntry ); @@ -243,7 +248,7 @@ public class GuiController public void rename( EntryReference deobfReference, String newName ) { EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); - m_deobfuscator.rename( obfReference.entry, newName ); + m_deobfuscator.rename( obfReference.getNameableEntry(), newName ); m_isDirty = true; refreshClasses(); refreshCurrentClass( obfReference ); @@ -252,7 +257,7 @@ public class GuiController public void removeMapping( EntryReference deobfReference ) { EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); - m_deobfuscator.removeMapping( obfReference.entry ); + m_deobfuscator.removeMapping( obfReference.getNameableEntry() ); m_isDirty = true; refreshClasses(); refreshCurrentClass( obfReference ); @@ -261,7 +266,7 @@ public class GuiController public void markAsDeobfuscated( EntryReference deobfReference ) { EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); - m_deobfuscator.markAsDeobfuscated( obfReference.entry ); + m_deobfuscator.markAsDeobfuscated( obfReference.getNameableEntry() ); m_isDirty = true; refreshClasses(); refreshCurrentClass( obfReference ); @@ -273,7 +278,7 @@ public class GuiController { throw new IllegalArgumentException( "Entry cannot be null!" ); } - openReference( new EntryReference( deobfEntry ) ); + openReference( new EntryReference( deobfEntry, deobfEntry.getName() ) ); } public void openReference( EntryReference deobfReference ) @@ -285,7 +290,7 @@ public class GuiController // get the reference target class EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); - ClassEntry obfClassEntry = obfReference.getClassEntry().getOuterClassEntry(); + ClassEntry obfClassEntry = obfReference.getLocationClassEntry().getOuterClassEntry(); if( !m_deobfuscator.isObfuscatedIdentifier( obfClassEntry ) ) { throw new IllegalArgumentException( "Obfuscated class " + obfClassEntry + " was not found in the jar!" ); @@ -390,13 +395,16 @@ public class GuiController for( Token token : m_index.referenceTokens() ) { EntryReference reference = m_index.getDeobfReference( token ); - if( entryHasMapping( reference.entry ) ) - { - deobfuscatedTokens.add( token ); - } - else if( entryIsInJar( reference.entry ) ) + if( referenceIsRenameable( reference ) ) { - obfuscatedTokens.add( token ); + if( entryHasDeobfuscatedName( reference.getNameableEntry() ) ) + { + deobfuscatedTokens.add( token ); + } + else + { + obfuscatedTokens.add( token ); + } } else { -- cgit v1.2.3 From b71adf885f9d950cd8c138e332b4bfc7c77222a8 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 28 Sep 2014 15:35:54 -0400 Subject: argument names now default to the names chosen by Procyon --- src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index b883087c..7ffd1700 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -154,7 +154,7 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { behaviorEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); } - ArgumentEntry argumentEntry = new ArgumentEntry( behaviorEntry, def.getPosition(), def.getName() ); + ArgumentEntry argumentEntry = new ArgumentEntry( behaviorEntry, def.getPosition(), node.getName() ); index.addDeclaration( node.getNameToken(), argumentEntry ); return recurse( node, index ); -- cgit v1.2.3 From 3e9960f8a712e8590b3ab3126d823504027516da Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 28 Sep 2014 16:48:54 -0400 Subject: added jar export --- src/cuchaz/enigma/Deobfuscator.java | 67 +++++++++++++++++++++++++--- src/cuchaz/enigma/TranslatingTypeLoader.java | 59 +++++++++++++----------- src/cuchaz/enigma/gui/Gui.java | 37 ++++++++++++--- src/cuchaz/enigma/gui/GuiController.java | 37 ++++++++------- src/cuchaz/enigma/gui/ProgressDialog.java | 36 ++++++++++++--- 5 files changed, 177 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index ff83d21a..9235cf74 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -12,14 +12,18 @@ package cuchaz.enigma; import java.io.File; +import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import javassist.CtClass; import javassist.bytecode.Descriptor; import com.google.common.collect.Lists; @@ -36,11 +40,11 @@ import com.strobel.decompiler.languages.java.ast.CompilationUnit; import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; import cuchaz.enigma.analysis.EntryReference; +import cuchaz.enigma.analysis.JarClassIterator; import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; import cuchaz.enigma.analysis.Token; -import cuchaz.enigma.analysis.TreeDumpVisitor; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.BehaviorEntryFactory; @@ -61,7 +65,7 @@ public class Deobfuscator { public interface ProgressListener { - void init( int totalWork ); + void init( int totalWork, String title ); void onProgress( int numDone, String message ); } @@ -393,7 +397,7 @@ public class Deobfuscator if( progress != null ) { - progress.init( classEntries.size() ); + progress.init( classEntries.size(), "Decompiling classes..." ); } // DEOBFUSCATE ALL THE THINGS!! @_@ @@ -424,9 +428,60 @@ public class Deobfuscator throw new Error( "Unable to deobfuscate class " + deobfClassEntry.toString() + " (" + obfClassEntry.toString() + ")", t ); } } - - // done! - progress.onProgress( classEntries.size(), "Done!" ); + if( progress != null ) + { + progress.onProgress( i, "Done!" ); + } + } + + public void writeJar( File out, ProgressListener progress ) + { + try( JarOutputStream outJar = new JarOutputStream( new FileOutputStream( out ) ) ) + { + if( progress != null ) + { + progress.init( JarClassIterator.getClassEntries( m_jar ).size(), "Translating classes..." ); + } + + // prep the loader + TranslatingTypeLoader loader = new TranslatingTypeLoader( + m_jar, + m_jarIndex, + getTranslator( TranslationDirection.Obfuscating ), + getTranslator( TranslationDirection.Deobfuscating ) + ); + + int i = 0; + for( CtClass c : JarClassIterator.classes( m_jar ) ) + { + if( progress != null ) + { + progress.onProgress( i++, c.getName() ); + } + + try + { + c = loader.transformClass( c ); + outJar.putNextEntry( new JarEntry( c.getName().replace( '.', '/' ) + ".class" ) ); + outJar.write( c.toBytecode() ); + outJar.closeEntry(); + } + catch( Throwable t ) + { + throw new Error( "Unable to deobfuscate class " + c.getName(), t ); + } + } + if( progress != null ) + { + progress.onProgress( i, "Done!" ); + } + + outJar.close(); + } + catch( IOException ex ) + { + throw new Error( "Unable to write to Jar file!" ); + } } public T obfuscateEntry( T deobfEntry ) diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 8b969857..6179879a 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -13,7 +13,6 @@ package cuchaz.enigma; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.Arrays; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -157,12 +156,13 @@ public class TranslatingTypeLoader implements ITypeLoader // otherwise, just use the class name (ie for classes in packages) classFileName = obfClassEntry.getName(); } + JarEntry entry = m_jar.getJarEntry( classFileName + ".class" ); if( entry == null ) { return null; } - + try { // read the class file into a buffer @@ -188,33 +188,11 @@ public class TranslatingTypeLoader implements ITypeLoader classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, buf ) ); CtClass c = classPool.get( javaClassFileName ); - // we moved a lot of classes out of the default package into the none package - // make sure all the class references are consistent - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); - - // reconstruct inner classes - new InnerClassWriter( m_jarIndex ).write( c ); - - // re-get the javassist handle since we changed class names - String javaClassReconstructedName = Descriptor.toJavaName( obfClassEntry.getName() ); - classPool = new ClassPool(); - classPool.insertClassPath( new ByteArrayClassPath( javaClassReconstructedName, c.toBytecode() ) ); - c = classPool.get( javaClassReconstructedName ); - - // check that the file is correct after inner class reconstruction (ie cause Javassist to fail fast if something is wrong) - assertClassName( c, obfClassEntry ); - - // do all kinds of deobfuscating transformations on the class - new BridgeFixer( m_jarIndex ).fixBridges( c ); - new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); - new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); + c = transformClass( c ); // sanity checking assertClassName( c, deobfClassEntry ); - // DEBUG - //Util.writeClass( c ); - // we have a transformed class! return c.toBytecode(); } @@ -223,6 +201,37 @@ public class TranslatingTypeLoader implements ITypeLoader throw new Error( ex ); } } + + public CtClass transformClass( CtClass c ) + throws IOException, NotFoundException, CannotCompileException + { + // we moved a lot of classes out of the default package into the none package + // make sure all the class references are consistent + ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); + + // reconstruct inner classes + new InnerClassWriter( m_jarIndex ).write( c ); + + // re-get the javassist handle since we changed class names + ClassEntry obfClassEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); + String javaClassReconstructedName = Descriptor.toJavaName( obfClassEntry.getName() ); + ClassPool classPool = new ClassPool(); + classPool.insertClassPath( new ByteArrayClassPath( javaClassReconstructedName, c.toBytecode() ) ); + c = classPool.get( javaClassReconstructedName ); + + // check that the file is correct after inner class reconstruction (ie cause Javassist to fail fast if something is wrong) + assertClassName( c, obfClassEntry ); + + // do all kinds of deobfuscating transformations on the class + new BridgeFixer( m_jarIndex ).fixBridges( c ); + new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); + new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); + + // DEBUG + //Util.writeClass( c ); + + return c; + } private void assertClassName( CtClass c, ClassEntry obfClassEntry ) { diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 920bc0b9..dbfcba83 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -123,12 +123,15 @@ public class Gui private JMenuItem m_showCallsMenu; private JMenuItem m_showImplementationsMenu; private JMenuItem m_toggleMappingMenu; + private JMenuItem m_exportSourceMenu; + private JMenuItem m_exportJarMenu; // state private EntryReference m_reference; private JFileChooser m_jarFileChooser; private JFileChooser m_mappingsFileChooser; - private JFileChooser m_exportFileChooser; + private JFileChooser m_exportSourceFileChooser; + private JFileChooser m_exportJarFileChooser; public Gui( ) { @@ -157,8 +160,9 @@ public class Gui // init file choosers m_jarFileChooser = new JFileChooser(); m_mappingsFileChooser = new JFileChooser(); - m_exportFileChooser = new JFileChooser(); - m_exportFileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); + m_exportSourceFileChooser = new JFileChooser(); + m_exportSourceFileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); + m_exportJarFileChooser = new JFileChooser(); // init obfuscated classes list m_obfClasses = new ClassSelector( ClassSelector.ObfuscatedClassEntryComparator ); @@ -663,19 +667,36 @@ public class Gui } menu.addSeparator(); { - JMenuItem item = new JMenuItem( "Export..." ); + JMenuItem item = new JMenuItem( "Export Source..." ); menu.add( item ); item.addActionListener( new ActionListener( ) { @Override public void actionPerformed( ActionEvent event ) { - if( m_exportFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) + if( m_exportSourceFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) { - m_controller.export( m_exportFileChooser.getSelectedFile() ); + m_controller.exportSource( m_exportSourceFileChooser.getSelectedFile() ); } } } ); + m_exportSourceMenu = item; + } + { + JMenuItem item = new JMenuItem( "Export Jar..." ); + menu.add( item ); + item.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + if( m_exportJarFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) + { + m_controller.exportJar( m_exportJarFileChooser.getSelectedFile() ); + } + } + } ); + m_exportJarMenu = item; } menu.addSeparator(); { @@ -762,6 +783,8 @@ public class Gui m_saveMappingsMenu.setEnabled( false ); m_saveMappingsAsMenu.setEnabled( true ); m_closeMappingsMenu.setEnabled( true ); + m_exportSourceMenu.setEnabled( true ); + m_exportJarMenu.setEnabled( true ); redraw(); } @@ -781,6 +804,8 @@ public class Gui m_saveMappingsMenu.setEnabled( false ); m_saveMappingsAsMenu.setEnabled( false ); m_closeMappingsMenu.setEnabled( false ); + m_exportSourceMenu.setEnabled( false ); + m_exportJarMenu.setEnabled( false ); redraw(); } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index c7efbce6..2862ebed 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -23,6 +23,7 @@ import com.google.common.collect.Queues; import com.strobel.decompiler.languages.java.ast.CompilationUnit; import cuchaz.enigma.Deobfuscator; +import cuchaz.enigma.Deobfuscator.ProgressListener; import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; import cuchaz.enigma.analysis.ClassImplementationsTreeNode; import cuchaz.enigma.analysis.ClassInheritanceTreeNode; @@ -32,6 +33,7 @@ import cuchaz.enigma.analysis.MethodImplementationsTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.Token; +import cuchaz.enigma.gui.ProgressDialog.ProgressRunnable; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.Entry; @@ -110,28 +112,29 @@ public class GuiController refreshCurrentClass(); } - public void export( final File dirOut ) + public void exportSource( final File dirOut ) { - new Thread( ) + ProgressDialog.runInThread( m_gui.getFrame(), new ProgressRunnable( ) { @Override - public void run( ) + public void run( ProgressListener progress ) + throws Exception { - ProgressDialog progress = new ProgressDialog( m_gui.getFrame() ); - try - { - m_deobfuscator.writeSources( dirOut, progress ); - } - catch( Exception ex ) - { - throw new Error( ex ); - } - finally - { - progress.close(); - } + m_deobfuscator.writeSources( dirOut, progress ); } - }.start(); + } ); + } + + public void exportJar( final File fileOut ) + { + ProgressDialog.runInThread( m_gui.getFrame(), new ProgressRunnable( ) + { + @Override + public void run( ProgressListener progress ) + { + m_deobfuscator.writeJar( fileOut, progress ); + } + } ); } public Token getToken( int pos ) diff --git a/src/cuchaz/enigma/gui/ProgressDialog.java b/src/cuchaz/enigma/gui/ProgressDialog.java index 40ac6a69..7f954314 100644 --- a/src/cuchaz/enigma/gui/ProgressDialog.java +++ b/src/cuchaz/enigma/gui/ProgressDialog.java @@ -25,22 +25,24 @@ import javax.swing.WindowConstants; import cuchaz.enigma.Constants; import cuchaz.enigma.Deobfuscator.ProgressListener; -public class ProgressDialog implements ProgressListener +public class ProgressDialog implements ProgressListener, AutoCloseable { private JFrame m_frame; + private JLabel m_title; private JLabel m_text; private JProgressBar m_progress; public ProgressDialog( JFrame parent ) { // init frame - m_frame = new JFrame( Constants.Name + " - Export" ); + m_frame = new JFrame( Constants.Name + " - Operation in progress" ); final Container pane = m_frame.getContentPane(); FlowLayout layout = new FlowLayout(); layout.setAlignment( FlowLayout.LEFT ); pane.setLayout( layout ); - pane.add( new JLabel( "Decompiling classes..." ) ); + m_title = new JLabel(); + pane.add( m_title ); // set up the progress bar JPanel panel = new JPanel(); @@ -68,9 +70,9 @@ public class ProgressDialog implements ProgressListener } @Override - public void init( int totalWork ) + public void init( int totalWork, String title ) { - m_text.setText( "Decompiling " + totalWork + " classes..." ); + m_title.setText( title ); m_progress.setMinimum( 0 ); m_progress.setMaximum( totalWork ); m_progress.setValue( 0 ); @@ -86,4 +88,28 @@ public class ProgressDialog implements ProgressListener m_frame.validate(); m_frame.repaint(); } + + public static interface ProgressRunnable + { + void run( ProgressListener listener ) throws Exception; + } + + public static void runInThread( final JFrame parent, final ProgressRunnable runnable ) + { + new Thread( ) + { + @Override + public void run( ) + { + try( ProgressDialog progress = new ProgressDialog( parent ) ) + { + runnable.run( progress ); + } + catch( Exception ex ) + { + throw new Error( ex ); + } + } + }.start(); + } } -- cgit v1.2.3 From 8bfaa26a1483e7875b649e23f045abe9d0fe9f7c Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 28 Sep 2014 19:47:51 -0400 Subject: fixed a crash parsing method signatures with generics in them --- src/cuchaz/enigma/mapping/SignatureUpdater.java | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/mapping/SignatureUpdater.java b/src/cuchaz/enigma/mapping/SignatureUpdater.java index d1216bde..809473e5 100644 --- a/src/cuchaz/enigma/mapping/SignatureUpdater.java +++ b/src/cuchaz/enigma/mapping/SignatureUpdater.java @@ -69,19 +69,32 @@ public class SignatureUpdater throws IOException { // read all the characters in the buffer until we hit a ';' + // remember to treat generics correctly StringBuilder buf = new StringBuilder(); + int depth = 0; int i = -1; while( ( i = reader.read() ) != -1 ) { char c = (char)i; - if( c == ';' ) + if( c == '<' ) { - return buf.toString(); + depth++; } - else + else if( c == '>' ) { - buf.append( c ); + depth--; + } + else if( depth == 0 ) + { + if( c == ';' ) + { + return buf.toString(); + } + else + { + buf.append( c ); + } } } -- cgit v1.2.3 From fd65d9727ec0f443fd9a1504f9b50bafba1fbd76 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 28 Sep 2014 20:27:49 -0400 Subject: fixed recognition of static initializer tokens --- src/cuchaz/enigma/Deobfuscator.java | 1 + src/cuchaz/enigma/analysis/EntryReference.java | 2 +- src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java | 12 +++++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 9235cf74..bd4345e7 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -45,6 +45,7 @@ import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; import cuchaz.enigma.analysis.Token; +import cuchaz.enigma.analysis.TreeDumpVisitor; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.BehaviorEntryFactory; diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java index df977fb5..4da2f589 100644 --- a/src/cuchaz/enigma/analysis/EntryReference.java +++ b/src/cuchaz/enigma/analysis/EntryReference.java @@ -20,7 +20,7 @@ import cuchaz.enigma.mapping.Entry; public class EntryReference { - private static final List ConstructorNonNames = Arrays.asList( "this", "super" ); + private static final List ConstructorNonNames = Arrays.asList( "this", "super", "static" ); public E entry; public C context; diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index fc8cd665..24c48227 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -15,6 +15,7 @@ import com.strobel.assembler.metadata.MethodDefinition; import com.strobel.assembler.metadata.TypeDefinition; import com.strobel.assembler.metadata.TypeReference; import com.strobel.decompiler.languages.TextLocation; +import com.strobel.decompiler.languages.java.ast.AstNode; import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; import com.strobel.decompiler.languages.java.ast.FieldDeclaration; @@ -74,7 +75,16 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( classEntry, def.getName(), def.getSignature() ); - index.addDeclaration( node.getNameToken(), behaviorEntry ); + AstNode tokenNode = node.getNameToken(); + if( behaviorEntry instanceof ConstructorEntry ) + { + ConstructorEntry constructorEntry = (ConstructorEntry)behaviorEntry; + if( constructorEntry.isStatic() ) + { + tokenNode = node.getModifiers().firstOrNullObject(); + } + } + index.addDeclaration( tokenNode, behaviorEntry ); return node.acceptVisitor( new SourceIndexBehaviorVisitor( behaviorEntry ), index ); } -- cgit v1.2.3 From a83bbfd5c510367a194073b1db132022cacf65ed Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 30 Sep 2014 00:25:36 -0400 Subject: fixed nasty issue with renaming inner classes, but alas, more bugs remain --- src/cuchaz/enigma/Deobfuscator.java | 3 +- src/cuchaz/enigma/TranslatingTypeLoader.java | 10 +++--- src/cuchaz/enigma/analysis/EntryReference.java | 15 +++++++++ src/cuchaz/enigma/analysis/JarIndex.java | 7 ++-- src/cuchaz/enigma/analysis/SourceIndex.java | 2 -- src/cuchaz/enigma/bytecode/ClassRenamer.java | 31 ++++-------------- src/cuchaz/enigma/bytecode/ClassTranslator.java | 6 +++- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 20 ++++++------ src/cuchaz/enigma/gui/Gui.java | 4 +-- src/cuchaz/enigma/mapping/ClassMapping.java | 18 +++++++++-- src/cuchaz/enigma/mapping/MappingsReader.java | 41 +++++++++++++----------- src/cuchaz/enigma/mapping/MappingsRenamer.java | 6 ++-- src/cuchaz/enigma/mapping/NameValidator.java | 6 ++-- src/cuchaz/enigma/mapping/Translator.java | 17 +++++++--- 14 files changed, 108 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index bd4345e7..d45ffb41 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -45,7 +45,6 @@ import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.SourceIndexVisitor; import cuchaz.enigma.analysis.Token; -import cuchaz.enigma.analysis.TreeDumpVisitor; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.BehaviorEntryFactory; @@ -221,7 +220,7 @@ public class Deobfuscator String outerClassName = m_jarIndex.getOuterClass( classMapping.getObfName() ); if( outerClassName != null ) { - classEntry = new ClassEntry( outerClassName + "$" + classEntry.getSimpleName() ); + classEntry = new ClassEntry( outerClassName + "$" + classMapping.getObfName() ); } if( !m_jarIndex.getObfClassEntries().contains( classEntry ) ) { diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 6179879a..86e52a34 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -13,6 +13,7 @@ package cuchaz.enigma; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -119,7 +120,6 @@ public class TranslatingTypeLoader implements ITypeLoader private byte[] loadType( String deobfClassName ) { - // what class file should we actually load? ClassEntry deobfClassEntry = new ClassEntry( deobfClassName ); ClassEntry obfClassEntry = m_obfuscatingTranslator.translateEntry( deobfClassEntry ); @@ -143,7 +143,7 @@ public class TranslatingTypeLoader implements ITypeLoader String classFileName; if( obfClassEntry.isInnerClass() ) { - // use just the inner class simple name for inner classes + // use just the inner class name for inner classes classFileName = obfClassEntry.getInnerClassName(); } else if( obfClassEntry.getPackageName().equals( Constants.NonePackage ) ) @@ -193,6 +193,9 @@ public class TranslatingTypeLoader implements ITypeLoader // sanity checking assertClassName( c, deobfClassEntry ); + // DEBUG + //Util.writeClass( c ); + // we have a transformed class! return c.toBytecode(); } @@ -227,9 +230,6 @@ public class TranslatingTypeLoader implements ITypeLoader new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); - // DEBUG - //Util.writeClass( c ); - return c; } diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java index 4da2f589..0cde8759 100644 --- a/src/cuchaz/enigma/analysis/EntryReference.java +++ b/src/cuchaz/enigma/analysis/EntryReference.java @@ -79,6 +79,21 @@ public class EntryReference return entry; } + public String getNamableName( ) + { + if( getNameableEntry() instanceof ClassEntry ) + { + ClassEntry classEntry = (ClassEntry)getNameableEntry(); + if( classEntry.isInnerClass() ) + { + // make sure we only rename the inner class name + return classEntry.getInnerClassName(); + } + } + + return getNameableEntry().getName(); + } + @Override public int hashCode( ) { diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 604e4853..ba082064 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -164,9 +164,10 @@ public class JarIndex String outerClassName = findOuterClass( c ); if( outerClassName != null ) { - String innerClassName = Descriptor.toJvmName( c.getName() ); + String innerClassName = c.getSimpleName(); m_innerClasses.put( outerClassName, innerClassName ); - m_outerClasses.put( innerClassName, outerClassName ); + boolean innerWasAdded = m_outerClasses.put( innerClassName, outerClassName ) == null; + assert( innerWasAdded ); BehaviorEntry enclosingBehavior = isAnonymousClass( c, outerClassName ); if( enclosingBehavior != null ) @@ -188,7 +189,7 @@ public class JarIndex Map renames = Maps.newHashMap(); for( Map.Entry entry : m_outerClasses.entrySet() ) { - renames.put( entry.getKey(), entry.getValue() + "$" + new ClassEntry( entry.getKey() ).getSimpleName() ); + renames.put( Constants.NonePackage + "/" + entry.getKey(), entry.getValue() + "$" + entry.getKey() ); } EntryRenamer.renameClassesInSet( renames, m_obfClassEntries ); m_translationIndex.renameClasses( renames ); diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index faae1a14..21a499e8 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -89,14 +89,12 @@ public class SourceIndex // DEBUG //System.out.println( String.format( "%s \"%s\" region: %s", node.getNodeType(), name, region ) ); - /* TODO: double check that we still need this // for tokens representing inner classes, make sure we only get the simple name int pos = node.getText().lastIndexOf( '$' ); if( pos >= 0 ) { token.end -= pos + 1; } - */ return token; } diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java index 9f0845da..849a3233 100644 --- a/src/cuchaz/enigma/bytecode/ClassRenamer.java +++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java @@ -37,34 +37,25 @@ public class ClassRenamer { nameMap.put( entry.getKey().getName(), entry.getValue().getName() ); } + c.replaceClassName( nameMap ); - // translate the names in the InnerClasses attribute + // replace simple names in the InnerClasses attribute too ConstPool constants = c.getClassFile().getConstPool(); InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute( InnerClassesAttribute.tag ); if( attr != null ) { for( int i=0; i ATTR: %s,%s,%s", - obfClassEntry, deobfClassEntry, + System.out.println( String.format( "\tDEOBF: %s-> ATTR: %s,%s,%s", + classEntry, attr.outerClass( i ), attr.innerClass( i ), attr.innerName( i ) @@ -109,16 +100,6 @@ public class ClassRenamer }; c.replaceClassName( map ); - // also check InnerClassesAttribute - InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute( InnerClassesAttribute.tag ); - if( attr != null ) - { - for( int i=0; i map = Maps.newHashMap(); for( ClassEntry obfClassEntry : ClassRenamer.getAllClassEntries( c ) ) { - map.put( obfClassEntry, m_translator.translateEntry( obfClassEntry ) ); + ClassEntry deobfClassEntry = m_translator.translateEntry( obfClassEntry ); + if( !obfClassEntry.equals( deobfClassEntry ) ) + { + map.put( obfClassEntry, deobfClassEntry ); + } } ClassRenamer.renameClasses( c, map ); } diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java index a0617925..5e593078 100644 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -18,6 +18,7 @@ import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; import javassist.bytecode.EnclosingMethodAttribute; import javassist.bytecode.InnerClassesAttribute; +import cuchaz.enigma.Constants; import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; @@ -33,21 +34,21 @@ public class InnerClassWriter public void write( CtClass c ) { - // get the outer class name - String obfClassName = Descriptor.toJvmName( c.getName() ); - String obfOuterClassName = m_jarIndex.getOuterClass( obfClassName ); + // is this an inner or outer class? + String obfInnerClassName = new ClassEntry( Descriptor.toJvmName( c.getName() ) ).getSimpleName(); + String obfOuterClassName = m_jarIndex.getOuterClass( obfInnerClassName ); if( obfOuterClassName == null ) { // this is an outer class - obfOuterClassName = obfClassName; + obfOuterClassName = Descriptor.toJvmName( c.getName() ); } else { // this is an inner class, rename it to outer$inner - ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + new ClassEntry( obfClassName ).getSimpleName() ); + ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfInnerClassName ); c.setName( obfClassEntry.getName() ); - BehaviorEntry caller = m_jarIndex.getAnonymousClassCaller( obfClassName ); + BehaviorEntry caller = m_jarIndex.getAnonymousClassCaller( obfInnerClassName ); if( caller != null ) { // write the enclosing method attribute @@ -85,7 +86,7 @@ public class InnerClassWriter for( String obfInnerClassName : obfInnerClassNames ) { // get the new inner class name - ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + new ClassEntry( obfInnerClassName ).getSimpleName() ); + ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfInnerClassName ); // here's what the JVM spec says about the InnerClasses attribute // append( inner, outer of inner if inner is member of outer 0 ow, name after $ if inner not anonymous 0 ow, flags ); @@ -114,12 +115,13 @@ public class InnerClassWriter attr.outerClass( attr.tableLength() - 1 ), attr.innerClass( attr.tableLength() - 1 ), attr.innerName( attr.tableLength() - 1 ), - obfInnerClassName, obfClassEntry.getName() + Constants.NonePackage + "/" + obfInnerClassName, + obfClassEntry.getName() ) ); */ // make sure the outer class references only the new inner class names - c.replaceClassName( obfInnerClassName, obfClassEntry.getName() ); + c.replaceClassName( Constants.NonePackage + "/" + obfInnerClassName, obfClassEntry.getName() ); } } } diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index dbfcba83..faa9b7b1 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -1124,7 +1124,7 @@ public class Gui { // init the text box final JTextField text = new JTextField(); - text.setText( m_reference.getNameableEntry().getName() ); + text.setText( m_reference.getNamableName() ); text.setPreferredSize( new Dimension( 360, text.getPreferredSize().height ) ); text.addKeyListener( new KeyAdapter( ) { @@ -1175,7 +1175,7 @@ public class Gui // abort the rename JPanel panel = (JPanel)m_infoPanel.getComponent( 0 ); panel.remove( panel.getComponentCount() - 1 ); - panel.add( GuiTricks.unboldLabel( new JLabel( m_reference.getNameableEntry().getName(), JLabel.LEFT ) ) ); + panel.add( GuiTricks.unboldLabel( new JLabel( m_reference.getNamableName(), JLabel.LEFT ) ) ); m_editor.grabFocus(); diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index 88106dfa..ee02781e 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -37,7 +37,7 @@ public class ClassMapping implements Serializable, Comparable public ClassMapping( String obfName, String deobfName ) { m_obfName = obfName; - m_deobfName = NameValidator.validateClassName( deobfName ); + m_deobfName = NameValidator.validateClassName( deobfName, false ); m_innerClassesByObf = Maps.newHashMap(); m_innerClassesByDeobf = Maps.newHashMap(); m_fieldsByObf = Maps.newHashMap(); @@ -57,7 +57,7 @@ public class ClassMapping implements Serializable, Comparable } public void setDeobfName( String val ) { - m_deobfName = NameValidator.validateClassName( val ); + m_deobfName = NameValidator.validateClassName( val, false ); } //// INNER CLASSES //////// @@ -70,10 +70,12 @@ public class ClassMapping implements Serializable, Comparable public void addInnerClassMapping( ClassMapping classMapping ) { + assert( isSimpleClassName( classMapping.getObfName() ) ); boolean obfWasAdded = m_innerClassesByObf.put( classMapping.getObfName(), classMapping ) == null; assert( obfWasAdded ); if( classMapping.getDeobfName() != null ) { + assert( isSimpleClassName( classMapping.getDeobfName() ) ); boolean deobfWasAdded = m_innerClassesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null; assert( deobfWasAdded ); } @@ -92,6 +94,7 @@ public class ClassMapping implements Serializable, Comparable public ClassMapping getOrCreateInnerClass( String obfName ) { + assert( isSimpleClassName( obfName ) ); ClassMapping classMapping = m_innerClassesByObf.get( obfName ); if( classMapping == null ) { @@ -104,16 +107,19 @@ public class ClassMapping implements Serializable, Comparable public ClassMapping getInnerClassByObf( String obfName ) { + assert( isSimpleClassName( obfName ) ); return m_innerClassesByObf.get( obfName ); } public ClassMapping getInnerClassByDeobf( String deobfName ) { + assert( isSimpleClassName( deobfName ) ); return m_innerClassesByDeobf.get( deobfName ); } public String getObfInnerClassName( String deobfName ) { + assert( isSimpleClassName( deobfName ) ); ClassMapping classMapping = m_innerClassesByDeobf.get( deobfName ); if( classMapping != null ) { @@ -124,6 +130,7 @@ public class ClassMapping implements Serializable, Comparable public String getDeobfInnerClassName( String obfName ) { + assert( isSimpleClassName( obfName ) ); ClassMapping classMapping = m_innerClassesByObf.get( obfName ); if( classMapping != null ) { @@ -134,6 +141,7 @@ public class ClassMapping implements Serializable, Comparable public void setInnerClassName( String obfName, String deobfName ) { + assert( isSimpleClassName( obfName ) ); ClassMapping classMapping = getOrCreateInnerClass( obfName ); if( classMapping.getDeobfName() != null ) { @@ -143,6 +151,7 @@ public class ClassMapping implements Serializable, Comparable classMapping.setDeobfName( deobfName ); if( deobfName != null ) { + assert( isSimpleClassName( deobfName ) ); boolean wasAdded = m_innerClassesByDeobf.put( deobfName, classMapping ) == null; assert( wasAdded ); } @@ -442,4 +451,9 @@ public class ClassMapping implements Serializable, Comparable } return false; } + + public static boolean isSimpleClassName( String name ) + { + return name.indexOf( '/' ) < 0 && name.indexOf( '$' ) < 0; + } } diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java index 5cbad59c..4bd9f121 100644 --- a/src/cuchaz/enigma/mapping/MappingsReader.java +++ b/src/cuchaz/enigma/mapping/MappingsReader.java @@ -78,10 +78,11 @@ public class MappingsReader if( token.equalsIgnoreCase( "CLASS" ) ) { - ClassMapping classMapping = readClass( parts ); + ClassMapping classMapping; if( indent == 0 ) { // outer class + classMapping = readClass( parts, false ); mappings.addClassMapping( classMapping ); } else if( indent == 1 ) @@ -91,11 +92,13 @@ public class MappingsReader { throw new MappingParseException( lineNumber, "Unexpected CLASS entry here!" ); } + + classMapping = readClass( parts, true ); ((ClassMapping)mappingStack.getFirst()).addInnerClassMapping( classMapping ); } else { - throw new MappingParseException( lineNumber, "Unexpected CLASS entry here!" ); + throw new MappingParseException( lineNumber, "Unexpected CLASS entry nesting!" ); } mappingStack.push( classMapping ); } @@ -140,28 +143,30 @@ public class MappingsReader return new ArgumentMapping( Integer.parseInt( parts[1] ), parts[2] ); } - private ClassMapping readClass( String[] parts ) + private ClassMapping readClass( String[] parts, boolean makeSimple ) { if( parts.length == 2 ) { - String obfName = parts[1]; - return new ClassMapping( moveClassOutOfDefaultPackage( obfName, Constants.NonePackage ) ); + String obfName = processName( parts[1], makeSimple ); + return new ClassMapping( obfName ); } else { - String obfName = parts[1]; - String deobfName = parts[2]; - if( obfName.equals( deobfName ) ) - { - return new ClassMapping( moveClassOutOfDefaultPackage( obfName, Constants.NonePackage ) ); - } - else - { - return new ClassMapping( - moveClassOutOfDefaultPackage( parts[1], Constants.NonePackage ), - moveClassOutOfDefaultPackage( parts[2], Constants.NonePackage ) - ); - } + String obfName = processName( parts[1], makeSimple ); + String deobfName = processName( parts[2], makeSimple ); + return new ClassMapping( obfName, deobfName ); + } + } + + private String processName( String name, boolean makeSimple ) + { + if( makeSimple ) + { + return new ClassEntry( name ).getSimpleName(); + } + else + { + return moveClassOutOfDefaultPackage( name, Constants.NonePackage ); } } diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index 957b6d68..24ec7318 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -16,6 +16,7 @@ import java.io.OutputStream; import java.util.Set; import java.util.zip.GZIPOutputStream; +import cuchaz.enigma.Constants; import cuchaz.enigma.analysis.JarIndex; public class MappingsRenamer @@ -31,7 +32,7 @@ public class MappingsRenamer public void setClassName( ClassEntry obf, String deobfName ) { - deobfName = NameValidator.validateClassName( deobfName ); + deobfName = NameValidator.validateClassName( deobfName, !obf.isInnerClass() ); ClassEntry targetEntry = new ClassEntry( deobfName ); if( m_mappings.containsDeobfClass( deobfName ) || m_index.containsObfClass( targetEntry ) ) { @@ -77,7 +78,8 @@ public class MappingsRenamer ClassMapping classMapping = getOrCreateClassMapping( obf ); if( obf.isInnerClass() ) { - classMapping.setInnerClassName( obf.getName(), obf.getName() ); + String innerClassName = Constants.NonePackage + "/" + obf.getInnerClassName(); + classMapping.setInnerClassName( innerClassName, innerClassName ); } else { diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java index 9adf1ac1..c6ae5969 100644 --- a/src/cuchaz/enigma/mapping/NameValidator.java +++ b/src/cuchaz/enigma/mapping/NameValidator.java @@ -55,7 +55,7 @@ public class NameValidator ClassPattern = Pattern.compile( String.format( "^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex ) ); } - public static String validateClassName( String name ) + public static String validateClassName( String name, boolean packageRequired ) { if( name == null ) { @@ -65,9 +65,9 @@ public class NameValidator { throw new IllegalNameException( name, "This doesn't look like a legal class name" ); } - if( new ClassEntry( name ).getPackageName() == null ) + if( packageRequired && new ClassEntry( name ).getPackageName() == null ) { - throw new IllegalNameException( name, "Classes must be in a package" ); + throw new IllegalNameException( name, "Class must be in a package" ); } return Descriptor.toJvmName( name ); } diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index 7904ef53..1c69b2f4 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -80,19 +80,26 @@ public class Translator { if( in.isInnerClass() ) { - // look for the inner class + // translate the inner class String translatedInnerClassName = m_direction.choose( classMapping.getDeobfInnerClassName( in.getInnerClassName() ), classMapping.getObfInnerClassName( in.getInnerClassName() ) ); if( translatedInnerClassName != null ) { - // return outer$inner + // try to translate the outer name String translatedOuterClassName = m_direction.choose( classMapping.getDeobfName(), classMapping.getObfName() ); - return translatedOuterClassName + "$" + translatedInnerClassName; + if( translatedOuterClassName != null ) + { + return translatedOuterClassName + "$" + translatedInnerClassName; + } + else + { + return in.getOuterClassName() + "$" + translatedInnerClassName; + } } } else @@ -109,6 +116,7 @@ public class Translator public ClassEntry translateEntry( ClassEntry in ) { + // can we translate the inner class? String name = translate( in ); if( name != null ) { @@ -117,13 +125,14 @@ public class Translator if( in.isInnerClass() ) { - // just translate the outer class name + // guess not. just translate the outer class name then String outerClassName = translate( in.getOuterClassEntry() ); if( outerClassName != null ) { return new ClassEntry( outerClassName + "$" + in.getInnerClassName() ); } } + return in; } -- cgit v1.2.3 From 5eeee98418bb39367258442a82b75a081a6f91e0 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 1 Oct 2014 00:04:18 -0400 Subject: fixed inner class renaming bug also added smarter sorting to class mappings --- src/cuchaz/enigma/Deobfuscator.java | 2 +- src/cuchaz/enigma/Main.java | 3 +- src/cuchaz/enigma/TranslatingTypeLoader.java | 1 - src/cuchaz/enigma/analysis/SourceIndex.java | 2 +- src/cuchaz/enigma/gui/GuiController.java | 1 + src/cuchaz/enigma/mapping/ClassMapping.java | 28 ++++++- src/cuchaz/enigma/mapping/Mappings.java | 26 +------ src/cuchaz/enigma/mapping/MappingsRenamer.java | 11 +-- src/cuchaz/enigma/mapping/Translator.java | 104 +++++++++---------------- 9 files changed, 73 insertions(+), 105 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index d45ffb41..7e0f0927 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -261,7 +261,7 @@ public class Deobfuscator Translator translator = m_translatorCache.get( direction ); if( translator == null ) { - translator = m_mappings.getTranslator( m_jarIndex.getTranslationIndex(), direction ); + translator = m_mappings.getTranslator( direction ); m_translatorCache.put( direction, translator ); } return translator; diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index bbd734c6..371662bc 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -13,6 +13,7 @@ package cuchaz.enigma; import java.io.File; import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.mapping.ClassEntry; public class Main { @@ -32,7 +33,7 @@ public class Main } // DEBUG - //gui.getController().openDeclaration( new ClassEntry( "none/bub" ) ); + gui.getController().openDeclaration( new ClassEntry( "none/ry" ) ); } private static File getFile( String path ) diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 86e52a34..939e342d 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -13,7 +13,6 @@ package cuchaz.enigma; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.Arrays; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 21a499e8..0e33de00 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -90,7 +90,7 @@ public class SourceIndex //System.out.println( String.format( "%s \"%s\" region: %s", node.getNodeType(), name, region ) ); // for tokens representing inner classes, make sure we only get the simple name - int pos = node.getText().lastIndexOf( '$' ); + int pos = name.lastIndexOf( '$' ); if( pos >= 0 ) { token.end -= pos + 1; diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 2862ebed..646bb87d 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -43,6 +43,7 @@ import cuchaz.enigma.mapping.MappingsReader; import cuchaz.enigma.mapping.MappingsWriter; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.TranslationDirection; +import cuchaz.enigma.mapping.Translator; public class GuiController { diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index ee02781e..e084d4df 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -117,6 +117,16 @@ public class ClassMapping implements Serializable, Comparable return m_innerClassesByDeobf.get( deobfName ); } + public ClassMapping getInnerClassByDeobfThenObf( String name ) + { + ClassMapping classMapping = getInnerClassByDeobf( name ); + if( classMapping == null ) + { + classMapping = getInnerClassByObf( name ); + } + return classMapping; + } + public String getObfInnerClassName( String deobfName ) { assert( isSimpleClassName( deobfName ) ); @@ -392,9 +402,18 @@ public class ClassMapping implements Serializable, Comparable buf.append( "\n" ); } buf.append( "Methods:\n" ); - for( MethodMapping methodIndex : m_methodsByObf.values() ) + for( MethodMapping methodMapping : m_methodsByObf.values() ) { - buf.append( methodIndex.toString() ); + buf.append( methodMapping.toString() ); + buf.append( "\n" ); + } + buf.append( "Inner Classes:\n" ); + for( ClassMapping classMapping : m_innerClassesByObf.values() ) + { + buf.append( "\t" ); + buf.append( classMapping.getObfName() ); + buf.append( " <-> " ); + buf.append( classMapping.getDeobfName() ); buf.append( "\n" ); } return buf.toString(); @@ -403,6 +422,11 @@ public class ClassMapping implements Serializable, Comparable @Override public int compareTo( ClassMapping other ) { + // sort by a, b, c, ... aa, ab, etc + if( m_obfName.length() != other.m_obfName.length() ) + { + return m_obfName.length() - other.m_obfName.length(); + } return m_obfName.compareTo( other.m_obfName ); } diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 45b41bcd..3a39d100 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -24,7 +24,6 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import cuchaz.enigma.Util; -import cuchaz.enigma.analysis.TranslationIndex; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class Mappings implements Serializable @@ -125,35 +124,16 @@ public class Mappings implements Serializable return m_classesByDeobf.get( deobfName ); } - public Translator getTranslator( TranslationIndex index, TranslationDirection direction ) + public Translator getTranslator( TranslationDirection direction ) { switch( direction ) { case Deobfuscating: - return new Translator( direction, m_classesByObf, index ); + return new Translator( direction, m_classesByObf ); case Obfuscating: - // deobfuscate the index - index = new TranslationIndex( index ); - Map renames = Maps.newHashMap(); - for( ClassMapping classMapping : classes() ) - { - if( classMapping.getDeobfName() != null ) - { - renames.put( classMapping.getObfName(), classMapping.getDeobfName() ); - } - for( ClassMapping innerClassMapping : classMapping.innerClasses() ) - { - if( innerClassMapping.getDeobfName() != null ) - { - renames.put( innerClassMapping.getObfName(), innerClassMapping.getDeobfName() ); - } - } - } - index.renameClasses( renames ); - // fill in the missing deobf class entries with obf entries Map classes = Maps.newHashMap(); for( ClassMapping classMapping : classes() ) @@ -168,7 +148,7 @@ public class Mappings implements Serializable } } - return new Translator( direction, classes, index ); + return new Translator( direction, classes ); default: throw new Error( "Invalid translation direction!" ); diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index 24ec7318..3e5f1a4d 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -121,11 +121,11 @@ public class MappingsRenamer deobfName = NameValidator.validateMethodName( deobfName ); for( MethodEntry entry : implementations ) { - String deobfSignature = getTranslator( TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); + String deobfSignature = m_mappings.getTranslator( TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); MethodEntry targetEntry = new MethodEntry( entry.getClassEntry(), deobfName, deobfSignature ); if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfBehavior( targetEntry ) ) { - String deobfClassName = getTranslator( TranslationDirection.Deobfuscating ).translateClass( entry.getClassName() ); + String deobfClassName = m_mappings.getTranslator( TranslationDirection.Deobfuscating ).translateClass( entry.getClassName() ); throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName ); } } @@ -142,7 +142,7 @@ public class MappingsRenamer MethodEntry targetEntry = new MethodEntry( obf.getClassEntry(), deobfName, obf.getSignature() ); if( m_mappings.containsDeobfMethod( obf.getClassEntry(), deobfName, obf.getSignature() ) || m_index.containsObfBehavior( targetEntry ) ) { - String deobfClassName = getTranslator( TranslationDirection.Deobfuscating ).translateClass( obf.getClassName() ); + String deobfClassName = m_mappings.getTranslator( TranslationDirection.Deobfuscating ).translateClass( obf.getClassName() ); throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName ); } @@ -288,9 +288,4 @@ public class MappingsRenamer } return classMapping; } - - private Translator getTranslator( TranslationDirection direction ) - { - return m_mappings.getTranslator( m_index.getTranslationIndex(), direction ); - } } diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index 1c69b2f4..6cb52402 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -10,33 +10,27 @@ ******************************************************************************/ package cuchaz.enigma.mapping; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import com.google.common.collect.Maps; -import cuchaz.enigma.analysis.TranslationIndex; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class Translator { private TranslationDirection m_direction; private Map m_classes; - private TranslationIndex m_index; public Translator( ) { m_direction = null; m_classes = Maps.newHashMap(); - m_index = new TranslationIndex(); } - public Translator( TranslationDirection direction, Map classes, TranslationIndex index ) + public Translator( TranslationDirection direction, Map classes ) { m_direction = direction; m_classes = classes; - m_index = index; } @SuppressWarnings( "unchecked" ) @@ -138,28 +132,18 @@ public class Translator public String translate( FieldEntry in ) { - for( String className : getSelfAndAncestors( in.getClassName() ) ) + // look for the class + ClassMapping classMapping = findClassMapping( in.getClassEntry() ); + if( classMapping != null ) { - // look for the class - ClassMapping classMapping = findClassMapping( new ClassEntry( className ) ); - if( classMapping != null ) - { - // look for the field - String translatedName = m_direction.choose( - classMapping.getDeobfFieldName( in.getName() ), - classMapping.getObfFieldName( in.getName() ) - ); - if( translatedName != null ) - { - return translatedName; - } - } - - // is the field implemented in this class? - if( m_index.containsField( className, in.getName() ) ) + // look for the field + String translatedName = m_direction.choose( + classMapping.getDeobfFieldName( in.getName() ), + classMapping.getObfFieldName( in.getName() ) + ); + if( translatedName != null ) { - // stop traversing the superclass chain - break; + return translatedName; } } return null; @@ -180,27 +164,23 @@ public class Translator public String translate( MethodEntry in ) { - for( String className : getSelfAndAncestors( in.getClassName() ) ) + // look for class + ClassMapping classMapping = findClassMapping( in.getClassEntry() ); + if( classMapping != null ) { - // look for class - ClassMapping classMapping = findClassMapping( new ClassEntry( className ) ); - if( classMapping != null ) + // look for the method + MethodMapping methodMapping = m_direction.choose( + classMapping.getMethodByObf( in.getName(), in.getSignature() ), + classMapping.getMethodByDeobf( in.getName(), translateSignature( in.getSignature() ) ) + ); + if( methodMapping != null ) { - // look for the method - MethodMapping methodMapping = m_direction.choose( - classMapping.getMethodByObf( in.getName(), in.getSignature() ), - classMapping.getMethodByDeobf( in.getName(), translateSignature( in.getSignature() ) ) + return m_direction.choose( + methodMapping.getDeobfName(), + methodMapping.getObfName() ); - if( methodMapping != null ) - { - return m_direction.choose( - methodMapping.getDeobfName(), - methodMapping.getObfName() - ); - } } } - return null; } @@ -248,27 +228,23 @@ public class Translator public String translate( ArgumentEntry in ) { - for( String className : getSelfAndAncestors( in.getClassName() ) ) + // look for the class + ClassMapping classMapping = findClassMapping( in.getClassEntry() ); + if( classMapping != null ) { - // look for the class - ClassMapping classMapping = findClassMapping( new ClassEntry( className ) ); - if( classMapping != null ) + // look for the method + MethodMapping methodMapping = m_direction.choose( + classMapping.getMethodByObf( in.getMethodName(), in.getMethodSignature() ), + classMapping.getMethodByDeobf( in.getMethodName(), translateSignature( in.getMethodSignature() ) ) + ); + if( methodMapping != null ) { - // look for the method - MethodMapping methodMapping = m_direction.choose( - classMapping.getMethodByObf( in.getMethodName(), in.getMethodSignature() ), - classMapping.getMethodByDeobf( in.getMethodName(), translateSignature( in.getMethodSignature() ) ) + return m_direction.choose( + methodMapping.getDeobfArgumentName( in.getIndex() ), + methodMapping.getObfArgumentName( in.getIndex() ) ); - if( methodMapping != null ) - { - return m_direction.choose( - methodMapping.getDeobfArgumentName( in.getIndex() ), - methodMapping.getObfArgumentName( in.getIndex() ) - ); - } } } - return null; } @@ -303,14 +279,6 @@ public class Translator } ); } - private List getSelfAndAncestors( String className ) - { - List ancestry = new ArrayList(); - ancestry.add( className ); - ancestry.addAll( m_index.getAncestry( className ) ); - return ancestry; - } - private ClassMapping findClassMapping( ClassEntry classEntry ) { ClassMapping classMapping = m_classes.get( classEntry.getOuterClassName() ); @@ -318,7 +286,7 @@ public class Translator { classMapping = m_direction.choose( classMapping.getInnerClassByObf( classEntry.getInnerClassName() ), - classMapping.getInnerClassByDeobf( classEntry.getInnerClassName() ) + classMapping.getInnerClassByDeobfThenObf( classEntry.getInnerClassName() ) ); } return classMapping; -- cgit v1.2.3 From 056f388494337a0f3cec10fab8e207017757bf6d Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 1 Oct 2014 00:21:29 -0400 Subject: fix inner classes test --- src/cuchaz/enigma/gui/GuiController.java | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 646bb87d..2862ebed 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -43,7 +43,6 @@ import cuchaz.enigma.mapping.MappingsReader; import cuchaz.enigma.mapping.MappingsWriter; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.TranslationDirection; -import cuchaz.enigma.mapping.Translator; public class GuiController { -- cgit v1.2.3 From 42e3b23f03a98a81ce7238bda96c4f046eab30be Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 2 Oct 2014 22:18:23 -0400 Subject: fixed issue with decompiling inner classes --- src/cuchaz/enigma/Deobfuscator.java | 8 +++++--- src/cuchaz/enigma/Main.java | 3 +-- src/cuchaz/enigma/TranslatingTypeLoader.java | 2 +- src/cuchaz/enigma/analysis/JarIndex.java | 5 +++++ 4 files changed, 12 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 7e0f0927..82c786cb 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -127,11 +127,13 @@ public class Deobfuscator Map renames = Maps.newHashMap(); for( ClassMapping classMapping : val.classes() ) { - String outerClassName = m_jarIndex.getOuterClass( classMapping.getObfName() ); + // make sure we strip the packages off of obfuscated inner classes + String innerClassName = new ClassEntry( classMapping.getObfName() ).getSimpleName(); + String outerClassName = m_jarIndex.getOuterClass( innerClassName ); if( outerClassName != null ) { // build the composite class name - String newName = outerClassName + "$" + new ClassEntry( classMapping.getObfName() ).getSimpleName(); + String newName = outerClassName + "$" + innerClassName; // add a rename renames.put( classMapping.getObfName(), newName ); @@ -217,7 +219,7 @@ public class Deobfuscator { // check the class ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); - String outerClassName = m_jarIndex.getOuterClass( classMapping.getObfName() ); + String outerClassName = m_jarIndex.getOuterClass( classEntry.getSimpleName() ); if( outerClassName != null ) { classEntry = new ClassEntry( outerClassName + "$" + classMapping.getObfName() ); diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index 371662bc..73a12db5 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -13,7 +13,6 @@ package cuchaz.enigma; import java.io.File; import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.mapping.ClassEntry; public class Main { @@ -33,7 +32,7 @@ public class Main } // DEBUG - gui.getController().openDeclaration( new ClassEntry( "none/ry" ) ); + //gui.getController().openDeclaration( new ClassEntry( "none/ces" ) ); } private static File getFile( String path ) diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 939e342d..e69e5cfe 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -123,7 +123,7 @@ public class TranslatingTypeLoader implements ITypeLoader ClassEntry obfClassEntry = m_obfuscatingTranslator.translateEntry( deobfClassEntry ); // is this an inner class referenced directly? - String obfOuterClassName = m_jarIndex.getOuterClass( obfClassEntry.getName() ); + String obfOuterClassName = m_jarIndex.getOuterClass( obfClassEntry.getSimpleName() ); if( obfOuterClassName != null ) { // this class doesn't really exist. Reference it by outer$inner instead diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index ba082064..0954564e 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -885,6 +885,11 @@ public class JarIndex public String getOuterClass( String obfInnerClassName ) { + // make sure we use the right name + if( new ClassEntry( obfInnerClassName ).getPackageName() != null ) + { + throw new IllegalArgumentException( "Don't reference obfuscated inner classes using packages: " + obfInnerClassName ); + } return m_outerClasses.get( obfInnerClassName ); } -- cgit v1.2.3 From a1d72afcd4a2f462ba72fdd7a0f2ab82bb795494 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 2 Oct 2014 22:54:30 -0400 Subject: package for 0.6 beta --- src/cuchaz/enigma/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java index bf6ab846..29a08b73 100644 --- a/src/cuchaz/enigma/Constants.java +++ b/src/cuchaz/enigma/Constants.java @@ -14,7 +14,7 @@ package cuchaz.enigma; public class Constants { public static final String Name = "Enigma"; - public static final String Version = "0.5 beta"; + public static final String Version = "0.6 beta"; 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 -- cgit v1.2.3 From 035e73fba69ab06172ae9d784b9e0e4fffeb8388 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 8 Oct 2014 23:54:08 -0400 Subject: relicense as LGPL --- src/cuchaz/enigma/Constants.java | 6 +++--- src/cuchaz/enigma/Deobfuscator.java | 9 ++++----- src/cuchaz/enigma/Main.java | 6 +++--- src/cuchaz/enigma/TranslatingTypeLoader.java | 6 +++--- src/cuchaz/enigma/Util.java | 6 +++--- src/cuchaz/enigma/analysis/Access.java | 8 ++++---- src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/BridgeFixer.java | 6 +++--- src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/EntryReference.java | 6 +++--- src/cuchaz/enigma/analysis/EntryRenamer.java | 6 +++--- src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/JarClassIterator.java | 6 +++--- src/cuchaz/enigma/analysis/JarIndex.java | 6 +++--- src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/ReferenceTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/SourceIndex.java | 6 +++--- src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java | 6 +++--- src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java | 6 +++--- src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 6 +++--- src/cuchaz/enigma/analysis/Token.java | 6 +++--- src/cuchaz/enigma/analysis/TranslationIndex.java | 6 +++--- src/cuchaz/enigma/analysis/TreeDumpVisitor.java | 6 +++--- src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java | 6 +++--- src/cuchaz/enigma/bytecode/BytecodeTools.java | 6 +++--- src/cuchaz/enigma/bytecode/CheckCastIterator.java | 6 +++--- src/cuchaz/enigma/bytecode/ClassRenamer.java | 6 +++--- src/cuchaz/enigma/bytecode/ClassTranslator.java | 6 +++--- src/cuchaz/enigma/bytecode/ConstPoolEditor.java | 6 +++--- src/cuchaz/enigma/bytecode/InfoType.java | 6 +++--- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 6 +++--- src/cuchaz/enigma/bytecode/MethodParameterWriter.java | 6 +++--- src/cuchaz/enigma/bytecode/MethodParametersAttribute.java | 6 +++--- src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java | 6 +++--- src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java | 6 +++--- .../enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java | 6 +++--- src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java | 6 +++--- .../enigma/bytecode/accessors/MethodHandleInfoAccessor.java | 6 +++--- src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java | 6 +++--- .../enigma/bytecode/accessors/NameAndTypeInfoAccessor.java | 6 +++--- src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java | 6 +++--- src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java | 6 +++--- src/cuchaz/enigma/convert/ClassIdentity.java | 6 +++--- src/cuchaz/enigma/convert/ClassMatcher.java | 6 +++--- src/cuchaz/enigma/convert/ClassMatching.java | 6 +++--- src/cuchaz/enigma/convert/ClassNamer.java | 6 +++--- src/cuchaz/enigma/gui/AboutDialog.java | 6 +++--- src/cuchaz/enigma/gui/BoxHighlightPainter.java | 6 +++--- src/cuchaz/enigma/gui/BrowserCaret.java | 6 +++--- src/cuchaz/enigma/gui/ClassListCellRenderer.java | 6 +++--- src/cuchaz/enigma/gui/ClassSelector.java | 6 +++--- src/cuchaz/enigma/gui/ClassSelectorClassNode.java | 6 +++--- src/cuchaz/enigma/gui/ClassSelectorPackageNode.java | 6 +++--- src/cuchaz/enigma/gui/CrashDialog.java | 6 +++--- src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java | 6 +++--- src/cuchaz/enigma/gui/Gui.java | 6 +++--- src/cuchaz/enigma/gui/GuiController.java | 6 +++--- src/cuchaz/enigma/gui/GuiTricks.java | 6 +++--- src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java | 6 +++--- src/cuchaz/enigma/gui/OtherHighlightPainter.java | 6 +++--- src/cuchaz/enigma/gui/ProgressDialog.java | 6 +++--- src/cuchaz/enigma/gui/ReadableToken.java | 6 +++--- src/cuchaz/enigma/gui/RenameListener.java | 6 +++--- src/cuchaz/enigma/gui/SelectionHighlightPainter.java | 6 +++--- src/cuchaz/enigma/gui/TokenListCellRenderer.java | 6 +++--- src/cuchaz/enigma/mapping/ArgumentEntry.java | 6 +++--- src/cuchaz/enigma/mapping/ArgumentMapping.java | 6 +++--- src/cuchaz/enigma/mapping/BehaviorEntry.java | 6 +++--- src/cuchaz/enigma/mapping/BehaviorEntryFactory.java | 6 +++--- src/cuchaz/enigma/mapping/ClassEntry.java | 6 +++--- src/cuchaz/enigma/mapping/ClassMapping.java | 6 +++--- src/cuchaz/enigma/mapping/ConstructorEntry.java | 6 +++--- src/cuchaz/enigma/mapping/Entry.java | 6 +++--- src/cuchaz/enigma/mapping/EntryPair.java | 6 +++--- src/cuchaz/enigma/mapping/FieldEntry.java | 6 +++--- src/cuchaz/enigma/mapping/FieldMapping.java | 6 +++--- src/cuchaz/enigma/mapping/IllegalNameException.java | 6 +++--- src/cuchaz/enigma/mapping/MappingParseException.java | 6 +++--- src/cuchaz/enigma/mapping/Mappings.java | 6 +++--- src/cuchaz/enigma/mapping/MappingsReader.java | 6 +++--- src/cuchaz/enigma/mapping/MappingsRenamer.java | 6 +++--- src/cuchaz/enigma/mapping/MappingsWriter.java | 6 +++--- src/cuchaz/enigma/mapping/MethodEntry.java | 6 +++--- src/cuchaz/enigma/mapping/MethodMapping.java | 6 +++--- src/cuchaz/enigma/mapping/NameValidator.java | 6 +++--- src/cuchaz/enigma/mapping/SignatureUpdater.java | 6 +++--- src/cuchaz/enigma/mapping/TranslationDirection.java | 6 +++--- src/cuchaz/enigma/mapping/Translator.java | 6 +++--- 90 files changed, 272 insertions(+), 273 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java index 29a08b73..065e9f0c 100644 --- a/src/cuchaz/enigma/Constants.java +++ b/src/cuchaz/enigma/Constants.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 82c786cb..186a9934 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -1,10 +1,9 @@ /******************************************************************************* - * Copyright (c) 2014 Jeff Martin.\ - * + * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index 73a12db5..c9b2761c 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index e69e5cfe..0f2a1c13 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/Util.java b/src/cuchaz/enigma/Util.java index 678de546..fad92d7a 100644 --- a/src/cuchaz/enigma/Util.java +++ b/src/cuchaz/enigma/Util.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/Access.java b/src/cuchaz/enigma/analysis/Access.java index e35bb21b..7ef4dcdd 100644 --- a/src/cuchaz/enigma/analysis/Access.java +++ b/src/cuchaz/enigma/analysis/Access.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation @@ -48,4 +48,4 @@ public enum Access // assume public by default return Public; } -} \ No newline at end of file +} diff --git a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java index 20f1d472..2a5dfe5f 100644 --- a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java index 112b864a..50b0315c 100644 --- a/src/cuchaz/enigma/analysis/BridgeFixer.java +++ b/src/cuchaz/enigma/analysis/BridgeFixer.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java index 4e9dd523..bf563f1f 100644 --- a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java index d3fc9dc8..5e080e82 100644 --- a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java index 0cde8759..001ea764 100644 --- a/src/cuchaz/enigma/analysis/EntryReference.java +++ b/src/cuchaz/enigma/analysis/EntryReference.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java index 2d59fe9d..a9447e66 100644 --- a/src/cuchaz/enigma/analysis/EntryRenamer.java +++ b/src/cuchaz/enigma/analysis/EntryRenamer.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java index 2652f64a..a0ad8076 100644 --- a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/JarClassIterator.java b/src/cuchaz/enigma/analysis/JarClassIterator.java index f65b8e79..c1a1c6cd 100644 --- a/src/cuchaz/enigma/analysis/JarClassIterator.java +++ b/src/cuchaz/enigma/analysis/JarClassIterator.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 0954564e..d124a241 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java index a050282b..fa10c333 100644 --- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index bd919518..484f81b0 100644 --- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java index e0a0a747..11ff8502 100644 --- a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 0e33de00..95a06020 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index 7ffd1700..e2742544 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index 24c48227..81d1568a 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java index 4e98989e..b6bf9d0c 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/Token.java b/src/cuchaz/enigma/analysis/Token.java index 5e70db71..388acd4c 100644 --- a/src/cuchaz/enigma/analysis/Token.java +++ b/src/cuchaz/enigma/analysis/Token.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java index 5311ec70..f2f6e0ad 100644 --- a/src/cuchaz/enigma/analysis/TranslationIndex.java +++ b/src/cuchaz/enigma/analysis/TranslationIndex.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java index e6ecb10e..4ad234b6 100644 --- a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java +++ b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java index aadbeb25..fb171994 100644 --- a/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java +++ b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/BytecodeTools.java b/src/cuchaz/enigma/bytecode/BytecodeTools.java index 4407a904..eaf5de53 100644 --- a/src/cuchaz/enigma/bytecode/BytecodeTools.java +++ b/src/cuchaz/enigma/bytecode/BytecodeTools.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/CheckCastIterator.java b/src/cuchaz/enigma/bytecode/CheckCastIterator.java index 7ed5d7fb..ba77dbb7 100644 --- a/src/cuchaz/enigma/bytecode/CheckCastIterator.java +++ b/src/cuchaz/enigma/bytecode/CheckCastIterator.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java index 849a3233..f2f9e2d5 100644 --- a/src/cuchaz/enigma/bytecode/ClassRenamer.java +++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index 181fadb1..d375b154 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/ConstPoolEditor.java b/src/cuchaz/enigma/bytecode/ConstPoolEditor.java index aa6149c9..9b1f7915 100644 --- a/src/cuchaz/enigma/bytecode/ConstPoolEditor.java +++ b/src/cuchaz/enigma/bytecode/ConstPoolEditor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/InfoType.java b/src/cuchaz/enigma/bytecode/InfoType.java index fe030066..eba3bec4 100644 --- a/src/cuchaz/enigma/bytecode/InfoType.java +++ b/src/cuchaz/enigma/bytecode/InfoType.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java index 5e593078..027c4680 100644 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java index adea7eae..867599c6 100644 --- a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java +++ b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java b/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java index baf1ac1e..3399cf1e 100644 --- a/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java +++ b/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java index 41e1d047..7269f2ab 100644 --- a/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java index 3c3d3fa4..a2d21ca2 100644 --- a/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java index 169306a4..8ae2ad40 100644 --- a/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java index 2ee3aff8..7b83ca2b 100644 --- a/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java index 27b7aee8..5503d867 100644 --- a/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java index 4cba6a2a..3df8ca1c 100644 --- a/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java index 03b4de3c..4d4c50a5 100644 --- a/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java index 5cdfce4d..6f65a417 100644 --- a/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java index 1cadd836..f532137e 100644 --- a/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java index 1de345ff..6b865f80 100644 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ b/src/cuchaz/enigma/convert/ClassIdentity.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java index 290d90a7..168bda67 100644 --- a/src/cuchaz/enigma/convert/ClassMatcher.java +++ b/src/cuchaz/enigma/convert/ClassMatcher.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java index e45c0e1a..6856fc06 100644 --- a/src/cuchaz/enigma/convert/ClassMatching.java +++ b/src/cuchaz/enigma/convert/ClassMatching.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/convert/ClassNamer.java b/src/cuchaz/enigma/convert/ClassNamer.java index a01aec5c..3401a8bc 100644 --- a/src/cuchaz/enigma/convert/ClassNamer.java +++ b/src/cuchaz/enigma/convert/ClassNamer.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/AboutDialog.java b/src/cuchaz/enigma/gui/AboutDialog.java index a245956e..c2716315 100644 --- a/src/cuchaz/enigma/gui/AboutDialog.java +++ b/src/cuchaz/enigma/gui/AboutDialog.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/BoxHighlightPainter.java b/src/cuchaz/enigma/gui/BoxHighlightPainter.java index df63f5a8..fee8776f 100644 --- a/src/cuchaz/enigma/gui/BoxHighlightPainter.java +++ b/src/cuchaz/enigma/gui/BoxHighlightPainter.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/BrowserCaret.java b/src/cuchaz/enigma/gui/BrowserCaret.java index f7e608bb..5f17ef0d 100644 --- a/src/cuchaz/enigma/gui/BrowserCaret.java +++ b/src/cuchaz/enigma/gui/BrowserCaret.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/ClassListCellRenderer.java b/src/cuchaz/enigma/gui/ClassListCellRenderer.java index d9d65788..610aa15a 100644 --- a/src/cuchaz/enigma/gui/ClassListCellRenderer.java +++ b/src/cuchaz/enigma/gui/ClassListCellRenderer.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/ClassSelector.java b/src/cuchaz/enigma/gui/ClassSelector.java index 8365def1..094b5380 100644 --- a/src/cuchaz/enigma/gui/ClassSelector.java +++ b/src/cuchaz/enigma/gui/ClassSelector.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java index cffa7952..791e3c4b 100644 --- a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java +++ b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java b/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java index ad88fb44..6215188c 100644 --- a/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java +++ b/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/CrashDialog.java b/src/cuchaz/enigma/gui/CrashDialog.java index 0eb9830c..178342cd 100644 --- a/src/cuchaz/enigma/gui/CrashDialog.java +++ b/src/cuchaz/enigma/gui/CrashDialog.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java b/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java index 6a428842..c8bce3d0 100644 --- a/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java +++ b/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index faa9b7b1..87c14200 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 2862ebed..7da79c6c 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/GuiTricks.java b/src/cuchaz/enigma/gui/GuiTricks.java index 9b889ef4..a276753b 100644 --- a/src/cuchaz/enigma/gui/GuiTricks.java +++ b/src/cuchaz/enigma/gui/GuiTricks.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java b/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java index 724be34e..d586bab9 100644 --- a/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java +++ b/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/OtherHighlightPainter.java b/src/cuchaz/enigma/gui/OtherHighlightPainter.java index 78de7325..782bb243 100644 --- a/src/cuchaz/enigma/gui/OtherHighlightPainter.java +++ b/src/cuchaz/enigma/gui/OtherHighlightPainter.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/ProgressDialog.java b/src/cuchaz/enigma/gui/ProgressDialog.java index 7f954314..be2c1792 100644 --- a/src/cuchaz/enigma/gui/ProgressDialog.java +++ b/src/cuchaz/enigma/gui/ProgressDialog.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/ReadableToken.java b/src/cuchaz/enigma/gui/ReadableToken.java index 3f430453..f4156edf 100644 --- a/src/cuchaz/enigma/gui/ReadableToken.java +++ b/src/cuchaz/enigma/gui/ReadableToken.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/RenameListener.java b/src/cuchaz/enigma/gui/RenameListener.java index 7d45505b..3d824b8d 100644 --- a/src/cuchaz/enigma/gui/RenameListener.java +++ b/src/cuchaz/enigma/gui/RenameListener.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/SelectionHighlightPainter.java b/src/cuchaz/enigma/gui/SelectionHighlightPainter.java index 35f94518..9d8d38a3 100644 --- a/src/cuchaz/enigma/gui/SelectionHighlightPainter.java +++ b/src/cuchaz/enigma/gui/SelectionHighlightPainter.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/gui/TokenListCellRenderer.java b/src/cuchaz/enigma/gui/TokenListCellRenderer.java index 9247c066..4561dcb2 100644 --- a/src/cuchaz/enigma/gui/TokenListCellRenderer.java +++ b/src/cuchaz/enigma/gui/TokenListCellRenderer.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java index 7ed3d328..96d7e71e 100644 --- a/src/cuchaz/enigma/mapping/ArgumentEntry.java +++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/ArgumentMapping.java b/src/cuchaz/enigma/mapping/ArgumentMapping.java index 168306a2..12f28828 100644 --- a/src/cuchaz/enigma/mapping/ArgumentMapping.java +++ b/src/cuchaz/enigma/mapping/ArgumentMapping.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/BehaviorEntry.java b/src/cuchaz/enigma/mapping/BehaviorEntry.java index 8fc4eaf0..0eac62bf 100644 --- a/src/cuchaz/enigma/mapping/BehaviorEntry.java +++ b/src/cuchaz/enigma/mapping/BehaviorEntry.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java index d3cfb938..95352f04 100644 --- a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java +++ b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index 2c708f2a..cad2c527 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index e084d4df..14f46a4b 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java index d99d1c35..befb0f6e 100644 --- a/src/cuchaz/enigma/mapping/ConstructorEntry.java +++ b/src/cuchaz/enigma/mapping/ConstructorEntry.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/Entry.java b/src/cuchaz/enigma/mapping/Entry.java index 8524834c..a948e1dc 100644 --- a/src/cuchaz/enigma/mapping/Entry.java +++ b/src/cuchaz/enigma/mapping/Entry.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/EntryPair.java b/src/cuchaz/enigma/mapping/EntryPair.java index f94d77ea..3b2e9ed8 100644 --- a/src/cuchaz/enigma/mapping/EntryPair.java +++ b/src/cuchaz/enigma/mapping/EntryPair.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java index 626af576..76a54329 100644 --- a/src/cuchaz/enigma/mapping/FieldEntry.java +++ b/src/cuchaz/enigma/mapping/FieldEntry.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/FieldMapping.java b/src/cuchaz/enigma/mapping/FieldMapping.java index ae0855a8..83c56efa 100644 --- a/src/cuchaz/enigma/mapping/FieldMapping.java +++ b/src/cuchaz/enigma/mapping/FieldMapping.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/IllegalNameException.java b/src/cuchaz/enigma/mapping/IllegalNameException.java index 830f05c4..4cab5945 100644 --- a/src/cuchaz/enigma/mapping/IllegalNameException.java +++ b/src/cuchaz/enigma/mapping/IllegalNameException.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/MappingParseException.java b/src/cuchaz/enigma/mapping/MappingParseException.java index 4fcc1f18..c0d21d20 100644 --- a/src/cuchaz/enigma/mapping/MappingParseException.java +++ b/src/cuchaz/enigma/mapping/MappingParseException.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 3a39d100..dfe06ddf 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java index 4bd9f121..058a666d 100644 --- a/src/cuchaz/enigma/mapping/MappingsReader.java +++ b/src/cuchaz/enigma/mapping/MappingsReader.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index 3e5f1a4d..98ed51df 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/MappingsWriter.java b/src/cuchaz/enigma/mapping/MappingsWriter.java index 3c86dfc0..306d9a63 100644 --- a/src/cuchaz/enigma/mapping/MappingsWriter.java +++ b/src/cuchaz/enigma/mapping/MappingsWriter.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index dbc18855..4aafa0f8 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java index c51b0110..eb45331f 100644 --- a/src/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/cuchaz/enigma/mapping/MethodMapping.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java index c6ae5969..d337d94d 100644 --- a/src/cuchaz/enigma/mapping/NameValidator.java +++ b/src/cuchaz/enigma/mapping/NameValidator.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/SignatureUpdater.java b/src/cuchaz/enigma/mapping/SignatureUpdater.java index 809473e5..1b56a09f 100644 --- a/src/cuchaz/enigma/mapping/SignatureUpdater.java +++ b/src/cuchaz/enigma/mapping/SignatureUpdater.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/TranslationDirection.java b/src/cuchaz/enigma/mapping/TranslationDirection.java index 79ae0d32..87b79dfe 100644 --- a/src/cuchaz/enigma/mapping/TranslationDirection.java +++ b/src/cuchaz/enigma/mapping/TranslationDirection.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index 6cb52402..d239b5e8 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -1,9 +1,9 @@ /******************************************************************************* * 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 + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation -- cgit v1.2.3 From 812e2a4630ef01463ff153ba5ffae675e8ac24ac Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 9 Oct 2014 19:37:19 -0400 Subject: reverting to GPL license --- src/cuchaz/enigma/Constants.java | 6 +++--- src/cuchaz/enigma/Deobfuscator.java | 9 +++++---- src/cuchaz/enigma/Main.java | 6 +++--- src/cuchaz/enigma/TranslatingTypeLoader.java | 6 +++--- src/cuchaz/enigma/Util.java | 6 +++--- src/cuchaz/enigma/analysis/Access.java | 8 ++++---- src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/BridgeFixer.java | 6 +++--- src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/EntryReference.java | 6 +++--- src/cuchaz/enigma/analysis/EntryRenamer.java | 6 +++--- src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/JarClassIterator.java | 6 +++--- src/cuchaz/enigma/analysis/JarIndex.java | 6 +++--- src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/ReferenceTreeNode.java | 6 +++--- src/cuchaz/enigma/analysis/SourceIndex.java | 6 +++--- src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java | 6 +++--- src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java | 6 +++--- src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 6 +++--- src/cuchaz/enigma/analysis/Token.java | 6 +++--- src/cuchaz/enigma/analysis/TranslationIndex.java | 6 +++--- src/cuchaz/enigma/analysis/TreeDumpVisitor.java | 6 +++--- src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java | 6 +++--- src/cuchaz/enigma/bytecode/BytecodeTools.java | 6 +++--- src/cuchaz/enigma/bytecode/CheckCastIterator.java | 6 +++--- src/cuchaz/enigma/bytecode/ClassRenamer.java | 6 +++--- src/cuchaz/enigma/bytecode/ClassTranslator.java | 6 +++--- src/cuchaz/enigma/bytecode/ConstPoolEditor.java | 6 +++--- src/cuchaz/enigma/bytecode/InfoType.java | 6 +++--- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 6 +++--- src/cuchaz/enigma/bytecode/MethodParameterWriter.java | 6 +++--- src/cuchaz/enigma/bytecode/MethodParametersAttribute.java | 6 +++--- src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java | 6 +++--- src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java | 6 +++--- .../enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java | 6 +++--- src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java | 6 +++--- .../enigma/bytecode/accessors/MethodHandleInfoAccessor.java | 6 +++--- src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java | 6 +++--- .../enigma/bytecode/accessors/NameAndTypeInfoAccessor.java | 6 +++--- src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java | 6 +++--- src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java | 6 +++--- src/cuchaz/enigma/convert/ClassIdentity.java | 6 +++--- src/cuchaz/enigma/convert/ClassMatcher.java | 6 +++--- src/cuchaz/enigma/convert/ClassMatching.java | 6 +++--- src/cuchaz/enigma/convert/ClassNamer.java | 6 +++--- src/cuchaz/enigma/gui/AboutDialog.java | 6 +++--- src/cuchaz/enigma/gui/BoxHighlightPainter.java | 6 +++--- src/cuchaz/enigma/gui/BrowserCaret.java | 6 +++--- src/cuchaz/enigma/gui/ClassListCellRenderer.java | 6 +++--- src/cuchaz/enigma/gui/ClassSelector.java | 6 +++--- src/cuchaz/enigma/gui/ClassSelectorClassNode.java | 6 +++--- src/cuchaz/enigma/gui/ClassSelectorPackageNode.java | 6 +++--- src/cuchaz/enigma/gui/CrashDialog.java | 6 +++--- src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java | 6 +++--- src/cuchaz/enigma/gui/Gui.java | 6 +++--- src/cuchaz/enigma/gui/GuiController.java | 6 +++--- src/cuchaz/enigma/gui/GuiTricks.java | 6 +++--- src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java | 6 +++--- src/cuchaz/enigma/gui/OtherHighlightPainter.java | 6 +++--- src/cuchaz/enigma/gui/ProgressDialog.java | 6 +++--- src/cuchaz/enigma/gui/ReadableToken.java | 6 +++--- src/cuchaz/enigma/gui/RenameListener.java | 6 +++--- src/cuchaz/enigma/gui/SelectionHighlightPainter.java | 6 +++--- src/cuchaz/enigma/gui/TokenListCellRenderer.java | 6 +++--- src/cuchaz/enigma/mapping/ArgumentEntry.java | 6 +++--- src/cuchaz/enigma/mapping/ArgumentMapping.java | 6 +++--- src/cuchaz/enigma/mapping/BehaviorEntry.java | 6 +++--- src/cuchaz/enigma/mapping/BehaviorEntryFactory.java | 6 +++--- src/cuchaz/enigma/mapping/ClassEntry.java | 6 +++--- src/cuchaz/enigma/mapping/ClassMapping.java | 6 +++--- src/cuchaz/enigma/mapping/ConstructorEntry.java | 6 +++--- src/cuchaz/enigma/mapping/Entry.java | 6 +++--- src/cuchaz/enigma/mapping/EntryPair.java | 6 +++--- src/cuchaz/enigma/mapping/FieldEntry.java | 6 +++--- src/cuchaz/enigma/mapping/FieldMapping.java | 6 +++--- src/cuchaz/enigma/mapping/IllegalNameException.java | 6 +++--- src/cuchaz/enigma/mapping/MappingParseException.java | 6 +++--- src/cuchaz/enigma/mapping/Mappings.java | 6 +++--- src/cuchaz/enigma/mapping/MappingsReader.java | 6 +++--- src/cuchaz/enigma/mapping/MappingsRenamer.java | 6 +++--- src/cuchaz/enigma/mapping/MappingsWriter.java | 6 +++--- src/cuchaz/enigma/mapping/MethodEntry.java | 6 +++--- src/cuchaz/enigma/mapping/MethodMapping.java | 6 +++--- src/cuchaz/enigma/mapping/NameValidator.java | 6 +++--- src/cuchaz/enigma/mapping/SignatureUpdater.java | 6 +++--- src/cuchaz/enigma/mapping/TranslationDirection.java | 6 +++--- src/cuchaz/enigma/mapping/Translator.java | 6 +++--- 90 files changed, 273 insertions(+), 272 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java index 065e9f0c..29a08b73 100644 --- a/src/cuchaz/enigma/Constants.java +++ b/src/cuchaz/enigma/Constants.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 186a9934..82c786cb 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2014 Jeff Martin. + * Copyright (c) 2014 Jeff Martin.\ + * * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index c9b2761c..73a12db5 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 0f2a1c13..e69e5cfe 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/Util.java b/src/cuchaz/enigma/Util.java index fad92d7a..678de546 100644 --- a/src/cuchaz/enigma/Util.java +++ b/src/cuchaz/enigma/Util.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/Access.java b/src/cuchaz/enigma/analysis/Access.java index 7ef4dcdd..e35bb21b 100644 --- a/src/cuchaz/enigma/analysis/Access.java +++ b/src/cuchaz/enigma/analysis/Access.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 @@ -48,4 +48,4 @@ public enum Access // assume public by default return Public; } -} +} \ No newline at end of file diff --git a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java index 2a5dfe5f..20f1d472 100644 --- a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java index 50b0315c..112b864a 100644 --- a/src/cuchaz/enigma/analysis/BridgeFixer.java +++ b/src/cuchaz/enigma/analysis/BridgeFixer.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java index bf563f1f..4e9dd523 100644 --- a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java index 5e080e82..d3fc9dc8 100644 --- a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java index 001ea764..0cde8759 100644 --- a/src/cuchaz/enigma/analysis/EntryReference.java +++ b/src/cuchaz/enigma/analysis/EntryReference.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java index a9447e66..2d59fe9d 100644 --- a/src/cuchaz/enigma/analysis/EntryRenamer.java +++ b/src/cuchaz/enigma/analysis/EntryRenamer.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java index a0ad8076..2652f64a 100644 --- a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/JarClassIterator.java b/src/cuchaz/enigma/analysis/JarClassIterator.java index c1a1c6cd..f65b8e79 100644 --- a/src/cuchaz/enigma/analysis/JarClassIterator.java +++ b/src/cuchaz/enigma/analysis/JarClassIterator.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index d124a241..0954564e 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java index fa10c333..a050282b 100644 --- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index 484f81b0..bd919518 100644 --- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java index 11ff8502..e0a0a747 100644 --- a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 95a06020..0e33de00 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index e2742544..7ffd1700 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index 81d1568a..24c48227 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java index b6bf9d0c..4e98989e 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/Token.java b/src/cuchaz/enigma/analysis/Token.java index 388acd4c..5e70db71 100644 --- a/src/cuchaz/enigma/analysis/Token.java +++ b/src/cuchaz/enigma/analysis/Token.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java index f2f6e0ad..5311ec70 100644 --- a/src/cuchaz/enigma/analysis/TranslationIndex.java +++ b/src/cuchaz/enigma/analysis/TranslationIndex.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java index 4ad234b6..e6ecb10e 100644 --- a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java +++ b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java index fb171994..aadbeb25 100644 --- a/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java +++ b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/BytecodeTools.java b/src/cuchaz/enigma/bytecode/BytecodeTools.java index eaf5de53..4407a904 100644 --- a/src/cuchaz/enigma/bytecode/BytecodeTools.java +++ b/src/cuchaz/enigma/bytecode/BytecodeTools.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/CheckCastIterator.java b/src/cuchaz/enigma/bytecode/CheckCastIterator.java index ba77dbb7..7ed5d7fb 100644 --- a/src/cuchaz/enigma/bytecode/CheckCastIterator.java +++ b/src/cuchaz/enigma/bytecode/CheckCastIterator.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java index f2f9e2d5..849a3233 100644 --- a/src/cuchaz/enigma/bytecode/ClassRenamer.java +++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index d375b154..181fadb1 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/ConstPoolEditor.java b/src/cuchaz/enigma/bytecode/ConstPoolEditor.java index 9b1f7915..aa6149c9 100644 --- a/src/cuchaz/enigma/bytecode/ConstPoolEditor.java +++ b/src/cuchaz/enigma/bytecode/ConstPoolEditor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/InfoType.java b/src/cuchaz/enigma/bytecode/InfoType.java index eba3bec4..fe030066 100644 --- a/src/cuchaz/enigma/bytecode/InfoType.java +++ b/src/cuchaz/enigma/bytecode/InfoType.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java index 027c4680..5e593078 100644 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java index 867599c6..adea7eae 100644 --- a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java +++ b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java b/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java index 3399cf1e..baf1ac1e 100644 --- a/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java +++ b/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java index 7269f2ab..41e1d047 100644 --- a/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java index a2d21ca2..3c3d3fa4 100644 --- a/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java index 8ae2ad40..169306a4 100644 --- a/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java index 7b83ca2b..2ee3aff8 100644 --- a/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java index 5503d867..27b7aee8 100644 --- a/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java index 3df8ca1c..4cba6a2a 100644 --- a/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java index 4d4c50a5..03b4de3c 100644 --- a/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java index 6f65a417..5cdfce4d 100644 --- a/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java index f532137e..1cadd836 100644 --- a/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java index 6b865f80..1de345ff 100644 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ b/src/cuchaz/enigma/convert/ClassIdentity.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java index 168bda67..290d90a7 100644 --- a/src/cuchaz/enigma/convert/ClassMatcher.java +++ b/src/cuchaz/enigma/convert/ClassMatcher.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java index 6856fc06..e45c0e1a 100644 --- a/src/cuchaz/enigma/convert/ClassMatching.java +++ b/src/cuchaz/enigma/convert/ClassMatching.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/convert/ClassNamer.java b/src/cuchaz/enigma/convert/ClassNamer.java index 3401a8bc..a01aec5c 100644 --- a/src/cuchaz/enigma/convert/ClassNamer.java +++ b/src/cuchaz/enigma/convert/ClassNamer.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/AboutDialog.java b/src/cuchaz/enigma/gui/AboutDialog.java index c2716315..a245956e 100644 --- a/src/cuchaz/enigma/gui/AboutDialog.java +++ b/src/cuchaz/enigma/gui/AboutDialog.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/BoxHighlightPainter.java b/src/cuchaz/enigma/gui/BoxHighlightPainter.java index fee8776f..df63f5a8 100644 --- a/src/cuchaz/enigma/gui/BoxHighlightPainter.java +++ b/src/cuchaz/enigma/gui/BoxHighlightPainter.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/BrowserCaret.java b/src/cuchaz/enigma/gui/BrowserCaret.java index 5f17ef0d..f7e608bb 100644 --- a/src/cuchaz/enigma/gui/BrowserCaret.java +++ b/src/cuchaz/enigma/gui/BrowserCaret.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/ClassListCellRenderer.java b/src/cuchaz/enigma/gui/ClassListCellRenderer.java index 610aa15a..d9d65788 100644 --- a/src/cuchaz/enigma/gui/ClassListCellRenderer.java +++ b/src/cuchaz/enigma/gui/ClassListCellRenderer.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/ClassSelector.java b/src/cuchaz/enigma/gui/ClassSelector.java index 094b5380..8365def1 100644 --- a/src/cuchaz/enigma/gui/ClassSelector.java +++ b/src/cuchaz/enigma/gui/ClassSelector.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java index 791e3c4b..cffa7952 100644 --- a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java +++ b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java b/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java index 6215188c..ad88fb44 100644 --- a/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java +++ b/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/CrashDialog.java b/src/cuchaz/enigma/gui/CrashDialog.java index 178342cd..0eb9830c 100644 --- a/src/cuchaz/enigma/gui/CrashDialog.java +++ b/src/cuchaz/enigma/gui/CrashDialog.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java b/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java index c8bce3d0..6a428842 100644 --- a/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java +++ b/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 87c14200..faa9b7b1 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 7da79c6c..2862ebed 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/GuiTricks.java b/src/cuchaz/enigma/gui/GuiTricks.java index a276753b..9b889ef4 100644 --- a/src/cuchaz/enigma/gui/GuiTricks.java +++ b/src/cuchaz/enigma/gui/GuiTricks.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java b/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java index d586bab9..724be34e 100644 --- a/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java +++ b/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/OtherHighlightPainter.java b/src/cuchaz/enigma/gui/OtherHighlightPainter.java index 782bb243..78de7325 100644 --- a/src/cuchaz/enigma/gui/OtherHighlightPainter.java +++ b/src/cuchaz/enigma/gui/OtherHighlightPainter.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/ProgressDialog.java b/src/cuchaz/enigma/gui/ProgressDialog.java index be2c1792..7f954314 100644 --- a/src/cuchaz/enigma/gui/ProgressDialog.java +++ b/src/cuchaz/enigma/gui/ProgressDialog.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/ReadableToken.java b/src/cuchaz/enigma/gui/ReadableToken.java index f4156edf..3f430453 100644 --- a/src/cuchaz/enigma/gui/ReadableToken.java +++ b/src/cuchaz/enigma/gui/ReadableToken.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/RenameListener.java b/src/cuchaz/enigma/gui/RenameListener.java index 3d824b8d..7d45505b 100644 --- a/src/cuchaz/enigma/gui/RenameListener.java +++ b/src/cuchaz/enigma/gui/RenameListener.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/SelectionHighlightPainter.java b/src/cuchaz/enigma/gui/SelectionHighlightPainter.java index 9d8d38a3..35f94518 100644 --- a/src/cuchaz/enigma/gui/SelectionHighlightPainter.java +++ b/src/cuchaz/enigma/gui/SelectionHighlightPainter.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/gui/TokenListCellRenderer.java b/src/cuchaz/enigma/gui/TokenListCellRenderer.java index 4561dcb2..9247c066 100644 --- a/src/cuchaz/enigma/gui/TokenListCellRenderer.java +++ b/src/cuchaz/enigma/gui/TokenListCellRenderer.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java index 96d7e71e..7ed3d328 100644 --- a/src/cuchaz/enigma/mapping/ArgumentEntry.java +++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/ArgumentMapping.java b/src/cuchaz/enigma/mapping/ArgumentMapping.java index 12f28828..168306a2 100644 --- a/src/cuchaz/enigma/mapping/ArgumentMapping.java +++ b/src/cuchaz/enigma/mapping/ArgumentMapping.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/BehaviorEntry.java b/src/cuchaz/enigma/mapping/BehaviorEntry.java index 0eac62bf..8fc4eaf0 100644 --- a/src/cuchaz/enigma/mapping/BehaviorEntry.java +++ b/src/cuchaz/enigma/mapping/BehaviorEntry.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java index 95352f04..d3cfb938 100644 --- a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java +++ b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index cad2c527..2c708f2a 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index 14f46a4b..e084d4df 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java index befb0f6e..d99d1c35 100644 --- a/src/cuchaz/enigma/mapping/ConstructorEntry.java +++ b/src/cuchaz/enigma/mapping/ConstructorEntry.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/Entry.java b/src/cuchaz/enigma/mapping/Entry.java index a948e1dc..8524834c 100644 --- a/src/cuchaz/enigma/mapping/Entry.java +++ b/src/cuchaz/enigma/mapping/Entry.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/EntryPair.java b/src/cuchaz/enigma/mapping/EntryPair.java index 3b2e9ed8..f94d77ea 100644 --- a/src/cuchaz/enigma/mapping/EntryPair.java +++ b/src/cuchaz/enigma/mapping/EntryPair.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java index 76a54329..626af576 100644 --- a/src/cuchaz/enigma/mapping/FieldEntry.java +++ b/src/cuchaz/enigma/mapping/FieldEntry.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/FieldMapping.java b/src/cuchaz/enigma/mapping/FieldMapping.java index 83c56efa..ae0855a8 100644 --- a/src/cuchaz/enigma/mapping/FieldMapping.java +++ b/src/cuchaz/enigma/mapping/FieldMapping.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/IllegalNameException.java b/src/cuchaz/enigma/mapping/IllegalNameException.java index 4cab5945..830f05c4 100644 --- a/src/cuchaz/enigma/mapping/IllegalNameException.java +++ b/src/cuchaz/enigma/mapping/IllegalNameException.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/MappingParseException.java b/src/cuchaz/enigma/mapping/MappingParseException.java index c0d21d20..4fcc1f18 100644 --- a/src/cuchaz/enigma/mapping/MappingParseException.java +++ b/src/cuchaz/enigma/mapping/MappingParseException.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index dfe06ddf..3a39d100 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java index 058a666d..4bd9f121 100644 --- a/src/cuchaz/enigma/mapping/MappingsReader.java +++ b/src/cuchaz/enigma/mapping/MappingsReader.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index 98ed51df..3e5f1a4d 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/MappingsWriter.java b/src/cuchaz/enigma/mapping/MappingsWriter.java index 306d9a63..3c86dfc0 100644 --- a/src/cuchaz/enigma/mapping/MappingsWriter.java +++ b/src/cuchaz/enigma/mapping/MappingsWriter.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index 4aafa0f8..dbc18855 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java index eb45331f..c51b0110 100644 --- a/src/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/cuchaz/enigma/mapping/MethodMapping.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java index d337d94d..c6ae5969 100644 --- a/src/cuchaz/enigma/mapping/NameValidator.java +++ b/src/cuchaz/enigma/mapping/NameValidator.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/SignatureUpdater.java b/src/cuchaz/enigma/mapping/SignatureUpdater.java index 1b56a09f..809473e5 100644 --- a/src/cuchaz/enigma/mapping/SignatureUpdater.java +++ b/src/cuchaz/enigma/mapping/SignatureUpdater.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/TranslationDirection.java b/src/cuchaz/enigma/mapping/TranslationDirection.java index 87b79dfe..79ae0d32 100644 --- a/src/cuchaz/enigma/mapping/TranslationDirection.java +++ b/src/cuchaz/enigma/mapping/TranslationDirection.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index d239b5e8..6cb52402 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -1,9 +1,9 @@ /******************************************************************************* * Copyright (c) 2014 Jeff Martin. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html + * 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 -- cgit v1.2.3 From 959cb5fd4f9586ec3bd265b452fe25fe1db82e3f Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 13 Jan 2015 23:25:04 -0500 Subject: source format change don't hate me too much if you were planning a big merge. =P --- src/cuchaz/enigma/CommandMain.java | 7 + src/cuchaz/enigma/Constants.java | 8 +- src/cuchaz/enigma/Deobfuscator.java | 595 ++++----- src/cuchaz/enigma/Main.java | 41 +- src/cuchaz/enigma/TranslatingTypeLoader.java | 176 ++- src/cuchaz/enigma/Util.java | 107 +- src/cuchaz/enigma/analysis/Access.java | 30 +- .../enigma/analysis/BehaviorReferenceTreeNode.java | 56 +- src/cuchaz/enigma/analysis/BridgeFixer.java | 51 +- .../analysis/ClassImplementationsTreeNode.java | 48 +- .../enigma/analysis/ClassInheritanceTreeNode.java | 58 +- src/cuchaz/enigma/analysis/EntryReference.java | 94 +- src/cuchaz/enigma/analysis/EntryRenamer.java | 173 ++- .../enigma/analysis/FieldReferenceTreeNode.java | 65 +- src/cuchaz/enigma/analysis/JarClassIterator.java | 107 +- src/cuchaz/enigma/analysis/JarIndex.java | 820 ++++++------- .../analysis/MethodImplementationsTreeNode.java | 66 +- .../enigma/analysis/MethodInheritanceTreeNode.java | 80 +- src/cuchaz/enigma/analysis/ReferenceTreeNode.java | 3 +- src/cuchaz/enigma/analysis/SourceIndex.java | 144 +-- .../analysis/SourceIndexBehaviorVisitor.java | 159 +-- .../enigma/analysis/SourceIndexClassVisitor.java | 97 +- src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 370 +++--- src/cuchaz/enigma/analysis/Token.java | 41 +- src/cuchaz/enigma/analysis/TranslationIndex.java | 93 +- src/cuchaz/enigma/analysis/TreeDumpVisitor.java | 424 +++---- .../enigma/bytecode/BytecodeIndexIterator.java | 121 +- src/cuchaz/enigma/bytecode/BytecodeTools.java | 269 ++--- src/cuchaz/enigma/bytecode/CheckCastIterator.java | 98 +- src/cuchaz/enigma/bytecode/ClassRenamer.java | 103 +- src/cuchaz/enigma/bytecode/ClassTranslator.java | 104 +- src/cuchaz/enigma/bytecode/ConstPoolEditor.java | 295 ++--- src/cuchaz/enigma/bytecode/InfoType.java | 347 +++--- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 103 +- .../enigma/bytecode/MethodParameterWriter.java | 47 +- .../enigma/bytecode/MethodParametersAttribute.java | 65 +- .../bytecode/accessors/ClassInfoAccessor.java | 58 +- .../bytecode/accessors/ConstInfoAccessor.java | 181 ++- .../accessors/InvokeDynamicInfoAccessor.java | 90 +- .../bytecode/accessors/MemberRefInfoAccessor.java | 90 +- .../accessors/MethodHandleInfoAccessor.java | 90 +- .../bytecode/accessors/MethodTypeInfoAccessor.java | 58 +- .../accessors/NameAndTypeInfoAccessor.java | 90 +- .../bytecode/accessors/StringInfoAccessor.java | 58 +- .../bytecode/accessors/Utf8InfoAccessor.java | 23 +- src/cuchaz/enigma/convert/ClassIdentity.java | 436 +++---- src/cuchaz/enigma/convert/ClassMatcher.java | 412 +++---- src/cuchaz/enigma/convert/ClassMatching.java | 152 +-- src/cuchaz/enigma/convert/ClassNamer.java | 53 +- src/cuchaz/enigma/gui/AboutDialog.java | 80 +- src/cuchaz/enigma/gui/BoxHighlightPainter.java | 37 +- src/cuchaz/enigma/gui/BrowserCaret.java | 21 +- src/cuchaz/enigma/gui/ClassListCellRenderer.java | 14 +- src/cuchaz/enigma/gui/ClassSelector.java | 131 +- src/cuchaz/enigma/gui/ClassSelectorClassNode.java | 13 +- .../enigma/gui/ClassSelectorPackageNode.java | 13 +- src/cuchaz/enigma/gui/CrashDialog.java | 77 +- .../enigma/gui/DeobfuscatedHighlightPainter.java | 9 +- src/cuchaz/enigma/gui/Gui.java | 1265 ++++++++------------ src/cuchaz/enigma/gui/GuiController.java | 349 +++--- src/cuchaz/enigma/gui/GuiTricks.java | 23 +- .../enigma/gui/ObfuscatedHighlightPainter.java | 9 +- src/cuchaz/enigma/gui/OtherHighlightPainter.java | 9 +- src/cuchaz/enigma/gui/ProgressDialog.java | 90 +- src/cuchaz/enigma/gui/ReadableToken.java | 22 +- src/cuchaz/enigma/gui/RenameListener.java | 5 +- .../enigma/gui/SelectionHighlightPainter.java | 15 +- src/cuchaz/enigma/gui/TokenListCellRenderer.java | 14 +- src/cuchaz/enigma/mapping/ArgumentEntry.java | 85 +- src/cuchaz/enigma/mapping/ArgumentMapping.java | 26 +- src/cuchaz/enigma/mapping/BehaviorEntry.java | 3 +- .../enigma/mapping/BehaviorEntryFactory.java | 71 +- src/cuchaz/enigma/mapping/ClassEntry.java | 116 +- src/cuchaz/enigma/mapping/ClassMapping.java | 520 ++++---- src/cuchaz/enigma/mapping/ConstructorEntry.java | 99 +- src/cuchaz/enigma/mapping/Entry.java | 11 +- src/cuchaz/enigma/mapping/EntryPair.java | 9 +- src/cuchaz/enigma/mapping/FieldEntry.java | 65 +- src/cuchaz/enigma/mapping/FieldMapping.java | 30 +- .../enigma/mapping/IllegalNameException.java | 29 +- .../enigma/mapping/MappingParseException.java | 10 +- src/cuchaz/enigma/mapping/Mappings.java | 230 ++-- src/cuchaz/enigma/mapping/MappingsReader.java | 218 ++-- src/cuchaz/enigma/mapping/MappingsRenamer.java | 308 ++--- src/cuchaz/enigma/mapping/MappingsWriter.java | 110 +- src/cuchaz/enigma/mapping/MethodEntry.java | 79 +- src/cuchaz/enigma/mapping/MethodMapping.java | 168 ++- src/cuchaz/enigma/mapping/NameValidator.java | 79 +- src/cuchaz/enigma/mapping/SignatureUpdater.java | 88 +- .../enigma/mapping/TranslationDirection.java | 21 +- src/cuchaz/enigma/mapping/Translator.java | 280 ++--- 91 files changed, 4868 insertions(+), 7239 deletions(-) create mode 100644 src/cuchaz/enigma/CommandMain.java (limited to 'src') diff --git a/src/cuchaz/enigma/CommandMain.java b/src/cuchaz/enigma/CommandMain.java new file mode 100644 index 00000000..7f881749 --- /dev/null +++ b/src/cuchaz/enigma/CommandMain.java @@ -0,0 +1,7 @@ +package cuchaz.enigma; + +public class CommandMain { + + public static void main(String[] args) { + } +} diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java index 29a08b73..a1ba2e98 100644 --- a/src/cuchaz/enigma/Constants.java +++ b/src/cuchaz/enigma/Constants.java @@ -10,13 +10,11 @@ ******************************************************************************/ package cuchaz.enigma; - -public class Constants -{ +public class Constants { public static final String Name = "Enigma"; public static final String Version = "0.6 beta"; 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 + public static final int MiB = 1024 * 1024; // 1 mebibyte + public static final int KiB = 1024; // 1 kebibyte public static final String NonePackage = "none"; } diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 82c786cb..679518a4 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -61,12 +61,11 @@ import cuchaz.enigma.mapping.MethodMapping; import cuchaz.enigma.mapping.TranslationDirection; import cuchaz.enigma.mapping.Translator; -public class Deobfuscator -{ - public interface ProgressListener - { - void init( int totalWork, String title ); - void onProgress( int numDone, String message ); +public class Deobfuscator { + + public interface ProgressListener { + void init(int totalWork, String title); + void onProgress(int numDone, String message); } private File m_file; @@ -77,121 +76,104 @@ public class Deobfuscator private MappingsRenamer m_renamer; private Map m_translatorCache; - public Deobfuscator( File file ) - throws IOException - { + public Deobfuscator(File file) throws IOException { m_file = file; - m_jar = new JarFile( m_file ); + m_jar = new JarFile(m_file); // build the jar index m_jarIndex = new JarIndex(); - m_jarIndex.indexJar( m_jar, true ); + m_jarIndex.indexJar(m_jar, true); // config the decompiler m_settings = DecompilerSettings.javaDefaults(); - m_settings.setMergeVariables( true ); - m_settings.setForceExplicitImports( true ); - m_settings.setForceExplicitTypeArguments( true ); + m_settings.setMergeVariables(true); + m_settings.setForceExplicitImports(true); + m_settings.setForceExplicitTypeArguments(true); // DEBUG - //m_settings.setShowSyntheticMembers( true ); + // m_settings.setShowSyntheticMembers( true ); // init defaults m_translatorCache = Maps.newTreeMap(); // init mappings - setMappings( new Mappings() ); + setMappings(new Mappings()); } - public String getJarName( ) - { + public String getJarName() { return m_file.getName(); } - public JarIndex getJarIndex( ) - { + public JarIndex getJarIndex() { return m_jarIndex; } - public Mappings getMappings( ) - { + public Mappings getMappings() { return m_mappings; } - public void setMappings( Mappings val ) - { - if( val == null ) - { + + public void setMappings(Mappings val) { + if (val == null) { val = new Mappings(); } // pass 1: look for any classes that got moved to inner classes Map renames = Maps.newHashMap(); - for( ClassMapping classMapping : val.classes() ) - { + for (ClassMapping classMapping : val.classes()) { // make sure we strip the packages off of obfuscated inner classes - String innerClassName = new ClassEntry( classMapping.getObfName() ).getSimpleName(); - String outerClassName = m_jarIndex.getOuterClass( innerClassName ); - if( outerClassName != null ) - { + String innerClassName = new ClassEntry(classMapping.getObfName()).getSimpleName(); + String outerClassName = m_jarIndex.getOuterClass(innerClassName); + if (outerClassName != null) { // build the composite class name String newName = outerClassName + "$" + innerClassName; // add a rename - renames.put( classMapping.getObfName(), newName ); + renames.put(classMapping.getObfName(), newName); - System.out.println( String.format( "Converted class mapping %s to %s", classMapping.getObfName(), newName ) ); + System.out.println(String.format("Converted class mapping %s to %s", classMapping.getObfName(), newName)); } } - for( Map.Entry entry : renames.entrySet() ) - { - val.renameObfClass( entry.getKey(), entry.getValue() ); + for (Map.Entry entry : renames.entrySet()) { + val.renameObfClass(entry.getKey(), entry.getValue()); } // pass 2: look for fields/methods that are actually declared in superclasses - MappingsRenamer renamer = new MappingsRenamer( m_jarIndex, val ); - for( ClassMapping classMapping : val.classes() ) - { - ClassEntry obfClassEntry = new ClassEntry( classMapping.getObfName() ); + MappingsRenamer renamer = new MappingsRenamer(m_jarIndex, val); + for (ClassMapping classMapping : val.classes()) { + ClassEntry obfClassEntry = new ClassEntry(classMapping.getObfName()); // fields - for( FieldMapping fieldMapping : Lists.newArrayList( classMapping.fields() ) ) - { - FieldEntry fieldEntry = new FieldEntry( obfClassEntry, fieldMapping.getObfName() ); - ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( fieldEntry ); - if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( fieldEntry.getClassEntry() ) ) - { - boolean wasMoved = renamer.moveFieldToObfClass( classMapping, fieldMapping, resolvedObfClassEntry ); - if( wasMoved ) - { - System.out.println( String.format( "Moved field %s to class %s", fieldEntry, resolvedObfClassEntry ) ); - } - else - { - System.err.println( String.format( "WARNING: Would move field %s to class %s but the field was already there. Dropping instead.", fieldEntry, resolvedObfClassEntry ) ); + for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) { + FieldEntry fieldEntry = new FieldEntry(obfClassEntry, fieldMapping.getObfName()); + ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(fieldEntry); + if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(fieldEntry.getClassEntry())) { + boolean wasMoved = renamer.moveFieldToObfClass(classMapping, fieldMapping, resolvedObfClassEntry); + if (wasMoved) { + System.out.println(String.format("Moved field %s to class %s", fieldEntry, resolvedObfClassEntry)); + } else { + System.err.println(String.format("WARNING: Would move field %s to class %s but the field was already there. Dropping instead.", fieldEntry, resolvedObfClassEntry)); } } } // methods - for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) - { + for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { // skip constructors - if( methodMapping.isConstructor() ) - { + if (methodMapping.isConstructor()) { continue; } - MethodEntry methodEntry = new MethodEntry( obfClassEntry, methodMapping.getObfName(), methodMapping.getObfSignature() ); - ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( methodEntry ); - if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( methodEntry.getClassEntry() ) ) - { - boolean wasMoved = renamer.moveMethodToObfClass( classMapping, methodMapping, resolvedObfClassEntry ); - if( wasMoved ) - { - System.out.println( String.format( "Moved method %s to class %s", methodEntry, resolvedObfClassEntry ) ); - } - else - { - System.err.println( String.format( "WARNING: Would move method %s to class %s but the method was already there. Dropping instead.", methodEntry, resolvedObfClassEntry ) ); + MethodEntry methodEntry = new MethodEntry( + obfClassEntry, + methodMapping.getObfName(), + methodMapping.getObfSignature() + ); + ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(methodEntry); + if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(methodEntry.getClassEntry())) { + boolean wasMoved = renamer.moveMethodToObfClass(classMapping, methodMapping, resolvedObfClassEntry); + if (wasMoved) { + System.out.println(String.format("Moved method %s to class %s", methodEntry, resolvedObfClassEntry)); + } else { + System.err.println(String.format("WARNING: Would move method %s to class %s but the method was already there. Dropping instead.", methodEntry, resolvedObfClassEntry)); } } } @@ -201,13 +183,11 @@ public class Deobfuscator // drop mappings that don't match the jar List unknownClasses = Lists.newArrayList(); - for( ClassMapping classMapping : val.classes() ) - { - checkClassMapping( unknownClasses, classMapping ); + for (ClassMapping classMapping : val.classes()) { + checkClassMapping(unknownClasses, classMapping); } - if( !unknownClasses.isEmpty() ) - { - throw new Error( "Unable to find classes in jar: " + unknownClasses ); + if (!unknownClasses.isEmpty()) { + throw new Error("Unable to find classes in jar: " + unknownClasses); } m_mappings = val; @@ -215,453 +195,346 @@ public class Deobfuscator m_translatorCache.clear(); } - private void checkClassMapping( List unknownClasses, ClassMapping classMapping ) - { + private void checkClassMapping(List unknownClasses, ClassMapping classMapping) { // check the class - ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); - String outerClassName = m_jarIndex.getOuterClass( classEntry.getSimpleName() ); - if( outerClassName != null ) - { - classEntry = new ClassEntry( outerClassName + "$" + classMapping.getObfName() ); + ClassEntry classEntry = new ClassEntry(classMapping.getObfName()); + String outerClassName = m_jarIndex.getOuterClass(classEntry.getSimpleName()); + if (outerClassName != null) { + classEntry = new ClassEntry(outerClassName + "$" + classMapping.getObfName()); } - if( !m_jarIndex.getObfClassEntries().contains( classEntry ) ) - { - unknownClasses.add( classEntry ); + if (!m_jarIndex.getObfClassEntries().contains(classEntry)) { + unknownClasses.add(classEntry); } // check the fields - for( FieldMapping fieldMapping : Lists.newArrayList( classMapping.fields() ) ) - { - FieldEntry fieldEntry = new FieldEntry( classEntry, fieldMapping.getObfName() ); - if( !m_jarIndex.containsObfField( fieldEntry ) ) - { - System.err.println( "WARNING: unable to find field " + fieldEntry + ". dropping mapping." ); - classMapping.removeFieldMapping( fieldMapping ); + for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) { + FieldEntry fieldEntry = new FieldEntry(classEntry, fieldMapping.getObfName()); + if (!m_jarIndex.containsObfField(fieldEntry)) { + System.err.println("WARNING: unable to find field " + fieldEntry + ". dropping mapping."); + classMapping.removeFieldMapping(fieldMapping); } } // check methods - for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) - { - BehaviorEntry obfBehaviorEntry = BehaviorEntryFactory.createObf( classEntry, methodMapping ); - if( !m_jarIndex.containsObfBehavior( obfBehaviorEntry ) ) - { - System.err.println( "WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping." ); - classMapping.removeMethodMapping( methodMapping ); - } + for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { + BehaviorEntry obfBehaviorEntry = BehaviorEntryFactory.createObf(classEntry, methodMapping); + if (!m_jarIndex.containsObfBehavior(obfBehaviorEntry)) { + System.err.println("WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping."); + classMapping.removeMethodMapping(methodMapping); + } } // check inner classes - for( ClassMapping innerClassMapping : classMapping.innerClasses() ) - { - checkClassMapping( unknownClasses, innerClassMapping ); + for (ClassMapping innerClassMapping : classMapping.innerClasses()) { + checkClassMapping(unknownClasses, innerClassMapping); } } - - public Translator getTranslator( TranslationDirection direction ) - { - Translator translator = m_translatorCache.get( direction ); - if( translator == null ) - { - translator = m_mappings.getTranslator( direction ); - m_translatorCache.put( direction, translator ); + + public Translator getTranslator(TranslationDirection direction) { + Translator translator = m_translatorCache.get(direction); + if (translator == null) { + translator = m_mappings.getTranslator(direction); + m_translatorCache.put(direction, translator); } return translator; } - public void getSeparatedClasses( List obfClasses, List deobfClasses ) - { - for( ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries() ) - { + public void getSeparatedClasses(List obfClasses, List deobfClasses) { + for (ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries()) { // skip inner classes - if( obfClassEntry.isInnerClass() ) - { + if (obfClassEntry.isInnerClass()) { continue; } // separate the classes - ClassEntry deobfClassEntry = deobfuscateEntry( obfClassEntry ); - if( !deobfClassEntry.equals( obfClassEntry ) ) - { + ClassEntry deobfClassEntry = deobfuscateEntry(obfClassEntry); + if (!deobfClassEntry.equals(obfClassEntry)) { // if the class has a mapping, clearly it's deobfuscated - deobfClasses.add( deobfClassEntry ); - } - else if( !obfClassEntry.getPackageName().equals( Constants.NonePackage ) ) - { + deobfClasses.add(deobfClassEntry); + } else if (!obfClassEntry.getPackageName().equals(Constants.NonePackage)) { // also call it deobufscated if it's not in the none package - deobfClasses.add( obfClassEntry ); - } - else - { + deobfClasses.add(obfClassEntry); + } else { // otherwise, assume it's still obfuscated - obfClasses.add( obfClassEntry ); + obfClasses.add(obfClassEntry); } } } - public CompilationUnit getSourceTree( String obfClassName ) - { + public CompilationUnit getSourceTree(String obfClassName) { // 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 lookupClassName = obfClassName; - ClassMapping classMapping = m_mappings.getClassByObf( obfClassName ); - if( classMapping != null && classMapping.getDeobfName() != null ) - { + ClassMapping classMapping = m_mappings.getClassByObf(obfClassName); + if (classMapping != null && classMapping.getDeobfName() != null) { lookupClassName = classMapping.getDeobfName(); } // is this class even in the jar? - if( !m_jarIndex.containsObfClass( new ClassEntry( obfClassName ) ) ) - { + if (!m_jarIndex.containsObfClass(new ClassEntry(obfClassName))) { return null; } // set the type loader - m_settings.setTypeLoader( new TranslatingTypeLoader( + m_settings.setTypeLoader(new TranslatingTypeLoader( m_jar, m_jarIndex, - getTranslator( TranslationDirection.Obfuscating ), - getTranslator( TranslationDirection.Deobfuscating ) - ) ); + getTranslator(TranslationDirection.Obfuscating), + getTranslator(TranslationDirection.Deobfuscating) + )); // decompile it! - TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( lookupClassName ).resolve(); + TypeDefinition resolvedType = new MetadataSystem(m_settings.getTypeLoader()).lookupType(lookupClassName).resolve(); DecompilerContext context = new DecompilerContext(); - context.setCurrentType( resolvedType ); - context.setSettings( m_settings ); - AstBuilder builder = new AstBuilder( context ); - builder.addType( resolvedType ); - builder.runTransformations( null ); + context.setCurrentType(resolvedType); + context.setSettings(m_settings); + AstBuilder builder = new AstBuilder(context); + builder.addType(resolvedType); + builder.runTransformations(null); return builder.getCompilationUnit(); } - public SourceIndex getSourceIndex( CompilationUnit sourceTree, String source ) - { + public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source) { // build the source index - SourceIndex index = new SourceIndex( source ); - sourceTree.acceptVisitor( new SourceIndexVisitor(), index ); + SourceIndex index = new SourceIndex(source); + sourceTree.acceptVisitor(new SourceIndexVisitor(), index); // DEBUG - //sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); + // sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); // resolve all the classes in the source references - for( Token token : index.referenceTokens() ) - { - EntryReference deobfReference = index.getDeobfReference( token ); + for (Token token : index.referenceTokens()) { + EntryReference deobfReference = index.getDeobfReference(token); // get the obfuscated entry - Entry obfEntry = obfuscateEntry( deobfReference.entry ); + Entry obfEntry = obfuscateEntry(deobfReference.entry); // try to resolve the class - ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( obfEntry ); - if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( obfEntry.getClassEntry() ) ) - { + ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(obfEntry); + if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getClassEntry())) { // change the class of the entry - obfEntry = obfEntry.cloneToNewClass( resolvedObfClassEntry ); + obfEntry = obfEntry.cloneToNewClass(resolvedObfClassEntry); // save the new deobfuscated reference - deobfReference.entry = deobfuscateEntry( obfEntry ); - index.replaceDeobfReference( token, deobfReference ); + deobfReference.entry = deobfuscateEntry(obfEntry); + index.replaceDeobfReference(token, deobfReference); } // DEBUG - //System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); + // System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); } return index; } - public String getSource( CompilationUnit sourceTree ) - { + public String getSource(CompilationUnit sourceTree) { // render the AST into source StringWriter buf = new StringWriter(); - sourceTree.acceptVisitor( new InsertParenthesesVisitor(), null ); - sourceTree.acceptVisitor( new JavaOutputVisitor( new PlainTextOutput( buf ), m_settings ), null ); + sourceTree.acceptVisitor(new InsertParenthesesVisitor(), null); + sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(buf), m_settings), null); return buf.toString(); } - public void writeSources( File dirOut, ProgressListener progress ) - throws IOException - { + public void writeSources(File dirOut, ProgressListener progress) throws IOException { // get the classes to decompile Set classEntries = Sets.newHashSet(); - for( ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries() ) - { + for (ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries()) { // skip inner classes - if( obfClassEntry.isInnerClass() ) - { + if (obfClassEntry.isInnerClass()) { continue; } - classEntries.add( obfClassEntry ); + classEntries.add(obfClassEntry); } - if( progress != null ) - { - progress.init( classEntries.size(), "Decompiling classes..." ); + if (progress != null) { + progress.init(classEntries.size(), "Decompiling classes..."); } // DEOBFUSCATE ALL THE THINGS!! @_@ int i = 0; - for( ClassEntry obfClassEntry : classEntries ) - { - ClassEntry deobfClassEntry = deobfuscateEntry( new ClassEntry( obfClassEntry ) ); - if( progress != null ) - { - progress.onProgress( i++, deobfClassEntry.toString() ); + for (ClassEntry obfClassEntry : classEntries) { + ClassEntry deobfClassEntry = deobfuscateEntry(new ClassEntry(obfClassEntry)); + if (progress != null) { + progress.onProgress(i++, deobfClassEntry.toString()); } - try - { + try { // get the source - String source = getSource( getSourceTree( obfClassEntry.getName() ) ); + String source = getSource(getSourceTree(obfClassEntry.getName())); // write the file - File file = new File( dirOut, deobfClassEntry.getName().replace( '.', '/' ) + ".java" ); + File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java"); file.getParentFile().mkdirs(); - try( FileWriter out = new FileWriter( file ) ) - { - out.write( source ); + try (FileWriter out = new FileWriter(file)) { + out.write(source); } - } - catch( Throwable t ) - { - throw new Error( "Unable to deobfuscate class " + deobfClassEntry.toString() + " (" + obfClassEntry.toString() + ")", t ); + } catch (Throwable t) { + throw new Error("Unable to deobfuscate class " + deobfClassEntry.toString() + " (" + obfClassEntry.toString() + ")", t); } } - if( progress != null ) - { - progress.onProgress( i, "Done!" ); + if (progress != null) { + progress.onProgress(i, "Done!"); } } - public void writeJar( File out, ProgressListener progress ) - { - try( JarOutputStream outJar = new JarOutputStream( new FileOutputStream( out ) ) ) - { - if( progress != null ) - { - progress.init( JarClassIterator.getClassEntries( m_jar ).size(), "Translating classes..." ); + public void writeJar(File out, ProgressListener progress) { + try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) { + if (progress != null) { + progress.init(JarClassIterator.getClassEntries(m_jar).size(), "Translating classes..."); } // prep the loader TranslatingTypeLoader loader = new TranslatingTypeLoader( m_jar, m_jarIndex, - getTranslator( TranslationDirection.Obfuscating ), - getTranslator( TranslationDirection.Deobfuscating ) + getTranslator(TranslationDirection.Obfuscating), + getTranslator(TranslationDirection.Deobfuscating) ); int i = 0; - for( CtClass c : JarClassIterator.classes( m_jar ) ) - { - if( progress != null ) - { - progress.onProgress( i++, c.getName() ); + for (CtClass c : JarClassIterator.classes(m_jar)) { + if (progress != null) { + progress.onProgress(i++, c.getName()); } - try - { - c = loader.transformClass( c ); - outJar.putNextEntry( new JarEntry( c.getName().replace( '.', '/' ) + ".class" ) ); - outJar.write( c.toBytecode() ); + try { + c = loader.transformClass(c); + outJar.putNextEntry(new JarEntry(c.getName().replace('.', '/') + ".class")); + outJar.write(c.toBytecode()); outJar.closeEntry(); - } - catch( Throwable t ) - { - throw new Error( "Unable to deobfuscate class " + c.getName(), t ); + } catch (Throwable t) { + throw new Error("Unable to deobfuscate class " + c.getName(), t); } } - if( progress != null ) - { - progress.onProgress( i, "Done!" ); + if (progress != null) { + progress.onProgress(i, "Done!"); } outJar.close(); - } - catch( IOException ex ) - { - throw new Error( "Unable to write to Jar file!" ); + } catch (IOException ex) { + throw new Error("Unable to write to Jar file!"); } } - public T obfuscateEntry( T deobfEntry ) - { - if( deobfEntry == null ) - { + public T obfuscateEntry(T deobfEntry) { + if (deobfEntry == null) { return null; } - return getTranslator( TranslationDirection.Obfuscating ).translateEntry( deobfEntry ); + return getTranslator(TranslationDirection.Obfuscating).translateEntry(deobfEntry); } - public T deobfuscateEntry( T obfEntry ) - { - if( obfEntry == null ) - { + public T deobfuscateEntry(T obfEntry) { + if (obfEntry == null) { return null; } - return getTranslator( TranslationDirection.Deobfuscating ).translateEntry( obfEntry ); + return getTranslator(TranslationDirection.Deobfuscating).translateEntry(obfEntry); } - public EntryReference obfuscateReference( EntryReference deobfReference ) - { - if( deobfReference == null ) - { + public EntryReference obfuscateReference(EntryReference deobfReference) { + if (deobfReference == null) { return null; } return new EntryReference( - obfuscateEntry( deobfReference.entry ), - obfuscateEntry( deobfReference.context ), + obfuscateEntry(deobfReference.entry), + obfuscateEntry(deobfReference.context), deobfReference ); } - public EntryReference deobfuscateReference( EntryReference obfReference ) - { - if( obfReference == null ) - { + public EntryReference deobfuscateReference(EntryReference obfReference) { + if (obfReference == null) { return null; } return new EntryReference( - deobfuscateEntry( obfReference.entry ), - deobfuscateEntry( obfReference.context ), + deobfuscateEntry(obfReference.entry), + deobfuscateEntry(obfReference.context), obfReference ); } - public boolean isObfuscatedIdentifier( Entry obfEntry ) - { - return m_jarIndex.containsObfEntry( obfEntry ); + public boolean isObfuscatedIdentifier(Entry obfEntry) { + return m_jarIndex.containsObfEntry(obfEntry); } - public boolean isRenameable( EntryReference obfReference ) - { - return obfReference.isNamed() && isObfuscatedIdentifier( obfReference.getNameableEntry() ); + public boolean isRenameable(EntryReference obfReference) { + return obfReference.isNamed() && isObfuscatedIdentifier(obfReference.getNameableEntry()); } - // NOTE: these methods are a bit messy... oh well - - public boolean hasDeobfuscatedName( Entry obfEntry ) - { - Translator translator = getTranslator( TranslationDirection.Deobfuscating ); - if( obfEntry instanceof ClassEntry ) - { - return translator.translate( (ClassEntry)obfEntry ) != null; - } - else if( obfEntry instanceof FieldEntry ) - { - return translator.translate( (FieldEntry)obfEntry ) != null; - } - else if( obfEntry instanceof MethodEntry ) - { - return translator.translate( (MethodEntry)obfEntry ) != null; - } - else if( obfEntry instanceof ConstructorEntry ) - { + + public boolean hasDeobfuscatedName(Entry obfEntry) { + Translator translator = getTranslator(TranslationDirection.Deobfuscating); + if (obfEntry instanceof ClassEntry) { + return translator.translate((ClassEntry)obfEntry) != null; + } else if (obfEntry instanceof FieldEntry) { + return translator.translate((FieldEntry)obfEntry) != null; + } else if (obfEntry instanceof MethodEntry) { + return translator.translate((MethodEntry)obfEntry) != null; + } else if (obfEntry instanceof ConstructorEntry) { // constructors have no names return false; - } - else if( obfEntry instanceof ArgumentEntry ) - { - return translator.translate( (ArgumentEntry)obfEntry ) != null; - } - else - { - throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); + } else if (obfEntry instanceof ArgumentEntry) { + return translator.translate((ArgumentEntry)obfEntry) != null; + } else { + throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); } } - - public void rename( Entry obfEntry, String newName ) - { - if( obfEntry instanceof ClassEntry ) - { - m_renamer.setClassName( (ClassEntry)obfEntry, Descriptor.toJvmName( newName ) ); - } - else if( obfEntry instanceof FieldEntry ) - { - m_renamer.setFieldName( (FieldEntry)obfEntry, newName ); - } - else if( obfEntry instanceof MethodEntry ) - { - m_renamer.setMethodTreeName( (MethodEntry)obfEntry, newName ); - } - else if( obfEntry instanceof ConstructorEntry ) - { - throw new IllegalArgumentException( "Cannot rename constructors" ); - } - else if( obfEntry instanceof ArgumentEntry ) - { - m_renamer.setArgumentName( (ArgumentEntry)obfEntry, newName ); - } - else - { - throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); + + public void rename(Entry obfEntry, String newName) { + if (obfEntry instanceof ClassEntry) { + m_renamer.setClassName((ClassEntry)obfEntry, Descriptor.toJvmName(newName)); + } else if (obfEntry instanceof FieldEntry) { + m_renamer.setFieldName((FieldEntry)obfEntry, newName); + } else if (obfEntry instanceof MethodEntry) { + m_renamer.setMethodTreeName((MethodEntry)obfEntry, newName); + } else if (obfEntry instanceof ConstructorEntry) { + throw new IllegalArgumentException("Cannot rename constructors"); + } else if (obfEntry instanceof ArgumentEntry) { + m_renamer.setArgumentName((ArgumentEntry)obfEntry, newName); + } else { + throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); } // clear caches m_translatorCache.clear(); } - public void removeMapping( Entry obfEntry ) - { - if( obfEntry instanceof ClassEntry ) - { - m_renamer.removeClassMapping( (ClassEntry)obfEntry ); - } - else if( obfEntry instanceof FieldEntry ) - { - m_renamer.removeFieldMapping( (FieldEntry)obfEntry ); - } - else if( obfEntry instanceof MethodEntry ) - { - m_renamer.removeMethodTreeMapping( (MethodEntry)obfEntry ); - } - else if( obfEntry instanceof ConstructorEntry ) - { - throw new IllegalArgumentException( "Cannot rename constructors" ); - } - else if( obfEntry instanceof ArgumentEntry ) - { - m_renamer.removeArgumentMapping( (ArgumentEntry)obfEntry ); - } - else - { - throw new Error( "Unknown entry type: " + obfEntry ); + public void removeMapping(Entry obfEntry) { + if (obfEntry instanceof ClassEntry) { + m_renamer.removeClassMapping((ClassEntry)obfEntry); + } else if (obfEntry instanceof FieldEntry) { + m_renamer.removeFieldMapping((FieldEntry)obfEntry); + } else if (obfEntry instanceof MethodEntry) { + m_renamer.removeMethodTreeMapping((MethodEntry)obfEntry); + } else if (obfEntry instanceof ConstructorEntry) { + throw new IllegalArgumentException("Cannot rename constructors"); + } else if (obfEntry instanceof ArgumentEntry) { + m_renamer.removeArgumentMapping((ArgumentEntry)obfEntry); + } else { + throw new Error("Unknown entry type: " + obfEntry); } // clear caches m_translatorCache.clear(); } - public void markAsDeobfuscated( Entry obfEntry ) - { - if( obfEntry instanceof ClassEntry ) - { - m_renamer.markClassAsDeobfuscated( (ClassEntry)obfEntry ); - } - else if( obfEntry instanceof FieldEntry ) - { - m_renamer.markFieldAsDeobfuscated( (FieldEntry)obfEntry ); - } - else if( obfEntry instanceof MethodEntry ) - { - m_renamer.markMethodTreeAsDeobfuscated( (MethodEntry)obfEntry ); - } - else if( obfEntry instanceof ConstructorEntry ) - { - throw new IllegalArgumentException( "Cannot rename constructors" ); + public void markAsDeobfuscated(Entry obfEntry) { + if (obfEntry instanceof ClassEntry) { + m_renamer.markClassAsDeobfuscated((ClassEntry)obfEntry); + } else if (obfEntry instanceof FieldEntry) { + m_renamer.markFieldAsDeobfuscated((FieldEntry)obfEntry); + } else if (obfEntry instanceof MethodEntry) { + m_renamer.markMethodTreeAsDeobfuscated((MethodEntry)obfEntry); + } else if (obfEntry instanceof ConstructorEntry) { + throw new IllegalArgumentException("Cannot rename constructors"); + } else if (obfEntry instanceof ArgumentEntry) { + m_renamer.markArgumentAsDeobfuscated((ArgumentEntry)obfEntry); + } else { + throw new Error("Unknown entry type: " + obfEntry); } - else if( obfEntry instanceof ArgumentEntry ) - { - m_renamer.markArgumentAsDeobfuscated( (ArgumentEntry)obfEntry ); - } - else - { - throw new Error( "Unknown entry type: " + obfEntry ); - } - + // clear caches m_translatorCache.clear(); } diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index 73a12db5..f8d3afe2 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -14,46 +14,37 @@ import java.io.File; import cuchaz.enigma.gui.Gui; -public class Main -{ - public static void main( String[] args ) - throws Exception - { +public class Main { + + public static void main(String[] args) throws Exception { Gui gui = new Gui(); // parse command-line args - if( args.length >= 1 ) - { - gui.getController().openJar( getFile( args[0] ) ); + if (args.length >= 1) { + gui.getController().openJar(getFile(args[0])); } - if( args.length >= 2 ) - { - gui.getController().openMappings( getFile( args[1] ) ); + if (args.length >= 2) { + gui.getController().openMappings(getFile(args[1])); } // DEBUG - //gui.getController().openDeclaration( new ClassEntry( "none/ces" ) ); + // gui.getController().openDeclaration( new ClassEntry( "none/ces" ) ); } - private static File getFile( String path ) - { + private static File getFile(String path) { // expand ~ to the home dir - if( path.startsWith( "~" ) ) - { + if (path.startsWith("~")) { // get the home dir - File dirHome = new File( System.getProperty( "user.home" ) ); + 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 ) ); + if (path.startsWith("~/")) { + return new File(dirHome, path.substring(2)); + } else { + return new File(dirHome.getParentFile(), path.substring(1)); } } - return new File( path ); + return new File(path); } } diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index e69e5cfe..091f916d 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -38,8 +38,8 @@ import cuchaz.enigma.bytecode.MethodParameterWriter; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.Translator; -public class TranslatingTypeLoader implements ITypeLoader -{ +public class TranslatingTypeLoader implements ITypeLoader { + private JarFile m_jar; private JarIndex m_jarIndex; private Translator m_obfuscatingTranslator; @@ -47,13 +47,11 @@ public class TranslatingTypeLoader implements ITypeLoader private Map m_cache; private ClasspathTypeLoader m_defaultTypeLoader; - public TranslatingTypeLoader( JarFile jar, JarIndex jarIndex ) - { - this( jar, jarIndex, new Translator(), new Translator() ); + public TranslatingTypeLoader(JarFile jar, JarIndex jarIndex) { + this(jar, jarIndex, new Translator(), new Translator()); } - public TranslatingTypeLoader( JarFile jar, JarIndex jarIndex, Translator obfuscatingTranslator, Translator deobfuscatingTranslator ) - { + public TranslatingTypeLoader(JarFile jar, JarIndex jarIndex, Translator obfuscatingTranslator, Translator deobfuscatingTranslator) { m_jar = jar; m_jarIndex = jarIndex; m_obfuscatingTranslator = obfuscatingTranslator; @@ -62,184 +60,154 @@ public class TranslatingTypeLoader implements ITypeLoader m_defaultTypeLoader = new ClasspathTypeLoader(); } - public void clearCache( ) - { + public void clearCache() { m_cache.clear(); } @Override - public boolean tryLoadType( String deobfClassName, Buffer out ) - { + public boolean tryLoadType(String deobfClassName, Buffer out) { // check the cache byte[] data; - if( m_cache.containsKey( deobfClassName ) ) - { - data = m_cache.get( deobfClassName ); - } - else - { - data = loadType( deobfClassName ); - m_cache.put( deobfClassName, data ); + if (m_cache.containsKey(deobfClassName)) { + data = m_cache.get(deobfClassName); + } else { + data = loadType(deobfClassName); + m_cache.put(deobfClassName, data); } - if( data == null ) - { + if (data == null) { // chain to default type loader - return m_defaultTypeLoader.tryLoadType( deobfClassName, out ); + return m_defaultTypeLoader.tryLoadType(deobfClassName, out); } // send the class to the decompiler - out.reset( data.length ); - System.arraycopy( data, 0, out.array(), out.position(), data.length ); - out.position( 0 ); + out.reset(data.length); + System.arraycopy(data, 0, out.array(), out.position(), data.length); + out.position(0); return true; } - public CtClass loadClass( String deobfClassName ) - { - byte[] data = loadType( deobfClassName ); - if( data == null ) - { + public CtClass loadClass(String deobfClassName) { + byte[] data = loadType(deobfClassName); + if (data == null) { return null; } // return a javassist handle for the class - String javaClassFileName = Descriptor.toJavaName( deobfClassName ); + String javaClassFileName = Descriptor.toJavaName(deobfClassName); ClassPool classPool = new ClassPool(); - classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, data ) ); - try - { - return classPool.get( javaClassFileName ); - } - catch( NotFoundException ex ) - { - throw new Error( ex ); + classPool.insertClassPath(new ByteArrayClassPath(javaClassFileName, data)); + try { + return classPool.get(javaClassFileName); + } catch (NotFoundException ex) { + throw new Error(ex); } } - private byte[] loadType( String deobfClassName ) - { - ClassEntry deobfClassEntry = new ClassEntry( deobfClassName ); - ClassEntry obfClassEntry = m_obfuscatingTranslator.translateEntry( deobfClassEntry ); + private byte[] loadType(String deobfClassName) { + ClassEntry deobfClassEntry = new ClassEntry(deobfClassName); + ClassEntry obfClassEntry = m_obfuscatingTranslator.translateEntry(deobfClassEntry); // is this an inner class referenced directly? - String obfOuterClassName = m_jarIndex.getOuterClass( obfClassEntry.getSimpleName() ); - if( obfOuterClassName != null ) - { + String obfOuterClassName = m_jarIndex.getOuterClass(obfClassEntry.getSimpleName()); + if (obfOuterClassName != null) { // this class doesn't really exist. Reference it by outer$inner instead - System.err.println( String.format( "WARNING: class %s referenced by bare inner name instead of via outer class %s", deobfClassName, obfOuterClassName ) ); + System.err.println(String.format("WARNING: class %s referenced by bare inner name instead of via outer class %s", deobfClassName, obfOuterClassName)); return null; } /* DEBUG - if( !Arrays.asList( "java", "org", "io" ).contains( deobfClassName.split( "/" )[0] ) ) - { + if( !Arrays.asList( "java", "org", "io" ).contains( deobfClassName.split( "/" )[0] ) ) { System.out.println( String.format( "Looking for %s (%s)", deobfClassEntry.getName(), obfClassEntry.getName() ) ); } */ // get the jar entry String classFileName; - if( obfClassEntry.isInnerClass() ) - { + if (obfClassEntry.isInnerClass()) { // use just the inner class name for inner classes classFileName = obfClassEntry.getInnerClassName(); - } - else if( obfClassEntry.getPackageName().equals( Constants.NonePackage ) ) - { + } else if (obfClassEntry.getPackageName().equals(Constants.NonePackage)) { // use the outer class simple name for classes in the none package classFileName = obfClassEntry.getSimpleName(); - } - else - { + } else { // otherwise, just use the class name (ie for classes in packages) classFileName = obfClassEntry.getName(); } - JarEntry entry = m_jar.getJarEntry( classFileName + ".class" ); - if( entry == null ) - { + JarEntry entry = m_jar.getJarEntry(classFileName + ".class"); + if (entry == null) { return null; } - - try - { + + try { // read the class file into a buffer ByteArrayOutputStream data = new ByteArrayOutputStream(); - byte[] buf = new byte[1024*1024]; // 1 KiB - InputStream in = m_jar.getInputStream( entry ); - while( true ) - { - int bytesRead = in.read( buf ); - if( bytesRead <= 0 ) - { + byte[] buf = new byte[1024 * 1024]; // 1 KiB + InputStream in = m_jar.getInputStream(entry); + while (true) { + int bytesRead = in.read(buf); + if (bytesRead <= 0) { break; } - data.write( buf, 0, bytesRead ); + data.write(buf, 0, bytesRead); } data.close(); in.close(); buf = data.toByteArray(); // load the javassist handle to the raw class - String javaClassFileName = Descriptor.toJavaName( classFileName ); + String javaClassFileName = Descriptor.toJavaName(classFileName); ClassPool classPool = new ClassPool(); - classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, buf ) ); - CtClass c = classPool.get( javaClassFileName ); + classPool.insertClassPath(new ByteArrayClassPath(javaClassFileName, buf)); + CtClass c = classPool.get(javaClassFileName); - c = transformClass( c ); + c = transformClass(c); // sanity checking - assertClassName( c, deobfClassEntry ); + assertClassName(c, deobfClassEntry); // DEBUG - //Util.writeClass( c ); - + // Util.writeClass( c ); + // we have a transformed class! return c.toBytecode(); - } - catch( IOException | NotFoundException | CannotCompileException ex ) - { - throw new Error( ex ); + } catch (IOException | NotFoundException | CannotCompileException ex) { + throw new Error(ex); } } - public CtClass transformClass( CtClass c ) - throws IOException, NotFoundException, CannotCompileException - { + public CtClass transformClass(CtClass c) throws IOException, NotFoundException, CannotCompileException { // we moved a lot of classes out of the default package into the none package // make sure all the class references are consistent - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); + ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); // reconstruct inner classes - new InnerClassWriter( m_jarIndex ).write( c ); + new InnerClassWriter(m_jarIndex).write(c); // re-get the javassist handle since we changed class names - ClassEntry obfClassEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); - String javaClassReconstructedName = Descriptor.toJavaName( obfClassEntry.getName() ); + ClassEntry obfClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); + String javaClassReconstructedName = Descriptor.toJavaName(obfClassEntry.getName()); ClassPool classPool = new ClassPool(); - classPool.insertClassPath( new ByteArrayClassPath( javaClassReconstructedName, c.toBytecode() ) ); - c = classPool.get( javaClassReconstructedName ); + classPool.insertClassPath(new ByteArrayClassPath(javaClassReconstructedName, c.toBytecode())); + c = classPool.get(javaClassReconstructedName); // check that the file is correct after inner class reconstruction (ie cause Javassist to fail fast if something is wrong) - assertClassName( c, obfClassEntry ); + assertClassName(c, obfClassEntry); // do all kinds of deobfuscating transformations on the class - new BridgeFixer( m_jarIndex ).fixBridges( c ); - new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); - new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); + new BridgeFixer(m_jarIndex).fixBridges(c); + new MethodParameterWriter(m_deobfuscatingTranslator).writeMethodArguments(c); + new ClassTranslator(m_deobfuscatingTranslator).translate(c); return c; } - - private void assertClassName( CtClass c, ClassEntry obfClassEntry ) - { - String name1 = Descriptor.toJvmName( c.getName() ); - assert( name1.equals( obfClassEntry.getName() ) ) - : String.format( "Looking for %s, instead found %s", obfClassEntry.getName(), name1 ); + + private void assertClassName(CtClass c, ClassEntry obfClassEntry) { + String name1 = Descriptor.toJvmName(c.getName()); + assert (name1.equals(obfClassEntry.getName())) : String.format("Looking for %s, instead found %s", obfClassEntry.getName(), name1); - String name2 = Descriptor.toJvmName( c.getClassFile().getName() ); - assert( name2.equals( obfClassEntry.getName() ) ) - : String.format( "Looking for %s, instead found %s", obfClassEntry.getName(), name2 ); + String name2 = Descriptor.toJvmName(c.getClassFile().getName()); + assert (name2.equals(obfClassEntry.getName())) : String.format("Looking for %s, instead found %s", obfClassEntry.getName(), name2); } } diff --git a/src/cuchaz/enigma/Util.java b/src/cuchaz/enigma/Util.java index 678de546..7f04bda0 100644 --- a/src/cuchaz/enigma/Util.java +++ b/src/cuchaz/enigma/Util.java @@ -28,108 +28,77 @@ import javassist.bytecode.Descriptor; import com.google.common.io.CharStreams; - -public class Util -{ - public static int combineHashesOrdered( Object ... objs ) - { - return combineHashesOrdered( Arrays.asList( objs ) ); +public class Util { + + public static int combineHashesOrdered(Object... objs) { + return combineHashesOrdered(Arrays.asList(objs)); } - public static int combineHashesOrdered( Iterable objs ) - { + public static int combineHashesOrdered(Iterable objs) { final int prime = 67; int result = 1; - for( Object obj : objs ) - { + for (Object obj : objs) { result *= prime; - if( obj != null ) - { + if (obj != null) { result += obj.hashCode(); } } return result; } - public static void closeQuietly( Closeable closeable ) - { - if( closeable != null ) - { - try - { + public static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { closeable.close(); - } - catch( IOException ex ) - { + } catch (IOException ex) { // just ignore any further exceptions } } } - public static void closeQuietly( JarFile jarFile ) - { + public static void closeQuietly(JarFile jarFile) { // silly library should implement Closeable... - if( jarFile != null ) - { - try - { + if (jarFile != null) { + try { jarFile.close(); - } - catch( IOException ex ) - { + } catch (IOException ex) { // just ignore any further exceptions } } } - - public static String readStreamToString( InputStream in ) - throws IOException - { - return CharStreams.toString( new InputStreamReader( in, "UTF-8" ) ); + + 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 ); + 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 ); + return readStreamToString(in); } - public static void openUrl( String url ) - { - if( Desktop.isDesktopSupported() ) - { + 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 ); + try { + desktop.browse(new URI(url)); + } catch (IOException ex) { + throw new Error(ex); + } catch (URISyntaxException ex) { + throw new IllegalArgumentException(ex); } } } - public static void writeClass( CtClass c ) - { - String name = Descriptor.toJavaName( c.getName() ); - File file = new File( name + ".class" ); - try( FileOutputStream out = new FileOutputStream( file ) ) - { - out.write( c.toBytecode() ); - } - catch( IOException | CannotCompileException ex ) - { - throw new Error( ex ); + public static void writeClass(CtClass c) { + String name = Descriptor.toJavaName(c.getName()); + File file = new File(name + ".class"); + try (FileOutputStream out = new FileOutputStream(file)) { + out.write(c.toBytecode()); + } catch (IOException | CannotCompileException ex) { + throw new Error(ex); } } } diff --git a/src/cuchaz/enigma/analysis/Access.java b/src/cuchaz/enigma/analysis/Access.java index e35bb21b..8d3409ac 100644 --- a/src/cuchaz/enigma/analysis/Access.java +++ b/src/cuchaz/enigma/analysis/Access.java @@ -15,37 +15,29 @@ import java.lang.reflect.Modifier; import javassist.CtBehavior; import javassist.CtField; -public enum Access -{ +public enum Access { + Public, Protected, Private; - public static Access get( CtBehavior behavior ) - { - return get( behavior.getModifiers() ); + public static Access get(CtBehavior behavior) { + return get(behavior.getModifiers()); } - public static Access get( CtField field ) - { - return get( field.getModifiers() ); + public static Access get(CtField field) { + return get(field.getModifiers()); } - public static Access get( int modifiers ) - { - if( Modifier.isPublic( modifiers ) ) - { + public static Access get(int modifiers) { + if (Modifier.isPublic(modifiers)) { return Public; - } - else if( Modifier.isProtected( modifiers ) ) - { + } else if (Modifier.isProtected(modifiers)) { return Protected; - } - else if( Modifier.isPrivate( modifiers ) ) - { + } else if (Modifier.isPrivate(modifiers)) { return Private; } // assume public by default return Public; } -} \ No newline at end of file +} diff --git a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java index 20f1d472..9adac5e9 100644 --- a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java @@ -21,8 +21,8 @@ import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.Translator; -public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode -{ +public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode { + private static final long serialVersionUID = -3658163700783307520L; private Translator m_deobfuscatingTranslator; @@ -30,15 +30,13 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements private EntryReference m_reference; private Access m_access; - public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, BehaviorEntry entry ) - { + public BehaviorReferenceTreeNode(Translator deobfuscatingTranslator, BehaviorEntry entry) { m_deobfuscatingTranslator = deobfuscatingTranslator; m_entry = entry; m_reference = null; } - public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference, Access access ) - { + public BehaviorReferenceTreeNode(Translator deobfuscatingTranslator, EntryReference reference, Access access) { m_deobfuscatingTranslator = deobfuscatingTranslator; m_entry = reference.entry; m_reference = reference; @@ -46,60 +44,48 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements } @Override - public BehaviorEntry getEntry( ) - { + public BehaviorEntry getEntry() { return m_entry; } @Override - public EntryReference getReference( ) - { + public EntryReference getReference() { return m_reference; } @Override - public String toString( ) - { - if( m_reference != null ) - { - return String.format( "%s (%s)", m_deobfuscatingTranslator.translateEntry( m_reference.context ), m_access ); + public String toString() { + if (m_reference != null) { + return String.format("%s (%s)", m_deobfuscatingTranslator.translateEntry(m_reference.context), m_access); } - return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); + return m_deobfuscatingTranslator.translateEntry(m_entry).toString(); } - public void load( JarIndex index, boolean recurse ) - { + public void load(JarIndex index, boolean recurse) { // get all the child nodes - for( EntryReference reference : index.getBehaviorReferences( m_entry ) ) - { - add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference, index.getAccess( m_entry ) ) ); + for (EntryReference reference : index.getBehaviorReferences(m_entry)) { + add(new BehaviorReferenceTreeNode(m_deobfuscatingTranslator, reference, index.getAccess(m_entry))); } - if( recurse && children != null ) - { - for( Object child : children ) - { - if( child instanceof BehaviorReferenceTreeNode ) - { + if (recurse && children != null) { + for (Object child : children) { + if (child instanceof BehaviorReferenceTreeNode) { BehaviorReferenceTreeNode node = (BehaviorReferenceTreeNode)child; // don't recurse into ancestor Set ancestors = Sets.newHashSet(); TreeNode n = (TreeNode)node; - while( n.getParent() != null ) - { + while (n.getParent() != null) { n = n.getParent(); - if( n instanceof BehaviorReferenceTreeNode ) - { - ancestors.add( ((BehaviorReferenceTreeNode)n).getEntry() ); + if (n instanceof BehaviorReferenceTreeNode) { + ancestors.add( ((BehaviorReferenceTreeNode)n).getEntry()); } } - if( ancestors.contains( node.getEntry() ) ) - { + if (ancestors.contains(node.getEntry())) { continue; } - node.load( index, true ); + node.load(index, true); } } } diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java index 112b864a..ad23b000 100644 --- a/src/cuchaz/enigma/analysis/BridgeFixer.java +++ b/src/cuchaz/enigma/analysis/BridgeFixer.java @@ -20,61 +20,48 @@ import cuchaz.enigma.mapping.BehaviorEntryFactory; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.MethodEntry; -public class BridgeFixer -{ +public class BridgeFixer { + private JarIndex m_index; - public BridgeFixer( JarIndex index ) - { + public BridgeFixer(JarIndex index) { m_index = index; } - - public void fixBridges( CtClass c ) - { + + public void fixBridges(CtClass c) { // rename declared methods - for( CtMethod method : c.getDeclaredMethods() ) - { + for (CtMethod method : c.getDeclaredMethods()) { // get the method entry MethodEntry methodEntry = new MethodEntry( - new ClassEntry( Descriptor.toJvmName( c.getName() ) ), + new ClassEntry(Descriptor.toJvmName(c.getName())), method.getName(), method.getSignature() ); - MethodEntry bridgeMethodEntry = m_index.getBridgeMethod( methodEntry ); - if( bridgeMethodEntry != null ) - { + MethodEntry bridgeMethodEntry = m_index.getBridgeMethod(methodEntry); + if (bridgeMethodEntry != null) { // fix this bridged method - method.setName( bridgeMethodEntry.getName() ); + method.setName(bridgeMethodEntry.getName()); } } // rename method references // translate all the field and method references in the code by editing the constant pool ConstPool constants = c.getClassFile().getConstPool(); - ConstPoolEditor editor = new ConstPoolEditor( constants ); - for( int i=1; i nodes = Lists.newArrayList(); - for( String implementingClassName : index.getImplementingClasses( m_entry.getClassName() ) ) - { - nodes.add( new ClassImplementationsTreeNode( m_deobfuscatingTranslator, new ClassEntry( implementingClassName ) ) ); + for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) { + nodes.add(new ClassImplementationsTreeNode(m_deobfuscatingTranslator, new ClassEntry(implementingClassName))); } // add them to this node - for( ClassImplementationsTreeNode node : nodes ) - { - this.add( node ); + for (ClassImplementationsTreeNode node : nodes) { + this.add(node); } } - public static ClassImplementationsTreeNode findNode( ClassImplementationsTreeNode node, MethodEntry entry ) - { + public static ClassImplementationsTreeNode findNode(ClassImplementationsTreeNode node, MethodEntry entry) { // is this the node? - if( node.m_entry.equals( entry ) ) - { + if (node.m_entry.equals(entry)) { return node; } // recurse - for( int i=0; i nodes = Lists.newArrayList(); - for( String subclassName : ancestries.getSubclassNames( m_obfClassName ) ) - { - nodes.add( new ClassInheritanceTreeNode( m_deobfuscatingTranslator, subclassName ) ); + for (String subclassName : ancestries.getSubclassNames(m_obfClassName)) { + nodes.add(new ClassInheritanceTreeNode(m_deobfuscatingTranslator, subclassName)); } // add them to this node - for( ClassInheritanceTreeNode node : nodes ) - { - this.add( node ); + for (ClassInheritanceTreeNode node : nodes) { + this.add(node); } - if( recurse ) - { - for( ClassInheritanceTreeNode node : nodes ) - { - node.load( ancestries, true ); + if (recurse) { + for (ClassInheritanceTreeNode node : nodes) { + node.load(ancestries, true); } } } - - public static ClassInheritanceTreeNode findNode( ClassInheritanceTreeNode node, ClassEntry entry ) - { + + public static ClassInheritanceTreeNode findNode(ClassInheritanceTreeNode node, ClassEntry entry) { // is this the node? - if( node.getObfClassName().equals( entry.getName() ) ) - { + if (node.getObfClassName().equals(entry.getName())) { return node; } // recurse - for( int i=0; i -{ - private static final List ConstructorNonNames = Arrays.asList( "this", "super", "static" ); +public class EntryReference { + + private static final List ConstructorNonNames = Arrays.asList("this", "super", "static"); public E entry; public C context; private boolean m_isNamed; - public EntryReference( E entry, String sourceName ) - { - this( entry, sourceName, null ); + public EntryReference(E entry, String sourceName) { + this(entry, sourceName, null); } - public EntryReference( E entry, String sourceName, C context ) - { - if( entry == null ) - { - throw new IllegalArgumentException( "Entry cannot be null!" ); + public EntryReference(E entry, String sourceName, C context) { + if (entry == null) { + throw new IllegalArgumentException("Entry cannot be null!"); } this.entry = entry; this.context = context; m_isNamed = sourceName != null && sourceName.length() > 0; - if( entry instanceof ConstructorEntry && ConstructorNonNames.contains( sourceName ) ) - { + if (entry instanceof ConstructorEntry && ConstructorNonNames.contains(sourceName)) { m_isNamed = false; } } - public EntryReference( E entry, C context, EntryReference other ) - { + public EntryReference(E entry, C context, EntryReference other) { this.entry = entry; this.context = context; m_isNamed = other.m_isNamed; } - public ClassEntry getLocationClassEntry( ) - { - if( context != null ) - { + public ClassEntry getLocationClassEntry() { + if (context != null) { return context.getClassEntry(); } return entry.getClassEntry(); } - public boolean isNamed( ) - { + public boolean isNamed() { return m_isNamed; } - public Entry getNameableEntry( ) - { - if( entry instanceof ConstructorEntry ) - { + public Entry getNameableEntry() { + if (entry instanceof ConstructorEntry) { // renaming a constructor really means renaming the class return entry.getClassEntry(); } return entry; } - public String getNamableName( ) - { - if( getNameableEntry() instanceof ClassEntry ) - { + public String getNamableName() { + if (getNameableEntry() instanceof ClassEntry) { ClassEntry classEntry = (ClassEntry)getNameableEntry(); - if( classEntry.isInnerClass() ) - { + if (classEntry.isInnerClass()) { // make sure we only rename the inner class name return classEntry.getInnerClassName(); } @@ -95,55 +82,44 @@ public class EntryReference } @Override - public int hashCode( ) - { - if( context != null ) - { - return Util.combineHashesOrdered( entry.hashCode(), context.hashCode() ); + public int hashCode() { + if (context != null) { + return Util.combineHashesOrdered(entry.hashCode(), context.hashCode()); } return entry.hashCode(); } @Override - public boolean equals( Object other ) - { - if( other instanceof EntryReference ) - { - return equals( (EntryReference)other ); + public boolean equals(Object other) { + if (other instanceof EntryReference) { + return equals((EntryReference)other); } return false; } - public boolean equals( EntryReference other ) - { + public boolean equals(EntryReference other) { // check entry first - boolean isEntrySame = entry.equals( other.entry ); - if( !isEntrySame ) - { + boolean isEntrySame = entry.equals(other.entry); + if (!isEntrySame) { return false; } // check caller - if( context == null && other.context == null ) - { + if (context == null && other.context == null) { return true; - } - else if( context != null && other.context != null ) - { - return context.equals( other.context ); + } else if (context != null && other.context != null) { + return context.equals(other.context); } return false; } @Override - public String toString( ) - { + public String toString() { StringBuilder buf = new StringBuilder(); - buf.append( entry ); - if( context != null ) - { - buf.append( " called from " ); - buf.append( context ); + buf.append(entry); + if (context != null) { + buf.append(" called from "); + buf.append(context); } return buf.toString(); } diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java index 2d59fe9d..b54489cd 100644 --- a/src/cuchaz/enigma/analysis/EntryRenamer.java +++ b/src/cuchaz/enigma/analysis/EntryRenamer.java @@ -26,100 +26,83 @@ import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MethodEntry; -public class EntryRenamer -{ - public static void renameClassesInSet( Map renames, Set set ) - { +public class EntryRenamer { + + public static void renameClassesInSet(Map renames, Set set) { List entries = Lists.newArrayList(); - for( T val : set ) - { - entries.add( renameClassesInThing( renames, val ) ); + for (T val : set) { + entries.add(renameClassesInThing(renames, val)); } set.clear(); - set.addAll( entries ); + set.addAll(entries); } - public static void renameClassesInMap( Map renames, Map map ) - { + public static void renameClassesInMap(Map renames, Map map) { // for each key/value pair... Set> entriesToAdd = Sets.newHashSet(); - for( Map.Entry entry : map.entrySet() ) - { - entriesToAdd.add( new AbstractMap.SimpleEntry( - renameClassesInThing( renames, entry.getKey() ), - renameClassesInThing( renames, entry.getValue() ) - ) ); + for (Map.Entry entry : map.entrySet()) { + entriesToAdd.add(new AbstractMap.SimpleEntry( + renameClassesInThing(renames, entry.getKey()), + renameClassesInThing(renames, entry.getValue()) + )); } map.clear(); - for( Map.Entry entry : entriesToAdd ) - { - map.put( entry.getKey(), entry.getValue() ); + for (Map.Entry entry : entriesToAdd) { + map.put(entry.getKey(), entry.getValue()); } } - public static void renameClassesInMultimap( Map renames, Multimap map ) - { + public static void renameClassesInMultimap(Map renames, Multimap map) { // for each key/value pair... Set> entriesToAdd = Sets.newHashSet(); - for( Map.Entry entry : map.entries() ) - { - entriesToAdd.add( new AbstractMap.SimpleEntry( - renameClassesInThing( renames, entry.getKey() ), - renameClassesInThing( renames, entry.getValue() ) - ) ); + for (Map.Entry entry : map.entries()) { + entriesToAdd.add(new AbstractMap.SimpleEntry( + renameClassesInThing(renames, entry.getKey()), + renameClassesInThing(renames, entry.getValue()) + )); } map.clear(); - for( Map.Entry entry : entriesToAdd ) - { - map.put( entry.getKey(), entry.getValue() ); + for (Map.Entry entry : entriesToAdd) { + map.put(entry.getKey(), entry.getValue()); } } - public static void renameMethodsInMultimap( Map renames, Multimap map ) - { + public static void renameMethodsInMultimap(Map renames, Multimap map) { // for each key/value pair... Set> entriesToAdd = Sets.newHashSet(); - for( Map.Entry entry : map.entries() ) - { - entriesToAdd.add( new AbstractMap.SimpleEntry( - renameMethodsInThing( renames, entry.getKey() ), - renameMethodsInThing( renames, entry.getValue() ) - ) ); + for (Map.Entry entry : map.entries()) { + entriesToAdd.add(new AbstractMap.SimpleEntry( + renameMethodsInThing(renames, entry.getKey()), + renameMethodsInThing(renames, entry.getValue()) + )); } map.clear(); - for( Map.Entry entry : entriesToAdd ) - { - map.put( entry.getKey(), entry.getValue() ); + for (Map.Entry entry : entriesToAdd) { + map.put(entry.getKey(), entry.getValue()); } } - public static void renameMethodsInMap( Map renames, Map map ) - { + public static void renameMethodsInMap(Map renames, Map map) { // for each key/value pair... Set> entriesToAdd = Sets.newHashSet(); - for( Map.Entry entry : map.entrySet() ) - { - entriesToAdd.add( new AbstractMap.SimpleEntry( - renameMethodsInThing( renames, entry.getKey() ), - renameMethodsInThing( renames, entry.getValue() ) - ) ); + for (Map.Entry entry : map.entrySet()) { + entriesToAdd.add(new AbstractMap.SimpleEntry( + renameMethodsInThing(renames, entry.getKey()), + renameMethodsInThing(renames, entry.getValue()) + )); } map.clear(); - for( Map.Entry entry : entriesToAdd ) - { - map.put( entry.getKey(), entry.getValue() ); + for (Map.Entry entry : entriesToAdd) { + map.put(entry.getKey(), entry.getValue()); } } - @SuppressWarnings( "unchecked" ) - public static T renameMethodsInThing( Map renames, T thing ) - { - if( thing instanceof MethodEntry ) - { + @SuppressWarnings("unchecked") + public static T renameMethodsInThing(Map renames, T thing) { + if (thing instanceof MethodEntry) { MethodEntry methodEntry = (MethodEntry)thing; - MethodEntry newMethodEntry = renames.get( methodEntry ); - if( newMethodEntry != null ) - { + MethodEntry newMethodEntry = renames.get(methodEntry); + if (newMethodEntry != null) { return (T)new MethodEntry( methodEntry.getClassEntry(), newMethodEntry.getName(), @@ -127,81 +110,59 @@ public class EntryRenamer ); } return thing; - } - else if( thing instanceof ArgumentEntry ) - { + } else if (thing instanceof ArgumentEntry) { ArgumentEntry argumentEntry = (ArgumentEntry)thing; return (T)new ArgumentEntry( - renameMethodsInThing( renames, argumentEntry.getBehaviorEntry() ), + renameMethodsInThing(renames, argumentEntry.getBehaviorEntry()), argumentEntry.getIndex(), argumentEntry.getName() ); - } - else if( thing instanceof EntryReference ) - { + } else if (thing instanceof EntryReference) { EntryReference reference = (EntryReference)thing; - reference.entry = renameMethodsInThing( renames, reference.entry ); - reference.context = renameMethodsInThing( renames, reference.context ); + reference.entry = renameMethodsInThing(renames, reference.entry); + reference.context = renameMethodsInThing(renames, reference.context); return thing; } return thing; } - - @SuppressWarnings( "unchecked" ) - public static T renameClassesInThing( Map renames, T thing ) - { - if( thing instanceof String ) - { + + @SuppressWarnings("unchecked") + public static T renameClassesInThing(Map renames, T thing) { + if (thing instanceof String) { String stringEntry = (String)thing; - if( renames.containsKey( stringEntry ) ) - { - return (T)renames.get( stringEntry ); + if (renames.containsKey(stringEntry)) { + return (T)renames.get(stringEntry); } - } - else if( thing instanceof ClassEntry ) - { + } else if (thing instanceof ClassEntry) { ClassEntry classEntry = (ClassEntry)thing; - return (T)new ClassEntry( renameClassesInThing( renames, classEntry.getClassName() ) ); - } - else if( thing instanceof FieldEntry ) - { + return (T)new ClassEntry(renameClassesInThing(renames, classEntry.getClassName())); + } else if (thing instanceof FieldEntry) { FieldEntry fieldEntry = (FieldEntry)thing; - return (T)new FieldEntry( - renameClassesInThing( renames, fieldEntry.getClassEntry() ), - fieldEntry.getName() - ); - } - else if( thing instanceof ConstructorEntry ) - { + return (T)new FieldEntry(renameClassesInThing(renames, fieldEntry.getClassEntry()), fieldEntry.getName()); + } else if (thing instanceof ConstructorEntry) { ConstructorEntry constructorEntry = (ConstructorEntry)thing; return (T)new ConstructorEntry( - renameClassesInThing( renames, constructorEntry.getClassEntry() ), + renameClassesInThing(renames, constructorEntry.getClassEntry()), constructorEntry.getSignature() ); - } - else if( thing instanceof MethodEntry ) - { + } else if (thing instanceof MethodEntry) { MethodEntry methodEntry = (MethodEntry)thing; return (T)new MethodEntry( - renameClassesInThing( renames, methodEntry.getClassEntry() ), + renameClassesInThing(renames, methodEntry.getClassEntry()), methodEntry.getName(), methodEntry.getSignature() ); - } - else if( thing instanceof ArgumentEntry ) - { + } else if (thing instanceof ArgumentEntry) { ArgumentEntry argumentEntry = (ArgumentEntry)thing; return (T)new ArgumentEntry( - renameClassesInThing( renames, argumentEntry.getBehaviorEntry() ), + renameClassesInThing(renames, argumentEntry.getBehaviorEntry()), argumentEntry.getIndex(), argumentEntry.getName() ); - } - else if( thing instanceof EntryReference ) - { + } else if (thing instanceof EntryReference) { EntryReference reference = (EntryReference)thing; - reference.entry = renameClassesInThing( renames, reference.entry ); - reference.context = renameClassesInThing( renames, reference.context ); + reference.entry = renameClassesInThing(renames, reference.entry); + reference.context = renameClassesInThing(renames, reference.context); return thing; } diff --git a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java index 2652f64a..2173eea6 100644 --- a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java @@ -16,24 +16,22 @@ import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.Translator; -public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode -{ +public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode { + private static final long serialVersionUID = -7934108091928699835L; private Translator m_deobfuscatingTranslator; private FieldEntry m_entry; private EntryReference m_reference; private Access m_access; - - public FieldReferenceTreeNode( Translator deobfuscatingTranslator, FieldEntry entry ) - { + + public FieldReferenceTreeNode(Translator deobfuscatingTranslator, FieldEntry entry) { m_deobfuscatingTranslator = deobfuscatingTranslator; m_entry = entry; m_reference = null; } - private FieldReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference, Access access ) - { + private FieldReferenceTreeNode(Translator deobfuscatingTranslator, EntryReference reference, Access access) { m_deobfuscatingTranslator = deobfuscatingTranslator; m_entry = reference.entry; m_reference = reference; @@ -41,56 +39,41 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re } @Override - public FieldEntry getEntry( ) - { + public FieldEntry getEntry() { return m_entry; } @Override - public EntryReference getReference( ) - { + public EntryReference getReference() { return m_reference; } @Override - public String toString( ) - { - if( m_reference != null ) - { - return String.format( "%s (%s)", m_deobfuscatingTranslator.translateEntry( m_reference.context ), m_access ); + public String toString() { + if (m_reference != null) { + return String.format("%s (%s)", m_deobfuscatingTranslator.translateEntry(m_reference.context), m_access); } - return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); + return m_deobfuscatingTranslator.translateEntry(m_entry).toString(); } - public void load( JarIndex index, boolean recurse ) - { + public void load(JarIndex index, boolean recurse) { // get all the child nodes - if( m_reference == null ) - { - for( EntryReference reference : index.getFieldReferences( m_entry ) ) - { - add( new FieldReferenceTreeNode( m_deobfuscatingTranslator, reference, index.getAccess( m_entry ) ) ); + if (m_reference == null) { + for (EntryReference reference : index.getFieldReferences(m_entry)) { + add(new FieldReferenceTreeNode(m_deobfuscatingTranslator, reference, index.getAccess(m_entry))); } - } - else - { - for( EntryReference reference : index.getBehaviorReferences( m_reference.context ) ) - { - add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference, index.getAccess( m_reference.context ) ) ); + } else { + for (EntryReference reference : index.getBehaviorReferences(m_reference.context)) { + add(new BehaviorReferenceTreeNode(m_deobfuscatingTranslator, reference, index.getAccess(m_reference.context))); } } - if( recurse && children != null ) - { - for( Object node : children ) - { - if( node instanceof BehaviorReferenceTreeNode ) - { - ((BehaviorReferenceTreeNode)node).load( index, true ); - } - else if( node instanceof FieldReferenceTreeNode ) - { - ((FieldReferenceTreeNode)node).load( index, true ); + if (recurse && children != null) { + for (Object node : children) { + if (node instanceof BehaviorReferenceTreeNode) { + ((BehaviorReferenceTreeNode)node).load(index, true); + } else if (node instanceof FieldReferenceTreeNode) { + ((FieldReferenceTreeNode)node).load(index, true); } } } diff --git a/src/cuchaz/enigma/analysis/JarClassIterator.java b/src/cuchaz/enigma/analysis/JarClassIterator.java index f65b8e79..8d9947c1 100644 --- a/src/cuchaz/enigma/analysis/JarClassIterator.java +++ b/src/cuchaz/enigma/analysis/JarClassIterator.java @@ -30,132 +30,107 @@ import com.google.common.collect.Lists; import cuchaz.enigma.Constants; import cuchaz.enigma.mapping.ClassEntry; -public class JarClassIterator implements Iterator -{ +public class JarClassIterator implements Iterator { + private JarFile m_jar; private Iterator m_iter; - public JarClassIterator( JarFile jar ) - { + public JarClassIterator(JarFile jar) { m_jar = jar; // get the jar entries that correspond to classes List classEntries = Lists.newArrayList(); Enumeration entries = m_jar.entries(); - while( entries.hasMoreElements() ) - { + while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); // is this a class file? - if( entry.getName().endsWith( ".class" ) ) - { - classEntries.add( entry ); + if (entry.getName().endsWith(".class")) { + classEntries.add(entry); } } m_iter = classEntries.iterator(); } @Override - public boolean hasNext( ) - { + public boolean hasNext() { return m_iter.hasNext(); } - + @Override - public CtClass next( ) - { + public CtClass next() { JarEntry entry = m_iter.next(); - try - { - return getClass( m_jar, entry ); - } - catch( IOException | NotFoundException ex ) - { - throw new Error( "Unable to load class: " + entry.getName() ); + try { + return getClass(m_jar, entry); + } catch (IOException | NotFoundException ex) { + throw new Error("Unable to load class: " + entry.getName()); } } - + @Override - public void remove( ) - { + public void remove() { throw new UnsupportedOperationException(); } - public static List getClassEntries( JarFile jar ) - { + public static List getClassEntries(JarFile jar) { List classEntries = Lists.newArrayList(); Enumeration entries = jar.entries(); - while( entries.hasMoreElements() ) - { + while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); // is this a class file? - if( !entry.isDirectory() && entry.getName().endsWith( ".class" ) ) - { - classEntries.add( getClassEntry( entry ) ); + if (!entry.isDirectory() && entry.getName().endsWith(".class")) { + classEntries.add(getClassEntry(entry)); } } return classEntries; } - public static Iterable classes( final JarFile jar ) - { - return new Iterable( ) - { + public static Iterable classes(final JarFile jar) { + return new Iterable() { @Override - public Iterator iterator( ) - { - return new JarClassIterator( jar ); + public Iterator iterator() { + return new JarClassIterator(jar); } }; } - public static CtClass getClass( JarFile jar, ClassEntry classEntry ) - { - try - { - return getClass( jar, new JarEntry( classEntry.getName() + ".class" ) ); - } - catch( IOException | NotFoundException ex ) - { - throw new Error( "Unable to load class: " + classEntry.getName() ); + public static CtClass getClass(JarFile jar, ClassEntry classEntry) { + try { + return getClass(jar, new JarEntry(classEntry.getName() + ".class")); + } catch (IOException | NotFoundException ex) { + throw new Error("Unable to load class: " + classEntry.getName()); } } - private static CtClass getClass( JarFile jar, JarEntry entry ) - throws IOException, NotFoundException - { + private static CtClass getClass(JarFile jar, JarEntry entry) throws IOException, NotFoundException { // read the class into a buffer ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buf = new byte[Constants.KiB]; int totalNumBytesRead = 0; - InputStream in = jar.getInputStream( entry ); - while( in.available() > 0 ) - { - int numBytesRead = in.read( buf ); - if( numBytesRead < 0 ) - { + InputStream in = jar.getInputStream(entry); + while (in.available() > 0) { + int numBytesRead = in.read(buf); + if (numBytesRead < 0) { break; } - bos.write( buf, 0, numBytesRead ); + bos.write(buf, 0, numBytesRead); // sanity checking totalNumBytesRead += numBytesRead; - if( totalNumBytesRead > Constants.MiB ) - { - throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" ); + if (totalNumBytesRead > Constants.MiB) { + throw new Error("Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!"); } } // get a javassist handle for the class - String className = Descriptor.toJavaName( getClassEntry( entry ).getName() ); + String className = Descriptor.toJavaName(getClassEntry(entry).getName()); ClassPool classPool = new ClassPool(); - classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); - return classPool.get( className ); + classPool.insertClassPath(new ByteArrayClassPath(className, bos.toByteArray())); + return classPool.get(className); } - private static ClassEntry getClassEntry( JarEntry entry ) - { - return new ClassEntry( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) ); + private static ClassEntry getClassEntry(JarEntry entry) { + return new ClassEntry(entry.getName().substring(0, entry.getName().length() - ".class".length())); } } diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 0954564e..4b03a332 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -53,8 +53,8 @@ import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.SignatureUpdater; import cuchaz.enigma.mapping.Translator; -public class JarIndex -{ +public class JarIndex { + private Set m_obfClassEntries; private TranslationIndex m_translationIndex; private Multimap m_interfaces; @@ -68,8 +68,7 @@ public class JarIndex private Map m_anonymousClasses; private Map m_bridgeMethods; - public JarIndex( ) - { + public JarIndex() { m_obfClassEntries = Sets.newHashSet(); m_translationIndex = new TranslationIndex(); m_interfaces = HashMultimap.create(); @@ -84,192 +83,161 @@ public class JarIndex m_bridgeMethods = Maps.newHashMap(); } - public void indexJar( JarFile jar, boolean buildInnerClasses ) - { + public void indexJar(JarFile jar, boolean buildInnerClasses) { // step 1: read the class names - for( ClassEntry classEntry : JarClassIterator.getClassEntries( jar ) ) - { - if( classEntry.isInDefaultPackage() ) - { + for (ClassEntry classEntry : JarClassIterator.getClassEntries(jar)) { + if (classEntry.isInDefaultPackage()) { // move out of default package - classEntry = new ClassEntry( Constants.NonePackage + "/" + classEntry.getName() ); + classEntry = new ClassEntry(Constants.NonePackage + "/" + classEntry.getName()); } - m_obfClassEntries.add( classEntry ); + m_obfClassEntries.add(classEntry); } // step 2: index field/method/constructor access - for( CtClass c : JarClassIterator.classes( jar ) ) - { - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); - ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); - for( CtField field : c.getDeclaredFields() ) - { - FieldEntry fieldEntry = new FieldEntry( classEntry, field.getName() ); - m_access.put( fieldEntry, Access.get( field ) ); + for (CtClass c : JarClassIterator.classes(jar)) { + ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); + ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); + for (CtField field : c.getDeclaredFields()) { + FieldEntry fieldEntry = new FieldEntry(classEntry, field.getName()); + m_access.put(fieldEntry, Access.get(field)); } - for( CtMethod method : c.getDeclaredMethods() ) - { - MethodEntry methodEntry = new MethodEntry( classEntry, method.getName(), method.getSignature() ); - m_access.put( methodEntry, Access.get( method ) ); + for (CtMethod method : c.getDeclaredMethods()) { + MethodEntry methodEntry = new MethodEntry(classEntry, method.getName(), method.getSignature()); + m_access.put(methodEntry, Access.get(method)); } - for( CtConstructor constructor : c.getDeclaredConstructors() ) - { - ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getSignature() ); - m_access.put( constructorEntry, Access.get( constructor ) ); + for (CtConstructor constructor : c.getDeclaredConstructors()) { + ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, constructor.getSignature()); + m_access.put(constructorEntry, Access.get(constructor)); } } // step 3: index extends, implements, fields, and methods - for( CtClass c : JarClassIterator.classes( jar ) ) - { - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); - String className = Descriptor.toJvmName( c.getName() ); - m_translationIndex.addSuperclass( className, Descriptor.toJvmName( c.getClassFile().getSuperclass() ) ); - for( String interfaceName : c.getClassFile().getInterfaces() ) - { - className = Descriptor.toJvmName( className ); - interfaceName = Descriptor.toJvmName( interfaceName ); - if( className.equals( interfaceName ) ) - { - throw new IllegalArgumentException( "Class cannot be its own interface! " + className ); + for (CtClass c : JarClassIterator.classes(jar)) { + ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); + String className = Descriptor.toJvmName(c.getName()); + m_translationIndex.addSuperclass(className, Descriptor.toJvmName(c.getClassFile().getSuperclass())); + for (String interfaceName : c.getClassFile().getInterfaces()) { + className = Descriptor.toJvmName(className); + interfaceName = Descriptor.toJvmName(interfaceName); + if (className.equals(interfaceName)) { + throw new IllegalArgumentException("Class cannot be its own interface! " + className); } - m_interfaces.put( className, interfaceName ); + m_interfaces.put(className, interfaceName); } - for( CtField field : c.getDeclaredFields() ) - { - indexField( field ); + for (CtField field : c.getDeclaredFields()) { + indexField(field); } - for( CtBehavior behavior : c.getDeclaredBehaviors() ) - { - indexBehavior( behavior ); + for (CtBehavior behavior : c.getDeclaredBehaviors()) { + indexBehavior(behavior); } } // step 4: index field, method, constructor references - for( CtClass c : JarClassIterator.classes( jar ) ) - { - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); - for( CtBehavior behavior : c.getDeclaredBehaviors() ) - { - indexBehaviorReferences( behavior ); + for (CtClass c : JarClassIterator.classes(jar)) { + ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); + for (CtBehavior behavior : c.getDeclaredBehaviors()) { + indexBehaviorReferences(behavior); } } - if( buildInnerClasses ) - { + if (buildInnerClasses) { // step 5: index inner classes and anonymous classes - for( CtClass c : JarClassIterator.classes( jar ) ) - { - ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); - String outerClassName = findOuterClass( c ); - if( outerClassName != null ) - { + for (CtClass c : JarClassIterator.classes(jar)) { + ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); + String outerClassName = findOuterClass(c); + if (outerClassName != null) { String innerClassName = c.getSimpleName(); - m_innerClasses.put( outerClassName, innerClassName ); - boolean innerWasAdded = m_outerClasses.put( innerClassName, outerClassName ) == null; - assert( innerWasAdded ); + m_innerClasses.put(outerClassName, innerClassName); + boolean innerWasAdded = m_outerClasses.put(innerClassName, outerClassName) == null; + assert (innerWasAdded); - BehaviorEntry enclosingBehavior = isAnonymousClass( c, outerClassName ); - if( enclosingBehavior != null ) - { - m_anonymousClasses.put( innerClassName, enclosingBehavior ); + BehaviorEntry enclosingBehavior = isAnonymousClass(c, outerClassName); + if (enclosingBehavior != null) { + m_anonymousClasses.put(innerClassName, enclosingBehavior); // DEBUG - //System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); - } - else - { + // System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); + } else { // DEBUG - //System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); + // System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); } } } // step 6: update other indices with inner class info Map renames = Maps.newHashMap(); - for( Map.Entry entry : m_outerClasses.entrySet() ) - { - renames.put( Constants.NonePackage + "/" + entry.getKey(), entry.getValue() + "$" + entry.getKey() ); + for (Map.Entry entry : m_outerClasses.entrySet()) { + renames.put(Constants.NonePackage + "/" + entry.getKey(), entry.getValue() + "$" + entry.getKey()); } - EntryRenamer.renameClassesInSet( renames, m_obfClassEntries ); - m_translationIndex.renameClasses( renames ); - EntryRenamer.renameClassesInMultimap( renames, m_interfaces ); - EntryRenamer.renameClassesInMultimap( renames, m_methodImplementations ); - EntryRenamer.renameClassesInMultimap( renames, m_behaviorReferences ); - EntryRenamer.renameClassesInMultimap( renames, m_fieldReferences ); - EntryRenamer.renameClassesInMap( renames, m_bridgeMethods ); - EntryRenamer.renameClassesInMap( renames, m_access ); + EntryRenamer.renameClassesInSet(renames, m_obfClassEntries); + m_translationIndex.renameClasses(renames); + EntryRenamer.renameClassesInMultimap(renames, m_interfaces); + EntryRenamer.renameClassesInMultimap(renames, m_methodImplementations); + EntryRenamer.renameClassesInMultimap(renames, m_behaviorReferences); + EntryRenamer.renameClassesInMultimap(renames, m_fieldReferences); + EntryRenamer.renameClassesInMap(renames, m_bridgeMethods); + EntryRenamer.renameClassesInMap(renames, m_access); } // step 6: update other indices with bridge method info - EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_methodImplementations ); - EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_behaviorReferences ); - EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences ); - EntryRenamer.renameMethodsInMap( m_bridgeMethods, m_access ); + EntryRenamer.renameMethodsInMultimap(m_bridgeMethods, m_methodImplementations); + EntryRenamer.renameMethodsInMultimap(m_bridgeMethods, m_behaviorReferences); + EntryRenamer.renameMethodsInMultimap(m_bridgeMethods, m_fieldReferences); + EntryRenamer.renameMethodsInMap(m_bridgeMethods, m_access); } - private void indexField( CtField field ) - { + private void indexField(CtField field) { // get the field entry - String className = Descriptor.toJvmName( field.getDeclaringClass().getName() ); - FieldEntry fieldEntry = new FieldEntry( new ClassEntry( className ), field.getName() ); + String className = Descriptor.toJvmName(field.getDeclaringClass().getName()); + FieldEntry fieldEntry = new FieldEntry(new ClassEntry(className), field.getName()); - m_translationIndex.addField( className, field.getName() ); + m_translationIndex.addField(className, field.getName()); // is the field a class type? - if( field.getSignature().startsWith( "L" ) ) - { - ClassEntry fieldTypeEntry = new ClassEntry( field.getSignature().substring( 1, field.getSignature().length() - 1 ) ); - m_fieldClasses.put( fieldEntry, fieldTypeEntry ); + if (field.getSignature().startsWith("L")) { + ClassEntry fieldTypeEntry = new ClassEntry(field.getSignature().substring(1, field.getSignature().length() - 1)); + m_fieldClasses.put(fieldEntry, fieldTypeEntry); } } - - private void indexBehavior( CtBehavior behavior ) - { + + private void indexBehavior(CtBehavior behavior) { // get the behavior entry - final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( behavior ); - if( behaviorEntry instanceof MethodEntry ) - { + final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior); + if (behaviorEntry instanceof MethodEntry) { MethodEntry methodEntry = (MethodEntry)behaviorEntry; // index implementation - m_methodImplementations.put( behaviorEntry.getClassName(), methodEntry ); + m_methodImplementations.put(behaviorEntry.getClassName(), methodEntry); // look for bridge methods - CtMethod bridgedMethod = getBridgedMethod( (CtMethod)behavior ); - if( bridgedMethod != null ) - { + CtMethod bridgedMethod = getBridgedMethod((CtMethod)behavior); + if (bridgedMethod != null) { MethodEntry bridgedMethodEntry = new MethodEntry( behaviorEntry.getClassEntry(), bridgedMethod.getName(), bridgedMethod.getSignature() ); - m_bridgeMethods.put( bridgedMethodEntry, methodEntry ); + m_bridgeMethods.put(bridgedMethodEntry, methodEntry); } } // looks like we don't care about constructors here } - private void indexBehaviorReferences( CtBehavior behavior ) - { + private void indexBehaviorReferences(CtBehavior behavior) { // index method calls - final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( behavior ); - try - { - behavior.instrument( new ExprEditor( ) - { + final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior); + try { + behavior.instrument(new ExprEditor() { @Override - public void edit( MethodCall call ) - { - String className = Descriptor.toJvmName( call.getClassName() ); + public void edit(MethodCall call) { + String className = Descriptor.toJvmName(call.getClassName()); MethodEntry calledMethodEntry = new MethodEntry( - new ClassEntry( className ), + new ClassEntry(className), call.getMethodName(), call.getSignature() ); - ClassEntry resolvedClassEntry = resolveEntryClass( calledMethodEntry ); - if( resolvedClassEntry != null && !resolvedClassEntry.equals( calledMethodEntry.getClassEntry() ) ) - { + ClassEntry resolvedClassEntry = resolveEntryClass(calledMethodEntry); + if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) { calledMethodEntry = new MethodEntry( resolvedClassEntry, call.getMethodName(), @@ -281,39 +249,33 @@ public class JarIndex call.getMethodName(), behaviorEntry ); - m_behaviorReferences.put( calledMethodEntry, reference ); + m_behaviorReferences.put(calledMethodEntry, reference); } @Override - public void edit( FieldAccess call ) - { - String className = Descriptor.toJvmName( call.getClassName() ); + public void edit(FieldAccess call) { + String className = Descriptor.toJvmName(call.getClassName()); FieldEntry calledFieldEntry = new FieldEntry( - new ClassEntry( className ), + new ClassEntry(className), call.getFieldName() ); - ClassEntry resolvedClassEntry = resolveEntryClass( calledFieldEntry ); - if( resolvedClassEntry != null && !resolvedClassEntry.equals( calledFieldEntry.getClassEntry() ) ) - { - calledFieldEntry = new FieldEntry( - resolvedClassEntry, - call.getFieldName() - ); + ClassEntry resolvedClassEntry = resolveEntryClass(calledFieldEntry); + if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) { + calledFieldEntry = new FieldEntry(resolvedClassEntry, call.getFieldName()); } EntryReference reference = new EntryReference( calledFieldEntry, call.getFieldName(), behaviorEntry ); - m_fieldReferences.put( calledFieldEntry, reference ); + m_fieldReferences.put(calledFieldEntry, reference); } @Override - public void edit( ConstructorCall call ) - { - String className = Descriptor.toJvmName( call.getClassName() ); + public void edit(ConstructorCall call) { + String className = Descriptor.toJvmName(call.getClassName()); ConstructorEntry calledConstructorEntry = new ConstructorEntry( - new ClassEntry( className ), + new ClassEntry(className), call.getSignature() ); EntryReference reference = new EntryReference( @@ -321,15 +283,14 @@ public class JarIndex call.getMethodName(), behaviorEntry ); - m_behaviorReferences.put( calledConstructorEntry, reference ); + m_behaviorReferences.put(calledConstructorEntry, reference); } @Override - public void edit( NewExpr call ) - { - String className = Descriptor.toJvmName( call.getClassName() ); + public void edit(NewExpr call) { + String className = Descriptor.toJvmName(call.getClassName()); ConstructorEntry calledConstructorEntry = new ConstructorEntry( - new ClassEntry( className ), + new ClassEntry(className), call.getSignature() ); EntryReference reference = new EntryReference( @@ -337,173 +298,141 @@ public class JarIndex call.getClassName(), behaviorEntry ); - m_behaviorReferences.put( calledConstructorEntry, reference ); + m_behaviorReferences.put(calledConstructorEntry, reference); } - } ); - } - catch( CannotCompileException ex ) - { - throw new Error( ex ); + }); + } catch (CannotCompileException ex) { + throw new Error(ex); } } - public ClassEntry resolveEntryClass( Entry obfEntry ) - { + public ClassEntry resolveEntryClass(Entry obfEntry) { + // this entry could refer to a method on a class where the method is not actually implemented // travel up the inheritance tree to find the closest implementation - while( !containsObfEntry( obfEntry ) ) - { + while (!containsObfEntry(obfEntry)) { // is there a parent class? - String superclassName = m_translationIndex.getSuperclassName( obfEntry.getClassName() ); - if( superclassName == null ) - { + String superclassName = m_translationIndex.getSuperclassName(obfEntry.getClassName()); + if (superclassName == null) { // this is probably a method from a class in a library // we can't trace the implementation up any higher unless we index the library return null; } // move up to the parent class - obfEntry = obfEntry.cloneToNewClass( new ClassEntry( superclassName ) ); + obfEntry = obfEntry.cloneToNewClass(new ClassEntry(superclassName)); } return obfEntry.getClassEntry(); } - - private CtMethod getBridgedMethod( CtMethod method ) - { + + private CtMethod getBridgedMethod(CtMethod method) { + // bridge methods just call another method, cast it to the return type, and return the result // let's see if we can detect this scenario // skip non-synthetic methods - if( ( method.getModifiers() & AccessFlag.SYNTHETIC ) == 0 ) - { + if ( (method.getModifiers() & AccessFlag.SYNTHETIC) == 0) { return null; } - + // get all the called methods final List methodCalls = Lists.newArrayList(); - try - { - method.instrument( new ExprEditor( ) - { + try { + method.instrument(new ExprEditor() { @Override - public void edit( MethodCall call ) - { - methodCalls.add( call ); + public void edit(MethodCall call) { + methodCalls.add(call); } - } ); - } - catch( CannotCompileException ex ) - { + }); + } catch (CannotCompileException ex) { // this is stupid... we're not even compiling anything - throw new Error( ex ); + throw new Error(ex); } // is there just one? - if( methodCalls.size() != 1 ) - { + if (methodCalls.size() != 1) { return null; } - MethodCall call = methodCalls.get( 0 ); + MethodCall call = methodCalls.get(0); - try - { + try { // we have a bridge method! return call.getMethod(); - } - catch( NotFoundException ex ) - { + } catch (NotFoundException ex) { // can't find the type? not a bridge method return null; } } - private String findOuterClass( CtClass c ) - { + private String findOuterClass(CtClass c) { + // inner classes: - // have constructors that can (illegally) set synthetic fields - // the outer class is the only class that calls constructors + // have constructors that can (illegally) set synthetic fields + // the outer class is the only class that calls constructors // use the synthetic fields to find the synthetic constructors - for( CtConstructor constructor : c.getDeclaredConstructors() ) - { + for (CtConstructor constructor : c.getDeclaredConstructors()) { Set syntheticFieldTypes = Sets.newHashSet(); - if( !isIllegalConstructor( syntheticFieldTypes, constructor ) ) - { + if (!isIllegalConstructor(syntheticFieldTypes, constructor)) { continue; } - ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); - ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getMethodInfo().getDescriptor() ); + ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); + ConstructorEntry constructorEntry = new ConstructorEntry( + classEntry, + constructor.getMethodInfo().getDescriptor() + ); // gather the classes from the illegally-set synthetic fields Set illegallySetClasses = Sets.newHashSet(); - for( String type : syntheticFieldTypes ) - { - if( type.startsWith( "L" ) ) - { - ClassEntry outerClassEntry = new ClassEntry( type.substring( 1, type.length() - 1 ) ); - if( isSaneOuterClass( outerClassEntry, classEntry ) ) - { - illegallySetClasses.add( outerClassEntry ); + for (String type : syntheticFieldTypes) { + if (type.startsWith("L")) { + ClassEntry outerClassEntry = new ClassEntry(type.substring(1, type.length() - 1)); + if (isSaneOuterClass(outerClassEntry, classEntry)) { + illegallySetClasses.add(outerClassEntry); } } } // who calls this constructor? Set callerClasses = Sets.newHashSet(); - for( EntryReference reference : getBehaviorReferences( constructorEntry ) ) - { + for (EntryReference reference : getBehaviorReferences(constructorEntry)) { + // make sure it's not a call to super - if( reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry ) - { + if (reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry) { + // is the entry a superclass of the context? String calledClassName = reference.entry.getClassName(); - String callerSuperclassName = m_translationIndex.getSuperclassName( reference.context.getClassName() ); - if( callerSuperclassName != null && callerSuperclassName.equals( calledClassName ) ) - { + String callerSuperclassName = m_translationIndex.getSuperclassName(reference.context.getClassName()); + if (callerSuperclassName != null && callerSuperclassName.equals(calledClassName)) { // it's a super call, skip continue; } } - if( isSaneOuterClass( reference.context.getClassEntry(), classEntry ) ) - { - callerClasses.add( reference.context.getClassEntry() ); + if (isSaneOuterClass(reference.context.getClassEntry(), classEntry)) { + callerClasses.add(reference.context.getClassEntry()); } } // do we have an answer yet? - if( callerClasses.isEmpty() ) - { - if( illegallySetClasses.size() == 1 ) - { + if (callerClasses.isEmpty()) { + if (illegallySetClasses.size() == 1) { return illegallySetClasses.iterator().next().getName(); + } else { + System.out.println(String.format("WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry)); } - else - { - System.out.println( String.format( "WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry ) ); - } - } - else - { - if( callerClasses.size() == 1 ) - { + } else { + if (callerClasses.size() == 1) { return callerClasses.iterator().next().getName(); - } - else - { + } else { // multiple callers, do the illegally set classes narrow it down? - Set intersection = Sets.newHashSet( callerClasses ); - intersection.retainAll( illegallySetClasses ); - if( intersection.size() == 1 ) - { + Set intersection = Sets.newHashSet(callerClasses); + intersection.retainAll(illegallySetClasses); + if (intersection.size() == 1) { return intersection.iterator().next().getName(); - } - else - { - System.out.println( String.format( "WARNING: Unable to choose outer class for %s among options: %s", - classEntry, callerClasses - ) ); + } else { + System.out.println(String.format("WARNING: Unable to choose outer class for %s among options: %s", classEntry, callerClasses)); } } } @@ -512,99 +441,82 @@ public class JarIndex return null; } - private boolean isSaneOuterClass( ClassEntry outerClassEntry, ClassEntry innerClassEntry ) - { + private boolean isSaneOuterClass(ClassEntry outerClassEntry, ClassEntry innerClassEntry) { + // clearly this would be silly - if( outerClassEntry.equals( innerClassEntry ) ) - { + if (outerClassEntry.equals(innerClassEntry)) { return false; } // is the outer class in the jar? - if( !m_obfClassEntries.contains( outerClassEntry ) ) - { + if (!m_obfClassEntries.contains(outerClassEntry)) { return false; } return true; } - - @SuppressWarnings( "unchecked" ) - private boolean isIllegalConstructor( Set syntheticFieldTypes, CtConstructor constructor ) - { + + @SuppressWarnings("unchecked") + private boolean isIllegalConstructor(Set syntheticFieldTypes, CtConstructor constructor) { + // illegal constructors only set synthetic member fields, then call super() String className = constructor.getDeclaringClass().getName(); // collect all the field accesses, constructor calls, and method calls final List illegalFieldWrites = Lists.newArrayList(); final List constructorCalls = Lists.newArrayList(); - try - { - constructor.instrument( new ExprEditor( ) - { + try { + constructor.instrument(new ExprEditor() { @Override - public void edit( FieldAccess fieldAccess ) - { - if( fieldAccess.isWriter() && constructorCalls.isEmpty() ) - { - illegalFieldWrites.add( fieldAccess ); + public void edit(FieldAccess fieldAccess) { + if (fieldAccess.isWriter() && constructorCalls.isEmpty()) { + illegalFieldWrites.add(fieldAccess); } } @Override - public void edit( ConstructorCall constructorCall ) - { - constructorCalls.add( constructorCall ); + public void edit(ConstructorCall constructorCall) { + constructorCalls.add(constructorCall); } - } ); - } - catch( CannotCompileException ex ) - { + }); + } catch (CannotCompileException ex) { // we're not compiling anything... this is stupid - throw new Error( ex ); + throw new Error(ex); } // are there any illegal field writes? - if( illegalFieldWrites.isEmpty() ) - { + if (illegalFieldWrites.isEmpty()) { return false; } // are all the writes to synthetic fields? - for( FieldAccess fieldWrite : illegalFieldWrites ) - { + for (FieldAccess fieldWrite : illegalFieldWrites) { + // all illegal writes have to be to the local class - if( !fieldWrite.getClassName().equals( className ) ) - { - System.err.println( String.format( "WARNING: illegal write to non-member field %s.%s", fieldWrite.getClassName(), fieldWrite.getFieldName() ) ); + if (!fieldWrite.getClassName().equals(className)) { + System.err.println(String.format("WARNING: illegal write to non-member field %s.%s", fieldWrite.getClassName(), fieldWrite.getFieldName())); return false; } // find the field FieldInfo fieldInfo = null; - for( FieldInfo info : (List)constructor.getDeclaringClass().getClassFile().getFields() ) - { - if( info.getName().equals( fieldWrite.getFieldName() ) && info.getDescriptor().equals( fieldWrite.getSignature() ) ) - { + for (FieldInfo info : (List)constructor.getDeclaringClass().getClassFile().getFields()) { + if (info.getName().equals(fieldWrite.getFieldName()) && info.getDescriptor().equals(fieldWrite.getSignature())) { fieldInfo = info; break; } } - if( fieldInfo == null ) - { + if (fieldInfo == null) { // field is in a superclass or something, can't be a local synthetic member return false; } // is this field synthetic? boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; - if( isSynthetic ) - { - syntheticFieldTypes.add( fieldInfo.getDescriptor() ); - } - else - { - System.err.println( String.format( "WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName() ) ); + if (isSynthetic) { + syntheticFieldTypes.add(fieldInfo.getDescriptor()); + } else { + System.err.println(String.format("WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName())); return false; } } @@ -612,56 +524,51 @@ public class JarIndex // we passed all the tests! return true; } - - private BehaviorEntry isAnonymousClass( CtClass c, String outerClassName ) - { - ClassEntry innerClassEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); + + private BehaviorEntry isAnonymousClass(CtClass c, String outerClassName) { + + ClassEntry innerClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); // anonymous classes: - // can't be abstract - // have only one constructor - // it's called exactly once by the outer class - // the type the instance is assigned to can't be this type + // can't be abstract + // have only one constructor + // it's called exactly once by the outer class + // the type the instance is assigned to can't be this type // is abstract? - if( Modifier.isAbstract( c.getModifiers() ) ) - { + if (Modifier.isAbstract(c.getModifiers())) { return null; } // is there exactly one constructor? - if( c.getDeclaredConstructors().length != 1 ) - { + if (c.getDeclaredConstructors().length != 1) { return null; } CtConstructor constructor = c.getDeclaredConstructors()[0]; // is this constructor called exactly once? - ConstructorEntry constructorEntry = new ConstructorEntry( innerClassEntry, constructor.getMethodInfo().getDescriptor() ); - Collection> references = getBehaviorReferences( constructorEntry ); - if( references.size() != 1 ) - { + ConstructorEntry constructorEntry = new ConstructorEntry( + innerClassEntry, + constructor.getMethodInfo().getDescriptor() + ); + Collection> references = getBehaviorReferences(constructorEntry); + if (references.size() != 1) { return null; } // does the caller use this type? BehaviorEntry caller = references.iterator().next().context; - for( FieldEntry fieldEntry : getReferencedFields( caller ) ) - { - ClassEntry fieldClass = getFieldClass( fieldEntry ); - if( fieldClass != null && fieldClass.equals( innerClassEntry ) ) - { + for (FieldEntry fieldEntry : getReferencedFields(caller)) { + ClassEntry fieldClass = getFieldClass(fieldEntry); + if (fieldClass != null && fieldClass.equals(innerClassEntry)) { // caller references this type, so it can't be anonymous return null; } } - for( BehaviorEntry behaviorEntry : getReferencedBehaviors( caller ) ) - { + for (BehaviorEntry behaviorEntry : getReferencedBehaviors(caller)) { // get the class types from the signature - for( String className : SignatureUpdater.getClasses( behaviorEntry.getSignature() ) ) - { - if( className.equals( innerClassEntry.getName() ) ) - { + for (String className : SignatureUpdater.getClasses(behaviorEntry.getSignature())) { + if (className.equals(innerClassEntry.getName())) { // caller references this type, so it can't be anonymous return null; } @@ -670,330 +577,275 @@ public class JarIndex return caller; } - - public Set getObfClassEntries( ) - { + + public Set getObfClassEntries() { return m_obfClassEntries; } - public TranslationIndex getTranslationIndex( ) - { + public TranslationIndex getTranslationIndex() { return m_translationIndex; } - public Access getAccess( Entry entry ) - { - return m_access.get( entry ); + public Access getAccess(Entry entry) { + return m_access.get(entry); } - public ClassEntry getFieldClass( FieldEntry fieldEntry ) - { - return m_fieldClasses.get( fieldEntry ); + public ClassEntry getFieldClass(FieldEntry fieldEntry) { + return m_fieldClasses.get(fieldEntry); } - public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) - { + public ClassInheritanceTreeNode getClassInheritance(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) { + // get the root node List ancestry = Lists.newArrayList(); - ancestry.add( obfClassEntry.getName() ); - ancestry.addAll( m_translationIndex.getAncestry( obfClassEntry.getName() ) ); - ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) ); + ancestry.add(obfClassEntry.getName()); + ancestry.addAll(m_translationIndex.getAncestry(obfClassEntry.getName())); + ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( + deobfuscatingTranslator, + ancestry.get(ancestry.size() - 1) + ); // expand all children recursively - rootNode.load( m_translationIndex, true ); + rootNode.load(m_translationIndex, true); return rootNode; } - public ClassImplementationsTreeNode getClassImplementations( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) - { + public ClassImplementationsTreeNode getClassImplementations(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) { + // is this even an interface? - if( isInterface( obfClassEntry.getClassName() ) ) - { - ClassImplementationsTreeNode node = new ClassImplementationsTreeNode( deobfuscatingTranslator, obfClassEntry ); - node.load( this ); + if (isInterface(obfClassEntry.getClassName())) { + ClassImplementationsTreeNode node = new ClassImplementationsTreeNode(deobfuscatingTranslator, obfClassEntry); + node.load(this); return node; } return null; } - public MethodInheritanceTreeNode getMethodInheritance( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) - { + public MethodInheritanceTreeNode getMethodInheritance(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { + // travel to the ancestor implementation String baseImplementationClassName = obfMethodEntry.getClassName(); - for( String ancestorClassName : m_translationIndex.getAncestry( obfMethodEntry.getClassName() ) ) - { + for (String ancestorClassName : m_translationIndex.getAncestry(obfMethodEntry.getClassName())) { MethodEntry ancestorMethodEntry = new MethodEntry( - new ClassEntry( ancestorClassName ), + new ClassEntry(ancestorClassName), obfMethodEntry.getName(), obfMethodEntry.getSignature() ); - if( containsObfBehavior( ancestorMethodEntry ) ) - { + if (containsObfBehavior(ancestorMethodEntry)) { baseImplementationClassName = ancestorClassName; } } // make a root node at the base MethodEntry methodEntry = new MethodEntry( - new ClassEntry( baseImplementationClassName ), + new ClassEntry(baseImplementationClassName), obfMethodEntry.getName(), obfMethodEntry.getSignature() ); MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( deobfuscatingTranslator, methodEntry, - containsObfBehavior( methodEntry ) + containsObfBehavior(methodEntry) ); // expand the full tree - rootNode.load( this, true ); + rootNode.load(this, true); return rootNode; } - public MethodImplementationsTreeNode getMethodImplementations( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) - { + public MethodImplementationsTreeNode getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { + MethodEntry interfaceMethodEntry; // is this method on an interface? - if( isInterface( obfMethodEntry.getClassName() ) ) - { + if (isInterface(obfMethodEntry.getClassName())) { interfaceMethodEntry = obfMethodEntry; - } - else - { + } else { // get the interface class List methodInterfaces = Lists.newArrayList(); - for( String interfaceName : getInterfaces( obfMethodEntry.getClassName() ) ) - { + for (String interfaceName : getInterfaces(obfMethodEntry.getClassName())) { // is this method defined in this interface? MethodEntry methodInterface = new MethodEntry( - new ClassEntry( interfaceName ), + new ClassEntry(interfaceName), obfMethodEntry.getName(), obfMethodEntry.getSignature() ); - if( containsObfBehavior( methodInterface ) ) - { - methodInterfaces.add( methodInterface ); + if (containsObfBehavior(methodInterface)) { + methodInterfaces.add(methodInterface); } } - if( methodInterfaces.isEmpty() ) - { + if (methodInterfaces.isEmpty()) { return null; } - if( methodInterfaces.size() > 1 ) - { - throw new Error( "Too many interfaces define this method! This is not yet supported by Enigma!" ); + if (methodInterfaces.size() > 1) { + throw new Error("Too many interfaces define this method! This is not yet supported by Enigma!"); } - interfaceMethodEntry = methodInterfaces.get( 0 ); + interfaceMethodEntry = methodInterfaces.get(0); } - MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode( deobfuscatingTranslator, interfaceMethodEntry ); - rootNode.load( this ); + MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry); + rootNode.load(this); return rootNode; } - public Set getRelatedMethodImplementations( MethodEntry obfMethodEntry ) - { + public Set getRelatedMethodImplementations(MethodEntry obfMethodEntry) { Set methodEntries = Sets.newHashSet(); - getRelatedMethodImplementations( methodEntries, getMethodInheritance( null, obfMethodEntry ) ); + getRelatedMethodImplementations(methodEntries, getMethodInheritance(null, obfMethodEntry)); return methodEntries; } - private void getRelatedMethodImplementations( Set methodEntries, MethodInheritanceTreeNode node ) - { + private void getRelatedMethodImplementations(Set methodEntries, MethodInheritanceTreeNode node) { MethodEntry methodEntry = node.getMethodEntry(); - if( containsObfBehavior( methodEntry ) ) - { + if (containsObfBehavior(methodEntry)) { // collect the entry - methodEntries.add( methodEntry ); + methodEntries.add(methodEntry); } // look at interface methods too - MethodImplementationsTreeNode implementations = getMethodImplementations( null, methodEntry ); - if( implementations != null ) - { - getRelatedMethodImplementations( methodEntries, implementations ); + MethodImplementationsTreeNode implementations = getMethodImplementations(null, methodEntry); + if (implementations != null) { + getRelatedMethodImplementations(methodEntries, implementations); } // recurse - for( int i=0; i methodEntries, MethodImplementationsTreeNode node ) - { + private void getRelatedMethodImplementations(Set methodEntries, MethodImplementationsTreeNode node) { MethodEntry methodEntry = node.getMethodEntry(); - if( containsObfBehavior( methodEntry ) ) - { + if (containsObfBehavior(methodEntry)) { // collect the entry - methodEntries.add( methodEntry ); + methodEntries.add(methodEntry); } // recurse - for( int i=0; i> getFieldReferences( FieldEntry fieldEntry ) - { - return m_fieldReferences.get( fieldEntry ); + + public Collection> getFieldReferences(FieldEntry fieldEntry) { + return m_fieldReferences.get(fieldEntry); } - public Collection getReferencedFields( BehaviorEntry behaviorEntry ) - { + public Collection getReferencedFields(BehaviorEntry behaviorEntry) { // linear search is fast enough for now Set fieldEntries = Sets.newHashSet(); - for( EntryReference reference : m_fieldReferences.values() ) - { - if( reference.context == behaviorEntry ) - { - fieldEntries.add( reference.entry ); + for (EntryReference reference : m_fieldReferences.values()) { + if (reference.context == behaviorEntry) { + fieldEntries.add(reference.entry); } } return fieldEntries; } - public Collection> getBehaviorReferences( BehaviorEntry behaviorEntry ) - { - return m_behaviorReferences.get( behaviorEntry ); + public Collection> getBehaviorReferences(BehaviorEntry behaviorEntry) { + return m_behaviorReferences.get(behaviorEntry); } - - public Collection getReferencedBehaviors( BehaviorEntry behaviorEntry ) - { + + public Collection getReferencedBehaviors(BehaviorEntry behaviorEntry) { // linear search is fast enough for now Set behaviorEntries = Sets.newHashSet(); - for( EntryReference reference : m_behaviorReferences.values() ) - { - if( reference.context == behaviorEntry ) - { - behaviorEntries.add( reference.entry ); + for (EntryReference reference : m_behaviorReferences.values()) { + if (reference.context == behaviorEntry) { + behaviorEntries.add(reference.entry); } } return behaviorEntries; } - public Collection getInnerClasses( String obfOuterClassName ) - { - return m_innerClasses.get( obfOuterClassName ); + public Collection getInnerClasses(String obfOuterClassName) { + return m_innerClasses.get(obfOuterClassName); } - public String getOuterClass( String obfInnerClassName ) - { + public String getOuterClass(String obfInnerClassName) { // make sure we use the right name - if( new ClassEntry( obfInnerClassName ).getPackageName() != null ) - { - throw new IllegalArgumentException( "Don't reference obfuscated inner classes using packages: " + obfInnerClassName ); + if (new ClassEntry(obfInnerClassName).getPackageName() != null) { + throw new IllegalArgumentException("Don't reference obfuscated inner classes using packages: " + obfInnerClassName); } - return m_outerClasses.get( obfInnerClassName ); + return m_outerClasses.get(obfInnerClassName); } - public boolean isAnonymousClass( String obfInnerClassName ) - { - return m_anonymousClasses.containsKey( obfInnerClassName ); + public boolean isAnonymousClass(String obfInnerClassName) { + return m_anonymousClasses.containsKey(obfInnerClassName); } - public BehaviorEntry getAnonymousClassCaller( String obfInnerClassName ) - { - return m_anonymousClasses.get( obfInnerClassName ); + public BehaviorEntry getAnonymousClassCaller(String obfInnerClassName) { + return m_anonymousClasses.get(obfInnerClassName); } - public Set getInterfaces( String className ) - { + public Set getInterfaces(String className) { Set interfaceNames = new HashSet(); - interfaceNames.addAll( m_interfaces.get( className ) ); - for( String ancestor : m_translationIndex.getAncestry( className ) ) - { - interfaceNames.addAll( m_interfaces.get( ancestor ) ); + interfaceNames.addAll(m_interfaces.get(className)); + for (String ancestor : m_translationIndex.getAncestry(className)) { + interfaceNames.addAll(m_interfaces.get(ancestor)); } return interfaceNames; } - public Set getImplementingClasses( String targetInterfaceName ) - { + public Set getImplementingClasses(String targetInterfaceName) { // linear search is fast enough for now Set classNames = Sets.newHashSet(); - for( Map.Entry entry : m_interfaces.entries() ) - { + for (Map.Entry entry : m_interfaces.entries()) { String className = entry.getKey(); String interfaceName = entry.getValue(); - if( interfaceName.equals( targetInterfaceName ) ) - { - classNames.add( className ); - m_translationIndex.getSubclassNamesRecursively( classNames, className ); + if (interfaceName.equals(targetInterfaceName)) { + classNames.add(className); + m_translationIndex.getSubclassNamesRecursively(classNames, className); } } return classNames; } - public boolean isInterface( String className ) - { - return m_interfaces.containsValue( className ); + public boolean isInterface(String className) { + return m_interfaces.containsValue(className); } - public MethodEntry getBridgeMethod( MethodEntry methodEntry ) - { - return m_bridgeMethods.get( methodEntry ); + public MethodEntry getBridgeMethod(MethodEntry methodEntry) { + return m_bridgeMethods.get(methodEntry); } - public boolean containsObfClass( ClassEntry obfClassEntry ) - { - return m_obfClassEntries.contains( obfClassEntry ); + public boolean containsObfClass(ClassEntry obfClassEntry) { + return m_obfClassEntries.contains(obfClassEntry); } - - public boolean containsObfField( FieldEntry obfFieldEntry ) - { - return m_access.containsKey( obfFieldEntry ); + + public boolean containsObfField(FieldEntry obfFieldEntry) { + return m_access.containsKey(obfFieldEntry); } - - public boolean containsObfBehavior( BehaviorEntry obfBehaviorEntry ) - { - return m_access.containsKey( obfBehaviorEntry ); + + public boolean containsObfBehavior(BehaviorEntry obfBehaviorEntry) { + return m_access.containsKey(obfBehaviorEntry); } - public boolean containsObfArgument( ArgumentEntry obfArgumentEntry ) - { + public boolean containsObfArgument(ArgumentEntry obfArgumentEntry) { // check the behavior - if( !containsObfBehavior( obfArgumentEntry.getBehaviorEntry() ) ) - { + if (!containsObfBehavior(obfArgumentEntry.getBehaviorEntry())) { return false; } // check the argument - if( obfArgumentEntry.getIndex() >= Descriptor.numOfParameters( obfArgumentEntry.getBehaviorEntry().getSignature() ) ) - { + if (obfArgumentEntry.getIndex() >= Descriptor.numOfParameters(obfArgumentEntry.getBehaviorEntry().getSignature())) { return false; } return true; } - public boolean containsObfEntry( Entry obfEntry ) - { - if( obfEntry instanceof ClassEntry ) - { - return containsObfClass( (ClassEntry)obfEntry ); - } - else if( obfEntry instanceof FieldEntry ) - { - return containsObfField( (FieldEntry)obfEntry ); - } - else if( obfEntry instanceof BehaviorEntry ) - { - return containsObfBehavior( (BehaviorEntry)obfEntry ); - } - else if( obfEntry instanceof ArgumentEntry ) - { - return containsObfArgument( (ArgumentEntry)obfEntry ); - } - else - { - throw new Error( "Entry type not supported: " + obfEntry.getClass().getName() ); + public boolean containsObfEntry(Entry obfEntry) { + if (obfEntry instanceof ClassEntry) { + return containsObfClass((ClassEntry)obfEntry); + } else if (obfEntry instanceof FieldEntry) { + return containsObfField((FieldEntry)obfEntry); + } else if (obfEntry instanceof BehaviorEntry) { + return containsObfBehavior((BehaviorEntry)obfEntry); + } else if (obfEntry instanceof ArgumentEntry) { + return containsObfArgument((ArgumentEntry)obfEntry); + } else { + throw new Error("Entry type not supported: " + obfEntry.getClass().getName()); } } } diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java index a050282b..10092268 100644 --- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java @@ -20,94 +20,78 @@ import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.Translator; -public class MethodImplementationsTreeNode extends DefaultMutableTreeNode -{ +public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { + private static final long serialVersionUID = 3781080657461899915L; private Translator m_deobfuscatingTranslator; private MethodEntry m_entry; - public MethodImplementationsTreeNode( Translator deobfuscatingTranslator, MethodEntry entry ) - { - if( entry == null ) - { - throw new IllegalArgumentException( "entry cannot be null!" ); + public MethodImplementationsTreeNode(Translator deobfuscatingTranslator, MethodEntry entry) { + if (entry == null) { + throw new IllegalArgumentException("entry cannot be null!"); } m_deobfuscatingTranslator = deobfuscatingTranslator; m_entry = entry; } - public MethodEntry getMethodEntry( ) - { + public MethodEntry getMethodEntry() { return m_entry; } - public String getDeobfClassName( ) - { - return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() ); + public String getDeobfClassName() { + return m_deobfuscatingTranslator.translateClass(m_entry.getClassName()); } - public String getDeobfMethodName( ) - { - return m_deobfuscatingTranslator.translate( m_entry ); + public String getDeobfMethodName() { + return m_deobfuscatingTranslator.translate(m_entry); } @Override - public String toString( ) - { + public String toString() { String className = getDeobfClassName(); - if( className == null ) - { + if (className == null) { className = m_entry.getClassName(); } String methodName = getDeobfMethodName(); - if( methodName == null ) - { + if (methodName == null) { methodName = m_entry.getName(); } return className + "." + methodName + "()"; } - public void load( JarIndex index ) - { + public void load(JarIndex index) { // get all method implementations List nodes = Lists.newArrayList(); - for( String implementingClassName : index.getImplementingClasses( m_entry.getClassName() ) ) - { + for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) { MethodEntry methodEntry = new MethodEntry( - new ClassEntry( implementingClassName ), + new ClassEntry(implementingClassName), m_entry.getName(), m_entry.getSignature() ); - if( index.containsObfBehavior( methodEntry ) ) - { - nodes.add( new MethodImplementationsTreeNode( m_deobfuscatingTranslator, methodEntry ) ); + if (index.containsObfBehavior(methodEntry)) { + nodes.add(new MethodImplementationsTreeNode(m_deobfuscatingTranslator, methodEntry)); } } // add them to this node - for( MethodImplementationsTreeNode node : nodes ) - { - this.add( node ); + for (MethodImplementationsTreeNode node : nodes) { + this.add(node); } } - public static MethodImplementationsTreeNode findNode( MethodImplementationsTreeNode node, MethodEntry entry ) - { + public static MethodImplementationsTreeNode findNode(MethodImplementationsTreeNode node, MethodEntry entry) { // is this the node? - if( node.getMethodEntry().equals( entry ) ) - { + if (node.getMethodEntry().equals(entry)) { return node; } // recurse - for( int i=0; i nodes = Lists.newArrayList(); - for( String subclassName : index.getTranslationIndex().getSubclassNames( m_entry.getClassName() ) ) - { + for (String subclassName : index.getTranslationIndex().getSubclassNames(m_entry.getClassName())) { MethodEntry methodEntry = new MethodEntry( - new ClassEntry( subclassName ), + new ClassEntry(subclassName), m_entry.getName(), m_entry.getSignature() ); - nodes.add( new MethodInheritanceTreeNode( + nodes.add(new MethodInheritanceTreeNode( m_deobfuscatingTranslator, methodEntry, - index.containsObfBehavior( methodEntry ) - ) ); + index.containsObfBehavior(methodEntry) + )); } // add them to this node - for( MethodInheritanceTreeNode node : nodes ) - { - this.add( node ); + for (MethodInheritanceTreeNode node : nodes) { + this.add(node); } - if( recurse ) - { - for( MethodInheritanceTreeNode node : nodes ) - { - node.load( index, true ); + if (recurse) { + for (MethodInheritanceTreeNode node : nodes) { + node.load(index, true); } } } - public static MethodInheritanceTreeNode findNode( MethodInheritanceTreeNode node, MethodEntry entry ) - { + public static MethodInheritanceTreeNode findNode(MethodInheritanceTreeNode node, MethodEntry entry) { // is this the node? - if( node.getMethodEntry().equals( entry ) ) - { + if (node.getMethodEntry().equals(entry)) { return node; } // recurse - for( int i=0; i -{ +public interface ReferenceTreeNode { E getEntry(); EntryReference getReference(); } diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 0e33de00..b43ab614 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -25,16 +25,15 @@ import com.strobel.decompiler.languages.java.ast.Identifier; import cuchaz.enigma.mapping.Entry; -public class SourceIndex -{ +public class SourceIndex { + private String m_source; private TreeMap> m_tokenToReference; private Multimap,Token> m_referenceToTokens; private Map m_declarationToToken; private List m_lineOffsets; - public SourceIndex( String source ) - { + public SourceIndex(String source) { m_source = source; m_tokenToReference = Maps.newTreeMap(); m_referenceToTokens = HashMultimap.create(); @@ -42,142 +41,119 @@ public class SourceIndex m_lineOffsets = Lists.newArrayList(); // count the lines - m_lineOffsets.add( 0 ); - for( int i=0; i= 0 ) - { + int pos = name.lastIndexOf('$'); + if (pos >= 0) { token.end -= pos + 1; } return token; } - public void addReference( AstNode node, Entry deobfEntry, Entry deobfContext ) - { - Token token = getToken( node ); - if( token != null ) - { - EntryReference deobfReference = new EntryReference( deobfEntry, token.text, deobfContext ); - m_tokenToReference.put( token, deobfReference ); - m_referenceToTokens.put( deobfReference, token ); + public void addReference(AstNode node, Entry deobfEntry, Entry deobfContext) { + Token token = getToken(node); + if (token != null) { + EntryReference deobfReference = new EntryReference(deobfEntry, token.text, deobfContext); + m_tokenToReference.put(token, deobfReference); + m_referenceToTokens.put(deobfReference, token); } } - public void addDeclaration( AstNode node, Entry deobfEntry ) - { - Token token = getToken( node ); - if( token != null ) - { - EntryReference reference = new EntryReference( deobfEntry, token.text ); - m_tokenToReference.put( token, reference ); - m_referenceToTokens.put( reference, token ); - m_declarationToToken.put( deobfEntry, token ); + public void addDeclaration(AstNode node, Entry deobfEntry) { + Token token = getToken(node); + if (token != null) { + EntryReference reference = new EntryReference(deobfEntry, token.text); + m_tokenToReference.put(token, reference); + m_referenceToTokens.put(reference, token); + m_declarationToToken.put(deobfEntry, token); } } - public Token getReferenceToken( int pos ) - { - Token token = m_tokenToReference.floorKey( new Token( pos, pos, null ) ); - if( token != null && token.contains( pos ) ) - { + public Token getReferenceToken(int pos) { + Token token = m_tokenToReference.floorKey(new Token(pos, pos, null)); + if (token != null && token.contains(pos)) { return token; } return null; } - public Collection getReferenceTokens( EntryReference deobfReference ) - { - return m_referenceToTokens.get( deobfReference ); + public Collection getReferenceTokens(EntryReference deobfReference) { + return m_referenceToTokens.get(deobfReference); } - public EntryReference getDeobfReference( Token token ) - { - if( token == null ) - { + public EntryReference getDeobfReference(Token token) { + if (token == null) { return null; } - return m_tokenToReference.get( token ); + return m_tokenToReference.get(token); } - public void replaceDeobfReference( Token token, EntryReference newDeobfReference ) - { - EntryReference oldDeobfReference = m_tokenToReference.get( token ); - m_tokenToReference.put( token, newDeobfReference ); - Collection tokens = m_referenceToTokens.get( oldDeobfReference ); - m_referenceToTokens.removeAll( oldDeobfReference ); - m_referenceToTokens.putAll( newDeobfReference, tokens ); + public void replaceDeobfReference(Token token, EntryReference newDeobfReference) { + EntryReference oldDeobfReference = m_tokenToReference.get(token); + m_tokenToReference.put(token, newDeobfReference); + Collection tokens = m_referenceToTokens.get(oldDeobfReference); + m_referenceToTokens.removeAll(oldDeobfReference); + m_referenceToTokens.putAll(newDeobfReference, tokens); } - public Iterable referenceTokens( ) - { + public Iterable referenceTokens() { return m_tokenToReference.keySet(); } - public Iterable declarationTokens( ) - { + public Iterable declarationTokens() { return m_declarationToToken.values(); } - public Token getDeclarationToken( Entry deobfEntry ) - { - return m_declarationToToken.get( deobfEntry ); + public Token getDeclarationToken(Entry deobfEntry) { + return m_declarationToToken.get(deobfEntry); } - public int getLineNumber( int pos ) - { + public int getLineNumber(int pos) { // line number is 1-based int line = 0; - for( Integer offset : m_lineOffsets ) - { - if( offset > pos ) - { + for (Integer offset : m_lineOffsets) { + if (offset > pos) { break; } line++; @@ -185,15 +161,13 @@ public class SourceIndex return line; } - public int getColumnNumber( int pos ) - { + public int getColumnNumber(int pos) { // column number is 1-based - return pos - m_lineOffsets.get( getLineNumber( pos ) - 1 ) + 1; + return pos - m_lineOffsets.get(getLineNumber(pos) - 1) + 1; } - - private int toPos( int line, int col ) - { + + private int toPos(int line, int col) { // line and col are 1-based - return m_lineOffsets.get( line - 1 ) + col - 1; + return m_lineOffsets.get(line - 1) + col - 1; } } diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index 7ffd1700..43c17499 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -36,159 +36,128 @@ import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MethodEntry; -public class SourceIndexBehaviorVisitor extends SourceIndexVisitor -{ +public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { + private BehaviorEntry m_behaviorEntry; - public SourceIndexBehaviorVisitor( BehaviorEntry behaviorEntry ) - { + public SourceIndexBehaviorVisitor(BehaviorEntry behaviorEntry) { m_behaviorEntry = behaviorEntry; } @Override - public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) - { - MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) { + MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); // get the behavior entry - ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); BehaviorEntry behaviorEntry = null; - if( ref instanceof MethodReference ) - { + if (ref instanceof MethodReference) { MethodReference methodRef = (MethodReference)ref; - if( methodRef.isConstructor() ) - { - behaviorEntry = new ConstructorEntry( classEntry, ref.getSignature() ); - } - else if( methodRef.isTypeInitializer() ) - { - behaviorEntry = new ConstructorEntry( classEntry ); - } - else - { - behaviorEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); + if (methodRef.isConstructor()) { + behaviorEntry = new ConstructorEntry(classEntry, ref.getSignature()); + } else if (methodRef.isTypeInitializer()) { + behaviorEntry = new ConstructorEntry(classEntry); + } else { + behaviorEntry = new MethodEntry(classEntry, ref.getName(), ref.getSignature()); } } - if( behaviorEntry != null ) - { + if (behaviorEntry != null) { // get the node for the token AstNode tokenNode = null; - if( node.getTarget() instanceof MemberReferenceExpression ) - { + if (node.getTarget() instanceof MemberReferenceExpression) { tokenNode = ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(); - } - else if( node.getTarget() instanceof SuperReferenceExpression ) - { + } else if (node.getTarget() instanceof SuperReferenceExpression) { tokenNode = node.getTarget(); - } - else if( node.getTarget() instanceof ThisReferenceExpression ) - { + } else if (node.getTarget() instanceof ThisReferenceExpression) { tokenNode = node.getTarget(); } - if( tokenNode != null ) - { - index.addReference( tokenNode, behaviorEntry, m_behaviorEntry ); + if (tokenNode != null) { + index.addReference(tokenNode, behaviorEntry, m_behaviorEntry); } } - return recurse( node, index ); + return recurse(node, index); } @Override - public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index ) - { - MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); - if( ref != null ) - { + public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { + MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); + if (ref != null) { // make sure this is actually a field - if( ref.getSignature().indexOf( '(' ) >= 0 ) - { - throw new Error( "Expected a field here! got " + ref ); + if (ref.getSignature().indexOf('(') >= 0) { + throw new Error("Expected a field here! got " + ref); } - ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); - FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); - index.addReference( node.getMemberNameToken(), fieldEntry, m_behaviorEntry ); + ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); + FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName()); + index.addReference(node.getMemberNameToken(), fieldEntry, m_behaviorEntry); } - return recurse( node, index ); + return recurse(node, index); } @Override - public Void visitSimpleType( SimpleType node, SourceIndex index ) - { - TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); - if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) - { - ClassEntry classEntry = new ClassEntry( ref.getInternalName() ); - index.addReference( node.getIdentifierToken(), classEntry, m_behaviorEntry ); + public Void visitSimpleType(SimpleType node, SourceIndex index) { + TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); + if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { + ClassEntry classEntry = new ClassEntry(ref.getInternalName()); + index.addReference(node.getIdentifierToken(), classEntry, m_behaviorEntry); } - return recurse( node, index ); + return recurse(node, index); } @Override - public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) - { - ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) { + ParameterDefinition def = node.getUserData(Keys.PARAMETER_DEFINITION); + ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName()); MethodDefinition methodDef = (MethodDefinition)def.getMethod(); BehaviorEntry behaviorEntry; - if( methodDef.isConstructor() ) - { - behaviorEntry = new ConstructorEntry( classEntry, methodDef.getSignature() ); - } - else - { - behaviorEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); + if (methodDef.isConstructor()) { + behaviorEntry = new ConstructorEntry(classEntry, methodDef.getSignature()); + } else { + behaviorEntry = new MethodEntry(classEntry, methodDef.getName(), methodDef.getSignature()); } - ArgumentEntry argumentEntry = new ArgumentEntry( behaviorEntry, def.getPosition(), node.getName() ); - index.addDeclaration( node.getNameToken(), argumentEntry ); + ArgumentEntry argumentEntry = new ArgumentEntry(behaviorEntry, def.getPosition(), node.getName()); + index.addDeclaration(node.getNameToken(), argumentEntry); - return recurse( node, index ); + return recurse(node, index); } @Override - public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) - { - MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); - if( ref != null ) - { - ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); - FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); - index.addReference( node.getIdentifierToken(), fieldEntry, m_behaviorEntry ); + public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { + MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); + if (ref != null) { + ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); + FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName()); + index.addReference(node.getIdentifierToken(), fieldEntry, m_behaviorEntry); } - return recurse( node, index ); + return recurse(node, index); } @Override - public Void visitObjectCreationExpression( ObjectCreationExpression node, SourceIndex index ) - { - MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); - if( ref != null ) - { - ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); - ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, ref.getSignature() ); - if( node.getType() instanceof SimpleType ) - { + public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { + MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); + if (ref != null) { + ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); + ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, ref.getSignature()); + if (node.getType() instanceof SimpleType) { SimpleType simpleTypeNode = (SimpleType)node.getType(); - index.addReference( simpleTypeNode.getIdentifierToken(), constructorEntry, m_behaviorEntry ); + index.addReference(simpleTypeNode.getIdentifierToken(), constructorEntry, m_behaviorEntry); } } - return recurse( node, index ); + return recurse(node, index); } } diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index 24c48227..7b902a9d 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -31,95 +31,84 @@ import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.FieldEntry; -public class SourceIndexClassVisitor extends SourceIndexVisitor -{ +public class SourceIndexClassVisitor extends SourceIndexVisitor { + private ClassEntry m_classEntry; - public SourceIndexClassVisitor( ClassEntry classEntry ) - { + public SourceIndexClassVisitor(ClassEntry classEntry) { m_classEntry = classEntry; } @Override - public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) - { + public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { // is this this class, or a subtype? - TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getInternalName() ); - if( !classEntry.equals( m_classEntry ) ) - { + TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); + ClassEntry classEntry = new ClassEntry(def.getInternalName()); + if (!classEntry.equals(m_classEntry)) { // it's a sub-type, recurse - index.addDeclaration( node.getNameToken(), classEntry ); - return node.acceptVisitor( new SourceIndexClassVisitor( classEntry ), index ); + index.addDeclaration(node.getNameToken(), classEntry); + return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); } - return recurse( node, index ); + return recurse(node, index); } @Override - public Void visitSimpleType( SimpleType node, SourceIndex index ) - { - TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); - if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) - { - ClassEntry classEntry = new ClassEntry( ref.getInternalName() ); - index.addReference( node.getIdentifierToken(), classEntry, m_classEntry ); + public Void visitSimpleType(SimpleType node, SourceIndex index) { + TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); + if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { + ClassEntry classEntry = new ClassEntry(ref.getInternalName()); + index.addReference(node.getIdentifierToken(), classEntry, m_classEntry); } - return recurse( node, index ); + return recurse(node, index); } @Override - public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) - { - MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( classEntry, def.getName(), def.getSignature() ); + public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { + MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); + ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName()); + BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(classEntry, def.getName(), def.getSignature()); AstNode tokenNode = node.getNameToken(); - if( behaviorEntry instanceof ConstructorEntry ) - { + if (behaviorEntry instanceof ConstructorEntry) { ConstructorEntry constructorEntry = (ConstructorEntry)behaviorEntry; - if( constructorEntry.isStatic() ) - { + if (constructorEntry.isStatic()) { tokenNode = node.getModifiers().firstOrNullObject(); } } - index.addDeclaration( tokenNode, behaviorEntry ); - return node.acceptVisitor( new SourceIndexBehaviorVisitor( behaviorEntry ), index ); + index.addDeclaration(tokenNode, behaviorEntry); + return node.acceptVisitor(new SourceIndexBehaviorVisitor(behaviorEntry), index); } @Override - public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) - { - MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, def.getSignature() ); - index.addDeclaration( node.getNameToken(), constructorEntry ); - return node.acceptVisitor( new SourceIndexBehaviorVisitor( constructorEntry ), index ); + public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { + MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); + ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName()); + ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, def.getSignature()); + index.addDeclaration(node.getNameToken(), constructorEntry); + return node.acceptVisitor(new SourceIndexBehaviorVisitor(constructorEntry), index); } @Override - public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) - { - FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); - assert( node.getVariables().size() == 1 ); + public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) { + FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); + ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName()); + FieldEntry fieldEntry = new FieldEntry(classEntry, def.getName()); + assert (node.getVariables().size() == 1); VariableInitializer variable = node.getVariables().firstOrNullObject(); - index.addDeclaration( variable.getNameToken(), fieldEntry ); + index.addDeclaration(variable.getNameToken(), fieldEntry); - return recurse( node, index ); + return recurse(node, index); } @Override - public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) - { + public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) { // treat enum declarations as field declarations - FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); - index.addDeclaration( node.getNameToken(), fieldEntry ); + FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); + ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName()); + FieldEntry fieldEntry = new FieldEntry(classEntry, def.getName()); + index.addDeclaration(node.getNameToken(), fieldEntry); - return recurse( node, index ); + return recurse(node, index); } } diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java index 4e98989e..0d5bdc02 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java @@ -87,438 +87,366 @@ import com.strobel.decompiler.patterns.Pattern; import cuchaz.enigma.mapping.ClassEntry; -public class SourceIndexVisitor implements IAstVisitor -{ - @Override - public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) - { - TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getInternalName() ); - index.addDeclaration( node.getNameToken(), classEntry ); +public class SourceIndexVisitor implements IAstVisitor { + + @Override + public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { + TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); + ClassEntry classEntry = new ClassEntry(def.getInternalName()); + index.addDeclaration(node.getNameToken(), classEntry); - return node.acceptVisitor( new SourceIndexClassVisitor( classEntry ), index ); + return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); } - protected Void recurse( AstNode node, SourceIndex index ) - { - for( final AstNode child : node.getChildren() ) - { - child.acceptVisitor( this, index ); + protected Void recurse(AstNode node, SourceIndex index) { + for (final AstNode child : node.getChildren()) { + child.acceptVisitor(this, index); } return null; } @Override - public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitSimpleType( SimpleType node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitSimpleType(SimpleType node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitComment( Comment node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitComment(Comment node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitPatternPlaceholder( AstNode node, Pattern pattern, SourceIndex index ) - { - return recurse( node, index ); + public Void visitPatternPlaceholder(AstNode node, Pattern pattern, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitTypeReference( TypeReferenceExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitTypeReference(TypeReferenceExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitJavaTokenNode( JavaTokenNode node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitJavaTokenNode(JavaTokenNode node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitIdentifier( Identifier node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitIdentifier(Identifier node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitNullReferenceExpression( NullReferenceExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitNullReferenceExpression(NullReferenceExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitThisReferenceExpression( ThisReferenceExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitThisReferenceExpression(ThisReferenceExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitSuperReferenceExpression( SuperReferenceExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitSuperReferenceExpression(SuperReferenceExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitClassOfExpression( ClassOfExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitClassOfExpression(ClassOfExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitBlockStatement( BlockStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitBlockStatement(BlockStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitExpressionStatement( ExpressionStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitExpressionStatement(ExpressionStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitBreakStatement( BreakStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitBreakStatement(BreakStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitContinueStatement( ContinueStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitContinueStatement(ContinueStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitDoWhileStatement( DoWhileStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitDoWhileStatement(DoWhileStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitEmptyStatement( EmptyStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitEmptyStatement(EmptyStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitIfElseStatement( IfElseStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitIfElseStatement(IfElseStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitLabelStatement( LabelStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitLabelStatement(LabelStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitLabeledStatement( LabeledStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitLabeledStatement(LabeledStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitReturnStatement( ReturnStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitReturnStatement(ReturnStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitSwitchStatement( SwitchStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitSwitchStatement(SwitchStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitSwitchSection( SwitchSection node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitSwitchSection(SwitchSection node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitCaseLabel( CaseLabel node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitCaseLabel(CaseLabel node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitThrowStatement( ThrowStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitThrowStatement(ThrowStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitCatchClause( CatchClause node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitCatchClause(CatchClause node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitAnnotation( Annotation node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitAnnotation(Annotation node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitNewLine( NewLineNode node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitNewLine(NewLineNode node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitVariableDeclaration( VariableDeclarationStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitVariableDeclaration(VariableDeclarationStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitVariableInitializer( VariableInitializer node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitVariableInitializer(VariableInitializer node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitText( TextNode node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitText(TextNode node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitImportDeclaration( ImportDeclaration node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitImportDeclaration(ImportDeclaration node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitInitializerBlock( InstanceInitializer node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitInitializerBlock(InstanceInitializer node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitCompilationUnit( CompilationUnit node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitCompilationUnit(CompilationUnit node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitPackageDeclaration( PackageDeclaration node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitPackageDeclaration(PackageDeclaration node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitArraySpecifier( ArraySpecifier node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitArraySpecifier(ArraySpecifier node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitComposedType( ComposedType node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitComposedType(ComposedType node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitWhileStatement( WhileStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitWhileStatement(WhileStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitPrimitiveExpression( PrimitiveExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitPrimitiveExpression(PrimitiveExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitCastExpression( CastExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitCastExpression(CastExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitBinaryOperatorExpression( BinaryOperatorExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitInstanceOfExpression( InstanceOfExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitInstanceOfExpression(InstanceOfExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitIndexerExpression( IndexerExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitIndexerExpression(IndexerExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitConditionalExpression( ConditionalExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitConditionalExpression(ConditionalExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitArrayInitializerExpression( ArrayInitializerExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitArrayInitializerExpression(ArrayInitializerExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitObjectCreationExpression( ObjectCreationExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitArrayCreationExpression( ArrayCreationExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitArrayCreationExpression(ArrayCreationExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitAssignmentExpression( AssignmentExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitAssignmentExpression(AssignmentExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitForStatement( ForStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitForStatement(ForStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitForEachStatement( ForEachStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitForEachStatement(ForEachStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitTryCatchStatement( TryCatchStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitTryCatchStatement(TryCatchStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitGotoStatement( GotoStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitGotoStatement(GotoStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitParenthesizedExpression( ParenthesizedExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitParenthesizedExpression(ParenthesizedExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitSynchronizedStatement( SynchronizedStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitSynchronizedStatement(SynchronizedStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitAnonymousObjectCreationExpression( AnonymousObjectCreationExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitWildcardType( WildcardType node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitWildcardType(WildcardType node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitMethodGroupExpression( MethodGroupExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitMethodGroupExpression(MethodGroupExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitAssertStatement( AssertStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitAssertStatement(AssertStatement node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitLambdaExpression( LambdaExpression node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitLambdaExpression(LambdaExpression node, SourceIndex index) { + return recurse(node, index); } @Override - public Void visitLocalTypeDeclarationStatement( LocalTypeDeclarationStatement node, SourceIndex index ) - { - return recurse( node, index ); + public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, SourceIndex index) { + return recurse(node, index); } } diff --git a/src/cuchaz/enigma/analysis/Token.java b/src/cuchaz/enigma/analysis/Token.java index 5e70db71..481d2f47 100644 --- a/src/cuchaz/enigma/analysis/Token.java +++ b/src/cuchaz/enigma/analysis/Token.java @@ -10,56 +10,47 @@ ******************************************************************************/ package cuchaz.enigma.analysis; -public class Token implements Comparable -{ +public class Token implements Comparable { + public int start; public int end; public String text; - public Token( int start, int end ) - { - this( start, end, null ); + public Token(int start, int end) { + this(start, end, null); } - public Token( int start, int end, String source ) - { + public Token(int start, int end, String source) { this.start = start; this.end = end; - if( source != null ) - { - this.text = source.substring( start, end ); + if (source != null) { + this.text = source.substring(start, end); } } - public boolean contains( int pos ) - { + public boolean contains(int pos) { return pos >= start && pos <= end; } - + @Override - public int compareTo( Token other ) - { + public int compareTo(Token other) { return start - other.start; } @Override - public boolean equals( Object other ) - { - if( other instanceof Token ) - { - return equals( (Token)other ); + public boolean equals(Object other) { + if (other instanceof Token) { + return equals((Token)other); } return false; } - public boolean equals( Token other ) - { + public boolean equals(Token other) { return start == other.start && end == other.end; } @Override - public String toString( ) - { - return String.format( "[%d,%d]", start, end ); + public String toString() { + return String.format("[%d,%d]", start, end); } } diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java index 5311ec70..c14fd593 100644 --- a/src/cuchaz/enigma/analysis/TranslationIndex.java +++ b/src/cuchaz/enigma/analysis/TranslationIndex.java @@ -23,104 +23,85 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; -public class TranslationIndex implements Serializable -{ +public class TranslationIndex implements Serializable { + private static final long serialVersionUID = 738687982126844179L; private Map m_superclasses; private Multimap m_fields; - public TranslationIndex( ) - { + public TranslationIndex() { m_superclasses = Maps.newHashMap(); m_fields = HashMultimap.create(); } - public TranslationIndex( TranslationIndex other ) - { - m_superclasses = Maps.newHashMap( other.m_superclasses ); - m_fields = HashMultimap.create( other.m_fields ); + public TranslationIndex(TranslationIndex other) { + m_superclasses = Maps.newHashMap(other.m_superclasses); + m_fields = HashMultimap.create(other.m_fields); } - public void addSuperclass( String className, String superclassName ) - { - className = Descriptor.toJvmName( className ); - superclassName = Descriptor.toJvmName( superclassName ); + public void addSuperclass(String className, String superclassName) { + className = Descriptor.toJvmName(className); + superclassName = Descriptor.toJvmName(superclassName); - if( className.equals( superclassName ) ) - { - throw new IllegalArgumentException( "Class cannot be its own superclass! " + className ); + if (className.equals(superclassName)) { + throw new IllegalArgumentException("Class cannot be its own superclass! " + className); } - if( !isJre( className ) && !isJre( superclassName ) ) - { - m_superclasses.put( className, superclassName ); + if (!isJre(className) && !isJre(superclassName)) { + m_superclasses.put(className, superclassName); } } - public void addField( String className, String fieldName ) - { - m_fields.put( className, fieldName ); + public void addField(String className, String fieldName) { + m_fields.put(className, fieldName); } - public void renameClasses( Map renames ) - { - EntryRenamer.renameClassesInMap( renames, m_superclasses ); - EntryRenamer.renameClassesInMultimap( renames, m_fields ); + public void renameClasses(Map renames) { + EntryRenamer.renameClassesInMap(renames, m_superclasses); + EntryRenamer.renameClassesInMultimap(renames, m_fields); } - public String getSuperclassName( String className ) - { - return m_superclasses.get( className ); + public String getSuperclassName(String className) { + return m_superclasses.get(className); } - public List getAncestry( String className ) - { + public List getAncestry(String className) { List ancestors = new ArrayList(); - while( className != null ) - { - className = getSuperclassName( className ); - if( className != null ) - { - ancestors.add( className ); + while (className != null) { + className = getSuperclassName(className); + if (className != null) { + ancestors.add(className); } } return ancestors; } - public List getSubclassNames( String className ) - { + public List getSubclassNames(String className) { // linear search is fast enough for now List subclasses = Lists.newArrayList(); - for( Map.Entry entry : m_superclasses.entrySet() ) - { + for (Map.Entry entry : m_superclasses.entrySet()) { String subclass = entry.getKey(); String superclass = entry.getValue(); - if( className.equals( superclass ) ) - { - subclasses.add( subclass ); + if (className.equals(superclass)) { + subclasses.add(subclass); } } return subclasses; } - public void getSubclassNamesRecursively( Set out, String className ) - { - for( String subclassName : getSubclassNames( className ) ) - { - out.add( subclassName ); - getSubclassNamesRecursively( out, subclassName ); + public void getSubclassNamesRecursively(Set out, String className) { + for (String subclassName : getSubclassNames(className)) { + out.add(subclassName); + getSubclassNamesRecursively(out, subclassName); } } - public boolean containsField( String className, String fieldName ) - { - return m_fields.containsEntry( className, fieldName ); + public boolean containsField(String className, String fieldName) { + return m_fields.containsEntry(className, fieldName); } - private boolean isJre( String className ) - { - return className.startsWith( "java/" ) - || className.startsWith( "javax/" ); + private boolean isJre(String className) { + return className.startsWith("java/") || className.startsWith("javax/"); } } diff --git a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java index e6ecb10e..23f80899 100644 --- a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java +++ b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java @@ -90,92 +90,73 @@ import com.strobel.decompiler.languages.java.ast.WhileStatement; import com.strobel.decompiler.languages.java.ast.WildcardType; import com.strobel.decompiler.patterns.Pattern; -public class TreeDumpVisitor implements IAstVisitor -{ +public class TreeDumpVisitor implements IAstVisitor { + private File m_file; private Writer m_out; - public TreeDumpVisitor( File file ) - { + public TreeDumpVisitor(File file) { m_file = file; m_out = null; } @Override - public Void visitCompilationUnit( CompilationUnit node, Void ignored ) - { - try - { - m_out = new FileWriter( m_file ); - recurse( node, ignored ); + public Void visitCompilationUnit(CompilationUnit node, Void ignored) { + try { + m_out = new FileWriter(m_file); + recurse(node, ignored); m_out.close(); return null; - } - catch( IOException ex ) - { - throw new Error( ex ); + } catch (IOException ex) { + throw new Error(ex); } } - - private Void recurse( AstNode node, Void ignored ) - { + + private Void recurse(AstNode node, Void ignored) { // show the tree - try - { - m_out.write( getIndent( node ) + node.getClass().getSimpleName() + " " + getText( node ) + " " + dumpUserData( node ) + " " + node.getRegion() + "\n" ); - } - catch( IOException ex ) - { - throw new Error( ex ); + try { + m_out.write(getIndent(node) + node.getClass().getSimpleName() + " " + getText(node) + " " + dumpUserData(node) + " " + node.getRegion() + "\n"); + } catch (IOException ex) { + throw new Error(ex); } // recurse - for( final AstNode child : node.getChildren() ) - { - child.acceptVisitor( this, ignored ); + for (final AstNode child : node.getChildren()) { + child.acceptVisitor(this, ignored); } return null; } - private String getText( AstNode node ) - { - if( node instanceof Identifier ) - { + private String getText(AstNode node) { + if (node instanceof Identifier) { return "\"" + ((Identifier)node).getName() + "\""; } return ""; } - private String dumpUserData( AstNode node ) - { + private String dumpUserData(AstNode node) { StringBuilder buf = new StringBuilder(); - for( Key key : Keys.ALL_KEYS ) - { - Object val = node.getUserData( key ); - if( val != null ) - { - buf.append( String.format( " [%s=%s]", key, val ) ); + for (Key key : Keys.ALL_KEYS) { + Object val = node.getUserData(key); + if (val != null) { + buf.append(String.format(" [%s=%s]", key, val)); } } return buf.toString(); } - private String getIndent( AstNode node ) - { + private String getIndent(AstNode node) { StringBuilder buf = new StringBuilder(); - int depth = getDepth( node ); - for( int i = 0; i < depth; i++ ) - { - buf.append( "\t" ); + int depth = getDepth(node); + for (int i = 0; i < depth; i++) { + buf.append("\t"); } return buf.toString(); } - private int getDepth( AstNode node ) - { + private int getDepth(AstNode node) { int depth = -1; - while( node != null ) - { + while (node != null) { depth++; node = node.getParent(); } @@ -185,416 +166,347 @@ public class TreeDumpVisitor implements IAstVisitor // OVERRIDES WE DON'T CARE ABOUT @Override - public Void visitInvocationExpression( InvocationExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitInvocationExpression(InvocationExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitMemberReferenceExpression( MemberReferenceExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitMemberReferenceExpression(MemberReferenceExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitSimpleType( SimpleType node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitSimpleType(SimpleType node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitMethodDeclaration( MethodDeclaration node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitMethodDeclaration(MethodDeclaration node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitConstructorDeclaration( ConstructorDeclaration node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitConstructorDeclaration(ConstructorDeclaration node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitParameterDeclaration( ParameterDeclaration node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitParameterDeclaration(ParameterDeclaration node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitFieldDeclaration( FieldDeclaration node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitFieldDeclaration(FieldDeclaration node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitTypeDeclaration( TypeDeclaration node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitTypeDeclaration(TypeDeclaration node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitComment( Comment node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitComment(Comment node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitPatternPlaceholder( AstNode node, Pattern pattern, Void ignored ) - { - return recurse( node, ignored ); + public Void visitPatternPlaceholder(AstNode node, Pattern pattern, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitTypeReference( TypeReferenceExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitTypeReference(TypeReferenceExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitJavaTokenNode( JavaTokenNode node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitJavaTokenNode(JavaTokenNode node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitIdentifier( Identifier node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitIdentifier(Identifier node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitNullReferenceExpression( NullReferenceExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitNullReferenceExpression(NullReferenceExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitThisReferenceExpression( ThisReferenceExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitThisReferenceExpression(ThisReferenceExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitSuperReferenceExpression( SuperReferenceExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitSuperReferenceExpression(SuperReferenceExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitClassOfExpression( ClassOfExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitClassOfExpression(ClassOfExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitBlockStatement( BlockStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitBlockStatement(BlockStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitExpressionStatement( ExpressionStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitExpressionStatement(ExpressionStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitBreakStatement( BreakStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitBreakStatement(BreakStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitContinueStatement( ContinueStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitContinueStatement(ContinueStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitDoWhileStatement( DoWhileStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitDoWhileStatement(DoWhileStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitEmptyStatement( EmptyStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitEmptyStatement(EmptyStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitIfElseStatement( IfElseStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitIfElseStatement(IfElseStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitLabelStatement( LabelStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitLabelStatement(LabelStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitLabeledStatement( LabeledStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitLabeledStatement(LabeledStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitReturnStatement( ReturnStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitReturnStatement(ReturnStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitSwitchStatement( SwitchStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitSwitchStatement(SwitchStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitSwitchSection( SwitchSection node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitSwitchSection(SwitchSection node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitCaseLabel( CaseLabel node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitCaseLabel(CaseLabel node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitThrowStatement( ThrowStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitThrowStatement(ThrowStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitCatchClause( CatchClause node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitCatchClause(CatchClause node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitAnnotation( Annotation node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitAnnotation(Annotation node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitNewLine( NewLineNode node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitNewLine(NewLineNode node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitVariableDeclaration( VariableDeclarationStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitVariableDeclaration(VariableDeclarationStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitVariableInitializer( VariableInitializer node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitVariableInitializer(VariableInitializer node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitText( TextNode node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitText(TextNode node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitImportDeclaration( ImportDeclaration node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitImportDeclaration(ImportDeclaration node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitInitializerBlock( InstanceInitializer node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitInitializerBlock(InstanceInitializer node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitPackageDeclaration( PackageDeclaration node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitPackageDeclaration(PackageDeclaration node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitArraySpecifier( ArraySpecifier node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitArraySpecifier(ArraySpecifier node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitComposedType( ComposedType node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitComposedType(ComposedType node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitWhileStatement( WhileStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitWhileStatement(WhileStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitPrimitiveExpression( PrimitiveExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitPrimitiveExpression(PrimitiveExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitCastExpression( CastExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitCastExpression(CastExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitBinaryOperatorExpression( BinaryOperatorExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitInstanceOfExpression( InstanceOfExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitInstanceOfExpression(InstanceOfExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitIndexerExpression( IndexerExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitIndexerExpression(IndexerExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitIdentifierExpression( IdentifierExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitIdentifierExpression(IdentifierExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitConditionalExpression( ConditionalExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitConditionalExpression(ConditionalExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitArrayInitializerExpression( ArrayInitializerExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitArrayInitializerExpression(ArrayInitializerExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitObjectCreationExpression( ObjectCreationExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitObjectCreationExpression(ObjectCreationExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitArrayCreationExpression( ArrayCreationExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitArrayCreationExpression(ArrayCreationExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitAssignmentExpression( AssignmentExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitAssignmentExpression(AssignmentExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitForStatement( ForStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitForStatement(ForStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitForEachStatement( ForEachStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitForEachStatement(ForEachStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitTryCatchStatement( TryCatchStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitTryCatchStatement(TryCatchStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitGotoStatement( GotoStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitGotoStatement(GotoStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitParenthesizedExpression( ParenthesizedExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitParenthesizedExpression(ParenthesizedExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitSynchronizedStatement( SynchronizedStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitSynchronizedStatement(SynchronizedStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitAnonymousObjectCreationExpression( AnonymousObjectCreationExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitWildcardType( WildcardType node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitWildcardType(WildcardType node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitMethodGroupExpression( MethodGroupExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitMethodGroupExpression(MethodGroupExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitEnumValueDeclaration( EnumValueDeclaration node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitEnumValueDeclaration(EnumValueDeclaration node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitAssertStatement( AssertStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitAssertStatement(AssertStatement node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitLambdaExpression( LambdaExpression node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitLambdaExpression(LambdaExpression node, Void ignored) { + return recurse(node, ignored); } @Override - public Void visitLocalTypeDeclarationStatement( LocalTypeDeclarationStatement node, Void ignored ) - { - return recurse( node, ignored ); + public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, Void ignored) { + return recurse(node, ignored); } } diff --git a/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java index aadbeb25..fc2bac3d 100644 --- a/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java +++ b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java @@ -18,67 +18,53 @@ import javassist.bytecode.CodeAttribute; import javassist.bytecode.CodeIterator; import javassist.bytecode.Opcode; -public class BytecodeIndexIterator implements Iterator -{ - public static class Index - { +public class BytecodeIndexIterator implements Iterator { + + public static class Index { + private CodeIterator m_iter; private int m_pos; private boolean m_isWide; - protected Index( CodeIterator iter, int pos, boolean isWide ) - { + protected Index(CodeIterator iter, int pos, boolean isWide) { m_iter = iter; m_pos = pos; m_isWide = isWide; } - public int getIndex( ) - { - if( m_isWide ) - { - return m_iter.s16bitAt( m_pos ); - } - else - { - return m_iter.byteAt( m_pos ); + public int getIndex() { + if (m_isWide) { + return m_iter.s16bitAt(m_pos); + } else { + return m_iter.byteAt(m_pos); } } - public void setIndex( int val ) - throws BadBytecode - { - if( m_isWide ) - { - m_iter.write16bit( val, m_pos ); - } - else - { - if( val < 256 ) - { + public void setIndex(int val) throws BadBytecode { + if (m_isWide) { + m_iter.write16bit(val, m_pos); + } else { + if (val < 256) { // we can write the byte - m_iter.writeByte( val, m_pos ); - } - else - { + m_iter.writeByte(val, m_pos); + } else { // we need to upgrade this instruction to LDC_W - assert( m_iter.byteAt( m_pos - 1 ) == Opcode.LDC ); - m_iter.insertGap( m_pos - 1, 1 ); - m_iter.writeByte( Opcode.LDC_W, m_pos - 1 ); - m_iter.write16bit( val, m_pos ); + assert (m_iter.byteAt(m_pos - 1) == Opcode.LDC); + m_iter.insertGap(m_pos - 1, 1); + m_iter.writeByte(Opcode.LDC_W, m_pos - 1); + m_iter.write16bit(val, m_pos); m_isWide = true; // move the iterator to the next opcode - m_iter.move( m_pos + 2 ); + m_iter.move(m_pos + 2); } } // sanity check - assert( val == getIndex() ); + assert (val == getIndex()); } - public boolean isValid( Bytecode bytecode ) - { + public boolean isValid(Bytecode bytecode) { return getIndex() >= 0 && getIndex() < bytecode.getConstPool().getSize(); } } @@ -88,9 +74,7 @@ public class BytecodeIndexIterator implements Iterator indices( ) - { - return new Iterable( ) - { + public Iterable indices() { + return new Iterable() { @Override - public Iterator iterator( ) - { + public Iterator iterator() { return BytecodeIndexIterator.this; } }; } - public void saveChangesToBytecode( ) - { - BytecodeTools.setBytecode( m_bytecode, m_attribute.getCode() ); + public void saveChangesToBytecode() { + BytecodeTools.setBytecode(m_bytecode, m_attribute.getCode()); } } diff --git a/src/cuchaz/enigma/bytecode/BytecodeTools.java b/src/cuchaz/enigma/bytecode/BytecodeTools.java index 4407a904..2e456f45 100644 --- a/src/cuchaz/enigma/bytecode/BytecodeTools.java +++ b/src/cuchaz/enigma/bytecode/BytecodeTools.java @@ -34,256 +34,222 @@ import cuchaz.enigma.Util; import cuchaz.enigma.bytecode.BytecodeIndexIterator.Index; import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; -public class BytecodeTools -{ - public static byte[] writeBytecode( Bytecode bytecode ) - throws IOException - { +public class BytecodeTools { + + public static byte[] writeBytecode(Bytecode bytecode) throws IOException { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream( buf ); - try - { + DataOutputStream out = new DataOutputStream(buf); + + try { // write the constant pool - new ConstPoolEditor( bytecode.getConstPool() ).writePool( out ); + new ConstPoolEditor(bytecode.getConstPool()).writePool(out); // write metadata - out.writeShort( bytecode.getMaxStack() ); - out.writeShort( bytecode.getMaxLocals() ); - out.writeShort( bytecode.getStackDepth() ); + out.writeShort(bytecode.getMaxStack()); + out.writeShort(bytecode.getMaxLocals()); + out.writeShort(bytecode.getStackDepth()); // write the code - out.writeShort( bytecode.getSize() ); - out.write( bytecode.get() ); + out.writeShort(bytecode.getSize()); + out.write(bytecode.get()); // write the exception table int numEntries = bytecode.getExceptionTable().size(); - out.writeShort( numEntries ); - for( int i=0; i attribute.getMaxLocals() ) - { - attribute.setMaxLocals( bytecode.getMaxLocals() ); + if (bytecode.getMaxLocals() > attribute.getMaxLocals()) { + attribute.setMaxLocals(bytecode.getMaxLocals()); } - if( bytecode.getMaxStack() > attribute.getMaxStack() ) - { - attribute.setMaxStack( bytecode.getMaxStack() ); + if (bytecode.getMaxStack() > attribute.getMaxStack()) { + attribute.setMaxStack(bytecode.getMaxStack()); } return bytecode; } - public static Bytecode copyBytecodeToConstPool( ConstPool dest, Bytecode bytecode ) - throws BadBytecode - { + public static Bytecode copyBytecodeToConstPool(ConstPool dest, Bytecode bytecode) throws BadBytecode { + // get the entries this bytecode needs from the const pool Set indices = Sets.newTreeSet(); - ConstPoolEditor editor = new ConstPoolEditor( bytecode.getConstPool() ); - BytecodeIndexIterator iterator = new BytecodeIndexIterator( bytecode ); - for( Index index : iterator.indices() ) - { - assert( index.isValid( bytecode ) ); - InfoType.gatherIndexTree( indices, editor, index.getIndex() ); + ConstPoolEditor editor = new ConstPoolEditor(bytecode.getConstPool()); + BytecodeIndexIterator iterator = new BytecodeIndexIterator(bytecode); + for (Index index : iterator.indices()) { + assert (index.isValid(bytecode)); + InfoType.gatherIndexTree(indices, editor, index.getIndex()); } Map indexMap = Maps.newTreeMap(); ConstPool src = bytecode.getConstPool(); - ConstPoolEditor editorSrc = new ConstPoolEditor( src ); - ConstPoolEditor editorDest = new ConstPoolEditor( dest ); + ConstPoolEditor editorSrc = new ConstPoolEditor(src); + ConstPoolEditor editorDest = new ConstPoolEditor(dest); // copy entries over in order of level so the index mapping is easier - for( InfoType type : InfoType.getSortedByLevel() ) - { - for( int index : indices ) - { - ConstInfoAccessor entry = editorSrc.getItem( index ); + for (InfoType type : InfoType.getSortedByLevel()) { + for (int index : indices) { + ConstInfoAccessor entry = editorSrc.getItem(index); // skip entries that aren't this type - if( entry.getType() != type ) - { + if (entry.getType() != type) { continue; } // make sure the source entry is valid before we copy it - assert( type.subIndicesAreValid( entry, editorSrc ) ); - assert( type.selfIndexIsValid( entry, editorSrc ) ); + assert (type.subIndicesAreValid(entry, editorSrc)); + assert (type.selfIndexIsValid(entry, editorSrc)); // make a copy of the entry so we can modify it safely - ConstInfoAccessor entryCopy = editorSrc.getItem( index ).copy(); - assert( type.subIndicesAreValid( entryCopy, editorSrc ) ); - assert( type.selfIndexIsValid( entryCopy, editorSrc ) ); + ConstInfoAccessor entryCopy = editorSrc.getItem(index).copy(); + assert (type.subIndicesAreValid(entryCopy, editorSrc)); + assert (type.selfIndexIsValid(entryCopy, editorSrc)); // remap the indices - type.remapIndices( indexMap, entryCopy ); - assert( type.subIndicesAreValid( entryCopy, editorDest ) ); + type.remapIndices(indexMap, entryCopy); + assert (type.subIndicesAreValid(entryCopy, editorDest)); // put the copy in the destination pool - int newIndex = editorDest.addItem( entryCopy.getItem() ); - entryCopy.setIndex( newIndex ); - assert( type.selfIndexIsValid( entryCopy, editorDest ) ) : type + ", self: " + entryCopy + " dest: " + editorDest.getItem( entryCopy.getIndex() ); + int newIndex = editorDest.addItem(entryCopy.getItem()); + entryCopy.setIndex(newIndex); + assert (type.selfIndexIsValid(entryCopy, editorDest)) : type + ", self: " + entryCopy + " dest: " + editorDest.getItem(entryCopy.getIndex()); // make sure the source entry is unchanged - assert( type.subIndicesAreValid( entry, editorSrc ) ); - assert( type.selfIndexIsValid( entry, editorSrc ) ); + assert (type.subIndicesAreValid(entry, editorSrc)); + assert (type.selfIndexIsValid(entry, editorSrc)); // add the index mapping so we can update the bytecode later - if( indexMap.containsKey( index ) ) - { - throw new Error( "Entry at index " + index + " already copied!" ); + if (indexMap.containsKey(index)) { + throw new Error("Entry at index " + index + " already copied!"); } - indexMap.put( index, newIndex ); + indexMap.put(index, newIndex); } } // make a new bytecode - Bytecode newBytecode = new Bytecode( dest, bytecode.getMaxStack(), bytecode.getMaxLocals() ); - bytecode.setStackDepth( bytecode.getStackDepth() ); - setBytecode( newBytecode, bytecode.get() ); - setExceptionTable( newBytecode, bytecode.getExceptionTable() ); + Bytecode newBytecode = new Bytecode(dest, bytecode.getMaxStack(), bytecode.getMaxLocals()); + bytecode.setStackDepth(bytecode.getStackDepth()); + setBytecode(newBytecode, bytecode.get()); + setExceptionTable(newBytecode, bytecode.getExceptionTable()); // apply the mappings to the bytecode - BytecodeIndexIterator iter = new BytecodeIndexIterator( newBytecode ); - for( Index index : iter.indices() ) - { + BytecodeIndexIterator iter = new BytecodeIndexIterator(newBytecode); + for (Index index : iter.indices()) { int oldIndex = index.getIndex(); - Integer newIndex = indexMap.get( oldIndex ); - if( newIndex != null ) - { + Integer newIndex = indexMap.get(oldIndex); + if (newIndex != null) { // make sure this mapping makes sense - InfoType typeSrc = editorSrc.getItem( oldIndex ).getType(); - InfoType typeDest = editorDest.getItem( newIndex ).getType(); - assert( typeSrc == typeDest ); + InfoType typeSrc = editorSrc.getItem(oldIndex).getType(); + InfoType typeDest = editorDest.getItem(newIndex).getType(); + assert (typeSrc == typeDest); // apply the mapping - index.setIndex( newIndex ); + index.setIndex(newIndex); } } iter.saveChangesToBytecode(); // make sure all the indices are valid - iter = new BytecodeIndexIterator( newBytecode ); - for( Index index : iter.indices() ) - { - assert( index.isValid( newBytecode ) ); + iter = new BytecodeIndexIterator(newBytecode); + for (Index index : iter.indices()) { + assert (index.isValid(newBytecode)); } return newBytecode; } - public static void setBytecode( Bytecode dest, byte[] src ) - { - if( src.length > dest.getSize() ) - { - dest.addGap( src.length - dest.getSize() ); + public static void setBytecode(Bytecode dest, byte[] src) { + if (src.length > dest.getSize()) { + dest.addGap(src.length - dest.getSize()); } - assert( dest.getSize() == src.length ); - for( int i=0; i=0; i-- ) - { - dest.getExceptionTable().remove( i ); + for (int i = size - 1; i >= 0; i--) { + dest.getExceptionTable().remove(i); } // copy the exception table - for( int i=0; i getParameterTypes( String signature ) - { + public static List getParameterTypes(String signature) { List types = Lists.newArrayList(); - for( int i=0; i 0 ) - { + while (arrayDim-- > 0) { type = "[" + type; } - types.add( type ); + types.add(type); } return types; } diff --git a/src/cuchaz/enigma/bytecode/CheckCastIterator.java b/src/cuchaz/enigma/bytecode/CheckCastIterator.java index 7ed5d7fb..b6efbd49 100644 --- a/src/cuchaz/enigma/bytecode/CheckCastIterator.java +++ b/src/cuchaz/enigma/bytecode/CheckCastIterator.java @@ -22,15 +22,14 @@ import cuchaz.enigma.bytecode.CheckCastIterator.CheckCast; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.MethodEntry; -public class CheckCastIterator implements Iterator -{ - public static class CheckCast - { +public class CheckCastIterator implements Iterator { + + public static class CheckCast { + public String className; public MethodEntry prevMethodEntry; - public CheckCast( String className, MethodEntry prevMethodEntry ) - { + public CheckCast(String className, MethodEntry prevMethodEntry) { this.className = className; this.prevMethodEntry = prevMethodEntry; } @@ -41,9 +40,7 @@ public class CheckCastIterator implements Iterator private CodeIterator m_iter; private CheckCast m_next; - public CheckCastIterator( CodeAttribute codeAttribute ) - throws BadBytecode - { + public CheckCastIterator(CodeAttribute codeAttribute) throws BadBytecode { m_constants = codeAttribute.getConstPool(); m_attribute = codeAttribute; m_iter = m_attribute.iterator(); @@ -52,52 +49,38 @@ public class CheckCastIterator implements Iterator } @Override - public boolean hasNext( ) - { + public boolean hasNext() { return m_next != null; } - + @Override - public CheckCast next( ) - { + public CheckCast next() { CheckCast out = m_next; - try - { + try { m_next = getNext(); - } - catch( BadBytecode ex ) - { - throw new Error( ex ); + } catch (BadBytecode ex) { + throw new Error(ex); } return out; } - + @Override - public void remove( ) - { + public void remove() { throw new UnsupportedOperationException(); } - private CheckCast getNext( ) - throws BadBytecode - { + private CheckCast getNext() throws BadBytecode { int prevPos = 0; - while( m_iter.hasNext() ) - { + while (m_iter.hasNext()) { int pos = m_iter.next(); - int opcode = m_iter.byteAt( pos ); - switch( opcode ) - { + int opcode = m_iter.byteAt(pos); + switch (opcode) { case Opcode.CHECKCAST: // get the type of this op code (next two bytes are a classinfo index) - MethodEntry prevMethodEntry = getMethodEntry( prevPos ); - if( prevMethodEntry != null ) - { - return new CheckCast( - m_constants.getClassInfo( m_iter.s16bitAt( pos + 1 ) ), - prevMethodEntry - ); + MethodEntry prevMethodEntry = getMethodEntry(prevPos); + if (prevMethodEntry != null) { + return new CheckCast(m_constants.getClassInfo(m_iter.s16bitAt(pos + 1)), prevMethodEntry); } break; } @@ -106,43 +89,36 @@ public class CheckCastIterator implements Iterator return null; } - private MethodEntry getMethodEntry( int pos ) - { - switch( m_iter.byteAt( pos ) ) - { + private MethodEntry getMethodEntry(int pos) { + switch (m_iter.byteAt(pos)) { case Opcode.INVOKEVIRTUAL: case Opcode.INVOKESTATIC: case Opcode.INVOKEDYNAMIC: - case Opcode.INVOKESPECIAL: - { - int index = m_iter.s16bitAt( pos + 1 ); + case Opcode.INVOKESPECIAL: { + int index = m_iter.s16bitAt(pos + 1); return new MethodEntry( - new ClassEntry( Descriptor.toJvmName( m_constants.getMethodrefClassName( index ) ) ), - m_constants.getMethodrefName( index ), - m_constants.getMethodrefType( index ) + new ClassEntry(Descriptor.toJvmName(m_constants.getMethodrefClassName(index))), + m_constants.getMethodrefName(index), + m_constants.getMethodrefType(index) ); } - case Opcode.INVOKEINTERFACE: - { - int index = m_iter.s16bitAt( pos + 1 ); + case Opcode.INVOKEINTERFACE: { + int index = m_iter.s16bitAt(pos + 1); return new MethodEntry( - new ClassEntry( Descriptor.toJvmName( m_constants.getInterfaceMethodrefClassName( index ) ) ), - m_constants.getInterfaceMethodrefName( index ), - m_constants.getInterfaceMethodrefType( index ) + new ClassEntry(Descriptor.toJvmName(m_constants.getInterfaceMethodrefClassName(index))), + m_constants.getInterfaceMethodrefName(index), + m_constants.getInterfaceMethodrefType(index) ); } } return null; } - - public Iterable casts( ) - { - return new Iterable( ) - { + + public Iterable casts() { + return new Iterable() { @Override - public Iterator iterator( ) - { + public Iterator iterator() { return CheckCastIterator.this; } }; diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java index 849a3233..f8e63d16 100644 --- a/src/cuchaz/enigma/bytecode/ClassRenamer.java +++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java @@ -27,55 +27,43 @@ import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.SignatureUpdater; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; -public class ClassRenamer -{ - public static void renameClasses( CtClass c, Map map ) - { +public class ClassRenamer { + + public static void renameClasses(CtClass c, Map map) { + // build the map used by javassist ClassMap nameMap = new ClassMap(); - for( Map.Entry entry : map.entrySet() ) - { - nameMap.put( entry.getKey().getName(), entry.getValue().getName() ); + for (Map.Entry entry : map.entrySet()) { + nameMap.put(entry.getKey().getName(), entry.getValue().getName()); } - c.replaceClassName( nameMap ); + c.replaceClassName(nameMap); // replace simple names in the InnerClasses attribute too ConstPool constants = c.getClassFile().getConstPool(); - InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute( InnerClassesAttribute.tag ); - if( attr != null ) - { - for( int i=0; i ATTR: %s,%s,%s", - classEntry, - attr.outerClass( i ), - attr.innerClass( i ), - attr.innerName( i ) - ) ); + System.out.println(String.format("\tDEOBF: %s-> ATTR: %s,%s,%s", classEntry, attr.outerClass(i), attr.innerClass(i), attr.innerName(i))); */ } } } - public static Set getAllClassEntries( final CtClass c ) - { + public static Set getAllClassEntries(final CtClass c) { + // get the classes that javassist knows about final Set entries = Sets.newHashSet(); - ClassMap map = new ClassMap( ) - { + ClassMap map = new ClassMap() { @Override - public Object get( Object obj ) - { - if( obj instanceof String ) - { + public Object get(Object obj) { + if (obj instanceof String) { String str = (String)obj; // javassist throws a lot of weird things at this map @@ -83,69 +71,60 @@ public class ClassRenamer // I'm opting to filter out the weirdness for now // skip anything with generic arguments - if( str.indexOf( '<' ) >= 0 || str.indexOf( '>' ) >= 0 || str.indexOf( ';' ) >= 0 ) - { + if (str.indexOf('<') >= 0 || str.indexOf('>') >= 0 || str.indexOf(';') >= 0) { return null; } // convert path/to/class.inner to path/to/class$inner - str = str.replace( '.', '$' ); + str = str.replace('.', '$'); // remember everything else - entries.add( new ClassEntry( str ) ); + entries.add(new ClassEntry(str)); } return null; } + private static final long serialVersionUID = -202160293602070641L; }; - c.replaceClassName( map ); + c.replaceClassName(map); return entries; } - public static void moveAllClassesOutOfDefaultPackage( CtClass c, String newPackageName ) - { + public static void moveAllClassesOutOfDefaultPackage(CtClass c, String newPackageName) { + // rename all classes Map map = Maps.newHashMap(); - for( ClassEntry classEntry : ClassRenamer.getAllClassEntries( c ) ) - { - if( classEntry.isInDefaultPackage() ) - { - map.put( classEntry, new ClassEntry( newPackageName + "/" + classEntry.getName() ) ); + for (ClassEntry classEntry : ClassRenamer.getAllClassEntries(c)) { + if (classEntry.isInDefaultPackage()) { + map.put(classEntry, new ClassEntry(newPackageName + "/" + classEntry.getName())); } } - ClassRenamer.renameClasses( c, map ); + ClassRenamer.renameClasses(c, map); // TEMP - for( ClassEntry classEntry : ClassRenamer.getAllClassEntries( c ) ) - { - if( classEntry.isInDefaultPackage() ) - { - throw new Error( "!!! " + classEntry ); + for (ClassEntry classEntry : ClassRenamer.getAllClassEntries(c)) { + if (classEntry.isInDefaultPackage()) { + throw new Error("!!! " + classEntry); } } // TEMP - for( CtBehavior behavior : c.getDeclaredBehaviors() ) - { - if( behavior.getSignature() == null ) - { + for (CtBehavior behavior : c.getDeclaredBehaviors()) { + if (behavior.getSignature() == null) { continue; } - SignatureUpdater.update( behavior.getSignature(), new ClassNameUpdater( ) - { + SignatureUpdater.update(behavior.getSignature(), new ClassNameUpdater() { @Override - public String update( String className ) - { - ClassEntry classEntry = new ClassEntry( className ); - if( classEntry.isInDefaultPackage() ) - { - throw new Error( "!!! " + className ); + public String update(String className) { + ClassEntry classEntry = new ClassEntry(className); + if (classEntry.isInDefaultPackage()) { + throw new Error("!!! " + className); } return className; } - } ); + }); } } } diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index 181fadb1..bc12405c 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java @@ -28,116 +28,102 @@ import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.Translator; -public class ClassTranslator -{ +public class ClassTranslator { + private Translator m_translator; - public ClassTranslator( Translator translator ) - { + public ClassTranslator(Translator translator) { m_translator = translator; } - public void translate( CtClass c ) - { + public void translate(CtClass c) { // NOTE: the order of these translations is very important // translate all the field and method references in the code by editing the constant pool ConstPool constants = c.getClassFile().getConstPool(); - ConstPoolEditor editor = new ConstPoolEditor( constants ); - for( int i=1; i map = Maps.newHashMap(); - for( ClassEntry obfClassEntry : ClassRenamer.getAllClassEntries( c ) ) - { - ClassEntry deobfClassEntry = m_translator.translateEntry( obfClassEntry ); - if( !obfClassEntry.equals( deobfClassEntry ) ) - { - map.put( obfClassEntry, deobfClassEntry ); + for (ClassEntry obfClassEntry : ClassRenamer.getAllClassEntries(c)) { + ClassEntry deobfClassEntry = m_translator.translateEntry(obfClassEntry); + if (!obfClassEntry.equals(deobfClassEntry)) { + map.put(obfClassEntry, deobfClassEntry); } } - ClassRenamer.renameClasses( c, map ); + ClassRenamer.renameClasses(c, map); } } diff --git a/src/cuchaz/enigma/bytecode/ConstPoolEditor.java b/src/cuchaz/enigma/bytecode/ConstPoolEditor.java index aa6149c9..2dec3b76 100644 --- a/src/cuchaz/enigma/bytecode/ConstPoolEditor.java +++ b/src/cuchaz/enigma/bytecode/ConstPoolEditor.java @@ -23,8 +23,8 @@ import cuchaz.enigma.bytecode.accessors.ClassInfoAccessor; import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; import cuchaz.enigma.bytecode.accessors.MemberRefInfoAccessor; -public class ConstPoolEditor -{ +public class ConstPoolEditor { + private static Method m_getItem; private static Method m_addItem; private static Method m_addItem0; @@ -36,264 +36,213 @@ public class ConstPoolEditor private static Method m_methodWritePool; private static Constructor m_constructorPool; - static - { - try - { - m_getItem = ConstPool.class.getDeclaredMethod( "getItem", int.class ); - m_getItem.setAccessible( true ); + static { + try { + m_getItem = ConstPool.class.getDeclaredMethod("getItem", int.class); + m_getItem.setAccessible(true); - m_addItem = ConstPool.class.getDeclaredMethod( "addItem", Class.forName( "javassist.bytecode.ConstInfo" ) ); - m_addItem.setAccessible( true ); + m_addItem = ConstPool.class.getDeclaredMethod("addItem", Class.forName("javassist.bytecode.ConstInfo")); + m_addItem.setAccessible(true); - m_addItem0 = ConstPool.class.getDeclaredMethod( "addItem0", Class.forName( "javassist.bytecode.ConstInfo" ) ); - m_addItem0.setAccessible( true ); + m_addItem0 = ConstPool.class.getDeclaredMethod("addItem0", Class.forName("javassist.bytecode.ConstInfo")); + m_addItem0.setAccessible(true); - m_items = ConstPool.class.getDeclaredField( "items" ); - m_items.setAccessible( true ); + m_items = ConstPool.class.getDeclaredField("items"); + m_items.setAccessible(true); - m_cache = ConstPool.class.getDeclaredField( "itemsCache" ); - m_cache.setAccessible( true ); + m_cache = ConstPool.class.getDeclaredField("itemsCache"); + m_cache.setAccessible(true); - m_numItems = ConstPool.class.getDeclaredField( "numOfItems" ); - m_numItems.setAccessible( true ); + m_numItems = ConstPool.class.getDeclaredField("numOfItems"); + m_numItems.setAccessible(true); - m_objects = Class.forName( "javassist.bytecode.LongVector" ).getDeclaredField( "objects" ); - m_objects.setAccessible( true ); + m_objects = Class.forName("javassist.bytecode.LongVector").getDeclaredField("objects"); + m_objects.setAccessible(true); - m_elements = Class.forName( "javassist.bytecode.LongVector" ).getDeclaredField( "elements" ); - m_elements.setAccessible( true ); + m_elements = Class.forName("javassist.bytecode.LongVector").getDeclaredField("elements"); + m_elements.setAccessible(true); - m_methodWritePool = ConstPool.class.getDeclaredMethod( "write", DataOutputStream.class ); - m_methodWritePool.setAccessible( true ); + m_methodWritePool = ConstPool.class.getDeclaredMethod("write", DataOutputStream.class); + m_methodWritePool.setAccessible(true); - m_constructorPool = ConstPool.class.getDeclaredConstructor( DataInputStream.class ); - m_constructorPool.setAccessible( true ); - } - catch( Exception ex ) - { - throw new Error( ex ); + m_constructorPool = ConstPool.class.getDeclaredConstructor(DataInputStream.class); + m_constructorPool.setAccessible(true); + } catch (Exception ex) { + throw new Error(ex); } } private ConstPool m_pool; - public ConstPoolEditor( ConstPool pool ) - { + public ConstPoolEditor(ConstPool pool) { m_pool = pool; } - public void writePool( DataOutputStream out ) - { - try - { - m_methodWritePool.invoke( m_pool, out ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void writePool(DataOutputStream out) { + try { + m_methodWritePool.invoke(m_pool, out); + } catch (Exception ex) { + throw new Error(ex); } } - public static ConstPool readPool( DataInputStream in ) - { - try - { - return m_constructorPool.newInstance( in ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public static ConstPool readPool(DataInputStream in) { + try { + return m_constructorPool.newInstance(in); + } catch (Exception ex) { + throw new Error(ex); } } - public String getMemberrefClassname( int memberrefIndex ) - { - return Descriptor.toJvmName( m_pool.getClassInfo( m_pool.getMemberClass( memberrefIndex ) ) ); + public String getMemberrefClassname(int memberrefIndex) { + return Descriptor.toJvmName(m_pool.getClassInfo(m_pool.getMemberClass(memberrefIndex))); } - public String getMemberrefName( int memberrefIndex ) - { - return m_pool.getUtf8Info( m_pool.getNameAndTypeName( m_pool.getMemberNameAndType( memberrefIndex ) ) ); + public String getMemberrefName(int memberrefIndex) { + return m_pool.getUtf8Info(m_pool.getNameAndTypeName(m_pool.getMemberNameAndType(memberrefIndex))); } - public String getMemberrefType( int memberrefIndex ) - { - return m_pool.getUtf8Info( m_pool.getNameAndTypeDescriptor( m_pool.getMemberNameAndType( memberrefIndex ) ) ); + public String getMemberrefType(int memberrefIndex) { + return m_pool.getUtf8Info(m_pool.getNameAndTypeDescriptor(m_pool.getMemberNameAndType(memberrefIndex))); } - public ConstInfoAccessor getItem( int index ) - { - try - { - Object entry = m_getItem.invoke( m_pool, index ); - if( entry == null ) - { + public ConstInfoAccessor getItem(int index) { + try { + Object entry = m_getItem.invoke(m_pool, index); + if (entry == null) { return null; } - return new ConstInfoAccessor( entry ); - } - catch( Exception ex ) - { - throw new Error( ex ); + return new ConstInfoAccessor(entry); + } catch (Exception ex) { + throw new Error(ex); } } - public int addItem( Object item ) - { - try - { - return (Integer)m_addItem.invoke( m_pool, item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int addItem(Object item) { + try { + return (Integer)m_addItem.invoke(m_pool, item); + } catch (Exception ex) { + throw new Error(ex); } } - public int addItemForceNew( Object item ) - { - try - { - return (Integer)m_addItem0.invoke( m_pool, item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int addItemForceNew(Object item) { + try { + return (Integer)m_addItem0.invoke(m_pool, item); + } catch (Exception ex) { + throw new Error(ex); } } - @SuppressWarnings( "rawtypes" ) - public void removeLastItem( ) - { - try - { + + @SuppressWarnings("rawtypes") + public void removeLastItem() { + try { // remove the item from the cache HashMap cache = getCache(); - if( cache != null ) - { - Object item = getItem( m_pool.getSize() - 1 ); - cache.remove( item ); + if (cache != null) { + Object item = getItem(m_pool.getSize() - 1); + cache.remove(item); } // remove the actual item // based off of LongVector.addElement() - Object items = m_items.get( m_pool ); - Object[][] objects = (Object[][])m_objects.get( items ); - int numElements = (Integer)m_elements.get( items ) - 1; + Object items = m_items.get(m_pool); + Object[][] objects = (Object[][])m_objects.get(items); + int numElements = (Integer)m_elements.get(items) - 1; int nth = numElements >> 7; - int offset = numElements & (128 - 1); - objects[nth][offset] = null; + int offset = numElements & (128 - 1); + objects[nth][offset] = null; // decrement the number of items - m_elements.set( items, numElements ); - m_numItems.set( m_pool, (Integer)m_numItems.get( m_pool ) - 1 ); - } - catch( Exception ex ) - { - throw new Error( ex ); + m_elements.set(items, numElements); + m_numItems.set(m_pool, (Integer)m_numItems.get(m_pool) - 1); + } catch (Exception ex) { + throw new Error(ex); } } - @SuppressWarnings( "rawtypes" ) - /* TEMP */public HashMap getCache( ) - { - try - { - return (HashMap)m_cache.get( m_pool ); - } - catch( Exception ex ) - { - throw new Error( ex ); + @SuppressWarnings("rawtypes") + public HashMap getCache() { + try { + return (HashMap)m_cache.get(m_pool); + } catch (Exception ex) { + throw new Error(ex); } } - @SuppressWarnings( { "rawtypes", "unchecked" } ) - public void changeMemberrefNameAndType( int memberrefIndex, String newName, String newType ) - { + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void changeMemberrefNameAndType(int memberrefIndex, String newName, String newType) { // NOTE: when changing values, we always need to copy-on-write - try - { + try { // get the memberref item - Object item = getItem( memberrefIndex ).getItem(); + Object item = getItem(memberrefIndex).getItem(); // update the cache HashMap cache = getCache(); - if( cache != null ) - { - cache.remove( item ); + if (cache != null) { + cache.remove(item); } - new MemberRefInfoAccessor( item ).setNameAndTypeIndex( m_pool.addNameAndTypeInfo( newName, newType ) ); + new MemberRefInfoAccessor(item).setNameAndTypeIndex(m_pool.addNameAndTypeInfo(newName, newType)); // update the cache - if( cache != null ) - { - cache.put( item, item ); + if (cache != null) { + cache.put(item, item); } - } - catch( Exception ex ) - { - throw new Error( ex ); + } catch (Exception ex) { + throw new Error(ex); } // make sure the change worked - assert( newName.equals( getMemberrefName( memberrefIndex ) ) ); - assert( newType.equals( getMemberrefType( memberrefIndex ) ) ); + assert (newName.equals(getMemberrefName(memberrefIndex))); + assert (newType.equals(getMemberrefType(memberrefIndex))); } - @SuppressWarnings( { "rawtypes", "unchecked" } ) - public void changeClassName( int classNameIndex, String newName ) - { + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void changeClassName(int classNameIndex, String newName) { // NOTE: when changing values, we always need to copy-on-write - try - { + try { // get the class item - Object item = getItem( classNameIndex ).getItem(); + Object item = getItem(classNameIndex).getItem(); // update the cache HashMap cache = getCache(); - if( cache != null ) - { - cache.remove( item ); + if (cache != null) { + cache.remove(item); } // add the new name and repoint the name-and-type to it - new ClassInfoAccessor( item ).setNameIndex( m_pool.addUtf8Info( newName ) ); + new ClassInfoAccessor(item).setNameIndex(m_pool.addUtf8Info(newName)); // update the cache - if( cache != null ) - { - cache.put( item, item ); + if (cache != null) { + cache.put(item, item); } - } - catch( Exception ex ) - { - throw new Error( ex ); + } catch (Exception ex) { + throw new Error(ex); } } - public static ConstPool newConstPool( ) - { + public static ConstPool newConstPool() { // const pool expects the name of a class to initialize itself // but we want an empty pool // so give it a bogus name, and then clear the entries afterwards - ConstPool pool = new ConstPool( "a" ); + ConstPool pool = new ConstPool("a"); - ConstPoolEditor editor = new ConstPoolEditor( pool ); + ConstPoolEditor editor = new ConstPoolEditor(pool); int size = pool.getSize(); - for( int i=0; i indices, ConstPoolEditor editor, ConstInfoAccessor entry ) - { - ClassInfoAccessor accessor = new ClassInfoAccessor( entry.getItem() ); - gatherIndexTree( indices, editor, accessor.getNameIndex() ); + public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { + ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem()); + gatherIndexTree(indices, editor, accessor.getNameIndex()); } @Override - public void remapIndices( Map map, ConstInfoAccessor entry ) - { - ClassInfoAccessor accessor = new ClassInfoAccessor( entry.getItem() ); - accessor.setNameIndex( remapIndex( map, accessor.getNameIndex() ) ); + public void remapIndices(Map map, ConstInfoAccessor entry) { + ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem()); + accessor.setNameIndex(remapIndex(map, accessor.getNameIndex())); } @Override - public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) - { - ClassInfoAccessor accessor = new ClassInfoAccessor( entry.getItem() ); - ConstInfoAccessor nameEntry = pool.getItem( accessor.getNameIndex() ); + public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { + ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem()); + ConstInfoAccessor nameEntry = pool.getItem(accessor.getNameIndex()); return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag(); } }, - StringInfo( 8, 1 ) - { + StringInfo( 8, 1 ) { + @Override - public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) - { - StringInfoAccessor accessor = new StringInfoAccessor( entry.getItem() ); - gatherIndexTree( indices, editor, accessor.getStringIndex() ); + public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { + StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem()); + gatherIndexTree(indices, editor, accessor.getStringIndex()); } @Override - public void remapIndices( Map map, ConstInfoAccessor entry ) - { - StringInfoAccessor accessor = new StringInfoAccessor( entry.getItem() ); - accessor.setStringIndex( remapIndex( map, accessor.getStringIndex() ) ); + public void remapIndices(Map map, ConstInfoAccessor entry) { + StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem()); + accessor.setStringIndex(remapIndex(map, accessor.getStringIndex())); } @Override - public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) - { - StringInfoAccessor accessor = new StringInfoAccessor( entry.getItem() ); - ConstInfoAccessor stringEntry = pool.getItem( accessor.getStringIndex() ); + public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { + StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem()); + ConstInfoAccessor stringEntry = pool.getItem(accessor.getStringIndex()); return stringEntry != null && stringEntry.getTag() == Utf8Info.getTag(); } }, - FieldRefInfo( 9, 2 ) - { + FieldRefInfo( 9, 2 ) { + @Override - public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) - { - MemberRefInfoAccessor accessor = new MemberRefInfoAccessor( entry.getItem() ); - gatherIndexTree( indices, editor, accessor.getClassIndex() ); - gatherIndexTree( indices, editor, accessor.getNameAndTypeIndex() ); + public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { + MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem()); + gatherIndexTree(indices, editor, accessor.getClassIndex()); + gatherIndexTree(indices, editor, accessor.getNameAndTypeIndex()); } @Override - public void remapIndices( Map map, ConstInfoAccessor entry ) - { - MemberRefInfoAccessor accessor = new MemberRefInfoAccessor( entry.getItem() ); - accessor.setClassIndex( remapIndex( map, accessor.getClassIndex() ) ); - accessor.setNameAndTypeIndex( remapIndex( map, accessor.getNameAndTypeIndex() ) ); + public void remapIndices(Map map, ConstInfoAccessor entry) { + MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem()); + accessor.setClassIndex(remapIndex(map, accessor.getClassIndex())); + accessor.setNameAndTypeIndex(remapIndex(map, accessor.getNameAndTypeIndex())); } - + @Override - public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) - { - MemberRefInfoAccessor accessor = new MemberRefInfoAccessor( entry.getItem() ); - ConstInfoAccessor classEntry = pool.getItem( accessor.getClassIndex() ); - ConstInfoAccessor nameAndTypeEntry = pool.getItem( accessor.getNameAndTypeIndex() ); - return classEntry != null && classEntry.getTag() == ClassInfo.getTag() - && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag(); + public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { + MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem()); + ConstInfoAccessor classEntry = pool.getItem(accessor.getClassIndex()); + ConstInfoAccessor nameAndTypeEntry = pool.getItem(accessor.getNameAndTypeIndex()); + return classEntry != null && classEntry.getTag() == ClassInfo.getTag() && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag(); } }, - MethodRefInfo( 10, 2 ) // same as FieldRefInfo - { + // same as FieldRefInfo + MethodRefInfo( 10, 2 ) { + @Override - public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) - { - FieldRefInfo.gatherIndexTree( indices, editor, entry ); + public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { + FieldRefInfo.gatherIndexTree(indices, editor, entry); } @Override - public void remapIndices( Map map, ConstInfoAccessor entry ) - { - FieldRefInfo.remapIndices( map, entry ); + public void remapIndices(Map map, ConstInfoAccessor entry) { + FieldRefInfo.remapIndices(map, entry); } - + @Override - public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) - { - return FieldRefInfo.subIndicesAreValid( entry, pool ); + public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { + return FieldRefInfo.subIndicesAreValid(entry, pool); } }, - InterfaceMethodRefInfo( 11, 2 ) // same as FieldRefInfo - { + // same as FieldRefInfo + InterfaceMethodRefInfo( 11, 2 ) { + @Override - public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) - { - FieldRefInfo.gatherIndexTree( indices, editor, entry ); + public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { + FieldRefInfo.gatherIndexTree(indices, editor, entry); } @Override - public void remapIndices( Map map, ConstInfoAccessor entry ) - { - FieldRefInfo.remapIndices( map, entry ); + public void remapIndices(Map map, ConstInfoAccessor entry) { + FieldRefInfo.remapIndices(map, entry); } - + @Override - public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) - { - return FieldRefInfo.subIndicesAreValid( entry, pool ); + public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { + return FieldRefInfo.subIndicesAreValid(entry, pool); } }, - NameAndTypeInfo( 12, 1 ) - { + NameAndTypeInfo( 12, 1 ) { + @Override - public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) - { - NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor( entry.getItem() ); - gatherIndexTree( indices, editor, accessor.getNameIndex() ); - gatherIndexTree( indices, editor, accessor.getTypeIndex() ); + public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { + NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem()); + gatherIndexTree(indices, editor, accessor.getNameIndex()); + gatherIndexTree(indices, editor, accessor.getTypeIndex()); } @Override - public void remapIndices( Map map, ConstInfoAccessor entry ) - { - NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor( entry.getItem() ); - accessor.setNameIndex( remapIndex( map, accessor.getNameIndex() ) ); - accessor.setTypeIndex( remapIndex( map, accessor.getTypeIndex() ) ); + public void remapIndices(Map map, ConstInfoAccessor entry) { + NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem()); + accessor.setNameIndex(remapIndex(map, accessor.getNameIndex())); + accessor.setTypeIndex(remapIndex(map, accessor.getTypeIndex())); } @Override - public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) - { - NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor( entry.getItem() ); - ConstInfoAccessor nameEntry = pool.getItem( accessor.getNameIndex() ); - ConstInfoAccessor typeEntry = pool.getItem( accessor.getTypeIndex() ); - return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag() - && typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); + public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { + NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem()); + ConstInfoAccessor nameEntry = pool.getItem(accessor.getNameIndex()); + ConstInfoAccessor typeEntry = pool.getItem(accessor.getTypeIndex()); + return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag() && typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); } }, - MethodHandleInfo( 15, 3 ) - { + MethodHandleInfo( 15, 3 ) { + @Override - public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) - { - MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor( entry.getItem() ); - gatherIndexTree( indices, editor, accessor.getTypeIndex() ); - gatherIndexTree( indices, editor, accessor.getMethodRefIndex() ); + public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { + MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem()); + gatherIndexTree(indices, editor, accessor.getTypeIndex()); + gatherIndexTree(indices, editor, accessor.getMethodRefIndex()); } @Override - public void remapIndices( Map map, ConstInfoAccessor entry ) - { - MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor( entry.getItem() ); - accessor.setTypeIndex( remapIndex( map, accessor.getTypeIndex() ) ); - accessor.setMethodRefIndex( remapIndex( map, accessor.getMethodRefIndex() ) ); + public void remapIndices(Map map, ConstInfoAccessor entry) { + MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem()); + accessor.setTypeIndex(remapIndex(map, accessor.getTypeIndex())); + accessor.setMethodRefIndex(remapIndex(map, accessor.getMethodRefIndex())); } - + @Override - public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) - { - MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor( entry.getItem() ); - ConstInfoAccessor typeEntry = pool.getItem( accessor.getTypeIndex() ); - ConstInfoAccessor methodRefEntry = pool.getItem( accessor.getMethodRefIndex() ); - return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag() - && methodRefEntry != null && methodRefEntry.getTag() == MethodRefInfo.getTag(); + public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { + MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem()); + ConstInfoAccessor typeEntry = pool.getItem(accessor.getTypeIndex()); + ConstInfoAccessor methodRefEntry = pool.getItem(accessor.getMethodRefIndex()); + return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag() && methodRefEntry != null && methodRefEntry.getTag() == MethodRefInfo.getTag(); } }, - MethodTypeInfo( 16, 1 ) - { + MethodTypeInfo( 16, 1 ) { + @Override - public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) - { - MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor( entry.getItem() ); - gatherIndexTree( indices, editor, accessor.getTypeIndex() ); + public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { + MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem()); + gatherIndexTree(indices, editor, accessor.getTypeIndex()); } @Override - public void remapIndices( Map map, ConstInfoAccessor entry ) - { - MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor( entry.getItem() ); - accessor.setTypeIndex( remapIndex( map, accessor.getTypeIndex() ) ); + public void remapIndices(Map map, ConstInfoAccessor entry) { + MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem()); + accessor.setTypeIndex(remapIndex(map, accessor.getTypeIndex())); } - + @Override - public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) - { - MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor( entry.getItem() ); - ConstInfoAccessor typeEntry = pool.getItem( accessor.getTypeIndex() ); + public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { + MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem()); + ConstInfoAccessor typeEntry = pool.getItem(accessor.getTypeIndex()); return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); } }, - InvokeDynamicInfo( 18, 2 ) - { + InvokeDynamicInfo( 18, 2 ) { + @Override - public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) - { - InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor( entry.getItem() ); - gatherIndexTree( indices, editor, accessor.getBootstrapIndex() ); - gatherIndexTree( indices, editor, accessor.getNameAndTypeIndex() ); + public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { + InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem()); + gatherIndexTree(indices, editor, accessor.getBootstrapIndex()); + gatherIndexTree(indices, editor, accessor.getNameAndTypeIndex()); } @Override - public void remapIndices( Map map, ConstInfoAccessor entry ) - { - InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor( entry.getItem() ); - accessor.setBootstrapIndex( remapIndex( map, accessor.getBootstrapIndex() ) ); - accessor.setNameAndTypeIndex( remapIndex( map, accessor.getNameAndTypeIndex() ) ); + public void remapIndices(Map map, ConstInfoAccessor entry) { + InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem()); + accessor.setBootstrapIndex(remapIndex(map, accessor.getBootstrapIndex())); + accessor.setNameAndTypeIndex(remapIndex(map, accessor.getNameAndTypeIndex())); } - + @Override - public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) - { - InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor( entry.getItem() ); - ConstInfoAccessor bootstrapEntry = pool.getItem( accessor.getBootstrapIndex() ); - ConstInfoAccessor nameAndTypeEntry = pool.getItem( accessor.getNameAndTypeIndex() ); - return bootstrapEntry != null && bootstrapEntry.getTag() == Utf8Info.getTag() - && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag(); + public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { + InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem()); + ConstInfoAccessor bootstrapEntry = pool.getItem(accessor.getBootstrapIndex()); + ConstInfoAccessor nameAndTypeEntry = pool.getItem(accessor.getNameAndTypeIndex()); + return bootstrapEntry != null && bootstrapEntry.getTag() == Utf8Info.getTag() && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag(); } }; private static Map m_types; - static - { + static { m_types = Maps.newTreeMap(); - for( InfoType type : values() ) - { - m_types.put( type.getTag(), type ); + for (InfoType type : values()) { + m_types.put(type.getTag(), type); } } private int m_tag; private int m_level; - private InfoType( int tag, int level ) - { + private InfoType(int tag, int level) { m_tag = tag; m_level = level; } - public int getTag( ) - { + public int getTag() { return m_tag; } - public int getLevel( ) - { + public int getLevel() { return m_level; } - public void gatherIndexTree( Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry ) - { + public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { // by default, do nothing } - public void remapIndices( Map map, ConstInfoAccessor entry ) - { + public void remapIndices(Map map, ConstInfoAccessor entry) { // by default, do nothing } - public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) - { + public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { // by default, everything is good return true; } - public boolean selfIndexIsValid( ConstInfoAccessor entry, ConstPoolEditor pool ) - { - ConstInfoAccessor entryCheck = pool.getItem( entry.getIndex() ); - if( entryCheck == null ) - { + public boolean selfIndexIsValid(ConstInfoAccessor entry, ConstPoolEditor pool) { + ConstInfoAccessor entryCheck = pool.getItem(entry.getIndex()); + if (entryCheck == null) { return false; } - return entryCheck.getItem().equals( entry.getItem() ); + return entryCheck.getItem().equals(entry.getItem()); } - public static InfoType getByTag( int tag ) - { - return m_types.get( tag ); + public static InfoType getByTag(int tag) { + return m_types.get(tag); } - public static List getByLevel( int level ) - { + public static List getByLevel(int level) { List types = Lists.newArrayList(); - for( InfoType type : values() ) - { - if( type.getLevel() == level ) - { - types.add( type ); + for (InfoType type : values()) { + if (type.getLevel() == level) { + types.add(type); } } return types; } - public static List getSortedByLevel( ) - { + public static List getSortedByLevel() { List types = Lists.newArrayList(); - types.addAll( getByLevel( 0 ) ); - types.addAll( getByLevel( 1 ) ); - types.addAll( getByLevel( 2 ) ); - types.addAll( getByLevel( 3 ) ); + types.addAll(getByLevel(0)); + types.addAll(getByLevel(1)); + types.addAll(getByLevel(2)); + types.addAll(getByLevel(3)); return types; } - public static void gatherIndexTree( Collection indices, ConstPoolEditor editor, int index ) - { + public static void gatherIndexTree(Collection indices, ConstPoolEditor editor, int index) { // add own index - indices.add( index ); + indices.add(index); // recurse - ConstInfoAccessor entry = editor.getItem( index ); - entry.getType().gatherIndexTree( indices, editor, entry ); + ConstInfoAccessor entry = editor.getItem(index); + entry.getType().gatherIndexTree(indices, editor, entry); } - private static int remapIndex( Map map, int index ) - { - Integer newIndex = map.get( index ); - if( newIndex == null ) - { + private static int remapIndex(Map map, int index) { + Integer newIndex = map.get(index); + if (newIndex == null) { newIndex = index; } return newIndex; diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java index 5e593078..f52c31aa 100644 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -23,105 +23,80 @@ import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; -public class InnerClassWriter -{ +public class InnerClassWriter { + private JarIndex m_jarIndex; - public InnerClassWriter( JarIndex jarIndex ) - { + public InnerClassWriter(JarIndex jarIndex) { m_jarIndex = jarIndex; } - public void write( CtClass c ) - { + public void write(CtClass c) { + // is this an inner or outer class? - String obfInnerClassName = new ClassEntry( Descriptor.toJvmName( c.getName() ) ).getSimpleName(); - String obfOuterClassName = m_jarIndex.getOuterClass( obfInnerClassName ); - if( obfOuterClassName == null ) - { + String obfInnerClassName = new ClassEntry(Descriptor.toJvmName(c.getName())).getSimpleName(); + String obfOuterClassName = m_jarIndex.getOuterClass(obfInnerClassName); + if (obfOuterClassName == null) { // this is an outer class - obfOuterClassName = Descriptor.toJvmName( c.getName() ); - } - else - { + obfOuterClassName = Descriptor.toJvmName(c.getName()); + } else { // this is an inner class, rename it to outer$inner - ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfInnerClassName ); - c.setName( obfClassEntry.getName() ); + ClassEntry obfClassEntry = new ClassEntry(obfOuterClassName + "$" + obfInnerClassName); + c.setName(obfClassEntry.getName()); - BehaviorEntry caller = m_jarIndex.getAnonymousClassCaller( obfInnerClassName ); - if( caller != null ) - { + BehaviorEntry caller = m_jarIndex.getAnonymousClassCaller(obfInnerClassName); + if (caller != null) { // write the enclosing method attribute - if( caller.getName().equals( "" ) ) - { - c.getClassFile().addAttribute( new EnclosingMethodAttribute( - c.getClassFile().getConstPool(), - caller.getClassName() - ) ); - } - else - { - c.getClassFile().addAttribute( new EnclosingMethodAttribute( - c.getClassFile().getConstPool(), - caller.getClassName(), - caller.getName(), - caller.getSignature() - ) ); + if (caller.getName().equals("")) { + c.getClassFile().addAttribute(new EnclosingMethodAttribute(c.getClassFile().getConstPool(), caller.getClassName())); + } else { + c.getClassFile().addAttribute(new EnclosingMethodAttribute(c.getClassFile().getConstPool(), caller.getClassName(), caller.getName(), caller.getSignature())); } } } // write the inner classes if needed - Collection obfInnerClassNames = m_jarIndex.getInnerClasses( obfOuterClassName ); - if( obfInnerClassNames != null && !obfInnerClassNames.isEmpty() ) - { - writeInnerClasses( c, obfOuterClassName, obfInnerClassNames ); + Collection obfInnerClassNames = m_jarIndex.getInnerClasses(obfOuterClassName); + if (obfInnerClassNames != null && !obfInnerClassNames.isEmpty()) { + writeInnerClasses(c, obfOuterClassName, obfInnerClassNames); } } - private void writeInnerClasses( CtClass c, String obfOuterClassName, Collection obfInnerClassNames ) - { - InnerClassesAttribute attr = new InnerClassesAttribute( c.getClassFile().getConstPool() ); - c.getClassFile().addAttribute( attr ); - for( String obfInnerClassName : obfInnerClassNames ) - { + private void writeInnerClasses(CtClass c, String obfOuterClassName, Collection obfInnerClassNames) { + InnerClassesAttribute attr = new InnerClassesAttribute(c.getClassFile().getConstPool()); + c.getClassFile().addAttribute(attr); + for (String obfInnerClassName : obfInnerClassNames) { // get the new inner class name - ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfInnerClassName ); + ClassEntry obfClassEntry = new ClassEntry(obfOuterClassName + "$" + obfInnerClassName); // here's what the JVM spec says about the InnerClasses attribute - // append( inner, outer of inner if inner is member of outer 0 ow, name after $ if inner not anonymous 0 ow, flags ); + // append( inner, outer of inner if inner is member of outer 0 ow, name after $ if inner not anonymous 0 ow, flags ); // update the attribute with this inner class ConstPool constPool = c.getClassFile().getConstPool(); - int innerClassIndex = constPool.addClassInfo( obfClassEntry.getName() ); + int innerClassIndex = constPool.addClassInfo(obfClassEntry.getName()); int outerClassIndex = 0; int innerClassSimpleNameIndex = 0; - if( !m_jarIndex.isAnonymousClass( obfInnerClassName ) ) - { - outerClassIndex = constPool.addClassInfo( obfClassEntry.getOuterClassName() ); - innerClassSimpleNameIndex = constPool.addUtf8Info( obfClassEntry.getInnerClassName() ); + if (!m_jarIndex.isAnonymousClass(obfInnerClassName)) { + outerClassIndex = constPool.addClassInfo(obfClassEntry.getOuterClassName()); + innerClassSimpleNameIndex = constPool.addUtf8Info(obfClassEntry.getInnerClassName()); } - attr.append( - innerClassIndex, - outerClassIndex, - innerClassSimpleNameIndex, - c.getClassFile().getAccessFlags() & ~AccessFlag.SUPER - ); + attr.append(innerClassIndex, outerClassIndex, innerClassSimpleNameIndex, c.getClassFile().getAccessFlags() & ~AccessFlag.SUPER); - /* DEBUG - System.out.println( String.format( "\tOBF: %s -> ATTR: %s,%s,%s (replace %s with %s)", + /* DEBUG + System.out.println(String.format("\tOBF: %s -> ATTR: %s,%s,%s (replace %s with %s)", obfClassEntry, - attr.outerClass( attr.tableLength() - 1 ), - attr.innerClass( attr.tableLength() - 1 ), - attr.innerName( attr.tableLength() - 1 ), + attr.outerClass(attr.tableLength() - 1), + attr.innerClass(attr.tableLength() - 1), + attr.innerName(attr.tableLength() - 1), Constants.NonePackage + "/" + obfInnerClassName, obfClassEntry.getName() - ) ); + )); */ // make sure the outer class references only the new inner class names - c.replaceClassName( Constants.NonePackage + "/" + obfInnerClassName, obfClassEntry.getName() ); + c.replaceClassName(Constants.NonePackage + "/" + obfInnerClassName, obfClassEntry.getName()); } } } diff --git a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java index adea7eae..5a11cd89 100644 --- a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java +++ b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java @@ -25,51 +25,42 @@ import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.Translator; -public class MethodParameterWriter -{ +public class MethodParameterWriter { + private Translator m_translator; - public MethodParameterWriter( Translator translator ) - { + public MethodParameterWriter(Translator translator) { m_translator = translator; } - public void writeMethodArguments( CtClass c ) - { + 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() ) - { - int numParams = Descriptor.numOfParameters( behavior.getMethodInfo().getDescriptor() ); - if( numParams <= 0 ) - { + ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); + for (CtBehavior behavior : c.getDeclaredBehaviors()) { + int numParams = Descriptor.numOfParameters(behavior.getMethodInfo().getDescriptor()); + if (numParams <= 0) { continue; } // get the behavior entry BehaviorEntry behaviorEntry; - if( behavior instanceof CtMethod ) - { - behaviorEntry = new MethodEntry( classEntry, behavior.getMethodInfo().getName(), behavior.getSignature() ); - } - else if( behavior instanceof CtConstructor ) - { - behaviorEntry = new ConstructorEntry( classEntry, behavior.getSignature() ); - } - else - { - throw new Error( "Unsupported behavior type: " + behavior.getClass().getName() ); + if (behavior instanceof CtMethod) { + behaviorEntry = new MethodEntry(classEntry, behavior.getMethodInfo().getName(), behavior.getSignature()); + } else if (behavior instanceof CtConstructor) { + behaviorEntry = new ConstructorEntry(classEntry, behavior.getSignature()); + } else { + throw new Error("Unsupported behavior type: " + behavior.getClass().getName()); } // get the list of parameter names - List names = new ArrayList( numParams ); - for( int i=0; i names = new ArrayList(numParams); + for (int i = 0; i < numParams; i++) { + names.add(m_translator.translate(new ArgumentEntry(behaviorEntry, i, ""))); } // save the mappings to the class - MethodParametersAttribute.updateClass( behavior.getMethodInfo(), names ); + MethodParametersAttribute.updateClass(behavior.getMethodInfo(), names); } } } diff --git a/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java b/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java index baf1ac1e..bf959564 100644 --- a/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java +++ b/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java @@ -20,45 +20,38 @@ import javassist.bytecode.AttributeInfo; import javassist.bytecode.ConstPool; import javassist.bytecode.MethodInfo; -public class MethodParametersAttribute extends AttributeInfo -{ - private MethodParametersAttribute( ConstPool pool, List parameterNameIndices ) - { - super( pool, "MethodParameters", writeStruct( parameterNameIndices ) ); +public class MethodParametersAttribute extends AttributeInfo { + + private MethodParametersAttribute(ConstPool pool, List parameterNameIndices) { + super(pool, "MethodParameters", writeStruct(parameterNameIndices)); } - public static void updateClass( MethodInfo info, List names ) - { + public static void updateClass(MethodInfo info, List names) { // 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 ); + 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 ) ); + info.addAttribute(new MethodParametersAttribute(constPool, parameterNameIndices)); } - private static byte[] writeStruct( List 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 // 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 + // 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 ); + 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 @@ -66,31 +59,27 @@ public class MethodParametersAttribute extends AttributeInfo // 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 int MAX_UINT8 = (1 << 8) - 1; + final int MAX_UINT16 = (1 << 16) - 1; - try - { - assert( parameterNameIndices.size() >= 0 && parameterNameIndices.size() <= MAX_UINT8 ); - out.writeByte( parameterNameIndices.size() ); + try { + 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 ); + for (Integer index : parameterNameIndices) { + assert (index >= 0 && index <= MAX_UINT16); + out.writeShort(index); // just write 0 for the access flags - out.writeShort( 0 ); + out.writeShort(0); } out.close(); byte[] data = buf.toByteArray(); - assert( data.length == SIZEOF_UINT8 + parameterNameIndices.size()*( SIZEOF_UINT16 + SIZEOF_UINT16 ) ); + assert (data.length == SIZEOF_UINT8 + parameterNameIndices.size() * (SIZEOF_UINT16 + SIZEOF_UINT16)); return data; - } - catch( IOException ex ) - { - throw new Error( ex ); + } catch (IOException ex) { + throw new Error(ex); } } } diff --git a/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java index 41e1d047..d76f0567 100644 --- a/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java @@ -12,58 +12,44 @@ package cuchaz.enigma.bytecode.accessors; import java.lang.reflect.Field; -public class ClassInfoAccessor -{ +public class ClassInfoAccessor { + private static Class m_class; private static Field m_nameIndex; - static - { - try - { - m_class = Class.forName( "javassist.bytecode.ClassInfo" ); - m_nameIndex = m_class.getDeclaredField( "name" ); - m_nameIndex.setAccessible( true ); - } - catch( Exception ex ) - { - throw new Error( ex ); + static { + try { + m_class = Class.forName("javassist.bytecode.ClassInfo"); + m_nameIndex = m_class.getDeclaredField("name"); + m_nameIndex.setAccessible(true); + } catch (Exception ex) { + throw new Error(ex); } } - public static boolean isType( ConstInfoAccessor accessor ) - { - return m_class.isAssignableFrom( accessor.getItem().getClass() ); + public static boolean isType(ConstInfoAccessor accessor) { + return m_class.isAssignableFrom(accessor.getItem().getClass()); } private Object m_item; - public ClassInfoAccessor( Object item ) - { + public ClassInfoAccessor(Object item) { m_item = item; } - public int getNameIndex( ) - { - try - { - return (Integer)m_nameIndex.get( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getNameIndex() { + try { + return (Integer)m_nameIndex.get(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public void setNameIndex( int val ) - { - try - { - m_nameIndex.set( m_item, val ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void setNameIndex(int val) { + try { + m_nameIndex.set(m_item, val); + } catch (Exception ex) { + throw new Error(ex); } } } diff --git a/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java index 3c3d3fa4..d00c1021 100644 --- a/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java @@ -22,44 +22,35 @@ import java.lang.reflect.Method; import cuchaz.enigma.bytecode.InfoType; -public class ConstInfoAccessor -{ +public class ConstInfoAccessor { + private static Class m_class; private static Field m_index; private static Method m_getTag; - static - { - try - { - m_class = Class.forName( "javassist.bytecode.ConstInfo" ); - m_index = m_class.getDeclaredField( "index" ); - m_index.setAccessible( true ); - m_getTag = m_class.getMethod( "getTag" ); - m_getTag.setAccessible( true ); - } - catch( Exception ex ) - { - throw new Error( ex ); + static { + try { + m_class = Class.forName("javassist.bytecode.ConstInfo"); + m_index = m_class.getDeclaredField("index"); + m_index.setAccessible(true); + m_getTag = m_class.getMethod("getTag"); + m_getTag.setAccessible(true); + } catch (Exception ex) { + throw new Error(ex); } } private Object m_item; - public ConstInfoAccessor( Object item ) - { - if( item == null ) - { - throw new IllegalArgumentException( "item cannot be null!" ); + public ConstInfoAccessor(Object item) { + if (item == null) { + throw new IllegalArgumentException("item cannot be null!"); } m_item = item; } - public ConstInfoAccessor( DataInputStream in ) - throws IOException - { - try - { + public ConstInfoAccessor(DataInputStream in) throws IOException { + try { // read the entry String className = in.readUTF(); int oldIndex = in.readInt(); @@ -68,132 +59,98 @@ public class ConstInfoAccessor // so we have to read it here in.readByte(); - Constructor constructor = Class.forName( className ).getConstructor( DataInputStream.class, int.class ); - constructor.setAccessible( true ); - m_item = constructor.newInstance( in, oldIndex ); - } - catch( IOException ex ) - { + Constructor constructor = Class.forName(className).getConstructor(DataInputStream.class, int.class); + constructor.setAccessible(true); + m_item = constructor.newInstance(in, oldIndex); + } catch (IOException ex) { throw ex; - } - catch( Exception ex ) - { - throw new Error( ex ); + } catch (Exception ex) { + throw new Error(ex); } } - public Object getItem( ) - { + public Object getItem() { return m_item; } - public int getIndex( ) - { - try - { - return (Integer)m_index.get( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getIndex() { + try { + return (Integer)m_index.get(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public void setIndex( int val ) - { - try - { - m_index.set( m_item, val ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void setIndex(int val) { + try { + m_index.set(m_item, val); + } catch (Exception ex) { + throw new Error(ex); } } - public int getTag( ) - { - try - { - return (Integer)m_getTag.invoke( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getTag() { + try { + return (Integer)m_getTag.invoke(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public ConstInfoAccessor copy( ) - { - return new ConstInfoAccessor( copyItem() ); + public ConstInfoAccessor copy() { + return new ConstInfoAccessor(copyItem()); } - public Object copyItem( ) - { + public Object copyItem() { // I don't know of a simpler way to copy one of these silly things... - try - { + try { // serialize the item ByteArrayOutputStream buf = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream( buf ); - write( out ); + DataOutputStream out = new DataOutputStream(buf); + write(out); // deserialize the item - DataInputStream in = new DataInputStream( new ByteArrayInputStream( buf.toByteArray() ) ); - Object item = new ConstInfoAccessor( in ).getItem(); + DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf.toByteArray())); + Object item = new ConstInfoAccessor(in).getItem(); in.close(); return item; - } - catch( Exception ex ) - { - throw new Error( ex ); + } catch (Exception ex) { + throw new Error(ex); } } - public void write( DataOutputStream out ) - throws IOException - { - try - { - out.writeUTF( m_item.getClass().getName() ); - out.writeInt( getIndex() ); + public void write(DataOutputStream out) throws IOException { + try { + out.writeUTF(m_item.getClass().getName()); + out.writeInt(getIndex()); - Method method = m_item.getClass().getMethod( "write", DataOutputStream.class ); - method.setAccessible( true ); - method.invoke( m_item, out ); - } - catch( IOException ex ) - { + Method method = m_item.getClass().getMethod("write", DataOutputStream.class); + method.setAccessible(true); + method.invoke(m_item, out); + } catch (IOException ex) { throw ex; - } - catch( Exception ex ) - { - throw new Error( ex ); + } catch (Exception ex) { + throw new Error(ex); } } @Override - public String toString( ) - { - try - { + public String toString() { + try { ByteArrayOutputStream buf = new ByteArrayOutputStream(); - PrintWriter out = new PrintWriter( buf ); - Method print = m_item.getClass().getMethod( "print", PrintWriter.class ); - print.setAccessible( true ); - print.invoke( m_item, out ); + PrintWriter out = new PrintWriter(buf); + Method print = m_item.getClass().getMethod("print", PrintWriter.class); + print.setAccessible(true); + print.invoke(m_item, out); out.close(); - return buf.toString().replace( "\n", "" ); - } - catch( Exception ex ) - { - throw new Error( ex ); + return buf.toString().replace("\n", ""); + } catch (Exception ex) { + throw new Error(ex); } } - public InfoType getType( ) - { - return InfoType.getByTag( getTag() ); + public InfoType getType() { + return InfoType.getByTag(getTag()); } } diff --git a/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java index 169306a4..0d780ea6 100644 --- a/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java @@ -12,85 +12,63 @@ package cuchaz.enigma.bytecode.accessors; import java.lang.reflect.Field; -public class InvokeDynamicInfoAccessor -{ +public class InvokeDynamicInfoAccessor { + private static Class m_class; private static Field m_bootstrapIndex; private static Field m_nameAndTypeIndex; - static - { - try - { - m_class = Class.forName( "javassist.bytecode.InvokeDynamicInfo" ); - m_bootstrapIndex = m_class.getDeclaredField( "bootstrap" ); - m_bootstrapIndex.setAccessible( true ); - m_nameAndTypeIndex = m_class.getDeclaredField( "nameAndType" ); - m_nameAndTypeIndex.setAccessible( true ); - } - catch( Exception ex ) - { - throw new Error( ex ); + static { + try { + m_class = Class.forName("javassist.bytecode.InvokeDynamicInfo"); + m_bootstrapIndex = m_class.getDeclaredField("bootstrap"); + m_bootstrapIndex.setAccessible(true); + m_nameAndTypeIndex = m_class.getDeclaredField("nameAndType"); + m_nameAndTypeIndex.setAccessible(true); + } catch (Exception ex) { + throw new Error(ex); } } - public static boolean isType( ConstInfoAccessor accessor ) - { - return m_class.isAssignableFrom( accessor.getItem().getClass() ); + public static boolean isType(ConstInfoAccessor accessor) { + return m_class.isAssignableFrom(accessor.getItem().getClass()); } private Object m_item; - public InvokeDynamicInfoAccessor( Object item ) - { + public InvokeDynamicInfoAccessor(Object item) { m_item = item; } - public int getBootstrapIndex( ) - { - try - { - return (Integer)m_bootstrapIndex.get( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getBootstrapIndex() { + try { + return (Integer)m_bootstrapIndex.get(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public void setBootstrapIndex( int val ) - { - try - { - m_bootstrapIndex.set( m_item, val ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void setBootstrapIndex(int val) { + try { + m_bootstrapIndex.set(m_item, val); + } catch (Exception ex) { + throw new Error(ex); } } - public int getNameAndTypeIndex( ) - { - try - { - return (Integer)m_nameAndTypeIndex.get( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getNameAndTypeIndex() { + try { + return (Integer)m_nameAndTypeIndex.get(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public void setNameAndTypeIndex( int val ) - { - try - { - m_nameAndTypeIndex.set( m_item, val ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void setNameAndTypeIndex(int val) { + try { + m_nameAndTypeIndex.set(m_item, val); + } catch (Exception ex) { + throw new Error(ex); } } } diff --git a/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java index 2ee3aff8..9fe945f7 100644 --- a/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java @@ -12,85 +12,63 @@ package cuchaz.enigma.bytecode.accessors; import java.lang.reflect.Field; -public class MemberRefInfoAccessor -{ +public class MemberRefInfoAccessor { + private static Class m_class; private static Field m_classIndex; private static Field m_nameAndTypeIndex; - static - { - try - { - m_class = Class.forName( "javassist.bytecode.MemberrefInfo" ); - m_classIndex = m_class.getDeclaredField( "classIndex" ); - m_classIndex.setAccessible( true ); - m_nameAndTypeIndex = m_class.getDeclaredField( "nameAndTypeIndex" ); - m_nameAndTypeIndex.setAccessible( true ); - } - catch( Exception ex ) - { - throw new Error( ex ); + static { + try { + m_class = Class.forName("javassist.bytecode.MemberrefInfo"); + m_classIndex = m_class.getDeclaredField("classIndex"); + m_classIndex.setAccessible(true); + m_nameAndTypeIndex = m_class.getDeclaredField("nameAndTypeIndex"); + m_nameAndTypeIndex.setAccessible(true); + } catch (Exception ex) { + throw new Error(ex); } } - public static boolean isType( ConstInfoAccessor accessor ) - { - return m_class.isAssignableFrom( accessor.getItem().getClass() ); + public static boolean isType(ConstInfoAccessor accessor) { + return m_class.isAssignableFrom(accessor.getItem().getClass()); } private Object m_item; - public MemberRefInfoAccessor( Object item ) - { + public MemberRefInfoAccessor(Object item) { m_item = item; } - public int getClassIndex( ) - { - try - { - return (Integer)m_classIndex.get( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getClassIndex() { + try { + return (Integer)m_classIndex.get(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public void setClassIndex( int val ) - { - try - { - m_classIndex.set( m_item, val ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void setClassIndex(int val) { + try { + m_classIndex.set(m_item, val); + } catch (Exception ex) { + throw new Error(ex); } } - public int getNameAndTypeIndex( ) - { - try - { - return (Integer)m_nameAndTypeIndex.get( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getNameAndTypeIndex() { + try { + return (Integer)m_nameAndTypeIndex.get(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public void setNameAndTypeIndex( int val ) - { - try - { - m_nameAndTypeIndex.set( m_item, val ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void setNameAndTypeIndex(int val) { + try { + m_nameAndTypeIndex.set(m_item, val); + } catch (Exception ex) { + throw new Error(ex); } } } diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java index 27b7aee8..4c95b226 100644 --- a/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java @@ -12,85 +12,63 @@ package cuchaz.enigma.bytecode.accessors; import java.lang.reflect.Field; -public class MethodHandleInfoAccessor -{ +public class MethodHandleInfoAccessor { + private static Class m_class; private static Field m_kindIndex; private static Field m_indexIndex; - static - { - try - { - m_class = Class.forName( "javassist.bytecode.MethodHandleInfo" ); - m_kindIndex = m_class.getDeclaredField( "refKind" ); - m_kindIndex.setAccessible( true ); - m_indexIndex = m_class.getDeclaredField( "refIndex" ); - m_indexIndex.setAccessible( true ); - } - catch( Exception ex ) - { - throw new Error( ex ); + static { + try { + m_class = Class.forName("javassist.bytecode.MethodHandleInfo"); + m_kindIndex = m_class.getDeclaredField("refKind"); + m_kindIndex.setAccessible(true); + m_indexIndex = m_class.getDeclaredField("refIndex"); + m_indexIndex.setAccessible(true); + } catch (Exception ex) { + throw new Error(ex); } } - public static boolean isType( ConstInfoAccessor accessor ) - { - return m_class.isAssignableFrom( accessor.getItem().getClass() ); + public static boolean isType(ConstInfoAccessor accessor) { + return m_class.isAssignableFrom(accessor.getItem().getClass()); } private Object m_item; - public MethodHandleInfoAccessor( Object item ) - { + public MethodHandleInfoAccessor(Object item) { m_item = item; } - public int getTypeIndex( ) - { - try - { - return (Integer)m_kindIndex.get( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getTypeIndex() { + try { + return (Integer)m_kindIndex.get(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public void setTypeIndex( int val ) - { - try - { - m_kindIndex.set( m_item, val ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void setTypeIndex(int val) { + try { + m_kindIndex.set(m_item, val); + } catch (Exception ex) { + throw new Error(ex); } } - public int getMethodRefIndex( ) - { - try - { - return (Integer)m_indexIndex.get( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getMethodRefIndex() { + try { + return (Integer)m_indexIndex.get(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public void setMethodRefIndex( int val ) - { - try - { - m_indexIndex.set( m_item, val ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void setMethodRefIndex(int val) { + try { + m_indexIndex.set(m_item, val); + } catch (Exception ex) { + throw new Error(ex); } } } diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java index 4cba6a2a..e1511179 100644 --- a/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java @@ -12,58 +12,44 @@ package cuchaz.enigma.bytecode.accessors; import java.lang.reflect.Field; -public class MethodTypeInfoAccessor -{ +public class MethodTypeInfoAccessor { + private static Class m_class; private static Field m_descriptorIndex; - static - { - try - { - m_class = Class.forName( "javassist.bytecode.MethodTypeInfo" ); - m_descriptorIndex = m_class.getDeclaredField( "descriptor" ); - m_descriptorIndex.setAccessible( true ); - } - catch( Exception ex ) - { - throw new Error( ex ); + static { + try { + m_class = Class.forName("javassist.bytecode.MethodTypeInfo"); + m_descriptorIndex = m_class.getDeclaredField("descriptor"); + m_descriptorIndex.setAccessible(true); + } catch (Exception ex) { + throw new Error(ex); } } - public static boolean isType( ConstInfoAccessor accessor ) - { - return m_class.isAssignableFrom( accessor.getItem().getClass() ); + public static boolean isType(ConstInfoAccessor accessor) { + return m_class.isAssignableFrom(accessor.getItem().getClass()); } private Object m_item; - public MethodTypeInfoAccessor( Object item ) - { + public MethodTypeInfoAccessor(Object item) { m_item = item; } - public int getTypeIndex( ) - { - try - { - return (Integer)m_descriptorIndex.get( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getTypeIndex() { + try { + return (Integer)m_descriptorIndex.get(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public void setTypeIndex( int val ) - { - try - { - m_descriptorIndex.set( m_item, val ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void setTypeIndex(int val) { + try { + m_descriptorIndex.set(m_item, val); + } catch (Exception ex) { + throw new Error(ex); } } } diff --git a/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java index 03b4de3c..6e82f3e9 100644 --- a/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java @@ -12,85 +12,63 @@ package cuchaz.enigma.bytecode.accessors; import java.lang.reflect.Field; -public class NameAndTypeInfoAccessor -{ +public class NameAndTypeInfoAccessor { + private static Class m_class; private static Field m_nameIndex; private static Field m_typeIndex; - static - { - try - { - m_class = Class.forName( "javassist.bytecode.NameAndTypeInfo" ); - m_nameIndex = m_class.getDeclaredField( "memberName" ); - m_nameIndex.setAccessible( true ); - m_typeIndex = m_class.getDeclaredField( "typeDescriptor" ); - m_typeIndex.setAccessible( true ); - } - catch( Exception ex ) - { - throw new Error( ex ); + static { + try { + m_class = Class.forName("javassist.bytecode.NameAndTypeInfo"); + m_nameIndex = m_class.getDeclaredField("memberName"); + m_nameIndex.setAccessible(true); + m_typeIndex = m_class.getDeclaredField("typeDescriptor"); + m_typeIndex.setAccessible(true); + } catch (Exception ex) { + throw new Error(ex); } } - public static boolean isType( ConstInfoAccessor accessor ) - { - return m_class.isAssignableFrom( accessor.getItem().getClass() ); + public static boolean isType(ConstInfoAccessor accessor) { + return m_class.isAssignableFrom(accessor.getItem().getClass()); } private Object m_item; - public NameAndTypeInfoAccessor( Object item ) - { + public NameAndTypeInfoAccessor(Object item) { m_item = item; } - public int getNameIndex( ) - { - try - { - return (Integer)m_nameIndex.get( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getNameIndex() { + try { + return (Integer)m_nameIndex.get(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public void setNameIndex( int val ) - { - try - { - m_nameIndex.set( m_item, val ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void setNameIndex(int val) { + try { + m_nameIndex.set(m_item, val); + } catch (Exception ex) { + throw new Error(ex); } } - public int getTypeIndex( ) - { - try - { - return (Integer)m_typeIndex.get( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getTypeIndex() { + try { + return (Integer)m_typeIndex.get(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public void setTypeIndex( int val ) - { - try - { - m_typeIndex.set( m_item, val ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void setTypeIndex(int val) { + try { + m_typeIndex.set(m_item, val); + } catch (Exception ex) { + throw new Error(ex); } } } diff --git a/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java index 5cdfce4d..6665ffe4 100644 --- a/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java @@ -12,58 +12,44 @@ package cuchaz.enigma.bytecode.accessors; import java.lang.reflect.Field; -public class StringInfoAccessor -{ +public class StringInfoAccessor { + private static Class m_class; private static Field m_stringIndex; - static - { - try - { - m_class = Class.forName( "javassist.bytecode.StringInfo" ); - m_stringIndex = m_class.getDeclaredField( "string" ); - m_stringIndex.setAccessible( true ); - } - catch( Exception ex ) - { - throw new Error( ex ); + static { + try { + m_class = Class.forName("javassist.bytecode.StringInfo"); + m_stringIndex = m_class.getDeclaredField("string"); + m_stringIndex.setAccessible(true); + } catch (Exception ex) { + throw new Error(ex); } } - public static boolean isType( ConstInfoAccessor accessor ) - { - return m_class.isAssignableFrom( accessor.getItem().getClass() ); + public static boolean isType(ConstInfoAccessor accessor) { + return m_class.isAssignableFrom(accessor.getItem().getClass()); } private Object m_item; - public StringInfoAccessor( Object item ) - { + public StringInfoAccessor(Object item) { m_item = item; } - public int getStringIndex( ) - { - try - { - return (Integer)m_stringIndex.get( m_item ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public int getStringIndex() { + try { + return (Integer)m_stringIndex.get(m_item); + } catch (Exception ex) { + throw new Error(ex); } } - public void setStringIndex( int val ) - { - try - { - m_stringIndex.set( m_item, val ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void setStringIndex(int val) { + try { + m_stringIndex.set(m_item, val); + } catch (Exception ex) { + throw new Error(ex); } } } diff --git a/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java index 1cadd836..2abf60b4 100644 --- a/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java +++ b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java @@ -10,24 +10,19 @@ ******************************************************************************/ package cuchaz.enigma.bytecode.accessors; -public class Utf8InfoAccessor -{ +public class Utf8InfoAccessor { + private static Class m_class; - static - { - try - { - m_class = Class.forName( "javassist.bytecode.Utf8Info" ); - } - catch( Exception ex ) - { - throw new Error( ex ); + static { + try { + m_class = Class.forName("javassist.bytecode.Utf8Info"); + } catch (Exception ex) { + throw new Error(ex); } } - public static boolean isType( ConstInfoAccessor accessor ) - { - return m_class.isAssignableFrom( accessor.getItem().getClass() ); + public static boolean isType(ConstInfoAccessor accessor) { + return m_class.isAssignableFrom(accessor.getItem().getClass()); } } diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java index 1de345ff..73404038 100644 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ b/src/cuchaz/enigma/convert/ClassIdentity.java @@ -57,8 +57,8 @@ import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.SignatureUpdater; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; -public class ClassIdentity -{ +public class ClassIdentity { + private ClassEntry m_classEntry; private SidedClassNamer m_namer; private Multiset m_fields; @@ -70,419 +70,339 @@ public class ClassIdentity private Multiset m_implementations; private Multiset m_references; - public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences ) - { + public ClassIdentity(CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences) { m_namer = namer; // stuff from the bytecode - m_classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); + m_classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); m_fields = HashMultiset.create(); - for( CtField field : c.getDeclaredFields() ) - { - m_fields.add( scrubSignature( field.getSignature() ) ); + for (CtField field : c.getDeclaredFields()) { + m_fields.add(scrubSignature(field.getSignature())); } m_methods = HashMultiset.create(); - for( CtMethod method : c.getDeclaredMethods() ) - { - m_methods.add( scrubSignature( method.getSignature() ) + "0x" + getBehaviorSignature( method ) ); + for (CtMethod method : c.getDeclaredMethods()) { + m_methods.add(scrubSignature(method.getSignature()) + "0x" + getBehaviorSignature(method)); } m_constructors = HashMultiset.create(); - for( CtConstructor constructor : c.getDeclaredConstructors() ) - { - m_constructors.add( scrubSignature( constructor.getSignature() ) + "0x" + getBehaviorSignature( constructor ) ); + for (CtConstructor constructor : c.getDeclaredConstructors()) { + m_constructors.add(scrubSignature(constructor.getSignature()) + "0x" + getBehaviorSignature(constructor)); } m_staticInitializer = ""; - if( c.getClassInitializer() != null ) - { - m_staticInitializer = getBehaviorSignature( c.getClassInitializer() ); + if (c.getClassInitializer() != null) { + m_staticInitializer = getBehaviorSignature(c.getClassInitializer()); } m_extends = ""; - if( c.getClassFile().getSuperclass() != null ) - { - m_extends = scrubClassName( c.getClassFile().getSuperclass() ); + if (c.getClassFile().getSuperclass() != null) { + m_extends = scrubClassName(c.getClassFile().getSuperclass()); } m_implements = HashMultiset.create(); - for( String interfaceName : c.getClassFile().getInterfaces() ) - { - m_implements.add( scrubClassName( interfaceName ) ); + for (String interfaceName : c.getClassFile().getInterfaces()) { + m_implements.add(scrubClassName(interfaceName)); } // stuff from the jar index m_implementations = HashMultiset.create(); - ClassImplementationsTreeNode implementationsNode = index.getClassImplementations( null, m_classEntry ); - if( implementationsNode != null ) - { - @SuppressWarnings( "unchecked" ) + ClassImplementationsTreeNode implementationsNode = index.getClassImplementations(null, m_classEntry); + if (implementationsNode != null) { + @SuppressWarnings("unchecked") Enumeration implementations = implementationsNode.children(); - while( implementations.hasMoreElements() ) - { + while (implementations.hasMoreElements()) { ClassImplementationsTreeNode node = implementations.nextElement(); - m_implementations.add( scrubClassName( node.getClassEntry().getName() ) ); + m_implementations.add(scrubClassName(node.getClassEntry().getName())); } } m_references = HashMultiset.create(); - if( useReferences ) - { - for( CtField field : c.getDeclaredFields() ) - { - FieldEntry fieldEntry = new FieldEntry( m_classEntry, field.getName() ); - for( EntryReference reference : index.getFieldReferences( fieldEntry ) ) - { - addReference( reference ); + if (useReferences) { + for (CtField field : c.getDeclaredFields()) { + FieldEntry fieldEntry = new FieldEntry(m_classEntry, field.getName()); + for (EntryReference reference : index.getFieldReferences(fieldEntry)) { + addReference(reference); } } - for( CtMethod method : c.getDeclaredMethods() ) - { - MethodEntry methodEntry = new MethodEntry( m_classEntry, method.getName(), method.getSignature() ); - for( EntryReference reference : index.getBehaviorReferences( methodEntry ) ) - { - addReference( reference ); + for (CtMethod method : c.getDeclaredMethods()) { + MethodEntry methodEntry = new MethodEntry(m_classEntry, method.getName(), method.getSignature()); + for (EntryReference reference : index.getBehaviorReferences(methodEntry)) { + addReference(reference); } } - for( CtConstructor constructor : c.getDeclaredConstructors() ) - { - ConstructorEntry constructorEntry = new ConstructorEntry( m_classEntry, constructor.getSignature() ); - for( EntryReference reference : index.getBehaviorReferences( constructorEntry ) ) - { - addReference( reference ); + for (CtConstructor constructor : c.getDeclaredConstructors()) { + ConstructorEntry constructorEntry = new ConstructorEntry(m_classEntry, constructor.getSignature()); + for (EntryReference reference : index.getBehaviorReferences(constructorEntry)) { + addReference(reference); } } } } - private void addReference( EntryReference reference ) - { - if( reference.context.getSignature() != null ) - { - m_references.add( String.format( "%s_%s", - scrubClassName( reference.context.getClassName() ), - scrubSignature( reference.context.getSignature() ) - ) ); - } - else - { - m_references.add( String.format( "%s_", - scrubClassName( reference.context.getClassName() ) - ) ); + private void addReference(EntryReference reference) { + if (reference.context.getSignature() != null) { + m_references.add(String.format("%s_%s", scrubClassName(reference.context.getClassName()), scrubSignature(reference.context.getSignature()))); + } else { + m_references.add(String.format("%s_", scrubClassName(reference.context.getClassName()))); } } - - public ClassEntry getClassEntry( ) - { + + public ClassEntry getClassEntry() { return m_classEntry; } @Override - public String toString( ) - { + public String toString() { StringBuilder buf = new StringBuilder(); - buf.append( "class: " ); - buf.append( m_classEntry.getName() ); - buf.append( " " ); - buf.append( hashCode() ); - buf.append( "\n" ); - for( String field : m_fields ) - { - buf.append( "\tfield " ); - buf.append( field ); - buf.append( "\n" ); + buf.append("class: "); + buf.append(m_classEntry.getName()); + buf.append(" "); + buf.append(hashCode()); + buf.append("\n"); + for (String field : m_fields) { + buf.append("\tfield "); + buf.append(field); + buf.append("\n"); } - for( String method : m_methods ) - { - buf.append( "\tmethod " ); - buf.append( method ); - buf.append( "\n" ); + for (String method : m_methods) { + buf.append("\tmethod "); + buf.append(method); + buf.append("\n"); } - for( String constructor : m_constructors ) - { - buf.append( "\tconstructor " ); - buf.append( constructor ); - buf.append( "\n" ); + for (String constructor : m_constructors) { + buf.append("\tconstructor "); + buf.append(constructor); + buf.append("\n"); } - if( m_staticInitializer.length() > 0 ) - { - buf.append( "\tinitializer " ); - buf.append( m_staticInitializer ); - buf.append( "\n" ); + if (m_staticInitializer.length() > 0) { + buf.append("\tinitializer "); + buf.append(m_staticInitializer); + buf.append("\n"); } - if( m_extends.length() > 0 ) - { - buf.append( "\textends " ); - buf.append( m_extends ); - buf.append( "\n" ); + if (m_extends.length() > 0) { + buf.append("\textends "); + buf.append(m_extends); + buf.append("\n"); } - for( String interfaceName : m_implements ) - { - buf.append( "\timplements " ); - buf.append( interfaceName ); - buf.append( "\n" ); + for (String interfaceName : m_implements) { + buf.append("\timplements "); + buf.append(interfaceName); + buf.append("\n"); } - for( String implementation : m_implementations ) - { - buf.append( "\timplemented by " ); - buf.append( implementation ); - buf.append( "\n" ); + for (String implementation : m_implementations) { + buf.append("\timplemented by "); + buf.append(implementation); + buf.append("\n"); } - for( String reference : m_references ) - { - buf.append( "\treference " ); - buf.append( reference ); - buf.append( "\n" ); + for (String reference : m_references) { + buf.append("\treference "); + buf.append(reference); + buf.append("\n"); } return buf.toString(); } - private String scrubClassName( String className ) - { - return scrubSignature( "L" + Descriptor.toJvmName( className ) + ";" ); + private String scrubClassName(String className) { + return scrubSignature("L" + Descriptor.toJvmName(className) + ";"); } - private String scrubSignature( String signature ) - { - return SignatureUpdater.update( signature, new ClassNameUpdater( ) - { + private String scrubSignature(String signature) { + return SignatureUpdater.update(signature, new ClassNameUpdater() { private Map m_classNames = Maps.newHashMap(); @Override - public String update( String className ) - { + public String update(String className) { // classes not in the none package can be passed through - ClassEntry classEntry = new ClassEntry( className ); - if( !classEntry.getPackageName().equals( Constants.NonePackage ) ) - { + ClassEntry classEntry = new ClassEntry(className); + if (!classEntry.getPackageName().equals(Constants.NonePackage)) { return className; } // is this class ourself? - if( className.equals( m_classEntry.getName() ) ) - { + if (className.equals(m_classEntry.getName())) { return "CSelf"; } // try the namer - if( m_namer != null ) - { - String newName = m_namer.getName( className ); - if( newName != null ) - { + if (m_namer != null) { + String newName = m_namer.getName(className); + if (newName != null) { return newName; } } // otherwise, use local naming - if( !m_classNames.containsKey( className ) ) - { - m_classNames.put( className, getNewClassName() ); + if (!m_classNames.containsKey(className)) { + m_classNames.put(className, getNewClassName()); } - return m_classNames.get( className ); + return m_classNames.get(className); } - - private String getNewClassName( ) - { - return String.format( "C%03d", m_classNames.size() ); + + private String getNewClassName() { + return String.format("C%03d", m_classNames.size()); } - } ); + }); } - private boolean isClassMatchedUniquely( String className ) - { - return m_namer != null && m_namer.getName( Descriptor.toJvmName( className ) ) != null; + private boolean isClassMatchedUniquely(String className) { + return m_namer != null && m_namer.getName(Descriptor.toJvmName(className)) != null; } - private String getBehaviorSignature( CtBehavior behavior ) - { - try - { + private String getBehaviorSignature(CtBehavior behavior) { + try { // does this method have an implementation? - if( behavior.getMethodInfo().getCodeAttribute() == null ) - { + if (behavior.getMethodInfo().getCodeAttribute() == null) { return "(none)"; } // compute the hash from the opcodes ConstPool constants = behavior.getMethodInfo().getConstPool(); - final MessageDigest digest = MessageDigest.getInstance( "MD5" ); + final MessageDigest digest = MessageDigest.getInstance("MD5"); CodeIterator iter = behavior.getMethodInfo().getCodeAttribute().iterator(); - while( iter.hasNext() ) - { + while (iter.hasNext()) { int pos = iter.next(); // update the hash with the opcode - int opcode = iter.byteAt( pos ); - digest.update( (byte)opcode ); + int opcode = iter.byteAt(pos); + digest.update((byte)opcode); - switch( opcode ) - { - case Opcode.LDC: - { - int constIndex = iter.byteAt( pos + 1 ); - updateHashWithConstant( digest, constants, constIndex ); + switch (opcode) { + case Opcode.LDC: { + int constIndex = iter.byteAt(pos + 1); + updateHashWithConstant(digest, constants, constIndex); } break; case Opcode.LDC_W: - case Opcode.LDC2_W: - { - int constIndex = ( iter.byteAt( pos + 1 ) << 8 ) | iter.byteAt( pos + 2 ); - updateHashWithConstant( digest, constants, constIndex ); + case Opcode.LDC2_W: { + int constIndex = (iter.byteAt(pos + 1) << 8) | iter.byteAt(pos + 2); + updateHashWithConstant(digest, constants, constIndex); } break; } } // update hash with method and field accesses - behavior.instrument( new ExprEditor( ) - { + behavior.instrument(new ExprEditor() { @Override - public void edit( MethodCall call ) - { - updateHashWithString( digest, scrubClassName( call.getClassName() ) ); - updateHashWithString( digest, scrubSignature( call.getSignature() ) ); - if( isClassMatchedUniquely( call.getClassName() ) ) - { - updateHashWithString( digest, call.getMethodName() ); + public void edit(MethodCall call) { + updateHashWithString(digest, scrubClassName(call.getClassName())); + updateHashWithString(digest, scrubSignature(call.getSignature())); + if (isClassMatchedUniquely(call.getClassName())) { + updateHashWithString(digest, call.getMethodName()); } } @Override - public void edit( FieldAccess access ) - { - updateHashWithString( digest, scrubClassName( access.getClassName() ) ); - updateHashWithString( digest, scrubSignature( access.getSignature() ) ); - if( isClassMatchedUniquely( access.getClassName() ) ) - { - updateHashWithString( digest, access.getFieldName() ); + public void edit(FieldAccess access) { + updateHashWithString(digest, scrubClassName(access.getClassName())); + updateHashWithString(digest, scrubSignature(access.getSignature())); + if (isClassMatchedUniquely(access.getClassName())) { + updateHashWithString(digest, access.getFieldName()); } } @Override - public void edit( ConstructorCall call ) - { - updateHashWithString( digest, scrubClassName( call.getClassName() ) ); - updateHashWithString( digest, scrubSignature( call.getSignature() ) ); + public void edit(ConstructorCall call) { + updateHashWithString(digest, scrubClassName(call.getClassName())); + updateHashWithString(digest, scrubSignature(call.getSignature())); } @Override - public void edit( NewExpr expr ) - { - updateHashWithString( digest, scrubClassName( expr.getClassName() ) ); + public void edit(NewExpr expr) { + updateHashWithString(digest, scrubClassName(expr.getClassName())); } - } ); + }); // convert the hash to a hex string - return toHex( digest.digest() ); - } - catch( BadBytecode | NoSuchAlgorithmException | CannotCompileException ex ) - { - throw new Error( ex ); + return toHex(digest.digest()); + } catch (BadBytecode | NoSuchAlgorithmException | CannotCompileException ex) { + throw new Error(ex); } } - private void updateHashWithConstant( MessageDigest digest, ConstPool constants, int index ) - { - ConstPoolEditor editor = new ConstPoolEditor( constants ); - ConstInfoAccessor item = editor.getItem( index ); - if( item.getType() == InfoType.StringInfo ) - { - updateHashWithString( digest, constants.getStringInfo( index ) ); + private void updateHashWithConstant(MessageDigest digest, ConstPool constants, int index) { + ConstPoolEditor editor = new ConstPoolEditor(constants); + ConstInfoAccessor item = editor.getItem(index); + if (item.getType() == InfoType.StringInfo) { + updateHashWithString(digest, constants.getStringInfo(index)); } // TODO: other constants } - private void updateHashWithString( MessageDigest digest, String val ) - { - try - { - digest.update( val.getBytes( "UTF8" ) ); - } - catch( UnsupportedEncodingException ex ) - { - throw new Error( ex ); + private void updateHashWithString(MessageDigest digest, String val) { + try { + digest.update(val.getBytes("UTF8")); + } catch (UnsupportedEncodingException ex) { + throw new Error(ex); } } - private String toHex( byte[] bytes ) - { + private String toHex(byte[] bytes) { // function taken from: // http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java final char[] hexArray = "0123456789ABCDEF".toCharArray(); char[] hexChars = new char[bytes.length * 2]; - for( int j = 0; j < bytes.length; j++ ) - { + for (int j = 0; j < bytes.length; j++) { int v = bytes[j] & 0xFF; hexChars[j * 2] = hexArray[v >>> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } - return new String( hexChars ); + return new String(hexChars); } - + @Override - public boolean equals( Object other ) - { - if( other instanceof ClassIdentity ) - { - return equals( (ClassIdentity)other ); + public boolean equals(Object other) { + if (other instanceof ClassIdentity) { + return equals((ClassIdentity)other); } return false; } - public boolean equals( ClassIdentity other ) - { - return m_fields.equals( other.m_fields ) - && m_methods.equals( other.m_methods ) - && m_constructors.equals( other.m_constructors ) - && m_staticInitializer.equals( other.m_staticInitializer ) - && m_extends.equals( other.m_extends ) - && m_implements.equals( other.m_implements ) - && m_implementations.equals( other.m_implementations ) - && m_references.equals( other.m_references ); + public boolean equals(ClassIdentity other) { + return m_fields.equals(other.m_fields) + && m_methods.equals(other.m_methods) + && m_constructors.equals(other.m_constructors) + && m_staticInitializer.equals(other.m_staticInitializer) + && m_extends.equals(other.m_extends) + && m_implements.equals(other.m_implements) + && m_implementations.equals(other.m_implementations) + && m_references.equals(other.m_references); } @Override - public int hashCode( ) - { + public int hashCode() { List objs = Lists.newArrayList(); - objs.addAll( m_fields ); - objs.addAll( m_methods ); - objs.addAll( m_constructors ); - objs.add( m_staticInitializer ); - objs.add( m_extends ); - objs.addAll( m_implements ); - objs.addAll( m_implementations ); - objs.addAll( m_references ); - return Util.combineHashesOrdered( objs ); + objs.addAll(m_fields); + objs.addAll(m_methods); + objs.addAll(m_constructors); + objs.add(m_staticInitializer); + objs.add(m_extends); + objs.addAll(m_implements); + objs.addAll(m_implementations); + objs.addAll(m_references); + return Util.combineHashesOrdered(objs); } - public int getMatchScore( ClassIdentity other ) - { - return getNumMatches( m_fields, other.m_fields ) - + getNumMatches( m_methods, other.m_methods ) - + getNumMatches( m_constructors, other.m_constructors ); + public int getMatchScore(ClassIdentity other) { + return getNumMatches(m_fields, other.m_fields) + + getNumMatches(m_methods, other.m_methods) + + getNumMatches(m_constructors, other.m_constructors); } - public int getMaxMatchScore( ) - { + public int getMaxMatchScore() { return m_fields.size() + m_methods.size() + m_constructors.size(); } - public boolean matches( CtClass c ) - { + public boolean matches(CtClass c) { // just compare declaration counts return m_fields.size() == c.getDeclaredFields().length && m_methods.size() == c.getDeclaredMethods().length && m_constructors.size() == c.getDeclaredConstructors().length; } - private int getNumMatches( Multiset a, Multiset b ) - { + private int getNumMatches(Multiset a, Multiset b) { int numMatches = 0; - for( String val : a ) - { - if( b.contains( val ) ) - { + for (String val : a) { + if (b.contains(val)) { numMatches++; } } diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java index 290d90a7..fc39ed0c 100644 --- a/src/cuchaz/enigma/convert/ClassMatcher.java +++ b/src/cuchaz/enigma/convert/ClassMatcher.java @@ -49,102 +49,92 @@ import cuchaz.enigma.mapping.MappingsWriter; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.MethodMapping; -public class ClassMatcher -{ - public static void main( String[] args ) - throws IOException, MappingParseException - { +public class ClassMatcher { + + public static void main(String[] args) throws IOException, MappingParseException { // TEMP - JarFile sourceJar = new JarFile( new File( "input/1.8-pre3.jar" ) ); - JarFile destJar = new JarFile( new File( "input/1.8.jar" ) ); - File inMappingsFile = new File( "../Enigma Mappings/1.8-pre3.mappings" ); - File outMappingsFile = new File( "../Enigma Mappings/1.8.mappings" ); + JarFile sourceJar = new JarFile(new File("input/1.8-pre3.jar")); + JarFile destJar = new JarFile(new File("input/1.8.jar")); + File inMappingsFile = new File("../Enigma Mappings/1.8-pre3.mappings"); + File outMappingsFile = new File("../Enigma Mappings/1.8.mappings"); // define a matching to use when the automated system cannot find a match Map fallbackMatching = Maps.newHashMap(); - fallbackMatching.put( "none/ayb", "none/ayf" ); - fallbackMatching.put( "none/ayd", "none/ayd" ); - fallbackMatching.put( "none/bgk", "unknown/bgk" ); + fallbackMatching.put("none/ayb", "none/ayf"); + fallbackMatching.put("none/ayd", "none/ayd"); + fallbackMatching.put("none/bgk", "unknown/bgk"); // do the conversion - Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) ); - convertMappings( sourceJar, destJar, mappings, fallbackMatching ); + Mappings mappings = new MappingsReader().read(new FileReader(inMappingsFile)); + convertMappings(sourceJar, destJar, mappings, fallbackMatching); // write out the converted mappings - FileWriter writer = new FileWriter( outMappingsFile ); - new MappingsWriter().write( writer, mappings ); + FileWriter writer = new FileWriter(outMappingsFile); + new MappingsWriter().write(writer, mappings); writer.close(); - System.out.println( "Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath() ); + System.out.println("Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath()); } - private static void convertMappings( JarFile sourceJar, JarFile destJar, Mappings mappings, Map fallbackMatching ) - { + private static void convertMappings(JarFile sourceJar, JarFile destJar, Mappings mappings, Map fallbackMatching) { // index jars - System.out.println( "Indexing source jar..." ); + System.out.println("Indexing source jar..."); JarIndex sourceIndex = new JarIndex(); - sourceIndex.indexJar( sourceJar, false ); - System.out.println( "Indexing dest jar..." ); + sourceIndex.indexJar(sourceJar, false); + System.out.println("Indexing dest jar..."); JarIndex destIndex = new JarIndex(); - destIndex.indexJar( destJar, false ); - TranslatingTypeLoader sourceLoader = new TranslatingTypeLoader( sourceJar, sourceIndex ); - TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex ); - + destIndex.indexJar(destJar, false); + TranslatingTypeLoader sourceLoader = new TranslatingTypeLoader(sourceJar, sourceIndex); + TranslatingTypeLoader destLoader = new TranslatingTypeLoader(destJar, destIndex); + // compute the matching - ClassMatching matching = computeMatching( sourceIndex, sourceLoader, destIndex, destLoader ); + ClassMatching matching = computeMatching(sourceIndex, sourceLoader, destIndex, destLoader); Map>> matchingIndex = matching.getIndex(); // get all the obf class names used in the mappings Set usedClassNames = mappings.getAllObfClassNames(); Set allClassNames = Sets.newHashSet(); - for( ClassEntry classEntry : sourceIndex.getObfClassEntries() ) - { - allClassNames.add( classEntry.getName() ); + for (ClassEntry classEntry : sourceIndex.getObfClassEntries()) { + allClassNames.add(classEntry.getName()); } - usedClassNames.retainAll( allClassNames ); - System.out.println( "Used " + usedClassNames.size() + " classes in the mappings" ); + usedClassNames.retainAll(allClassNames); + System.out.println("Used " + usedClassNames.size() + " classes in the mappings"); // probabilistically match the non-uniquely-matched source classes - for( Map.Entry> entry : matchingIndex.values() ) - { + for (Map.Entry> entry : matchingIndex.values()) { ClassIdentity sourceClass = entry.getKey(); List destClasses = entry.getValue(); // skip classes that are uniquely matched - if( destClasses.size() == 1 ) - { + if (destClasses.size() == 1) { continue; } // skip classes that aren't used in the mappings - if( !usedClassNames.contains( sourceClass.getClassEntry().getName() ) ) - { + if (!usedClassNames.contains(sourceClass.getClassEntry().getName())) { continue; } - System.out.println( "No exact match for source class " + sourceClass.getClassEntry() ); + System.out.println("No exact match for source class " + sourceClass.getClassEntry()); // find the closest classes Multimap scoredMatches = ArrayListMultimap.create(); - for( ClassIdentity c : destClasses ) - { - scoredMatches.put( sourceClass.getMatchScore( c ), c ); + for (ClassIdentity c : destClasses) { + scoredMatches.put(sourceClass.getMatchScore(c), c); } - List scores = new ArrayList( scoredMatches.keySet() ); - Collections.sort( scores, Collections.reverseOrder() ); - printScoredMatches( sourceClass.getMaxMatchScore(), scores, scoredMatches ); + List scores = new ArrayList(scoredMatches.keySet()); + Collections.sort(scores, Collections.reverseOrder()); + printScoredMatches(sourceClass.getMaxMatchScore(), scores, scoredMatches); // does the best match have a non-zero score and the same name? - int bestScore = scores.get( 0 ); - Collection bestMatches = scoredMatches.get( bestScore ); - if( bestScore > 0 && bestMatches.size() == 1 ) - { + int bestScore = scores.get(0); + Collection bestMatches = scoredMatches.get(bestScore); + if (bestScore > 0 && bestMatches.size() == 1) { ClassIdentity bestMatch = bestMatches.iterator().next(); - if( bestMatch.getClassEntry().equals( sourceClass.getClassEntry() ) ) - { + if (bestMatch.getClassEntry().equals(sourceClass.getClassEntry())) { // use it - System.out.println( "\tAutomatically choosing likely match: " + bestMatch.getClassEntry().getName() ); + System.out.println("\tAutomatically choosing likely match: " + bestMatch.getClassEntry().getName()); destClasses.clear(); - destClasses.add( bestMatch ); + destClasses.add(bestMatch); } } } @@ -152,63 +142,46 @@ public class ClassMatcher // group the matching into unique and non-unique matches BiMap matchedClassNames = HashBiMap.create(); Set unmatchedSourceClassNames = Sets.newHashSet(); - for( String className : usedClassNames ) - { + for (String className : usedClassNames) { // is there a match for this class? - Map.Entry> entry = matchingIndex.get( className ); + Map.Entry> entry = matchingIndex.get(className); ClassIdentity sourceClass = entry.getKey(); List matches = entry.getValue(); - if( matches.size() == 1 ) - { + if (matches.size() == 1) { // unique match! We're good to go! - matchedClassNames.put( - sourceClass.getClassEntry().getName(), - matches.get( 0 ).getClassEntry().getName() - ); - } - else - { + matchedClassNames.put(sourceClass.getClassEntry().getName(), matches.get(0).getClassEntry().getName()); + } else { // no match, check the fallback matching - String fallbackMatch = fallbackMatching.get( className ); - if( fallbackMatch != null ) - { - matchedClassNames.put( - sourceClass.getClassEntry().getName(), - fallbackMatch - ); - } - else - { - unmatchedSourceClassNames.add( className ); + String fallbackMatch = fallbackMatching.get(className); + if (fallbackMatch != null) { + matchedClassNames.put(sourceClass.getClassEntry().getName(), fallbackMatch); + } else { + unmatchedSourceClassNames.add(className); } } } // report unmatched classes - if( !unmatchedSourceClassNames.isEmpty() ) - { - System.err.println( "ERROR: there were unmatched classes!" ); - for( String className : unmatchedSourceClassNames ) - { - System.err.println( "\t" + className ); + if (!unmatchedSourceClassNames.isEmpty()) { + System.err.println("ERROR: there were unmatched classes!"); + for (String className : unmatchedSourceClassNames) { + System.err.println("\t" + className); } return; } // get the class name changes from the matched class names Map classChanges = Maps.newHashMap(); - for( Map.Entry entry : matchedClassNames.entrySet() ) - { - if( !entry.getKey().equals( entry.getValue() ) ) - { - classChanges.put( entry.getKey(), entry.getValue() ); - System.out.println( String.format( "Class change: %s -> %s", entry.getKey(), entry.getValue() ) ); + for (Map.Entry entry : matchedClassNames.entrySet()) { + if (!entry.getKey().equals(entry.getValue())) { + classChanges.put(entry.getKey(), entry.getValue()); + System.out.println(String.format("Class change: %s -> %s", entry.getKey(), entry.getValue())); /* DEBUG - System.out.println( String.format( "\n%s\n%s", - new ClassIdentity( sourceLoader.loadClass( entry.getKey() ), null, sourceIndex, false, false ), - new ClassIdentity( destLoader.loadClass( entry.getValue() ), null, destIndex, false, false ) - ) ); + System.out.println(String.format("\n%s\n%s", + new ClassIdentity(sourceLoader.loadClass(entry.getKey()), null, sourceIndex, false, false), + new ClassIdentity( destLoader.loadClass(entry.getValue()), null, destIndex, false, false) + )); */ } } @@ -217,52 +190,42 @@ public class ClassMatcher // ie. if we have the mappings a->b, b->c, we have to apply b->c before a->b LinkedHashMap orderedClassChanges = Maps.newLinkedHashMap(); int numChangesLeft = classChanges.size(); - while( !classChanges.isEmpty() ) - { + while (!classChanges.isEmpty()) { Iterator> iter = classChanges.entrySet().iterator(); - while( iter.hasNext() ) - { + while (iter.hasNext()) { Map.Entry entry = iter.next(); - if( classChanges.get( entry.getValue() ) == null ) - { - orderedClassChanges.put( entry.getKey(), entry.getValue() ); + if (classChanges.get(entry.getValue()) == null) { + orderedClassChanges.put(entry.getKey(), entry.getValue()); iter.remove(); } } // did we remove any changes? - if( numChangesLeft - classChanges.size() > 0 ) - { + if (numChangesLeft - classChanges.size() > 0) { // keep going - numChangesLeft = classChanges.size(); - } - else - { + numChangesLeft = classChanges.size(); + } else { // can't sort anymore. There must be a loop break; } } - if( classChanges.size() > 0 ) - { - throw new Error( String.format( "Unable to sort %d/%d class changes!", classChanges.size(), matchedClassNames.size() ) ); + if (classChanges.size() > 0) { + throw new Error(String.format("Unable to sort %d/%d class changes!", classChanges.size(), matchedClassNames.size())); } // convert the mappings in the correct class order - for( Map.Entry entry : orderedClassChanges.entrySet() ) - { - mappings.renameObfClass( entry.getKey(), entry.getValue() ); + for (Map.Entry entry : orderedClassChanges.entrySet()) { + mappings.renameObfClass(entry.getKey(), entry.getValue()); } // check the method matches - System.out.println( "Checking methods..." ); - for( ClassMapping classMapping : mappings.classes() ) - { - ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); - for( MethodMapping methodMapping : classMapping.methods() ) - { + System.out.println("Checking methods..."); + for (ClassMapping classMapping : mappings.classes()) { + ClassEntry classEntry = new ClassEntry(classMapping.getObfName()); + for (MethodMapping methodMapping : classMapping.methods()) { + // skip constructors - if( methodMapping.getObfName().equals( "" ) ) - { + if (methodMapping.getObfName().equals("")) { continue; } @@ -271,56 +234,51 @@ public class ClassMatcher methodMapping.getObfName(), methodMapping.getObfSignature() ); - if( !destIndex.containsObfBehavior( methodEntry ) ) - { - System.err.println( "WARNING: method doesn't match: " + methodEntry ); + if (!destIndex.containsObfBehavior(methodEntry)) { + System.err.println("WARNING: method doesn't match: " + methodEntry); // show the available methods - System.err.println( "\tAvailable dest methods:" ); - CtClass c = destLoader.loadClass( classMapping.getObfName() ); - for( CtBehavior behavior : c.getDeclaredBehaviors() ) - { + System.err.println("\tAvailable dest methods:"); + CtClass c = destLoader.loadClass(classMapping.getObfName()); + for (CtBehavior behavior : c.getDeclaredBehaviors()) { MethodEntry declaredMethodEntry = new MethodEntry( - new ClassEntry( classMapping.getObfName() ), + new ClassEntry(classMapping.getObfName()), behavior.getName(), behavior.getSignature() ); - System.err.println( "\t\t" + declaredMethodEntry ); + System.err.println("\t\t" + declaredMethodEntry); } - System.err.println( "\tAvailable source methods:" ); - c = sourceLoader.loadClass( matchedClassNames.inverse().get( classMapping.getObfName() ) ); - for( CtBehavior behavior : c.getDeclaredBehaviors() ) - { + System.err.println("\tAvailable source methods:"); + c = sourceLoader.loadClass(matchedClassNames.inverse().get(classMapping.getObfName())); + for (CtBehavior behavior : c.getDeclaredBehaviors()) { MethodEntry declaredMethodEntry = new MethodEntry( - new ClassEntry( classMapping.getObfName() ), + new ClassEntry(classMapping.getObfName()), behavior.getName(), behavior.getSignature() ); - System.err.println( "\t\t" + declaredMethodEntry ); + System.err.println("\t\t" + declaredMethodEntry); } } } } - System.out.println( "Done!" ); + System.out.println("Done!"); } - public static ClassMatching computeMatching( JarIndex sourceIndex, TranslatingTypeLoader sourceLoader, JarIndex destIndex, TranslatingTypeLoader destLoader ) - { - System.out.println( "Matching classes..." ); + public static ClassMatching computeMatching(JarIndex sourceIndex, TranslatingTypeLoader sourceLoader, JarIndex destIndex, TranslatingTypeLoader destLoader) { + + System.out.println("Matching classes..."); + ClassMatching matching = null; - for( boolean useReferences : Arrays.asList( false, true ) ) - { + for (boolean useReferences : Arrays.asList(false, true)) { int numMatches = 0; - do - { + do { SidedClassNamer sourceNamer = null; SidedClassNamer destNamer = null; - if( matching != null ) - { + if (matching != null) { // build a class namer - ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); + ClassNamer namer = new ClassNamer(matching.getUniqueMatches()); sourceNamer = namer.getSourceNamer(); destNamer = namer.getDestNamer(); @@ -331,158 +289,126 @@ public class ClassMatcher // get the entries left to match Set sourceClassEntries = Sets.newHashSet(); Set destClassEntries = Sets.newHashSet(); - if( matching == null ) - { - sourceClassEntries.addAll( sourceIndex.getObfClassEntries() ); - destClassEntries.addAll( destIndex.getObfClassEntries() ); + if (matching == null) { + sourceClassEntries.addAll(sourceIndex.getObfClassEntries()); + destClassEntries.addAll(destIndex.getObfClassEntries()); matching = new ClassMatching(); - } - else - { - for( Map.Entry,List> entry : matching.getAmbiguousMatches().entrySet() ) - { - for( ClassIdentity c : entry.getKey() ) - { - sourceClassEntries.add( c.getClassEntry() ); - matching.removeSource( c ); + } else { + for (Map.Entry,List> entry : matching.getAmbiguousMatches().entrySet()) { + for (ClassIdentity c : entry.getKey()) { + sourceClassEntries.add(c.getClassEntry()); + matching.removeSource(c); } - for( ClassIdentity c : entry.getValue() ) - { - destClassEntries.add( c.getClassEntry() ); - matching.removeDest( c ); + for (ClassIdentity c : entry.getValue()) { + destClassEntries.add(c.getClassEntry()); + matching.removeDest(c); } } - for( ClassIdentity c : matching.getUnmatchedSourceClasses() ) - { - sourceClassEntries.add( c.getClassEntry() ); - matching.removeSource( c ); + for (ClassIdentity c : matching.getUnmatchedSourceClasses()) { + sourceClassEntries.add(c.getClassEntry()); + matching.removeSource(c); } - for( ClassIdentity c : matching.getUnmatchedDestClasses() ) - { - destClassEntries.add( c.getClassEntry() ); - matching.removeDest( c ); + for (ClassIdentity c : matching.getUnmatchedDestClasses()) { + destClassEntries.add(c.getClassEntry()); + matching.removeDest(c); } } // compute a matching for the classes - for( ClassEntry classEntry : sourceClassEntries ) - { - CtClass c = sourceLoader.loadClass( classEntry.getName() ); - ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences ); - matching.addSource( sourceClass ); + for (ClassEntry classEntry : sourceClassEntries) { + CtClass c = sourceLoader.loadClass(classEntry.getName()); + ClassIdentity sourceClass = new ClassIdentity(c, sourceNamer, sourceIndex, useReferences); + matching.addSource(sourceClass); } - for( ClassEntry classEntry : destClassEntries ) - { - CtClass c = destLoader.loadClass( classEntry.getName() ); - ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences ); - matching.matchDestClass( destClass ); + for (ClassEntry classEntry : destClassEntries) { + CtClass c = destLoader.loadClass(classEntry.getName()); + ClassIdentity destClass = new ClassIdentity(c, destNamer, destIndex, useReferences); + matching.matchDestClass(destClass); } // TEMP - System.out.println( matching ); - } - while( matching.getUniqueMatches().size() - numMatches > 0 ); + System.out.println(matching); + } while (matching.getUniqueMatches().size() - numMatches > 0); } // check the class matches - System.out.println( "Checking class matches..." ); - ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); + System.out.println("Checking class matches..."); + ClassNamer namer = new ClassNamer(matching.getUniqueMatches()); SidedClassNamer sourceNamer = namer.getSourceNamer(); SidedClassNamer destNamer = namer.getDestNamer(); - for( Map.Entry entry : matching.getUniqueMatches().entrySet() ) - { + for (Map.Entry entry : matching.getUniqueMatches().entrySet()) { + // check source ClassIdentity sourceClass = entry.getKey(); - CtClass sourceC = sourceLoader.loadClass( sourceClass.getClassEntry().getName() ); - assert( sourceC != null ) - : "Unable to load source class " + sourceClass.getClassEntry(); - assert( sourceClass.matches( sourceC ) ) - : "Source " + sourceClass + " doesn't match " + new ClassIdentity( sourceC, sourceNamer, sourceIndex, false ); + CtClass sourceC = sourceLoader.loadClass(sourceClass.getClassEntry().getName()); + assert (sourceC != null) : "Unable to load source class " + sourceClass.getClassEntry(); + assert (sourceClass.matches(sourceC)) : "Source " + sourceClass + " doesn't match " + new ClassIdentity(sourceC, sourceNamer, sourceIndex, false); // check dest ClassIdentity destClass = entry.getValue(); - CtClass destC = destLoader.loadClass( destClass.getClassEntry().getName() ); - assert( destC != null ) - : "Unable to load dest class " + destClass.getClassEntry(); - assert( destClass.matches( destC ) ) - : "Dest " + destClass + " doesn't match " + new ClassIdentity( destC, destNamer, destIndex, false ); + CtClass destC = destLoader.loadClass(destClass.getClassEntry().getName()); + assert (destC != null) : "Unable to load dest class " + destClass.getClassEntry(); + assert (destClass.matches(destC)) : "Dest " + destClass + " doesn't match " + new ClassIdentity(destC, destNamer, destIndex, false); } // warn about the ambiguous matchings - List,List>> ambiguousMatches = new ArrayList,List>>( matching.getAmbiguousMatches().entrySet() ); - Collections.sort( ambiguousMatches, new Comparator,List>>( ) - { + List,List>> ambiguousMatches = new ArrayList,List>>(matching.getAmbiguousMatches().entrySet()); + Collections.sort(ambiguousMatches, new Comparator,List>>() { @Override - public int compare( Map.Entry,List> a, Map.Entry,List> b ) - { - String aName = a.getKey().get( 0 ).getClassEntry().getName(); - String bName = b.getKey().get( 0 ).getClassEntry().getName(); - return aName.compareTo( bName ); + public int compare(Map.Entry,List> a, Map.Entry,List> b) { + String aName = a.getKey().get(0).getClassEntry().getName(); + String bName = b.getKey().get(0).getClassEntry().getName(); + return aName.compareTo(bName); } - } ); - for( Map.Entry,List> entry : ambiguousMatches ) - { - System.out.println( "Ambiguous matching:" ); - System.out.println( "\tSource: " + getClassNames( entry.getKey() ) ); - System.out.println( "\tDest: " + getClassNames( entry.getValue() ) ); + }); + for (Map.Entry,List> entry : ambiguousMatches) { + System.out.println("Ambiguous matching:"); + System.out.println("\tSource: " + getClassNames(entry.getKey())); + System.out.println("\tDest: " + getClassNames(entry.getValue())); } /* DEBUG Map.Entry,List> entry = ambiguousMatches.get( 7 ); - for( ClassIdentity c : entry.getKey() ) - { - System.out.println( c ); + for (ClassIdentity c : entry.getKey()) { + System.out.println(c); } - for( ClassIdentity c : entry.getKey() ) - { - System.out.println( decompile( sourceLoader, c.getClassEntry() ) ); + for(ClassIdentity c : entry.getKey()) { + System.out.println(decompile(sourceLoader, c.getClassEntry())); } */ return matching; } - private static void printScoredMatches( int maxScore, List scores, Multimap scoredMatches ) - { + private static void printScoredMatches(int maxScore, List scores, Multimap scoredMatches) { int numScoredMatchesShown = 0; - for( int score : scores ) - { - for( ClassIdentity scoredMatch : scoredMatches.get( score ) ) - { - System.out.println( String.format( "\tScore: %3d %3.0f%% %s", - score, - 100.0*score/maxScore, - scoredMatch.getClassEntry().getName() - ) ); - - if( numScoredMatchesShown++ > 10 ) - { + for (int score : scores) { + for (ClassIdentity scoredMatch : scoredMatches.get(score)) { + System.out.println(String.format("\tScore: %3d %3.0f%% %s", score, 100.0 * score / maxScore, scoredMatch.getClassEntry().getName())); + if (numScoredMatchesShown++ > 10) { return; } } } } - private static List getClassNames( Collection classes ) - { + private static List getClassNames(Collection classes) { List out = Lists.newArrayList(); - for( ClassIdentity c : classes ) - { - out.add( c.getClassEntry().getName() ); + for (ClassIdentity c : classes) { + out.add(c.getClassEntry().getName()); } - Collections.sort( out ); + Collections.sort(out); return out; } /* DEBUG - private static String decompile( TranslatingTypeLoader loader, ClassEntry classEntry ) - { + private static String decompile(TranslatingTypeLoader loader, ClassEntry classEntry) { PlainTextOutput output = new PlainTextOutput(); DecompilerSettings settings = DecompilerSettings.javaDefaults(); - settings.setForceExplicitImports( true ); - settings.setShowSyntheticMembers( true ); - settings.setTypeLoader( loader ); - Decompiler.decompile( classEntry.getName(), output, settings ); + settings.setForceExplicitImports(true); + settings.setShowSyntheticMembers(true); + settings.setTypeLoader(loader); + Decompiler.decompile(classEntry.getName(), output, settings); return output.toString(); } */ diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java index e45c0e1a..53b6f7f4 100644 --- a/src/cuchaz/enigma/convert/ClassMatching.java +++ b/src/cuchaz/enigma/convert/ClassMatching.java @@ -24,180 +24,150 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; -public class ClassMatching -{ +public class ClassMatching { + private Multimap m_sourceClasses; private Multimap m_matchedDestClasses; private List m_unmatchedDestClasses; - public ClassMatching( ) - { + public ClassMatching() { m_sourceClasses = ArrayListMultimap.create(); m_matchedDestClasses = ArrayListMultimap.create(); m_unmatchedDestClasses = Lists.newArrayList(); } - - public void addSource( ClassIdentity c ) - { - m_sourceClasses.put( c, c ); + + public void addSource(ClassIdentity c) { + m_sourceClasses.put(c, c); } - public void matchDestClass( ClassIdentity destClass ) - { - Collection matchedSourceClasses = m_sourceClasses.get( destClass ); - if( matchedSourceClasses.isEmpty() ) - { + public void matchDestClass(ClassIdentity destClass) { + Collection matchedSourceClasses = m_sourceClasses.get(destClass); + if (matchedSourceClasses.isEmpty()) { // no match - m_unmatchedDestClasses.add( destClass ); - } - else - { + m_unmatchedDestClasses.add(destClass); + } else { // found a match - m_matchedDestClasses.put( destClass, destClass ); + m_matchedDestClasses.put(destClass, destClass); // DEBUG ClassIdentity sourceClass = matchedSourceClasses.iterator().next(); - assert( sourceClass.hashCode() == destClass.hashCode() ); - assert( sourceClass.equals( destClass ) ); + assert (sourceClass.hashCode() == destClass.hashCode()); + assert (sourceClass.equals(destClass)); } } - public void removeSource( ClassIdentity sourceClass ) - { - m_sourceClasses.remove( sourceClass, sourceClass ); + public void removeSource(ClassIdentity sourceClass) { + m_sourceClasses.remove(sourceClass, sourceClass); } - public void removeDest( ClassIdentity destClass ) - { - m_matchedDestClasses.remove( destClass, destClass ); - m_unmatchedDestClasses.remove( destClass ); + public void removeDest(ClassIdentity destClass) { + m_matchedDestClasses.remove(destClass, destClass); + m_unmatchedDestClasses.remove(destClass); } - public List getSourceClasses( ) - { - return new ArrayList( m_sourceClasses.values() ); + public List getSourceClasses() { + return new ArrayList(m_sourceClasses.values()); } - public List getDestClasses( ) - { + public List getDestClasses() { List classes = Lists.newArrayList(); - classes.addAll( m_matchedDestClasses.values() ); - classes.addAll( m_unmatchedDestClasses ); + classes.addAll(m_matchedDestClasses.values()); + classes.addAll(m_unmatchedDestClasses); return classes; } - public BiMap getUniqueMatches( ) - { + public BiMap getUniqueMatches() { BiMap uniqueMatches = HashBiMap.create(); - for( ClassIdentity sourceClass : m_sourceClasses.keySet() ) - { - Collection matchedSourceClasses = m_sourceClasses.get( sourceClass ); - Collection matchedDestClasses = m_matchedDestClasses.get( sourceClass ); - if( matchedSourceClasses.size() == 1 && matchedDestClasses.size() == 1 ) - { + for (ClassIdentity sourceClass : m_sourceClasses.keySet()) { + Collection matchedSourceClasses = m_sourceClasses.get(sourceClass); + Collection matchedDestClasses = m_matchedDestClasses.get(sourceClass); + if (matchedSourceClasses.size() == 1 && matchedDestClasses.size() == 1) { ClassIdentity matchedSourceClass = matchedSourceClasses.iterator().next(); ClassIdentity matchedDestClass = matchedDestClasses.iterator().next(); - uniqueMatches.put( matchedSourceClass, matchedDestClass ); + uniqueMatches.put(matchedSourceClass, matchedDestClass); } } return uniqueMatches; } - public BiMap,List> getAmbiguousMatches( ) - { + public BiMap,List> getAmbiguousMatches() { BiMap,List> ambiguousMatches = HashBiMap.create(); - for( ClassIdentity sourceClass : m_sourceClasses.keySet() ) - { - Collection matchedSourceClasses = m_sourceClasses.get( sourceClass ); - Collection matchedDestClasses = m_matchedDestClasses.get( sourceClass ); - if( matchedSourceClasses.size() > 1 && matchedDestClasses.size() > 1 ) - { + for (ClassIdentity sourceClass : m_sourceClasses.keySet()) { + Collection matchedSourceClasses = m_sourceClasses.get(sourceClass); + Collection matchedDestClasses = m_matchedDestClasses.get(sourceClass); + if (matchedSourceClasses.size() > 1 && matchedDestClasses.size() > 1) { ambiguousMatches.put( - new ArrayList( matchedSourceClasses ), - new ArrayList( matchedDestClasses ) + new ArrayList(matchedSourceClasses), + new ArrayList(matchedDestClasses) ); } } return ambiguousMatches; } - public int getNumAmbiguousSourceMatches( ) - { + public int getNumAmbiguousSourceMatches() { int num = 0; - for( Map.Entry,List> entry : getAmbiguousMatches().entrySet() ) - { + for (Map.Entry,List> entry : getAmbiguousMatches().entrySet()) { num += entry.getKey().size(); } return num; } - public int getNumAmbiguousDestMatches( ) - { + public int getNumAmbiguousDestMatches() { int num = 0; - for( Map.Entry,List> entry : getAmbiguousMatches().entrySet() ) - { + for (Map.Entry,List> entry : getAmbiguousMatches().entrySet()) { num += entry.getValue().size(); } return num; } - public List getUnmatchedSourceClasses( ) - { + public List getUnmatchedSourceClasses() { List classes = Lists.newArrayList(); - for( ClassIdentity sourceClass : getSourceClasses() ) - { - if( m_matchedDestClasses.get( sourceClass ).isEmpty() ) - { - classes.add( sourceClass ); + for (ClassIdentity sourceClass : getSourceClasses()) { + if (m_matchedDestClasses.get(sourceClass).isEmpty()) { + classes.add(sourceClass); } } return classes; } - public List getUnmatchedDestClasses( ) - { - return new ArrayList( m_unmatchedDestClasses ); + public List getUnmatchedDestClasses() { + return new ArrayList(m_unmatchedDestClasses); } - public Map>> getIndex( ) - { + public Map>> getIndex() { Map>> conversion = Maps.newHashMap(); - for( Map.Entry entry : getUniqueMatches().entrySet() ) - { + for (Map.Entry entry : getUniqueMatches().entrySet()) { conversion.put( entry.getKey().getClassEntry().getName(), - new AbstractMap.SimpleEntry>( entry.getKey(), Arrays.asList( entry.getValue() ) ) + new AbstractMap.SimpleEntry>(entry.getKey(), Arrays.asList(entry.getValue())) ); } - for( Map.Entry,List> entry : getAmbiguousMatches().entrySet() ) - { - for( ClassIdentity sourceClass : entry.getKey() ) - { + for (Map.Entry,List> entry : getAmbiguousMatches().entrySet()) { + for (ClassIdentity sourceClass : entry.getKey()) { conversion.put( sourceClass.getClassEntry().getName(), - new AbstractMap.SimpleEntry>( sourceClass, entry.getValue() ) + new AbstractMap.SimpleEntry>(sourceClass, entry.getValue()) ); } } - for( ClassIdentity sourceClass : getUnmatchedSourceClasses() ) - { + for (ClassIdentity sourceClass : getUnmatchedSourceClasses()) { conversion.put( sourceClass.getClassEntry().getName(), - new AbstractMap.SimpleEntry>( sourceClass, getUnmatchedDestClasses() ) + new AbstractMap.SimpleEntry>(sourceClass, getUnmatchedDestClasses()) ); } return conversion; } @Override - public String toString( ) - { + public String toString() { StringBuilder buf = new StringBuilder(); - buf.append( String.format( "%12s%8s%8s\n", "", "Source", "Dest" ) ); - buf.append( String.format( "%12s%8d%8d\n", "Classes", getSourceClasses().size(), getDestClasses().size() ) ); - buf.append( String.format( "%12s%8d%8d\n", "Unique", getUniqueMatches().size(), getUniqueMatches().size() ) ); - buf.append( String.format( "%12s%8d%8d\n", "Ambiguous", getNumAmbiguousSourceMatches(), getNumAmbiguousDestMatches() ) ); - buf.append( String.format( "%12s%8d%8d\n", "Unmatched", getUnmatchedSourceClasses().size(), getUnmatchedDestClasses().size() ) ); + buf.append(String.format("%12s%8s%8s\n", "", "Source", "Dest")); + buf.append(String.format("%12s%8d%8d\n", "Classes", getSourceClasses().size(), getDestClasses().size())); + buf.append(String.format("%12s%8d%8d\n", "Unique", getUniqueMatches().size(), getUniqueMatches().size())); + buf.append(String.format("%12s%8d%8d\n", "Ambiguous", getNumAmbiguousSourceMatches(), getNumAmbiguousDestMatches())); + buf.append(String.format("%12s%8d%8d\n", "Unmatched", getUnmatchedSourceClasses().size(), getUnmatchedDestClasses().size())); return buf.toString(); } } diff --git a/src/cuchaz/enigma/convert/ClassNamer.java b/src/cuchaz/enigma/convert/ClassNamer.java index a01aec5c..1b6e81c8 100644 --- a/src/cuchaz/enigma/convert/ClassNamer.java +++ b/src/cuchaz/enigma/convert/ClassNamer.java @@ -15,60 +15,49 @@ import java.util.Map; import com.google.common.collect.BiMap; import com.google.common.collect.Maps; -public class ClassNamer -{ - public interface SidedClassNamer - { - String getName( String name ); +public class ClassNamer { + + public interface SidedClassNamer { + String getName(String name); } private Map m_sourceNames; private Map m_destNames; - public ClassNamer( BiMap mappings ) - { + public ClassNamer(BiMap mappings) { // convert the identity mappings to name maps m_sourceNames = Maps.newHashMap(); m_destNames = Maps.newHashMap(); int i = 0; - for( Map.Entry entry : mappings.entrySet() ) - { - String name = String.format( "M%04d", i++ ); - m_sourceNames.put( entry.getKey().getClassEntry().getName(), name ); - m_destNames.put( entry.getValue().getClassEntry().getName(), name ); + for (Map.Entry entry : mappings.entrySet()) { + String name = String.format("M%04d", i++); + m_sourceNames.put(entry.getKey().getClassEntry().getName(), name); + m_destNames.put(entry.getValue().getClassEntry().getName(), name); } } - public String getSourceName( String name ) - { - return m_sourceNames.get( name ); + public String getSourceName(String name) { + return m_sourceNames.get(name); } - public String getDestName( String name ) - { - return m_destNames.get( name ); + public String getDestName(String name) { + return m_destNames.get(name); } - public SidedClassNamer getSourceNamer( ) - { - return new SidedClassNamer( ) - { + public SidedClassNamer getSourceNamer() { + return new SidedClassNamer() { @Override - public String getName( String name ) - { - return getSourceName( name ); + public String getName(String name) { + return getSourceName(name); } }; } - public SidedClassNamer getDestNamer( ) - { - return new SidedClassNamer( ) - { + public SidedClassNamer getDestNamer() { + return new SidedClassNamer() { @Override - public String getName( String name ) - { - return getDestName( name ); + public String getName(String name) { + return getDestName(name); } }; } diff --git a/src/cuchaz/enigma/gui/AboutDialog.java b/src/cuchaz/enigma/gui/AboutDialog.java index a245956e..2476b564 100644 --- a/src/cuchaz/enigma/gui/AboutDialog.java +++ b/src/cuchaz/enigma/gui/AboutDialog.java @@ -27,68 +27,60 @@ import javax.swing.WindowConstants; import cuchaz.enigma.Constants; import cuchaz.enigma.Util; -public class AboutDialog -{ - public static void show( JFrame parent ) - { +public class AboutDialog { + + public static void show(JFrame parent) { // init frame - final JFrame frame = new JFrame( Constants.Name + " - About" ); + final JFrame frame = new JFrame(Constants.Name + " - About"); final Container pane = frame.getContentPane(); - pane.setLayout( new FlowLayout() ); + 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 ); + 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( ) - { + 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 ); + 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 ); + }); + 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 ); + linkPanel.add(link); + pane.add(linkPanel); // show ok button - JButton okButton = new JButton( "Ok" ); - pane.add( okButton ); - okButton.addActionListener( new ActionListener( ) - { + JButton okButton = new JButton("Ok"); + pane.add(okButton); + okButton.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent arg0 ) - { + 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 ); + 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/BoxHighlightPainter.java b/src/cuchaz/enigma/gui/BoxHighlightPainter.java index df63f5a8..db7c85b4 100644 --- a/src/cuchaz/enigma/gui/BoxHighlightPainter.java +++ b/src/cuchaz/enigma/gui/BoxHighlightPainter.java @@ -19,40 +19,35 @@ import javax.swing.text.BadLocationException; import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; -public abstract class BoxHighlightPainter implements Highlighter.HighlightPainter -{ +public abstract class BoxHighlightPainter implements Highlighter.HighlightPainter { + private Color m_fillColor; private Color m_borderColor; - protected BoxHighlightPainter( Color fillColor, Color 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 ) - { - Rectangle bounds = getBounds( text, start, end ); + public void paint(Graphics g, int start, int end, Shape shape, JTextComponent text) { + Rectangle bounds = getBounds(text, start, end); // fill the area - if( m_fillColor != null ) - { - g.setColor( m_fillColor ); - g.fillRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); + if (m_fillColor != null) { + g.setColor(m_fillColor); + g.fillRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); } // draw a box around the area - g.setColor( m_borderColor ); - g.drawRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); + g.setColor(m_borderColor); + g.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); } - protected static Rectangle getBounds( JTextComponent text, int start, int end ) - { - try - { + protected static Rectangle getBounds(JTextComponent text, int start, int end) { + try { // determine the bounds of the text - Rectangle bounds = text.modelToView( start ).union( text.modelToView( end ) ); + Rectangle bounds = text.modelToView(start).union(text.modelToView(end)); // adjust the box so it looks nice bounds.x -= 2; @@ -61,11 +56,9 @@ public abstract class BoxHighlightPainter implements Highlighter.HighlightPainte bounds.height -= 2; return bounds; - } - catch( BadLocationException ex ) - { + } catch (BadLocationException ex) { // don't care... just return something - return new Rectangle( 0, 0, 0, 0 ); + return new Rectangle(0, 0, 0, 0); } } } diff --git a/src/cuchaz/enigma/gui/BrowserCaret.java b/src/cuchaz/enigma/gui/BrowserCaret.java index f7e608bb..acee4833 100644 --- a/src/cuchaz/enigma/gui/BrowserCaret.java +++ b/src/cuchaz/enigma/gui/BrowserCaret.java @@ -17,34 +17,29 @@ import javax.swing.text.DefaultCaret; import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; -public class BrowserCaret extends DefaultCaret -{ +public class BrowserCaret extends DefaultCaret { + private static final long serialVersionUID = 1158977422507969940L; - private static final Highlighter.HighlightPainter m_selectionPainter = new Highlighter.HighlightPainter( ) - { + private static final Highlighter.HighlightPainter m_selectionPainter = new Highlighter.HighlightPainter() { @Override - public void paint( Graphics g, int p0, int p1, Shape bounds, JTextComponent c ) - { + public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c) { // don't paint anything } }; @Override - public boolean isSelectionVisible( ) - { + public boolean isSelectionVisible() { return false; } - + @Override - public boolean isVisible( ) - { + public boolean isVisible() { return true; } @Override - public Highlighter.HighlightPainter getSelectionPainter( ) - { + public Highlighter.HighlightPainter getSelectionPainter() { return m_selectionPainter; } } diff --git a/src/cuchaz/enigma/gui/ClassListCellRenderer.java b/src/cuchaz/enigma/gui/ClassListCellRenderer.java index d9d65788..d0f01e6a 100644 --- a/src/cuchaz/enigma/gui/ClassListCellRenderer.java +++ b/src/cuchaz/enigma/gui/ClassListCellRenderer.java @@ -19,20 +19,18 @@ import javax.swing.JLabel; import javax.swing.JList; import javax.swing.ListCellRenderer; -public class ClassListCellRenderer implements ListCellRenderer -{ +public class ClassListCellRenderer implements ListCellRenderer { + private DefaultListCellRenderer m_defaultRenderer; - public ClassListCellRenderer( ) - { + public ClassListCellRenderer() { m_defaultRenderer = new DefaultListCellRenderer(); } @Override - public Component getListCellRendererComponent( JList list, String className, int index, boolean isSelected, boolean hasFocus ) - { - JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, className, index, isSelected, hasFocus ); - label.setText( Descriptor.toJavaName( className ) ); + public Component getListCellRendererComponent(JList list, String className, int index, boolean isSelected, boolean hasFocus) { + JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent(list, className, index, isSelected, hasFocus); + label.setText(Descriptor.toJavaName(className)); return label; } } diff --git a/src/cuchaz/enigma/gui/ClassSelector.java b/src/cuchaz/enigma/gui/ClassSelector.java index 8365def1..654bfbed 100644 --- a/src/cuchaz/enigma/gui/ClassSelector.java +++ b/src/cuchaz/enigma/gui/ClassSelector.java @@ -30,39 +30,32 @@ import com.google.common.collect.Multimap; import cuchaz.enigma.mapping.ClassEntry; -public class ClassSelector extends JTree -{ +public class ClassSelector extends JTree { + private static final long serialVersionUID = -7632046902384775977L; - public interface ClassSelectionListener - { - void onSelectClass( ClassEntry classEntry ); + public interface ClassSelectionListener { + void onSelectClass(ClassEntry classEntry); } public static Comparator ObfuscatedClassEntryComparator; public static Comparator DeobfuscatedClassEntryComparator; - static - { - ObfuscatedClassEntryComparator = new Comparator( ) - { + static { + ObfuscatedClassEntryComparator = new Comparator() { @Override - public int compare( ClassEntry a, ClassEntry b ) - { - if( a.getName().length() != b.getName().length() ) - { + public int compare(ClassEntry a, ClassEntry b) { + if (a.getName().length() != b.getName().length()) { return a.getName().length() - b.getName().length(); } - return a.getName().compareTo( b.getName() ); + return a.getName().compareTo(b.getName()); } }; - DeobfuscatedClassEntryComparator = new Comparator( ) - { + DeobfuscatedClassEntryComparator = new Comparator() { @Override - public int compare( ClassEntry a, ClassEntry b ) - { - return a.getName().compareTo( b.getName() ); + public int compare(ClassEntry a, ClassEntry b) { + return a.getName().compareTo(b.getName()); } }; } @@ -70,122 +63,102 @@ public class ClassSelector extends JTree private ClassSelectionListener m_listener; private Comparator m_comparator; - public ClassSelector( Comparator comparator ) - { + public ClassSelector(Comparator comparator) { m_comparator = comparator; // configure the tree control - setRootVisible( false ); - setShowsRootHandles( false ); - setModel( null ); + setRootVisible(false); + setShowsRootHandles(false); + setModel(null); // hook events - addMouseListener( new MouseAdapter() - { + addMouseListener(new MouseAdapter() { @Override - public void mouseClicked( MouseEvent event ) - { - if( m_listener != null && event.getClickCount() == 2 ) - { + public void mouseClicked(MouseEvent event) { + if (m_listener != null && event.getClickCount() == 2) { // get the selected node TreePath path = getSelectionPath(); - if( path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode ) - { + if (path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode) { ClassSelectorClassNode node = (ClassSelectorClassNode)path.getLastPathComponent(); - m_listener.onSelectClass( node.getClassEntry() ); + m_listener.onSelectClass(node.getClassEntry()); } } } - } ); + }); // init defaults m_listener = null; } - public void setListener( ClassSelectionListener val ) - { + public void setListener(ClassSelectionListener val) { m_listener = val; } - public void setClasses( Collection classEntries ) - { - if( classEntries == null ) - { - setModel( null ); + public void setClasses(Collection classEntries) { + if (classEntries == null) { + setModel(null); return; } // build the package names Map packages = Maps.newHashMap(); - for( ClassEntry classEntry : classEntries ) - { - packages.put( classEntry.getPackageName(), null ); + for (ClassEntry classEntry : classEntries) { + packages.put(classEntry.getPackageName(), null); } // sort the packages - List sortedPackageNames = Lists.newArrayList( packages.keySet() ); - Collections.sort( sortedPackageNames, new Comparator( ) - { + List sortedPackageNames = Lists.newArrayList(packages.keySet()); + Collections.sort(sortedPackageNames, new Comparator() { @Override - public int compare( String a, String b ) - { + public int compare(String a, String b) { // I can never keep this rule straight when writing these damn things... // a < b => -1, a == b => 0, a > b => +1 - String[] aparts = a.split( "/" ); - String[] bparts = b.split( "/" ); - for( int i=0; true; i++ ) - { - if( i >= aparts.length ) - { + String[] aparts = a.split("/"); + String[] bparts = b.split("/"); + for (int i = 0; true; i++) { + if (i >= aparts.length) { return -1; - } - else if( i >= bparts.length ) - { + } else if (i >= bparts.length) { return 1; } - int result = aparts[i].compareTo( bparts[i] ); - if( result != 0 ) - { + int result = aparts[i].compareTo(bparts[i]); + if (result != 0) { return result; } } } - } ); + }); // create the root node and the package nodes DefaultMutableTreeNode root = new DefaultMutableTreeNode(); - for( String packageName : sortedPackageNames ) - { - ClassSelectorPackageNode node = new ClassSelectorPackageNode( packageName ); - packages.put( packageName, node ); - root.add( node ); + for (String packageName : sortedPackageNames) { + ClassSelectorPackageNode node = new ClassSelectorPackageNode(packageName); + packages.put(packageName, node); + root.add(node); } // put the classes into packages Multimap packagedClassEntries = ArrayListMultimap.create(); - for( ClassEntry classEntry : classEntries ) - { - packagedClassEntries.put( classEntry.getPackageName(), classEntry ); + for (ClassEntry classEntry : classEntries) { + packagedClassEntries.put(classEntry.getPackageName(), classEntry); } // build the class nodes - for( String packageName : packagedClassEntries.keySet() ) - { + for (String packageName : packagedClassEntries.keySet()) { // sort the class entries - List classEntriesInPackage = Lists.newArrayList( packagedClassEntries.get( packageName ) ); - Collections.sort( classEntriesInPackage, m_comparator ); + List classEntriesInPackage = Lists.newArrayList(packagedClassEntries.get(packageName)); + Collections.sort(classEntriesInPackage, m_comparator); // create the nodes in order - for( ClassEntry classEntry : classEntriesInPackage ) - { - ClassSelectorPackageNode node = packages.get( packageName ); - node.add( new ClassSelectorClassNode( classEntry ) ); + for (ClassEntry classEntry : classEntriesInPackage) { + ClassSelectorPackageNode node = packages.get(packageName); + node.add(new ClassSelectorClassNode(classEntry)); } } // finally, update the tree control - setModel( new DefaultTreeModel( root ) ); + setModel(new DefaultTreeModel(root)); } } diff --git a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java index cffa7952..66e931b4 100644 --- a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java +++ b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java @@ -14,25 +14,22 @@ import javax.swing.tree.DefaultMutableTreeNode; import cuchaz.enigma.mapping.ClassEntry; -public class ClassSelectorClassNode extends DefaultMutableTreeNode -{ +public class ClassSelectorClassNode extends DefaultMutableTreeNode { + private static final long serialVersionUID = -8956754339813257380L; private ClassEntry m_classEntry; - public ClassSelectorClassNode( ClassEntry classEntry ) - { + public ClassSelectorClassNode(ClassEntry classEntry) { m_classEntry = classEntry; } - public ClassEntry getClassEntry( ) - { + public ClassEntry getClassEntry() { return m_classEntry; } @Override - public String toString( ) - { + public String toString() { return m_classEntry.getSimpleName(); } } diff --git a/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java b/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java index ad88fb44..451d3809 100644 --- a/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java +++ b/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java @@ -12,25 +12,22 @@ package cuchaz.enigma.gui; import javax.swing.tree.DefaultMutableTreeNode; -public class ClassSelectorPackageNode extends DefaultMutableTreeNode -{ +public class ClassSelectorPackageNode extends DefaultMutableTreeNode { + private static final long serialVersionUID = -3730868701219548043L; private String m_packageName; - public ClassSelectorPackageNode( String packageName ) - { + public ClassSelectorPackageNode(String packageName) { m_packageName = packageName; } - public String getPackageName( ) - { + public String getPackageName() { return m_packageName; } @Override - public String toString( ) - { + public String toString() { return m_packageName; } } diff --git a/src/cuchaz/enigma/gui/CrashDialog.java b/src/cuchaz/enigma/gui/CrashDialog.java index 0eb9830c..360091ab 100644 --- a/src/cuchaz/enigma/gui/CrashDialog.java +++ b/src/cuchaz/enigma/gui/CrashDialog.java @@ -29,80 +29,73 @@ import javax.swing.WindowConstants; import cuchaz.enigma.Constants; -public class CrashDialog -{ +public class CrashDialog { + private static CrashDialog m_instance = null; private JFrame m_frame; private JTextArea m_text; - private CrashDialog( JFrame parent ) - { + private CrashDialog(JFrame parent) { // init frame - m_frame = new JFrame( Constants.Name + " - Crash Report" ); + m_frame = new JFrame(Constants.Name + " - Crash Report"); final Container pane = m_frame.getContentPane(); - pane.setLayout( new BorderLayout() ); + pane.setLayout(new BorderLayout()); - JLabel label = new JLabel( Constants.Name + " has crashed! =(" ); - label.setBorder( BorderFactory.createEmptyBorder( 10, 10, 10, 10 ) ); - pane.add( label, BorderLayout.NORTH ); + JLabel label = new JLabel(Constants.Name + " has crashed! =("); + label.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + pane.add(label, BorderLayout.NORTH); // report panel m_text = new JTextArea(); - m_text.setTabSize( 2 ); - pane.add( new JScrollPane( m_text ), BorderLayout.CENTER ); + m_text.setTabSize(2); + pane.add(new JScrollPane(m_text), BorderLayout.CENTER); // buttons panel JPanel buttonsPanel = new JPanel(); FlowLayout buttonsLayout = new FlowLayout(); - buttonsLayout.setAlignment( FlowLayout.RIGHT ); - buttonsPanel.setLayout( buttonsLayout ); - buttonsPanel.add( GuiTricks.unboldLabel( new JLabel( "If you choose exit, you will lose any unsaved work." ) ) ); - JButton ignoreButton = new JButton( "Ignore" ); - ignoreButton.addActionListener( new ActionListener( ) - { + buttonsLayout.setAlignment(FlowLayout.RIGHT); + buttonsPanel.setLayout(buttonsLayout); + buttonsPanel.add(GuiTricks.unboldLabel(new JLabel("If you choose exit, you will lose any unsaved work."))); + JButton ignoreButton = new JButton("Ignore"); + ignoreButton.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { + public void actionPerformed(ActionEvent event) { // close (hide) the dialog - m_frame.setVisible( false ); + m_frame.setVisible(false); } - } ); - buttonsPanel.add( ignoreButton ); - JButton exitButton = new JButton( "Exit" ); - exitButton.addActionListener( new ActionListener( ) - { + }); + buttonsPanel.add(ignoreButton); + JButton exitButton = new JButton("Exit"); + exitButton.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { + public void actionPerformed(ActionEvent event) { // exit enigma - System.exit( 1 ); + System.exit(1); } - } ); - buttonsPanel.add( exitButton ); - pane.add( buttonsPanel, BorderLayout.SOUTH ); + }); + buttonsPanel.add(exitButton); + pane.add(buttonsPanel, BorderLayout.SOUTH); // show the frame - m_frame.setSize( 600, 400 ); - m_frame.setLocationRelativeTo( parent ); - m_frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); + m_frame.setSize(600, 400); + m_frame.setLocationRelativeTo(parent); + m_frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); } - public static void init( JFrame parent ) - { - m_instance = new CrashDialog( parent ); + public static void init(JFrame parent) { + m_instance = new CrashDialog(parent); } - public static void show( Throwable ex ) - { + public static void show(Throwable ex) { // get the error report StringWriter buf = new StringWriter(); - ex.printStackTrace( new PrintWriter( buf ) ); + ex.printStackTrace(new PrintWriter(buf)); String report = buf.toString(); // show it! - m_instance.m_text.setText( report ); + m_instance.m_text.setText(report); m_instance.m_frame.doLayout(); - m_instance.m_frame.setVisible( true ); + m_instance.m_frame.setVisible(true); } } diff --git a/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java b/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java index 6a428842..26a31639 100644 --- a/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java +++ b/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java @@ -12,11 +12,10 @@ package cuchaz.enigma.gui; import java.awt.Color; -public class DeobfuscatedHighlightPainter extends BoxHighlightPainter -{ - public DeobfuscatedHighlightPainter( ) - { +public class DeobfuscatedHighlightPainter extends BoxHighlightPainter { + + public DeobfuscatedHighlightPainter() { // green ish - super( new Color( 220, 255, 220 ), new Color( 80, 160, 80 ) ); + 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 faa9b7b1..86ba93b2 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -88,8 +88,8 @@ import cuchaz.enigma.mapping.IllegalNameException; import cuchaz.enigma.mapping.MappingParseException; import cuchaz.enigma.mapping.MethodEntry; -public class Gui -{ +public class Gui { + private GuiController m_controller; // controls @@ -133,81 +133,74 @@ public class Gui private JFileChooser m_exportSourceFileChooser; private JFileChooser m_exportJarFileChooser; - public Gui( ) - { + public Gui() { + // init frame - m_frame = new JFrame( Constants.Name ); + m_frame = new JFrame(Constants.Name); final Container pane = m_frame.getContentPane(); - pane.setLayout( new BorderLayout() ); + pane.setLayout(new BorderLayout()); - if( Boolean.parseBoolean( System.getProperty( "enigma.catchExceptions", "true" ) ) ) - { + if (Boolean.parseBoolean(System.getProperty("enigma.catchExceptions", "true"))) { // install a global exception handler to the event thread - CrashDialog.init( m_frame ); - Thread.setDefaultUncaughtExceptionHandler( new UncaughtExceptionHandler( ) - { + CrashDialog.init(m_frame); + Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override - public void uncaughtException( Thread thread, Throwable ex ) - { - ex.printStackTrace( System.err ); - CrashDialog.show( ex ); + public void uncaughtException(Thread thread, Throwable ex) { + ex.printStackTrace(System.err); + CrashDialog.show(ex); } - } ); + }); } - m_controller = new GuiController( this ); + m_controller = new GuiController(this); // init file choosers m_jarFileChooser = new JFileChooser(); m_mappingsFileChooser = new JFileChooser(); m_exportSourceFileChooser = new JFileChooser(); - m_exportSourceFileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); + m_exportSourceFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); m_exportJarFileChooser = new JFileChooser(); // init obfuscated classes list - m_obfClasses = new ClassSelector( ClassSelector.ObfuscatedClassEntryComparator ); - m_obfClasses.setListener( new ClassSelectionListener( ) - { + m_obfClasses = new ClassSelector(ClassSelector.ObfuscatedClassEntryComparator); + m_obfClasses.setListener(new ClassSelectionListener() { @Override - public void onSelectClass( ClassEntry classEntry ) - { - navigateTo( classEntry ); + public void onSelectClass(ClassEntry classEntry) { + navigateTo(classEntry); } - } ); - JScrollPane obfScroller = new JScrollPane( m_obfClasses ); + }); + JScrollPane obfScroller = new JScrollPane(m_obfClasses); JPanel obfPanel = new JPanel(); - obfPanel.setLayout( new BorderLayout() ); - obfPanel.add( new JLabel( "Obfuscated Classes" ), BorderLayout.NORTH ); - obfPanel.add( obfScroller, BorderLayout.CENTER ); + obfPanel.setLayout(new BorderLayout()); + obfPanel.add(new JLabel("Obfuscated Classes"), BorderLayout.NORTH); + obfPanel.add(obfScroller, BorderLayout.CENTER); // init deobfuscated classes list - m_deobfClasses = new ClassSelector( ClassSelector.DeobfuscatedClassEntryComparator ); - m_deobfClasses.setListener( new ClassSelectionListener( ) - { + m_deobfClasses = new ClassSelector(ClassSelector.DeobfuscatedClassEntryComparator); + m_deobfClasses.setListener(new ClassSelectionListener() { @Override - public void onSelectClass( ClassEntry classEntry ) - { - navigateTo( classEntry ); + public void onSelectClass(ClassEntry classEntry) { + navigateTo(classEntry); } - } ); - JScrollPane deobfScroller = new JScrollPane( m_deobfClasses ); + }); + JScrollPane deobfScroller = new JScrollPane(m_deobfClasses); JPanel deobfPanel = new JPanel(); - deobfPanel.setLayout( new BorderLayout() ); - deobfPanel.add( new JLabel( "De-obfuscated Classes" ), BorderLayout.NORTH ); - deobfPanel.add( deobfScroller, BorderLayout.CENTER ); + deobfPanel.setLayout(new BorderLayout()); + deobfPanel.add(new JLabel("De-obfuscated Classes"), BorderLayout.NORTH); + deobfPanel.add(deobfScroller, BorderLayout.CENTER); // set up classes panel (don't add the splitter yet) - m_splitClasses = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); - m_splitClasses.setResizeWeight( 0.3 ); + m_splitClasses = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel); + m_splitClasses.setResizeWeight(0.3); m_classesPanel = new JPanel(); - m_classesPanel.setLayout( new BorderLayout() ); - m_classesPanel.setPreferredSize( new Dimension( 250, 0 ) ); + m_classesPanel.setLayout(new BorderLayout()); + m_classesPanel.setPreferredSize(new Dimension(250, 0)); // 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" ) ); + m_infoPanel.setLayout(new GridLayout(4, 1, 0, 0)); + m_infoPanel.setPreferredSize(new Dimension(0, 100)); + m_infoPanel.setBorder(BorderFactory.createTitledBorder("Identifier Info")); clearReference(); // init editor @@ -217,25 +210,20 @@ public class Gui m_otherHighlightPainter = new OtherHighlightPainter(); m_selectionHighlightPainter = new SelectionHighlightPainter(); 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( ) - { + 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() { @Override - public void caretUpdate( CaretEvent event ) - { - onCaretMove( event.getDot() ); + public void caretUpdate(CaretEvent event) { + onCaretMove(event.getDot()); } - } ); - m_editor.addKeyListener( new KeyAdapter( ) - { + }); + m_editor.addKeyListener(new KeyAdapter() { @Override - public void keyPressed( KeyEvent event ) - { - switch( event.getKeyCode() ) - { + public void keyPressed(KeyEvent event) { + switch (event.getKeyCode()) { case KeyEvent.VK_R: m_renameMenu.doClick(); break; @@ -265,713 +253,594 @@ public class Gui 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" ); + kit.toggleComponent(m_editor, "jsyntaxpane.components.TokenMarker"); // init editor popup menu JPopupMenu popupMenu = new JPopupMenu(); - m_editor.setComponentPopupMenu( popupMenu ); + m_editor.setComponentPopupMenu(popupMenu); { - JMenuItem menu = new JMenuItem( "Rename" ); - menu.addActionListener( new ActionListener( ) - { + JMenuItem menu = new JMenuItem("Rename"); + menu.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { + public void actionPerformed(ActionEvent event) { startRename(); } - } ); - menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_R, 0 ) ); - menu.setEnabled( false ); - popupMenu.add( menu ); + }); + menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0)); + menu.setEnabled(false); + popupMenu.add(menu); m_renameMenu = menu; } { - JMenuItem menu = new JMenuItem( "Show Inheritance" ); - menu.addActionListener( new ActionListener( ) - { + JMenuItem menu = new JMenuItem("Show Inheritance"); + menu.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { + public void actionPerformed(ActionEvent event) { showInheritance(); } - } ); - menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_I, 0 ) ); - menu.setEnabled( false ); - popupMenu.add( menu ); + }); + menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, 0)); + menu.setEnabled(false); + popupMenu.add(menu); m_showInheritanceMenu = menu; } { - JMenuItem menu = new JMenuItem( "Show Implementations" ); - menu.addActionListener( new ActionListener( ) - { + JMenuItem menu = new JMenuItem("Show Implementations"); + menu.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { + public void actionPerformed(ActionEvent event) { showImplementations(); } - } ); - menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_M, 0 ) ); - menu.setEnabled( false ); - popupMenu.add( menu ); + }); + menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, 0)); + menu.setEnabled(false); + popupMenu.add(menu); m_showImplementationsMenu = menu; } { - JMenuItem menu = new JMenuItem( "Show Calls" ); - menu.addActionListener( new ActionListener( ) - { + JMenuItem menu = new JMenuItem("Show Calls"); + menu.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { + public void actionPerformed(ActionEvent event) { showCalls(); } - } ); - menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_C, 0 ) ); - menu.setEnabled( false ); - popupMenu.add( menu ); + }); + menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, 0)); + menu.setEnabled(false); + popupMenu.add(menu); m_showCallsMenu = menu; } { - JMenuItem menu = new JMenuItem( "Go to Declaration" ); - menu.addActionListener( new ActionListener( ) - { + JMenuItem menu = new JMenuItem("Go to Declaration"); + menu.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { - navigateTo( m_reference.entry ); + public void actionPerformed(ActionEvent event) { + navigateTo(m_reference.entry); } - } ); - menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_N, 0 ) ); - menu.setEnabled( false ); - popupMenu.add( menu ); + }); + menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, 0)); + menu.setEnabled(false); + popupMenu.add(menu); m_openEntryMenu = menu; } { - JMenuItem menu = new JMenuItem( "Go to previous" ); - menu.addActionListener( new ActionListener( ) - { + JMenuItem menu = new JMenuItem("Go to previous"); + menu.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { + public void actionPerformed(ActionEvent event) { m_controller.openPreviousReference(); } - } ); - menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_P, 0 ) ); - menu.setEnabled( false ); - popupMenu.add( menu ); + }); + menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0)); + menu.setEnabled(false); + popupMenu.add(menu); m_openPreviousMenu = menu; } { - JMenuItem menu = new JMenuItem( "Mark as deobfuscated" ); - menu.addActionListener( new ActionListener( ) - { + JMenuItem menu = new JMenuItem("Mark as deobfuscated"); + menu.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { + public void actionPerformed(ActionEvent event) { toggleMapping(); } - } ); - menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_T, 0 ) ); - menu.setEnabled( false ); - popupMenu.add( menu ); + }); + menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0)); + menu.setEnabled(false); + popupMenu.add(menu); m_toggleMappingMenu = menu; } // init inheritance panel m_inheritanceTree = new JTree(); - m_inheritanceTree.setModel( null ); - m_inheritanceTree.addMouseListener( new MouseAdapter( ) - { + m_inheritanceTree.setModel(null); + m_inheritanceTree.addMouseListener(new MouseAdapter() { @Override - public void mouseClicked( MouseEvent event ) - { - if( event.getClickCount() == 2 ) - { + public void mouseClicked(MouseEvent event) { + if (event.getClickCount() == 2) { // get the selected node TreePath path = m_inheritanceTree.getSelectionPath(); - if( path == null ) - { + if (path == null) { return; } Object node = path.getLastPathComponent(); - if( node instanceof ClassInheritanceTreeNode ) - { + if (node instanceof ClassInheritanceTreeNode) { ClassInheritanceTreeNode classNode = (ClassInheritanceTreeNode)node; - navigateTo( new ClassEntry( classNode.getObfClassName() ) ); - } - else if( node instanceof MethodInheritanceTreeNode ) - { + navigateTo(new ClassEntry(classNode.getObfClassName())); + } else if (node instanceof MethodInheritanceTreeNode) { MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode)node; - if( methodNode.isImplemented() ) - { - navigateTo( methodNode.getMethodEntry() ); + if (methodNode.isImplemented()) { + navigateTo(methodNode.getMethodEntry()); } } } } - } ); + }); JPanel inheritancePanel = new JPanel(); - inheritancePanel.setLayout( new BorderLayout() ); - inheritancePanel.add( new JScrollPane( m_inheritanceTree ) ); + inheritancePanel.setLayout(new BorderLayout()); + inheritancePanel.add(new JScrollPane(m_inheritanceTree)); // init implementations panel m_implementationsTree = new JTree(); - m_implementationsTree.setModel( null ); - m_implementationsTree.addMouseListener( new MouseAdapter( ) - { + m_implementationsTree.setModel(null); + m_implementationsTree.addMouseListener(new MouseAdapter() { @Override - public void mouseClicked( MouseEvent event ) - { - if( event.getClickCount() == 2 ) - { + public void mouseClicked(MouseEvent event) { + if (event.getClickCount() == 2) { // get the selected node TreePath path = m_implementationsTree.getSelectionPath(); - if( path == null ) - { + if (path == null) { return; } Object node = path.getLastPathComponent(); - if( node instanceof ClassImplementationsTreeNode ) - { + if (node instanceof ClassImplementationsTreeNode) { ClassImplementationsTreeNode classNode = (ClassImplementationsTreeNode)node; - navigateTo( classNode.getClassEntry() ); - } - else if( node instanceof MethodImplementationsTreeNode ) - { + navigateTo(classNode.getClassEntry()); + } else if (node instanceof MethodImplementationsTreeNode) { MethodImplementationsTreeNode methodNode = (MethodImplementationsTreeNode)node; - navigateTo( methodNode.getMethodEntry() ); + navigateTo(methodNode.getMethodEntry()); } } } - } ); + }); JPanel implementationsPanel = new JPanel(); - implementationsPanel.setLayout( new BorderLayout() ); - implementationsPanel.add( new JScrollPane( m_implementationsTree ) ); + implementationsPanel.setLayout(new BorderLayout()); + implementationsPanel.add(new JScrollPane(m_implementationsTree)); // init call panel m_callsTree = new JTree(); - m_callsTree.setModel( null ); - m_callsTree.addMouseListener( new MouseAdapter( ) - { - @SuppressWarnings( "unchecked" ) + m_callsTree.setModel(null); + m_callsTree.addMouseListener(new MouseAdapter() { + @SuppressWarnings("unchecked") @Override - public void mouseClicked( MouseEvent event ) - { - if( event.getClickCount() == 2 ) - { + public void mouseClicked(MouseEvent event) { + if (event.getClickCount() == 2) { // get the selected node TreePath path = m_callsTree.getSelectionPath(); - if( path == null ) - { + if (path == null) { return; } Object node = path.getLastPathComponent(); - if( node instanceof ReferenceTreeNode ) - { + if (node instanceof ReferenceTreeNode) { ReferenceTreeNode referenceNode = ((ReferenceTreeNode)node); - if( referenceNode.getReference() != null ) - { - navigateTo( referenceNode.getReference() ); - } - else - { - navigateTo( referenceNode.getEntry() ); + if (referenceNode.getReference() != null) { + navigateTo(referenceNode.getReference()); + } else { + navigateTo(referenceNode.getEntry()); } } } } - } ); + }); m_tokens = new JList(); - m_tokens.setCellRenderer( new TokenListCellRenderer( m_controller ) ); - m_tokens.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); - m_tokens.setLayoutOrientation( JList.VERTICAL ); - m_tokens.addMouseListener( new MouseAdapter() - { + m_tokens.setCellRenderer(new TokenListCellRenderer(m_controller)); + m_tokens.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + m_tokens.setLayoutOrientation(JList.VERTICAL); + m_tokens.addMouseListener(new MouseAdapter() { @Override - public void mouseClicked( MouseEvent event ) - { - if( event.getClickCount() == 2 ) - { + public void mouseClicked(MouseEvent event) { + if (event.getClickCount() == 2) { Token selected = m_tokens.getSelectedValue(); - if( selected != null ) - { - showToken( selected ); + if (selected != null) { + showToken(selected); } } } - } ); - m_tokens.setPreferredSize( new Dimension( 0, 200 ) ); - m_tokens.setMinimumSize( new Dimension( 0, 200 ) ); - JSplitPane callPanel = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, new JScrollPane( m_callsTree ), new JScrollPane( m_tokens ) ); - callPanel.setResizeWeight( 1 ); // let the top side take all the slack + }); + m_tokens.setPreferredSize(new Dimension(0, 200)); + m_tokens.setMinimumSize(new Dimension(0, 200)); + JSplitPane callPanel = new JSplitPane( + JSplitPane.VERTICAL_SPLIT, + true, + new JScrollPane(m_callsTree), + new JScrollPane(m_tokens) + ); + callPanel.setResizeWeight(1); // let the top side take all the slack callPanel.resetToPreferredSizes(); // layout controls JPanel centerPanel = new JPanel(); - centerPanel.setLayout( new BorderLayout() ); - centerPanel.add( m_infoPanel, BorderLayout.NORTH ); - centerPanel.add( sourceScroller, BorderLayout.CENTER ); + centerPanel.setLayout(new BorderLayout()); + centerPanel.add(m_infoPanel, BorderLayout.NORTH); + centerPanel.add(sourceScroller, BorderLayout.CENTER); m_tabs = new JTabbedPane(); - m_tabs.setPreferredSize( new Dimension( 250, 0 ) ); - m_tabs.addTab( "Inheritance", inheritancePanel ); - m_tabs.addTab( "Implementations", implementationsPanel ); - m_tabs.addTab( "Call Graph", callPanel ); - JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs ); - splitRight.setResizeWeight( 1 ); // let the left side take all the slack + m_tabs.setPreferredSize(new Dimension(250, 0)); + m_tabs.addTab("Inheritance", inheritancePanel); + m_tabs.addTab("Implementations", implementationsPanel); + m_tabs.addTab("Call Graph", callPanel); + JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs); + splitRight.setResizeWeight(1); // let the left side take all the slack splitRight.resetToPreferredSizes(); - JSplitPane splitCenter = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, m_classesPanel, splitRight ); - splitCenter.setResizeWeight( 0 ); // let the right side take all the slack - pane.add( splitCenter, BorderLayout.CENTER ); + JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, m_classesPanel, splitRight); + splitCenter.setResizeWeight(0); // let the right side take all the slack + pane.add(splitCenter, BorderLayout.CENTER); // init menus JMenuBar menuBar = new JMenuBar(); - m_frame.setJMenuBar( menuBar ); + m_frame.setJMenuBar(menuBar); { - JMenu menu = new JMenu( "File" ); - menuBar.add( menu ); + JMenu menu = new JMenu("File"); + menuBar.add(menu); { - JMenuItem item = new JMenuItem( "Open Jar..." ); - menu.add( item ); - item.addActionListener( new ActionListener( ) - { + 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 ) - { + public void actionPerformed(ActionEvent event) { + if (m_jarFileChooser.showOpenDialog(m_frame) == JFileChooser.APPROVE_OPTION) { // load the jar in a separate thread - new Thread( ) - { + new Thread() { @Override - public void run( ) - { - try - { - m_controller.openJar( m_jarFileChooser.getSelectedFile() ); - } - catch( IOException ex ) - { - throw new Error( ex ); + public void run() { + try { + m_controller.openJar(m_jarFileChooser.getSelectedFile()); + } catch (IOException ex) { + throw new Error(ex); } } }.start(); } } - } ); + }); } { - JMenuItem item = new JMenuItem( "Close Jar" ); - menu.add( item ); - item.addActionListener( new ActionListener( ) - { + JMenuItem item = new JMenuItem("Close Jar"); + menu.add(item); + item.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { + 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( ) - { + JMenuItem item = new JMenuItem("Open Mappings..."); + menu.add(item); + item.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { - if( m_mappingsFileChooser.showOpenDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) - { - try - { - m_controller.openMappings( m_mappingsFileChooser.getSelectedFile() ); - } - catch( IOException ex ) - { - throw new Error( ex ); - } - catch( MappingParseException ex ) - { - JOptionPane.showMessageDialog( m_frame, ex.getMessage() ); + public void actionPerformed(ActionEvent event) { + if (m_mappingsFileChooser.showOpenDialog(m_frame) == JFileChooser.APPROVE_OPTION) { + try { + m_controller.openMappings(m_mappingsFileChooser.getSelectedFile()); + } catch (IOException ex) { + throw new Error(ex); + } catch (MappingParseException ex) { + JOptionPane.showMessageDialog(m_frame, ex.getMessage()); } } } - } ); + }); m_openMappingsMenu = item; } { - JMenuItem item = new JMenuItem( "Save Mappings" ); - menu.add( item ); - item.addActionListener( new ActionListener( ) - { + JMenuItem item = new JMenuItem("Save Mappings"); + menu.add(item); + item.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { - try - { - m_controller.saveMappings( m_mappingsFileChooser.getSelectedFile() ); - } - catch( IOException ex ) - { - throw new Error( ex ); + public void actionPerformed(ActionEvent event) { + try { + m_controller.saveMappings(m_mappingsFileChooser.getSelectedFile()); + } catch (IOException ex) { + throw new Error(ex); } } - } ); - item.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK ) ); + }); + item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK)); m_saveMappingsMenu = item; } { - JMenuItem item = new JMenuItem( "Save Mappings As..." ); - menu.add( item ); - item.addActionListener( new ActionListener( ) - { + JMenuItem item = new JMenuItem("Save Mappings As..."); + menu.add(item); + item.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { - if( m_mappingsFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) - { - try - { - m_controller.saveMappings( m_mappingsFileChooser.getSelectedFile() ); - m_saveMappingsMenu.setEnabled( true ); - } - catch( IOException ex ) - { - throw new Error( ex ); + public void actionPerformed(ActionEvent event) { + if (m_mappingsFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) { + try { + m_controller.saveMappings(m_mappingsFileChooser.getSelectedFile()); + m_saveMappingsMenu.setEnabled(true); + } catch (IOException ex) { + throw new Error(ex); } } } - } ); - item.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK ) ); + }); + item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)); m_saveMappingsAsMenu = item; } { - JMenuItem item = new JMenuItem( "Close Mappings" ); - menu.add( item ); - item.addActionListener( new ActionListener( ) - { + JMenuItem item = new JMenuItem("Close Mappings"); + menu.add(item); + item.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { + public void actionPerformed(ActionEvent event) { m_controller.closeMappings(); } - } ); + }); m_closeMappingsMenu = item; } menu.addSeparator(); { - JMenuItem item = new JMenuItem( "Export Source..." ); - menu.add( item ); - item.addActionListener( new ActionListener( ) - { + JMenuItem item = new JMenuItem("Export Source..."); + menu.add(item); + item.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { - if( m_exportSourceFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) - { - m_controller.exportSource( m_exportSourceFileChooser.getSelectedFile() ); + public void actionPerformed(ActionEvent event) { + if (m_exportSourceFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) { + m_controller.exportSource(m_exportSourceFileChooser.getSelectedFile()); } } - } ); + }); m_exportSourceMenu = item; } { - JMenuItem item = new JMenuItem( "Export Jar..." ); - menu.add( item ); - item.addActionListener( new ActionListener( ) - { + JMenuItem item = new JMenuItem("Export Jar..."); + menu.add(item); + item.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { - if( m_exportJarFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) - { - m_controller.exportJar( m_exportJarFileChooser.getSelectedFile() ); + public void actionPerformed(ActionEvent event) { + if (m_exportJarFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) { + m_controller.exportJar(m_exportJarFileChooser.getSelectedFile()); } } - } ); + }); m_exportJarMenu = item; } menu.addSeparator(); { - JMenuItem item = new JMenuItem( "Exit" ); - menu.add( item ); - item.addActionListener( new ActionListener( ) - { + JMenuItem item = new JMenuItem("Exit"); + menu.add(item); + item.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { + public void actionPerformed(ActionEvent event) { close(); } - } ); + }); } } { - JMenu menu = new JMenu( "Help" ); - menuBar.add( menu ); + JMenu menu = new JMenu("Help"); + menuBar.add(menu); { - JMenuItem item = new JMenuItem( "About" ); - menu.add( item ); - item.addActionListener( new ActionListener( ) - { + JMenuItem item = new JMenuItem("About"); + menu.add(item); + item.addActionListener(new ActionListener() { @Override - public void actionPerformed( ActionEvent event ) - { - AboutDialog.show( m_frame ); + public void actionPerformed(ActionEvent event) { + AboutDialog.show(m_frame); } - } ); + }); } } // init state onCloseJar(); - m_frame.addWindowListener( new WindowAdapter( ) - { + m_frame.addWindowListener(new WindowAdapter() { @Override - public void windowClosing( WindowEvent event ) - { + public void windowClosing(WindowEvent event) { close(); } - } ); + }); // show the frame pane.doLayout(); - m_frame.setSize( 1024, 576 ); - m_frame.setMinimumSize( new Dimension( 640, 480 ) ); - m_frame.setVisible( true ); - m_frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); + m_frame.setSize(1024, 576); + m_frame.setMinimumSize(new Dimension(640, 480)); + m_frame.setVisible(true); + m_frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); } - public JFrame getFrame( ) - { + public JFrame getFrame() { return m_frame; } - public GuiController getController( ) - { + public GuiController getController() { return m_controller; } - public void onStartOpenJar( ) - { + public void onStartOpenJar() { m_classesPanel.removeAll(); JPanel panel = new JPanel(); - panel.setLayout( new FlowLayout() ); - panel.add( new JLabel( "Loading..." ) ); - m_classesPanel.add( panel ); + panel.setLayout(new FlowLayout()); + panel.add(new JLabel("Loading...")); + m_classesPanel.add(panel); redraw(); } - public void onFinishOpenJar( String jarName ) - { + public void onFinishOpenJar(String jarName) { // update gui - m_frame.setTitle( Constants.Name + " - " + jarName ); + m_frame.setTitle(Constants.Name + " - " + jarName); m_classesPanel.removeAll(); - m_classesPanel.add( m_splitClasses ); - setSource( null ); + m_classesPanel.add(m_splitClasses); + setSource(null); // update menu - m_closeJarMenu.setEnabled( true ); - m_openMappingsMenu.setEnabled( true ); - m_saveMappingsMenu.setEnabled( false ); - m_saveMappingsAsMenu.setEnabled( true ); - m_closeMappingsMenu.setEnabled( true ); - m_exportSourceMenu.setEnabled( true ); - m_exportJarMenu.setEnabled( true ); + m_closeJarMenu.setEnabled(true); + m_openMappingsMenu.setEnabled(true); + m_saveMappingsMenu.setEnabled(false); + m_saveMappingsAsMenu.setEnabled(true); + m_closeMappingsMenu.setEnabled(true); + m_exportSourceMenu.setEnabled(true); + m_exportJarMenu.setEnabled(true); redraw(); } - public void onCloseJar( ) - { + public void onCloseJar() { // update gui - m_frame.setTitle( Constants.Name ); - setObfClasses( null ); - setDeobfClasses( null ); - setSource( null ); + m_frame.setTitle(Constants.Name); + setObfClasses(null); + setDeobfClasses(null); + setSource(null); m_classesPanel.removeAll(); // update menu - m_closeJarMenu.setEnabled( false ); - m_openMappingsMenu.setEnabled( false ); - m_saveMappingsMenu.setEnabled( false ); - m_saveMappingsAsMenu.setEnabled( false ); - m_closeMappingsMenu.setEnabled( false ); - m_exportSourceMenu.setEnabled( false ); - m_exportJarMenu.setEnabled( false ); + m_closeJarMenu.setEnabled(false); + m_openMappingsMenu.setEnabled(false); + m_saveMappingsMenu.setEnabled(false); + m_saveMappingsAsMenu.setEnabled(false); + m_closeMappingsMenu.setEnabled(false); + m_exportSourceMenu.setEnabled(false); + m_exportJarMenu.setEnabled(false); redraw(); } - public void setObfClasses( Collection obfClasses ) - { - m_obfClasses.setClasses( obfClasses ); + public void setObfClasses(Collection obfClasses) { + m_obfClasses.setClasses(obfClasses); } - public void setDeobfClasses( Collection deobfClasses ) - { - m_deobfClasses.setClasses( deobfClasses ); + public void setDeobfClasses(Collection deobfClasses) { + m_deobfClasses.setClasses(deobfClasses); } - public void setMappingsFile( File file ) - { - m_mappingsFileChooser.setSelectedFile( file ); - m_saveMappingsMenu.setEnabled( file != null ); + public void setMappingsFile(File file) { + m_mappingsFileChooser.setSelectedFile(file); + m_saveMappingsMenu.setEnabled(file != null); } - public void setSource( String source ) - { + public void setSource(String source) { m_editor.getHighlighter().removeAllHighlights(); - m_editor.setText( source ); + m_editor.setText(source); } - public void showToken( final Token token ) - { - if( token == null ) - { - throw new IllegalArgumentException( "Token cannot be null!" ); + public void showToken(final Token token) { + if (token == null) { + throw new IllegalArgumentException("Token cannot be null!"); } // set the caret position to the token - m_editor.setCaretPosition( token.start ); + m_editor.setCaretPosition(token.start); m_editor.grabFocus(); - try - { + try { // make sure the token is visible in the scroll window - Rectangle start = m_editor.modelToView( token.start ); - Rectangle end = m_editor.modelToView( token.end ); - final Rectangle show = start.union( end ); - show.grow( start.width*10, start.height*6 ); - SwingUtilities.invokeLater( new Runnable( ) - { + Rectangle start = m_editor.modelToView(token.start); + Rectangle end = m_editor.modelToView(token.end); + final Rectangle show = start.union(end); + show.grow(start.width * 10, start.height * 6); + SwingUtilities.invokeLater(new Runnable() { @Override - public void run( ) - { - m_editor.scrollRectToVisible( show ); + public void run() { + m_editor.scrollRectToVisible(show); } - } ); - } - catch( BadLocationException ex ) - { - throw new Error( ex ); + }); + } catch (BadLocationException ex) { + throw new Error(ex); } // highlight the token momentarily - final Timer timer = new Timer( 200, new ActionListener( ) - { + final Timer timer = new Timer(200, new ActionListener() { private int m_counter = 0; private Object m_highlight = null; @Override - public void actionPerformed( ActionEvent event ) - { - if( m_counter % 2 == 0 ) - { - try - { - m_highlight = m_editor.getHighlighter().addHighlight( token.start, token.end, m_selectionHighlightPainter ); - } - catch( BadLocationException ex ) - { + public void actionPerformed(ActionEvent event) { + if (m_counter % 2 == 0) { + try { + m_highlight = m_editor.getHighlighter().addHighlight(token.start, token.end, m_selectionHighlightPainter); + } catch (BadLocationException ex) { // don't care } - } - else if( m_highlight != null ) - { - m_editor.getHighlighter().removeHighlight( m_highlight ); + } else if (m_highlight != null) { + m_editor.getHighlighter().removeHighlight(m_highlight); } - if( m_counter++ > 6 ) - { + if (m_counter++ > 6) { Timer timer = (Timer)event.getSource(); timer.stop(); } } - } ); + }); timer.start(); redraw(); } - public void showTokens( Collection tokens ) - { - Vector sortedTokens = new Vector( tokens ); - Collections.sort( sortedTokens ); - if( sortedTokens.size() > 1 ) - { + public void showTokens(Collection tokens) { + Vector sortedTokens = new Vector(tokens); + Collections.sort(sortedTokens); + if (sortedTokens.size() > 1) { // sort the tokens and update the tokens panel - m_tokens.setListData( sortedTokens ); - m_tokens.setSelectedIndex( 0 ); - } - else - { - m_tokens.setListData( new Vector() ); + m_tokens.setListData(sortedTokens); + m_tokens.setSelectedIndex(0); + } else { + m_tokens.setListData(new Vector()); } // show the first token - showToken( sortedTokens.get( 0 ) ); + showToken(sortedTokens.get(0)); } - public void setHighlightedTokens( Iterable obfuscatedTokens, Iterable deobfuscatedTokens, Iterable otherTokens ) - { + public void setHighlightedTokens(Iterable obfuscatedTokens, Iterable deobfuscatedTokens, Iterable otherTokens) { + // remove any old highlighters m_editor.getHighlighter().removeAllHighlights(); // color things based on the index - if( obfuscatedTokens != null ) - { - setHighlightedTokens( obfuscatedTokens, m_obfuscatedHighlightPainter ); + if (obfuscatedTokens != null) { + setHighlightedTokens(obfuscatedTokens, m_obfuscatedHighlightPainter); } - if( deobfuscatedTokens != null ) - { - setHighlightedTokens( deobfuscatedTokens, m_deobfuscatedHighlightPainter ); + if (deobfuscatedTokens != null) { + setHighlightedTokens(deobfuscatedTokens, m_deobfuscatedHighlightPainter); } - if( otherTokens != null ) - { - setHighlightedTokens( otherTokens, m_otherHighlightPainter ); + if (otherTokens != null) { + setHighlightedTokens(otherTokens, m_otherHighlightPainter); } redraw(); } - private void setHighlightedTokens( Iterable tokens, Highlighter.HighlightPainter painter ) - { - for( Token token : tokens ) - { - try - { - m_editor.getHighlighter().addHighlight( token.start, token.end, painter ); - } - catch( BadLocationException ex ) - { - throw new IllegalArgumentException( ex ); + private void setHighlightedTokens(Iterable tokens, Highlighter.HighlightPainter painter) { + for (Token token : tokens) { + try { + m_editor.getHighlighter().addHighlight(token.start, token.end, painter); + } catch (BadLocationException ex) { + throw new IllegalArgumentException(ex); } } } - private void clearReference( ) - { + private void clearReference() { m_infoPanel.removeAll(); - JLabel label = new JLabel( "No identifier selected" ); - GuiTricks.unboldLabel( label ); - label.setHorizontalAlignment( JLabel.CENTER ); - m_infoPanel.add( label ); + JLabel label = new JLabel("No identifier selected"); + GuiTricks.unboldLabel(label); + label.setHorizontalAlignment(JLabel.CENTER); + m_infoPanel.add(label); redraw(); } - private void showReference( EntryReference reference ) - { - if( reference == null ) - { + private void showReference(EntryReference reference) { + if (reference == null) { clearReference(); return; } @@ -979,383 +848,300 @@ public class Gui m_reference = reference; m_infoPanel.removeAll(); - if( reference.entry instanceof ClassEntry ) - { - showClassEntry( (ClassEntry)m_reference.entry ); - } - else if( m_reference.entry instanceof FieldEntry ) - { - showFieldEntry( (FieldEntry)m_reference.entry ); - } - else if( m_reference.entry instanceof MethodEntry ) - { - showMethodEntry( (MethodEntry)m_reference.entry ); - } - else if( m_reference.entry instanceof ConstructorEntry ) - { - showConstructorEntry( (ConstructorEntry)m_reference.entry ); - } - else if( m_reference.entry instanceof ArgumentEntry ) - { - showArgumentEntry( (ArgumentEntry)m_reference.entry ); - } - else - { - throw new Error( "Unknown entry type: " + m_reference.entry.getClass().getName() ); + if (reference.entry instanceof ClassEntry) { + showClassEntry((ClassEntry)m_reference.entry); + } else if (m_reference.entry instanceof FieldEntry) { + showFieldEntry((FieldEntry)m_reference.entry); + } else if (m_reference.entry instanceof MethodEntry) { + showMethodEntry((MethodEntry)m_reference.entry); + } else if (m_reference.entry instanceof ConstructorEntry) { + showConstructorEntry((ConstructorEntry)m_reference.entry); + } else if (m_reference.entry instanceof ArgumentEntry) { + showArgumentEntry((ArgumentEntry)m_reference.entry); + } else { + throw new Error("Unknown entry type: " + m_reference.entry.getClass().getName()); } redraw(); } - private void showClassEntry( ClassEntry entry ) - { - addNameValue( m_infoPanel, "Class", entry.getName() ); + private void showClassEntry(ClassEntry entry) { + addNameValue(m_infoPanel, "Class", entry.getName()); } - private void showFieldEntry( FieldEntry entry ) - { - addNameValue( m_infoPanel, "Field", entry.getName() ); - addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); + private void showFieldEntry(FieldEntry entry) { + addNameValue(m_infoPanel, "Field", entry.getName()); + addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); } - private void showMethodEntry( MethodEntry entry ) - { - addNameValue( m_infoPanel, "Method", entry.getName() ); - addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); - addNameValue( m_infoPanel, "Signature", entry.getSignature() ); + private void showMethodEntry(MethodEntry entry) { + addNameValue(m_infoPanel, "Method", entry.getName()); + addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); + addNameValue(m_infoPanel, "Signature", entry.getSignature()); } - private void showConstructorEntry( ConstructorEntry entry ) - { - addNameValue( m_infoPanel, "Constructor", entry.getClassEntry().getName() ); - addNameValue( m_infoPanel, "Signature", entry.getSignature() ); + private void showConstructorEntry(ConstructorEntry entry) { + addNameValue(m_infoPanel, "Constructor", entry.getClassEntry().getName()); + addNameValue(m_infoPanel, "Signature", entry.getSignature()); } - private void showArgumentEntry( ArgumentEntry entry ) - { - addNameValue( m_infoPanel, "Argument", entry.getName() ); - addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); - addNameValue( m_infoPanel, "Method", entry.getBehaviorEntry().getName() ); - addNameValue( m_infoPanel, "Index", Integer.toString( entry.getIndex() ) ); + private void showArgumentEntry(ArgumentEntry entry) { + addNameValue(m_infoPanel, "Argument", entry.getName()); + addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); + addNameValue(m_infoPanel, "Method", entry.getBehaviorEntry().getName()); + addNameValue(m_infoPanel, "Index", Integer.toString(entry.getIndex())); } - private void addNameValue( JPanel container, String name, String value ) - { + private void addNameValue(JPanel container, String name, String value) { JPanel panel = new JPanel(); - panel.setLayout( new FlowLayout( FlowLayout.LEFT, 6, 0 ) ); - container.add( panel ); + panel.setLayout(new FlowLayout(FlowLayout.LEFT, 6, 0)); + container.add(panel); - JLabel label = new JLabel( name + ":", JLabel.RIGHT ); - label.setPreferredSize( new Dimension( 100, label.getPreferredSize().height ) ); - panel.add( label ); + JLabel label = new JLabel(name + ":", JLabel.RIGHT); + label.setPreferredSize(new Dimension(100, label.getPreferredSize().height)); + panel.add(label); - panel.add( GuiTricks.unboldLabel( new JLabel( value, JLabel.LEFT ) ) ); + panel.add(GuiTricks.unboldLabel(new JLabel(value, JLabel.LEFT))); } - private void onCaretMove( int pos ) - { - Token token = m_controller.getToken( pos ); + private void onCaretMove(int pos) { + + Token token = m_controller.getToken(pos); boolean isToken = token != null; - m_reference = m_controller.getDeobfReference( token ); + m_reference = m_controller.getDeobfReference(token); boolean isClassEntry = isToken && m_reference.entry instanceof ClassEntry; boolean isFieldEntry = isToken && m_reference.entry instanceof FieldEntry; boolean isMethodEntry = isToken && m_reference.entry instanceof MethodEntry; boolean isConstructorEntry = isToken && m_reference.entry instanceof ConstructorEntry; - boolean isInJar = isToken && m_controller.entryIsInJar( m_reference.entry ); - boolean isRenameable = isToken && m_controller.referenceIsRenameable( m_reference ); + boolean isInJar = isToken && m_controller.entryIsInJar(m_reference.entry); + boolean isRenameable = isToken && m_controller.referenceIsRenameable(m_reference); - if( isToken ) - { - showReference( m_reference ); - } - else - { + if (isToken) { + showReference(m_reference); + } else { clearReference(); } - m_renameMenu.setEnabled( isRenameable && isToken ); - m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry || isConstructorEntry ); - m_showImplementationsMenu.setEnabled( isClassEntry || isMethodEntry ); - m_showCallsMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); - m_openEntryMenu.setEnabled( isInJar && ( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ) ); - m_openPreviousMenu.setEnabled( m_controller.hasPreviousLocation() ); - m_toggleMappingMenu.setEnabled( isRenameable && isToken ); + m_renameMenu.setEnabled(isRenameable && isToken); + m_showInheritanceMenu.setEnabled(isClassEntry || isMethodEntry || isConstructorEntry); + m_showImplementationsMenu.setEnabled(isClassEntry || isMethodEntry); + m_showCallsMenu.setEnabled(isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry); + m_openEntryMenu.setEnabled(isInJar && (isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry)); + m_openPreviousMenu.setEnabled(m_controller.hasPreviousLocation()); + m_toggleMappingMenu.setEnabled(isRenameable && isToken); - if( isToken && m_controller.entryHasDeobfuscatedName( m_reference.entry ) ) - { - m_toggleMappingMenu.setText( "Reset to obfuscated" ); - } - else - { - m_toggleMappingMenu.setText( "Mark as deobfuscated" ); + if (isToken && m_controller.entryHasDeobfuscatedName(m_reference.entry)) { + m_toggleMappingMenu.setText("Reset to obfuscated"); + } else { + m_toggleMappingMenu.setText("Mark as deobfuscated"); } } - private void navigateTo( Entry entry ) - { - if( !m_controller.entryIsInJar( entry ) ) - { + private void navigateTo(Entry entry) { + if (!m_controller.entryIsInJar(entry)) { // entry is not in the jar. Ignore it return; } - if( m_reference != null ) - { - m_controller.savePreviousReference( m_reference ); + if (m_reference != null) { + m_controller.savePreviousReference(m_reference); } - m_controller.openDeclaration( entry ); + m_controller.openDeclaration(entry); } - private void navigateTo( EntryReference reference ) - { - if( !m_controller.entryIsInJar( reference.getLocationClassEntry() ) ) - { + private void navigateTo(EntryReference reference) { + if (!m_controller.entryIsInJar(reference.getLocationClassEntry())) { // reference is not in the jar. Ignore it return; } - if( m_reference != null ) - { - m_controller.savePreviousReference( m_reference ); + if (m_reference != null) { + m_controller.savePreviousReference(m_reference); } - m_controller.openReference( reference ); + m_controller.openReference(reference); } - private void startRename( ) - { + private void startRename() { + // init the text box final JTextField text = new JTextField(); - text.setText( m_reference.getNamableName() ); - text.setPreferredSize( new Dimension( 360, text.getPreferredSize().height ) ); - text.addKeyListener( new KeyAdapter( ) - { + text.setText(m_reference.getNamableName()); + text.setPreferredSize(new Dimension(360, text.getPreferredSize().height)); + text.addKeyListener(new KeyAdapter() { @Override - public void keyPressed( KeyEvent event ) - { - switch( event.getKeyCode() ) - { + public void keyPressed(KeyEvent event) { + switch (event.getKeyCode()) { case KeyEvent.VK_ENTER: - finishRename( text, true ); + finishRename(text, true); break; case KeyEvent.VK_ESCAPE: - finishRename( text, false ); + 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 ); + 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 ) - { + private void finishRename(JTextField text, boolean saveName) { String newName = text.getText(); - if( saveName && newName != null && newName.length() > 0 ) - { - try - { - m_controller.rename( m_reference, newName ); - } - catch( IllegalNameException ex ) - { - text.setBorder( BorderFactory.createLineBorder( Color.red, 1 ) ); - text.setToolTipText( ex.getReason() ); - GuiTricks.showToolTipNow( text ); + if (saveName && newName != null && newName.length() > 0) { + try { + m_controller.rename(m_reference, newName); + } catch (IllegalNameException ex) { + text.setBorder(BorderFactory.createLineBorder(Color.red, 1)); + text.setToolTipText(ex.getReason()); + GuiTricks.showToolTipNow(text); } return; } // abort the rename - JPanel panel = (JPanel)m_infoPanel.getComponent( 0 ); - panel.remove( panel.getComponentCount() - 1 ); - panel.add( GuiTricks.unboldLabel( new JLabel( m_reference.getNamableName(), JLabel.LEFT ) ) ); + JPanel panel = (JPanel)m_infoPanel.getComponent(0); + panel.remove(panel.getComponentCount() - 1); + panel.add(GuiTricks.unboldLabel(new JLabel(m_reference.getNamableName(), JLabel.LEFT))); m_editor.grabFocus(); redraw(); } - private void showInheritance( ) - { - if( m_reference == null ) - { + private void showInheritance() { + + if (m_reference == null) { return; } - m_inheritanceTree.setModel( null ); + m_inheritanceTree.setModel(null); - if( m_reference.entry instanceof ClassEntry ) - { + if (m_reference.entry instanceof ClassEntry) { // get the class inheritance - ClassInheritanceTreeNode classNode = m_controller.getClassInheritance( (ClassEntry)m_reference.entry ); + ClassInheritanceTreeNode classNode = m_controller.getClassInheritance((ClassEntry)m_reference.entry); // show the tree at the root - TreePath path = getPathToRoot( classNode ); - m_inheritanceTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); - m_inheritanceTree.expandPath( path ); - m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); - } - else if( m_reference.entry instanceof MethodEntry ) - { + TreePath path = getPathToRoot(classNode); + m_inheritanceTree.setModel(new DefaultTreeModel((TreeNode)path.getPathComponent(0))); + m_inheritanceTree.expandPath(path); + m_inheritanceTree.setSelectionRow(m_inheritanceTree.getRowForPath(path)); + } else if (m_reference.entry instanceof MethodEntry) { // get the method inheritance - MethodInheritanceTreeNode classNode = m_controller.getMethodInheritance( (MethodEntry)m_reference.entry ); + MethodInheritanceTreeNode classNode = m_controller.getMethodInheritance((MethodEntry)m_reference.entry); // show the tree at the root - TreePath path = getPathToRoot( classNode ); - m_inheritanceTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); - m_inheritanceTree.expandPath( path ); - m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); + TreePath path = getPathToRoot(classNode); + m_inheritanceTree.setModel(new DefaultTreeModel((TreeNode)path.getPathComponent(0))); + m_inheritanceTree.expandPath(path); + m_inheritanceTree.setSelectionRow(m_inheritanceTree.getRowForPath(path)); } - m_tabs.setSelectedIndex( 0 ); + m_tabs.setSelectedIndex(0); redraw(); } - private void showImplementations( ) - { - if( m_reference == null ) - { + private void showImplementations() { + + if (m_reference == null) { return; } - m_implementationsTree.setModel( null ); + m_implementationsTree.setModel(null); - if( m_reference.entry instanceof ClassEntry ) - { + if (m_reference.entry instanceof ClassEntry) { // get the class implementations - ClassImplementationsTreeNode node = m_controller.getClassImplementations( (ClassEntry)m_reference.entry ); - if( node != null ) - { + ClassImplementationsTreeNode node = m_controller.getClassImplementations((ClassEntry)m_reference.entry); + if (node != null) { // show the tree at the root - TreePath path = getPathToRoot( node ); - m_implementationsTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); - m_implementationsTree.expandPath( path ); - m_implementationsTree.setSelectionRow( m_implementationsTree.getRowForPath( path ) ); + TreePath path = getPathToRoot(node); + m_implementationsTree.setModel(new DefaultTreeModel((TreeNode)path.getPathComponent(0))); + m_implementationsTree.expandPath(path); + m_implementationsTree.setSelectionRow(m_implementationsTree.getRowForPath(path)); } - } - else if( m_reference.entry instanceof MethodEntry ) - { + } else if (m_reference.entry instanceof MethodEntry) { // get the method implementations - MethodImplementationsTreeNode node = m_controller.getMethodImplementations( (MethodEntry)m_reference.entry ); - if( node != null ) - { + MethodImplementationsTreeNode node = m_controller.getMethodImplementations((MethodEntry)m_reference.entry); + if (node != null) { // show the tree at the root - TreePath path = getPathToRoot( node ); - m_implementationsTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); - m_implementationsTree.expandPath( path ); - m_implementationsTree.setSelectionRow( m_implementationsTree.getRowForPath( path ) ); + TreePath path = getPathToRoot(node); + m_implementationsTree.setModel(new DefaultTreeModel((TreeNode)path.getPathComponent(0))); + m_implementationsTree.expandPath(path); + m_implementationsTree.setSelectionRow(m_implementationsTree.getRowForPath(path)); } } - m_tabs.setSelectedIndex( 1 ); + m_tabs.setSelectedIndex(1); redraw(); } - private void showCalls( ) - { - if( m_reference == null ) - { + private void showCalls() { + + if (m_reference == null) { return; } - if( m_reference.entry instanceof ClassEntry ) - { + if (m_reference.entry instanceof ClassEntry) { // look for calls to the default constructor // TODO: get a list of all the constructors and find calls to all of them - BehaviorReferenceTreeNode node = m_controller.getMethodReferences( new ConstructorEntry( (ClassEntry)m_reference.entry, "()V" ) ); - m_callsTree.setModel( new DefaultTreeModel( node ) ); - } - else if( m_reference.entry instanceof FieldEntry ) - { - FieldReferenceTreeNode node = m_controller.getFieldReferences( (FieldEntry)m_reference.entry ); - m_callsTree.setModel( new DefaultTreeModel( node ) ); - } - else if( m_reference.entry instanceof MethodEntry ) - { - BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (MethodEntry)m_reference.entry ); - m_callsTree.setModel( new DefaultTreeModel( node ) ); - } - else if( m_reference.entry instanceof ConstructorEntry ) - { - BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (ConstructorEntry)m_reference.entry ); - m_callsTree.setModel( new DefaultTreeModel( node ) ); + BehaviorReferenceTreeNode node = m_controller.getMethodReferences(new ConstructorEntry((ClassEntry)m_reference.entry, "()V")); + m_callsTree.setModel(new DefaultTreeModel(node)); + } else if (m_reference.entry instanceof FieldEntry) { + FieldReferenceTreeNode node = m_controller.getFieldReferences((FieldEntry)m_reference.entry); + m_callsTree.setModel(new DefaultTreeModel(node)); + } else if (m_reference.entry instanceof MethodEntry) { + BehaviorReferenceTreeNode node = m_controller.getMethodReferences((MethodEntry)m_reference.entry); + m_callsTree.setModel(new DefaultTreeModel(node)); + } else if (m_reference.entry instanceof ConstructorEntry) { + BehaviorReferenceTreeNode node = m_controller.getMethodReferences((ConstructorEntry)m_reference.entry); + m_callsTree.setModel(new DefaultTreeModel(node)); } - m_tabs.setSelectedIndex( 2 ); + m_tabs.setSelectedIndex(2); redraw(); } - private void toggleMapping() - { - if( m_controller.entryHasDeobfuscatedName( m_reference.entry ) ) - { - m_controller.removeMapping( m_reference ); - } - else - { - m_controller.markAsDeobfuscated( m_reference ); + private void toggleMapping() { + if (m_controller.entryHasDeobfuscatedName(m_reference.entry)) { + m_controller.removeMapping(m_reference); + } else { + m_controller.markAsDeobfuscated(m_reference); } } - private TreePath getPathToRoot( TreeNode node ) - { + private TreePath getPathToRoot(TreeNode node) { List nodes = Lists.newArrayList(); TreeNode n = node; - do - { - nodes.add( n ); + do { + nodes.add(n); n = n.getParent(); - } - while( n != null ); - Collections.reverse( nodes ); - return new TreePath( nodes.toArray() ); + } while (n != null); + Collections.reverse(nodes); + return new TreePath(nodes.toArray()); } - private void close( ) - { - if( !m_controller.isDirty() ) - { + private void close() { + if (!m_controller.isDirty()) { // everything is saved, we can exit safely m_frame.dispose(); - } - else - { + } 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 ) - { + 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() ); + 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 ); + } catch (IOException ex) { + throw new Error(ex); } } break; @@ -1364,14 +1150,13 @@ public class Gui // don't save, exit m_frame.dispose(); break; - + // cancel means do nothing } } } - - private void redraw( ) - { + + private void redraw() { m_frame.validate(); m_frame.repaint(); } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 2862ebed..908c16fa 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -44,8 +44,8 @@ import cuchaz.enigma.mapping.MappingsWriter; import cuchaz.enigma.mapping.MethodEntry; import cuchaz.enigma.mapping.TranslationDirection; -public class GuiController -{ +public class GuiController { + private Deobfuscator m_deobfuscator; private Gui m_gui; private SourceIndex m_index; @@ -53,8 +53,7 @@ public class GuiController private boolean m_isDirty; private Deque> m_referenceStack; - public GuiController( Gui gui ) - { + public GuiController(Gui gui) { m_gui = gui; m_deobfuscator = null; m_index = null; @@ -63,358 +62,292 @@ public class GuiController m_referenceStack = Queues.newArrayDeque(); } - public boolean isDirty( ) - { + public boolean isDirty() { return m_isDirty; } - public void openJar( final File file ) - throws IOException - { + public void openJar(final File file) throws IOException { m_gui.onStartOpenJar(); - m_deobfuscator = new Deobfuscator( file ); - m_gui.onFinishOpenJar( m_deobfuscator.getJarName() ); + m_deobfuscator = new Deobfuscator(file); + m_gui.onFinishOpenJar(m_deobfuscator.getJarName()); refreshClasses(); } - public void closeJar( ) - { + public void closeJar() { m_deobfuscator = null; m_gui.onCloseJar(); } - public void openMappings( File file ) - throws IOException, MappingParseException - { - FileReader in = new FileReader( file ); - m_deobfuscator.setMappings( new MappingsReader().read( in ) ); + public void openMappings(File file) throws IOException, MappingParseException { + FileReader in = new FileReader(file); + m_deobfuscator.setMappings(new MappingsReader().read(in)); in.close(); m_isDirty = false; - m_gui.setMappingsFile( file ); + m_gui.setMappingsFile(file); refreshClasses(); refreshCurrentClass(); } - - public void saveMappings( File file ) - throws IOException - { - FileWriter out = new FileWriter( file ); - new MappingsWriter().write( out, m_deobfuscator.getMappings() ); + + public void saveMappings(File file) throws IOException { + 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 ); + + public void closeMappings() { + m_deobfuscator.setMappings(null); + m_gui.setMappingsFile(null); refreshClasses(); refreshCurrentClass(); } - public void exportSource( final File dirOut ) - { - ProgressDialog.runInThread( m_gui.getFrame(), new ProgressRunnable( ) - { + public void exportSource(final File dirOut) { + ProgressDialog.runInThread(m_gui.getFrame(), new ProgressRunnable() { @Override - public void run( ProgressListener progress ) - throws Exception - { - m_deobfuscator.writeSources( dirOut, progress ); + public void run(ProgressListener progress) throws Exception { + m_deobfuscator.writeSources(dirOut, progress); } - } ); + }); } - public void exportJar( final File fileOut ) - { - ProgressDialog.runInThread( m_gui.getFrame(), new ProgressRunnable( ) - { + public void exportJar(final File fileOut) { + ProgressDialog.runInThread(m_gui.getFrame(), new ProgressRunnable() { @Override - public void run( ProgressListener progress ) - { - m_deobfuscator.writeJar( fileOut, progress ); + public void run(ProgressListener progress) { + m_deobfuscator.writeJar(fileOut, progress); } - } ); + }); } - public Token getToken( int pos ) - { - if( m_index == null ) - { + public Token getToken(int pos) { + if (m_index == null) { return null; } - return m_index.getReferenceToken( pos ); + return m_index.getReferenceToken(pos); } - public EntryReference getDeobfReference( Token token ) - { - if( m_index == null ) - { + public EntryReference getDeobfReference(Token token) { + if (m_index == null) { return null; } - return m_index.getDeobfReference( token ); + return m_index.getDeobfReference(token); } - public ReadableToken getReadableToken( Token token ) - { - if( m_index == null ) - { + public ReadableToken getReadableToken(Token token) { + if (m_index == null) { return null; } return new ReadableToken( - m_index.getLineNumber( token.start ), - m_index.getColumnNumber( token.start ), - m_index.getColumnNumber( token.end ) + m_index.getLineNumber(token.start), + m_index.getColumnNumber(token.start), + m_index.getColumnNumber(token.end) ); } - public boolean entryHasDeobfuscatedName( Entry deobfEntry ) - { - return m_deobfuscator.hasDeobfuscatedName( m_deobfuscator.obfuscateEntry( deobfEntry ) ); + public boolean entryHasDeobfuscatedName(Entry deobfEntry) { + return m_deobfuscator.hasDeobfuscatedName(m_deobfuscator.obfuscateEntry(deobfEntry)); } - public boolean entryIsInJar( Entry deobfEntry ) - { - return m_deobfuscator.isObfuscatedIdentifier( m_deobfuscator.obfuscateEntry( deobfEntry ) ); + public boolean entryIsInJar(Entry deobfEntry) { + return m_deobfuscator.isObfuscatedIdentifier(m_deobfuscator.obfuscateEntry(deobfEntry)); } - public boolean referenceIsRenameable( EntryReference deobfReference ) - { - return m_deobfuscator.isRenameable( m_deobfuscator.obfuscateReference( deobfReference ) ); + public boolean referenceIsRenameable(EntryReference deobfReference) { + return m_deobfuscator.isRenameable(m_deobfuscator.obfuscateReference(deobfReference)); } - public ClassInheritanceTreeNode getClassInheritance( ClassEntry deobfClassEntry ) - { - ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry( deobfClassEntry ); + public ClassInheritanceTreeNode getClassInheritance(ClassEntry deobfClassEntry) { + ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry(deobfClassEntry); ClassInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getClassInheritance( - m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), obfClassEntry ); - return ClassInheritanceTreeNode.findNode( rootNode, obfClassEntry ); + return ClassInheritanceTreeNode.findNode(rootNode, obfClassEntry); } - public ClassImplementationsTreeNode getClassImplementations( ClassEntry deobfClassEntry ) - { - ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry( deobfClassEntry ); + public ClassImplementationsTreeNode getClassImplementations(ClassEntry deobfClassEntry) { + ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry(deobfClassEntry); return m_deobfuscator.getJarIndex().getClassImplementations( - m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), obfClassEntry ); } - public MethodInheritanceTreeNode getMethodInheritance( MethodEntry deobfMethodEntry ) - { - MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry( deobfMethodEntry ); + public MethodInheritanceTreeNode getMethodInheritance(MethodEntry deobfMethodEntry) { + MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry(deobfMethodEntry); MethodInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodInheritance( - m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), obfMethodEntry ); - return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); + return MethodInheritanceTreeNode.findNode(rootNode, obfMethodEntry); } - public MethodImplementationsTreeNode getMethodImplementations( MethodEntry deobfMethodEntry ) - { - MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry( deobfMethodEntry ); + public MethodImplementationsTreeNode getMethodImplementations(MethodEntry deobfMethodEntry) { + MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry(deobfMethodEntry); MethodImplementationsTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodImplementations( - m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), obfMethodEntry ); - if( rootNode == null ) - { + if (rootNode == null) { return null; } - return MethodImplementationsTreeNode.findNode( rootNode, obfMethodEntry ); + return MethodImplementationsTreeNode.findNode(rootNode, obfMethodEntry); } - public FieldReferenceTreeNode getFieldReferences( FieldEntry deobfFieldEntry ) - { - FieldEntry obfFieldEntry = m_deobfuscator.obfuscateEntry( deobfFieldEntry ); + public FieldReferenceTreeNode getFieldReferences(FieldEntry deobfFieldEntry) { + FieldEntry obfFieldEntry = m_deobfuscator.obfuscateEntry(deobfFieldEntry); FieldReferenceTreeNode rootNode = new FieldReferenceTreeNode( - m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), obfFieldEntry ); - rootNode.load( m_deobfuscator.getJarIndex(), true ); + rootNode.load(m_deobfuscator.getJarIndex(), true); return rootNode; } - public BehaviorReferenceTreeNode getMethodReferences( BehaviorEntry deobfBehaviorEntry ) - { - BehaviorEntry obfBehaviorEntry = m_deobfuscator.obfuscateEntry( deobfBehaviorEntry ); + public BehaviorReferenceTreeNode getMethodReferences(BehaviorEntry deobfBehaviorEntry) { + BehaviorEntry obfBehaviorEntry = m_deobfuscator.obfuscateEntry(deobfBehaviorEntry); BehaviorReferenceTreeNode rootNode = new BehaviorReferenceTreeNode( - m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), obfBehaviorEntry ); - rootNode.load( m_deobfuscator.getJarIndex(), true ); + rootNode.load(m_deobfuscator.getJarIndex(), true); return rootNode; } - public void rename( EntryReference deobfReference, String newName ) - { - EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); - m_deobfuscator.rename( obfReference.getNameableEntry(), newName ); + public void rename(EntryReference deobfReference, String newName) { + EntryReference obfReference = m_deobfuscator.obfuscateReference(deobfReference); + m_deobfuscator.rename(obfReference.getNameableEntry(), newName); m_isDirty = true; refreshClasses(); - refreshCurrentClass( obfReference ); + refreshCurrentClass(obfReference); } - public void removeMapping( EntryReference deobfReference ) - { - EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); - m_deobfuscator.removeMapping( obfReference.getNameableEntry() ); + public void removeMapping(EntryReference deobfReference) { + EntryReference obfReference = m_deobfuscator.obfuscateReference(deobfReference); + m_deobfuscator.removeMapping(obfReference.getNameableEntry()); m_isDirty = true; refreshClasses(); - refreshCurrentClass( obfReference ); + refreshCurrentClass(obfReference); } - public void markAsDeobfuscated( EntryReference deobfReference ) - { - EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); - m_deobfuscator.markAsDeobfuscated( obfReference.getNameableEntry() ); + public void markAsDeobfuscated(EntryReference deobfReference) { + EntryReference obfReference = m_deobfuscator.obfuscateReference(deobfReference); + m_deobfuscator.markAsDeobfuscated(obfReference.getNameableEntry()); m_isDirty = true; refreshClasses(); - refreshCurrentClass( obfReference ); + refreshCurrentClass(obfReference); } - public void openDeclaration( Entry deobfEntry ) - { - if( deobfEntry == null ) - { - throw new IllegalArgumentException( "Entry cannot be null!" ); + public void openDeclaration(Entry deobfEntry) { + if (deobfEntry == null) { + throw new IllegalArgumentException("Entry cannot be null!"); } - openReference( new EntryReference( deobfEntry, deobfEntry.getName() ) ); + openReference(new EntryReference(deobfEntry, deobfEntry.getName())); } - public void openReference( EntryReference deobfReference ) - { - if( deobfReference == null ) - { - throw new IllegalArgumentException( "Reference cannot be null!" ); + public void openReference(EntryReference deobfReference) { + if (deobfReference == null) { + throw new IllegalArgumentException("Reference cannot be null!"); } // get the reference target class - EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); + EntryReference obfReference = m_deobfuscator.obfuscateReference(deobfReference); ClassEntry obfClassEntry = obfReference.getLocationClassEntry().getOuterClassEntry(); - if( !m_deobfuscator.isObfuscatedIdentifier( obfClassEntry ) ) - { - throw new IllegalArgumentException( "Obfuscated class " + obfClassEntry + " was not found in the jar!" ); + if (!m_deobfuscator.isObfuscatedIdentifier(obfClassEntry)) { + throw new IllegalArgumentException("Obfuscated class " + obfClassEntry + " was not found in the jar!"); } - if( m_currentObfClass == null || !m_currentObfClass.equals( obfClassEntry ) ) - { + if (m_currentObfClass == null || !m_currentObfClass.equals(obfClassEntry)) { // deobfuscate the class, then navigate to the reference m_currentObfClass = obfClassEntry; - deobfuscate( m_currentObfClass, obfReference ); - } - else - { - showReference( obfReference ); + deobfuscate(m_currentObfClass, obfReference); + } else { + showReference(obfReference); } } - private void showReference( EntryReference obfReference ) - { - EntryReference deobfReference = m_deobfuscator.deobfuscateReference( obfReference ); - Collection tokens = m_index.getReferenceTokens( deobfReference ); - if( tokens.isEmpty() ) - { + private void showReference(EntryReference obfReference) { + EntryReference deobfReference = m_deobfuscator.deobfuscateReference(obfReference); + Collection tokens = m_index.getReferenceTokens(deobfReference); + if (tokens.isEmpty()) { // DEBUG - System.err.println( String.format( "WARNING: no tokens found for %s in %s", deobfReference, m_currentObfClass ) ); - } - else - { - m_gui.showTokens( tokens ); + System.err.println(String.format("WARNING: no tokens found for %s in %s", deobfReference, m_currentObfClass)); + } else { + m_gui.showTokens(tokens); } } - public void savePreviousReference( EntryReference deobfReference ) - { - m_referenceStack.push( m_deobfuscator.obfuscateReference( deobfReference ) ); + public void savePreviousReference(EntryReference deobfReference) { + m_referenceStack.push(m_deobfuscator.obfuscateReference(deobfReference)); } - public void openPreviousReference( ) - { - if( hasPreviousLocation() ) - { - openReference( m_deobfuscator.deobfuscateReference( m_referenceStack.pop() ) ); + public void openPreviousReference() { + if (hasPreviousLocation()) { + openReference(m_deobfuscator.deobfuscateReference(m_referenceStack.pop())); } } - public boolean hasPreviousLocation( ) - { + public boolean hasPreviousLocation() { return !m_referenceStack.isEmpty(); } - private void refreshClasses( ) - { + private void refreshClasses() { List obfClasses = Lists.newArrayList(); List deobfClasses = Lists.newArrayList(); - m_deobfuscator.getSeparatedClasses( obfClasses, deobfClasses ); - m_gui.setObfClasses( obfClasses ); - m_gui.setDeobfClasses( deobfClasses ); + m_deobfuscator.getSeparatedClasses(obfClasses, deobfClasses); + m_gui.setObfClasses(obfClasses); + m_gui.setDeobfClasses(deobfClasses); } - private void refreshCurrentClass( ) - { - refreshCurrentClass( null ); + private void refreshCurrentClass() { + refreshCurrentClass(null); } - private void refreshCurrentClass( EntryReference obfReference ) - { - if( m_currentObfClass != null ) - { - deobfuscate( m_currentObfClass, obfReference ); + private void refreshCurrentClass(EntryReference obfReference) { + if (m_currentObfClass != null) { + deobfuscate(m_currentObfClass, obfReference); } } - private void deobfuscate( final ClassEntry classEntry, final EntryReference obfReference ) - { - m_gui.setSource( "(deobfuscating...)" ); + private void deobfuscate(final ClassEntry classEntry, final EntryReference obfReference) { + + m_gui.setSource("(deobfuscating...)"); // run the deobfuscator in a separate thread so we don't block the GUI event queue - new Thread( ) - { + new Thread() { @Override - public void run( ) - { + public void run() { // decompile,deobfuscate the bytecode - CompilationUnit sourceTree = m_deobfuscator.getSourceTree( classEntry.getClassName() ); - if( sourceTree == null ) - { + CompilationUnit sourceTree = m_deobfuscator.getSourceTree(classEntry.getClassName()); + if (sourceTree == null) { // decompilation of this class is not supported m_gui.setSource("Unable to find class: " + classEntry); return; } - String source = m_deobfuscator.getSource( sourceTree ); - m_index = m_deobfuscator.getSourceIndex( sourceTree, source ); - m_gui.setSource( m_index.getSource() ); - if( obfReference != null ) - { - showReference( obfReference ); + String source = m_deobfuscator.getSource(sourceTree); + m_index = m_deobfuscator.getSourceIndex(sourceTree, source); + m_gui.setSource(m_index.getSource()); + if (obfReference != null) { + showReference(obfReference); } // set the highlighted tokens List obfuscatedTokens = Lists.newArrayList(); List deobfuscatedTokens = Lists.newArrayList(); List otherTokens = Lists.newArrayList(); - for( Token token : m_index.referenceTokens() ) - { - EntryReference reference = m_index.getDeobfReference( token ); - if( referenceIsRenameable( reference ) ) - { - if( entryHasDeobfuscatedName( reference.getNameableEntry() ) ) - { - deobfuscatedTokens.add( token ); + for (Token token : m_index.referenceTokens()) { + EntryReference reference = m_index.getDeobfReference(token); + if (referenceIsRenameable(reference)) { + if (entryHasDeobfuscatedName(reference.getNameableEntry())) { + deobfuscatedTokens.add(token); + } else { + obfuscatedTokens.add(token); } - else - { - obfuscatedTokens.add( token ); - } - } - else - { - otherTokens.add( token ); + } else { + otherTokens.add(token); } } - m_gui.setHighlightedTokens( obfuscatedTokens, deobfuscatedTokens, otherTokens ); + m_gui.setHighlightedTokens(obfuscatedTokens, deobfuscatedTokens, otherTokens); } }.start(); } diff --git a/src/cuchaz/enigma/gui/GuiTricks.java b/src/cuchaz/enigma/gui/GuiTricks.java index 9b889ef4..df9e2215 100644 --- a/src/cuchaz/enigma/gui/GuiTricks.java +++ b/src/cuchaz/enigma/gui/GuiTricks.java @@ -17,27 +17,20 @@ import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.ToolTipManager; -public class GuiTricks -{ - public static JLabel unboldLabel( JLabel label ) - { +public class GuiTricks { + + public static JLabel unboldLabel(JLabel label) { Font font = label.getFont(); - label.setFont( font.deriveFont( font.getStyle() & ~Font.BOLD ) ); + label.setFont(font.deriveFont(font.getStyle() & ~Font.BOLD)); return label; } - public static void showToolTipNow( JComponent component ) - { + public static void showToolTipNow(JComponent component) { // HACKHACK: trick the tooltip manager into showing the tooltip right now ToolTipManager manager = ToolTipManager.sharedInstance(); int oldDelay = manager.getInitialDelay(); - manager.setInitialDelay( 0 ); - manager.mouseMoved( new MouseEvent( - component, - MouseEvent.MOUSE_MOVED, - System.currentTimeMillis(), - 0, 0, 0, 0, false - ) ); - manager.setInitialDelay( oldDelay ); + manager.setInitialDelay(0); + manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false)); + manager.setInitialDelay(oldDelay); } } diff --git a/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java b/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java index 724be34e..177835f4 100644 --- a/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java +++ b/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java @@ -12,11 +12,10 @@ package cuchaz.enigma.gui; import java.awt.Color; -public class ObfuscatedHighlightPainter extends BoxHighlightPainter -{ - public ObfuscatedHighlightPainter( ) - { +public class ObfuscatedHighlightPainter extends BoxHighlightPainter { + + public ObfuscatedHighlightPainter() { // red ish - super( new Color( 255, 220, 220 ), new Color( 160, 80, 80 ) ); + super(new Color(255, 220, 220), new Color(160, 80, 80)); } } diff --git a/src/cuchaz/enigma/gui/OtherHighlightPainter.java b/src/cuchaz/enigma/gui/OtherHighlightPainter.java index 78de7325..4e9c8709 100644 --- a/src/cuchaz/enigma/gui/OtherHighlightPainter.java +++ b/src/cuchaz/enigma/gui/OtherHighlightPainter.java @@ -12,11 +12,10 @@ package cuchaz.enigma.gui; import java.awt.Color; -public class OtherHighlightPainter extends BoxHighlightPainter -{ - public OtherHighlightPainter( ) - { +public class OtherHighlightPainter extends BoxHighlightPainter { + + public OtherHighlightPainter() { // grey - super( null, new Color( 180, 180, 180 ) ); + super(null, new Color(180, 180, 180)); } } diff --git a/src/cuchaz/enigma/gui/ProgressDialog.java b/src/cuchaz/enigma/gui/ProgressDialog.java index 7f954314..b864fdbf 100644 --- a/src/cuchaz/enigma/gui/ProgressDialog.java +++ b/src/cuchaz/enigma/gui/ProgressDialog.java @@ -25,89 +25,79 @@ import javax.swing.WindowConstants; import cuchaz.enigma.Constants; import cuchaz.enigma.Deobfuscator.ProgressListener; -public class ProgressDialog implements ProgressListener, AutoCloseable -{ +public class ProgressDialog implements ProgressListener, AutoCloseable { + private JFrame m_frame; private JLabel m_title; private JLabel m_text; private JProgressBar m_progress; - public ProgressDialog( JFrame parent ) - { + public ProgressDialog(JFrame parent) { + // init frame - m_frame = new JFrame( Constants.Name + " - Operation in progress" ); + m_frame = new JFrame(Constants.Name + " - Operation in progress"); final Container pane = m_frame.getContentPane(); FlowLayout layout = new FlowLayout(); - layout.setAlignment( FlowLayout.LEFT ); - pane.setLayout( layout ); + layout.setAlignment(FlowLayout.LEFT); + pane.setLayout(layout); m_title = new JLabel(); - pane.add( m_title ); + pane.add(m_title); // set up the progress bar JPanel panel = new JPanel(); - pane.add( panel ); - panel.setLayout( new BorderLayout() ); - m_text = GuiTricks.unboldLabel( new JLabel() ); + pane.add(panel); + panel.setLayout(new BorderLayout()); + m_text = GuiTricks.unboldLabel(new JLabel()); m_progress = new JProgressBar(); - m_text.setBorder( BorderFactory.createEmptyBorder( 0, 0, 10, 0 ) ); - panel.add( m_text, BorderLayout.NORTH ); - panel.add( m_progress, BorderLayout.CENTER ); - panel.setPreferredSize( new Dimension( 360, 50 ) ); + m_text.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); + panel.add(m_text, BorderLayout.NORTH); + panel.add(m_progress, BorderLayout.CENTER); + panel.setPreferredSize(new Dimension(360, 50)); // show the frame pane.doLayout(); - m_frame.setSize( 400, 120 ); - m_frame.setResizable( false ); - m_frame.setLocationRelativeTo( parent ); - m_frame.setVisible( true ); - m_frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); + m_frame.setSize(400, 120); + m_frame.setResizable(false); + m_frame.setLocationRelativeTo(parent); + m_frame.setVisible(true); + m_frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); } - public void close( ) - { + public void close() { m_frame.dispose(); } - + @Override - public void init( int totalWork, String title ) - { - m_title.setText( title ); - m_progress.setMinimum( 0 ); - m_progress.setMaximum( totalWork ); - m_progress.setValue( 0 ); + public void init(int totalWork, String title) { + m_title.setText(title); + m_progress.setMinimum(0); + m_progress.setMaximum(totalWork); + m_progress.setValue(0); } - + @Override - public void onProgress( int numDone, String message ) - { - m_text.setText( message ); - m_progress.setValue( numDone ); + public void onProgress(int numDone, String message) { + m_text.setText(message); + m_progress.setValue(numDone); // update the frame m_frame.validate(); m_frame.repaint(); } - public static interface ProgressRunnable - { - void run( ProgressListener listener ) throws Exception; + public static interface ProgressRunnable { + void run(ProgressListener listener) throws Exception; } - public static void runInThread( final JFrame parent, final ProgressRunnable runnable ) - { - new Thread( ) - { + public static void runInThread(final JFrame parent, final ProgressRunnable runnable) { + new Thread() { @Override - public void run( ) - { - try( ProgressDialog progress = new ProgressDialog( parent ) ) - { - runnable.run( progress ); - } - catch( Exception ex ) - { - throw new Error( ex ); + public void run() { + try (ProgressDialog progress = new ProgressDialog(parent)) { + runnable.run(progress); + } catch (Exception ex) { + throw new Error(ex); } } }.start(); diff --git a/src/cuchaz/enigma/gui/ReadableToken.java b/src/cuchaz/enigma/gui/ReadableToken.java index 3f430453..66bcbc2a 100644 --- a/src/cuchaz/enigma/gui/ReadableToken.java +++ b/src/cuchaz/enigma/gui/ReadableToken.java @@ -10,29 +10,27 @@ ******************************************************************************/ package cuchaz.enigma.gui; -public class ReadableToken -{ +public class ReadableToken { + public int line; public int startColumn; public int endColumn; - public ReadableToken( int line, int startColumn, int endColumn ) - { + public ReadableToken(int line, int startColumn, int endColumn) { this.line = line; this.startColumn = startColumn; this.endColumn = endColumn; } @Override - public String toString( ) - { + public String toString() { StringBuilder buf = new StringBuilder(); - buf.append( "line " ); - buf.append( line ); - buf.append( " columns " ); - buf.append( startColumn ); - buf.append( "-" ); - buf.append( endColumn ); + buf.append("line "); + buf.append(line); + buf.append(" columns "); + buf.append(startColumn); + buf.append("-"); + buf.append(endColumn); return buf.toString(); } } diff --git a/src/cuchaz/enigma/gui/RenameListener.java b/src/cuchaz/enigma/gui/RenameListener.java index 7d45505b..abeda0ce 100644 --- a/src/cuchaz/enigma/gui/RenameListener.java +++ b/src/cuchaz/enigma/gui/RenameListener.java @@ -12,7 +12,6 @@ package cuchaz.enigma.gui; import cuchaz.enigma.mapping.Entry; -public interface RenameListener -{ - void rename( Entry obfEntry, String newName ); +public interface RenameListener { + void rename(Entry obfEntry, String newName); } diff --git a/src/cuchaz/enigma/gui/SelectionHighlightPainter.java b/src/cuchaz/enigma/gui/SelectionHighlightPainter.java index 35f94518..5e189d2e 100644 --- a/src/cuchaz/enigma/gui/SelectionHighlightPainter.java +++ b/src/cuchaz/enigma/gui/SelectionHighlightPainter.java @@ -20,16 +20,15 @@ import java.awt.Shape; import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; -public class SelectionHighlightPainter implements Highlighter.HighlightPainter -{ +public class SelectionHighlightPainter implements Highlighter.HighlightPainter { + @Override - public void paint( Graphics g, int start, int end, Shape shape, JTextComponent text ) - { + public void paint(Graphics g, int start, int end, Shape shape, JTextComponent text) { // draw a thick border Graphics2D g2d = (Graphics2D)g; - Rectangle bounds = BoxHighlightPainter.getBounds( text, start, end ); - g2d.setColor( Color.black ); - g2d.setStroke( new BasicStroke( 2.0f ) ); - g2d.drawRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); + Rectangle bounds = BoxHighlightPainter.getBounds(text, start, end); + g2d.setColor(Color.black); + g2d.setStroke(new BasicStroke(2.0f)); + g2d.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); } } diff --git a/src/cuchaz/enigma/gui/TokenListCellRenderer.java b/src/cuchaz/enigma/gui/TokenListCellRenderer.java index 9247c066..a49be37b 100644 --- a/src/cuchaz/enigma/gui/TokenListCellRenderer.java +++ b/src/cuchaz/enigma/gui/TokenListCellRenderer.java @@ -19,22 +19,20 @@ import javax.swing.ListCellRenderer; import cuchaz.enigma.analysis.Token; -public class TokenListCellRenderer implements ListCellRenderer -{ +public class TokenListCellRenderer implements ListCellRenderer { + private GuiController m_controller; private DefaultListCellRenderer m_defaultRenderer; - public TokenListCellRenderer( GuiController controller ) - { + public TokenListCellRenderer(GuiController controller) { m_controller = controller; m_defaultRenderer = new DefaultListCellRenderer(); } @Override - public Component getListCellRendererComponent( JList list, Token token, int index, boolean isSelected, boolean hasFocus ) - { - JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, token, index, isSelected, hasFocus ); - label.setText( m_controller.getReadableToken( token ).toString() ); + public Component getListCellRendererComponent(JList list, Token token, int index, boolean isSelected, boolean hasFocus) { + JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent(list, token, index, isSelected, hasFocus); + label.setText(m_controller.getReadableToken(token).toString()); return label; } } diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java index 7ed3d328..2c15f4e8 100644 --- a/src/cuchaz/enigma/mapping/ArgumentEntry.java +++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java @@ -14,27 +14,23 @@ import java.io.Serializable; import cuchaz.enigma.Util; -public class ArgumentEntry implements Entry, Serializable -{ +public class ArgumentEntry implements Entry, Serializable { + private static final long serialVersionUID = 4472172468162696006L; private BehaviorEntry m_behaviorEntry; private int m_index; private String m_name; - public ArgumentEntry( BehaviorEntry behaviorEntry, int index, String name ) - { - if( behaviorEntry == null ) - { - throw new IllegalArgumentException( "Behavior cannot be null!" ); + public ArgumentEntry(BehaviorEntry behaviorEntry, int index, String name) { + if (behaviorEntry == null) { + throw new IllegalArgumentException("Behavior cannot be null!"); } - if( index < 0 ) - { - throw new IllegalArgumentException( "Index must be non-negative!" ); + if (index < 0) { + throw new IllegalArgumentException("Index must be non-negative!"); } - if( name == null ) - { - throw new IllegalArgumentException( "Argument name cannot be null!" ); + if (name == null) { + throw new IllegalArgumentException("Argument name cannot be null!"); } m_behaviorEntry = behaviorEntry; @@ -42,90 +38,79 @@ public class ArgumentEntry implements Entry, Serializable m_name = name; } - public ArgumentEntry( ArgumentEntry other ) - { - m_behaviorEntry = (BehaviorEntry)m_behaviorEntry.cloneToNewClass( getClassEntry() ); + public ArgumentEntry(ArgumentEntry other) { + m_behaviorEntry = (BehaviorEntry)m_behaviorEntry.cloneToNewClass(getClassEntry()); m_index = other.m_index; m_name = other.m_name; } - public ArgumentEntry( ArgumentEntry other, String newClassName ) - { - m_behaviorEntry = (BehaviorEntry)other.m_behaviorEntry.cloneToNewClass( new ClassEntry( newClassName ) ); + public ArgumentEntry(ArgumentEntry other, String newClassName) { + m_behaviorEntry = (BehaviorEntry)other.m_behaviorEntry.cloneToNewClass(new ClassEntry(newClassName)); m_index = other.m_index; m_name = other.m_name; } - public BehaviorEntry getBehaviorEntry( ) - { + public BehaviorEntry getBehaviorEntry() { return m_behaviorEntry; } - public int getIndex( ) - { + public int getIndex() { return m_index; } @Override - public String getName( ) - { + public String getName() { return m_name; } @Override - public ClassEntry getClassEntry( ) - { + public ClassEntry getClassEntry() { return m_behaviorEntry.getClassEntry(); } @Override - public String getClassName( ) - { + public String getClassName() { return m_behaviorEntry.getClassName(); } @Override - public ArgumentEntry cloneToNewClass( ClassEntry classEntry ) - { - return new ArgumentEntry( this, classEntry.getName() ); + public ArgumentEntry cloneToNewClass(ClassEntry classEntry) { + return new ArgumentEntry(this, classEntry.getName()); } - public String getMethodName( ) - { + public String getMethodName() { return m_behaviorEntry.getName(); } - public String getMethodSignature( ) - { + public String getMethodSignature() { return m_behaviorEntry.getSignature(); } @Override - public int hashCode( ) - { - return Util.combineHashesOrdered( m_behaviorEntry, Integer.valueOf( m_index ).hashCode(), m_name.hashCode() ); + public int hashCode() { + return Util.combineHashesOrdered( + m_behaviorEntry, + Integer.valueOf(m_index).hashCode(), + m_name.hashCode() + ); } @Override - public boolean equals( Object other ) - { - if( other instanceof ArgumentEntry ) - { - return equals( (ArgumentEntry)other ); + public boolean equals(Object other) { + if (other instanceof ArgumentEntry) { + return equals((ArgumentEntry)other); } return false; } - public boolean equals( ArgumentEntry other ) - { - return m_behaviorEntry.equals( other.m_behaviorEntry ) + public boolean equals(ArgumentEntry other) { + return m_behaviorEntry.equals(other.m_behaviorEntry) && m_index == other.m_index - && m_name.equals( other.m_name ); + && m_name.equals(other.m_name); } @Override - public String toString( ) - { + public String toString() { return m_behaviorEntry.toString() + "(" + m_index + ":" + m_name + ")"; } } diff --git a/src/cuchaz/enigma/mapping/ArgumentMapping.java b/src/cuchaz/enigma/mapping/ArgumentMapping.java index 168306a2..f4d8e774 100644 --- a/src/cuchaz/enigma/mapping/ArgumentMapping.java +++ b/src/cuchaz/enigma/mapping/ArgumentMapping.java @@ -12,37 +12,33 @@ package cuchaz.enigma.mapping; import java.io.Serializable; -public class ArgumentMapping implements Serializable, Comparable -{ +public class ArgumentMapping implements Serializable, Comparable { + 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 ) - { + public ArgumentMapping(int index, String name) { m_index = index; - m_name = NameValidator.validateArgumentName( name ); + m_name = NameValidator.validateArgumentName(name); } - public int getIndex( ) - { + public int getIndex() { return m_index; } - public String getName( ) - { + public String getName() { return m_name; } - public void setName( String val ) - { - m_name = NameValidator.validateArgumentName( val ); + + public void setName(String val) { + m_name = NameValidator.validateArgumentName(val); } @Override - public int compareTo( ArgumentMapping other ) - { - return Integer.compare( m_index, other.m_index ); + public int compareTo(ArgumentMapping other) { + return Integer.compare(m_index, other.m_index); } } diff --git a/src/cuchaz/enigma/mapping/BehaviorEntry.java b/src/cuchaz/enigma/mapping/BehaviorEntry.java index 8fc4eaf0..f4200b8b 100644 --- a/src/cuchaz/enigma/mapping/BehaviorEntry.java +++ b/src/cuchaz/enigma/mapping/BehaviorEntry.java @@ -10,7 +10,6 @@ ******************************************************************************/ package cuchaz.enigma.mapping; -public interface BehaviorEntry extends Entry -{ +public interface BehaviorEntry extends Entry { String getSignature(); } diff --git a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java index d3cfb938..386faeb8 100644 --- a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java +++ b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java @@ -15,62 +15,43 @@ import javassist.CtConstructor; import javassist.CtMethod; import javassist.bytecode.Descriptor; - -public class BehaviorEntryFactory -{ - public static BehaviorEntry create( String className, String name, String signature ) - { - return create( new ClassEntry( className ), name, signature ); +public class BehaviorEntryFactory { + + public static BehaviorEntry create(String className, String name, String signature) { + return create(new ClassEntry(className), name, signature); } - public static BehaviorEntry create( ClassEntry classEntry, String name, String signature ) - { - if( name.equals( "" ) ) - { - return new ConstructorEntry( classEntry, signature ); - } - else if( name.equals( "" ) ) - { - return new ConstructorEntry( classEntry ); - } - else - { - return new MethodEntry( classEntry, name, signature ); + public static BehaviorEntry create(ClassEntry classEntry, String name, String signature) { + if (name.equals("")) { + return new ConstructorEntry(classEntry, signature); + } else if (name.equals("")) { + return new ConstructorEntry(classEntry); + } else { + return new MethodEntry(classEntry, name, signature); } } - public static BehaviorEntry create( CtBehavior behavior ) - { - String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); - if( behavior instanceof CtMethod ) - { - return create( className, behavior.getName(), behavior.getSignature() ); - } - else if( behavior instanceof CtConstructor ) - { + public static BehaviorEntry create(CtBehavior behavior) { + String className = Descriptor.toJvmName(behavior.getDeclaringClass().getName()); + if (behavior instanceof CtMethod) { + return create(className, behavior.getName(), behavior.getSignature()); + } else if (behavior instanceof CtConstructor) { CtConstructor constructor = (CtConstructor)behavior; - if( constructor.isClassInitializer() ) - { - return create( className, "", null ); - } - else - { - return create( className, "", constructor.getSignature() ); + if (constructor.isClassInitializer()) { + return create(className, "", null); + } else { + return create(className, "", constructor.getSignature()); } - } - else - { - throw new IllegalArgumentException( "Unable to create BehaviorEntry from " + behavior ); + } else { + throw new IllegalArgumentException("Unable to create BehaviorEntry from " + behavior); } } - public static BehaviorEntry createObf( ClassEntry classEntry, MethodMapping methodMapping ) - { - return create( classEntry, methodMapping.getObfName(), methodMapping.getObfSignature() ); + public static BehaviorEntry createObf(ClassEntry classEntry, MethodMapping methodMapping) { + return create(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature()); } - public static BehaviorEntry createDeobf( ClassEntry classEntry, MethodMapping methodMapping ) - { - return create( classEntry, methodMapping.getDeobfName(), methodMapping.getObfSignature() ); + public static BehaviorEntry createDeobf(ClassEntry classEntry, MethodMapping methodMapping) { + return create(classEntry, methodMapping.getDeobfName(), methodMapping.getObfSignature()); } } diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index 2c708f2a..cf410012 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java @@ -12,137 +12,111 @@ package cuchaz.enigma.mapping; import java.io.Serializable; - -public class ClassEntry implements Entry, Serializable -{ +public class ClassEntry implements Entry, Serializable { + private static final long serialVersionUID = 4235460580973955811L; private String m_name; - public ClassEntry( String className ) - { - if( className == null ) - { - throw new IllegalArgumentException( "Class name cannot be null!" ); + public ClassEntry(String className) { + if (className == null) { + throw new IllegalArgumentException("Class name cannot be null!"); } - if( className.indexOf( '.' ) >= 0 ) - { - throw new IllegalArgumentException( "Class name must be in JVM format. ie, path/to/package/class$inner : " + className ); + if (className.indexOf('.') >= 0) { + throw new IllegalArgumentException("Class name must be in JVM format. ie, path/to/package/class$inner : " + className); } m_name = className; - if( isInnerClass() && getInnerClassName().indexOf( '/' ) >= 0 ) - { - throw new IllegalArgumentException( "Inner class must not have a package: " + className ); + if (isInnerClass() && getInnerClassName().indexOf('/') >= 0) { + throw new IllegalArgumentException("Inner class must not have a package: " + className); } } - public ClassEntry( ClassEntry other ) - { + public ClassEntry(ClassEntry other) { m_name = other.m_name; } @Override - public String getName( ) - { + public String getName() { return m_name; } @Override - public String getClassName( ) - { + public String getClassName() { return m_name; } @Override - public ClassEntry getClassEntry( ) - { + public ClassEntry getClassEntry() { return this; } @Override - public ClassEntry cloneToNewClass( ClassEntry classEntry ) - { + public ClassEntry cloneToNewClass(ClassEntry classEntry) { return classEntry; } - + @Override - public int hashCode( ) - { + public int hashCode() { return m_name.hashCode(); } @Override - public boolean equals( Object other ) - { - if( other instanceof ClassEntry ) - { - return equals( (ClassEntry)other ); + public boolean equals(Object other) { + if (other instanceof ClassEntry) { + return equals((ClassEntry)other); } return false; } - public boolean equals( ClassEntry other ) - { - return m_name.equals( other.m_name ); + public boolean equals(ClassEntry other) { + return m_name.equals(other.m_name); } @Override - public String toString( ) - { + public String toString() { return m_name; } - public boolean isInnerClass( ) - { - return m_name.lastIndexOf( '$' ) >= 0; + public boolean isInnerClass() { + return m_name.lastIndexOf('$') >= 0; } - public String getOuterClassName( ) - { - if( isInnerClass() ) - { - return m_name.substring( 0, m_name.lastIndexOf( '$' ) ); + public String getOuterClassName() { + if (isInnerClass()) { + return m_name.substring(0, m_name.lastIndexOf('$')); } return m_name; } - public String getInnerClassName( ) - { - if( !isInnerClass() ) - { - throw new Error( "This is not an inner class!" ); + public String getInnerClassName() { + if (!isInnerClass()) { + throw new Error("This is not an inner class!"); } - return m_name.substring( m_name.lastIndexOf( '$' ) + 1 ); + return m_name.substring(m_name.lastIndexOf('$') + 1); } - public ClassEntry getOuterClassEntry( ) - { - return new ClassEntry( getOuterClassName() ); + public ClassEntry getOuterClassEntry() { + return new ClassEntry(getOuterClassName()); } - public boolean isInDefaultPackage( ) - { - return m_name.indexOf( '/' ) < 0; + public boolean isInDefaultPackage() { + return m_name.indexOf('/') < 0; } - - public String getPackageName( ) - { - int pos = m_name.lastIndexOf( '/' ); - if( pos > 0 ) - { - return m_name.substring( 0, pos ); + + public String getPackageName() { + int pos = m_name.lastIndexOf('/'); + if (pos > 0) { + return m_name.substring(0, pos); } return null; } - - public String getSimpleName( ) - { - int pos = m_name.lastIndexOf( '/' ); - if( pos > 0 ) - { - return m_name.substring( pos + 1 ); + + public String getSimpleName() { + int pos = m_name.lastIndexOf('/'); + if (pos > 0) { + return m_name.substring(pos + 1); } return m_name; } diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java index e084d4df..dbb8717f 100644 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/cuchaz/enigma/mapping/ClassMapping.java @@ -16,8 +16,8 @@ import java.util.Map; import com.google.common.collect.Maps; -public class ClassMapping implements Serializable, Comparable -{ +public class ClassMapping implements Serializable, Comparable { + private static final long serialVersionUID = -5148491146902340107L; private String m_obfName; @@ -29,15 +29,13 @@ public class ClassMapping implements Serializable, Comparable private Map m_methodsByObf; private Map m_methodsByDeobf; - public ClassMapping( String obfName ) - { - this( obfName, null ); + public ClassMapping(String obfName) { + this(obfName, null); } - public ClassMapping( String obfName, String deobfName ) - { + public ClassMapping(String obfName, String deobfName) { m_obfName = obfName; - m_deobfName = NameValidator.validateClassName( deobfName, false ); + m_deobfName = NameValidator.validateClassName(deobfName, false); m_innerClassesByObf = Maps.newHashMap(); m_innerClassesByDeobf = Maps.newHashMap(); m_fieldsByObf = Maps.newHashMap(); @@ -45,439 +43,363 @@ public class ClassMapping implements Serializable, Comparable m_methodsByObf = Maps.newHashMap(); m_methodsByDeobf = Maps.newHashMap(); } - - public String getObfName( ) - { + + public String getObfName() { return m_obfName; } - public String getDeobfName( ) - { + public String getDeobfName() { return m_deobfName; } - public void setDeobfName( String val ) - { - m_deobfName = NameValidator.validateClassName( val, false ); + + public void setDeobfName(String val) { + m_deobfName = NameValidator.validateClassName(val, false); } //// INNER CLASSES //////// - public Iterable innerClasses( ) - { - assert( m_innerClassesByObf.size() >= m_innerClassesByDeobf.size() ); + public Iterable innerClasses() { + assert (m_innerClassesByObf.size() >= m_innerClassesByDeobf.size()); return m_innerClassesByObf.values(); } - public void addInnerClassMapping( ClassMapping classMapping ) - { - assert( isSimpleClassName( classMapping.getObfName() ) ); - boolean obfWasAdded = m_innerClassesByObf.put( classMapping.getObfName(), classMapping ) == null; - assert( obfWasAdded ); - if( classMapping.getDeobfName() != null ) - { - assert( isSimpleClassName( classMapping.getDeobfName() ) ); - boolean deobfWasAdded = m_innerClassesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null; - assert( deobfWasAdded ); + public void addInnerClassMapping(ClassMapping classMapping) { + assert (isSimpleClassName(classMapping.getObfName())); + boolean obfWasAdded = m_innerClassesByObf.put(classMapping.getObfName(), classMapping) == null; + assert (obfWasAdded); + if (classMapping.getDeobfName() != null) { + assert (isSimpleClassName(classMapping.getDeobfName())); + boolean deobfWasAdded = m_innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping) == null; + assert (deobfWasAdded); } } - public void removeInnerClassMapping( ClassMapping classMapping ) - { - boolean obfWasRemoved = m_innerClassesByObf.remove( classMapping.getObfName() ) != null; - assert( obfWasRemoved ); - if( classMapping.getDeobfName() != null ) - { - boolean deobfWasRemoved = m_innerClassesByDeobf.remove( classMapping.getDeobfName() ) != null; - assert( deobfWasRemoved ); + public void removeInnerClassMapping(ClassMapping classMapping) { + boolean obfWasRemoved = m_innerClassesByObf.remove(classMapping.getObfName()) != null; + assert (obfWasRemoved); + if (classMapping.getDeobfName() != null) { + boolean deobfWasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; + assert (deobfWasRemoved); } } - public ClassMapping getOrCreateInnerClass( String obfName ) - { - assert( isSimpleClassName( obfName ) ); - ClassMapping classMapping = m_innerClassesByObf.get( obfName ); - if( classMapping == null ) - { - classMapping = new ClassMapping( obfName ); - boolean wasAdded = m_innerClassesByObf.put( obfName, classMapping ) == null; - assert( wasAdded ); + public ClassMapping getOrCreateInnerClass(String obfName) { + assert (isSimpleClassName(obfName)); + ClassMapping classMapping = m_innerClassesByObf.get(obfName); + if (classMapping == null) { + classMapping = new ClassMapping(obfName); + boolean wasAdded = m_innerClassesByObf.put(obfName, classMapping) == null; + assert (wasAdded); } return classMapping; } - public ClassMapping getInnerClassByObf( String obfName ) - { - assert( isSimpleClassName( obfName ) ); - return m_innerClassesByObf.get( obfName ); + public ClassMapping getInnerClassByObf(String obfName) { + assert (isSimpleClassName(obfName)); + return m_innerClassesByObf.get(obfName); } - public ClassMapping getInnerClassByDeobf( String deobfName ) - { - assert( isSimpleClassName( deobfName ) ); - return m_innerClassesByDeobf.get( deobfName ); + public ClassMapping getInnerClassByDeobf(String deobfName) { + assert (isSimpleClassName(deobfName)); + return m_innerClassesByDeobf.get(deobfName); } - public ClassMapping getInnerClassByDeobfThenObf( String name ) - { - ClassMapping classMapping = getInnerClassByDeobf( name ); - if( classMapping == null ) - { - classMapping = getInnerClassByObf( name ); + public ClassMapping getInnerClassByDeobfThenObf(String name) { + ClassMapping classMapping = getInnerClassByDeobf(name); + if (classMapping == null) { + classMapping = getInnerClassByObf(name); } return classMapping; } - public String getObfInnerClassName( String deobfName ) - { - assert( isSimpleClassName( deobfName ) ); - ClassMapping classMapping = m_innerClassesByDeobf.get( deobfName ); - if( classMapping != null ) - { + public String getObfInnerClassName(String deobfName) { + assert (isSimpleClassName(deobfName)); + ClassMapping classMapping = m_innerClassesByDeobf.get(deobfName); + if (classMapping != null) { return classMapping.getObfName(); } return null; } - public String getDeobfInnerClassName( String obfName ) - { - assert( isSimpleClassName( obfName ) ); - ClassMapping classMapping = m_innerClassesByObf.get( obfName ); - if( classMapping != null ) - { + public String getDeobfInnerClassName(String obfName) { + assert (isSimpleClassName(obfName)); + ClassMapping classMapping = m_innerClassesByObf.get(obfName); + if (classMapping != null) { return classMapping.getDeobfName(); } return null; } - public void setInnerClassName( String obfName, String deobfName ) - { - assert( isSimpleClassName( obfName ) ); - ClassMapping classMapping = getOrCreateInnerClass( obfName ); - if( classMapping.getDeobfName() != null ) - { - boolean wasRemoved = m_innerClassesByDeobf.remove( classMapping.getDeobfName() ) != null; - assert( wasRemoved ); + public void setInnerClassName(String obfName, String deobfName) { + assert (isSimpleClassName(obfName)); + ClassMapping classMapping = getOrCreateInnerClass(obfName); + if (classMapping.getDeobfName() != null) { + boolean wasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; + assert (wasRemoved); } - classMapping.setDeobfName( deobfName ); - if( deobfName != null ) - { - assert( isSimpleClassName( deobfName ) ); - boolean wasAdded = m_innerClassesByDeobf.put( deobfName, classMapping ) == null; - assert( wasAdded ); + classMapping.setDeobfName(deobfName); + if (deobfName != null) { + assert (isSimpleClassName(deobfName)); + boolean wasAdded = m_innerClassesByDeobf.put(deobfName, classMapping) == null; + assert (wasAdded); } } //// FIELDS //////// - public Iterable fields( ) - { - assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() ); + public Iterable fields() { + assert (m_fieldsByObf.size() == m_fieldsByDeobf.size()); return m_fieldsByObf.values(); } - public boolean containsObfField( String obfName ) - { - return m_fieldsByObf.containsKey( obfName ); + public boolean containsObfField(String obfName) { + return m_fieldsByObf.containsKey(obfName); } - public boolean containsDeobfField( String deobfName ) - { - return m_fieldsByDeobf.containsKey( deobfName ); + public boolean containsDeobfField(String deobfName) { + return m_fieldsByDeobf.containsKey(deobfName); } - public void addFieldMapping( FieldMapping fieldMapping ) - { - if( m_fieldsByObf.containsKey( fieldMapping.getObfName() ) ) - { - throw new Error( "Already have mapping for " + m_obfName + "." + fieldMapping.getObfName() ); + public void addFieldMapping(FieldMapping fieldMapping) { + if (m_fieldsByObf.containsKey(fieldMapping.getObfName())) { + throw new Error("Already have mapping for " + m_obfName + "." + fieldMapping.getObfName()); } - if( m_fieldsByDeobf.containsKey( fieldMapping.getDeobfName() ) ) - { - throw new Error( "Already have mapping for " + m_deobfName + "." + fieldMapping.getDeobfName() ); + if (m_fieldsByDeobf.containsKey(fieldMapping.getDeobfName())) { + throw new Error("Already have mapping for " + m_deobfName + "." + fieldMapping.getDeobfName()); } - boolean obfWasAdded = m_fieldsByObf.put( fieldMapping.getObfName(), fieldMapping ) == null; - assert( obfWasAdded ); - boolean deobfWasAdded = m_fieldsByDeobf.put( fieldMapping.getDeobfName(), fieldMapping ) == null; - assert( deobfWasAdded ); - assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() ); - } - - public void removeFieldMapping( FieldMapping fieldMapping ) - { - boolean obfWasRemoved = m_fieldsByObf.remove( fieldMapping.getObfName() ) != null; - assert( obfWasRemoved ); - if( fieldMapping.getDeobfName() != null ) - { - boolean deobfWasRemoved = m_fieldsByDeobf.remove( fieldMapping.getDeobfName() ) != null; - assert( deobfWasRemoved ); + boolean obfWasAdded = m_fieldsByObf.put(fieldMapping.getObfName(), fieldMapping) == null; + assert (obfWasAdded); + boolean deobfWasAdded = m_fieldsByDeobf.put(fieldMapping.getDeobfName(), fieldMapping) == null; + assert (deobfWasAdded); + assert (m_fieldsByObf.size() == m_fieldsByDeobf.size()); + } + + public void removeFieldMapping(FieldMapping fieldMapping) { + boolean obfWasRemoved = m_fieldsByObf.remove(fieldMapping.getObfName()) != null; + assert (obfWasRemoved); + if (fieldMapping.getDeobfName() != null) { + boolean deobfWasRemoved = m_fieldsByDeobf.remove(fieldMapping.getDeobfName()) != null; + assert (deobfWasRemoved); } } - public FieldMapping getFieldByObf( String obfName ) - { - return m_fieldsByObf.get( obfName ); + public FieldMapping getFieldByObf(String obfName) { + return m_fieldsByObf.get(obfName); } - public FieldMapping getFieldByDeobf( String deobfName ) - { - return m_fieldsByDeobf.get( deobfName ); + public FieldMapping getFieldByDeobf(String deobfName) { + return m_fieldsByDeobf.get(deobfName); } - - public String getObfFieldName( String deobfName ) - { - FieldMapping fieldMapping = m_fieldsByDeobf.get( deobfName ); - if( fieldMapping != null ) - { + + 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 ) - { + 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 ) - { - FieldMapping fieldMapping = m_fieldsByObf.get( obfName ); - if( fieldMapping == null ) - { - fieldMapping = new FieldMapping( obfName, deobfName ); - boolean obfWasAdded = m_fieldsByObf.put( obfName, fieldMapping ) == null; - assert( obfWasAdded ); + public void setFieldName(String obfName, String deobfName) { + FieldMapping fieldMapping = m_fieldsByObf.get(obfName); + if (fieldMapping == null) { + fieldMapping = new FieldMapping(obfName, deobfName); + boolean obfWasAdded = m_fieldsByObf.put(obfName, fieldMapping) == null; + assert (obfWasAdded); + } else { + boolean wasRemoved = m_fieldsByDeobf.remove(fieldMapping.getDeobfName()) != null; + assert (wasRemoved); } - else - { - boolean wasRemoved = m_fieldsByDeobf.remove( fieldMapping.getDeobfName() ) != null; - assert( wasRemoved ); - } - fieldMapping.setDeobfName( deobfName ); - if( deobfName != null ) - { - boolean wasAdded = m_fieldsByDeobf.put( deobfName, fieldMapping ) == null; - assert( wasAdded ); + fieldMapping.setDeobfName(deobfName); + if (deobfName != null) { + boolean wasAdded = m_fieldsByDeobf.put(deobfName, fieldMapping) == null; + assert (wasAdded); } } //// METHODS //////// - public Iterable methods( ) - { - assert( m_methodsByObf.size() >= m_methodsByDeobf.size() ); + public Iterable methods() { + assert (m_methodsByObf.size() >= m_methodsByDeobf.size()); return m_methodsByObf.values(); } - public boolean containsObfMethod( String obfName, String obfSignature ) - { - return m_methodsByObf.containsKey( getMethodKey( obfName, obfSignature ) ); + public boolean containsObfMethod(String obfName, String obfSignature) { + return m_methodsByObf.containsKey(getMethodKey(obfName, obfSignature)); } - public boolean containsDeobfMethod( String deobfName, String deobfSignature ) - { - return m_methodsByDeobf.containsKey( getMethodKey( deobfName, deobfSignature ) ); + public boolean containsDeobfMethod(String deobfName, String deobfSignature) { + return m_methodsByDeobf.containsKey(getMethodKey(deobfName, deobfSignature)); } - public void addMethodMapping( MethodMapping methodMapping ) - { - String obfKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ); - if( m_methodsByObf.containsKey( obfKey ) ) - { - throw new Error( "Already have mapping for " + m_obfName + "." + obfKey ); + public void addMethodMapping(MethodMapping methodMapping) { + String obfKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()); + if (m_methodsByObf.containsKey(obfKey)) { + throw new Error("Already have mapping for " + m_obfName + "." + obfKey); } - boolean wasAdded = m_methodsByObf.put( obfKey, methodMapping ) == null; - assert( wasAdded ); - if( methodMapping.getDeobfName() != null ) - { - String deobfKey = getMethodKey( methodMapping.getDeobfName(), methodMapping.getObfSignature() ); - if( m_methodsByDeobf.containsKey( deobfKey ) ) - { - throw new Error( "Already have mapping for " + m_deobfName + "." + deobfKey ); + boolean wasAdded = m_methodsByObf.put(obfKey, methodMapping) == null; + assert (wasAdded); + if (methodMapping.getDeobfName() != null) { + String deobfKey = getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature()); + if (m_methodsByDeobf.containsKey(deobfKey)) { + throw new Error("Already have mapping for " + m_deobfName + "." + deobfKey); } - boolean deobfWasAdded = m_methodsByDeobf.put( deobfKey, methodMapping ) == null; - assert( deobfWasAdded ); + boolean deobfWasAdded = m_methodsByDeobf.put(deobfKey, methodMapping) == null; + assert (deobfWasAdded); } - assert( m_methodsByObf.size() >= m_methodsByDeobf.size() ); + assert (m_methodsByObf.size() >= m_methodsByDeobf.size()); } - public void removeMethodMapping( MethodMapping methodMapping ) - { - boolean obfWasRemoved = m_methodsByObf.remove( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ) ) != null; - assert( obfWasRemoved ); - if( methodMapping.getDeobfName() != null ) - { - boolean deobfWasRemoved = m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) ) != null; - assert( deobfWasRemoved ); + public void removeMethodMapping(MethodMapping methodMapping) { + boolean obfWasRemoved = m_methodsByObf.remove(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature())) != null; + assert (obfWasRemoved); + if (methodMapping.getDeobfName() != null) { + boolean deobfWasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null; + assert (deobfWasRemoved); } } - public MethodMapping getMethodByObf( String obfName, String signature ) - { - return m_methodsByObf.get( getMethodKey( obfName, signature ) ); + 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 ) ); + 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!" ); + 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!" ); + if (signature == null) { + throw new IllegalArgumentException("signature cannot be null!"); } return name + signature; } - public void setMethodName( String obfName, String obfSignature, String deobfName ) - { - MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) ); - if( methodMapping == null ) - { - methodMapping = createMethodMapping( obfName, obfSignature ); - } - else if( methodMapping.getDeobfName() != null ) - { - boolean wasRemoved = m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) ) != null; - assert( wasRemoved ); + public void setMethodName(String obfName, String obfSignature, String deobfName) { + MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfName, obfSignature)); + if (methodMapping == null) { + methodMapping = createMethodMapping(obfName, obfSignature); + } else if (methodMapping.getDeobfName() != null) { + boolean wasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null; + assert (wasRemoved); } - methodMapping.setDeobfName( deobfName ); - if( deobfName != null ) - { - boolean wasAdded = m_methodsByDeobf.put( getMethodKey( deobfName, obfSignature ), methodMapping ) == null; - assert( wasAdded ); + methodMapping.setDeobfName(deobfName); + if (deobfName != null) { + boolean wasAdded = m_methodsByDeobf.put(getMethodKey(deobfName, obfSignature), methodMapping) == null; + assert (wasAdded); } } //// ARGUMENTS //////// - public void setArgumentName( String obfMethodName, String obfMethodSignature, int argumentIndex, String argumentName ) - { - MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) ); - if( methodMapping == null ) - { - methodMapping = createMethodMapping( obfMethodName, obfMethodSignature ); + public void setArgumentName(String obfMethodName, String obfMethodSignature, int argumentIndex, String argumentName) { + MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)); + if (methodMapping == null) { + methodMapping = createMethodMapping(obfMethodName, obfMethodSignature); } - methodMapping.setArgumentName( argumentIndex, argumentName ); + methodMapping.setArgumentName(argumentIndex, argumentName); } - public void removeArgumentName( String obfMethodName, String obfMethodSignature, int argumentIndex ) - { - m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) ).removeArgumentName( argumentIndex ); + public void removeArgumentName(String obfMethodName, String obfMethodSignature, int argumentIndex) { + m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)).removeArgumentName(argumentIndex); } - - private MethodMapping createMethodMapping( String obfName, String obfSignature ) - { - MethodMapping methodMapping = new MethodMapping( obfName, obfSignature ); - boolean wasAdded = m_methodsByObf.put( getMethodKey( obfName, obfSignature ), methodMapping ) == null; - assert( wasAdded ); + + private MethodMapping createMethodMapping(String obfName, String obfSignature) { + MethodMapping methodMapping = new MethodMapping(obfName, obfSignature); + boolean wasAdded = m_methodsByObf.put(getMethodKey(obfName, obfSignature), methodMapping) == null; + assert (wasAdded); return methodMapping; } - + @Override - public String toString( ) - { + 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 methodMapping : m_methodsByObf.values() ) - { - buf.append( methodMapping.toString() ); - buf.append( "\n" ); - } - buf.append( "Inner Classes:\n" ); - for( ClassMapping classMapping : m_innerClassesByObf.values() ) - { - buf.append( "\t" ); - buf.append( classMapping.getObfName() ); - buf.append( " <-> " ); - buf.append( classMapping.getDeobfName() ); - buf.append( "\n" ); + 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 methodMapping : m_methodsByObf.values()) { + buf.append(methodMapping.toString()); + buf.append("\n"); + } + buf.append("Inner Classes:\n"); + for (ClassMapping classMapping : m_innerClassesByObf.values()) { + buf.append("\t"); + buf.append(classMapping.getObfName()); + buf.append(" <-> "); + buf.append(classMapping.getDeobfName()); + buf.append("\n"); } return buf.toString(); } @Override - public int compareTo( ClassMapping other ) - { + public int compareTo(ClassMapping other) { // sort by a, b, c, ... aa, ab, etc - if( m_obfName.length() != other.m_obfName.length() ) - { + if (m_obfName.length() != other.m_obfName.length()) { return m_obfName.length() - other.m_obfName.length(); } - return m_obfName.compareTo( other.m_obfName ); + return m_obfName.compareTo(other.m_obfName); } - public boolean renameObfClass( String oldObfClassName, String newObfClassName ) - { + public boolean renameObfClass(String oldObfClassName, String newObfClassName) { + // rename inner classes - for( ClassMapping innerClassMapping : new ArrayList( m_innerClassesByObf.values() ) ) - { - if( innerClassMapping.renameObfClass( oldObfClassName, newObfClassName ) ) - { - boolean wasRemoved = m_innerClassesByObf.remove( oldObfClassName ) != null; - assert( wasRemoved ); - boolean wasAdded = m_innerClassesByObf.put( newObfClassName, innerClassMapping ) == null; - assert( wasAdded ); + for (ClassMapping innerClassMapping : new ArrayList(m_innerClassesByObf.values())) { + if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) { + boolean wasRemoved = m_innerClassesByObf.remove(oldObfClassName) != null; + assert (wasRemoved); + boolean wasAdded = m_innerClassesByObf.put(newObfClassName, innerClassMapping) == null; + assert (wasAdded); } } // rename method signatures - for( MethodMapping methodMapping : new ArrayList( m_methodsByObf.values() ) ) - { - String oldMethodKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ); - if( methodMapping.renameObfClass( oldObfClassName, newObfClassName ) ) - { - boolean wasRemoved = m_methodsByObf.remove( oldMethodKey ) != null; - assert( wasRemoved ); - boolean wasAdded = m_methodsByObf.put( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ), methodMapping ) == null; - assert( wasAdded ); + for (MethodMapping methodMapping : new ArrayList(m_methodsByObf.values())) { + String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()); + if (methodMapping.renameObfClass(oldObfClassName, newObfClassName)) { + boolean wasRemoved = m_methodsByObf.remove(oldMethodKey) != null; + assert (wasRemoved); + boolean wasAdded = m_methodsByObf.put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()), methodMapping) == null; + assert (wasAdded); } } - if( m_obfName.equals( oldObfClassName ) ) - { + if (m_obfName.equals(oldObfClassName)) { // rename this class m_obfName = newObfClassName; return true; } return false; } - - public boolean containsArgument( BehaviorEntry obfBehaviorEntry, String name ) - { - MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature() ) ); - if( methodMapping != null ) - { - return methodMapping.containsArgument( name ); + + public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) { + MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature())); + if (methodMapping != null) { + return methodMapping.containsArgument(name); } return false; } - public static boolean isSimpleClassName( String name ) - { - return name.indexOf( '/' ) < 0 && name.indexOf( '$' ) < 0; + public static boolean isSimpleClassName(String name) { + return name.indexOf('/') < 0 && name.indexOf('$') < 0; } } diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java index d99d1c35..ea0535f8 100644 --- a/src/cuchaz/enigma/mapping/ConstructorEntry.java +++ b/src/cuchaz/enigma/mapping/ConstructorEntry.java @@ -14,129 +14,102 @@ import java.io.Serializable; import cuchaz.enigma.Util; -public class ConstructorEntry implements BehaviorEntry, Serializable -{ +public class ConstructorEntry implements BehaviorEntry, Serializable { + private static final long serialVersionUID = -868346075317366758L; private ClassEntry m_classEntry; private String m_signature; - public ConstructorEntry( ClassEntry classEntry ) - { - this( classEntry, null ); + public ConstructorEntry(ClassEntry classEntry) { + this(classEntry, null); } - public ConstructorEntry( ClassEntry classEntry, String signature ) - { - if( classEntry == null ) - { - throw new IllegalArgumentException( "Class cannot be null!" ); + public ConstructorEntry(ClassEntry classEntry, String signature) { + if (classEntry == null) { + throw new IllegalArgumentException("Class cannot be null!"); } m_classEntry = classEntry; m_signature = signature; } - public ConstructorEntry( ConstructorEntry other ) - { - m_classEntry = new ClassEntry( other.m_classEntry ); + public ConstructorEntry(ConstructorEntry other) { + m_classEntry = new ClassEntry(other.m_classEntry); m_signature = other.m_signature; } - public ConstructorEntry( ConstructorEntry other, String newClassName ) - { - m_classEntry = new ClassEntry( newClassName ); + public ConstructorEntry(ConstructorEntry other, String newClassName) { + m_classEntry = new ClassEntry(newClassName); m_signature = other.m_signature; } @Override - public ClassEntry getClassEntry( ) - { + public ClassEntry getClassEntry() { return m_classEntry; } @Override - public String getName( ) - { - if( isStatic() ) - { + public String getName() { + if (isStatic()) { return ""; } return ""; } - public boolean isStatic( ) - { + public boolean isStatic() { return m_signature == null; } @Override - public String getSignature( ) - { + public String getSignature() { return m_signature; } @Override - public String getClassName( ) - { + public String getClassName() { return m_classEntry.getName(); } @Override - public ConstructorEntry cloneToNewClass( ClassEntry classEntry ) - { - return new ConstructorEntry( this, classEntry.getName() ); + public ConstructorEntry cloneToNewClass(ClassEntry classEntry) { + return new ConstructorEntry(this, classEntry.getName()); } @Override - public int hashCode( ) - { - if( isStatic() ) - { - return Util.combineHashesOrdered( m_classEntry ); - } - else - { - return Util.combineHashesOrdered( m_classEntry, m_signature ); + public int hashCode() { + if (isStatic()) { + return Util.combineHashesOrdered(m_classEntry); + } else { + return Util.combineHashesOrdered(m_classEntry, m_signature); } } @Override - public boolean equals( Object other ) - { - if( other instanceof ConstructorEntry ) - { - return equals( (ConstructorEntry)other ); + public boolean equals(Object other) { + if (other instanceof ConstructorEntry) { + return equals((ConstructorEntry)other); } return false; } - public boolean equals( ConstructorEntry other ) - { - if( isStatic() != other.isStatic() ) - { + public boolean equals(ConstructorEntry other) { + if (isStatic() != other.isStatic()) { return false; } - if( isStatic() ) - { - return m_classEntry.equals( other.m_classEntry ); - } - else - { - return m_classEntry.equals( other.m_classEntry ) && m_signature.equals( other.m_signature ); + if (isStatic()) { + return m_classEntry.equals(other.m_classEntry); + } else { + return m_classEntry.equals(other.m_classEntry) && m_signature.equals(other.m_signature); } } @Override - public String toString( ) - { - if( isStatic() ) - { + public String toString() { + if (isStatic()) { return m_classEntry.getName() + "." + getName(); - } - else - { + } else { return m_classEntry.getName() + "." + getName() + m_signature; } } diff --git a/src/cuchaz/enigma/mapping/Entry.java b/src/cuchaz/enigma/mapping/Entry.java index 8524834c..39e1507d 100644 --- a/src/cuchaz/enigma/mapping/Entry.java +++ b/src/cuchaz/enigma/mapping/Entry.java @@ -10,10 +10,9 @@ ******************************************************************************/ package cuchaz.enigma.mapping; -public interface Entry -{ - String getName( ); - String getClassName( ); - ClassEntry getClassEntry( ); - Entry cloneToNewClass( ClassEntry classEntry ); +public interface Entry { + String getName(); + String getClassName(); + ClassEntry getClassEntry(); + Entry cloneToNewClass(ClassEntry classEntry); } diff --git a/src/cuchaz/enigma/mapping/EntryPair.java b/src/cuchaz/enigma/mapping/EntryPair.java index f94d77ea..60411c40 100644 --- a/src/cuchaz/enigma/mapping/EntryPair.java +++ b/src/cuchaz/enigma/mapping/EntryPair.java @@ -10,15 +10,12 @@ ******************************************************************************/ package cuchaz.enigma.mapping; - - -public class EntryPair -{ +public class EntryPair { + public T obf; public T deobf; - public EntryPair( T obf, T deobf ) - { + public EntryPair(T obf, T deobf) { this.obf = obf; this.deobf = deobf; } diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java index 626af576..6cc9eb78 100644 --- a/src/cuchaz/enigma/mapping/FieldEntry.java +++ b/src/cuchaz/enigma/mapping/FieldEntry.java @@ -14,90 +14,75 @@ import java.io.Serializable; import cuchaz.enigma.Util; -public class FieldEntry implements Entry, Serializable -{ +public class FieldEntry implements Entry, Serializable { + private static final long serialVersionUID = 3004663582802885451L; 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 ) - { - throw new IllegalArgumentException( "Class cannot be null!" ); + public FieldEntry(ClassEntry classEntry, String name) { + if (classEntry == null) { + throw new IllegalArgumentException("Class cannot be null!"); } - if( name == null ) - { - throw new IllegalArgumentException( "Field name cannot be null!" ); + if (name == null) { + throw new IllegalArgumentException("Field name cannot be null!"); } m_classEntry = classEntry; m_name = name; } - public FieldEntry( FieldEntry other ) - { - m_classEntry = new ClassEntry( other.m_classEntry ); + public FieldEntry(FieldEntry other) { + m_classEntry = new ClassEntry(other.m_classEntry); m_name = other.m_name; } - - public FieldEntry( FieldEntry other, String newClassName ) - { - m_classEntry = new ClassEntry( newClassName ); + + public FieldEntry(FieldEntry other, String newClassName) { + m_classEntry = new ClassEntry(newClassName); m_name = other.m_name; } @Override - public ClassEntry getClassEntry( ) - { + public ClassEntry getClassEntry() { return m_classEntry; } @Override - public String getName( ) - { + public String getName() { return m_name; } @Override - public String getClassName( ) - { + public String getClassName() { return m_classEntry.getName(); } @Override - public FieldEntry cloneToNewClass( ClassEntry classEntry ) - { - return new FieldEntry( this, classEntry.getName() ); + public FieldEntry cloneToNewClass(ClassEntry classEntry) { + return new FieldEntry(this, classEntry.getName()); } @Override - public int hashCode( ) - { - return Util.combineHashesOrdered( m_classEntry, m_name ); + public int hashCode() { + return Util.combineHashesOrdered(m_classEntry, m_name); } @Override - public boolean equals( Object other ) - { - if( other instanceof FieldEntry ) - { - return equals( (FieldEntry)other ); + public boolean equals(Object other) { + if (other instanceof FieldEntry) { + return equals((FieldEntry)other); } return false; } - public boolean equals( FieldEntry other ) - { - return m_classEntry.equals( other.m_classEntry ) - && m_name.equals( other.m_name ); + public boolean equals(FieldEntry other) { + return m_classEntry.equals(other.m_classEntry) && m_name.equals(other.m_name); } @Override - public String toString( ) - { + public String toString() { return m_classEntry.getName() + "." + m_name; } } diff --git a/src/cuchaz/enigma/mapping/FieldMapping.java b/src/cuchaz/enigma/mapping/FieldMapping.java index ae0855a8..5f5c270d 100644 --- a/src/cuchaz/enigma/mapping/FieldMapping.java +++ b/src/cuchaz/enigma/mapping/FieldMapping.java @@ -12,36 +12,32 @@ package cuchaz.enigma.mapping; import java.io.Serializable; -public class FieldMapping implements Serializable, Comparable -{ +public class FieldMapping implements Serializable, Comparable { + private static final long serialVersionUID = 8610742471440861315L; private String m_obfName; private String m_deobfName; - public FieldMapping( String obfName, String deobfName ) - { + public FieldMapping(String obfName, String deobfName) { m_obfName = obfName; - m_deobfName = NameValidator.validateFieldName( deobfName ); + m_deobfName = NameValidator.validateFieldName(deobfName); } - - public String getObfName( ) - { + + public String getObfName() { return m_obfName; } - - public String getDeobfName( ) - { + + public String getDeobfName() { return m_deobfName; } - public void setDeobfName( String val ) - { - m_deobfName = NameValidator.validateFieldName( val ); + + public void setDeobfName(String val) { + m_deobfName = NameValidator.validateFieldName(val); } @Override - public int compareTo( FieldMapping other ) - { - return m_obfName.compareTo( other.m_obfName ); + 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 index 830f05c4..aacaf3b0 100644 --- a/src/cuchaz/enigma/mapping/IllegalNameException.java +++ b/src/cuchaz/enigma/mapping/IllegalNameException.java @@ -10,39 +10,34 @@ ******************************************************************************/ package cuchaz.enigma.mapping; -public class IllegalNameException extends RuntimeException -{ +public class IllegalNameException extends RuntimeException { + private static final long serialVersionUID = -2279910052561114323L; private String m_name; private String m_reason; - public IllegalNameException( String name ) - { - this( name, null ); + public IllegalNameException(String name) { + this(name, null); } - public IllegalNameException( String name, String reason ) - { + public IllegalNameException(String name, String reason) { m_name = name; m_reason = reason; } - public String getReason( ) - { + public String getReason() { return m_reason; } @Override - public String getMessage( ) - { + public String getMessage() { StringBuilder buf = new StringBuilder(); - buf.append( "Illegal name: " ); - buf.append( m_name ); - if( m_reason != null ) - { - buf.append( " because " ); - buf.append( m_reason ); + buf.append("Illegal name: "); + buf.append(m_name); + if (m_reason != null) { + buf.append(" because "); + buf.append(m_reason); } return buf.toString(); } diff --git a/src/cuchaz/enigma/mapping/MappingParseException.java b/src/cuchaz/enigma/mapping/MappingParseException.java index 4fcc1f18..1974c222 100644 --- a/src/cuchaz/enigma/mapping/MappingParseException.java +++ b/src/cuchaz/enigma/mapping/MappingParseException.java @@ -10,22 +10,20 @@ ******************************************************************************/ package cuchaz.enigma.mapping; -public class MappingParseException extends Exception -{ +public class MappingParseException extends Exception { + private static final long serialVersionUID = -5487280332892507236L; private int m_line; private String m_message; - public MappingParseException( int line, String message ) - { + public MappingParseException(int line, String message) { m_line = line; m_message = message; } @Override - public String getMessage( ) - { + public String getMessage() { return "Line " + m_line + ": " + m_message; } } diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 3a39d100..c5e38f4b 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -26,230 +26,182 @@ import com.google.common.collect.Sets; import cuchaz.enigma.Util; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; -public class Mappings implements Serializable -{ +public class Mappings implements Serializable { + private static final long serialVersionUID = 4649790259460259026L; protected Map m_classesByObf; protected Map m_classesByDeobf; - public Mappings( ) - { + public Mappings() { m_classesByObf = Maps.newHashMap(); m_classesByDeobf = Maps.newHashMap(); } - public Mappings( Iterable classes ) - { + public Mappings(Iterable classes) { this(); - for( ClassMapping classMapping : classes ) - { - m_classesByObf.put( classMapping.getObfName(), classMapping ); - if( classMapping.getDeobfName() != null ) - { - m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ); + for (ClassMapping classMapping : classes) { + m_classesByObf.put(classMapping.getObfName(), classMapping); + if (classMapping.getDeobfName() != null) { + m_classesByDeobf.put(classMapping.getDeobfName(), classMapping); } } } - public static Mappings newFromResource( String resource ) - throws IOException - { + public static Mappings newFromResource(String resource) throws IOException { InputStream in = null; - try - { - in = Mappings.class.getResourceAsStream( resource ); - return newFromStream( in ); - } - finally - { - Util.closeQuietly( in ); + try { + in = Mappings.class.getResourceAsStream(resource); + return newFromStream(in); + } finally { + Util.closeQuietly(in); } } - public Collection classes( ) - { - assert( m_classesByObf.size() >= m_classesByDeobf.size() ); + public Collection classes() { + assert (m_classesByObf.size() >= m_classesByDeobf.size()); return m_classesByObf.values(); } - public void addClassMapping( ClassMapping classMapping ) - { - if( m_classesByObf.containsKey( classMapping.getObfName() ) ) - { - throw new Error( "Already have mapping for " + classMapping.getObfName() ); + public void addClassMapping(ClassMapping classMapping) { + if (m_classesByObf.containsKey(classMapping.getObfName())) { + throw new Error("Already have mapping for " + classMapping.getObfName()); } - boolean obfWasAdded = m_classesByObf.put( classMapping.getObfName(), classMapping ) == null; - assert( obfWasAdded ); - if( classMapping.getDeobfName() != null ) - { - if( m_classesByDeobf.containsKey( classMapping.getDeobfName() ) ) - { - throw new Error( "Already have mapping for " + classMapping.getDeobfName() ); + boolean obfWasAdded = m_classesByObf.put(classMapping.getObfName(), classMapping) == null; + assert (obfWasAdded); + if (classMapping.getDeobfName() != null) { + if (m_classesByDeobf.containsKey(classMapping.getDeobfName())) { + throw new Error("Already have mapping for " + classMapping.getDeobfName()); } - boolean deobfWasAdded = m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null; - assert( deobfWasAdded ); + boolean deobfWasAdded = m_classesByDeobf.put(classMapping.getDeobfName(), classMapping) == null; + assert (deobfWasAdded); } } - public void removeClassMapping( ClassMapping classMapping ) - { - boolean obfWasRemoved = m_classesByObf.remove( classMapping.getObfName() ) != null; - assert( obfWasRemoved ); - if( classMapping.getDeobfName() != null ) - { - boolean deobfWasRemoved = m_classesByDeobf.remove( classMapping.getDeobfName() ) != null; - assert( deobfWasRemoved ); + public void removeClassMapping(ClassMapping classMapping) { + boolean obfWasRemoved = m_classesByObf.remove(classMapping.getObfName()) != null; + assert (obfWasRemoved); + if (classMapping.getDeobfName() != null) { + boolean deobfWasRemoved = m_classesByDeobf.remove(classMapping.getDeobfName()) != null; + assert (deobfWasRemoved); } } - public ClassMapping getClassByObf( ClassEntry entry ) - { - return getClassByObf( entry.getName() ); + public ClassMapping getClassByObf(ClassEntry entry) { + return getClassByObf(entry.getName()); } - public ClassMapping getClassByObf( String obfName ) - { - return m_classesByObf.get( obfName ); + public ClassMapping getClassByObf(String obfName) { + return m_classesByObf.get(obfName); } - public ClassMapping getClassByDeobf( ClassEntry entry ) - { - return getClassByDeobf( entry.getName() ); + public ClassMapping getClassByDeobf(ClassEntry entry) { + return getClassByDeobf(entry.getName()); } - public ClassMapping getClassByDeobf( String deobfName ) - { - return m_classesByDeobf.get( deobfName ); + public ClassMapping getClassByDeobf(String deobfName) { + return m_classesByDeobf.get(deobfName); } - public Translator getTranslator( TranslationDirection direction ) - { - switch( direction ) - { + public Translator getTranslator(TranslationDirection direction) { + switch (direction) { case Deobfuscating: - return new Translator( direction, m_classesByObf ); + return new Translator(direction, m_classesByObf); case Obfuscating: // fill in the missing deobf class entries with obf entries Map classes = Maps.newHashMap(); - for( ClassMapping classMapping : classes() ) - { - if( classMapping.getDeobfName() != null ) - { - classes.put( classMapping.getDeobfName(), classMapping ); - } - else - { - classes.put( classMapping.getObfName(), classMapping ); + for (ClassMapping classMapping : classes()) { + if (classMapping.getDeobfName() != null) { + classes.put(classMapping.getDeobfName(), classMapping); + } else { + classes.put(classMapping.getObfName(), classMapping); } } - return new Translator( direction, classes ); + return new Translator(direction, classes); default: - throw new Error( "Invalid translation direction!" ); + throw new Error("Invalid translation direction!"); } } - public static Mappings newFromStream( InputStream in ) - throws IOException - { - try - { - return (Mappings)new ObjectInputStream( new GZIPInputStream( in ) ).readObject(); - } - catch( ClassNotFoundException ex ) - { - throw new Error( ex ); + 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( ) - { + public String toString() { StringBuilder buf = new StringBuilder(); - for( ClassMapping classMapping : m_classesByObf.values() ) - { - buf.append( classMapping.toString() ); - buf.append( "\n" ); + for (ClassMapping classMapping : m_classesByObf.values()) { + buf.append(classMapping.toString()); + buf.append("\n"); } return buf.toString(); } - public void renameObfClass( String oldObfName, String newObfName ) - { - for( ClassMapping classMapping : new ArrayList( classes() ) ) - { - if( classMapping.renameObfClass( oldObfName, newObfName ) ) - { - boolean wasRemoved = m_classesByObf.remove( oldObfName ) != null; - assert( wasRemoved ); - boolean wasAdded = m_classesByObf.put( newObfName, classMapping ) == null; - assert( wasAdded ); + public void renameObfClass(String oldObfName, String newObfName) { + for (ClassMapping classMapping : new ArrayList(classes())) { + if (classMapping.renameObfClass(oldObfName, newObfName)) { + boolean wasRemoved = m_classesByObf.remove(oldObfName) != null; + assert (wasRemoved); + boolean wasAdded = m_classesByObf.put(newObfName, classMapping) == null; + assert (wasAdded); } } } - public Set getAllObfClassNames( ) - { + public Set getAllObfClassNames() { final Set classNames = Sets.newHashSet(); - for( ClassMapping classMapping : classes() ) - { + for (ClassMapping classMapping : classes()) { // add the class name - classNames.add( classMapping.getObfName() ); + classNames.add(classMapping.getObfName()); // add classes from method signatures - for( MethodMapping methodMapping : classMapping.methods() ) - { - SignatureUpdater.update( methodMapping.getObfSignature(), new ClassNameUpdater( ) - { + for (MethodMapping methodMapping : classMapping.methods()) { + SignatureUpdater.update(methodMapping.getObfSignature(), new ClassNameUpdater() { @Override - public String update( String className ) - { - classNames.add( className ); + public String update(String className) { + classNames.add(className); return className; } - } ); + }); } } return classNames; } - - public boolean containsDeobfClass( String deobfName ) - { - return m_classesByDeobf.containsKey( deobfName ); + + public boolean containsDeobfClass(String deobfName) { + return m_classesByDeobf.containsKey(deobfName); } - public boolean containsDeobfField( ClassEntry obfClassEntry, String deobfName ) - { - ClassMapping classMapping = m_classesByObf.get( obfClassEntry.getName() ); - if( classMapping != null ) - { - return classMapping.containsDeobfField( deobfName ); + public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName) { + ClassMapping classMapping = m_classesByObf.get(obfClassEntry.getName()); + if (classMapping != null) { + return classMapping.containsDeobfField(deobfName); } return false; } - - public boolean containsDeobfMethod( ClassEntry obfClassEntry, String deobfName, String deobfSignature ) - { - ClassMapping classMapping = m_classesByObf.get( obfClassEntry.getName() ); - if( classMapping != null ) - { - return classMapping.containsDeobfMethod( deobfName, deobfSignature ); + + public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, String deobfSignature) { + ClassMapping classMapping = m_classesByObf.get(obfClassEntry.getName()); + if (classMapping != null) { + return classMapping.containsDeobfMethod(deobfName, deobfSignature); } return false; } - - public boolean containsArgument( BehaviorEntry obfBehaviorEntry, String name ) - { - ClassMapping classMapping = m_classesByObf.get( obfBehaviorEntry.getClassName() ); - if( classMapping != null ) - { - return classMapping.containsArgument( obfBehaviorEntry, name ); + + public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) { + ClassMapping classMapping = m_classesByObf.get(obfBehaviorEntry.getClassName()); + if (classMapping != null) { + return classMapping.containsArgument(obfBehaviorEntry, name); } return false; } diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java index 4bd9f121..72e829d5 100644 --- a/src/cuchaz/enigma/mapping/MappingsReader.java +++ b/src/cuchaz/enigma/mapping/MappingsReader.java @@ -20,209 +20,157 @@ import com.google.common.collect.Queues; import cuchaz.enigma.Constants; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; -public class MappingsReader -{ - public Mappings read( Reader in ) - throws IOException, MappingParseException - { - return read( new BufferedReader( in ) ); +public class MappingsReader { + + public Mappings read(Reader in) throws IOException, MappingParseException { + return read(new BufferedReader(in)); } - public Mappings read( BufferedReader in ) - throws IOException, MappingParseException - { + public Mappings read(BufferedReader in) throws IOException, MappingParseException { Mappings mappings = new Mappings(); Deque mappingStack = Queues.newArrayDeque(); int lineNumber = 0; String line = null; - while( ( line = in.readLine() ) != null ) - { + while ( (line = in.readLine()) != null) { lineNumber++; // strip comments - int commentPos = line.indexOf( '#' ); - if( commentPos >= 0 ) - { - line = line.substring( 0, commentPos ); + int commentPos = line.indexOf('#'); + if (commentPos >= 0) { + line = line.substring(0, commentPos); } // skip blank lines - if( line.trim().length() <= 0 ) - { + if (line.trim().length() <= 0) { continue; } // get the indent of this line int indent = 0; - for( int i=0; i implementations = m_index.getRelatedMethodImplementations( obf ); + public void setMethodTreeName(MethodEntry obf, String deobfName) { + Set implementations = m_index.getRelatedMethodImplementations(obf); - deobfName = NameValidator.validateMethodName( deobfName ); - for( MethodEntry entry : implementations ) - { - String deobfSignature = m_mappings.getTranslator( TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); - MethodEntry targetEntry = new MethodEntry( entry.getClassEntry(), deobfName, deobfSignature ); - if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfBehavior( targetEntry ) ) - { - String deobfClassName = m_mappings.getTranslator( TranslationDirection.Deobfuscating ).translateClass( entry.getClassName() ); - throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName ); + deobfName = NameValidator.validateMethodName(deobfName); + for (MethodEntry entry : implementations) { + String deobfSignature = m_mappings.getTranslator(TranslationDirection.Deobfuscating).translateSignature(obf.getSignature()); + MethodEntry targetEntry = new MethodEntry(entry.getClassEntry(), deobfName, deobfSignature); + if (m_mappings.containsDeobfMethod(entry.getClassEntry(), deobfName, entry.getSignature()) || m_index.containsObfBehavior(targetEntry)) { + String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating).translateClass(entry.getClassName()); + throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); } } - for( MethodEntry entry : implementations ) - { - setMethodName( entry, deobfName ); + for (MethodEntry entry : implementations) { + setMethodName(entry, deobfName); } } - - public void setMethodName( MethodEntry obf, String deobfName ) - { - deobfName = NameValidator.validateMethodName( deobfName ); - MethodEntry targetEntry = new MethodEntry( obf.getClassEntry(), deobfName, obf.getSignature() ); - if( m_mappings.containsDeobfMethod( obf.getClassEntry(), deobfName, obf.getSignature() ) || m_index.containsObfBehavior( targetEntry ) ) - { - String deobfClassName = m_mappings.getTranslator( TranslationDirection.Deobfuscating ).translateClass( obf.getClassName() ); - throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName ); + + public void setMethodName(MethodEntry obf, String deobfName) { + deobfName = NameValidator.validateMethodName(deobfName); + MethodEntry targetEntry = new MethodEntry(obf.getClassEntry(), deobfName, obf.getSignature()); + if (m_mappings.containsDeobfMethod(obf.getClassEntry(), deobfName, obf.getSignature()) || m_index.containsObfBehavior(targetEntry)) { + String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating).translateClass(obf.getClassName()); + throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); } - ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); - classMapping.setMethodName( obf.getName(), obf.getSignature(), deobfName ); + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry()); + classMapping.setMethodName(obf.getName(), obf.getSignature(), deobfName); } - public void removeMethodTreeMapping( MethodEntry obf ) - { - for( MethodEntry implementation : m_index.getRelatedMethodImplementations( obf ) ) - { - removeMethodMapping( implementation ); + public void removeMethodTreeMapping(MethodEntry obf) { + for (MethodEntry implementation : m_index.getRelatedMethodImplementations(obf)) { + removeMethodMapping(implementation); } } - public void removeMethodMapping( MethodEntry obf ) - { - ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); - classMapping.setMethodName( obf.getName(), obf.getSignature(), null ); + public void removeMethodMapping(MethodEntry obf) { + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry()); + classMapping.setMethodName(obf.getName(), obf.getSignature(), null); } - public void markMethodTreeAsDeobfuscated( MethodEntry obf ) - { - for( MethodEntry implementation : m_index.getRelatedMethodImplementations( obf ) ) - { - markMethodAsDeobfuscated( implementation ); + public void markMethodTreeAsDeobfuscated(MethodEntry obf) { + for (MethodEntry implementation : m_index.getRelatedMethodImplementations(obf)) { + markMethodAsDeobfuscated(implementation); } } - public void markMethodAsDeobfuscated( MethodEntry obf ) - { - ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); - classMapping.setMethodName( obf.getName(), obf.getSignature(), obf.getName() ); + public void markMethodAsDeobfuscated(MethodEntry obf) { + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry()); + classMapping.setMethodName(obf.getName(), obf.getSignature(), obf.getName()); } - public void setArgumentName( ArgumentEntry obf, String deobfName ) - { - deobfName = NameValidator.validateArgumentName( deobfName ); + public void setArgumentName(ArgumentEntry obf, String deobfName) { + deobfName = NameValidator.validateArgumentName(deobfName); // NOTE: don't need to check arguments for name collisions with names determined by Procyon - if( m_mappings.containsArgument( obf.getBehaviorEntry(), deobfName ) ) - { - throw new IllegalNameException( deobfName, "There is already an argument with that name" ); + if (m_mappings.containsArgument(obf.getBehaviorEntry(), deobfName)) { + throw new IllegalNameException(deobfName, "There is already an argument with that name"); } - ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); - classMapping.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName ); + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry()); + classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName); } - public void removeArgumentMapping( ArgumentEntry obf ) - { - ClassMapping classMapping = getClassMappingOrInnerClassMapping( obf.getClassEntry() ); - classMapping.removeArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex() ); + public void removeArgumentMapping(ArgumentEntry obf) { + ClassMapping classMapping = getClassMappingOrInnerClassMapping(obf.getClassEntry()); + classMapping.removeArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex()); } - public void markArgumentAsDeobfuscated( ArgumentEntry obf ) - { - ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); - classMapping.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName() ); + public void markArgumentAsDeobfuscated(ArgumentEntry obf) { + ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry()); + classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName()); } - public boolean moveFieldToObfClass( ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass ) - { - classMapping.removeFieldMapping( fieldMapping ); - ClassMapping targetClassMapping = getOrCreateClassMapping( obfClass ); - if( !targetClassMapping.containsObfField( fieldMapping.getObfName() ) ) - { - if( !targetClassMapping.containsDeobfField( fieldMapping.getDeobfName() ) ) - { - targetClassMapping.addFieldMapping( fieldMapping ); + public boolean moveFieldToObfClass(ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass) { + classMapping.removeFieldMapping(fieldMapping); + ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass); + if (!targetClassMapping.containsObfField(fieldMapping.getObfName())) { + if (!targetClassMapping.containsDeobfField(fieldMapping.getDeobfName())) { + targetClassMapping.addFieldMapping(fieldMapping); return true; - } - else - { - System.err.println( "WARNING: deobf field was already there: " + obfClass + "." + fieldMapping.getDeobfName() ); + } else { + System.err.println("WARNING: deobf field was already there: " + obfClass + "." + fieldMapping.getDeobfName()); } } return false; } - public boolean moveMethodToObfClass( ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass ) - { - classMapping.removeMethodMapping( methodMapping ); - ClassMapping targetClassMapping = getOrCreateClassMapping( obfClass ); - if( !targetClassMapping.containsObfMethod( methodMapping.getObfName(), methodMapping.getObfSignature() ) ) - { - if( !targetClassMapping.containsDeobfMethod( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) ) - { - targetClassMapping.addMethodMapping( methodMapping ); + public boolean moveMethodToObfClass(ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass) { + classMapping.removeMethodMapping(methodMapping); + ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass); + if (!targetClassMapping.containsObfMethod(methodMapping.getObfName(), methodMapping.getObfSignature())) { + if (!targetClassMapping.containsDeobfMethod(methodMapping.getDeobfName(), methodMapping.getObfSignature())) { + targetClassMapping.addMethodMapping(methodMapping); return true; - } - else - { - System.err.println( "WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfSignature() ); + } else { + System.err.println("WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfSignature()); } } return false; } - public void write( OutputStream out ) - throws IOException - { + 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 ); + GZIPOutputStream gzipout = new GZIPOutputStream(out); + ObjectOutputStream oout = new ObjectOutputStream(gzipout); + oout.writeObject(this); gzipout.finish(); } - private ClassMapping getClassMapping( ClassEntry obfClassEntry ) - { - return m_mappings.m_classesByObf.get( obfClassEntry.getOuterClassName() ); + private ClassMapping getClassMapping(ClassEntry obfClassEntry) { + return m_mappings.m_classesByObf.get(obfClassEntry.getOuterClassName()); } - private ClassMapping getOrCreateClassMapping( ClassEntry obfClassEntry ) - { + private ClassMapping getOrCreateClassMapping(ClassEntry obfClassEntry) { String obfClassName = obfClassEntry.getOuterClassName(); - ClassMapping classMapping = m_mappings.m_classesByObf.get( obfClassName ); - if( classMapping == null ) - { - classMapping = new ClassMapping( obfClassName ); - boolean obfWasAdded = m_mappings.m_classesByObf.put( classMapping.getObfName(), classMapping ) == null; - assert( obfWasAdded ); + ClassMapping classMapping = m_mappings.m_classesByObf.get(obfClassName); + if (classMapping == null) { + classMapping = new ClassMapping(obfClassName); + boolean obfWasAdded = m_mappings.m_classesByObf.put(classMapping.getObfName(), classMapping) == null; + assert (obfWasAdded); } return classMapping; } - private ClassMapping getClassMappingOrInnerClassMapping( ClassEntry obfClassEntry ) - { - ClassMapping classMapping = getClassMapping( obfClassEntry ); - if( obfClassEntry.isInDefaultPackage() ) - { - classMapping = classMapping.getInnerClassByObf( obfClassEntry.getInnerClassName() ); + private ClassMapping getClassMappingOrInnerClassMapping(ClassEntry obfClassEntry) { + ClassMapping classMapping = getClassMapping(obfClassEntry); + if (obfClassEntry.isInDefaultPackage()) { + classMapping = classMapping.getInnerClassByObf(obfClassEntry.getInnerClassName()); } return classMapping; } - private ClassMapping getOrCreateClassMappingOrInnerClassMapping( ClassEntry obfClassEntry ) - { - ClassMapping classMapping = getOrCreateClassMapping( obfClassEntry ); - if( obfClassEntry.isInnerClass() ) - { - classMapping = classMapping.getOrCreateInnerClass( obfClassEntry.getInnerClassName() ); + private ClassMapping getOrCreateClassMappingOrInnerClassMapping(ClassEntry obfClassEntry) { + ClassMapping classMapping = getOrCreateClassMapping(obfClassEntry); + if (obfClassEntry.isInnerClass()) { + classMapping = classMapping.getOrCreateInnerClass(obfClassEntry.getInnerClassName()); } return classMapping; } diff --git a/src/cuchaz/enigma/mapping/MappingsWriter.java b/src/cuchaz/enigma/mapping/MappingsWriter.java index 3c86dfc0..5ac409fc 100644 --- a/src/cuchaz/enigma/mapping/MappingsWriter.java +++ b/src/cuchaz/enigma/mapping/MappingsWriter.java @@ -17,105 +17,71 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class MappingsWriter -{ - public void write( Writer out, Mappings mappings ) - throws IOException - { - write( new PrintWriter( out ), mappings ); +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 : sorted( mappings.classes() ) ) - { - write( out, classMapping, 0 ); + public void write(PrintWriter out, Mappings mappings) throws IOException { + for (ClassMapping classMapping : sorted(mappings.classes())) { + write(out, classMapping, 0); } } - private void write( PrintWriter out, ClassMapping classMapping, int depth ) - throws IOException - { - if( classMapping.getDeobfName() == null ) - { - out.format( "%sCLASS %s\n", getIndent( depth ), classMapping.getObfName() ); - } - else - { - out.format( "%sCLASS %s %s\n", getIndent( depth ), classMapping.getObfName(), classMapping.getDeobfName() ); + private void write(PrintWriter out, ClassMapping classMapping, int depth) throws IOException { + if (classMapping.getDeobfName() == null) { + out.format("%sCLASS %s\n", getIndent(depth), classMapping.getObfName()); + } else { + out.format("%sCLASS %s %s\n", getIndent(depth), classMapping.getObfName(), classMapping.getDeobfName()); } - for( ClassMapping innerClassMapping : sorted( classMapping.innerClasses() ) ) - { - write( out, innerClassMapping, depth + 1 ); + for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) { + write(out, innerClassMapping, depth + 1); } - for( FieldMapping fieldMapping : sorted( classMapping.fields() ) ) - { - write( out, fieldMapping, depth + 1 ); + for (FieldMapping fieldMapping : sorted(classMapping.fields())) { + write(out, fieldMapping, depth + 1); } - for( MethodMapping methodMapping : sorted( classMapping.methods() ) ) - { - write( out, methodMapping, depth + 1 ); + for (MethodMapping methodMapping : sorted(classMapping.methods())) { + write(out, methodMapping, depth + 1); } } - - private void write( PrintWriter out, FieldMapping fieldMapping, int depth ) - throws IOException - { - out.format( "%sFIELD %s %s\n", getIndent( depth ), fieldMapping.getObfName(), fieldMapping.getDeobfName() ); + + private void write(PrintWriter out, FieldMapping fieldMapping, int depth) throws IOException { + out.format("%sFIELD %s %s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getDeobfName()); } - private void write( PrintWriter out, MethodMapping methodMapping, int depth ) - throws IOException - { - if( methodMapping.getDeobfName() == null ) - { - out.format( "%sMETHOD %s %s\n", - getIndent( depth ), - methodMapping.getObfName(), methodMapping.getObfSignature() - ); - } - else - { - out.format( "%sMETHOD %s %s %s\n", - getIndent( depth ), - methodMapping.getObfName(), methodMapping.getDeobfName(), - methodMapping.getObfSignature() - ); + private void write(PrintWriter out, MethodMapping methodMapping, int depth) throws IOException { + if (methodMapping.getDeobfName() == null) { + out.format("%sMETHOD %s %s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getObfSignature()); + } else { + out.format("%sMETHOD %s %s %s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getDeobfName(), methodMapping.getObfSignature()); } - for( ArgumentMapping argumentMapping : sorted( methodMapping.arguments() ) ) - { - write( out, argumentMapping, depth + 1 ); + for (ArgumentMapping argumentMapping : sorted(methodMapping.arguments())) { + write(out, argumentMapping, depth + 1); } } - - private void write( PrintWriter out, ArgumentMapping argumentMapping, int depth ) - throws IOException - { - out.format( "%sARG %d %s\n", getIndent( depth ), argumentMapping.getIndex(), argumentMapping.getName() ); + + private void write(PrintWriter out, ArgumentMapping argumentMapping, int depth) throws IOException { + out.format("%sARG %d %s\n", getIndent(depth), argumentMapping.getIndex(), argumentMapping.getName()); } - private > List sorted( Iterable classes ) - { + private > List sorted(Iterable classes) { List out = new ArrayList(); - for( T t : classes ) - { - out.add( t ); + for (T t : classes) { + out.add(t); } - Collections.sort( out ); + Collections.sort(out); return out; } - private String getIndent( int depth ) - { + private String getIndent(int depth) { StringBuilder buf = new StringBuilder(); - for( int i=0; i -{ +public class MethodMapping implements Serializable, Comparable { + private static final long serialVersionUID = -4409570216084263978L; private String m_obfName; @@ -25,165 +25,135 @@ public class MethodMapping implements Serializable, Comparable private String m_obfSignature; private Map m_arguments; - public MethodMapping( String obfName, String obfSignature ) - { - this( obfName, obfSignature, null ); + public MethodMapping(String obfName, String obfSignature) { + this(obfName, obfSignature, null); } - public MethodMapping( String obfName, String obfSignature, String deobfName ) - { - if( obfName == null ) - { - throw new IllegalArgumentException( "obf name cannot be null!" ); + public MethodMapping(String obfName, String obfSignature, String deobfName) { + if (obfName == null) { + throw new IllegalArgumentException("obf name cannot be null!"); } - if( obfSignature == null ) - { - throw new IllegalArgumentException( "obf signature cannot be null!" ); + if (obfSignature == null) { + throw new IllegalArgumentException("obf signature cannot be null!"); } m_obfName = obfName; - m_deobfName = NameValidator.validateMethodName( deobfName ); + m_deobfName = NameValidator.validateMethodName(deobfName); m_obfSignature = obfSignature; m_arguments = new TreeMap(); } - - public String getObfName( ) - { + + public String getObfName() { return m_obfName; } - public String getDeobfName( ) - { + public String getDeobfName() { return m_deobfName; } - public void setDeobfName( String val ) - { - m_deobfName = NameValidator.validateMethodName( val ); + + public void setDeobfName(String val) { + m_deobfName = NameValidator.validateMethodName(val); } - public String getObfSignature( ) - { + public String getObfSignature() { return m_obfSignature; } - public Iterable arguments( ) - { + public Iterable arguments() { return m_arguments.values(); } - public boolean isConstructor( ) - { - return m_obfName.startsWith( "<" ); + public boolean isConstructor() { + return m_obfName.startsWith("<"); } - public void addArgumentMapping( ArgumentMapping argumentMapping ) - { - boolean wasAdded = m_arguments.put( argumentMapping.getIndex(), argumentMapping ) == null; - assert( wasAdded ); + public void addArgumentMapping(ArgumentMapping argumentMapping) { + boolean wasAdded = m_arguments.put(argumentMapping.getIndex(), argumentMapping) == null; + assert (wasAdded); } - public String getObfArgumentName( int index ) - { - ArgumentMapping argumentMapping = m_arguments.get( index ); - if( argumentMapping != null ) - { + 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 ) - { + 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 ); - boolean wasAdded = m_arguments.put( index, argumentMapping ) == null; - assert( wasAdded ); - } - else - { - argumentMapping.setName( name ); + public void setArgumentName(int index, String name) { + ArgumentMapping argumentMapping = m_arguments.get(index); + if (argumentMapping == null) { + argumentMapping = new ArgumentMapping(index, name); + boolean wasAdded = m_arguments.put(index, argumentMapping) == null; + assert (wasAdded); + } else { + argumentMapping.setName(name); } } - public void removeArgumentName( int index ) - { - boolean wasRemoved = m_arguments.remove( index ) != null; - assert( wasRemoved ); + public void removeArgumentName(int index) { + boolean wasRemoved = m_arguments.remove(index) != null; + assert (wasRemoved); } @Override - public String toString( ) - { + 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( "\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" ); + 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("\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(); } @Override - public int compareTo( MethodMapping other ) - { - return ( m_obfName + m_obfSignature ).compareTo( other.m_obfName + other.m_obfSignature ); + public int compareTo(MethodMapping other) { + return (m_obfName + m_obfSignature).compareTo(other.m_obfName + other.m_obfSignature); } - - public boolean renameObfClass( final String oldObfClassName, final String newObfClassName ) - { + + public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) { // rename obf classes in the signature - String newSignature = SignatureUpdater.update( m_obfSignature, new ClassNameUpdater( ) - { + String newSignature = SignatureUpdater.update(m_obfSignature, new ClassNameUpdater() { @Override - public String update( String className ) - { - if( className.equals( oldObfClassName ) ) - { + public String update(String className) { + if (className.equals(oldObfClassName)) { return newObfClassName; } return className; } - } ); + }); - if( newSignature != m_obfSignature ) - { + if (newSignature != m_obfSignature) { m_obfSignature = newSignature; return true; } return false; } - - public boolean containsArgument( String name ) - { - for( ArgumentMapping argumentMapping : m_arguments.values() ) - { - if( argumentMapping.getName().equals( name ) ) - { + + public boolean containsArgument(String name) { + for (ArgumentMapping argumentMapping : m_arguments.values()) { + if (argumentMapping.getName().equals(name)) { return true; } } diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java index c6ae5969..35a17f90 100644 --- a/src/cuchaz/enigma/mapping/NameValidator.java +++ b/src/cuchaz/enigma/mapping/NameValidator.java @@ -16,82 +16,65 @@ import java.util.regex.Pattern; import javassist.bytecode.Descriptor; -public class NameValidator -{ +public class NameValidator { + private static final Pattern IdentifierPattern; private static final Pattern ClassPattern; private static final List ReservedWords = Arrays.asList( - "abstract", "continue", "for", "new", "switch", - "assert", "default", "goto", "package", "synchronized", - "boolean", "do", "if", "private", "this", - "break", "double", "implements", "protected", "throw", - "byte", "else", "import", "public", "throws", - "case", "enum", "instanceof", "return", "transient", - "catch", "extends", "int", "short", "try", - "char", "final", "interface", "static", "void", - "class", "finally", "long", "strictfp", "volatile", - "const", "float", "native", "super", "while" + "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized", + "boolean", "do", "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte", + "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", "catch", + "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally", + "long", "strictfp", "volatile", "const", "float", "native", "super", "while" ); - static - { + 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 ); + 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 ); + if (Character.isJavaIdentifierPart(i)) { + partChars.appendCodePoint(i); } } String identifierRegex = "[A-Za-z_<][A-Za-z0-9_>]*"; - IdentifierPattern = Pattern.compile( identifierRegex ); - ClassPattern = Pattern.compile( String.format( "^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex ) ); + IdentifierPattern = Pattern.compile(identifierRegex); + ClassPattern = Pattern.compile(String.format("^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex)); } - public static String validateClassName( String name, boolean packageRequired ) - { - if( name == null ) - { + public static String validateClassName(String name, boolean packageRequired) { + if (name == null) { return null; } - if( !ClassPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) - { - throw new IllegalNameException( name, "This doesn't look like a legal class name" ); + if (!ClassPattern.matcher(name).matches() || ReservedWords.contains(name)) { + throw new IllegalNameException(name, "This doesn't look like a legal class name"); } - if( packageRequired && new ClassEntry( name ).getPackageName() == null ) - { - throw new IllegalNameException( name, "Class must be in a package" ); + if (packageRequired && new ClassEntry(name).getPackageName() == null) { + throw new IllegalNameException(name, "Class must be in a package"); } - return Descriptor.toJvmName( name ); + return Descriptor.toJvmName(name); } - public static String validateFieldName( String name ) - { - if( name == null ) - { + public static String validateFieldName(String name) { + if (name == null) { return null; } - if( !IdentifierPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) - { - throw new IllegalNameException( name, "This doesn't look like a legal identifier" ); + if (!IdentifierPattern.matcher(name).matches() || ReservedWords.contains(name)) { + throw new IllegalNameException(name, "This doesn't look like a legal identifier"); } return name; } - public static String validateMethodName( String name ) - { - return validateFieldName( name ); + public static String validateMethodName(String name) { + return validateFieldName(name); } - public static String validateArgumentName( String name ) - { - return validateFieldName( name ); + public static String validateArgumentName(String name) { + return validateFieldName(name); } } diff --git a/src/cuchaz/enigma/mapping/SignatureUpdater.java b/src/cuchaz/enigma/mapping/SignatureUpdater.java index 809473e5..3477cd56 100644 --- a/src/cuchaz/enigma/mapping/SignatureUpdater.java +++ b/src/cuchaz/enigma/mapping/SignatureUpdater.java @@ -16,84 +16,63 @@ import java.util.List; import com.google.common.collect.Lists; -public class SignatureUpdater -{ - public interface ClassNameUpdater - { - String update( String className ); +public class SignatureUpdater { + + public interface ClassNameUpdater { + String update(String className); } - public static String update( String signature, ClassNameUpdater updater ) - { - try - { + public static String update(String signature, ClassNameUpdater updater) { + try { StringBuilder buf = new StringBuilder(); // read the signature character-by-character - StringReader reader = new StringReader( signature ); + StringReader reader = new StringReader(signature); int i = -1; - while( ( i = reader.read() ) != -1 ) - { + while ( (i = reader.read()) != -1) { char c = (char)i; // does this character start a class name? - if( c == 'L' ) - { + if (c == 'L') { // update the class name and add it to the buffer - buf.append( 'L' ); - String className = readClass( reader ); - if( className == null ) - { - throw new IllegalArgumentException( "Malformed signature: " + signature ); + buf.append('L'); + String className = readClass(reader); + if (className == null) { + throw new IllegalArgumentException("Malformed signature: " + signature); } - buf.append( updater.update( className ) ); - buf.append( ';' ); - } - else - { + buf.append(updater.update(className)); + buf.append(';'); + } else { // copy the character into the buffer - buf.append( c ); + buf.append(c); } } return buf.toString(); - } - catch( IOException ex ) - { + } catch (IOException ex) { // I'm pretty sure a StringReader will never throw one of these - throw new Error( ex ); + throw new Error(ex); } } - private static String readClass( StringReader reader ) - throws IOException - { + private static String readClass(StringReader reader) throws IOException { // read all the characters in the buffer until we hit a ';' // remember to treat generics correctly StringBuilder buf = new StringBuilder(); int depth = 0; int i = -1; - while( ( i = reader.read() ) != -1 ) - { + while ( (i = reader.read()) != -1) { char c = (char)i; - if( c == '<' ) - { + if (c == '<') { depth++; - } - else if( c == '>' ) - { + } else if (c == '>') { depth--; - } - else if( depth == 0 ) - { - if( c == ';' ) - { + } else if (depth == 0) { + if (c == ';') { return buf.toString(); - } - else - { - buf.append( c ); + } else { + buf.append(c); } } } @@ -101,18 +80,15 @@ public class SignatureUpdater return null; } - public static List getClasses( String signature ) - { + public static List getClasses(String signature) { final List classNames = Lists.newArrayList(); - update( signature, new ClassNameUpdater( ) - { + update(signature, new ClassNameUpdater() { @Override - public String update( String className ) - { - classNames.add( className ); + public String update(String className) { + classNames.add(className); return className; } - } ); + }); return classNames; } } diff --git a/src/cuchaz/enigma/mapping/TranslationDirection.java b/src/cuchaz/enigma/mapping/TranslationDirection.java index 79ae0d32..d1b14cd5 100644 --- a/src/cuchaz/enigma/mapping/TranslationDirection.java +++ b/src/cuchaz/enigma/mapping/TranslationDirection.java @@ -10,25 +10,20 @@ ******************************************************************************/ package cuchaz.enigma.mapping; - -public enum TranslationDirection -{ - Deobfuscating - { +public enum TranslationDirection { + + Deobfuscating { @Override - public T choose( T deobfChoice, T obfChoice ) - { + public T choose(T deobfChoice, T obfChoice) { return deobfChoice; } }, - Obfuscating - { + Obfuscating { @Override - public T choose( T deobfChoice, T obfChoice ) - { + public T choose(T deobfChoice, T obfChoice) { return obfChoice; } }; - - public abstract T choose( T deobfChoice, T obfChoice ); + + public abstract T choose(T deobfChoice, T obfChoice); } diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index 6cb52402..d8d9f480 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -16,277 +16,203 @@ import com.google.common.collect.Maps; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; -public class Translator -{ +public class Translator { + private TranslationDirection m_direction; private Map m_classes; - public Translator( ) - { + public Translator() { m_direction = null; m_classes = Maps.newHashMap(); } - public Translator( TranslationDirection direction, Map classes ) - { + public Translator(TranslationDirection direction, Map classes) { m_direction = direction; m_classes = classes; } - @SuppressWarnings( "unchecked" ) - public T translateEntry( T entry ) - { - if( entry instanceof ClassEntry ) - { - return (T)translateEntry( (ClassEntry)entry ); - } - else if( entry instanceof FieldEntry ) - { - return (T)translateEntry( (FieldEntry)entry ); - } - else if( entry instanceof MethodEntry ) - { - return (T)translateEntry( (MethodEntry)entry ); - } - else if( entry instanceof ConstructorEntry ) - { - return (T)translateEntry( (ConstructorEntry)entry ); - } - else if( entry instanceof ArgumentEntry ) - { - return (T)translateEntry( (ArgumentEntry)entry ); - } - else - { - throw new Error( "Unknown entry type: " + entry.getClass().getName() ); + @SuppressWarnings("unchecked") + public T translateEntry(T entry) { + if (entry instanceof ClassEntry) { + return (T)translateEntry((ClassEntry)entry); + } else if (entry instanceof FieldEntry) { + return (T)translateEntry((FieldEntry)entry); + } else if (entry instanceof MethodEntry) { + return (T)translateEntry((MethodEntry)entry); + } else if (entry instanceof ConstructorEntry) { + return (T)translateEntry((ConstructorEntry)entry); + } else if (entry instanceof ArgumentEntry) { + return (T)translateEntry((ArgumentEntry)entry); + } else { + throw new Error("Unknown entry type: " + entry.getClass().getName()); } } - public String translateClass( String className ) - { - return translate( new ClassEntry( className ) ); + public String translateClass(String className) { + return translate(new ClassEntry(className)); } - public String translate( ClassEntry in ) - { - ClassMapping classMapping = m_classes.get( in.getOuterClassName() ); - if( classMapping != null ) - { - if( in.isInnerClass() ) - { + public String translate(ClassEntry in) { + ClassMapping classMapping = m_classes.get(in.getOuterClassName()); + if (classMapping != null) { + if (in.isInnerClass()) { // translate the inner class String translatedInnerClassName = m_direction.choose( - classMapping.getDeobfInnerClassName( in.getInnerClassName() ), - classMapping.getObfInnerClassName( in.getInnerClassName() ) + classMapping.getDeobfInnerClassName(in.getInnerClassName()), + classMapping.getObfInnerClassName(in.getInnerClassName()) ); - if( translatedInnerClassName != null ) - { + if (translatedInnerClassName != null) { // try to translate the outer name - String translatedOuterClassName = m_direction.choose( - classMapping.getDeobfName(), - classMapping.getObfName() - ); - if( translatedOuterClassName != null ) - { + String translatedOuterClassName = m_direction.choose(classMapping.getDeobfName(), classMapping.getObfName()); + if (translatedOuterClassName != null) { return translatedOuterClassName + "$" + translatedInnerClassName; - } - else - { + } else { return in.getOuterClassName() + "$" + translatedInnerClassName; } } - } - else - { + } else { // just return outer - return m_direction.choose( - classMapping.getDeobfName(), - classMapping.getObfName() - ); + return m_direction.choose(classMapping.getDeobfName(), classMapping.getObfName()); } } return null; } - public ClassEntry translateEntry( ClassEntry in ) - { + public ClassEntry translateEntry(ClassEntry in) { + // can we translate the inner class? - String name = translate( in ); - if( name != null ) - { - return new ClassEntry( name ); + String name = translate(in); + if (name != null) { + return new ClassEntry(name); } - if( in.isInnerClass() ) - { + if (in.isInnerClass()) { + // guess not. just translate the outer class name then - String outerClassName = translate( in.getOuterClassEntry() ); - if( outerClassName != null ) - { - return new ClassEntry( outerClassName + "$" + in.getInnerClassName() ); + String outerClassName = translate(in.getOuterClassEntry()); + if (outerClassName != null) { + return new ClassEntry(outerClassName + "$" + in.getInnerClassName()); } } return in; } - public String translate( FieldEntry in ) - { + public String translate(FieldEntry in) { + // look for the class - ClassMapping classMapping = findClassMapping( in.getClassEntry() ); - if( classMapping != null ) - { + ClassMapping classMapping = findClassMapping(in.getClassEntry()); + if (classMapping != null) { + // look for the field String translatedName = m_direction.choose( - classMapping.getDeobfFieldName( in.getName() ), - classMapping.getObfFieldName( in.getName() ) + classMapping.getDeobfFieldName(in.getName()), + classMapping.getObfFieldName(in.getName()) ); - if( translatedName != null ) - { + if (translatedName != null) { return translatedName; } } return null; } - public FieldEntry translateEntry( FieldEntry in ) - { - String name = translate( in ); - if( name == null ) - { + public FieldEntry translateEntry(FieldEntry in) { + String name = translate(in); + if (name == null) { name = in.getName(); } - return new FieldEntry( - translateEntry( in.getClassEntry() ), - name - ); + return new FieldEntry(translateEntry(in.getClassEntry()), name); } - public String translate( MethodEntry in ) - { + public String translate(MethodEntry in) { + // look for class - ClassMapping classMapping = findClassMapping( in.getClassEntry() ); - if( classMapping != null ) - { + ClassMapping classMapping = findClassMapping(in.getClassEntry()); + if (classMapping != null) { + // look for the method - MethodMapping methodMapping = m_direction.choose( - classMapping.getMethodByObf( in.getName(), in.getSignature() ), - classMapping.getMethodByDeobf( in.getName(), translateSignature( in.getSignature() ) ) - ); - if( methodMapping != null ) - { - return m_direction.choose( - methodMapping.getDeobfName(), - methodMapping.getObfName() - ); + MethodMapping methodMapping = m_direction.choose(classMapping.getMethodByObf(in.getName(), in.getSignature()), + classMapping.getMethodByDeobf(in.getName(), translateSignature(in.getSignature()))); + if (methodMapping != null) { + return m_direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName()); } } return null; } - public MethodEntry translateEntry( MethodEntry in ) - { - String name = translate( in ); - if( name == null ) - { + public MethodEntry translateEntry(MethodEntry in) { + String name = translate(in); + if (name == null) { name = in.getName(); } - return new MethodEntry( - translateEntry( in.getClassEntry() ), - name, - translateSignature( in.getSignature() ) - ); + return new MethodEntry(translateEntry(in.getClassEntry()), name, translateSignature(in.getSignature())); } - public ConstructorEntry translateEntry( ConstructorEntry in ) - { - if( in.isStatic() ) - { - return new ConstructorEntry( translateEntry( in.getClassEntry() ) ); - } - else - { - return new ConstructorEntry( - translateEntry( in.getClassEntry() ), - translateSignature( in.getSignature() ) - ); + public ConstructorEntry translateEntry(ConstructorEntry in) { + if (in.isStatic()) { + return new ConstructorEntry(translateEntry(in.getClassEntry())); + } else { + return new ConstructorEntry(translateEntry(in.getClassEntry()), translateSignature(in.getSignature())); } } - public BehaviorEntry translateEntry( BehaviorEntry in ) - { - if( in instanceof MethodEntry ) - { - return translateEntry( (MethodEntry)in ); + public BehaviorEntry translateEntry(BehaviorEntry in) { + if (in instanceof MethodEntry) { + return translateEntry((MethodEntry)in); + } else if (in instanceof ConstructorEntry) { + return translateEntry((ConstructorEntry)in); } - else if( in instanceof ConstructorEntry ) - { - return translateEntry( (ConstructorEntry)in ); - } - throw new Error( "Wrong entry type!" ); + throw new Error("Wrong entry type!"); } - public String translate( ArgumentEntry in ) - { + public String translate(ArgumentEntry in) { + // look for the class - ClassMapping classMapping = findClassMapping( in.getClassEntry() ); - if( classMapping != null ) - { + ClassMapping classMapping = findClassMapping(in.getClassEntry()); + if (classMapping != null) { + // look for the method MethodMapping methodMapping = m_direction.choose( - classMapping.getMethodByObf( in.getMethodName(), in.getMethodSignature() ), - classMapping.getMethodByDeobf( in.getMethodName(), translateSignature( in.getMethodSignature() ) ) + classMapping.getMethodByObf(in.getMethodName(), in.getMethodSignature()), + classMapping.getMethodByDeobf(in.getMethodName(), translateSignature(in.getMethodSignature())) ); - if( methodMapping != null ) - { + if (methodMapping != null) { return m_direction.choose( - methodMapping.getDeobfArgumentName( in.getIndex() ), - methodMapping.getObfArgumentName( in.getIndex() ) + methodMapping.getDeobfArgumentName(in.getIndex()), + methodMapping.getObfArgumentName(in.getIndex()) ); } } return null; } - public ArgumentEntry translateEntry( ArgumentEntry in ) - { - String name = translate( in ); - if( name == null ) - { + public ArgumentEntry translateEntry(ArgumentEntry in) { + String name = translate(in); + if (name == null) { name = in.getName(); } - return new ArgumentEntry( - translateEntry( in.getBehaviorEntry() ), - in.getIndex(), - name - ); + return new ArgumentEntry(translateEntry(in.getBehaviorEntry()), in.getIndex(), name); } - public String translateSignature( String signature ) - { - return SignatureUpdater.update( signature, new ClassNameUpdater( ) - { + public String translateSignature(String signature) { + return SignatureUpdater.update(signature, new ClassNameUpdater() { @Override - public String update( String className ) - { - String translatedName = translateClass( className ); - if( translatedName != null ) - { + public String update(String className) { + String translatedName = translateClass(className); + if (translatedName != null) { return translatedName; } return className; } - } ); + }); } - private ClassMapping findClassMapping( ClassEntry classEntry ) - { - ClassMapping classMapping = m_classes.get( classEntry.getOuterClassName() ); - if( classMapping != null && classEntry.isInnerClass() ) - { + private ClassMapping findClassMapping(ClassEntry classEntry) { + ClassMapping classMapping = m_classes.get(classEntry.getOuterClassName()); + if (classMapping != null && classEntry.isInnerClass()) { classMapping = m_direction.choose( - classMapping.getInnerClassByObf( classEntry.getInnerClassName() ), - classMapping.getInnerClassByDeobfThenObf( classEntry.getInnerClassName() ) + classMapping.getInnerClassByObf(classEntry.getInnerClassName()), + classMapping.getInnerClassByDeobfThenObf(classEntry.getInnerClassName()) ); } return classMapping; -- cgit v1.2.3 From 56c036d7d18e2e18682bf14d71e8dbecf266072a Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 13 Jan 2015 23:40:23 -0500 Subject: started on command line interface for build system --- src/cuchaz/enigma/CommandMain.java | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'src') diff --git a/src/cuchaz/enigma/CommandMain.java b/src/cuchaz/enigma/CommandMain.java index 7f881749..6a01661b 100644 --- a/src/cuchaz/enigma/CommandMain.java +++ b/src/cuchaz/enigma/CommandMain.java @@ -3,5 +3,41 @@ package cuchaz.enigma; public class CommandMain { public static void main(String[] args) { + + // parse the args + if (args.length < 1) { + printHelp(); + return; + } + + // process the command + String command = args[0]; + if (command.equalsIgnoreCase("deobfuscate")) { + deobfuscate(args); + } else if(command.equalsIgnoreCase("decompile")) { + decompile(args); + } else { + System.out.println("Command not recognized: " + args[0]); + printHelp(); + } + } + + private static void printHelp() { + System.out.println(String.format("%s - %s", Constants.Name, Constants.Version)); + System.out.println("Usage:"); + System.out.println("\tjava -jar enigma.jar cuchaz.enigma.CommandMain "); + System.out.println("\twhere is one of:"); + System.out.println("\t\tdeobfuscate "); + System.out.println("\t\tdecompile "); + } + + private static void decompile(String[] args) { + // TODO + throw new Error("Not implemented yet"); + } + + private static void deobfuscate(String[] args) { + // TODO + throw new Error("Not implemented yet"); } } -- cgit v1.2.3 From ba67f6c0231157c0b07b37fe0a09fca381bb37d9 Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 17 Jan 2015 16:20:15 -0500 Subject: added command-line interface for scriptable awesome --- src/cuchaz/enigma/CommandMain.java | 134 +++++++++++++++++++++++++++++++------ 1 file changed, 113 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/CommandMain.java b/src/cuchaz/enigma/CommandMain.java index 6a01661b..74bd4991 100644 --- a/src/cuchaz/enigma/CommandMain.java +++ b/src/cuchaz/enigma/CommandMain.java @@ -1,23 +1,65 @@ package cuchaz.enigma; +import java.io.File; +import java.io.FileReader; + +import cuchaz.enigma.Deobfuscator.ProgressListener; +import cuchaz.enigma.mapping.Mappings; +import cuchaz.enigma.mapping.MappingsReader; + public class CommandMain { - public static void main(String[] args) { + public static class ConsoleProgressListener implements ProgressListener { - // parse the args - if (args.length < 1) { - printHelp(); - return; + private static final int ReportTime = 5000; // 5s + + private int m_totalWork; + private long m_startTime; + private long m_lastReportTime; + + @Override + public void init(int totalWork, String title) { + m_totalWork = totalWork; + m_startTime = System.currentTimeMillis(); + m_lastReportTime = m_startTime; + System.out.println(title); + } + + @Override + public void onProgress(int numDone, String message) { + + long now = System.currentTimeMillis(); + boolean isLastUpdate = numDone == m_totalWork; + boolean shouldReport = isLastUpdate || now - m_lastReportTime > ReportTime; + + if (shouldReport) { + int percent = numDone*100/m_totalWork; + System.out.println(String.format("\tProgress: %3d%%", percent)); + m_lastReportTime = now; + } + if (isLastUpdate) { + double elapsedSeconds = (now - m_startTime)/1000; + System.out.println(String.format("Finished in %.1f seconds", elapsedSeconds)); + } } + } + + public static void main(String[] args) + throws Exception { - // process the command - String command = args[0]; - if (command.equalsIgnoreCase("deobfuscate")) { - deobfuscate(args); - } else if(command.equalsIgnoreCase("decompile")) { - decompile(args); - } else { - System.out.println("Command not recognized: " + args[0]); + try { + + // process the command + String command = getArg(args, 0, "command"); + if (command.equalsIgnoreCase("deobfuscate")) { + deobfuscate(args); + } else if(command.equalsIgnoreCase("decompile")) { + decompile(args); + } else { + throw new IllegalArgumentException("Command not recognized: " + command); + } + } catch (IllegalArgumentException ex) { + System.out.println(ex.getMessage()); printHelp(); } } @@ -25,19 +67,69 @@ public class CommandMain { private static void printHelp() { System.out.println(String.format("%s - %s", Constants.Name, Constants.Version)); System.out.println("Usage:"); - System.out.println("\tjava -jar enigma.jar cuchaz.enigma.CommandMain "); + System.out.println("\tjava -cp enigma.jar cuchaz.enigma.CommandMain "); System.out.println("\twhere is one of:"); System.out.println("\t\tdeobfuscate "); - System.out.println("\t\tdecompile "); + System.out.println("\t\tdecompile "); } - private static void decompile(String[] args) { - // TODO - throw new Error("Not implemented yet"); + private static void decompile(String[] args) + throws Exception { + File fileMappings = getReadableFile(getArg(args, 1, "mappings file")); + File fileJarIn = getReadableFile(getArg(args, 2, "in jar")); + File fileJarOut = getWritableFolder(getArg(args, 3, "out folder")); + Deobfuscator deobfuscator = getDeobfuscator(fileMappings, fileJarIn); + deobfuscator.writeSources(fileJarOut, new ConsoleProgressListener()); } - private static void deobfuscate(String[] args) { - // TODO - throw new Error("Not implemented yet"); + private static void deobfuscate(String[] args) + throws Exception { + File fileMappings = getReadableFile(getArg(args, 1, "mappings file")); + File fileJarIn = getReadableFile(getArg(args, 2, "in jar")); + File fileJarOut = getWritableFile(getArg(args, 3, "out jar")); + Deobfuscator deobfuscator = getDeobfuscator(fileMappings, fileJarIn); + deobfuscator.writeJar(fileJarOut, new ConsoleProgressListener()); + } + + private static Deobfuscator getDeobfuscator(File fileMappings, File fileJar) + throws Exception { + System.out.println("Reading mappings..."); + Mappings mappings = new MappingsReader().read(new FileReader(fileMappings)); + System.out.println("Reading jar..."); + Deobfuscator deobfuscator = new Deobfuscator(fileJar); + deobfuscator.setMappings(mappings); + return deobfuscator; + } + + private static String getArg(String[] args, int i, String name) { + if (i >= args.length) { + throw new IllegalArgumentException(name + " is required"); + } + return args[i]; + } + + private static File getWritableFile(String path) { + File file = new File(path).getAbsoluteFile(); + File dir = file.getParentFile(); + if (dir == null || !dir.exists()) { + throw new IllegalArgumentException("Cannot write to folder: " + file); + } + return file; + } + + private static File getWritableFolder(String path) { + File dir = new File(path).getAbsoluteFile(); + if (!dir.exists()) { + throw new IllegalArgumentException("Cannot write to folder: " + dir); + } + return dir; + } + + private static File getReadableFile(String path) { + File file = new File(path).getAbsoluteFile(); + if (!file.exists()) { + throw new IllegalArgumentException("Cannot find file: " + file.getAbsolutePath()); + } + return file; } } -- cgit v1.2.3 From 5390e6a1a2e2750b6e065cab4d4fbcdab477e9a3 Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 17 Jan 2015 20:11:44 -0500 Subject: move BytecodeTools to m3l --- .../enigma/bytecode/BytecodeIndexIterator.java | 151 ----------- src/cuchaz/enigma/bytecode/BytecodeTools.java | 287 --------------------- 2 files changed, 438 deletions(-) delete mode 100644 src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java delete mode 100644 src/cuchaz/enigma/bytecode/BytecodeTools.java (limited to 'src') diff --git a/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java deleted file mode 100644 index fc2bac3d..00000000 --- a/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java +++ /dev/null @@ -1,151 +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.bytecode; - -import java.util.Iterator; - -import javassist.bytecode.BadBytecode; -import javassist.bytecode.Bytecode; -import javassist.bytecode.CodeAttribute; -import javassist.bytecode.CodeIterator; -import javassist.bytecode.Opcode; - -public class BytecodeIndexIterator implements Iterator { - - public static class Index { - - private CodeIterator m_iter; - private int m_pos; - private boolean m_isWide; - - protected Index(CodeIterator iter, int pos, boolean isWide) { - m_iter = iter; - m_pos = pos; - m_isWide = isWide; - } - - public int getIndex() { - if (m_isWide) { - return m_iter.s16bitAt(m_pos); - } else { - return m_iter.byteAt(m_pos); - } - } - - public void setIndex(int val) throws BadBytecode { - if (m_isWide) { - m_iter.write16bit(val, m_pos); - } else { - if (val < 256) { - // we can write the byte - m_iter.writeByte(val, m_pos); - } else { - // we need to upgrade this instruction to LDC_W - assert (m_iter.byteAt(m_pos - 1) == Opcode.LDC); - m_iter.insertGap(m_pos - 1, 1); - m_iter.writeByte(Opcode.LDC_W, m_pos - 1); - m_iter.write16bit(val, m_pos); - m_isWide = true; - - // move the iterator to the next opcode - m_iter.move(m_pos + 2); - } - } - - // sanity check - assert (val == getIndex()); - } - - public boolean isValid(Bytecode bytecode) { - return getIndex() >= 0 && getIndex() < bytecode.getConstPool().getSize(); - } - } - - private Bytecode m_bytecode; - private CodeAttribute m_attribute; - private CodeIterator m_iter; - private Index m_next; - - public BytecodeIndexIterator(Bytecode bytecode) throws BadBytecode { - m_bytecode = bytecode; - m_attribute = bytecode.toCodeAttribute(); - m_iter = m_attribute.iterator(); - - m_next = getNext(); - } - - @Override - public boolean hasNext() { - return m_next != null; - } - - @Override - public Index next() { - Index out = m_next; - try { - m_next = getNext(); - } catch (BadBytecode ex) { - throw new Error(ex); - } - return out; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - private Index getNext() throws BadBytecode { - while (m_iter.hasNext()) { - int pos = m_iter.next(); - int opcode = m_iter.byteAt(pos); - switch (opcode) { - - // for only these opcodes, the next two bytes are a const pool reference - case Opcode.ANEWARRAY: - case Opcode.CHECKCAST: - case Opcode.INSTANCEOF: - case Opcode.INVOKEDYNAMIC: - case Opcode.INVOKEINTERFACE: - case Opcode.INVOKESPECIAL: - case Opcode.INVOKESTATIC: - case Opcode.INVOKEVIRTUAL: - case Opcode.LDC_W: - case Opcode.LDC2_W: - case Opcode.MULTIANEWARRAY: - case Opcode.NEW: - case Opcode.PUTFIELD: - case Opcode.PUTSTATIC: - case Opcode.GETFIELD: - case Opcode.GETSTATIC: - return new Index(m_iter, pos + 1, true); - - case Opcode.LDC: - return new Index(m_iter, pos + 1, false); - } - } - - return null; - } - - public Iterable indices() { - return new Iterable() { - @Override - public Iterator iterator() { - return BytecodeIndexIterator.this; - } - }; - } - - public void saveChangesToBytecode() { - BytecodeTools.setBytecode(m_bytecode, m_attribute.getCode()); - } -} diff --git a/src/cuchaz/enigma/bytecode/BytecodeTools.java b/src/cuchaz/enigma/bytecode/BytecodeTools.java deleted file mode 100644 index 2e456f45..00000000 --- a/src/cuchaz/enigma/bytecode/BytecodeTools.java +++ /dev/null @@ -1,287 +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.bytecode; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javassist.CtBehavior; -import javassist.bytecode.BadBytecode; -import javassist.bytecode.Bytecode; -import javassist.bytecode.CodeAttribute; -import javassist.bytecode.ConstPool; -import javassist.bytecode.ExceptionTable; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -import cuchaz.enigma.Util; -import cuchaz.enigma.bytecode.BytecodeIndexIterator.Index; -import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; - -public class BytecodeTools { - - public static byte[] writeBytecode(Bytecode bytecode) throws IOException { - - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(buf); - - try { - // write the constant pool - new ConstPoolEditor(bytecode.getConstPool()).writePool(out); - - // write metadata - out.writeShort(bytecode.getMaxStack()); - out.writeShort(bytecode.getMaxLocals()); - out.writeShort(bytecode.getStackDepth()); - - // write the code - out.writeShort(bytecode.getSize()); - out.write(bytecode.get()); - - // write the exception table - int numEntries = bytecode.getExceptionTable().size(); - out.writeShort(numEntries); - for (int i = 0; i < numEntries; i++) { - out.writeShort(bytecode.getExceptionTable().startPc(i)); - out.writeShort(bytecode.getExceptionTable().endPc(i)); - out.writeShort(bytecode.getExceptionTable().handlerPc(i)); - out.writeShort(bytecode.getExceptionTable().catchType(i)); - } - - out.close(); - return buf.toByteArray(); - } catch (Exception ex) { - Util.closeQuietly(out); - throw new Error(ex); - } - } - - public static Bytecode readBytecode(byte[] bytes) throws IOException { - - ByteArrayInputStream buf = new ByteArrayInputStream(bytes); - DataInputStream in = new DataInputStream(buf); - - try { - // read the constant pool entries and update the class - ConstPool pool = ConstPoolEditor.readPool(in); - - // read metadata - int maxStack = in.readShort(); - int maxLocals = in.readShort(); - int stackDepth = in.readShort(); - - Bytecode bytecode = new Bytecode(pool, maxStack, maxLocals); - bytecode.setStackDepth(stackDepth); - - // read the code - int size = in.readShort(); - byte[] code = new byte[size]; - in.read(code); - setBytecode(bytecode, code); - - // read the exception table - int numEntries = in.readShort(); - for (int i = 0; i < numEntries; i++) { - bytecode.getExceptionTable().add(in.readShort(), in.readShort(), in.readShort(), in.readShort()); - } - - in.close(); - return bytecode; - } catch (Exception ex) { - Util.closeQuietly(in); - throw new Error(ex); - } - } - - public static Bytecode prepareMethodForBytecode(CtBehavior behavior, Bytecode bytecode) throws BadBytecode { - - // update the destination class const pool - bytecode = copyBytecodeToConstPool(behavior.getMethodInfo().getConstPool(), bytecode); - - // update method locals and stack - CodeAttribute attribute = behavior.getMethodInfo().getCodeAttribute(); - if (bytecode.getMaxLocals() > attribute.getMaxLocals()) { - attribute.setMaxLocals(bytecode.getMaxLocals()); - } - if (bytecode.getMaxStack() > attribute.getMaxStack()) { - attribute.setMaxStack(bytecode.getMaxStack()); - } - - return bytecode; - } - - public static Bytecode copyBytecodeToConstPool(ConstPool dest, Bytecode bytecode) throws BadBytecode { - - // get the entries this bytecode needs from the const pool - Set indices = Sets.newTreeSet(); - ConstPoolEditor editor = new ConstPoolEditor(bytecode.getConstPool()); - BytecodeIndexIterator iterator = new BytecodeIndexIterator(bytecode); - for (Index index : iterator.indices()) { - assert (index.isValid(bytecode)); - InfoType.gatherIndexTree(indices, editor, index.getIndex()); - } - - Map indexMap = Maps.newTreeMap(); - - ConstPool src = bytecode.getConstPool(); - ConstPoolEditor editorSrc = new ConstPoolEditor(src); - ConstPoolEditor editorDest = new ConstPoolEditor(dest); - - // copy entries over in order of level so the index mapping is easier - for (InfoType type : InfoType.getSortedByLevel()) { - for (int index : indices) { - ConstInfoAccessor entry = editorSrc.getItem(index); - - // skip entries that aren't this type - if (entry.getType() != type) { - continue; - } - - // make sure the source entry is valid before we copy it - assert (type.subIndicesAreValid(entry, editorSrc)); - assert (type.selfIndexIsValid(entry, editorSrc)); - - // make a copy of the entry so we can modify it safely - ConstInfoAccessor entryCopy = editorSrc.getItem(index).copy(); - assert (type.subIndicesAreValid(entryCopy, editorSrc)); - assert (type.selfIndexIsValid(entryCopy, editorSrc)); - - // remap the indices - type.remapIndices(indexMap, entryCopy); - assert (type.subIndicesAreValid(entryCopy, editorDest)); - - // put the copy in the destination pool - int newIndex = editorDest.addItem(entryCopy.getItem()); - entryCopy.setIndex(newIndex); - assert (type.selfIndexIsValid(entryCopy, editorDest)) : type + ", self: " + entryCopy + " dest: " + editorDest.getItem(entryCopy.getIndex()); - - // make sure the source entry is unchanged - assert (type.subIndicesAreValid(entry, editorSrc)); - assert (type.selfIndexIsValid(entry, editorSrc)); - - // add the index mapping so we can update the bytecode later - if (indexMap.containsKey(index)) { - throw new Error("Entry at index " + index + " already copied!"); - } - indexMap.put(index, newIndex); - } - } - - // make a new bytecode - Bytecode newBytecode = new Bytecode(dest, bytecode.getMaxStack(), bytecode.getMaxLocals()); - bytecode.setStackDepth(bytecode.getStackDepth()); - setBytecode(newBytecode, bytecode.get()); - setExceptionTable(newBytecode, bytecode.getExceptionTable()); - - // apply the mappings to the bytecode - BytecodeIndexIterator iter = new BytecodeIndexIterator(newBytecode); - for (Index index : iter.indices()) { - int oldIndex = index.getIndex(); - Integer newIndex = indexMap.get(oldIndex); - if (newIndex != null) { - // make sure this mapping makes sense - InfoType typeSrc = editorSrc.getItem(oldIndex).getType(); - InfoType typeDest = editorDest.getItem(newIndex).getType(); - assert (typeSrc == typeDest); - - // apply the mapping - index.setIndex(newIndex); - } - } - iter.saveChangesToBytecode(); - - // make sure all the indices are valid - iter = new BytecodeIndexIterator(newBytecode); - for (Index index : iter.indices()) { - assert (index.isValid(newBytecode)); - } - - return newBytecode; - } - - public static void setBytecode(Bytecode dest, byte[] src) { - if (src.length > dest.getSize()) { - dest.addGap(src.length - dest.getSize()); - } - assert (dest.getSize() == src.length); - for (int i = 0; i < src.length; i++) { - dest.write(i, src[i]); - } - } - - public static void setExceptionTable(Bytecode dest, ExceptionTable src) { - - // clear the dest exception table - int size = dest.getExceptionTable().size(); - for (int i = size - 1; i >= 0; i--) { - dest.getExceptionTable().remove(i); - } - - // copy the exception table - for (int i = 0; i < src.size(); i++) { - dest.getExceptionTable().add(src.startPc(i), src.endPc(i), src.handlerPc(i), src.catchType(i)); - } - } - - public static List getParameterTypes(String signature) { - List types = Lists.newArrayList(); - for (int i = 0; i < signature.length();) { - char c = signature.charAt(i); - - // handle parens - if (c == '(') { - i++; - c = signature.charAt(i); - } - if (c == ')') { - break; - } - - // find a type - String type = null; - - int arrayDim = 0; - while (c == '[') { - // advance to array type - arrayDim++; - i++; - c = signature.charAt(i); - } - - if (c == 'L') { - // read class type - int pos = signature.indexOf(';', i + 1); - String className = signature.substring(i + 1, pos); - type = "L" + className + ";"; - i = pos + 1; - } else { - // read primitive type - type = signature.substring(i, i + 1); - i++; - } - - // was it an array? - while (arrayDim-- > 0) { - type = "[" + type; - } - types.add(type); - } - return types; - } -} -- cgit v1.2.3 From 91460a865cc5d4f8d1e0c38fd08c1f071af147bb Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 18 Jan 2015 17:17:27 -0500 Subject: also translate source file attributes so it's easy to browse decompiled sources --- src/cuchaz/enigma/bytecode/ClassTranslator.java | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index bc12405c..735a8fa3 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java @@ -18,6 +18,7 @@ import javassist.CtField; import javassist.CtMethod; import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; +import javassist.bytecode.SourceFileAttribute; import com.google.common.collect.Maps; @@ -125,5 +126,12 @@ public class ClassTranslator { } } ClassRenamer.renameClasses(c, map); + + // translate the source file attribute too + ClassEntry deobfClassEntry = map.get(classEntry); + if (deobfClassEntry != null) { + String sourceFile = Descriptor.toJvmName(deobfClassEntry.getOuterClassName()) + ".java"; + c.getClassFile().addAttribute(new SourceFileAttribute(constants, sourceFile)); + } } } -- cgit v1.2.3 From ec86ae2cc015baeba1d86db52311905051765c33 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 18 Jan 2015 18:06:25 -0500 Subject: add the system classpath to the javassist class pool --- src/cuchaz/enigma/analysis/JarClassIterator.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/JarClassIterator.java b/src/cuchaz/enigma/analysis/JarClassIterator.java index 8d9947c1..72a99122 100644 --- a/src/cuchaz/enigma/analysis/JarClassIterator.java +++ b/src/cuchaz/enigma/analysis/JarClassIterator.java @@ -126,6 +126,7 @@ public class JarClassIterator implements Iterator { // get a javassist handle for the class String className = Descriptor.toJavaName(getClassEntry(entry).getName()); ClassPool classPool = new ClassPool(); + classPool.appendSystemPath(); classPool.insertClassPath(new ByteArrayClassPath(className, bos.toByteArray())); return classPool.get(className); } -- cgit v1.2.3 From 5f88fcdc4fa9e8147ad7072da09c2bb49e007946 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 18 Jan 2015 22:57:15 -0500 Subject: added inverse operation for moving classes out of the default package --- src/cuchaz/enigma/bytecode/ClassRenamer.java | 34 ++++++---------------------- 1 file changed, 7 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java index f8e63d16..a5fea926 100644 --- a/src/cuchaz/enigma/bytecode/ClassRenamer.java +++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java @@ -14,7 +14,6 @@ import java.util.Map; import java.util.Set; import javassist.ClassMap; -import javassist.CtBehavior; import javassist.CtClass; import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; @@ -24,8 +23,6 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.SignatureUpdater; -import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class ClassRenamer { @@ -92,8 +89,6 @@ public class ClassRenamer { } public static void moveAllClassesOutOfDefaultPackage(CtClass c, String newPackageName) { - - // rename all classes Map map = Maps.newHashMap(); for (ClassEntry classEntry : ClassRenamer.getAllClassEntries(c)) { if (classEntry.isInDefaultPackage()) { @@ -101,30 +96,15 @@ public class ClassRenamer { } } ClassRenamer.renameClasses(c, map); - - // TEMP + } + + public static void moveAllClassesIntoDefaultPackage(CtClass c, String oldPackageName) { + Map map = Maps.newHashMap(); for (ClassEntry classEntry : ClassRenamer.getAllClassEntries(c)) { - if (classEntry.isInDefaultPackage()) { - throw new Error("!!! " + classEntry); + if (classEntry.getPackageName().equals(oldPackageName)) { + map.put(classEntry, new ClassEntry(classEntry.getSimpleName())); } } - - // TEMP - for (CtBehavior behavior : c.getDeclaredBehaviors()) { - if (behavior.getSignature() == null) { - continue; - } - - SignatureUpdater.update(behavior.getSignature(), new ClassNameUpdater() { - @Override - public String update(String className) { - ClassEntry classEntry = new ClassEntry(className); - if (classEntry.isInDefaultPackage()) { - throw new Error("!!! " + className); - } - return className; - } - }); - } + ClassRenamer.renameClasses(c, map); } } -- cgit v1.2.3 From 2fbcf8e5c4eec0aa4a4fc59c7cc8abac33b1429c Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 19 Jan 2015 22:22:57 -0500 Subject: solved tricky issue with incorrect translation of fields/methods referenced by a subclass instead of the declaring class --- src/cuchaz/enigma/Deobfuscator.java | 8 +- src/cuchaz/enigma/Main.java | 2 +- .../enigma/analysis/ClassInheritanceTreeNode.java | 4 +- src/cuchaz/enigma/analysis/JarIndex.java | 65 +++----- .../enigma/analysis/MethodInheritanceTreeNode.java | 4 +- src/cuchaz/enigma/analysis/TranslationIndex.java | 172 ++++++++++++++++----- src/cuchaz/enigma/bytecode/ClassTranslator.java | 9 ++ src/cuchaz/enigma/mapping/JavassistUtil.java | 55 +++++++ src/cuchaz/enigma/mapping/Mappings.java | 11 +- src/cuchaz/enigma/mapping/MappingsRenamer.java | 6 +- src/cuchaz/enigma/mapping/Translator.java | 57 ++++--- 11 files changed, 271 insertions(+), 122 deletions(-) create mode 100644 src/cuchaz/enigma/mapping/JavassistUtil.java (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 679518a4..23057223 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -144,7 +144,7 @@ public class Deobfuscator { // fields for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) { FieldEntry fieldEntry = new FieldEntry(obfClassEntry, fieldMapping.getObfName()); - ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(fieldEntry); + ClassEntry resolvedObfClassEntry = m_jarIndex.getTranslationIndex().resolveEntryClass(fieldEntry); if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(fieldEntry.getClassEntry())) { boolean wasMoved = renamer.moveFieldToObfClass(classMapping, fieldMapping, resolvedObfClassEntry); if (wasMoved) { @@ -167,7 +167,7 @@ public class Deobfuscator { methodMapping.getObfName(), methodMapping.getObfSignature() ); - ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(methodEntry); + ClassEntry resolvedObfClassEntry = m_jarIndex.getTranslationIndex().resolveEntryClass(methodEntry); if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(methodEntry.getClassEntry())) { boolean wasMoved = renamer.moveMethodToObfClass(classMapping, methodMapping, resolvedObfClassEntry); if (wasMoved) { @@ -233,7 +233,7 @@ public class Deobfuscator { public Translator getTranslator(TranslationDirection direction) { Translator translator = m_translatorCache.get(direction); if (translator == null) { - translator = m_mappings.getTranslator(direction); + translator = m_mappings.getTranslator(direction, m_jarIndex.getTranslationIndex()); m_translatorCache.put(direction, translator); } return translator; @@ -311,7 +311,7 @@ public class Deobfuscator { Entry obfEntry = obfuscateEntry(deobfReference.entry); // try to resolve the class - ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(obfEntry); + ClassEntry resolvedObfClassEntry = m_jarIndex.getTranslationIndex().resolveEntryClass(obfEntry); if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getClassEntry())) { // change the class of the entry obfEntry = obfEntry.cloneToNewClass(resolvedObfClassEntry); diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index f8d3afe2..1891ded8 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -28,7 +28,7 @@ public class Main { } // DEBUG - // gui.getController().openDeclaration( new ClassEntry( "none/ces" ) ); + //gui.getController().openDeclaration(new ClassEntry("none/bxq")); } private static File getFile(String path) { diff --git a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java index b132305c..3eaa3912 100644 --- a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java @@ -51,8 +51,8 @@ public class ClassInheritanceTreeNode extends DefaultMutableTreeNode { public void load(TranslationIndex ancestries, boolean recurse) { // get all the child nodes List nodes = Lists.newArrayList(); - for (String subclassName : ancestries.getSubclassNames(m_obfClassName)) { - nodes.add(new ClassInheritanceTreeNode(m_deobfuscatingTranslator, subclassName)); + for (ClassEntry subclassEntry : ancestries.getSubclass(new ClassEntry(m_obfClassName))) { + nodes.add(new ClassInheritanceTreeNode(m_deobfuscatingTranslator, subclassEntry.getName())); } // add them to this node diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 4b03a332..c96d3bc4 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -114,8 +114,8 @@ public class JarIndex { // step 3: index extends, implements, fields, and methods for (CtClass c : JarClassIterator.classes(jar)) { ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); + m_translationIndex.indexClass(c); String className = Descriptor.toJvmName(c.getName()); - m_translationIndex.addSuperclass(className, Descriptor.toJvmName(c.getClassFile().getSuperclass())); for (String interfaceName : c.getClassFile().getInterfaces()) { className = Descriptor.toJvmName(className); interfaceName = Descriptor.toJvmName(interfaceName); @@ -191,8 +191,6 @@ public class JarIndex { String className = Descriptor.toJvmName(field.getDeclaringClass().getName()); FieldEntry fieldEntry = new FieldEntry(new ClassEntry(className), field.getName()); - m_translationIndex.addField(className, field.getName()); - // is the field a class type? if (field.getSignature().startsWith("L")) { ClassEntry fieldTypeEntry = new ClassEntry(field.getSignature().substring(1, field.getSignature().length() - 1)); @@ -230,13 +228,12 @@ public class JarIndex { behavior.instrument(new ExprEditor() { @Override public void edit(MethodCall call) { - String className = Descriptor.toJvmName(call.getClassName()); MethodEntry calledMethodEntry = new MethodEntry( - new ClassEntry(className), + new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getMethodName(), call.getSignature() ); - ClassEntry resolvedClassEntry = resolveEntryClass(calledMethodEntry); + ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledMethodEntry); if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) { calledMethodEntry = new MethodEntry( resolvedClassEntry, @@ -254,12 +251,11 @@ public class JarIndex { @Override public void edit(FieldAccess call) { - String className = Descriptor.toJvmName(call.getClassName()); FieldEntry calledFieldEntry = new FieldEntry( - new ClassEntry(className), + new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getFieldName() ); - ClassEntry resolvedClassEntry = resolveEntryClass(calledFieldEntry); + ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledFieldEntry); if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) { calledFieldEntry = new FieldEntry(resolvedClassEntry, call.getFieldName()); } @@ -273,9 +269,8 @@ public class JarIndex { @Override public void edit(ConstructorCall call) { - String className = Descriptor.toJvmName(call.getClassName()); ConstructorEntry calledConstructorEntry = new ConstructorEntry( - new ClassEntry(className), + new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getSignature() ); EntryReference reference = new EntryReference( @@ -288,9 +283,8 @@ public class JarIndex { @Override public void edit(NewExpr call) { - String className = Descriptor.toJvmName(call.getClassName()); ConstructorEntry calledConstructorEntry = new ConstructorEntry( - new ClassEntry(className), + new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getSignature() ); EntryReference reference = new EntryReference( @@ -306,25 +300,6 @@ public class JarIndex { } } - public ClassEntry resolveEntryClass(Entry obfEntry) { - - // this entry could refer to a method on a class where the method is not actually implemented - // travel up the inheritance tree to find the closest implementation - while (!containsObfEntry(obfEntry)) { - // is there a parent class? - String superclassName = m_translationIndex.getSuperclassName(obfEntry.getClassName()); - if (superclassName == null) { - // this is probably a method from a class in a library - // we can't trace the implementation up any higher unless we index the library - return null; - } - - // move up to the parent class - obfEntry = obfEntry.cloneToNewClass(new ClassEntry(superclassName)); - } - return obfEntry.getClassEntry(); - } - private CtMethod getBridgedMethod(CtMethod method) { // bridge methods just call another method, cast it to the return type, and return the result @@ -402,9 +377,9 @@ public class JarIndex { if (reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry) { // is the entry a superclass of the context? - String calledClassName = reference.entry.getClassName(); - String callerSuperclassName = m_translationIndex.getSuperclassName(reference.context.getClassName()); - if (callerSuperclassName != null && callerSuperclassName.equals(calledClassName)) { + ClassEntry calledClassEntry = reference.entry.getClassEntry(); + ClassEntry superclassEntry = m_translationIndex.getSuperclass(reference.context.getClassEntry()); + if (superclassEntry != null && superclassEntry.equals(calledClassEntry)) { // it's a super call, skip continue; } @@ -599,7 +574,9 @@ public class JarIndex { // get the root node List ancestry = Lists.newArrayList(); ancestry.add(obfClassEntry.getName()); - ancestry.addAll(m_translationIndex.getAncestry(obfClassEntry.getName())); + for (ClassEntry classEntry : m_translationIndex.getAncestry(obfClassEntry)) { + ancestry.add(classEntry.getName()); + } ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get(ancestry.size() - 1) @@ -625,21 +602,21 @@ public class JarIndex { public MethodInheritanceTreeNode getMethodInheritance(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { // travel to the ancestor implementation - String baseImplementationClassName = obfMethodEntry.getClassName(); - for (String ancestorClassName : m_translationIndex.getAncestry(obfMethodEntry.getClassName())) { + ClassEntry baseImplementationClassEntry = obfMethodEntry.getClassEntry(); + for (ClassEntry ancestorClassEntry : m_translationIndex.getAncestry(obfMethodEntry.getClassEntry())) { MethodEntry ancestorMethodEntry = new MethodEntry( - new ClassEntry(ancestorClassName), + new ClassEntry(ancestorClassEntry), obfMethodEntry.getName(), obfMethodEntry.getSignature() ); if (containsObfBehavior(ancestorMethodEntry)) { - baseImplementationClassName = ancestorClassName; + baseImplementationClassEntry = ancestorClassEntry; } } // make a root node at the base MethodEntry methodEntry = new MethodEntry( - new ClassEntry(baseImplementationClassName), + baseImplementationClassEntry, obfMethodEntry.getName(), obfMethodEntry.getSignature() ); @@ -781,8 +758,8 @@ public class JarIndex { public Set getInterfaces(String className) { Set interfaceNames = new HashSet(); interfaceNames.addAll(m_interfaces.get(className)); - for (String ancestor : m_translationIndex.getAncestry(className)) { - interfaceNames.addAll(m_interfaces.get(ancestor)); + for (ClassEntry ancestor : m_translationIndex.getAncestry(new ClassEntry(className))) { + interfaceNames.addAll(m_interfaces.get(ancestor.getName())); } return interfaceNames; } @@ -795,7 +772,7 @@ public class JarIndex { String interfaceName = entry.getValue(); if (interfaceName.equals(targetInterfaceName)) { classNames.add(className); - m_translationIndex.getSubclassNamesRecursively(classNames, className); + m_translationIndex.getSubclassNamesRecursively(classNames, new ClassEntry(className)); } } return classNames; diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index eba8d874..87182204 100644 --- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java @@ -71,9 +71,9 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { public void load(JarIndex index, boolean recurse) { // get all the child nodes List nodes = Lists.newArrayList(); - for (String subclassName : index.getTranslationIndex().getSubclassNames(m_entry.getClassName())) { + for (ClassEntry subclassEntry : index.getTranslationIndex().getSubclass(m_entry.getClassEntry())) { MethodEntry methodEntry = new MethodEntry( - new ClassEntry(subclassName), + subclassEntry, m_entry.getName(), m_entry.getSignature() ); diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java index c14fd593..4a356eb6 100644 --- a/src/cuchaz/enigma/analysis/TranslationIndex.java +++ b/src/cuchaz/enigma/analysis/TranslationIndex.java @@ -11,97 +11,185 @@ package cuchaz.enigma.analysis; import java.io.Serializable; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; -import javassist.bytecode.Descriptor; +import javassist.CtBehavior; +import javassist.CtClass; +import javassist.CtField; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.JavassistUtil; +import cuchaz.enigma.mapping.Translator; + public class TranslationIndex implements Serializable { private static final long serialVersionUID = 738687982126844179L; - private Map m_superclasses; - private Multimap m_fields; + private Map m_superclasses; + private Multimap m_fieldEntries; + private Multimap m_behaviorEntries; public TranslationIndex() { m_superclasses = Maps.newHashMap(); - m_fields = HashMultimap.create(); - } - - public TranslationIndex(TranslationIndex other) { - m_superclasses = Maps.newHashMap(other.m_superclasses); - m_fields = HashMultimap.create(other.m_fields); + m_fieldEntries = HashMultimap.create(); + m_behaviorEntries = HashMultimap.create(); } - public void addSuperclass(String className, String superclassName) { - className = Descriptor.toJvmName(className); - superclassName = Descriptor.toJvmName(superclassName); + public TranslationIndex(TranslationIndex other, Translator translator) { - if (className.equals(superclassName)) { - throw new IllegalArgumentException("Class cannot be its own superclass! " + className); + // translate the superclasses + m_superclasses = Maps.newHashMap(); + for (Map.Entry mapEntry : other.m_superclasses.entrySet()) { + m_superclasses.put( + translator.translateEntry(mapEntry.getKey()), + translator.translateEntry(mapEntry.getValue()) + ); } - if (!isJre(className) && !isJre(superclassName)) { - m_superclasses.put(className, superclassName); + // translate the fields + m_fieldEntries = HashMultimap.create(); + for (Map.Entry mapEntry : other.m_fieldEntries.entries()) { + m_fieldEntries.put( + translator.translateEntry(mapEntry.getKey()), + translator.translateEntry(mapEntry.getValue()) + ); + } + + m_behaviorEntries = HashMultimap.create(); + for (Map.Entry mapEntry : other.m_behaviorEntries.entries()) { + m_behaviorEntries.put( + translator.translateEntry(mapEntry.getKey()), + translator.translateEntry(mapEntry.getValue()) + ); } } - public void addField(String className, String fieldName) { - m_fields.put(className, fieldName); + public void indexClass(CtClass c) { + + ClassEntry classEntry = JavassistUtil.getClassEntry(c); + + // add the superclass + ClassEntry superclassEntry = JavassistUtil.getSuperclassEntry(c); + if (!isJre(classEntry) && !isJre(superclassEntry)) { + m_superclasses.put(classEntry, superclassEntry); + } + + // add fields + for (CtField field : c.getDeclaredFields()) { + FieldEntry fieldEntry = JavassistUtil.getFieldEntry(field); + m_fieldEntries.put(fieldEntry.getClassEntry(), fieldEntry); + } + + // add behaviors + for (CtBehavior behavior : c.getDeclaredBehaviors()) { + BehaviorEntry behaviorEntry = JavassistUtil.getBehaviorEntry(behavior); + m_behaviorEntries.put(behaviorEntry.getClassEntry(), behaviorEntry); + } } public void renameClasses(Map renames) { EntryRenamer.renameClassesInMap(renames, m_superclasses); - EntryRenamer.renameClassesInMultimap(renames, m_fields); + EntryRenamer.renameClassesInMultimap(renames, m_fieldEntries); + EntryRenamer.renameClassesInMultimap(renames, m_behaviorEntries); } - public String getSuperclassName(String className) { - return m_superclasses.get(className); + public ClassEntry getSuperclass(ClassEntry classEntry) { + return m_superclasses.get(classEntry); } - public List getAncestry(String className) { - List ancestors = new ArrayList(); - while (className != null) { - className = getSuperclassName(className); - if (className != null) { - ancestors.add(className); + public List getAncestry(ClassEntry classEntry) { + List ancestors = Lists.newArrayList(); + while (classEntry != null) { + classEntry = getSuperclass(classEntry); + if (classEntry != null) { + ancestors.add(classEntry); } } return ancestors; } - public List getSubclassNames(String className) { + public List getSubclass(ClassEntry classEntry) { // linear search is fast enough for now - List subclasses = Lists.newArrayList(); - for (Map.Entry entry : m_superclasses.entrySet()) { - String subclass = entry.getKey(); - String superclass = entry.getValue(); - if (className.equals(superclass)) { + List subclasses = Lists.newArrayList(); + for (Map.Entry entry : m_superclasses.entrySet()) { + ClassEntry subclass = entry.getKey(); + ClassEntry superclass = entry.getValue(); + if (classEntry.equals(superclass)) { subclasses.add(subclass); } } return subclasses; } - public void getSubclassNamesRecursively(Set out, String className) { - for (String subclassName : getSubclassNames(className)) { - out.add(subclassName); - getSubclassNamesRecursively(out, subclassName); + public void getSubclassesRecursively(Set out, ClassEntry classEntry) { + for (ClassEntry subclassEntry : getSubclass(classEntry)) { + out.add(subclassEntry); + getSubclassesRecursively(out, subclassEntry); + } + } + + public void getSubclassNamesRecursively(Set out, ClassEntry classEntry) { + for (ClassEntry subclassEntry : getSubclass(classEntry)) { + out.add(subclassEntry.getName()); + getSubclassNamesRecursively(out, subclassEntry); } } - public boolean containsField(String className, String fieldName) { - return m_fields.containsEntry(className, fieldName); + public boolean entryExists(Entry entry) { + if (entry instanceof FieldEntry) { + return fieldExists((FieldEntry)entry); + } else if (entry instanceof BehaviorEntry) { + return behaviorExists((BehaviorEntry)entry); + } else if (entry instanceof ArgumentEntry) { + return behaviorExists(((ArgumentEntry)entry).getBehaviorEntry()); + } + throw new IllegalArgumentException("Cannot check existence for " + entry.getClass()); + } + + public boolean fieldExists(FieldEntry fieldEntry) { + return m_fieldEntries.containsEntry(fieldEntry.getClassEntry(), fieldEntry); + } + + public boolean behaviorExists(BehaviorEntry behaviorEntry) { + return m_behaviorEntries.containsEntry(behaviorEntry.getClassEntry(), behaviorEntry); + } + + public ClassEntry resolveEntryClass(Entry entry) { + + if (entry instanceof ClassEntry) { + return (ClassEntry)entry; + } + + // this entry could refer to a method on a class where the method is not actually implemented + // travel up the inheritance tree to find the closest implementation + while (!entryExists(entry)) { + + // is there a parent class? + ClassEntry superclassEntry = getSuperclass(entry.getClassEntry()); + if (superclassEntry == null) { + // this is probably a method from a class in a library + // we can't trace the implementation up any higher unless we index the library + return null; + } + + // move up to the parent class + entry = entry.cloneToNewClass(superclassEntry); + } + return entry.getClassEntry(); } - private boolean isJre(String className) { - return className.startsWith("java/") || className.startsWith("javax/"); + private boolean isJre(ClassEntry classEntry) { + return classEntry.getPackageName().startsWith("java") || classEntry.getPackageName().startsWith("javax"); } } diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index 735a8fa3..64418307 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java @@ -38,6 +38,7 @@ public class ClassTranslator { } public void translate(CtClass c) { + // NOTE: the order of these translations is very important // translate all the field and method references in the code by editing the constant pool @@ -45,7 +46,9 @@ public class ClassTranslator { ConstPoolEditor editor = new ConstPoolEditor(constants); for (int i = 1; i < constants.getSize(); i++) { switch (constants.getTag(i)) { + case ConstPool.CONST_Fieldref: { + // translate the name FieldEntry entry = new FieldEntry( new ClassEntry(Descriptor.toJvmName(constants.getFieldrefClassName(i))), @@ -53,6 +56,11 @@ public class ClassTranslator { ); FieldEntry translatedEntry = m_translator.translateEntry(entry); + // TEMP + if (entry.toString().equals("none/bxq.m")) { + System.out.println("FIELD: " + entry + " -> " + translatedEntry); + } + // translate the type String type = constants.getFieldrefType(i); String translatedType = m_translator.translateSignature(type); @@ -65,6 +73,7 @@ public class ClassTranslator { case ConstPool.CONST_Methodref: case ConstPool.CONST_InterfaceMethodref: { + // translate the name and type BehaviorEntry entry = BehaviorEntryFactory.create( Descriptor.toJvmName(editor.getMemberrefClassname(i)), diff --git a/src/cuchaz/enigma/mapping/JavassistUtil.java b/src/cuchaz/enigma/mapping/JavassistUtil.java new file mode 100644 index 00000000..b011e0be --- /dev/null +++ b/src/cuchaz/enigma/mapping/JavassistUtil.java @@ -0,0 +1,55 @@ +package cuchaz.enigma.mapping; + +import javassist.CtBehavior; +import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtField; +import javassist.CtMethod; +import javassist.bytecode.Descriptor; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; + +public class JavassistUtil { + + public static ClassEntry getClassEntry(CtClass c) { + return new ClassEntry(Descriptor.toJvmName(c.getName())); + } + + public static ClassEntry getSuperclassEntry(CtClass c) { + return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass())); + } + + public static MethodEntry getMethodEntry(CtMethod method) { + return new MethodEntry( + getClassEntry(method.getDeclaringClass()), + method.getName(), + method.getMethodInfo().getDescriptor() + ); + } + + public static ConstructorEntry getConstructorEntry(CtConstructor constructor) { + return new ConstructorEntry( + getClassEntry(constructor.getDeclaringClass()), + constructor.getMethodInfo().getDescriptor() + ); + } + + public static BehaviorEntry getBehaviorEntry(CtBehavior behavior) { + if (behavior instanceof CtMethod) { + return getMethodEntry((CtMethod)behavior); + } else if (behavior instanceof CtConstructor) { + return getConstructorEntry((CtConstructor)behavior); + } + throw new Error("behavior is neither Method nor Constructor!"); + } + + public static FieldEntry getFieldEntry(CtField field) { + return new FieldEntry( + getClassEntry(field.getDeclaringClass()), + field.getName() + ); + } +} diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index c5e38f4b..cc560a87 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -24,6 +24,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import cuchaz.enigma.Util; +import cuchaz.enigma.analysis.TranslationIndex; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class Mappings implements Serializable { @@ -104,11 +105,11 @@ public class Mappings implements Serializable { return m_classesByDeobf.get(deobfName); } - public Translator getTranslator(TranslationDirection direction) { + public Translator getTranslator(TranslationDirection direction, TranslationIndex index) { switch (direction) { case Deobfuscating: - return new Translator(direction, m_classesByObf); + return new Translator(direction, m_classesByObf, index); case Obfuscating: @@ -122,7 +123,11 @@ public class Mappings implements Serializable { } } - return new Translator(direction, classes); + // translate the translation index + // NOTE: this isn't actually recursive + TranslationIndex deobfIndex = new TranslationIndex(index, getTranslator(TranslationDirection.Deobfuscating, index)); + + return new Translator(direction, classes, deobfIndex); default: throw new Error("Invalid translation direction!"); diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index cb95f42b..3aac65a1 100644 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java @@ -100,10 +100,10 @@ public class MappingsRenamer { deobfName = NameValidator.validateMethodName(deobfName); for (MethodEntry entry : implementations) { - String deobfSignature = m_mappings.getTranslator(TranslationDirection.Deobfuscating).translateSignature(obf.getSignature()); + String deobfSignature = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateSignature(obf.getSignature()); MethodEntry targetEntry = new MethodEntry(entry.getClassEntry(), deobfName, deobfSignature); if (m_mappings.containsDeobfMethod(entry.getClassEntry(), deobfName, entry.getSignature()) || m_index.containsObfBehavior(targetEntry)) { - String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating).translateClass(entry.getClassName()); + String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(entry.getClassName()); throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); } } @@ -117,7 +117,7 @@ public class MappingsRenamer { deobfName = NameValidator.validateMethodName(deobfName); MethodEntry targetEntry = new MethodEntry(obf.getClassEntry(), deobfName, obf.getSignature()); if (m_mappings.containsDeobfMethod(obf.getClassEntry(), deobfName, obf.getSignature()) || m_index.containsObfBehavior(targetEntry)) { - String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating).translateClass(obf.getClassName()); + String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(obf.getClassName()); throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); } diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index d8d9f480..a5a3e2f0 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -14,21 +14,24 @@ import java.util.Map; import com.google.common.collect.Maps; +import cuchaz.enigma.analysis.TranslationIndex; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; public class Translator { private TranslationDirection m_direction; private Map m_classes; + private TranslationIndex m_index; public Translator() { m_direction = null; m_classes = Maps.newHashMap(); } - public Translator(TranslationDirection direction, Map classes) { + public Translator(TranslationDirection direction, Map classes, TranslationIndex index) { m_direction = direction; m_classes = classes; + m_index = index; } @SuppressWarnings("unchecked") @@ -100,17 +103,22 @@ public class Translator { public String translate(FieldEntry in) { - // look for the class - ClassMapping classMapping = findClassMapping(in.getClassEntry()); - if (classMapping != null) { - - // look for the field - String translatedName = m_direction.choose( - classMapping.getDeobfFieldName(in.getName()), - classMapping.getObfFieldName(in.getName()) - ); - if (translatedName != null) { - return translatedName; + // resolve the class entry + ClassEntry resolvedClassEntry = m_index.resolveEntryClass(in); + if (resolvedClassEntry != null) { + + // look for the class + ClassMapping classMapping = findClassMapping(resolvedClassEntry); + if (classMapping != null) { + + // look for the field + String translatedName = m_direction.choose( + classMapping.getDeobfFieldName(in.getName()), + classMapping.getObfFieldName(in.getName()) + ); + if (translatedName != null) { + return translatedName; + } } } return null; @@ -126,15 +134,22 @@ public class Translator { public String translate(MethodEntry in) { - // look for class - ClassMapping classMapping = findClassMapping(in.getClassEntry()); - if (classMapping != null) { - - // look for the method - MethodMapping methodMapping = m_direction.choose(classMapping.getMethodByObf(in.getName(), in.getSignature()), - classMapping.getMethodByDeobf(in.getName(), translateSignature(in.getSignature()))); - if (methodMapping != null) { - return m_direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName()); + // resolve the class entry + ClassEntry resolvedClassEntry = m_index.resolveEntryClass(in); + if (resolvedClassEntry != null) { + + // look for class + ClassMapping classMapping = findClassMapping(resolvedClassEntry); + if (classMapping != null) { + + // look for the method + MethodMapping methodMapping = m_direction.choose( + classMapping.getMethodByObf(in.getName(), in.getSignature()), + classMapping.getMethodByDeobf(in.getName(), translateSignature(in.getSignature())) + ); + if (methodMapping != null) { + return m_direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName()); + } } } return null; -- cgit v1.2.3 From c5b7e0ffd03259660221020250bb80cc4006c01e Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 19 Jan 2015 23:14:30 -0500 Subject: fixed M3L-related issues with translation index --- src/cuchaz/enigma/analysis/TranslationIndex.java | 36 ++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java index 4a356eb6..7597c3ae 100644 --- a/src/cuchaz/enigma/analysis/TranslationIndex.java +++ b/src/cuchaz/enigma/analysis/TranslationIndex.java @@ -10,10 +10,18 @@ ******************************************************************************/ package cuchaz.enigma.analysis; +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.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; import javassist.CtBehavior; import javassist.CtClass; @@ -81,7 +89,7 @@ public class TranslationIndex implements Serializable { // add the superclass ClassEntry superclassEntry = JavassistUtil.getSuperclassEntry(c); - if (!isJre(classEntry) && !isJre(superclassEntry)) { + if (!isJre(classEntry) && superclassEntry != null && !isJre(superclassEntry)) { m_superclasses.put(classEntry, superclassEntry); } @@ -190,6 +198,30 @@ public class TranslationIndex implements Serializable { } private boolean isJre(ClassEntry classEntry) { - return classEntry.getPackageName().startsWith("java") || classEntry.getPackageName().startsWith("javax"); + String packageName = classEntry.getPackageName(); + return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax")); + } + + public void write(OutputStream out) + throws IOException { + GZIPOutputStream gzipout = new GZIPOutputStream(out); + ObjectOutputStream oout = new ObjectOutputStream(gzipout); + oout.writeObject(m_superclasses); + oout.writeObject(m_fieldEntries); + oout.writeObject(m_behaviorEntries); + gzipout.finish(); + } + + @SuppressWarnings("unchecked") + public void read(InputStream in) + throws IOException { + try { + ObjectInputStream oin = new ObjectInputStream(new GZIPInputStream(in)); + m_superclasses = (HashMap)oin.readObject(); + m_fieldEntries = (HashMultimap)oin.readObject(); + m_behaviorEntries = (HashMultimap)oin.readObject(); + } catch (ClassNotFoundException ex) { + throw new Error(ex); + } } } -- cgit v1.2.3 From c349556a15c1bbd1d714616e604491a02a8ecf79 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 19 Jan 2015 23:16:55 -0500 Subject: remove debug code, silly... --- src/cuchaz/enigma/bytecode/ClassTranslator.java | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index 64418307..fb2fb27f 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java @@ -56,11 +56,6 @@ public class ClassTranslator { ); FieldEntry translatedEntry = m_translator.translateEntry(entry); - // TEMP - if (entry.toString().equals("none/bxq.m")) { - System.out.println("FIELD: " + entry + " -> " + translatedEntry); - } - // translate the type String type = constants.getFieldrefType(i); String translatedType = m_translator.translateSignature(type); -- cgit v1.2.3 From e66c456a9595d33c1db0d26e78347d4e0018b77e Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 24 Jan 2015 20:20:39 -0500 Subject: avoid concurrent modification exception --- src/cuchaz/enigma/Deobfuscator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 23057223..22c517a1 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -138,7 +138,7 @@ public class Deobfuscator { // pass 2: look for fields/methods that are actually declared in superclasses MappingsRenamer renamer = new MappingsRenamer(m_jarIndex, val); - for (ClassMapping classMapping : val.classes()) { + for (ClassMapping classMapping : Lists.newArrayList(val.classes())) { ClassEntry obfClassEntry = new ClassEntry(classMapping.getObfName()); // fields -- cgit v1.2.3 From 448685653e90415ebe10b08e8335462b81c30421 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 2 Feb 2015 21:26:10 -0500 Subject: fix issue with bridge methods --- src/cuchaz/enigma/CommandMain.java | 9 ++-- src/cuchaz/enigma/Deobfuscator.java | 8 ++-- src/cuchaz/enigma/TranslatingTypeLoader.java | 4 +- src/cuchaz/enigma/analysis/BridgeFixer.java | 72 ---------------------------- src/cuchaz/enigma/gui/Gui.java | 3 +- src/cuchaz/enigma/gui/GuiController.java | 5 +- 6 files changed, 14 insertions(+), 87 deletions(-) delete mode 100644 src/cuchaz/enigma/analysis/BridgeFixer.java (limited to 'src') diff --git a/src/cuchaz/enigma/CommandMain.java b/src/cuchaz/enigma/CommandMain.java index 74bd4991..1ec2ad23 100644 --- a/src/cuchaz/enigma/CommandMain.java +++ b/src/cuchaz/enigma/CommandMain.java @@ -2,6 +2,7 @@ package cuchaz.enigma; import java.io.File; import java.io.FileReader; +import java.util.jar.JarFile; import cuchaz.enigma.Deobfuscator.ProgressListener; import cuchaz.enigma.mapping.Mappings; @@ -78,7 +79,7 @@ public class CommandMain { File fileMappings = getReadableFile(getArg(args, 1, "mappings file")); File fileJarIn = getReadableFile(getArg(args, 2, "in jar")); File fileJarOut = getWritableFolder(getArg(args, 3, "out folder")); - Deobfuscator deobfuscator = getDeobfuscator(fileMappings, fileJarIn); + Deobfuscator deobfuscator = getDeobfuscator(fileMappings, new JarFile(fileJarIn)); deobfuscator.writeSources(fileJarOut, new ConsoleProgressListener()); } @@ -87,16 +88,16 @@ public class CommandMain { File fileMappings = getReadableFile(getArg(args, 1, "mappings file")); File fileJarIn = getReadableFile(getArg(args, 2, "in jar")); File fileJarOut = getWritableFile(getArg(args, 3, "out jar")); - Deobfuscator deobfuscator = getDeobfuscator(fileMappings, fileJarIn); + Deobfuscator deobfuscator = getDeobfuscator(fileMappings, new JarFile(fileJarIn)); deobfuscator.writeJar(fileJarOut, new ConsoleProgressListener()); } - private static Deobfuscator getDeobfuscator(File fileMappings, File fileJar) + private static Deobfuscator getDeobfuscator(File fileMappings, JarFile jar) throws Exception { System.out.println("Reading mappings..."); Mappings mappings = new MappingsReader().read(new FileReader(fileMappings)); System.out.println("Reading jar..."); - Deobfuscator deobfuscator = new Deobfuscator(fileJar); + Deobfuscator deobfuscator = new Deobfuscator(jar); deobfuscator.setMappings(mappings); return deobfuscator; } diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 22c517a1..62c062a5 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -68,7 +68,6 @@ public class Deobfuscator { void onProgress(int numDone, String message); } - private File m_file; private JarFile m_jar; private DecompilerSettings m_settings; private JarIndex m_jarIndex; @@ -76,9 +75,8 @@ public class Deobfuscator { private MappingsRenamer m_renamer; private Map m_translatorCache; - public Deobfuscator(File file) throws IOException { - m_file = file; - m_jar = new JarFile(m_file); + public Deobfuscator(JarFile jar) throws IOException { + m_jar = jar; // build the jar index m_jarIndex = new JarIndex(); @@ -100,7 +98,7 @@ public class Deobfuscator { } public String getJarName() { - return m_file.getName(); + return m_jar.getName(); } public JarIndex getJarIndex() { diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 091f916d..9287999b 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -29,7 +29,6 @@ import com.strobel.assembler.metadata.Buffer; import com.strobel.assembler.metadata.ClasspathTypeLoader; import com.strobel.assembler.metadata.ITypeLoader; -import cuchaz.enigma.analysis.BridgeFixer; import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.bytecode.ClassRenamer; import cuchaz.enigma.bytecode.ClassTranslator; @@ -168,7 +167,7 @@ public class TranslatingTypeLoader implements ITypeLoader { assertClassName(c, deobfClassEntry); // DEBUG - // Util.writeClass( c ); + Util.writeClass( c ); // we have a transformed class! return c.toBytecode(); @@ -196,7 +195,6 @@ public class TranslatingTypeLoader implements ITypeLoader { assertClassName(c, obfClassEntry); // do all kinds of deobfuscating transformations on the class - new BridgeFixer(m_jarIndex).fixBridges(c); new MethodParameterWriter(m_deobfuscatingTranslator).writeMethodArguments(c); new ClassTranslator(m_deobfuscatingTranslator).translate(c); diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java deleted file mode 100644 index ad23b000..00000000 --- a/src/cuchaz/enigma/analysis/BridgeFixer.java +++ /dev/null @@ -1,72 +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.analysis; - -import javassist.CtClass; -import javassist.CtMethod; -import javassist.bytecode.ConstPool; -import javassist.bytecode.Descriptor; -import cuchaz.enigma.bytecode.ConstPoolEditor; -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.BehaviorEntryFactory; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.MethodEntry; - -public class BridgeFixer { - - private JarIndex m_index; - - public BridgeFixer(JarIndex index) { - m_index = index; - } - - public void fixBridges(CtClass c) { - // rename declared methods - for (CtMethod method : c.getDeclaredMethods()) { - // get the method entry - MethodEntry methodEntry = new MethodEntry( - new ClassEntry(Descriptor.toJvmName(c.getName())), - method.getName(), - method.getSignature() - ); - MethodEntry bridgeMethodEntry = m_index.getBridgeMethod(methodEntry); - if (bridgeMethodEntry != null) { - // fix this bridged method - method.setName(bridgeMethodEntry.getName()); - } - } - - // rename method references - // translate all the field and method references in the code by editing the constant pool - ConstPool constants = c.getClassFile().getConstPool(); - ConstPoolEditor editor = new ConstPoolEditor(constants); - for (int i = 1; i < constants.getSize(); i++) { - switch (constants.getTag(i)) { - case ConstPool.CONST_Methodref: - case ConstPool.CONST_InterfaceMethodref: { - BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(Descriptor.toJvmName(editor.getMemberrefClassname(i)), editor.getMemberrefName(i), editor.getMemberrefType(i)); - - if (behaviorEntry instanceof MethodEntry) { - MethodEntry methodEntry = (MethodEntry)behaviorEntry; - - // translate the name and type - MethodEntry bridgeMethodEntry = m_index.getBridgeMethod(methodEntry); - if (bridgeMethodEntry != null) { - // FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT - editor.changeMemberrefNameAndType(i, bridgeMethodEntry.getName(), bridgeMethodEntry.getSignature()); - } - } - } - break; - } - } - } -} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 86ba93b2..e652202c 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -33,6 +33,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Vector; +import java.util.jar.JarFile; import javax.swing.BorderFactory; import javax.swing.JEditorPane; @@ -499,7 +500,7 @@ public class Gui { @Override public void run() { try { - m_controller.openJar(m_jarFileChooser.getSelectedFile()); + m_controller.openJar(new JarFile(m_jarFileChooser.getSelectedFile())); } catch (IOException ex) { throw new Error(ex); } diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 908c16fa..61fea9c0 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.util.Collection; import java.util.Deque; import java.util.List; +import java.util.jar.JarFile; import com.google.common.collect.Lists; import com.google.common.collect.Queues; @@ -66,9 +67,9 @@ public class GuiController { return m_isDirty; } - public void openJar(final File file) throws IOException { + public void openJar(final JarFile jar) throws IOException { m_gui.onStartOpenJar(); - m_deobfuscator = new Deobfuscator(file); + m_deobfuscator = new Deobfuscator(jar); m_gui.onFinishOpenJar(m_deobfuscator.getJarName()); refreshClasses(); } -- cgit v1.2.3 From fccf9aa1e78cb9413316850731f194e9d3f7de71 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 2 Feb 2015 22:37:00 -0500 Subject: herp a derp --- src/cuchaz/enigma/Deobfuscator.java | 2 +- src/cuchaz/enigma/Main.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 62c062a5..5f61686b 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -88,7 +88,7 @@ public class Deobfuscator { m_settings.setForceExplicitImports(true); m_settings.setForceExplicitTypeArguments(true); // DEBUG - // m_settings.setShowSyntheticMembers( true ); + //m_settings.setShowSyntheticMembers(true); // init defaults m_translatorCache = Maps.newTreeMap(); diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index 1891ded8..acae94b1 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -11,6 +11,7 @@ package cuchaz.enigma; import java.io.File; +import java.util.jar.JarFile; import cuchaz.enigma.gui.Gui; @@ -21,7 +22,7 @@ public class Main { // parse command-line args if (args.length >= 1) { - gui.getController().openJar(getFile(args[0])); + gui.getController().openJar(new JarFile(getFile(args[0]))); } if (args.length >= 2) { gui.getController().openMappings(getFile(args[1])); -- cgit v1.2.3 From 6d05a33a8eddd389c27ae70e3485f6a8cf3807ea Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 4 Feb 2015 21:16:40 -0500 Subject: turn off debug stuff --- src/cuchaz/enigma/TranslatingTypeLoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java index 9287999b..cfa03a1a 100644 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/cuchaz/enigma/TranslatingTypeLoader.java @@ -167,7 +167,7 @@ public class TranslatingTypeLoader implements ITypeLoader { assertClassName(c, deobfClassEntry); // DEBUG - Util.writeClass( c ); + //Util.writeClass( c ); // we have a transformed class! return c.toBytecode(); -- cgit v1.2.3 From 73313b0f1c1660986afc1449960889cac242eee0 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 5 Feb 2015 23:51:40 -0500 Subject: add new type/signature system --- src/cuchaz/enigma/mapping/BehaviorSignature.java | 96 ++++++++++++ src/cuchaz/enigma/mapping/Type.java | 179 +++++++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 src/cuchaz/enigma/mapping/BehaviorSignature.java create mode 100644 src/cuchaz/enigma/mapping/Type.java (limited to 'src') diff --git a/src/cuchaz/enigma/mapping/BehaviorSignature.java b/src/cuchaz/enigma/mapping/BehaviorSignature.java new file mode 100644 index 00000000..a6371f85 --- /dev/null +++ b/src/cuchaz/enigma/mapping/BehaviorSignature.java @@ -0,0 +1,96 @@ +package cuchaz.enigma.mapping; + +import java.util.List; + +import com.beust.jcommander.internal.Lists; + +public class BehaviorSignature { + + public static interface ClassReplacer { + ClassEntry replace(ClassEntry entry); + } + + private List m_argumentTypes; + private Type m_returnType; + + public BehaviorSignature(String signature) { + m_argumentTypes = Lists.newArrayList(); + int i=0; + while (i getArgumentTypes() { + return m_argumentTypes; + } + + public Type getReturnType() { + return m_returnType; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append("("); + for (int i=0; i 0) { + buf.append(","); + } + buf.append(m_argumentTypes.get(i).toString()); + } + buf.append(")"); + buf.append(m_returnType.toString()); + return buf.toString(); + } + + public Iterable types() { + List types = Lists.newArrayList(); + types.addAll(m_argumentTypes); + types.add(m_returnType); + return types; + } + + public Iterable classes() { + List out = Lists.newArrayList(); + for (Type type : types()) { + if (type.isClass()) { + out.add(type.getClassEntry()); + } + } + return out; + } +} diff --git a/src/cuchaz/enigma/mapping/Type.java b/src/cuchaz/enigma/mapping/Type.java new file mode 100644 index 00000000..2273e21b --- /dev/null +++ b/src/cuchaz/enigma/mapping/Type.java @@ -0,0 +1,179 @@ +package cuchaz.enigma.mapping; + +import java.util.Map; + +import com.google.common.collect.Maps; + +public class Type { + + public enum Primitive { + Byte('B'), + Character('C'), + Short('S'), + Integer('I'), + Long('J'), + Float('F'), + Double('D'), + Boolean('Z'); + + private static final Map m_lookup; + + static { + m_lookup = Maps.newTreeMap(); + for (Primitive val : values()) { + m_lookup.put(val.getCode(), val); + } + } + + public static Primitive get(char code) { + return m_lookup.get(code); + } + + private char m_code; + + private Primitive(char code) { + m_code = code; + } + + public char getCode() { + return m_code; + } + } + + public static String parseFirst(String in) { + + // read one type from the input + + char c = in.charAt(0); + + // first check for void + if (c == 'V') { + return "V"; + } + + // then check for primitives + Primitive primitive = Primitive.get(c); + if (primitive != null) { + return in.substring(0, 1); + } + + // then check for classes + if (c == 'L') { + return readClass(in); + } + + // then check for arrays + int dim = countArrayDimension(in); + if (dim > 0) { + String arrayType = Type.parseFirst(in.substring(dim)); + return in.substring(0, dim + arrayType.length()); + } + + throw new IllegalArgumentException("don't know how to parse: " + in); + } + + private String m_name; + + public Type(String name) { + m_name = name; + } + + public Type(ClassEntry classEntry) { + m_name = "L" + classEntry.getClassName() + ";"; + } + + @Override + public String toString() { + return m_name; + } + + public boolean isVoid() { + return m_name.length() == 1 && m_name.charAt(0) == 'V'; + } + + public boolean isPrimitive() { + return m_name.length() == 1 && Primitive.get(m_name.charAt(0)) != null; + } + + public Primitive getPrimitive() { + if (!isPrimitive()) { + throw new IllegalStateException("not a primitive"); + } + return Primitive.get(m_name.charAt(0)); + } + + public boolean isClass() { + return m_name.charAt(0) == 'L' && m_name.charAt(m_name.length() - 1) == ';'; + } + + public ClassEntry getClassEntry() { + if (!isClass()) { + throw new IllegalStateException("not a class"); + } + String name = m_name.substring(1, m_name.length() - 1); + + int pos = name.indexOf('<'); + if (pos >= 0) { + // remove the parameters from the class name + name = name.substring(0, pos); + } + + return new ClassEntry(name); + } + + public boolean isArray() { + return m_name.charAt(0) == '['; + } + + public int getArrayDimension() { + if (!isArray()) { + throw new IllegalStateException("not an array"); + } + return countArrayDimension(m_name); + } + + public Type getArrayType() { + if (!isArray()) { + throw new IllegalStateException("not an array"); + } + return new Type(m_name.substring(getArrayDimension(), m_name.length())); + } + + @Override + public boolean equals(Object other) { + if (other instanceof Type) { + return equals((Type)other); + } + return false; + } + + public boolean equals(Type other) { + return m_name.equals(other.m_name); + } + + private static int countArrayDimension(String in) { + int i=0; + for(; i < in.length() && in.charAt(i) == '['; i++); + return i; + } + + private static String readClass(String in) { + // read all the characters in the buffer until we hit a ';' + // remember to treat parameters correctly + StringBuilder buf = new StringBuilder(); + int depth = 0; + for (int i=0; i') { + depth--; + } else if (depth == 0 && c == ';') { + return buf.toString(); + } + } + return null; + } +} -- cgit v1.2.3 From cb22a55b241714a56f78b9c6ee863f0a37bbf005 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 5 Feb 2015 23:53:41 -0500 Subject: start some translation tests --- src/cuchaz/enigma/mapping/Mappings.java | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'src') diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index cc560a87..92134edf 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java @@ -10,20 +10,15 @@ ******************************************************************************/ package cuchaz.enigma.mapping; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.Set; -import java.util.zip.GZIPInputStream; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import cuchaz.enigma.Util; import cuchaz.enigma.analysis.TranslationIndex; import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; @@ -50,16 +45,6 @@ public class Mappings implements Serializable { } } - 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 Collection classes() { assert (m_classesByObf.size() >= m_classesByDeobf.size()); return m_classesByObf.values(); @@ -134,14 +119,6 @@ public class Mappings implements Serializable { } } - 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(); -- cgit v1.2.3