Package org.jreversepro.gui

Source Code of org.jreversepro.gui.GUIMain

/**
* JReversePro - Java Decompiler / Disassembler.
* Copyright (C) 2008 Karthik Kumar.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*    http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***/
package org.jreversepro.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.WindowConstants;

import org.apache.commons.io.IOUtils;
import org.jreversepro.JReverseProContext;
import org.jreversepro.JReverseProContext.OutputType;
import org.jreversepro.jls.JLSConstants;
import org.jreversepro.jvm.JVMConstants;
import org.jreversepro.jvm.TypeInferrer;
import org.jreversepro.parser.ClassParserException;
import org.jreversepro.reflect.ClassInfo;
import org.jreversepro.reflect.Field;
import org.jreversepro.reflect.Import;
import org.jreversepro.reflect.Method;

/**
* Entry point for swing-based GUI
*
* @author Karthik Kumar
*/
@SuppressWarnings("serial")
public class GUIMain extends JFrame implements ActionListener,
    GuiConstants {

  /**
   * Application Context shared between command line and GUI.
   */
  private final JReverseProContext context;

  /**
   * Represents the MenuBar.
   */
  private final MainMenu mMbrGen;

  /**
   * Panel containing the Reverse engineered code.
   */
  private final ClassEditPanel pnlEditor;

  /**
   * Panel containing the status bar.
   */
  private final StatusPanel mPnlStatusBar;

  /**
   * Path to class currently reverse engineered.
   */
  private final String mCurrentClass = null;

  /**
   * JClassInfo class currently reverse engineered.
   */
  private ClassInfo mClassInfo;

  /**
   * Name of the property file.
   */
  private final String mPropertyFile;

  /**
   * Default Directory of a file open/save dialog.
   */
  private String mCurDir;

  private static final String CURRENT_DIRECTORY = ".";

  /**
   * No-argument constructor.
   */
  public GUIMain(JReverseProContext _context) {
    super(TITLE);

    mPropertyFile = System.getProperty("user.home")
        + System.getProperty("file.separator") + PROP_FILE;

    pnlEditor = new ClassEditPanel();
    mPnlStatusBar = new StatusPanel();

    pnlEditor.setPreferredSize(new Dimension(500, 200));
    mPnlStatusBar.setPreferredSize(new Dimension(500, 20));

    getContentPane().setLayout(new BorderLayout());
    getContentPane().add(pnlEditor, BorderLayout.CENTER);
    getContentPane().add(mPnlStatusBar, BorderLayout.SOUTH);

    mMbrGen = new MainMenu(this);
    setJMenuBar(mMbrGen);

    mCurDir = CURRENT_DIRECTORY;

    mMbrGen.onViewCPool.setEnabled(false);

    context = _context;
    initAppState();
    addListeners();
  }

  /**
   * Method containing handlers for events generated by MenuItems.
   *
   * @param aEvent
   *          Event generated by GUI.
   */
  public void actionPerformed(ActionEvent aEvent) {
    if (aEvent.getSource() == mMbrGen.onFileOpen) {
      openFile();
    } else if (aEvent.getSource() == mMbrGen.onFileSave) {
      saveFile();
    } else if (aEvent.getSource() == mMbrGen.onFileExit) {
      appClose();
    } else if (aEvent.getSource() == mMbrGen.onViewCPool) {
      viewPool();
    } else if (aEvent.getSource() == mMbrGen.onOptFont) {
      showFontDialog();
    } else if (aEvent.getSource() == mMbrGen.onHelpAbout) {
      showAbout();
    } else if (aEvent.getSource() == mMbrGen.onEditCut) {
      cutText();
    } else if (aEvent.getSource() == mMbrGen.onEditCopy) {
      copyText();
    }
  }

  /**
   * Method to open a file.
   */
  public synchronized void openFile() {
    CustomFileChooser chooser = new CustomFileChooser(mCurDir, "Class Files",
        ".class", "Open File");
    if (chooser.showChooser(this, "Decompile File") == JFileChooser.APPROVE_OPTION) {
      File f = chooser.getSelectedFile();
      mCurDir = f.getAbsolutePath();
      try {
        reverseEngineer(f);
        formatTitle(f.getAbsolutePath());
      } catch (Exception _ex) {
        (new DlgError(this, f.toString(), _ex)).setVisible(true);
      }
    }
  }

  /**
   * Method to reverse engineer a file.
   *
   * @param aFile
   *          Class file to be reverse engineered.
   * @throws ClassParserException
   *           Thrown if class file not in proper format.
   * @throws IOException
   *           Thrown if error occured in reading class file.
   * @throws RevEngineException
   *           Thrown if error occured in reverse engineering file.
   */
  private synchronized void reverseEngineer(File aFile)
      throws ClassParserException, IOException {
    mClassInfo = context.loadResource(aFile.getAbsolutePath());

    // Extract code.
    // TODO: Select Disassembler / Decompiler based on a variable.
    String code = context.print(OutputType.DECOMPILER, mClassInfo);

    // Output the code
    pnlEditor.writeCode(code);
    mMbrGen.onViewCPool.setEnabled(true);
    createTree(mClassInfo, mCurrentClass);
  }

  /**
   * Method invoked while saving to a file.
   */
  public void saveFile() {
    CustomFileChooser chooser = new CustomFileChooser(mCurDir,
        "Java Source Files", ".java", "Save File");
    if (chooser.showChooser(this, "Save File") == JFileChooser.APPROVE_OPTION) {
      try {
        pnlEditor.writeToFile(this, chooser.getSelectedFile());
      } catch (Exception ex) {
        // TODO: Do something about this exception
      }
    }
  }

  /**
   * Method invoked while closing a file.
   */
  public void appClose() {
    if (ConfirmCloseDialog.confirmExit(this)) {
      saveProperties();
    }
  }

  /**
   * Method invoked while text is cut.
   */
  public void cutText() {
    // System.out.println("Text Cut");
  }

  /**
   * Method invoked while text is copied.
   */
  public void copyText() {
    // System.out.println("Text Copied");
  }

  /**
   * Method invoked while ConstantPool is viewed.
   */
  public void viewPool() {
    DlgConstantPool dlgPool = new DlgConstantPool(this, mCurrentClass,
        mClassInfo.getConstantPool());
    dlgPool.setVisible(true);
    dlgPool = null;
  }

  /**
   * Method invoked while System Font is being viewed.
   */
  public void showFontDialog() {
    DlgFont dlg = new DlgFont(this, "System Fonts");
    if (dlg.showFontDialog() == DlgFont.SELECTED) {
      pnlEditor.setEditorFont(dlg.getChosenFont());
    }
  }

  /**
   * Method invoked to show the About dialog box.
   */
  public void showAbout() {
    new DlgAbout(this, "About");
  }

  /**
   * Method invoked to initialize the GUI parameters.
   */
  private void initAppState() {
    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    FileInputStream fis = null;
    try {
      Properties pp = new Properties();
      fis = new FileInputStream(mPropertyFile);
      pp.load(fis);

      int x = Integer.parseInt(pp.getProperty(XPOS));
      int y = Integer.parseInt(pp.getProperty(YPOS));
      int width = Integer.parseInt(pp.getProperty(XSIZE));
      int height = Integer.parseInt(pp.getProperty(YSIZE));

      mMbrGen.setFlag(pp.getProperty(DECOMPILE_FLAG));
      pnlEditor.setEditorFont(new Font(pp.getProperty(FONT), Font.PLAIN,
          DlgFont.OPTIMUM_SIZE));

      setLocation(x, y);
      setSize(width, height);

    } catch (FileNotFoundException fnfe) {
      setLocation(0, 0);
      setSize(800, 550);
      pnlEditor.setEditorFont(new Font(ClassEditPanel.DEFAULT_FONT, Font.PLAIN,
          DlgFont.OPTIMUM_SIZE));
      System.err.println("Failed to load property file");
    } catch (IOException ioe) {
      System.err.println("Exception while closing a property file ");
    } finally {
      IOUtils.closeQuietly(fis);
    }
  }

  /**
   * Method to add property listeners to MenuItems and the MainFrame.
   */
  private void addListeners() {
    mMbrGen.onFileOpen.addActionListener(this);
    mMbrGen.onFileSave.addActionListener(this);
    mMbrGen.onFileExit.addActionListener(this);

    mMbrGen.onEditCut.addActionListener(this);
    mMbrGen.onEditCopy.addActionListener(this);
    mMbrGen.onViewCPool.addActionListener(this);
    mMbrGen.onOptFont.addActionListener(this);

    mMbrGen.onHelpAbout.addActionListener(this);
    addWindowListener(new WindowAdapter() {
      /**
       * WindowClosing event handler.
       *
       * @param aEvent
       *          Event generated.
       */
      @Override
      public void windowClosing(WindowEvent aEvent) {
        appClose();
        super.windowClosing(aEvent);
      }
    });
  }

  /**
   * Formats the title from the string Rhs and sets the title of the Frame.
   *
   * @param aFileName
   *          Full Path name to the class being reverse engineered.
   *
   */
  private void formatTitle(String aFileName) {
    int dotIndex = aFileName.indexOf(".");
    if (dotIndex != -1) {
      String className = aFileName.substring(0, dotIndex);
      setTitle(TITLE + " - " + className);
    }
  }

  /**
   * Save the state of the GUI as a properties file.
   *
   */
  private void saveProperties() {
    FileOutputStream fos = null;
    try {
      Properties pp = new Properties();
      pp.setProperty(DECOMPILE_FLAG, Boolean.valueOf(
          mMbrGen.onDecompiler.isSelected()).toString());
      pp.setProperty(XPOS, Integer.valueOf(getLocation().x).toString());
      pp.setProperty(YPOS, Integer.valueOf(getLocation().y).toString());
      pp.setProperty(XSIZE, Integer.valueOf(getSize().width).toString());
      pp.setProperty(YSIZE, Integer.valueOf(getSize().height).toString());
      pp.setProperty(FONT, pnlEditor.getEditorFont().getFamily());

      fos = new FileOutputStream(mPropertyFile);
      pp.store(fos, PROP_HEADING);
    } catch (Exception _ex) {
      System.err.println("Failed to write Properties" + mPropertyFile);
      System.err.println(_ex);
    } finally {
      IOUtils.closeQuietly(fos);
    }
  }


  /**
   * Creates the JTree of the LHS Panel ssociated with the class.
   *
   * @param aClassInfo
   *          Information about the class.
   * @param aCurrentClass
   *          Name of the current class being reverse engineered.
   *
   */
  private void createTree(ClassInfo aClassInfo, String aCurrentClass) {
    Import mImports = aClassInfo.getConstantPool().getImportedClasses();
    int dotIndex = aCurrentClass.indexOf(".");
    if (dotIndex != -1) {
      aCurrentClass = aCurrentClass.substring(0, dotIndex);
    }

    List<Field> listFields = aClassInfo.getFields();
    List<Method> listMethods = aClassInfo.getMethods();
    List<String> result = new ArrayList<String>();

    for (Field field : listFields) {
      StringBuilder sb = new StringBuilder("");
      String datatype = Import.getClassName(TypeInferrer.getJLSType(field
          .getDatatype(), false));

      sb.append(field.getQualifier());
      sb.append(" " + datatype);
      sb.append(" " + field.getName());
      result.add(sb.toString());
    }

    for (Method method : listMethods) {
      StringBuilder sb = new StringBuilder("");

      String returnType = Import.getClassName(TypeInferrer.getJLSType(method
          .getReturnType(), false));

      String name = method.getName();

      if (name.compareTo(JVMConstants.CLINIT) == 0) {
        sb.append(JLSConstants.STATIC);
      } else if (name.compareTo(JVMConstants.INIT) == 0) {
        sb.append(method.getQualifier());
        sb.append(aCurrentClass);
        sb.append(writeArgs(method.getArgList(), mImports));
      } else {
        sb.append(method.getQualifier());
        sb.append(returnType);
        sb.append(" " + name);
        sb.append(writeArgs(method.getArgList(), mImports));
      }
      result.add(sb.toString());
    }
    pnlEditor.createModel(this, aCurrentClass, result);
  }

  /**
   * Returns the argument in Java language Class Format.
   *
   * @param aArgs
   *          List of arguments of class names in JVM class format.
   * @param aImports
   *          List of imported classes.
   * @return A Concatenated list of classes separated by a comma.
   */
  private StringBuilder writeArgs(List<String> aArgs, Import aImports) {
    StringBuilder result = new StringBuilder("(");
    boolean first = true;
    for (String str : aArgs) {
      if (first) {
        first = false;
      } else {
        result.append(" ,");
      }
      String argType = Import.getClassName(TypeInferrer.getJLSType(str, false));
      result.append(argType);
    }
    result.append(")");
    return result;
  }

}
TOP

Related Classes of org.jreversepro.gui.GUIMain

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.