1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later. 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 */ 15 16 package javassist.bytecode; 17 18 import java.io.DataInputStream; 19 import java.io.DataOutputStream; 20 import java.io.IOException; 21 import java.util.Map; 22 import java.util.ArrayList; 23 import java.util.ListIterator; 24 import java.util.List; 25 import java.util.Iterator; 26 27 // Note: if you define a new subclass of AttributeInfo, then 28 // update AttributeInfo.read(), .copy(), and (maybe) write(). 29 30 /** 31 * <code>attribute_info</code> structure. 32 */ 33 public class AttributeInfo { 34 protected ConstPool constPool; 35 int name; 36 byte[] info; 37 38 protected AttributeInfo(ConstPool cp, int attrname, byte[] attrinfo) { 39 constPool = cp; 40 name = attrname; 41 info = attrinfo; 42 } 43 44 protected AttributeInfo(ConstPool cp, String attrname) { 45 this(cp, attrname, (byte[])null); 46 } 47 48 /** 49 * Constructs an <code>attribute_info</code> structure. 50 * 51 * @param cp constant pool table 52 * @param attrname attribute name 53 * @param attrinfo <code>info</code> field 54 * of <code>attribute_info</code> structure. 55 */ 56 public AttributeInfo(ConstPool cp, String attrname, byte[] attrinfo) { 57 this(cp, cp.addUtf8Info(attrname), attrinfo); 58 } 59 60 protected AttributeInfo(ConstPool cp, int n, DataInputStream in) 61 throws IOException 62 { 63 constPool = cp; 64 name = n; 65 int len = in.readInt(); 66 info = new byte[len]; 67 if (len > 0) 68 in.readFully(info); 69 } 70 71 static AttributeInfo read(ConstPool cp, DataInputStream in) 72 throws IOException 73 { 74 int name = in.readUnsignedShort(); 75 String nameStr = cp.getUtf8Info(name); 76 if (nameStr.charAt(0) < 'L') { 77 if (nameStr.equals(AnnotationDefaultAttribute.tag)) 78 return new AnnotationDefaultAttribute(cp, name, in); 79 else if (nameStr.equals(CodeAttribute.tag)) 80 return new CodeAttribute(cp, name, in); 81 else if (nameStr.equals(ConstantAttribute.tag)) 82 return new ConstantAttribute(cp, name, in); 83 else if (nameStr.equals(DeprecatedAttribute.tag)) 84 return new DeprecatedAttribute(cp, name, in); 85 else if (nameStr.equals(EnclosingMethodAttribute.tag)) 86 return new EnclosingMethodAttribute(cp, name, in); 87 else if (nameStr.equals(ExceptionsAttribute.tag)) 88 return new ExceptionsAttribute(cp, name, in); 89 else if (nameStr.equals(InnerClassesAttribute.tag)) 90 return new InnerClassesAttribute(cp, name, in); 91 } 92 else { 93 /* Note that the names of Annotations attributes begin with 'R'. 94 */ 95 if (nameStr.equals(LineNumberAttribute.tag)) 96 return new LineNumberAttribute(cp, name, in); 97 else if (nameStr.equals(LocalVariableAttribute.tag)) 98 return new LocalVariableAttribute(cp, name, in); 99 else if (nameStr.equals(LocalVariableTypeAttribute.tag)) 100 return new LocalVariableTypeAttribute(cp, name, in); 101 else if (nameStr.equals(AnnotationsAttribute.visibleTag) 102 || nameStr.equals(AnnotationsAttribute.invisibleTag)) { 103 // RuntimeVisibleAnnotations or RuntimeInvisibleAnnotations 104 return new AnnotationsAttribute(cp, name, in); 105 } 106 else if (nameStr.equals(ParameterAnnotationsAttribute.visibleTag) 107 || nameStr.equals(ParameterAnnotationsAttribute.invisibleTag)) 108 return new ParameterAnnotationsAttribute(cp, name, in); 109 else if (nameStr.equals(SignatureAttribute.tag)) 110 return new SignatureAttribute(cp, name, in); 111 else if (nameStr.equals(SourceFileAttribute.tag)) 112 return new SourceFileAttribute(cp, name, in); 113 else if (nameStr.equals(SyntheticAttribute.tag)) 114 return new SyntheticAttribute(cp, name, in); 115 else if (nameStr.equals(StackMap.tag)) 116 return new StackMap(cp, name, in); 117 else if (nameStr.equals(StackMapTable.tag)) 118 return new StackMapTable(cp, name, in); 119 } 120 121 return new AttributeInfo(cp, name, in); 122 } 123 124 /** 125 * Returns an attribute name. 126 */ 127 public String getName() { 128 return constPool.getUtf8Info(name); 129 } 130 131 /** 132 * Returns a constant pool table. 133 */ 134 public ConstPool getConstPool() { return constPool; } 135 136 /** 137 * Returns the length of this <code>attribute_info</code> 138 * structure. 139 * The returned value is <code>attribute_length + 6</code>. 140 */ 141 public int length() { 142 return info.length + 6; 143 } 144 145 /** 146 * Returns the <code>info</code> field 147 * of this <code>attribute_info</code> structure. 148 * 149 * <p>This method is not available if the object is an instance 150 * of <code>CodeAttribute</code>. 151 */ 152 public byte[] get() { return info; } 153 154 /** 155 * Sets the <code>info</code> field 156 * of this <code>attribute_info</code> structure. 157 * 158 * <p>This method is not available if the object is an instance 159 * of <code>CodeAttribute</code>. 160 */ 161 public void set(byte[] newinfo) { info = newinfo; } 162 163 /** 164 * Makes a copy. Class names are replaced according to the 165 * given <code>Map</code> object. 166 * 167 * @param newCp the constant pool table used by the new copy. 168 * @param classnames pairs of replaced and substituted 169 * class names. 170 */ 171 public AttributeInfo copy(ConstPool newCp, Map classnames) { 172 int s = info.length; 173 byte[] srcInfo = info; 174 byte[] newInfo = new byte[s]; 175 for (int i = 0; i < s; ++i) 176 newInfo[i] = srcInfo[i]; 177 178 return new AttributeInfo(newCp, getName(), newInfo); 179 } 180 181 void write(DataOutputStream out) throws IOException { 182 out.writeShort(name); 183 out.writeInt(info.length); 184 if (info.length > 0) 185 out.write(info); 186 } 187 188 static int getLength(ArrayList list) { 189 int size = 0; 190 int n = list.size(); 191 for (int i = 0; i < n; ++i) { 192 AttributeInfo attr = (AttributeInfo)list.get(i); 193 size += attr.length(); 194 } 195 196 return size; 197 } 198 199 static AttributeInfo lookup(ArrayList list, String name) { 200 if (list == null) 201 return null; 202 203 ListIterator iterator = list.listIterator(); 204 while (iterator.hasNext()) { 205 AttributeInfo ai = (AttributeInfo)iterator.next(); 206 if (ai.getName().equals(name)) 207 return ai; 208 } 209 210 return null; // no such attribute 211 } 212 213 static synchronized void remove(ArrayList list, String name) { 214 if (list == null) 215 return; 216 217 ListIterator iterator = list.listIterator(); 218 while (iterator.hasNext()) { 219 AttributeInfo ai = (AttributeInfo)iterator.next(); 220 if (ai.getName().equals(name)) 221 iterator.remove(); 222 } 223 } 224 225 static void writeAll(ArrayList list, DataOutputStream out) 226 throws IOException 227 { 228 if (list == null) 229 return; 230 231 int n = list.size(); 232 for (int i = 0; i < n; ++i) { 233 AttributeInfo attr = (AttributeInfo)list.get(i); 234 attr.write(out); 235 } 236 } 237 238 static ArrayList copyAll(ArrayList list, ConstPool cp) { 239 if (list == null) 240 return null; 241 242 ArrayList newList = new ArrayList(); 243 int n = list.size(); 244 for (int i = 0; i < n; ++i) { 245 AttributeInfo attr = (AttributeInfo)list.get(i); 246 newList.add(attr.copy(cp, null)); 247 } 248 249 return newList; 250 } 251 252 /* The following two methods are used to implement 253 * ClassFile.renameClass(). 254 * Only CodeAttribute, LocalVariableAttribute, 255 * AnnotationsAttribute, and SignatureAttribute 256 * override these methods. 257 */ 258 void renameClass(String oldname, String newname) {} 259 void renameClass(Map classnames) {} 260 261 static void renameClass(List attributes, String oldname, String newname) { 262 Iterator iterator = attributes.iterator(); 263 while (iterator.hasNext()) { 264 AttributeInfo ai = (AttributeInfo)iterator.next(); 265 ai.renameClass(oldname, newname); 266 } 267 } 268 269 static void renameClass(List attributes, Map classnames) { 270 Iterator iterator = attributes.iterator(); 271 while (iterator.hasNext()) { 272 AttributeInfo ai = (AttributeInfo)iterator.next(); 273 ai.renameClass(classnames); 274 } 275 } 276 277 void getRefClasses(Map classnames) {} 278 279 static void getRefClasses(List attributes, Map classnames) { 280 Iterator iterator = attributes.iterator(); 281 while (iterator.hasNext()) { 282 AttributeInfo ai = (AttributeInfo)iterator.next(); 283 ai.getRefClasses(classnames); 284 } 285 } 286 } 287