content: /*
   *  This file is part of AndroidIDE.
   *
   *  AndroidIDE is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  AndroidIDE is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *   along with AndroidIDE.  If not, see <https://www.gnu.org/licenses/>.
   */
  
  /*
   * reserved comment block
   * DO NOT REMOVE OR ALTER!
   */
  package jaxp.sun.org.apache.bcel.internal.classfile;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache BCEL" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache BCEL", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import jaxp.sun.org.apache.bcel.internal.Constants;
  
  import java.io.*;
  import java.util.HashMap;
  
  /**
   * Abstract super class for <em>Attribute</em> objects. Currently the
   * <em>ConstantValue</em>, <em>SourceFile</em>, <em>Code</em>,
   * <em>Exceptiontable</em>, <em>LineNumberTable</em>,
   * <em>LocalVariableTable</em>, <em>InnerClasses</em> and
   * <em>Synthetic</em> attributes are supported. The
   * <em>Unknown</em> attribute stands for non-standard-attributes.
   *
   * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
   * @see     ConstantValue
   * @see     SourceFile
   * @see     Code
   * @see     Unknown
   * @see     ExceptionTable
   * @see     LineNumberTable
   * @see     LocalVariableTable
   * @see     InnerClasses
   * @see     Synthetic
   * @see     Deprecated
   * @see     Signature
  */
  public abstract class Attribute implements Cloneable, Node, Serializable {
    protected int          name_index; // Points to attribute name in constant pool
    protected int          length;     // Content length of attribute field
    protected byte         tag;        // Tag to distiguish subclasses
    protected ConstantPool constant_pool;
  
    protected Attribute(byte tag, int name_index, int length,
                        ConstantPool constant_pool) {
      this.tag           = tag;
      this.name_index    = name_index;
      this.length        = length;
      this.constant_pool = constant_pool;
    }
  
    /**
     * Called by objects that are traversing the nodes of the tree implicitely
     * defined by the contents of a Java class. I.e., the hierarchy of methods,
     * fields, attributes, etc. spawns a tree of objects.
     *
     * @param v Visitor object
     */
    public abstract void accept(Visitor v);
  
    /**
     * Dump attribute to file stream in binary format.
     *
     * @param file Output file stream
     * @throws IOException
     */
    public void dump(DataOutputStream file) throws IOException
    {
      file.writeShort(name_index);
      file.writeInt(length);
    }
  
    private static HashMap readers = new HashMap();
  
    /** Add an Attribute reader capable of parsing (user-defined) attributes
     * named "name". You should not add readers for the standard attributes
     * such as "LineNumberTable", because those are handled internally.
     *
     * @param name the name of the attribute as stored in the class file
     * @param r the reader object
     */
    public static void addAttributeReader(String name, AttributeReader r) {
      readers.put(name, r);
    }
  
    /** Remove attribute reader
     *
     * @param name the name of the attribute as stored in the class file
     */
    public static void removeAttributeReader(String name) {
      readers.remove(name);
    }
  
    /* Class method reads one attribute from the input data stream.
     * This method must not be accessible from the outside.  It is
     * called by the Field and Method constructor methods.
     *
     * @see    Field
     * @see    Method
     * @param  file Input stream
     * @param  constant_pool Array of constants
     * @return Attribute
     * @throws  IOException
     * @throws  ClassFormatException
     */
    public static final Attribute readAttribute(DataInputStream file,
                                                ConstantPool constant_pool)
      throws IOException, ClassFormatException
    {
      ConstantUtf8 c;
      String       name;
      int          name_index;
      int          length;
      byte         tag = Constants.ATTR_UNKNOWN; // Unknown attribute
  
      // Get class name from constant pool via `name_index' indirection
      name_index = (int)file.readUnsignedShort();
      c          = (ConstantUtf8)constant_pool.getConstant(name_index,
                                                           Constants.CONSTANT_Utf8);
      name       = c.getBytes();
  
      // Length of data in bytes
      length = file.readInt();
  
      // Compare strings to find known attribute
      for(byte i=0; i < Constants.KNOWN_ATTRIBUTES; i++) {
        if(name.equals(Constants.ATTRIBUTE_NAMES[i])) {
          tag = i; // found!
          break;
        }
      }
  
      // Call proper constructor, depending on `tag'
      switch(tag) {
      case Constants.ATTR_UNKNOWN:
        AttributeReader r = (AttributeReader)readers.get(name);
  
        if(r != null)
          return r.createAttribute(name_index, length, file, constant_pool);
        else
          return new Unknown(name_index, length, file, constant_pool);
  
      case Constants.ATTR_CONSTANT_VALUE:
        return new ConstantValue(name_index, length, file, constant_pool);
  
      case Constants.ATTR_SOURCE_FILE:
        return new SourceFile(name_index, length, file, constant_pool);
  
      case Constants.ATTR_CODE:
        return new Code(name_index, length, file, constant_pool);
  
      case Constants.ATTR_EXCEPTIONS:
        return new ExceptionTable(name_index, length, file, constant_pool);
  
      case Constants.ATTR_LINE_NUMBER_TABLE:
        return new LineNumberTable(name_index, length, file, constant_pool);
  
      case Constants.ATTR_LOCAL_VARIABLE_TABLE:
        return new LocalVariableTable(name_index, length, file, constant_pool);
  
      case Constants.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
        return new LocalVariableTypeTable(name_index, length, file, constant_pool);
  
      case Constants.ATTR_INNER_CLASSES:
        return new InnerClasses(name_index, length, file, constant_pool);
  
      case Constants.ATTR_SYNTHETIC:
        return new Synthetic(name_index, length, file, constant_pool);
  
      case Constants.ATTR_DEPRECATED:
        return new Deprecated(name_index, length, file, constant_pool);
  
      case Constants.ATTR_PMG:
        return new PMGClass(name_index, length, file, constant_pool);
  
      case Constants.ATTR_SIGNATURE:
        return new Signature(name_index, length, file, constant_pool);
  
      case Constants.ATTR_STACK_MAP:
        return new StackMap(name_index, length, file, constant_pool);
  
      default: // Never reached
        throw new IllegalStateException("Ooops! default case reached.");
      }
    }
  
    /**
     * @return Length of attribute field in bytes.
     */
    public final int   getLength()    { return length; }
  
    /**
     * @param Attribute length in bytes.
     */
    public final void setLength(int length) {
      this.length = length;
    }
  
    /**
     * @param name_index of attribute.
     */
    public final void setNameIndex(int name_index) {
      this.name_index = name_index;
    }
  
    /**
     * @return Name index in constant pool of attribute name.
     */
    public final int getNameIndex() { return name_index; }
  
    /**
     * @return Tag of attribute, i.e., its type. Value may not be altered, thus
     * there is no setTag() method.
     */
    public final byte  getTag()       { return tag; }
  
    /**
     * @return Constant pool used by this object.
     * @see ConstantPool
     */
    public final ConstantPool getConstantPool() { return constant_pool; }
  
    /**
     * @param constant_pool Constant pool to be used for this object.
     * @see ConstantPool
     */
    public final void setConstantPool(ConstantPool constant_pool) {
      this.constant_pool = constant_pool;
    }
  
    /**
     * Use copy() if you want to have a deep copy(), i.e., with all references
     * copied correctly.
     *
     * @return shallow copy of this attribute
     */
    public Object clone() {
      Object o = null;
  
      try {
        o = super.clone();
      } catch(CloneNotSupportedException e) {
        e.printStackTrace(); // Never occurs
      }
  
      return o;
    }
  
    /**
     * @return deep copy of this attribute
     */
    public abstract Attribute copy(ConstantPool constant_pool);
  
    /**
     * @return attribute name.
     */
    public String toString() {
      return Constants.ATTRIBUTE_NAMES[tag];
    }
  }
  