Package cuchaz.enigma.gui

Source Code of cuchaz.enigma.gui.GuiController

/*******************************************************************************
* Copyright (c) 2014 Jeff Martin.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License 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.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.Deque;
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.Deobfuscator.ProgressListener;
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;
import cuchaz.enigma.gui.ProgressDialog.ProgressRunnable;
import cuchaz.enigma.mapping.BehaviorEntry;
import cuchaz.enigma.mapping.ClassEntry;
import cuchaz.enigma.mapping.Entry;
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;
import cuchaz.enigma.mapping.TranslationDirection;

public class GuiController
{
  private Deobfuscator m_deobfuscator;
  private Gui m_gui;
  private SourceIndex m_index;
  private ClassEntry m_currentObfClass;
  private boolean m_isDirty;
  private Deque<EntryReference<Entry,Entry>> m_referenceStack;
 
  public GuiController( Gui gui )
  {
    m_gui = gui;
    m_deobfuscator = null;
    m_index = null;
    m_currentObfClass = null;
    m_isDirty = false;
    m_referenceStack = Queues.newArrayDeque();
  }
 
  public boolean isDirty( )
  {
    return m_isDirty;
  }
 
  public void openJar( final File file )
  throws IOException
  {
    m_gui.onStartOpenJar();
    m_deobfuscator = new Deobfuscator( file );
    m_gui.onFinishOpenJar( m_deobfuscator.getJarName() );
    refreshClasses();
  }
 
  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 ) );
    in.close();
    m_isDirty = false;
    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() );
    out.close();
    m_isDirty = false;
  }

  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( )
    {
      @Override
      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( )
    {
      @Override
      public void run( ProgressListener progress )
      {
        m_deobfuscator.writeJar( fileOut, progress );
      }
    } );
  }
 
  public Token getToken( int pos )
  {
    if( m_index == null )
    {
      return null;
    }
    return m_index.getReferenceToken( pos );
  }
 
  public EntryReference<Entry,Entry> getDeobfReference( Token token )
  {
    if( m_index == null )
    {
      return null;
    }
    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 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 referenceIsRenameable( EntryReference<Entry,Entry> deobfReference )
  {
    return m_deobfuscator.isRenameable( m_deobfuscator.obfuscateReference( deobfReference ) );
  }
 
  public ClassInheritanceTreeNode getClassInheritance( ClassEntry deobfClassEntry )
  {
    ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry( deobfClassEntry );
    ClassInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getClassInheritance(
      m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ),
      obfClassEntry
    );
    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 );
    MethodInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodInheritance(
      m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ),
      obfMethodEntry
    );
    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 );
    FieldReferenceTreeNode rootNode = new FieldReferenceTreeNode(
      m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ),
      obfFieldEntry
    );
    rootNode.load( m_deobfuscator.getJarIndex(), true );
    return rootNode;
  }
 
  public BehaviorReferenceTreeNode getMethodReferences( BehaviorEntry deobfBehaviorEntry )
  {
    BehaviorEntry obfBehaviorEntry = m_deobfuscator.obfuscateEntry( deobfBehaviorEntry );
    BehaviorReferenceTreeNode rootNode = new BehaviorReferenceTreeNode(
      m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ),
      obfBehaviorEntry
    );
    rootNode.load( m_deobfuscator.getJarIndex(), true );
    return rootNode;
  }
 
  public void rename( EntryReference<Entry,Entry> deobfReference, String newName )
  {
    EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference( deobfReference );
    m_deobfuscator.rename( obfReference.getNameableEntry(), newName );
    m_isDirty = true;
    refreshClasses();
    refreshCurrentClass( obfReference );
  }
 
  public void removeMapping( EntryReference<Entry,Entry> deobfReference )
  {
    EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference( deobfReference );
    m_deobfuscator.removeMapping( obfReference.getNameableEntry() );
    m_isDirty = true;
    refreshClasses();
    refreshCurrentClass( obfReference );
  }
 
  public void markAsDeobfuscated( EntryReference<Entry,Entry> deobfReference )
  {
    EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference( deobfReference );
    m_deobfuscator.markAsDeobfuscated( obfReference.getNameableEntry() );
    m_isDirty = true;
    refreshClasses();
    refreshCurrentClass( obfReference );
  }
 
  public void openDeclaration( Entry deobfEntry )
  {
    if( deobfEntry == null )
    {
      throw new IllegalArgumentException( "Entry cannot be null!" );
    }
    openReference( new EntryReference<Entry,Entry>( deobfEntry, deobfEntry.getName() ) );
  }
 
  public void openReference( EntryReference<Entry,Entry> deobfReference )
  {
    if( deobfReference == null )
    {
      throw new IllegalArgumentException( "Reference cannot be null!" );
    }
   
    // get the reference target class
    EntryReference<Entry,Entry> 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_currentObfClass == null || !m_currentObfClass.equals( obfClassEntry ) )
    {
      // deobfuscate the class, then navigate to the reference
      m_currentObfClass = obfClassEntry;
      deobfuscate( m_currentObfClass, obfReference );
    }
    else
    {
      showReference( obfReference );
    }
  }
 
  private void showReference( EntryReference<Entry,Entry> obfReference )
  {
    EntryReference<Entry,Entry> deobfReference = m_deobfuscator.deobfuscateReference( obfReference );
    Collection<Token> 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 );
    }
  }
 
  public void savePreviousReference( EntryReference<Entry,Entry> deobfReference )
  {
    m_referenceStack.push( m_deobfuscator.obfuscateReference( deobfReference ) );
  }
 
  public void openPreviousReference( )
  {
    if( hasPreviousLocation() )
    {
      openReference( m_deobfuscator.deobfuscateReference( m_referenceStack.pop() ) );
    }
  }
 
  public boolean hasPreviousLocation( )
  {
    return !m_referenceStack.isEmpty();
  }
 
  private void refreshClasses( )
  {
    List<ClassEntry> obfClasses = Lists.newArrayList();
    List<ClassEntry> deobfClasses = Lists.newArrayList();
    m_deobfuscator.getSeparatedClasses( obfClasses, deobfClasses );
    m_gui.setObfClasses( obfClasses );
    m_gui.setDeobfClasses( deobfClasses );
  }
 
  private void refreshCurrentClass( )
  {
    refreshCurrentClass( null );
  }
 
  private void refreshCurrentClass( EntryReference<Entry,Entry> obfReference )
  {
    if( m_currentObfClass != null )
    {
      deobfuscate( m_currentObfClass, obfReference );
    }
  }
 
  private void deobfuscate( final ClassEntry classEntry, final EntryReference<Entry,Entry> obfReference )
  {
    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( )
      {
        // decompile,deobfuscate the bytecode
        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 );
        }
       
        // set the highlighted tokens
        List<Token> obfuscatedTokens = Lists.newArrayList();
        List<Token> deobfuscatedTokens = Lists.newArrayList();
        List<Token> otherTokens = Lists.newArrayList();
        for( Token token : m_index.referenceTokens() )
        {
          EntryReference<Entry,Entry> reference = m_index.getDeobfReference( token );
          if( referenceIsRenameable( reference ) )
          {
            if( entryHasDeobfuscatedName( reference.getNameableEntry() ) )
            {
              deobfuscatedTokens.add( token );
            }
            else
            {
              obfuscatedTokens.add( token );
            }
          }
          else
          {
            otherTokens.add( token );
          }
        }
        m_gui.setHighlightedTokens( obfuscatedTokens, deobfuscatedTokens, otherTokens );
      }
    }.start();
  }
}
TOP

Related Classes of cuchaz.enigma.gui.GuiController

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.