1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel.classfile;
18
19 import java.io.BufferedInputStream;
20 import java.io.DataInputStream;
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.zip.ZipEntry;
25 import java.util.zip.ZipFile;
26
27 import org.apache.bcel.Const;
28
29
30
31
32
33
34
35
36
37
38 public final class ClassParser {
39
40 private static final int BUFSIZE = 8192;
41 private DataInputStream dataInputStream;
42 private final boolean fileOwned;
43 private final String fileName;
44 private String zipFile;
45 private int classNameIndex;
46 private int superclassNameIndex;
47 private int major;
48 private int minor;
49 private int accessFlags;
50 private int[] interfaces;
51 private ConstantPool constantPool;
52 private Field[] fields;
53 private Method[] methods;
54 private Attribute[] attributes;
55 private final boolean isZip;
56
57
58
59
60
61
62
63 public ClassParser(final InputStream inputStream, final String fileName) {
64 this.fileName = fileName;
65 this.fileOwned = false;
66 final String clazz = inputStream.getClass().getName();
67 this.isZip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar.");
68 if (inputStream instanceof DataInputStream) {
69 this.dataInputStream = (DataInputStream) inputStream;
70 } else {
71 this.dataInputStream = new DataInputStream(new BufferedInputStream(inputStream, BUFSIZE));
72 }
73 }
74
75
76
77
78
79
80 public ClassParser(final String fileName) {
81 this.isZip = false;
82 this.fileName = fileName;
83 this.fileOwned = true;
84 }
85
86
87
88
89
90
91
92 public ClassParser(final String zipFile, final String fileName) {
93 this.isZip = true;
94 this.fileOwned = true;
95 this.zipFile = zipFile;
96 this.fileName = fileName;
97 }
98
99
100
101
102
103
104
105
106
107
108 public JavaClass parse() throws IOException, ClassFormatException {
109 ZipFile zip = null;
110 try {
111 if (fileOwned) {
112 if (isZip) {
113 zip = new ZipFile(zipFile);
114 final ZipEntry entry = zip.getEntry(fileName);
115
116 if (entry == null) {
117 throw new IOException("File " + fileName + " not found");
118 }
119
120 dataInputStream = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry), BUFSIZE));
121 } else {
122 dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(fileName), BUFSIZE));
123 }
124 }
125
126
127 readID();
128
129 readVersion();
130
131
132 readConstantPool();
133
134 readClassInfo();
135
136 readInterfaces();
137
138
139 readFields();
140
141 readMethods();
142
143 readAttributes();
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158 } finally {
159
160 if (fileOwned) {
161 try {
162 if (dataInputStream != null) {
163 dataInputStream.close();
164 }
165 } catch (final IOException ignored) {
166
167 }
168 }
169 try {
170 if (zip != null) {
171 zip.close();
172 }
173 } catch (final IOException ignored) {
174
175 }
176 }
177
178 return new JavaClass(classNameIndex, superclassNameIndex, fileName, major, minor, accessFlags, constantPool, interfaces, fields, methods, attributes,
179 isZip ? JavaClass.ZIP : JavaClass.FILE);
180 }
181
182
183
184
185
186
187
188 private void readAttributes() throws IOException, ClassFormatException {
189 final int attributesCount = dataInputStream.readUnsignedShort();
190 attributes = new Attribute[attributesCount];
191 for (int i = 0; i < attributesCount; i++) {
192 attributes[i] = Attribute.readAttribute(dataInputStream, constantPool);
193 }
194 }
195
196
197
198
199
200
201
202 private void readClassInfo() throws IOException, ClassFormatException {
203 accessFlags = dataInputStream.readUnsignedShort();
204
205
206
207 if ((accessFlags & Const.ACC_INTERFACE) != 0) {
208 accessFlags |= Const.ACC_ABSTRACT;
209 }
210 if ((accessFlags & Const.ACC_ABSTRACT) != 0 && (accessFlags & Const.ACC_FINAL) != 0) {
211 throw new ClassFormatException("Class " + fileName + " can't be both final and abstract");
212 }
213 classNameIndex = dataInputStream.readUnsignedShort();
214 superclassNameIndex = dataInputStream.readUnsignedShort();
215 }
216
217
218
219
220
221
222
223 private void readConstantPool() throws IOException, ClassFormatException {
224 constantPool = new ConstantPool(dataInputStream);
225 }
226
227
228
229
230
231
232
233 private void readFields() throws IOException, ClassFormatException {
234 final int fieldsCount = dataInputStream.readUnsignedShort();
235 fields = new Field[fieldsCount];
236 for (int i = 0; i < fieldsCount; i++) {
237 fields[i] = new Field(dataInputStream, constantPool);
238 }
239 }
240
241
242
243
244
245
246
247
248 private void readID() throws IOException, ClassFormatException {
249 if (dataInputStream.readInt() != Const.JVM_CLASSFILE_MAGIC) {
250 throw new ClassFormatException(fileName + " is not a Java .class file");
251 }
252 }
253
254
255
256
257
258
259
260 private void readInterfaces() throws IOException, ClassFormatException {
261 final int interfacesCount = dataInputStream.readUnsignedShort();
262 interfaces = new int[interfacesCount];
263 for (int i = 0; i < interfacesCount; i++) {
264 interfaces[i] = dataInputStream.readUnsignedShort();
265 }
266 }
267
268
269
270
271
272
273
274 private void readMethods() throws IOException {
275 final int methodsCount = dataInputStream.readUnsignedShort();
276 methods = new Method[methodsCount];
277 for (int i = 0; i < methodsCount; i++) {
278 methods[i] = new Method(dataInputStream, constantPool);
279 }
280 }
281
282
283
284
285
286
287
288 private void readVersion() throws IOException, ClassFormatException {
289 minor = dataInputStream.readUnsignedShort();
290 major = dataInputStream.readUnsignedShort();
291 }
292 }