2013-07-16 17:58:02 +10:00
package codechicken.lib.asm ;
import java.util.ArrayList ;
import java.util.HashMap ;
import java.util.HashSet ;
import org.objectweb.asm.tree.ClassNode ;
2013-07-23 16:04:41 +10:00
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper ;
2013-07-16 17:58:02 +10:00
import net.minecraft.launchwrapper.IClassTransformer ;
import net.minecraft.launchwrapper.LaunchClassLoader ;
/**
* This is added as a class transformer if CodeChickenCore is installed. Adding it as a class transformer will speed evaluation up slightly by automatically caching superclasses when they are first loaded.
*/
public class ClassHeirachyManager implements IClassTransformer
{
public static HashSet < String > knownClasses = new HashSet < String > ();
public static HashMap < String , ArrayList < String >> superclasses = new HashMap < String , ArrayList < String >> ();
private static LaunchClassLoader cl = ( LaunchClassLoader ) ClassHeirachyManager . class . getClassLoader ();
2013-07-17 18:18:57 +10:00
static
{
cl . addTransformerExclusion ( "codechicken.lib.asm" );
}
2013-07-23 16:04:41 +10:00
public static String toKey ( String name )
{
if ( ObfMapping . obfuscated )
name = FMLDeobfuscatingRemapper . INSTANCE . unmap ( name . replace ( '.' , '/' )). replace ( '/' , '.' );
return name ;
}
2013-07-16 17:58:02 +10:00
/**
* Returns true if clazz extends, either directly or indirectly, superclass.
2013-07-23 16:04:41 +10:00
* @param name The class in question
2013-07-16 17:58:02 +10:00
* @param superclass The class being extended
2013-07-23 16:04:41 +10:00
* @param bytes The bytes for the class. Only needed if not already defined.
2013-07-16 17:58:02 +10:00
* @return
*/
2013-07-23 16:04:41 +10:00
public static boolean classExtends ( String name , String superclass , byte [] bytes )
2013-07-16 17:58:02 +10:00
{
2013-07-23 16:04:41 +10:00
name = toKey ( name );
if ( ! knownClasses . contains ( name ))
new ClassHeirachyManager (). transform ( name , name , bytes );
2013-07-16 17:58:02 +10:00
2013-07-23 16:04:41 +10:00
return classExtends ( name , superclass );
2013-07-16 17:58:02 +10:00
}
public static boolean classExtends ( String clazz , String superclass )
{
if ( clazz . equals ( superclass ))
return true ;
if ( clazz . equals ( "java.lang.Object" ))
return false ;
declareClass ( clazz );
if ( ! superclasses . containsKey ( clazz )) //just can't handle this
return false ;
for ( String s : superclasses . get ( clazz ))
if ( classExtends ( s , superclass ))
return true ;
return false ;
}
2013-07-23 16:04:41 +10:00
private static void declareClass ( String name )
2013-07-16 17:58:02 +10:00
{
2013-07-23 16:04:41 +10:00
name = toKey ( name );
2013-07-16 17:58:02 +10:00
try
{
2013-07-23 16:04:41 +10:00
if ( ! knownClasses . contains ( name ))
2013-07-16 17:58:02 +10:00
{
try
{
2013-07-23 16:04:41 +10:00
byte [] bytes = cl . getClassBytes ( name );
2013-07-16 17:58:02 +10:00
if ( bytes != null )
2013-07-23 16:04:41 +10:00
new ClassHeirachyManager (). transform ( name , name , bytes );
2013-07-16 17:58:02 +10:00
}
catch ( Exception e )
{
}
2013-07-23 16:04:41 +10:00
if ( ! knownClasses . contains ( name ))
2013-07-16 17:58:02 +10:00
{
2013-07-23 16:04:41 +10:00
Class <?> aclass = Class . forName ( name );
2013-07-16 17:58:02 +10:00
2013-07-23 16:04:41 +10:00
knownClasses . add ( name );
2013-07-16 17:58:02 +10:00
if ( aclass . isInterface ())
2013-07-23 16:04:41 +10:00
addSuperclass ( name , "java.lang.Object" );
2013-07-16 17:58:02 +10:00
else
2013-07-23 16:04:41 +10:00
addSuperclass ( name , aclass . getSuperclass (). getName ());
2013-07-16 17:58:02 +10:00
for ( Class <?> iclass : aclass . getInterfaces ())
2013-07-23 16:04:41 +10:00
addSuperclass ( name , iclass . getName ());
2013-07-16 17:58:02 +10:00
}
}
}
catch ( ClassNotFoundException e )
{
}
}
@Override
public byte [] transform ( String name , String tname , byte [] bytes )
{
if ( bytes == null ) return null ;
if ( ! knownClasses . contains ( name ))
2013-07-17 18:18:57 +10:00
{
2013-07-16 17:58:02 +10:00
ClassNode node = ASMHelper . createClassNode ( bytes );
knownClasses . add ( name );
addSuperclass ( name , node . superName . replace ( '/' , '.' ));
for ( String iclass : node . interfaces )
addSuperclass ( name , iclass . replace ( '/' , '.' ));
}
return bytes ;
}
private static void addSuperclass ( String name , String superclass )
{
ArrayList < String > supers = superclasses . get ( name );
if ( supers == null )
superclasses . put ( name , supers = new ArrayList < String > ());
supers . add ( superclass );
2013-07-17 18:18:57 +10:00
supers . add ( new ObfMapping ( superclass . replace ( '.' , '/' )). toRuntime (). javaClass ());
2013-07-16 17:58:02 +10:00
}
2013-07-23 16:04:41 +10:00
public static String getSuperClass ( String name , boolean runtime )
2013-07-16 17:58:02 +10:00
{
2013-07-23 16:04:41 +10:00
name = toKey ( name );
declareClass ( name );
if ( ! knownClasses . contains ( name ))
2013-07-16 17:58:02 +10:00
return "java.lang.Object" ;
2013-07-23 16:04:41 +10:00
return superclasses . get ( name ). get ( runtime ? 1 : 0 );
2013-07-16 17:58:02 +10:00
}
}