Package org.jreversepro.parser.common

Source Code of org.jreversepro.parser.common.AbstractClassFileParser

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

import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.jreversepro.jls.JLSConstants;
import org.jreversepro.jvm.JVMConstants;
import org.jreversepro.parser.ClassParserException;
import org.jreversepro.reflect.ClassInfo;
import org.jreversepro.reflect.ConstantPool;
import org.jreversepro.reflect.Field;
import org.jreversepro.reflect.Method;


/**
* @author Karthik Kumar
*/
public class AbstractClassFileParser {

  /**
   * Reads the ConstantPool.
   *
   * @throws ClassParserException
   *           Thrown if class file not in desired format.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  public static ConstantPool readConstantPool(DataInputStream dis)
      throws IOException, ClassParserException {
    int numCpEntry = dis.readShort();
    ConstantPool cpInfo = new ConstantPool(numCpEntry);
    readCpEntries(dis, cpInfo, numCpEntry);
    return cpInfo;
  }

  /**
   * Reads the access specifier of the class.
   *
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  public static short readAccess(DataInputStream dis) throws IOException {
    return dis.readShort();
  }

  /**
   *
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  public static short readThisClassIndex(DataInputStream dis)
      throws IOException {
    return dis.readShort();
  }

  /**
   *
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  public static short readSuperClassIndex(DataInputStream dis)
      throws IOException {
    return dis.readShort();
  }

  /**
   * Reads the fully qualified name of the interfaces <code>implemented</code>
   * by the Current class.
   *
   *
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  public static List<String> readInterfaces(DataInputStream dis,
      ConstantPool cpInfo) throws IOException {
    short count = dis.readShort();
    List<String> interfaces = new ArrayList<String>();
    for (int i = 0; i < count; i++) {
      String interfaceName = cpInfo.getClassName(dis.readShort());
      interfaces.add(interfaceName);
    }
    return interfaces;
  }

  /**
   * Reads the fields <code>defined</code> in the Current class.
   *
   *
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  public static List<Field> readFields(DataInputStream dis, ConstantPool cpInfo)
      throws IOException {
    short count = dis.readShort();

    List<Field> fields = new ArrayList<Field>();
    for (int i = 0; i < count; i++) {
      Field curField = new Field();

      short accessFlags = dis.readShort();
      short nameIndex = dis.readShort();
      short descIndex = dis.readShort();

      String name = cpInfo.getUtf8String(nameIndex);
      String descriptor = cpInfo.getUtf8String(descIndex);

      curField.setName(name);
      curField.setDatatype(descriptor);
      curField.setQualifier(accessFlags);

      short attrCount = dis.readShort();
      for (int j = 0; j < attrCount; j++) {
        readFieldAttributes(curField, dis, cpInfo);
      }

      fields.add(curField);
    }
    return fields;
  }

  /**
   * Reads the methods <code>defined</code> in the Current class.
   *
   *
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  public static List<Method> readMethods(DataInputStream dis,
      ConstantPool cpInfo) throws IOException {
    short count = dis.readShort();

    List<Method> methods = new ArrayList<Method>();

    for (int i = 0; i < count; i++) {
      Method curMethod = new Method();

      short accessFlags = dis.readShort();
      short nameIndex = dis.readShort();
      short descIndex = dis.readShort();

      String name = cpInfo.getUtf8String(nameIndex);
      String descriptor = cpInfo.getUtf8String(descIndex);

      curMethod.setName(name);
      curMethod.setSignature(descriptor);
      curMethod.setQualifier(accessFlags);

      short attrCount = dis.readShort();
      for (int j = 0; j < attrCount; j++) {
        readMethodAttributes(curMethod, dis, cpInfo);
      }
      if (curMethod.getVariableTable() == null) {
        // It was not decompiled with variableTable- Hence setting it
        // using symboltable
        curMethod.initializeSymbolTable();
      }

      methods.add(curMethod);
    }
    return methods;
  }

  /**
   * Reads the ATTRIBUTES of the fields and methods.
   * <p>
   * The possible attributes here are Code, LineNumberTable, Exception
   * </p>
   * .
   *
   * @see AttributeParser
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  public static void readClassAttributes(DataInputStream dis,
      ConstantPool cpInfo, ClassInfo clazz) throws IOException {
    short attrCount = dis.readShort();

    for (int i = 0; i < attrCount; i++) {
      readClassAttribute(dis, cpInfo, clazz);
    }
  }

  /**
   * Reads the ConstantPool Entries.
   *
   * @param aNumEntry
   *          Number of constant pool entries.
   * @throws ClassParserException
   *           Thrown if class file not in desired format.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readCpEntries(DataInputStream dis, ConstantPool cpInfo,
      int aNumEntry) throws IOException, ClassParserException {
    cpInfo.addNullEntry();

    for (int i = 1; i < aNumEntry; i++) {
      byte tagByte = dis.readByte();

      switch (tagByte) {
      case ConstantPool.TAG_UTF8:
        readTagUtf8(dis, cpInfo, i);
        break;
      case ConstantPool.TAG_INTEGER:
        readTagInteger(dis, cpInfo, i);
        break;
      case ConstantPool.TAG_FLOAT:
        readTagFloat(dis, cpInfo, i);
        break;
      case ConstantPool.TAG_LONG:
        readTagLong(dis, cpInfo, i);
        // Long takes two ConstantPool Entries.
        i++;
        break;
      case ConstantPool.TAG_DOUBLE:
        readTagDouble(dis, cpInfo, i);
        // Double takes two ConstantPool Entries.
        i++;
        break;
      case ConstantPool.TAG_CLASS:
        readTagClass(dis, cpInfo, i);
        break;
      case ConstantPool.TAG_STRING:
        readTagString(dis, cpInfo, i);
        break;
      case ConstantPool.TAG_FIELDREF:
        readTagFieldRef(dis, cpInfo, i);
        break;
      case ConstantPool.TAG_METHODREF:
        readTagMethodRef(dis, cpInfo, i);
        break;
      case ConstantPool.TAG_INTERFACEREF:
        readTagInterfaceRef(dis, cpInfo, i);
        break;
      case ConstantPool.TAG_NAMETYPE:
        readTagNameType(dis, cpInfo, i);
        break;
      default:
        throw new ClassParserException("TagByte " + tagByte
            + " Invalid for ConstantPool Entry #" + i);
      }
    }
  }

  /**
   * Reads an UTF8 entry.
   *
   * @param aIndex
   *          Index of a ConstantPool Entry.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readTagUtf8(DataInputStream dis, ConstantPool cpInfo,
      int aIndex) throws IOException {
    String utfString = dis.readUTF();
    cpInfo.addUtf8Entry(utfString);
  }

  /**
   * Reads an integer entry.
   *
   * @param aIndex
   *          Index of a ConstantPool Entry.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readTagInteger(DataInputStream dis, ConstantPool cpInfo,
      int aIndex) throws IOException {
    int intValue = dis.readInt();

    cpInfo.addIntegerEntry(String.valueOf(intValue));
  }

  /**
   * Reads an float entry.
   *
   * @param aIndex
   *          Index of a ConstantPool Entry.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readTagFloat(DataInputStream dis, ConstantPool cpInfo,
      int aIndex) throws IOException {
    float floatValue = dis.readFloat();

    cpInfo.addFloatEntry(String.valueOf(floatValue)
        + JLSConstants.JLS_FLOATING_NUMBER_SUFFIX);
  }

  /**
   * Reads a long entry.
   *
   * @param aIndex
   *          Index of a ConstantPool Entry.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readTagLong(DataInputStream dis, ConstantPool cpInfo,
      int aIndex) throws IOException {

    long longValue = dis.readLong();

    cpInfo.addLongEntry(String.valueOf(longValue)
        + JLSConstants.JLS_LONG_NUMBER_SUFFIX);
    cpInfo.addNullEntry();
  }

  /**
   * Reads a double entry.
   *
   * @param aIndex
   *          Index of a ConstantPool Entry.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readTagDouble(DataInputStream dis, ConstantPool cpInfo,
      int aIndex) throws IOException {

    double doubleValue = dis.readDouble();

    cpInfo.addDoubleEntry(String.valueOf(doubleValue));
    cpInfo.addNullEntry();
  }

  /**
   * Reads an TAG_CLASS entry.
   * <p>
   * u1 tag; <br>
   * u2 name_index;<br>
   * </p>
   * Reads a class entry.
   *
   * @param aIndex
   *          Index of a ConstantPool Entry.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readTagClass(DataInputStream dis, ConstantPool cpInfo,
      int aIndex) throws IOException {
    int classIndex = dis.readShort();

    cpInfo.addClassEntry(classIndex);
  }

  /**
   * Reads a string entry.
   *
   * @param aIndex
   *          Index of a ConstantPool Entry.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readTagString(DataInputStream dis, ConstantPool cpInfo,
      int aIndex) throws IOException {
    int stringIndex = dis.readShort();
    cpInfo.addStringEntry(stringIndex);
  }

  /**
   * Reads a TAG_FIELDREF entry.
   * <p>
   * u1 tag; <br>
   * u2 class_index; <br>
   * u2 name_and_type_index; <br>
   * </p>
   *
   * @param aIndex
   *          Index of a ConstantPool Entry.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readTagFieldRef(DataInputStream dis, ConstantPool cpInfo,
      int aIndex) throws IOException {
    int classIndex = dis.readShort();
    int nameType = dis.readShort();

    cpInfo.addFieldRefEntry(classIndex, nameType);
  }

  /**
   * Reads a TAG_METHODREF entry.
   * <p>
   * u1 tag; <br>
   * u2 class_index; <br>
   * u2 name_and_type_index; <br>
   * </p>
   *
   * @param aIndex
   *          Index of a ConstantPool Entry.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readTagMethodRef(DataInputStream dis,
      ConstantPool cpInfo, int aIndex) throws IOException {
    int classIndex = dis.readShort();
    int nameType = dis.readShort();

    cpInfo.addMethodRefEntry(classIndex, nameType);
  }

  /**
   * Reads a TAG_INTERFACEREF entry.
   * <p>
   * u1 tag;<br>
   * u2 class_index;<br>
   * u2 name_and_type_index;<br>
   * </p>
   *
   * @param aIndex
   *          Index of a ConstantPool Entry.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readTagInterfaceRef(DataInputStream dis,
      ConstantPool cpInfo, int aIndex) throws IOException {
    int classIndex = dis.readShort();
    int nameType = dis.readShort();

    cpInfo.addInterfaceRefEntry(classIndex, nameType);
  }

  /**
   * Reads a TAG_NAMETYPE entry.
   * <p>
   * u1 tag; <br>
   * u2 name_index;<br>
   * u2 descriptor_index;<br>
   * </p>
   *
   * @param aIndex
   *          Index of a ConstantPool Entry.
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readTagNameType(DataInputStream dis, ConstantPool cpInfo,
      int aIndex) throws IOException {
    int nameIndex = dis.readShort();
    int descIndex = dis.readShort();

    cpInfo.addNameTypeEntry(nameIndex, descIndex);
  }

  /**
   * Reads the ATTRIBUTES of the field defined in the Current class.
   * <p>
   * The possible attributes here are ConstantValue , Deprecated , Synthetic.
   * </p>
   * .
   *
   * @param aRhsField
   *          Reads attributes into this field.
   * @see AttributeParser
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readFieldAttributes(Field aRhsField, DataInputStream dis,
      ConstantPool cpInfo) throws IOException {

    String attrName = cpInfo.getUtf8String(dis.readShort());

    if (attrName.equals(JVMConstants.ATTRIBUTE_CONSTANT_VALUE)) {
      aRhsField.setValue(AttributeParser.readConstantValue(dis, cpInfo));
    } else if (attrName.equals(JVMConstants.ATTRIBUTE_SYNTHETIC)) {
      AttributeParser.readSynthetic(dis);
    } else if (attrName.equals(JVMConstants.ATTRIBUTE_DEPRECATED)) {
      AttributeParser.readDeprecated(dis);
    }
  }

  /**
   * Reads the ATTRIBUTES of the method defined in the Current class.
   * <p>
   * The possible attributes here are Deprecated , Synthetic , <b> Code </b> and
   * Exceptions
   * </p>
   * .
   *
   * @param aRhsMethod
   *          Reads attributes into this method.
   * @see AttributeParser
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readMethodAttributes(Method method, DataInputStream dis,
      ConstantPool cpInfo) throws IOException {
    String attrName = cpInfo.getUtf8String(dis.readShort());

    if (attrName.compareTo(JVMConstants.ATTRIBUTE_CODE) == 0) {
      AttributeParser.readCode(method, dis, cpInfo);
    } else if (attrName.compareTo(JVMConstants.ATTRIBUTE_EXCEPTIONS) == 0) {
      // counterpart to 'throws' clause in the source code.
      method.setThrowsClasses(AttributeParser.readExceptions(dis, cpInfo));
    } else if (attrName.compareTo(JVMConstants.ATTRIBUTE_SYNTHETIC) == 0) {
      AttributeParser.readSynthetic(dis);
    } else if (attrName.compareTo(JVMConstants.ATTRIBUTE_DEPRECATED) == 0) {
      AttributeParser.readDeprecated(dis);
    } else if (attrName.compareTo(JVMConstants.ATTRIBUTE_INNERCLASSES) == 0) {
      // TODO Should discuss with akkumar if he has implemented it
      // already in some other code location.
      AttributeParser.readInnerClasses(dis);
    }
  }

  /**
   * Reads the ATTRIBUTES of the whole class itself.
   * <p>
   * The possible attributes here are Deprecated , SourceFile
   * </p>
   * .
   *
   * @see AttributeParser
   * @throws IOException
   *           Thrown if error in stream of bytes containing the class file.
   */
  private static void readClassAttribute(DataInputStream dis,
      ConstantPool cpInfo, ClassInfo clazz) throws IOException {
    int attrIndex = dis.readShort();
    String attrName = cpInfo.getUtf8String(attrIndex);

    if (attrName.compareTo(JVMConstants.ATTRIBUTE_SOURCEFILE) == 0) {
      clazz.setSourceFile(AttributeParser.readSourceFile(dis, cpInfo));
    } else if (attrName.compareTo(JVMConstants.ATTRIBUTE_DEPRECATED) == 0) {
      AttributeParser.readDeprecated(dis);
    } else {
      // System.out.println("Attribute " + AttrName );
    }
  }

}
TOP

Related Classes of org.jreversepro.parser.common.AbstractClassFileParser

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.