1 /*
   2  * Copyright (c) 2017, 2020, 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  * @see ConstantValue
  40  * @see SourceFile
  41  * @see Code
  42  * @see Unknown
  43  * @see ExceptionTable
  44  * @see LineNumberTable
  45  * @see LocalVariableTable
  46  * @see InnerClasses
  47  * @see Synthetic
  48  * @see Deprecated
  49  * @see Signature
  50  * @LastModified: Jan 2020
  51  */
  52 public abstract class Attribute implements Cloneable, Node {
  53     private static final boolean debug = false;
  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     private static final Map<String, Object> readers = new HashMap<>();
  60 
  61     /**
  62      * Add an Attribute reader capable of parsing (user-defined) attributes
  63      * named "name". You should not add readers for the standard attributes such
  64      * as "LineNumberTable", because those are handled internally.
  65      *
  66      * @param name the name of the attribute as stored in the class file
  67      * @param r    the reader object
  68      */
  69     public static void addAttributeReader(final String name, final UnknownAttributeReader r)
  70     {
  71         readers.put(name, r);
  72     }
  73 
  74     protected static void println(final String msg) {
  75         if (debug) {
  76             System.err.println(msg);
  77         }
  78     }
  79 
  80     /**
  81      * Class method reads one attribute from the input data stream. This method
  82      * must not be accessible from the outside. It is called by the Field and
  83      * Method constructor methods.
  84      *
  85      * @see Field
  86      * @see Method
  87      *
  88      * @param file Input stream
  89      * @param constant_pool Array of constants
  90      * @return Attribute
  91      * @throws IOException
  92      * @throws ClassFormatException
  93      * @since 6.0
  94      */
  95     public static Attribute readAttribute(final DataInput file, final ConstantPool constant_pool)
  96             throws IOException, ClassFormatException
  97     {
  98         byte tag = Const.ATTR_UNKNOWN; // Unknown attribute
  99         // Get class name from constant pool via `name_index' indirection
 100         final int name_index = file.readUnsignedShort();
 101         final ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8);
 102         final String name = c.getBytes();
 103 
 104         // Length of data in bytes
 105         final int length = file.readInt();
 106 
 107         // Compare strings to find known attribute
 108         for (byte i = 0; i < Const.KNOWN_ATTRIBUTES; i++)
 109         {
 110             if (name.equals(Const.getAttributeName(i)))
 111             {
 112                 tag = i; // found!
 113                 break;
 114             }
 115         }
 116 
 117         // Call proper constructor, depending on `tag'
 118         switch (tag)
 119         {
 120             case Const.ATTR_UNKNOWN:
 121                 final Object r = readers.get(name);
 122                 if (r instanceof UnknownAttributeReader)
 123                 {
 124                     return ((UnknownAttributeReader) r).createAttribute(name_index, length, file, constant_pool);
 125                 }
 126                 return new Unknown(name_index, length, file, constant_pool);
 127             case Const.ATTR_CONSTANT_VALUE:
 128                 return new ConstantValue(name_index, length, file, constant_pool);
 129             case Const.ATTR_SOURCE_FILE:
 130                 return new SourceFile(name_index, length, file, constant_pool);
 131             case Const.ATTR_CODE:
 132                 return new Code(name_index, length, file, constant_pool);
 133             case Const.ATTR_EXCEPTIONS:
 134                 return new ExceptionTable(name_index, length, file, constant_pool);
 135             case Const.ATTR_LINE_NUMBER_TABLE:
 136                 return new LineNumberTable(name_index, length, file, constant_pool);
 137             case Const.ATTR_LOCAL_VARIABLE_TABLE:
 138                 return new LocalVariableTable(name_index, length, file, constant_pool);
 139             case Const.ATTR_INNER_CLASSES:
 140                 return new InnerClasses(name_index, length, file, constant_pool);
 141             case Const.ATTR_SYNTHETIC:
 142                 return new Synthetic(name_index, length, file, constant_pool);
 143             case Const.ATTR_DEPRECATED:
 144                 return new Deprecated(name_index, length, file, constant_pool);
 145             case Const.ATTR_PMG:
 146                 return new PMGClass(name_index, length, file, constant_pool);
 147             case Const.ATTR_SIGNATURE:
 148                 return new Signature(name_index, length, file, constant_pool);
 149             case Const.ATTR_STACK_MAP:
 150                 // old style stack map: unneeded for JDK5 and below;
 151                 // illegal(?) for JDK6 and above.  So just delete with a warning.
 152                 println("Warning: Obsolete StackMap attribute ignored.");
 153                 return new Unknown(name_index, length, file, constant_pool);
 154             case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
 155                 return new RuntimeVisibleAnnotations(name_index, length, file, constant_pool);
 156             case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS:
 157                 return new RuntimeInvisibleAnnotations(name_index, length, file, constant_pool);
 158             case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
 159                 return new RuntimeVisibleParameterAnnotations(name_index, length, file, constant_pool);
 160             case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
 161                 return new RuntimeInvisibleParameterAnnotations(name_index, length, file, constant_pool);
 162             case Const.ATTR_ANNOTATION_DEFAULT:
 163                 return new AnnotationDefault(name_index, length, file, constant_pool);
 164             case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
 165                 return new LocalVariableTypeTable(name_index, length, file, constant_pool);
 166             case Const.ATTR_ENCLOSING_METHOD:
 167                 return new EnclosingMethod(name_index, length, file, constant_pool);
 168             case Const.ATTR_STACK_MAP_TABLE:
 169                 // read new style stack map: StackMapTable.  The rest of the code
 170                 // calls this a StackMap for historical reasons.
 171                 return new StackMap(name_index, length, file, constant_pool);
 172             case Const.ATTR_BOOTSTRAP_METHODS:
 173                 return new BootstrapMethods(name_index, length, file, constant_pool);
 174             case Const.ATTR_METHOD_PARAMETERS:
 175                 return new MethodParameters(name_index, length, file, constant_pool);
 176             case Const.ATTR_MODULE:
 177                 return new Module(name_index, length, file, constant_pool);
 178             case Const.ATTR_MODULE_PACKAGES:
 179                 return new ModulePackages(name_index, length, file, constant_pool);
 180             case Const.ATTR_MODULE_MAIN_CLASS:
 181                 return new ModuleMainClass(name_index, length, file, constant_pool);
 182             case Const.ATTR_NEST_HOST:
 183                 return new NestHost(name_index, length, file, constant_pool);
 184             case Const.ATTR_NEST_MEMBERS:
 185                 return new NestMembers(name_index, length, file, constant_pool);
 186             default:
 187                 // Never reached
 188                 throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
 189         }
 190     }
 191 
 192     /**
 193      * Class method reads one attribute from the input data stream. This method
 194      * must not be accessible from the outside. It is called by the Field and
 195      * Method constructor methods.
 196      *
 197      * @see Field
 198      * @see Method
 199      *
 200      * @param file Input stream
 201      * @param constant_pool Array of constants
 202      * @return Attribute
 203      * @throws IOException
 204      * @throws ClassFormatException
 205      */
 206     public static Attribute readAttribute(final DataInputStream file, final ConstantPool constant_pool)
 207             throws IOException, ClassFormatException
 208     {
 209         return readAttribute((DataInput) file, constant_pool);
 210     }
 211 
 212     /**
 213      * Remove attribute reader
 214      *
 215      * @param name the name of the attribute as stored in the class file
 216      */
 217     public static void removeAttributeReader(final String name)
 218     {
 219         readers.remove(name);
 220     }
 221 
 222     protected Attribute(final byte tag, final int name_index, final int length, final ConstantPool constant_pool)
 223     {
 224         this.tag = tag;
 225         this.name_index = name_index;
 226         this.length = length;
 227         this.constant_pool = constant_pool;
 228     }
 229 
 230     /**
 231      * Called by objects that are traversing the nodes of the tree implicitely
 232      * defined by the contents of a Java class. I.e., the hierarchy of methods,
 233      * fields, attributes, etc. spawns a tree of objects.
 234      *
 235      * @param v
 236      *            Visitor object
 237      */
 238     @Override
 239     public abstract void accept(Visitor v);
 240 
 241     /**
 242      * Use copy() if you want to have a deep copy(), i.e., with all references
 243      * copied correctly.
 244      *
 245      * @return shallow copy of this attribute
 246      */
 247     @Override
 248     public Object clone()
 249     {
 250         Attribute attr = null;
 251         try
 252         {
 253             attr = (Attribute) super.clone();
 254         }
 255         catch (final CloneNotSupportedException e)
 256         {
 257             throw new Error("Clone Not Supported"); // never happens
 258         }
 259         return attr;
 260     }
 261 
 262     /**
 263      * @return deep copy of this attribute
 264      */
 265     public abstract Attribute copy(ConstantPool _constant_pool);
 266 
 267     /**
 268      * Dump attribute to file stream in binary format.
 269      *
 270      * @param file
 271      *            Output file stream
 272      * @throws IOException
 273      */
 274     public void dump(final DataOutputStream file) throws IOException
 275     {
 276         file.writeShort(name_index);
 277         file.writeInt(length);
 278     }
 279 
 280     /**
 281      * @return Constant pool used by this object.
 282      * @see ConstantPool
 283      */
 284     public final ConstantPool getConstantPool()
 285     {
 286         return constant_pool;
 287     }
 288 
 289     /**
 290      * @return Length of attribute field in bytes.
 291      */
 292     public final int getLength()
 293     {
 294         return length;
 295     }
 296 
 297     /**
 298      * @return Name of attribute
 299      * @since 6.0
 300      */
 301     public String getName()
 302     {
 303         final ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8);
 304         return c.getBytes();
 305     }
 306 
 307     /**
 308      * @return Name index in constant pool of attribute name.
 309      */
 310     public final int getNameIndex()
 311     {
 312         return name_index;
 313     }
 314 
 315     /**
 316      * @return Tag of attribute, i.e., its type. Value may not be altered, thus there is no setTag() method.
 317      */
 318     public final byte getTag()
 319     {
 320         return tag;
 321     }
 322 
 323     /**
 324      * @param constant_pool Constant pool to be used for this object.
 325      * @see ConstantPool
 326      */
 327     public final void setConstantPool(final ConstantPool constant_pool)
 328     {
 329         this.constant_pool = constant_pool;
 330     }
 331 
 332     /**
 333      * @param length length in bytes.
 334      */
 335     public final void setLength(final int length)
 336     {
 337         this.length = length;
 338     }
 339 
 340     /**
 341      * @param name_index of attribute.
 342      */
 343     public final void setNameIndex(final int name_index)
 344     {
 345         this.name_index = name_index;
 346     }
 347 
 348     /**
 349      * @return attribute name.
 350      */
 351     @Override
 352     public String toString()
 353     {
 354         return Const.getAttributeName(tag);
 355     }
 356 }