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 }