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    }