Package cuchaz.enigma.bytecode

Source Code of cuchaz.enigma.bytecode.ClassRenamer

/*******************************************************************************
* Copyright (c) 2014 Jeff Martin.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License 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.CtBehavior;
import javassist.CtClass;
import javassist.bytecode.ConstPool;
import javassist.bytecode.Descriptor;
import javassist.bytecode.InnerClassesAttribute;

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
{
  public static void renameClasses( CtClass c, Map<ClassEntry,ClassEntry> map )
  {
    // build the map used by javassist
    ClassMap nameMap = new ClassMap();
    for( Map.Entry<ClassEntry,ClassEntry> entry : map.entrySet() )
    {
      nameMap.put( entry.getKey().getName(), entry.getValue().getName() );
    }
   
    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.tableLength(); i++ )
      {
        ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( attr.innerClass( i ) ) );
        if( attr.innerNameIndex( i ) != 0 )
        {
          attr.setInnerNameIndex( i, constants.addUtf8Info( classEntry.getInnerClassName() ) );
        }
       
        /* DEBUG
        System.out.println( String.format( "\tDEOBF: %s-> ATTR: %s,%s,%s",
          classEntry,
          attr.outerClass( i ),
          attr.innerClass( i ),
          attr.innerName( i )
        ) );
        */
      }
    }
  }
 
  public static Set<ClassEntry> getAllClassEntries( final CtClass c )
  {
    // get the classes that javassist knows about
    final Set<ClassEntry> entries = Sets.newHashSet();
    ClassMap map = new ClassMap( )
    {
      @Override
      public Object get( Object obj )
      {
        if( obj instanceof String )
        {
          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;
      }
      private static final long serialVersionUID = -202160293602070641L;
    };
    c.replaceClassName( map );
   
    return entries;
  }
 
  public static void moveAllClassesOutOfDefaultPackage( CtClass c, String newPackageName )
  {
    // rename all classes
    Map<ClassEntry,ClassEntry> map = Maps.newHashMap();
    for( ClassEntry classEntry : ClassRenamer.getAllClassEntries( c ) )
    {
      if( classEntry.isInDefaultPackage() )
      {
        map.put( classEntry, new ClassEntry( newPackageName + "/" + classEntry.getName() ) );
      }
    }
    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;
        }
      } );
    }
  }
}
TOP

Related Classes of cuchaz.enigma.bytecode.ClassRenamer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.