KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > bcel > classfile > ClassParser


1 /*
2  * Copyright 2000-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */

17 package org.apache.bcel.classfile;
18
19 import java.io.BufferedInputStream JavaDoc;
20 import java.io.DataInputStream JavaDoc;
21 import java.io.FileInputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.util.zip.ZipEntry JavaDoc;
25 import java.util.zip.ZipFile JavaDoc;
26 import org.apache.bcel.Constants;
27
28 /**
29  * Wrapper class that parses a given Java .class file. The method <A
30  * href ="#parse">parse</A> returns a <A href ="JavaClass.html">
31  * JavaClass</A> object on success. When an I/O error or an
32  * inconsistency occurs an appropiate exception is propagated back to
33  * the caller.
34  *
35  * The structure and the names comply, except for a few conveniences,
36  * exactly with the <A HREF="ftp://java.sun.com/docs/specs/vmspec.ps">
37  * JVM specification 1.0</a>. See this paper for
38  * further details about the structure of a bytecode file.
39  *
40  * @version $Id: ClassParser.java 386056 2006-03-15 11:31:56Z tcurdt $
41  * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
42  */

43 public final class ClassParser {
44
45     private DataInputStream JavaDoc file;
46     private boolean fileOwned;
47     private String JavaDoc file_name;
48     private String JavaDoc zip_file;
49     private int class_name_index, superclass_name_index;
50     private int major, minor; // Compiler version
51
private int access_flags; // Access rights of parsed class
52
private int[] interfaces; // Names of implemented interfaces
53
private ConstantPool constant_pool; // collection of constants
54
private Field[] fields; // class fields, i.e., its variables
55
private Method[] methods; // methods defined in the class
56
private Attribute[] attributes; // attributes defined in the class
57
private boolean is_zip; // Loaded from zip file
58
private static final int BUFSIZE = 8192;
59
60
61     /**
62      * Parse class from the given stream.
63      *
64      * @param file Input stream
65      * @param file_name File name
66      */

67     public ClassParser(InputStream JavaDoc file, String JavaDoc file_name) {
68         this.file_name = file_name;
69         fileOwned = false;
70         String JavaDoc clazz = file.getClass().getName(); // Not a very clean solution ...
71
is_zip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar.");
72         if (file instanceof DataInputStream JavaDoc) {
73             this.file = (DataInputStream JavaDoc) file;
74         } else {
75             this.file = new DataInputStream JavaDoc(new BufferedInputStream JavaDoc(file, BUFSIZE));
76         }
77     }
78
79
80     /** Parse class from given .class file.
81      *
82      * @param file_name file name
83      */

84     public ClassParser(String JavaDoc file_name) throws IOException JavaDoc {
85         is_zip = false;
86         this.file_name = file_name;
87         fileOwned = true;
88     }
89
90
91     /** Parse class from given .class file in a ZIP-archive
92      *
93      * @param zip_file zip file name
94      * @param file_name file name
95      */

96     public ClassParser(String JavaDoc zip_file, String JavaDoc file_name) {
97         is_zip = true;
98         fileOwned = true;
99         this.zip_file = zip_file;
100         this.file_name = file_name;
101     }
102
103
104     /**
105      * Parse the given Java class file and return an object that represents
106      * the contained data, i.e., constants, methods, fields and commands.
107      * A <em>ClassFormatException</em> is raised, if the file is not a valid
108      * .class file. (This does not include verification of the byte code as it
109      * is performed by the java interpreter).
110      *
111      * @return Class object representing the parsed class file
112      * @throws IOException
113      * @throws ClassFormatException
114      */

115     public JavaClass parse() throws IOException JavaDoc, ClassFormatException {
116         ZipFile JavaDoc zip = null;
117         try {
118             if (fileOwned) {
119                 if (is_zip) {
120                     zip = new ZipFile JavaDoc(zip_file);
121                     ZipEntry JavaDoc entry = zip.getEntry(file_name);
122                     file = new DataInputStream JavaDoc(new BufferedInputStream JavaDoc(zip.getInputStream(entry),
123                             BUFSIZE));
124                 } else {
125                     file = new DataInputStream JavaDoc(new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(
126                             file_name), BUFSIZE));
127                 }
128             }
129             /****************** Read headers ********************************/
130             // Check magic tag of class file
131
readID();
132             // Get compiler version
133
readVersion();
134             /****************** Read constant pool and related **************/
135             // Read constant pool entries
136
readConstantPool();
137             // Get class information
138
readClassInfo();
139             // Get interface information, i.e., implemented interfaces
140
readInterfaces();
141             /****************** Read class fields and methods ***************/
142             // Read class fields, i.e., the variables of the class
143
readFields();
144             // Read class methods, i.e., the functions in the class
145
readMethods();
146             // Read class attributes
147
readAttributes();
148             // Check for unknown variables
149
//Unknown[] u = Unknown.getUnknownAttributes();
150
//for(int i=0; i < u.length; i++)
151
// System.err.println("WARNING: " + u[i]);
152
// Everything should have been read now
153
// if(file.available() > 0) {
154
// int bytes = file.available();
155
// byte[] buf = new byte[bytes];
156
// file.read(buf);
157
// if(!(is_zip && (buf.length == 1))) {
158
// System.err.println("WARNING: Trailing garbage at end of " + file_name);
159
// System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf));
160
// }
161
// }
162
} finally {
163             // Read everything of interest, so close the file
164
if (fileOwned) {
165                 file.close();
166                 if (zip != null) {
167                     zip.close();
168                 }
169             }
170         }
171         // Return the information we have gathered in a new object
172
return new JavaClass(class_name_index, superclass_name_index, file_name, major, minor,
173                 access_flags, constant_pool, interfaces, fields, methods, attributes, is_zip
174                         ? JavaClass.ZIP
175                         : JavaClass.FILE);
176     }
177
178
179     /**
180      * Read information about the attributes of the class.
181      * @throws IOException
182      * @throws ClassFormatException
183      */

