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 }