00001 package de.fub.bytecode.classfile;
00002
00003 import de.fub.bytecode.Constants;
00004 import java.io.*;
00005 import java.util.zip.*;
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 public final class ClassParser {
00024 private DataInputStream file;
00025 private ZipFile zip;
00026 private String file_name;
00027 private int class_name_index, superclass_name_index;
00028 private int major, minor;
00029 private int access_flags;
00030 private int[] interfaces;
00031 private ConstantPool constant_pool;
00032 private Field[] fields;
00033 private Method[] methods;
00034 private Attribute[] attributes;
00035 private boolean is_zip;
00036
00037 private static final int BUFSIZE = 8192;
00038
00039
00040
00041
00042
00043
00044
00045 public ClassParser(InputStream file, String file_name) {
00046 this.file_name = file_name;
00047
00048 String clazz = file.getClass().getName();
00049 is_zip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar.");
00050
00051 if(file instanceof DataInputStream)
00052 this.file = (DataInputStream)file;
00053 else
00054 this.file = new DataInputStream(new BufferedInputStream(file, BUFSIZE));
00055 }
00056
00057
00058
00059
00060
00061 public ClassParser(String file_name) throws IOException
00062 {
00063 is_zip = false;
00064 this.file_name = file_name;
00065 file = new DataInputStream(new BufferedInputStream
00066 (new FileInputStream(file_name), BUFSIZE));
00067 }
00068
00069
00070
00071
00072
00073 public ClassParser(String zip_file, String file_name) throws IOException
00074 {
00075 is_zip = true;
00076 zip = new ZipFile(zip_file);
00077 ZipEntry entry = zip.getEntry(file_name);
00078
00079 this.file_name = file_name;
00080
00081 file = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry),
00082 BUFSIZE));
00083 }
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 public JavaClass parse() throws IOException, ClassFormatError
00096 {
00097
00098
00099 readID();
00100
00101
00102 readVersion();
00103
00104
00105
00106 readConstantPool();
00107
00108
00109 readClassInfo();
00110
00111
00112 readInterfaces();
00113
00114
00115
00116 readFields();
00117
00118
00119 readMethods();
00120
00121
00122 readAttributes();
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 file.close();
00143 if(zip != null)
00144 zip.close();
00145
00146
00147 return new JavaClass(class_name_index, superclass_name_index,
00148 file_name, major, minor, access_flags,
00149 constant_pool, interfaces, fields,
00150 methods, attributes, is_zip? JavaClass.ZIP : JavaClass.FILE);
00151 }
00152
00153
00154
00155
00156
00157 private final void readAttributes() throws IOException, ClassFormatError
00158 {
00159 int attributes_count;
00160
00161 attributes_count = file.readUnsignedShort();
00162 attributes = new Attribute[attributes_count];
00163
00164 for(int i=0; i < attributes_count; i++)
00165 attributes[i] = Attribute.readAttribute(file, constant_pool);
00166 }
00167
00168
00169
00170
00171
00172 private final void readClassInfo() throws IOException, ClassFormatError
00173 {
00174 access_flags = file.readUnsignedShort();
00175
00176
00177
00178
00179 if((access_flags & Constants.ACC_INTERFACE) != 0)
00180 access_flags |= Constants.ACC_ABSTRACT;
00181
00182 if(((access_flags & Constants.ACC_ABSTRACT) != 0) &&
00183 ((access_flags & Constants.ACC_FINAL) != 0 ))
00184 throw new ClassFormatError("Class can't be both final and abstract");
00185
00186 class_name_index = file.readUnsignedShort();
00187 superclass_name_index = file.readUnsignedShort();
00188 }
00189
00190
00191
00192
00193
00194 private final void readConstantPool() throws IOException, ClassFormatError
00195 {
00196 constant_pool = new ConstantPool(file);
00197 }
00198
00199
00200
00201
00202
00203 private final void readFields() throws IOException, ClassFormatError
00204 {
00205 int fields_count;
00206
00207 fields_count = file.readUnsignedShort();
00208 fields = new Field[fields_count];
00209
00210 for(int i=0; i < fields_count; i++)
00211 fields[i] = new Field(file, constant_pool);
00212 }
00213
00214
00215
00216
00217
00218
00219
00220
00221 private final void readID() throws IOException, ClassFormatError
00222 {
00223 int magic = 0xCAFEBABE;
00224
00225 if(file.readInt() != magic)
00226 throw new ClassFormatError(file_name + " is not a Java .class file");
00227 }
00228
00229
00230
00231
00232
00233 private final void readInterfaces() throws IOException, ClassFormatError
00234 {
00235 int interfaces_count;
00236
00237 interfaces_count = file.readUnsignedShort();
00238 interfaces = new int[interfaces_count];
00239
00240 for(int i=0; i < interfaces_count; i++)
00241 interfaces[i] = file.readUnsignedShort();
00242 }
00243
00244
00245
00246
00247
00248 private final void readMethods() throws IOException, ClassFormatError
00249 {
00250 int methods_count;
00251
00252 methods_count = file.readUnsignedShort();
00253 methods = new Method[methods_count];
00254
00255 for(int i=0; i < methods_count; i++)
00256 methods[i] = new Method(file, constant_pool);
00257 }
00258
00259
00260
00261
00262
00263 private final void readVersion() throws IOException, ClassFormatError
00264 {
00265 minor = file.readUnsignedShort();
00266 major = file.readUnsignedShort();
00267 }
00268 }