184     private final void readAttributes() throws IOException JavaDoc, ClassFormatException {
185         int attributes_count;
186         attributes_count = file.readUnsignedShort();
187         attributes = new Attribute[attributes_count];
188         for (int i = 0; i < attributes_count; i++) {
189             attributes[i] = Attribute.readAttribute(file, constant_pool);
190         }
191     }
192
193
194     /**
195      * Read information about the class and its super class.
196      * @throws IOException
197      * @throws ClassFormatException
198      */

199     private final void readClassInfo() throws IOException JavaDoc, ClassFormatException {
200         access_flags = file.readUnsignedShort();
201         /* Interfaces are implicitely abstract, the flag should be set
202          * according to the JVM specification.
203          */

204         if ((access_flags & Constants.ACC_INTERFACE) != 0) {
205             access_flags |= Constants.ACC_ABSTRACT;
206         }
207         if (((access_flags & Constants.ACC_ABSTRACT) != 0)
208                 && ((access_flags & Constants.ACC_FINAL) != 0)) {
209             throw new ClassFormatException("Class can't be both final and abstract");
210         }
211         class_name_index = file.readUnsignedShort();
212         superclass_name_index = file.readUnsignedShort();
213     }
214
215
216     /**
217      * Read constant pool entries.
218      * @throws IOException
219      * @throws ClassFormatException
220      */

221     private final void readConstantPool() throws IOException JavaDoc, ClassFormatException {
222         constant_pool = new ConstantPool(file);
223     }
224
225
226     /**
227      * Read information about the fields of the class, i.e., its variables.
228      * @throws IOException
229      * @throws ClassFormatException
230      */

231     private final void readFields() throws IOException JavaDoc, ClassFormatException {
232         int fields_count;
233         fields_count = file.readUnsignedShort();
234         fields = new Field[fields_count];
235         for (int i = 0; i < fields_count; i++) {
236             fields[i] = new Field(file, constant_pool);
237         }
238     }
239
240
241     /******************** Private utility methods **********************/
242     /**
243      * Check whether the header of the file is ok.
244      * Of course, this has to be the first action on successive file reads.
245      * @throws IOException
246      * @throws ClassFormatException
247      */

248     private final void readID() throws IOException JavaDoc, ClassFormatException {
249         int magic = 0xCAFEBABE;
250         if (file.readInt() != magic) {
251             throw new ClassFormatException(file_name + " is not a Java .class file");
252         }
253     }
254
255
256     /**
257      * Read information about the interfaces implemented by this class.
258      * @throws IOException
259      * @throws ClassFormatException
260      */

261     private final void readInterfaces() throws IOException JavaDoc, ClassFormatException {
262         int interfaces_count;
263         interfaces_count = file.readUnsignedShort();
264         interfaces = new int[interfaces_count];
265         for (int i = 0; i < interfaces_count; i++) {
266             interfaces[i] = file.readUnsignedShort();
267         }
268     }
269
270
271     /**
272      * Read information about the methods of the class.
273      * @throws IOException
274      * @throws ClassFormatException
275      */

276     private final void readMethods() throws IOException JavaDoc, ClassFormatException {
277         int methods_count;
278         methods_count = file.readUnsignedShort();
279         methods = new Method[methods_count];
280         for (int i = 0; i < methods_count; i++) {
281             methods[i] = new Method(file, constant_pool);
282         }
283     }
284
285
286     /**
287      * Read major and minor version of compiler which created the file.
288      * @throws IOException
289      * @throws ClassFormatException
290      */

291     private final void readVersion() throws IOException JavaDoc, ClassFormatException {
292         minor = file.readUnsignedShort();
293         major = file.readUnsignedShort();
294     }
295 }
296
Popular Tags