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 }