Package org.jreversepro.output

Source Code of org.jreversepro.output.AbstractClassOutputterImpl

/**
* 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.output;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import org.jreversepro.CustomLoggerFactory;
import org.jreversepro.jls.JLSConstants;
import org.jreversepro.jvm.JVMConstants;
import org.jreversepro.jvm.TypeInferrer;
import org.jreversepro.reflect.ClassInfo;
import org.jreversepro.reflect.Field;
import org.jreversepro.reflect.Import;
import org.jreversepro.reflect.Method;
import org.jreversepro.reflect.variabletable.VariableTable;


abstract class AbstractClassOutputterImpl implements JVMConstants {

  protected AbstractClassOutputterImpl(ClassInfo _clazz, CodeStyler _styler) {
    clazz = _clazz;
    sb = new StringBuilder();
    styler = _styler;

  }

  public void clearContents() {
    sb = null;
    sb = new StringBuilder();
  }

  public String getContents() {
    return sb.toString();
  }

  public abstract void process();

  /**
   *  Writes the header comments
   */
  protected void outputHeaderComments() {
    sb.append("\n// Source: " + clazz.getSourceFile());
  }

  /**
   *  Writes the package Imports
   */
  protected void outputPackageImports() {
    String packageName = Import.getPackageName(clazz.getThisClass());

    if (packageName.length() != 0) {
      sb.append("\n" + JLSConstants.PACKAGE + " " + packageName
          + JLSConstants.END_OF_STATEMENT);
    }

    sb.append("\n\n");
    Import imports = clazz.getConstantPool().getImportedClasses();
    this.outputImports(imports, packageName);
  }

  /**
   *  Outputs current and super classes
   */
  protected void outputThisSuperClasses() {
    sb.append("\n\n" + getTypeAsString() + " ");

    sb.append(Import.getClassName(clazz.getThisClass()));
    String superClass = clazz.getSuperClass();

    if (!superClass.equals(JVMConstants.CLASS_LANG_OBJECT)) {
      sb.append(" " + JLSConstants.EXTENDS + " ");
      sb.append(Import.getClassName(superClass) + "   ");
    }
  }

  /**
   *  outputs the interfaces implemented by this class.
   */
  protected void outputInterfaces() {
    List<String> interfaces = clazz.getInterfaces();
    if (interfaces.size() != 0) {
      sb.append("\n\t\t " + JLSConstants.IMPLEMENTS + " ");
      for (int i = 0; i < interfaces.size(); i++) {
        if (i != 0) {
          sb.append(JLSConstants.INTERFACE_DELIMITER);
        }
        sb.append(Import.getClassName(interfaces.get(i)));
      }
    }
  }

  /**
   *  output the Fields of the given class
   */
  protected void outputFields() {
    sb.append("\n");
    for (Field field : clazz.getFields()) {
      String datatype = Import.getClassName(TypeInferrer.getJLSType(field
          .getDatatype(), false));

      String access = this.getAccessQualifier(field.getQualifier(), true);

      sb.append("\n\t" + access);
      sb.append(datatype);
      sb.append(" " + field.getName());
      String val = field.getValue();
      if (field.isFinal() && val.length() != 0) {
        sb.append(JLSConstants.EQUALTO + val);
      }
      sb.append(JLSConstants.END_OF_STATEMENT);
    }
  }

  /**
   * Returns the access string of this class.
   *
   * @return Returns the access string of this class.
   */
  private String getTypeAsString() {
    StringBuilder accString = new StringBuilder();
    accString.append(getAccessQualifier(clazz.getAccess(), false));

    if (clazz.isClass()) {
      accString.append(JLSConstants.CLASS);
    } else {
      accString.append(JLSConstants.INTERFACE);
    }
    return accString.toString();
  }

  /**
   * Returns a string that contains all the imported classes in the proper
   * format as written in code. For eg, if the list contains p1.class1 ,
   * p2.class2 , this generates a string with import statements for both of
   * them. classes belonging to the default package are excluded. Also there is
   * an option by which we can exclude the classes that belong to a given
   * package ( current package ).
   *
   * @param packageName
   *          current packagename and name for which package name is to be
   *          excluded.
   * String containing the code mentioned.
   */
  private void outputImports(Import imports, String packageName) {
    List<String> restrictPackages = new ArrayList<String>(2);
    restrictPackages.add(packageName);
    restrictPackages.add(JLSConstants.DEFAULT_PACKAGE);

    logger.fine("Number of imports" + imports.getClasses().size());
    for (String currentClass : imports.getClasses()) {
      if (currentClass.indexOf(JVMConstants.JVM_PACKAGE_DELIMITER) != -1) {
        String currentPackage = Import.getPackageName(currentClass);
        if (!restrictPackages.contains(currentPackage)) {
          currentClass = currentClass.replace(
              JVMConstants.JVM_PACKAGE_DELIMITER,
              JLSConstants.JLS_PACKAGE_DELIMITER);
          sb.append(JLSConstants.IMPORT + " ");
          sb.append(currentClass + JLSConstants.END_OF_STATEMENT + "\n");
        }
      }
    }
  }

  /**
   * Returns the String Representation of the qualifier. Certain qualifiers like
   * volatile, transient, sync. are applicable only for methods and fields. and
   * not classes. To identify them separately, we also pass another parameter
   * called memberOnly. Only if this is set then those bits are checked for.
   * Else they are ignored, since for a class/interface they may not be
   * applicable.
   *
   * @param rhsQualifier
   *          Qualifier byte with the bits set.
   * @param memberOnly
   *          Only if this is set then the bits relevant to fields and methods
   *          only are checked for. Else ignored.
   * @return String Containing the representation.
   */
  private String getAccessQualifier(int rhsQualifier, boolean memberOnly) {

    StringBuilder access = new StringBuilder("");
    if ((rhsQualifier & ACC_PUBLIC) != 0) {
      access.append(JLSConstants.ACCESS_PUBLIC);
      access.append(" ");
    } else if ((rhsQualifier & ACC_PRIVATE) != 0) {
      access.append(JLSConstants.ACCESS_PRIVATE);
      access.append(" ");
    } else if ((rhsQualifier & ACC_PROTECTED) != 0) {
      access.append(JLSConstants.ACCESS_PROTECTED);
      access.append(" ");
    }

    if ((rhsQualifier & ACC_STATIC) != 0) {
      access.append(JLSConstants.ACCESS_STATIC);
      access.append(" ");
    }
    if ((rhsQualifier & ACC_FINAL) != 0) {
      access.append(JLSConstants.ACCESS_FINAL);
      access.append(" ");
    }
    if ((rhsQualifier & ACC_ABSTRACT) != 0) {
      access.append(JLSConstants.ACCESS_ABSTRACT);
      access.append(" ");
    }

    if (memberOnly) {

      // Fields only
      if ((rhsQualifier & ACC_VOLATILE) != 0) {
        access.append(JLSConstants.ACCESS_VOLATILE);
        access.append(" ");
      }
      if ((rhsQualifier & ACC_TRANSIENT) != 0) {
        access.append(JLSConstants.ACCESS_TRANSIENT);
        access.append(" ");
      }

      // Methods only
      if ((rhsQualifier & ACC_SYNCHRONIZED) != 0) {
        access.append(JLSConstants.ACCESS_SYNCHRONIZED);
        access.append(" ");
      }
      if ((rhsQualifier & ACC_NATIVE) != 0) {
        access.append(JLSConstants.ACCESS_NATIVE);
        access.append(" ");
      }
      if ((rhsQualifier & ACC_STRICT) != 0) {
        access.append(JLSConstants.ACCESS_STRICTFP);
        access.append(" ");
      }
    }
    return access.toString();
  }

  /**
   * Returns the headers for the method.
   *
   * @param method
   *          Method information for which method header needs to be outputted.
   * Returns the method header information.
   */
  protected void outputMethodHeader(Method method) {

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

    String name = method.getName();
    sb.append("\n\n    ");

    if (name.compareTo(CLINIT) == 0) {
      sb.append(JLSConstants.STATIC);
    } else if (name.compareTo(INIT) == 0) {
      sb.append(getAccessQualifier(method.getQualifier(), true));
      sb.append(extractClassOnly(clazz.getThisClass()));
    } else {
      sb.append(getAccessQualifier(method.getQualifier(), true));
      sb.append(returnType);
      sb.append(" " + method.getName());
    }

    List<String> args = method.getArgList();

    if (method.getName().compareTo(CLINIT) != 0) {
      sb.append("(");
      int baseVariableIndex = method.isStatic() ? 0 : 1;
      for (int i = 0; i < args.size(); i++) {
        if (i != 0) {
          sb.append(" ,");
        }
        String jvmArgType = args.get(i);
        String argType = Import.getClassName(TypeInferrer.getJLSType(
            jvmArgType, false));

        sb.append(argType);
        // TODO Later move this code to MethodEmitter
        sb.append(" ");
        // 0 is ok here - since the method arguments are
        // going to be in the full scope of the method.
        sb.append(method.getVariableTable().getName(baseVariableIndex++,
            VariableTable.FULL_SCOPE_INSTRUCTION_INDEX));

        if (TypeInferrer.doesTypeOccupy2EntriesInVariableTable(jvmArgType)) {
          baseVariableIndex++; // Ignore this.
        }

      }
      sb.append(")");
    }
    outputThrowsClause(method.getThrowsClasses(), clazz.getConstantPool()
        .getImportedClasses());
  }

  /**
   *
   * returns a throws clause for the method
   *
   * @param importInfo
   *          containing the import information.
   * @return Returns a string that contains the code representation.
   */
  private void outputThrowsClause(List<String> throwsClasses, Import importInfo) {
    int size = throwsClasses.size();
    if (size != 0) {
      sb.append("\n\t\t" + JLSConstants.THROWS + " ");
      for (int i = 0; i < size; i++) {
        String thrownClass = throwsClasses.get(i);
        if (i > 0) {
          sb.append(" ,");
        }
        sb.append(Import.getClassName(thrownClass));
      }
    }
  }

  private static String extractClassOnly(String jvmType) {
    int lastIndex = jvmType.lastIndexOf(JVMConstants.JVM_PACKAGE_DELIMITER);
    if (lastIndex != -1) {
      return jvmType.substring(lastIndex + 1);
    } else {
      return jvmType;
    }

  }

  protected void openBlock() {
    sb.append(styler.openBlock());
  }

  protected void closeBlock() {
    sb.append(styler.closeBlock());
  }

  protected void outputString(String str) {
    sb.append(str);
  }

  protected ClassInfo clazz;

  private final Logger logger = CustomLoggerFactory.createLogger();

  private StringBuilder sb;

  protected CodeStyler styler;
}
TOP

Related Classes of org.jreversepro.output.AbstractClassOutputterImpl

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.