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