001 package edu.rice.cs.cunit.classFile.attributes; 002 003 import edu.rice.cs.cunit.classFile.attributes.visitors.IAttributeVisitor; 004 import edu.rice.cs.cunit.classFile.code.instructions.LineNumberTable; 005 import edu.rice.cs.cunit.classFile.constantPool.AUTFPoolInfo; 006 import edu.rice.cs.cunit.classFile.constantPool.ConstantPool; 007 import edu.rice.cs.cunit.classFile.constantPool.visitors.CheckUTFVisitor; 008 009 import java.io.DataInputStream; 010 import java.io.DataOutputStream; 011 import java.io.IOException; 012 import java.lang.reflect.Method; 013 import java.lang.reflect.InvocationTargetException; 014 import java.lang.reflect.Constructor; 015 import java.util.Arrays; 016 017 /** 018 * @author Mathias Ricken 019 */ 020 public abstract class AAttributeInfo implements Cloneable { 021 /** 022 * Attribute _name information. 023 */ 024 protected AUTFPoolInfo _name; 025 026 /** 027 * Attribute _data. 028 */ 029 protected byte[] _data; 030 031 /** 032 * Constant pool. 033 */ 034 protected ConstantPool _constantPool; 035 036 /** 037 * Array with registered attributes. 038 */ 039 @SuppressWarnings("unchecked") private static Class<AAttributeInfo>[] _knownAttributes = new Class[] { 040 SourceFileAttributeInfo.class, 041 ConstantValueAttributeInfo.class, 042 CodeAttributeInfo.class, 043 ExceptionsAttributeInfo.class, 044 LineNumberTableAttributeInfo.class, 045 LocalVariableTableAttributeInfo.class, 046 LocalVariableTypeTableAttributeInfo.class, 047 SignatureAttributeInfo.class, 048 DeprecatedAttributeInfo.class, 049 SyntheticAttributeInfo.class, 050 EnclosingMethodAttributeInfo.class, 051 AnnotationDefaultAttributeInfo.class, 052 RuntimeInvisibleAnnotationsAttributeInfo.class, 053 RuntimeVisibleAnnotationsAttributeInfo.class, 054 RuntimeInvisibleParameterAnnotationsAttributeInfo.class, 055 RuntimeVisibleParameterAnnotationsAttributeInfo.class, 056 InnerClassesAttributeInfo.class, 057 InstrumentationAttributeInfo.class, 058 059 // non-standard: 060 RuntimeInvisibleLocalVariableAnnotationsAttributeInfo.class, 061 RuntimeVisibleLocalVariableAnnotationsAttributeInfo.class 062 }; 063 064 /** 065 * Read from stream and return unresolved constant pool object. 066 * 067 * @param di stream 068 * @param pool constant pool 069 * 070 * @return attribute 071 * 072 * @throws IOException 073 * @throws ClassFormatError 074 */ 075 public static AAttributeInfo read(DataInputStream di, ConstantPool pool) throws IOException, ClassFormatError { 076 AUTFPoolInfo name = pool.get(di.readShort()).execute(CheckUTFVisitor.singleton(), null); 077 String attrName = name.toString(); 078 079 int len = di.readInt(); 080 byte[] data = new byte[len]; 081 int offset = 0, bytesRead; 082 while((offset < data.length) && ((bytesRead = di.read(data, offset, data.length - offset)) != -1)) { 083 offset += bytesRead; 084 } 085 086 if ((len != data.length) && ((len != -1) || (data.length != 0))) { 087 throw new ClassFormatError( 088 "Attribute data of " + attrName + " has wrong length, actual=" + data.length + ", expected=" + len); 089 } 090 091 for (Class<AAttributeInfo> c: _knownAttributes) { 092 try { 093 Method m = c.getMethod("getAttributeName"); 094 String knownName = (String)m.invoke(null); 095 if (knownName.equals(name.toString())) { 096 Constructor ctor = c.getConstructor(AUTFPoolInfo.class, byte[].class, ConstantPool.class); 097 return (AAttributeInfo)ctor.newInstance(name, data, pool); 098 } 099 } 100 catch(NoSuchMethodException e) { 101 throw new Error("Error creating attribute info", e); 102 } 103 catch(IllegalAccessException e) { 104 throw new Error("Error creating attribute info", e); 105 } 106 catch(InvocationTargetException e) { 107 throw new Error("Error creating attribute info", e); 108 } 109 catch(InstantiationException e) { 110 e.printStackTrace(); 111 } 112 } 113 114 return new UnknownAttributeInfo(name, data, pool); 115 } 116 117 118 /** 119 * Constructor. 120 * 121 * @param name attrobite name 122 * @param data attribute data 123 * @param cp 124 */ 125 public AAttributeInfo(AUTFPoolInfo name, byte data[], ConstantPool cp) { 126 _name = name; 127 _data = data; 128 _constantPool = cp; 129 } 130 131 /** 132 * Accessor for _name information. 133 * 134 * @return _name information 135 */ 136 public AUTFPoolInfo getName() { 137 return _name; 138 } 139 140 /** 141 * Mutator for _name information. 142 * 143 * @param name _name information 144 */ 145 public void setName(AUTFPoolInfo name) { 146 _name = name; 147 } 148 149 /** 150 * Accessor for data. 151 * 152 * @return data data 153 */ 154 public byte[] getData() { 155 return _data; 156 } 157 158 /** 159 * Mutator for data. 160 * 161 * @param data data 162 */ 163 public void setData(byte[] data) { 164 _data = data; 165 } 166 167 /** 168 * Write this attribute into a stream 169 * 170 * @param dos output stream 171 * 172 * @throws java.io.IOException 173 */ 174 public void write(DataOutputStream dos) throws IOException { 175 dos.writeShort(_constantPool.indexOf(_name)); 176 dos.writeInt(_data.length); 177 dos.write(_data, 0, _data.length); 178 } 179 180 /** 181 * Return a human-readable version of this attribute. 182 * 183 * @return string 184 */ 185 public String toString() { 186 final String hexChars = "0123456789abcdef"; 187 StringBuilder sb = new StringBuilder(); 188 sb.append(_name); 189 sb.append(" <"); 190 sb.append(_data.length); 191 sb.append(" bytes:"); 192 for (byte b:_data) { 193 sb.append(" "); 194 sb.append(hexChars.charAt((b>>>4)&0x0F)); 195 sb.append(hexChars.charAt(b&0x0F)); 196 } 197 sb.append(">"); 198 return sb.toString(); 199 } 200 201 /** 202 * Execute a visitor on this attribute. 203 * 204 * @param visitor visitor 205 * @param param visitor-specific parameter 206 * 207 * @return visitor-specific return value 208 */ 209 public abstract <R, D> R execute(IAttributeVisitor<R, D> visitor, D param); 210 211 /** 212 * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them. 213 * 214 * @param startPC program counter to start at 215 * @param deltaPC change in program counter values 216 */ 217 public abstract void adjustPC(int startPC, int deltaPC); 218 219 /** 220 * Translate the program counter values contained in this attribute from an old line number table to a new one. 221 * 222 * @param index critical point (insertion or deletion point) 223 * @param deltaIndex delta value to add to all old line numbers greater than the critical point 224 * @param oldLnt old line number table 225 * @param newLnt new line number table 226 */ 227 public abstract void translatePC(int index, int deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt); 228 229 /** 230 * Creates and returns a copy of this object. 231 */ 232 public Object clone() throws CloneNotSupportedException { 233 AAttributeInfo a = (AAttributeInfo)super.clone(); 234 235 a._data = new byte[_data.length]; 236 System.arraycopy(_data, 0, a._data, 0, _data.length); 237 238 return a; 239 } 240 241 /** 242 * Indicates whether some other object is "equal to" this one. 243 * @param o the reference object with which to compare. 244 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise. 245 */ 246 public boolean equals(Object o) { 247 if (this == o) { 248 return true; 249 } 250 if (o == null || getClass() != o.getClass()) { 251 return false; 252 } 253 254 AAttributeInfo that = (AAttributeInfo)o; 255 256 if (_constantPool != null ? !_constantPool.equals(that._constantPool) : that._constantPool != null) { 257 return false; 258 } 259 if (!Arrays.equals(_data, that._data)) { 260 return false; 261 } 262 if (_name != null ? !_name.equals(that._name) : that._name != null) { 263 return false; 264 } 265 266 return true; 267 } 268 269 public int hashCode() { 270 int result; 271 result = (_name != null ? _name.hashCode() : 0); 272 result = 31 * result + (_data != null ? Arrays.hashCode(_data) : 0); 273 result = 31 * result + (_constantPool != null ? _constantPool.hashCode() : 0); 274 return result; 275 } 276 }