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 }