001 package sysModel.classFile.attributes;
002
003 import sysModel.classFile.attributes.visitors.IAttributeVisitor;
004 import sysModel.classFile.code.instructions.LineNumberTable;
005 import sysModel.classFile.constantPool.AUTFPoolInfo;
006 import sysModel.classFile.constantPool.ConstantPool;
007 import sysModel.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
016 /**
017 * Abstract class file attribute.
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 private static Class[] _knownAttributes = new Class[] {
040 SourceFileAttributeInfo.class,
041 CodeAttributeInfo.class,
042 };
043
044 /**
045 * Read from stream and return unresolved constant pool object.
046 *
047 * @param di stream
048 * @param pool constant pool
049 *
050 * @return attribute
051 *
052 * @throws IOException
053 * @throws ClassFormatError
054 */
055 public static AAttributeInfo read(DataInputStream di, ConstantPool pool) throws IOException, ClassFormatError {
056 AUTFPoolInfo name = pool.get(di.readShort()).execute(CheckUTFVisitor.singleton(), null);
057 String attrName = name.toString();
058
059 int len = di.readInt();
060 byte[] data = new byte[len];
061 int offset = 0, bytesRead;
062 while((offset < data.length) && (-1 != (bytesRead = di.read(data, offset, data.length - offset)))) {
063 offset += bytesRead;
064 }
065
066 if ((len != data.length) && ((-1 != len) || (0 != data.length))) {
067 throw new ClassFormatError(
068 "Attribute data of " + attrName + " has wrong length, actual=" + data.length + ", expected=" + len);
069 }
070
071 for (Class c: _knownAttributes) {
072 try {
073 Method m = c.getMethod("getAttributeName");
074 String knownName = (String)m.invoke(null);
075 if (knownName.equals(name.toString())) {
076 Constructor ctor = c.getConstructor(AUTFPoolInfo.class, byte[].class, ConstantPool.class);
077 return (AAttributeInfo)ctor.newInstance(name, data, pool);
078 }
079 }
080 catch(NoSuchMethodException e) {
081 throw new Error("Error creating attribute info", e);
082 }
083 catch(IllegalAccessException e) {
084 throw new Error("Error creating attribute info", e);
085 }
086 catch(InvocationTargetException e) {
087 throw new Error("Error creating attribute info", e);
088 }
089 catch(InstantiationException e) {
090 e.printStackTrace();
091 }
092 }
093
094 return new UnknownAttributeInfo(name, data, pool);
095 }
096
097
098 /**
099 * Constructor.
100 *
101 * @param name attrobite name
102 * @param data attribute data
103 * @param cp constant pool
104 */
105 public AAttributeInfo(AUTFPoolInfo name, byte[] data, ConstantPool cp) {
106 _name = name;
107 _data = data;
108 _constantPool = cp;
109 }
110
111 /**
112 * Accessor for _name information.
113 *
114 * @return _name information
115 */
116 public AUTFPoolInfo getName() {
117 return _name;
118 }
119
120 /**
121 * Mutator for _name information.
122 *
123 * @param name _name information
124 */
125 public void setName(AUTFPoolInfo name) {
126 _name = name;
127 }
128
129 /**
130 * Accessor for data.
131 *
132 * @return data data
133 */
134 public byte[] getData() {
135 return _data;
136 }
137
138 /**
139 * Mutator for data.
140 *
141 * @param data data
142 */
143 public void setData(byte[] data) {
144 _data = data;
145 }
146
147 /**
148 * Write this attribute into a stream
149 *
150 * @param dos output stream
151 *
152 * @throws IOException
153 */
154 public void write(DataOutputStream dos) throws IOException {
155 dos.writeShort(_constantPool.indexOf(_name));
156 dos.writeInt(_data.length);
157 dos.write(_data, 0, _data.length);
158 }
159
160 /**
161 * Return a human-readable version of this attribute.
162 *
163 * @return string
164 */
165 public String toString() {
166 String hexChars = "0123456789abcdef";
167 StringBuffer sb = new StringBuffer();
168 sb.append(_name);
169 sb.append(" <");
170 sb.append(_data.length);
171 sb.append(" bytes:");
172 for (byte b:_data) {
173 sb.append(' ');
174 sb.append(hexChars.charAt((b>>>4)&0x0F));
175 sb.append(hexChars.charAt(b&0x0F));
176 }
177 sb.append('>');
178 return sb.toString();
179 }
180
181 /**
182 * Execute a visitor on this attribute.
183 *
184 * @param visitor visitor
185 * @param param visitor-specific parameter
186 *
187 * @return visitor-specific return value
188 */
189 public abstract <R, D> R execute(IAttributeVisitor<R, D> visitor, D param);
190
191 /**
192 * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them.
193 *
194 * @param startPC program counter to start at
195 * @param deltaPC change in program counter values
196 */
197 public abstract void adjustPC(short startPC, short deltaPC);
198
199 /**
200 * Translate the program counter values contained in this attribute from an old line number table to a new one.
201 *
202 * @param index critical point (insertion or deletion point)
203 * @param deltaIndex delta value to add to all old line numbers greater than the critical point
204 * @param oldLnt old line number table
205 * @param newLnt new line number table
206 */
207 public abstract void translatePC(short index, short deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt);
208
209 /**
210 * Creates and returns a copy of this object.
211 * @return a clone of this instance.
212 * @throws CloneNotSupportedException if the object's class does not support the <code>Cloneable</code> interface.
213 */
214 public Object lone() throws CloneNotSupportedException {
215 AAttributeInfo a = (AAttributeInfo)super.clone();
216
217 a._data = new byte[_data.length];
218 System.arraycopy(_data, 0, a._data, 0, _data.length);
219
220 return a;
221 }
222 }