content: /**
   * 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 java.util.logging.Logger;
  
  import org.jreversepro.CustomLoggerFactory;
  import org.jreversepro.jvm.JVMConstants;
  import org.jreversepro.jvm.TypeInferrer;
  import org.jreversepro.reflect.ConstantPool;
  import org.jreversepro.reflect.LocalVariableTable;
  import org.jreversepro.reflect.Method;
  
  
  /**
   * <b>Attribute</b> has the ability to read the 'ATTRIBUTES' of the Field ,
   * Method and the Class as a whole.
   * 
   * @author Karthik Kumar
   * @version 1.00,
   */
  public final class AttributeParser {
  
    private static final Logger logger = CustomLoggerFactory.createLogger();
  
    /**
     * Manipulates the 'ConstantValue' attribute of the Fields.
     * <p>
     * <b>ConstantValue</b> attribute <br>
     * u2 attribute_name_index; <br>
     * u4 attribute_length;<br>
     * u2 constantvalue_index;<br>
     * </p>
     * 
     * @param aDis
     *          DataInputStream containing the bytes of the class.
     * @param aCpInfo
     *          ConstantPool Information.
     * @return a String containing the Constant value, of the field.
     * @throws IOException
     *           Error in Class Stream of bytes.
     */
    public static String readConstantValue(DataInputStream aDis,
        ConstantPool aCpInfo) throws IOException {
  
      int len = aDis.readInt();
      short index = aDis.readShort();
      return (aCpInfo.getBasicDataTypeValue(index));
    }
  
    /**
     * Manipulates the 'Deprecated' attribute of the Fields.
     * <p>
     * <b>Deprecated</b> attribute <br>
     * u2 attribute_name_index; <br>
     * u4 attribute_length;<br>
     * </p>
     * 
     * @param aDis
     *          DataInputStream containing the bytes of the class.
     * @throws IOException
     *           Error in Class Stream of bytes.
     */
    public static void readDeprecated(DataInputStream aDis) throws IOException {
      int len = aDis.readInt();// len must be zero.
    }
  
    /**
     * Manipulates the 'Synthetic' attribute of the Fields.
     * <p>
     * <b>Synthetic</b> attribute <br>
     * u2 attribute_name_index; <br>
     * u4 attribute_length;<br>
     * </p>
     * 
     * @param aDis
     *          DataInputStream containing the bytes of the class.
     * @throws IOException
     *           Error in Class Stream of bytes.
     */
    public static void readSynthetic(DataInputStream aDis) throws IOException {
      int len = aDis.readInt();// len must be zero.
    }
  
    /**
     * Manipulates the 'Code' attribute of the Methods.
     * <p>
     * <b>Code</b> attribute <br>
     * u2 attribute_name_index;<br>
     * u4 attribute_length;<br>
     * u2 max_stack; <br>
     * u2 max_locals; <br>
     * u4 code_length; <br>
     * u1 code[code_length];<br>
     * u2 exception_table_length;<br>
     * <br>
     * u2 start_pc; u2 end_pc; u2 handler_pc; u2 catch_type;<br>
     * exception_table[exception_table_length]; <br>
     * u2 attributes_count;<br>
     * attribute_info attributes[attributes_count]; <br>
     * </p>
     * 
     * @param aDis
     *          DataInputStream containing the bytes of the class.
     * @param aCpInfo
     *          ConstantPool Information.
     * @param aLocalMethod
     *          Reference to the current method for which the code is to be
     *          manipulated.
     * @throws IOException
     *           Error in Class Stream of bytes.
     */
    public static void readCode(Method aLocalMethod, DataInputStream aDis,
        ConstantPool aCpInfo) throws IOException {
  
      /*
       * This refers to the Code attribute length. All the attributes start with
       * the index which has a CONSTANT_Utf8 (2 bytes) and then 4 bytes denoting
       * length of the attribute [here Code]. Here we just read it to move the
       * aDis pointer to read and pass the 4 bytes length.
       */
      int len = aDis.readInt();
  
      short maxStack = aDis.readShort();
      aLocalMethod.setMaxStack(maxStack);
  
      short maxLocals = aDis.readShort();
      aLocalMethod.setMaxLocals(maxLocals);
  
      int codeLen = aDis.readInt();
  
      byte[] btArray = new byte[codeLen];
      aDis.readFully(btArray);
      aLocalMethod.setBytes(btArray);
  
      // exception_table_length
      short excLen = aDis.readShort();
  
      /**
       * startPc - Offset of start of try/catch range. endPc - Offset of end of
       * try/catch range. handlerPc - Offset of start of exception handler code.
       * catchType - Type of exception handled.
       */
      for (int i = 0; i < excLen; i++) {
        short startPc = aDis.readShort();
        short endPc = aDis.readShort();
        short handlerPc = aDis.readShort();
        short catchType = aDis.readShort();
  
        // If type of class caught is any, then CatchType is 0.
        aLocalMethod.addExceptionBlock(startPc, endPc, handlerPc, aCpInfo
            .getClassName(catchType));
      }
  
      short attrCount = aDis.readShort();
  
      for (int i = 0; i < attrCount; i++) {
        readCodeAttributes(aDis, aCpInfo, aLocalMethod);
      }
    }
  
    /**
     * Manipulates the 'SourceFile' attribute of the Fields.
     * <p>
     * <b> SourceFile </b> attribute <br>
     * u2 attribute_name_index; <br>
     * u4 attribute_length;<br>
     * u2 sourcefile_index;
     * </p>
     * 
     * @param aDis
     *          DataInputStream containing the bytes of the class.
     * @param aCpInfo
     *          ConstantPool Information.
     * @return NO_STRING
     * @throws IOException
     *           Error in Class Stream of bytes.
     */
    public static String readSourceFile(DataInputStream aDis, ConstantPool aCpInfo)
        throws IOException {
  
      aDis.readInt();
      short srcIndex = aDis.readShort();
      String srcName = aCpInfo.getUtf8String(srcIndex);
      return srcName;
    }
  
    /**
     * Manipulates the Exceptions attribute.
     * <p>
     * <b> Exceptions_attribute </b> <br>
     * u2 attribute_name_index;<br>
     * u4 attribute_length;<br>
     * u2 number_of_exceptions;<br>
     * u2 exception_index_table[number_of_exceptions]; <br>
     * 
     * Present , if there is a throws clause in the declaration of the method.<br>
     * </p>
     * 
     * @param aDis
     *          DataInputStream containing the bytes of the class.
     * @param aCpInfo
     *          ConstantPool Information.
     * 
     * @return Set of classes present in the 'throws' clause statement.
     * @throws IOException
     *           Error in Class Stream of bytes.
     */
    public static List<String> readExceptions(DataInputStream aDis,
        ConstantPool aCpInfo) throws IOException {
      // Responsible for the 'throws' clause
      List<String> classes = new ArrayList<String>(2);
      aDis.readInt();
      short numException = aDis.readShort();
      for (int i = 0; i < numException; i++) {
        short classIndex = aDis.readShort();
        classes.add(aCpInfo.getClassName(classIndex));
      }
      return classes;
    }
  
    public static void readInnerClasses(DataInputStream dis) {
      // TODO Auto-generated method stub
      
    }
  
    /**
     * Reads the possible attributes of Code.
     * <p>
     * Possible attributes of Code are <b> LineNumberTable </b> and <b>
     * LocalVariableTable </b>
     * </p>
     * 
     * @param aDis
     *          DataInputStream containing the bytes of the class.
     * @param aCpInfo
     *          ConstantPool Information.
     * @throws IOException
     *           Error in Class Stream of bytes.
     */
    private static void readCodeAttributes(DataInputStream aDis,
        ConstantPool aCpInfo, Method method) throws IOException {
  
      short attrNameIndex = aDis.readShort();
      String attrName = aCpInfo.getUtf8String(attrNameIndex);
  
      if (attrName.equals(JVMConstants.ATTRIBUTE_LINENUMBERTABLE)) {
        readLineNumberTable(aDis);
      } else if (attrName.equals(JVMConstants.ATTRIBUTE_LOCALVARIABLETABLE)) {
        readLocalVariableTable(aDis, aCpInfo, method);
      }
    }
  
    /**
     * Manipulates the LineNumberTable attribute.
     * <p>
     * <b> LineNumberTable_attribute </b> <br>
     * u2 attribute_name_index; <br>
     * u4 attribute_length; <br>
     * u2 line_number_table_length; { <br>
     * u2 start_pc; <br>
     * u2 line_number;<br>
     * line_number_table[line_number_table_length]; <br>
     * </p>
     * 
     * @param aDis
     *          DataInputStream containing the bytes of the class.
     * @throws IOException
     *           Error in Class Stream of bytes.
     */
    private static void readLineNumberTable(DataInputStream aDis)
        throws IOException {
      int len = aDis.readInt();
      byte[] btRead = new byte[len];
      // TODO - New: Do some manipulation with the LineNumberTable
      // attribute..
      aDis.readFully(btRead);
    }
  
    /**
     * Manipulates the LocalVariableTable attribute.
     * <p>
     * LocalVariableTable_attribute { u2 attribute_name_index; u4
     * attribute_length; u2 local_variable_table_length; { u2 start_pc; u2 length;
     * u2 name_index; u2 descriptor_index; u2 index; }
     * local_variable_table[local_variable_table_length]; }
     * 
     * @param aDis
     *          DataInputStream containing the bytes of the class.
     * @throws IOException
     *           Error in Class Stream of bytes.
     * 
     */
    private static void readLocalVariableTable(DataInputStream aDis,
        ConstantPool constPool, Method method) throws IOException {
      int len = aDis.readInt();
  
      LocalVariableTable localVarTable = new LocalVariableTable(method.isStatic());
  
      short localVarArrLen = aDis.readShort();
      for (int ctr = 1; ctr <= localVarArrLen; ctr++) {
        short startPc = aDis.readShort();
        short length = aDis.readShort();
        short nameIndex = aDis.readShort();
        short descIndex = aDis.readShort();
        short frameIndex = aDis.readShort();
  
        localVarTable.addLocalVariable(startPc, length, nameIndex, descIndex,
            constPool.getEntryValue(nameIndex), constPool
                .getEntryValue(descIndex), frameIndex);
  
        String jvmType = constPool.getEntryValue(descIndex);
        if (TypeInferrer.doesTypeOccupy2EntriesInVariableTable(jvmType)) {
          // Add another entry.
          localVarTable.addLocalVariable(startPc, length, nameIndex, descIndex,
              constPool.getEntryValue(nameIndex), constPool
                  .getEntryValue(descIndex), (short) (frameIndex + 1));
  
        }
  
      }
  
      method.setVariableTable(localVarTable);
  
    }
  
  
  }
  