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