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    }