1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 package com.sun.org.apache.bcel.internal.classfile;
  21 
  22 import java.io.DataInput;
  23 import java.io.DataInputStream;
  24 import java.io.DataOutputStream;
  25 import java.io.IOException;
  26 import java.util.HashMap;
  27 import java.util.Map;
  28 
  29 import com.sun.org.apache.bcel.internal.Const;
  30 
  31 /**
  32  * Abstract super class for <em>Attribute</em> objects. Currently the
  33  * <em>ConstantValue</em>, <em>SourceFile</em>, <em>Code</em>,
  34  * <em>Exceptiontable</em>, <em>LineNumberTable</em>,
  35  * <em>LocalVariableTable</em>, <em>InnerClasses</em> and
  36  * <em>Synthetic</em> attributes are supported. The <em>Unknown</em>
  37  * attribute stands for non-standard-attributes.
  38  *
  39  * @version $Id: Attribute.java 1750029 2016-06-23 22:14:38Z sebb $
  40  * @see ConstantValue
  41  * @see SourceFile
  42  * @see Code
  43  * @see Unknown
  44  * @see ExceptionTable
  45  * @see LineNumberTable
  46  * @see LocalVariableTable
  47  * @see InnerClasses
  48  * @see Synthetic
  49  * @see Deprecated
  50  * @see Signature
  51  */
  52 public abstract class Attribute implements Cloneable, Node {
  53 
  54     private int name_index; // Points to attribute name in constant pool
  55     private int length; // Content length of attribute field
  56     private final byte tag; // Tag to distinguish subclasses
  57     private ConstantPool constant_pool;
  58 
  59     protected Attribute(final byte tag, final int name_index, final int length, final ConstantPool constant_pool) {
  60         this.tag = tag;
  61         this.name_index = name_index;
  62         this.length = length;
  63         this.constant_pool = constant_pool;
  64     }
  65 
  66     /**
  67      * Called by objects that are traversing the nodes of the tree implicitely
  68      * defined by the contents of a Java class. I.e., the hierarchy of methods,
  69      * fields, attributes, etc. spawns a tree of objects.
  70      *
  71      * @param v Visitor object
  72      */
  73     @Override
  74     public abstract void accept(Visitor v);
  75 
  76     /**
  77      * Dump attribute to file stream in binary format.
  78      *
  79      * @param file Output file stream
  80      * @throws IOException
  81      */
  82     public void dump(final DataOutputStream file) throws IOException {
  83         file.writeShort(name_index);
  84         file.writeInt(length);
  85     }
  86 
  87     private static final Map<String, Object> readers = new HashMap<>();
  88 
  89     /**
  90      * Add an Attribute reader capable of parsing (user-defined) attributes
  91      * named "name". You should not add readers for the standard attributes such
  92      * as "LineNumberTable", because those are handled internally.
  93      *
  94      * @param name the name of the attribute as stored in the class file
  95      * @param r the reader object
  96      */
  97     public static void addAttributeReader(final String name, final UnknownAttributeReader r) {
  98         readers.put(name, r);
  99     }
 100 
 101     /**
 102      * Remove attribute reader
 103      *
 104      * @param name the name of the attribute as stored in the class file
 105      */
 106     public static void removeAttributeReader(final String name) {
 107         readers.remove(name);
 108     }
 109 
 110     /**
 111      * Class method reads one attribute from the input data stream. This method
 112      * must not be accessible from the outside. It is called by the Field and
 113      * Method constructor methods.
 114      *
 115      * @see Field
 116      * @see Method
 117      *
 118      * @param file Input stream
 119      * @param constant_pool Array of constants
 120      * @return Attribute
 121      * @throws IOException
 122      * @throws ClassFormatException
 123      */
 124     public static Attribute readAttribute(final DataInputStream file, final ConstantPool constant_pool)
 125             throws IOException, ClassFormatException {
 126         return readAttribute((DataInput) file, constant_pool);
 127     }
 128 
 129     /**
 130      * Class method reads one attribute from the input data stream. This method
 131      * must not be accessible from the outside. It is called by the Field and
 132      * Method constructor methods.
 133      *
 134      * @see Field
 135      * @see Method
 136      *
 137      * @param file Input stream
 138      * @param constant_pool Array of constants
 139      * @return Attribute
 140      * @throws IOException
 141      * @throws ClassFormatException
 142      * @since 6.0
 143      */
 144     public static Attribute readAttribute(final DataInput file, final ConstantPool constant_pool)
 145             throws IOException, ClassFormatException {
 146         byte tag = Const.ATTR_UNKNOWN; // Unknown attribute
 147         // Get class name from constant pool via `name_index' indirection
 148         final int name_index = file.readUnsignedShort();
 149         final ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8);
 150         final String name = c.getBytes();
 151 
 152         // Length of data in bytes
 153         final int length = file.readInt();
 154 
 155         // Compare strings to find known attribute
 156         for (byte i = 0; i < Const.KNOWN_ATTRIBUTES; i++) {
 157             if (name.equals(Const.getAttributeName(i))) {
 158                 tag = i; // found!
 159                 break;
 160             }
 161         }
 162 
 163         // Call proper constructor, depending on `tag'
 164         switch (tag) {
 165             case Const.ATTR_UNKNOWN:
 166                 final Object r = readers.get(name);
 167                 if (r instanceof UnknownAttributeReader) {
 168                     return ((UnknownAttributeReader) r).createAttribute(name_index, length, file, constant_pool);
 169                 }
 170                 return new Unknown(name_index, length, file, constant_pool);
 171             case Const.ATTR_CONSTANT_VALUE:
 172                 return new ConstantValue(name_index, length, file, constant_pool);
 173             case Const.ATTR_SOURCE_FILE:
 174                 return new SourceFile(name_index, length, file, constant_pool);
 175             case Const.ATTR_CODE:
 176                 return new Code(name_index, length, file, constant_pool);
 177             case Const.ATTR_EXCEPTIONS:
 178                 return new ExceptionTable(name_index, length, file, constant_pool);
 179             case Const.ATTR_LINE_NUMBER_TABLE:
 180                 return new LineNumberTable(name_index, length, file, constant_pool);
 181             case Const.ATTR_LOCAL_VARIABLE_TABLE:
 182                 return new LocalVariableTable(name_index, length, file, constant_pool);
 183             case Const.ATTR_INNER_CLASSES:
 184                 return new InnerClasses(name_index, length, file, constant_pool);
 185             case Const.ATTR_SYNTHETIC:
 186                 return new Synthetic(name_index, length, file, constant_pool);
 187             case Const.ATTR_DEPRECATED:
 188                 return new Deprecated(name_index, length, file, constant_pool);
 189             case Const.ATTR_PMG:
 190                 return new PMGClass(name_index, length, file, constant_pool);
 191             case Const.ATTR_SIGNATURE:
 192                 return new Signature(name_index, length, file, constant_pool);
 193             case Const.ATTR_STACK_MAP:
 194                 return new StackMap(name_index, length, file, constant_pool);
 195             case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
 196                 return new RuntimeVisibleAnnotations(name_index, length, file, constant_pool);
 197             case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS:
 198                 return new RuntimeInvisibleAnnotations(name_index, length, file, constant_pool);
 199             case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
 200                 return new RuntimeVisibleParameterAnnotations(name_index, length, file, constant_pool);
 201             case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
 202                 return new RuntimeInvisibleParameterAnnotations(name_index, length, file, constant_pool);
 203             case Const.ATTR_ANNOTATION_DEFAULT:
 204                 return new AnnotationDefault(name_index, length, file, constant_pool);
 205             case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
 206                 return new LocalVariableTypeTable(name_index, length, file, constant_pool);
 207             case Const.ATTR_ENCLOSING_METHOD:
 208                 return new EnclosingMethod(name_index, length, file, constant_pool);
 209             case Const.ATTR_STACK_MAP_TABLE:
 210                 return new StackMap(name_index, length, file, constant_pool);
 211             case Const.ATTR_BOOTSTRAP_METHODS:
 212                 return new BootstrapMethods(name_index, length, file, constant_pool);
 213             case Const.ATTR_METHOD_PARAMETERS:
 214                 return new MethodParameters(name_index, length, file, constant_pool);
 215             default:
 216                 // Never reached
 217                 throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
 218         }
 219     }
 220 
 221     /**
 222      * @return Name of attribute
 223      * @since 6.0
 224      */
 225     public String getName() {
 226         final ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8);
 227         return c.getBytes();
 228     }
 229 
 230     /**
 231      * @return Length of attribute field in bytes.
 232      */
 233     public final int getLength() {
 234         return length;
 235     }
 236 
 237     /**
 238      * @param length length in bytes.
 239      */
 240     public final void setLength(final int length) {
 241         this.length = length;
 242     }
 243 
 244     /**
 245      * @param name_index of attribute.
 246      */
 247     public final void setNameIndex(final int name_index) {
 248         this.name_index = name_index;
 249     }
 250 
 251     /**
 252      * @return Name index in constant pool of attribute name.
 253      */
 254     public final int getNameIndex() {
 255         return name_index;
 256     }
 257 
 258     /**
 259      * @return Tag of attribute, i.e., its type. Value may not be altered, thus
 260      * there is no setTag() method.
 261      */
 262     public final byte getTag() {
 263         return tag;
 264     }
 265 
 266     /**
 267      * @return Constant pool used by this object.
 268      * @see ConstantPool
 269      */
 270     public final ConstantPool getConstantPool() {
 271         return constant_pool;
 272     }
 273 
 274     /**
 275      * @param constant_pool Constant pool to be used for this object.
 276      * @see ConstantPool
 277      */
 278     public final void setConstantPool(final ConstantPool constant_pool) {
 279         this.constant_pool = constant_pool;
 280     }
 281 
 282     /**
 283      * Use copy() if you want to have a deep copy(), i.e., with all references
 284      * copied correctly.
 285      *
 286      * @return shallow copy of this attribute
 287      */
 288     @Override
 289     public Object clone() {
 290         Attribute attr = null;
 291         try {
 292             attr = (Attribute) super.clone();
 293         } catch (final CloneNotSupportedException e) {
 294             throw new Error("Clone Not Supported"); // never happens
 295         }
 296         return attr;
 297     }
 298 
 299     /**
 300      * @return deep copy of this attribute
 301      */
 302     public abstract Attribute copy(ConstantPool _constant_pool);
 303 
 304     /**
 305      * @return attribute name.
 306      */
 307     @Override
 308     public String toString() {
 309         return Const.getAttributeName(tag);
 310     }
 311 }