001    package sysModel.classFile;
002    
003    import sysModel.classFile.attributes.AAttributeInfo;
004    import sysModel.classFile.attributes.CodeAttributeInfo;
005    import sysModel.classFile.attributes.visitors.ADefaultAttributeVisitor;
006    import sysModel.classFile.code.InstructionList;
007    import sysModel.classFile.constantPool.AUTFPoolInfo;
008    import sysModel.classFile.constantPool.ConstantPool;
009    import sysModel.classFile.constantPool.visitors.CheckUTFVisitor;
010    
011    import java.io.DataInputStream;
012    import java.io.DataOutputStream;
013    import java.io.IOException;
014    import java.util.ArrayList;
015    
016    /**
017     * Represents a method in a class file.
018     *
019     * @author Mathias Ricken
020     */
021    
022    public final class MethodInfo {
023        /**
024         * Method access flags.
025         */
026        private short _accessFlags;
027    
028        /**
029         * Name information.
030         */
031        private AUTFPoolInfo _name;
032    
033        /**
034         * Type descriptor information.
035         */
036        private AUTFPoolInfo _descriptor;
037    
038        /**
039         * Attributes.
040         */
041        private ArrayList<AAttributeInfo> _attributes = new ArrayList<AAttributeInfo>();
042    
043        /**
044         * Constructor.
045         *
046         * @param accessFlags method access flags
047         * @param name        method name
048         * @param signature   method descriptor
049         * @param attributes  array of attributes
050         */
051        public MethodInfo(short accessFlags,
052                          AUTFPoolInfo name,
053                          AUTFPoolInfo signature,
054                          AAttributeInfo[] attributes) {
055            _accessFlags = accessFlags;
056            _name = name;
057            _descriptor = signature;
058            if (null != attributes) {
059                for(AAttributeInfo attr : attributes) {
060                    _attributes.add(attr);
061                }
062            }
063        }
064    
065        /**
066         * Constructor.
067         *
068         * @param di   input stream
069         * @param pool constant pool
070         *
071         * @throws IOException
072         * @throws ClassFormatError
073         */
074        public MethodInfo(DataInputStream di, ConstantPool pool) throws IOException, ClassFormatError {
075            _accessFlags = di.readShort();
076            _name = pool.get(di.readShort()).execute(CheckUTFVisitor.singleton(), null);
077            _descriptor = pool.get(di.readShort()).execute(CheckUTFVisitor.singleton(), null);
078    
079            int count = di.readShort();
080            for(int i = 0; i < count; i++) {
081                _attributes.add(AAttributeInfo.read(di, pool));
082            }
083        }
084    
085        /**
086         * Write this method into the stream.
087         *
088         * @param dos  output stream
089         * @param pool constant pool
090         *
091         * @throws IOException
092         */
093        public void write(DataOutputStream dos, ConstantPool pool) throws IOException {
094            dos.writeShort(_accessFlags);
095            dos.writeShort(pool.indexOf(_name));
096            dos.writeShort(pool.indexOf(_descriptor));
097            dos.writeShort(_attributes.size());
098            for(AAttributeInfo attr : _attributes) {
099                attr.write(dos);
100            }
101        }
102    
103        /**
104         * Return a human-readable version of this method.
105         *
106         * @return string
107         */
108        public String toString() {
109            String s = _descriptor.toString();
110            String paramSig = s.substring(s.indexOf('(') + 1, s.indexOf(')'));
111            String returnSig = s.substring(s.indexOf(')') + 1);
112    
113            // handle constructor correctly
114            StringBuffer parameterList = new StringBuffer();
115            parameterList.append(_name + "(");
116    
117            char initialParameter = 'a';
118            if ((0 < paramSig.length()) && 'V' != paramSig.charAt(0)) {
119                StringBuffer varName = new StringBuffer();
120                while(0 < paramSig.length()) {
121                    varName.setLength(0);
122                    varName.append(initialParameter);
123                    initialParameter++;
124                    parameterList.append(ClassFileTools.getTypeString(paramSig, varName.toString()));
125                    paramSig = ClassFileTools.getNextSignature(paramSig);
126                    if (0 < paramSig.length()) {
127                        parameterList.append(", ");
128                    }
129                }
130    
131            }
132            parameterList.append(')');
133    
134            StringBuffer x = new StringBuffer();
135            x.append(ClassFileTools.getAccessString(_accessFlags));
136            x.append(ClassFileTools.getTypeString(returnSig, parameterList.toString()));
137    
138            return x.toString();
139        }
140    
141        /**
142         * Return a human-readable version of this method.
143         *
144         * @param pool constant pool
145         *
146         * @return string
147         */
148        public String toString(ConstantPool pool) {
149            return toString(pool, true, true);
150        }
151    
152        /**
153         * Return a human-readable version of this method.
154         *
155         * @param pool constant pool
156         * @param lineNumbers print line numbers
157         * @param PCs print PC values
158         *
159         * @return string
160         */
161        public String toString(ConstantPool pool, boolean lineNumbers, boolean PCs) {
162            String s = _descriptor.toString();
163            String paramSig = s.substring(s.indexOf('(') + 1, s.indexOf(')'));
164            String returnSig = s.substring(s.indexOf(')') + 1);
165    
166            // handle constructor correctly
167            StringBuffer parameterList = new StringBuffer();
168            parameterList.append(_name + "(");
169    
170            char initialParameter = 'a';
171            if ((0 < paramSig.length()) && 'V' != paramSig.charAt(0)) {
172                StringBuffer varName = new StringBuffer();
173                while(0 < paramSig.length()) {
174                    varName.setLength(0);
175                    varName.append(initialParameter);
176                    initialParameter++;
177                    parameterList.append(ClassFileTools.getTypeString(paramSig, varName.toString()));
178                    paramSig = ClassFileTools.getNextSignature(paramSig);
179                    if (0 < paramSig.length()) {
180                        parameterList.append(", ");
181                    }
182                }
183    
184            }
185            parameterList.append(')');
186    
187            StringBuffer x = new StringBuffer();
188            x.append(ClassFileTools.getAccessString(_accessFlags));
189            x.append(ClassFileTools.getTypeString(returnSig, parameterList.toString()));
190    
191            for(AAttributeInfo attr : _attributes) {
192                x.append("\n\t").append(attr.toString());
193            }
194    
195            if (0 == (_accessFlags & (ClassFile.ACC_NATIVE | ClassFile.ACC_ABSTRACT))) {
196                CodeAttributeInfo ca = getCodeAttributeInfo();
197                x.append('\n').append((new InstructionList(ca.getCode())).toString(lineNumbers, PCs));
198            }
199    
200            return x.toString();
201        }
202    
203        /**
204         * Accessor for access flags.
205         *
206         * @return access flags
207         */
208        public short getAccessFlags() {
209            return _accessFlags;
210        }
211    
212        /**
213         * Mutator for access flags.
214         *
215         * @param accessFlags new access flags
216         */
217        public void setAccessFlags(short accessFlags) {
218            _accessFlags = accessFlags;
219        }
220    
221        /**
222         * Accessor for field name.
223         *
224         * @return field name
225         */
226        public AUTFPoolInfo getName() {
227            return _name;
228        }
229    
230        /**
231         * Mutator for field name.
232         *
233         * @param name new field name
234         */
235        public void setName(AUTFPoolInfo name) {
236            _name = name;
237        }
238    
239        /**
240         * Accessor for descriptor.
241         *
242         * @return descriptor
243         */
244        public AUTFPoolInfo getDescriptor() {
245            return _descriptor;
246        }
247    
248        /**
249         * Mutator for descriptor.
250         *
251         * @param descriptor new descriptor
252         */
253        public void setDescriptor(AUTFPoolInfo descriptor) {
254            _descriptor = descriptor;
255        }
256    
257        /**
258         * Accessor for attributes.
259         *
260         * @return attributes
261         */
262        public ArrayList<AAttributeInfo> getAttributes() {
263            return _attributes;
264        }
265    
266        /**
267         * Return this method's code attribute info.
268         *
269         * @return code attribute info
270         */
271        public CodeAttributeInfo getCodeAttributeInfo() {
272            ADefaultAttributeVisitor<CodeAttributeInfo, Object> getCodeAttributeVisitor
273                = new ADefaultAttributeVisitor<CodeAttributeInfo, Object>() {
274                public CodeAttributeInfo defaultCase(AAttributeInfo host, Object o) {
275                    return null;
276                }
277    
278                public CodeAttributeInfo codeCase(CodeAttributeInfo host, Object o) {
279                    return host;
280                }
281            };
282            for(AAttributeInfo attr : _attributes) {
283                CodeAttributeInfo code = attr.execute(getCodeAttributeVisitor, null);
284                if (null != code) {
285                    return code;
286                }
287    
288            }
289            throw new ClassFormatError("Method has no Code attribute");
290        }
291    }