2013-07-16 17:58:02 +10:00
package codechicken.lib.asm ;
2014-04-07 23:13:05 +10:00
import codechicken.lib.config.ConfigFile ;
import codechicken.lib.config.ConfigTag ;
import com.google.common.base.Charsets ;
2014-04-09 13:38:05 +10:00
import com.google.common.base.Objects ;
2014-04-07 23:13:05 +10:00
import com.google.common.io.LineProcessor ;
import com.google.common.io.Resources ;
2014-04-09 13:38:05 +10:00
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper ;
2014-04-07 23:13:05 +10:00
import cpw.mods.fml.relauncher.FMLInjectionData ;
2014-04-07 14:02:47 +10:00
import net.minecraft.launchwrapper.Launch ;
2013-07-16 17:58:02 +10:00
import org.objectweb.asm.MethodVisitor ;
import org.objectweb.asm.commons.Remapper ;
2014-04-09 13:38:05 +10:00
import org.objectweb.asm.tree.* ;
2013-07-16 17:58:02 +10:00
2014-04-07 23:13:05 +10:00
import javax.swing.* ;
2014-04-09 13:38:05 +10:00
import java.io.File ;
import java.io.IOException ;
import java.lang.reflect.Field ;
import java.util.HashMap ;
import java.util.Map ;
import java.util.Map.Entry ;
2014-04-07 23:13:05 +10:00
2013-07-16 17:58:02 +10:00
public class ObfMapping
{
2014-04-07 14:02:47 +10:00
public static class ObfRemapper extends Remapper
{
private HashMap < String , String > fields = new HashMap < String , String > ();
private HashMap < String , String > funcs = new HashMap < String , String > ();
public ObfRemapper () {
try {
Field rawFieldMapsField = FMLDeobfuscatingRemapper . class . getDeclaredField ( "rawFieldMaps" );
Field rawMethodMapsField = FMLDeobfuscatingRemapper . class . getDeclaredField ( "rawMethodMaps" );
rawFieldMapsField . setAccessible ( true );
rawMethodMapsField . setAccessible ( true );
Map < String , Map < String , String >> rawFieldMaps = ( Map < String , Map < String , String >> ) rawFieldMapsField . get ( FMLDeobfuscatingRemapper . INSTANCE );
Map < String , Map < String , String >> rawMethodMaps = ( Map < String , Map < String , String >> ) rawMethodMapsField . get ( FMLDeobfuscatingRemapper . INSTANCE );
2014-04-07 23:13:05 +10:00
if ( rawFieldMaps == null )
2014-04-07 14:02:47 +10:00
throw new IllegalStateException ( "codechicken.lib.asm.ObfMapping loaded too early. Make sure all references are in or after the asm transformer load stage" );
2014-04-07 23:13:05 +10:00
for ( Map < String , String > map : rawFieldMaps . values ())
for ( Entry < String , String > entry : map . entrySet ())
if ( entry . getValue (). startsWith ( "field" ))
2014-04-07 14:02:47 +10:00
fields . put ( entry . getValue (), entry . getKey (). substring ( 0 , entry . getKey (). indexOf ( ':' )));
2014-04-07 23:13:05 +10:00
for ( Map < String , String > map : rawMethodMaps . values ())
for ( Entry < String , String > entry : map . entrySet ())
if ( entry . getValue (). startsWith ( "func" ))
2014-04-07 14:02:47 +10:00
funcs . put ( entry . getValue (), entry . getKey (). substring ( 0 , entry . getKey (). indexOf ( '(' )));
} catch ( Exception e ) {
throw new RuntimeException ( e );
}
}
@Override
public String mapMethodName ( String owner , String name , String desc ) {
String s = funcs . get ( name );
return s == null ? name : s ;
}
@Override
public String mapFieldName ( String owner , String name , String desc ) {
String s = fields . get ( name );
return s == null ? name : s ;
}
@Override
public String map ( String typeName ) {
return FMLDeobfuscatingRemapper . INSTANCE . unmap ( typeName );
}
}
2014-04-07 23:13:05 +10:00
public static class MCPRemapper extends Remapper implements LineProcessor < Void >
{
public static ConfigFile config ;
public static File [] getConfFiles () {
if ( config == null )
config = new ConfigFile ( new File (( File ) FMLInjectionData . data () [ 6 ] , "config/CodeChickenLib.cfg" )). setComment ( "CodeChickenLib configuration file." );
ConfigTag tag = config . getTag ( "dev.mappingDir" ). setComment ( "Path to directory holding packaged.srg, fields.csv and methods.csv for mcp remapping" );
for ( int i = 0 ; i < 6 ; i ++ ) {
File dir = confDirectoryGuess ( i , tag );
if ( dir == null || dir . isFile ())
continue ;
File [] mappings ;
try {
mappings = parseConfDir ( dir );
} catch ( Exception e ) {
if ( i >= 3 )
e . printStackTrace ();
continue ;
}
tag . setValue ( dir . getPath ());
return mappings ;
}
throw new RuntimeException ( "Failed to select mappings directory, set it manually in the config" );
}
public static File confDirectoryGuess ( int i , ConfigTag tag ) {
File mcDir = ( File ) FMLInjectionData . data () [ 6 ] ;
switch ( i ) {
case 0 :
return tag . value != null ? new File ( tag . getValue ()) : null ;
case 1 :
return new File ( mcDir , "../conf" );
case 2 :
return new File ( mcDir , "../build/unpacked/conf" );
default :
JFileChooser fc = new JFileChooser ( mcDir );
fc . setFileSelectionMode ( JFileChooser . DIRECTORIES_ONLY );
fc . setDialogTitle ( "Select an mcp conf dir for the deobfuscator." );
int ret = fc . showDialog ( null , "Select" );
return ret == JFileChooser . APPROVE_OPTION ? fc . getSelectedFile () : null ;
}
}
public static File [] parseConfDir ( File confDir ) {
File srgDir = new File ( confDir , "conf" );
if ( ! srgDir . exists ())
srgDir = confDir ;
File srgs = new File ( srgDir , "packaged.srg" );
if ( ! srgs . exists ())
srgs = new File ( srgDir , "joined.srg" );
if ( ! srgs . exists ())
throw new RuntimeException ( "Could not find packaged.srg or joined.srg" );
File mapDir = new File ( confDir , "mappings" );
if ( ! mapDir . exists ())
mapDir = confDir ;
File methods = new File ( mapDir , "methods.csv" );
if ( ! methods . exists ())
throw new RuntimeException ( "Could not find methods.csv" );
File fields = new File ( mapDir , "fields.csv" );
if ( ! fields . exists ())
throw new RuntimeException ( "Could not find fields.csv" );
return new File [] { srgs , methods , fields };
}
private HashMap < String , String > fields = new HashMap < String , String > ();
private HashMap < String , String > funcs = new HashMap < String , String > ();
public MCPRemapper () {
File [] mappings = getConfFiles ();
try {
Resources . readLines ( mappings [ 1 ] . toURI (). toURL (), Charsets . UTF_8 , this );
Resources . readLines ( mappings [ 2 ] . toURI (). toURL (), Charsets . UTF_8 , this );
} catch ( IOException e ) {
e . printStackTrace ();
}
}
@Override
public String mapMethodName ( String owner , String name , String desc ) {
String s = funcs . get ( name );
return s == null ? name : s ;
}
@Override
public String mapFieldName ( String owner , String name , String desc ) {
String s = fields . get ( name );
return s == null ? name : s ;
}
@Override
public boolean processLine ( String line ) throws IOException {
int i = line . indexOf ( ',' );
String srg = line . substring ( 0 , i );
int i2 = i + 1 ;
i = line . indexOf ( ',' , i2 );
String mcp = line . substring ( i2 , i );
( srg . startsWith ( "func" ) ? funcs : fields ). put ( srg , mcp );
return true ;
}
@Override
public Void getResult () {
return null ;
}
}
2014-04-07 14:02:47 +10:00
public static ObfRemapper obfMapper = new ObfRemapper ();
2013-07-16 17:58:02 +10:00
public static Remapper mcpMapper = null ;
2014-04-07 14:02:47 +10:00
2014-04-07 23:13:05 +10:00
public static void loadMCPRemapper () {
if ( mcpMapper == null )
mcpMapper = new MCPRemapper ();
}
2013-07-16 17:58:02 +10:00
public static final boolean obfuscated ;
2014-04-07 14:02:47 +10:00
static {
2013-07-16 17:58:02 +10:00
boolean obf = true ;
2014-04-07 14:02:47 +10:00
try {
obf = Launch . classLoader . getClassBytes ( "net.minecraft.world.World" ) == null ;
} catch ( IOException ignored ) {}
2013-07-16 17:58:02 +10:00
obfuscated = obf ;
2014-04-07 23:13:05 +10:00
if ( ! obf )
loadMCPRemapper ();
2013-07-16 17:58:02 +10:00
}
2014-04-07 14:02:47 +10:00
2013-07-16 17:58:02 +10:00
public String s_owner ;
public String s_name ;
public String s_desc ;
2014-04-07 14:02:47 +10:00
public ObfMapping ( String owner ) {
2013-07-17 18:18:57 +10:00
this ( owner , "" , "" );
2013-07-16 17:58:02 +10:00
}
2014-04-07 14:02:47 +10:00
public ObfMapping ( String owner , String name , String desc ) {
2013-07-16 17:58:02 +10:00
this . s_owner = owner ;
this . s_name = name ;
this . s_desc = desc ;
2014-04-07 14:02:47 +10:00
if ( s_owner . contains ( "." ))
2013-07-16 17:58:02 +10:00
throw new IllegalArgumentException ( s_owner );
}
2014-04-07 14:02:47 +10:00
public ObfMapping ( ObfMapping descmap , String subclass ) {
2013-07-16 17:58:02 +10:00
this ( subclass , descmap . s_name , descmap . s_desc );
}
2014-04-07 14:02:47 +10:00
public static ObfMapping fromDesc ( String s ) {
2013-07-19 01:00:09 +10:00
int lastDot = s . lastIndexOf ( '.' );
2014-04-07 14:02:47 +10:00
if ( lastDot < 0 )
2013-07-16 17:58:02 +10:00
return new ObfMapping ( s , "" , "" );
int sep = s . indexOf ( '(' ); //methods
int sep_end = sep ;
2014-04-07 14:02:47 +10:00
if ( sep < 0 ) {
2013-07-16 17:58:02 +10:00
sep = s . indexOf ( ' ' ); //some stuffs
2014-04-07 14:02:47 +10:00
sep_end = sep + 1 ;
2013-07-16 17:58:02 +10:00
}
2014-04-07 14:02:47 +10:00
if ( sep < 0 ) {
2013-07-16 17:58:02 +10:00
sep = s . indexOf ( ':' ); //fields
2014-04-07 14:02:47 +10:00
sep_end = sep + 1 ;
2013-07-16 17:58:02 +10:00
}
2014-04-07 14:02:47 +10:00
if ( sep < 0 )
2013-07-16 17:58:02 +10:00
return new ObfMapping ( s . substring ( 0 , lastDot ), s . substring ( lastDot + 1 ), "" );
2014-04-07 14:02:47 +10:00
return new ObfMapping ( s . substring ( 0 , lastDot ), s . substring ( lastDot + 1 , sep ), s . substring ( sep_end ));
2013-07-16 17:58:02 +10:00
}
2014-04-07 14:02:47 +10:00
public ObfMapping subclass ( String subclass ) {
2013-07-16 17:58:02 +10:00
return new ObfMapping ( this , subclass );
}
2014-04-07 14:02:47 +10:00
public boolean matches ( MethodNode node ) {
2013-07-16 17:58:02 +10:00
return s_name . equals ( node . name ) && s_desc . equals ( node . desc );
}
2014-04-07 14:02:47 +10:00
public boolean matches ( MethodInsnNode node ) {
2013-07-16 17:58:02 +10:00
return s_owner . equals ( node . owner ) && s_name . equals ( node . name ) && s_desc . equals ( node . desc );
}
2014-04-07 14:02:47 +10:00
public AbstractInsnNode toInsn ( int opcode ) {
if ( isClass ())
2013-07-16 17:58:02 +10:00
return new TypeInsnNode ( opcode , s_owner );
2014-04-07 14:02:47 +10:00
else if ( isMethod ())
2013-07-16 17:58:02 +10:00
return new MethodInsnNode ( opcode , s_owner , s_name , s_desc );
else
return new FieldInsnNode ( opcode , s_owner , s_name , s_desc );
}
2014-04-07 14:02:47 +10:00
public void visitTypeInsn ( MethodVisitor mv , int opcode ) {
2013-07-16 17:58:02 +10:00
mv . visitTypeInsn ( opcode , s_owner );
}
2014-04-07 14:02:47 +10:00
public void visitMethodInsn ( MethodVisitor mv , int opcode ) {
2013-07-16 17:58:02 +10:00
mv . visitMethodInsn ( opcode , s_owner , s_name , s_desc );
}
2014-04-07 14:02:47 +10:00
public void visitFieldInsn ( MethodVisitor mv , int opcode ) {
2013-07-16 17:58:02 +10:00
mv . visitFieldInsn ( opcode , s_owner , s_name , s_desc );
}
2014-04-07 14:02:47 +10:00
public boolean isClass ( String name ) {
2013-07-16 17:58:02 +10:00
return name . replace ( '.' , '/' ). equals ( s_owner );
}
2014-04-07 14:02:47 +10:00
public boolean matches ( String name , String desc ) {
2013-07-16 17:58:02 +10:00
return s_name . equals ( name ) && s_desc . equals ( desc );
}
2014-04-07 14:02:47 +10:00
public boolean matches ( FieldNode node ) {
2013-07-16 17:58:02 +10:00
return s_name . equals ( node . name ) && s_desc . equals ( node . desc );
}
2014-04-07 14:02:47 +10:00
public boolean matches ( FieldInsnNode node ) {
2013-07-16 17:58:02 +10:00
return s_owner . equals ( node . owner ) && s_name . equals ( node . name ) && s_desc . equals ( node . desc );
}
2014-04-07 14:02:47 +10:00
public String javaClass () {
2013-07-16 17:58:02 +10:00
return s_owner . replace ( '/' , '.' );
}
2014-04-07 14:02:47 +10:00
2013-07-16 17:58:02 +10:00
@Override
2014-04-07 14:02:47 +10:00
public boolean equals ( Object obj ) {
if ( ! ( obj instanceof ObfMapping ))
2013-07-16 17:58:02 +10:00
return false ;
2014-04-07 14:02:47 +10:00
ObfMapping desc = ( ObfMapping ) obj ;
2013-07-16 17:58:02 +10:00
return s_owner . equals ( desc . s_owner ) && s_name . equals ( desc . s_name ) && s_desc . equals ( desc . s_desc );
}
2014-04-07 14:02:47 +10:00
2013-07-16 17:58:02 +10:00
@Override
2014-04-07 14:02:47 +10:00
public int hashCode () {
2013-07-16 17:58:02 +10:00
return Objects . hashCode ( s_desc , s_name , s_owner );
}
2014-04-07 14:02:47 +10:00
2013-07-16 17:58:02 +10:00
@Override
2014-04-07 14:02:47 +10:00
public String toString () {
if ( s_name . length () == 0 )
return "[" + s_owner + "]" ;
if ( s_desc . length () == 0 )
return "[" + s_owner + "." + s_name + "]" ;
return "[" + ( isMethod () ? methodDesc () : fieldDesc ()) + "]" ;
2013-07-19 01:00:09 +10:00
}
2014-04-07 14:02:47 +10:00
public String methodDesc () {
return s_owner + "." + s_name + s_desc ;
2013-07-19 01:00:09 +10:00
}
2014-04-07 14:02:47 +10:00
public String fieldDesc () {
return s_owner + "." + s_name + ":" + s_desc ;
2013-07-16 17:58:02 +10:00
}
2014-04-07 14:02:47 +10:00
public boolean isClass () {
2013-07-16 17:58:02 +10:00
return s_name . length () == 0 ;
}
2014-04-07 14:02:47 +10:00
public boolean isMethod () {
2013-07-16 17:58:02 +10:00
return s_desc . contains ( "(" );
}
2014-04-07 14:02:47 +10:00
public boolean isField () {
2013-07-16 17:58:02 +10:00
return ! isClass () && ! isMethod ();
}
2014-04-07 14:02:47 +10:00
public ObfMapping map ( Remapper mapper ) {
2014-04-07 23:13:05 +10:00
if ( mapper == null )
2014-04-07 14:02:47 +10:00
return this ;
if ( isMethod ())
2013-07-16 17:58:02 +10:00
s_name = mapper . mapMethodName ( s_owner , s_name , s_desc );
2014-04-07 14:02:47 +10:00
else if ( isField ())
2013-07-16 17:58:02 +10:00
s_name = mapper . mapFieldName ( s_owner , s_name , s_desc );
2014-04-07 14:02:47 +10:00
2013-07-16 17:58:02 +10:00
s_owner = mapper . mapType ( s_owner );
2014-04-07 14:02:47 +10:00
if ( isMethod ())
2013-07-19 01:00:09 +10:00
s_desc = mapper . mapMethodDesc ( s_desc );
2014-04-07 14:02:47 +10:00
else if ( s_desc . length () > 0 )
2013-07-16 17:58:02 +10:00
s_desc = mapper . mapDesc ( s_desc );
2014-04-07 14:02:47 +10:00
2013-07-16 17:58:02 +10:00
return this ;
}
2014-04-07 14:02:47 +10:00
public ObfMapping toRuntime () {
map ( mcpMapper );
2013-07-16 17:58:02 +10:00
return this ;
}
2014-04-07 14:02:47 +10:00
public ObfMapping toClassloading () {
map ( obfuscated ? obfMapper : mcpMapper );
return this ;
}
public ObfMapping copy () {
2013-07-19 01:00:09 +10:00
return new ObfMapping ( s_owner , s_name , s_desc );
2013-07-16 17:58:02 +10:00
}
}