001: // Copyright (c) 1997 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.bytecode;
005:
006: import java.io.InputStream;
007: import java.io.DataInputStream;
008: import java.io.IOException;
009: import java.io.FileInputStream;
010:
011: /** Class to read a ClassType from a DataInputStream (.class file).
012: * @author Per Bothner
013: */
014:
015: public class ClassFileInput extends DataInputStream {
016: ClassType ctype;
017: InputStream str;
018:
019: public ClassFileInput(InputStream str) throws IOException {
020: super (str);
021: }
022:
023: public ClassFileInput(ClassType ctype, InputStream str)
024: throws IOException, ClassFormatError {
025: super (str);
026: this .ctype = ctype;
027: if (!readHeader())
028: throw new ClassFormatError("invalid magic number");
029: ctype.constants = readConstants();
030: readClassInfo();
031: readFields();
032: readMethods();
033: readAttributes(ctype);
034: }
035:
036: /** Read a class (in .class format) from an InputStream.
037: * @return A new ClassType object representing the class that was read.
038: */
039: public static ClassType readClassType(InputStream str)
040: throws IOException, ClassFormatError {
041: ClassType ctype = new ClassType();
042: ClassFileInput reader = new ClassFileInput(ctype, str);
043: return ctype;
044: }
045:
046: /** Read a class of a known name (in .class format) from an InputStream.
047: * @return A ClassType object representing the class that was read.
048: */
049: public static ClassType readClassType(String name, InputStream str)
050: throws IOException, ClassFormatError {
051: // Try to see if the class is already known.
052: ClassType ctype = ClassType.make(name);
053:
054: /*
055: If the class existed but was empty (constants == null),
056: we use that same ClassType object. This is important since
057: two different ClassType objects for the same class would be
058: incomparable.
059: On the other hand, if the class was already read from a file,
060: we create a new ClassType object, so that we don't add members
061: to an existing class.
062: */
063: if (ctype.constants != null) {
064: ctype = new ClassType(name);
065: Type.registerTypeForName(name, ctype);
066: ctype.collectable = true;
067: }
068:
069: // Read the class from the file.
070: new ClassFileInput(ctype, str);
071:
072: return ctype;
073: }
074:
075: public boolean readHeader() throws IOException {
076: int magic = readInt();
077: if (magic != 0xcafebabe)
078: return false;
079: short minor_version = readShort();
080: short major_version = readShort();
081: return true;
082: }
083:
084: public ConstantPool readConstants() throws IOException {
085: return new ConstantPool(this );
086: }
087:
088: public void readClassInfo() throws IOException {
089: ctype.access_flags = readUnsignedShort();
090: CpoolClass clas;
091: String name;
092:
093: ctype.this ClassIndex = readUnsignedShort();
094: clas = (CpoolClass) ctype.constants.getForced(
095: ctype.this ClassIndex, ConstantPool.CLASS);
096: name = clas.name.string;
097: ctype.this _name = name.replace('/', '.');
098: ctype.setSignature("L" + name + ";");
099:
100: ctype.super ClassIndex = readUnsignedShort();
101: if (ctype.super ClassIndex == 0)
102: ctype.setSuper((ClassType) null);
103: else {
104: clas = (CpoolClass) ctype.constants.getForced(
105: ctype.super ClassIndex, ConstantPool.CLASS);
106: name = clas.name.string;
107: ctype.setSuper(name.replace('/', '.'));
108: }
109:
110: int nInterfaces = readUnsignedShort();
111: if (nInterfaces > 0) {
112: ctype.interfaces = new ClassType[nInterfaces];
113: ctype.interfaceIndexes = new int[nInterfaces];
114: for (int i = 0; i < nInterfaces; i++) {
115: int index = readUnsignedShort();
116: ctype.interfaceIndexes[i] = index;
117: clas = (CpoolClass) ctype.constants.getForced(index,
118: ConstantPool.CLASS);
119: name = clas.name.string.replace('/', '.');
120: ctype.interfaces[i] = ClassType.make(name);
121: }
122: }
123: }
124:
125: public int readAttributes(AttrContainer container)
126: throws IOException {
127: int count = readUnsignedShort();
128: Attribute last = container.getAttributes();
129: for (int i = 0; i < count; i++) {
130: if (last != null) {
131: for (;;) {
132: Attribute next = last.getNext();
133: if (next == null)
134: break;
135: last = next;
136: }
137: }
138:
139: int index = readUnsignedShort();
140: CpoolUtf8 nameConstant = (CpoolUtf8) ctype.constants
141: .getForced(index, ConstantPool.UTF8);
142: int length = readInt();
143: nameConstant.intern();
144: Attribute attr = readAttribute(nameConstant.string, length,
145: container);
146: if (attr != null) {
147: attr.setContainer(container);
148: if (attr.getNameIndex() == 0)
149: attr.setNameIndex(index);
150: if (last == null)
151: container.setAttributes(attr);
152: else {
153: if (container.getAttributes() == attr) { /* Move to end. */
154: container.setAttributes(attr.getNext());
155: attr.setNext(null);
156: }
157: last.setNext(attr);
158: }
159: last = attr;
160: }
161: }
162: return count;
163: }
164:
165: public final void skipAttribute(int length) throws IOException {
166: int read = 0;
167: while (read < length) {
168: int skipped = (int) skip(length - read);
169: if (skipped == 0) {
170: if (read() < 0)
171: throw new java.io.EOFException(
172: "EOF while reading class files attributes");
173: skipped = 1;
174: }
175: read += skipped;
176: }
177: }
178:
179: public Attribute readAttribute(String name, int length,
180: AttrContainer container) throws IOException {
181: if (name == "SourceFile" && container instanceof ClassType) {
182: return new SourceFileAttr(readUnsignedShort(),
183: (ClassType) container);
184: } else if (name == "Code" && container instanceof Method) {
185: CodeAttr code = new CodeAttr((Method) container);
186: code.setMaxStack(readUnsignedShort());
187: code.setMaxLocals(readUnsignedShort());
188: int code_len = readInt();
189: byte[] insns = new byte[code_len];
190: readFully(insns);
191: code.setCode(insns);
192: int exception_table_length = readUnsignedShort();
193: for (int i = 0; i < exception_table_length; i++) {
194: int start_pc = readUnsignedShort();
195: int end_pc = readUnsignedShort();
196: int handler_pc = readUnsignedShort();
197: int catch_type = readUnsignedShort();
198: code.addHandler(start_pc, end_pc, handler_pc,
199: catch_type);
200: }
201: readAttributes(code);
202: return code;
203: } else if (name == "LineNumberTable"
204: && container instanceof CodeAttr) {
205: int count = 2 * readUnsignedShort();
206: short[] numbers = new short[count];
207: for (int i = 0; i < count; i++) {
208: numbers[i] = readShort();
209: }
210: return new LineNumbersAttr(numbers, (CodeAttr) container);
211: } else if (name == "LocalVariableTable"
212: && container instanceof CodeAttr) {
213: LocalVarsAttr attr = new LocalVarsAttr((CodeAttr) container);
214: Method method = attr.getMethod();
215: if (attr.parameter_scope == null)
216: attr.parameter_scope = method.pushScope();
217: Scope scope = attr.parameter_scope;
218: ConstantPool constants = method.getConstants();
219: int count = readUnsignedShort();
220: for (int i = 0; i < count; i++) {
221: Variable var = new Variable();
222: scope.addVariable(var);
223: var.start_pc = readUnsignedShort();
224: var.end_pc = var.start_pc + readUnsignedShort();
225: var.setName(readUnsignedShort(), constants);
226: var.setSignature(readUnsignedShort(), constants);
227: var.offset = readUnsignedShort();
228: }
229: return attr;
230: } else if (name == "ConstantValue"
231: && container instanceof Field) {
232: return new ConstantValueAttr(readUnsignedShort());
233: } else if (name == "InnerClasses"
234: && container instanceof ClassType) {
235: int count = 4 * readUnsignedShort();
236: short[] data = new short[count];
237: for (int i = 0; i < count; i++) {
238: data[i] = readShort();
239: }
240: return new InnerClassesAttr(data, (ClassType) container);
241: } else if (name == "Exceptions" && container instanceof Method) {
242: Method meth = (Method) container;
243: int count = readUnsignedShort();
244: short[] exn_indices = new short[count];
245: for (int i = 0; i < count; ++i)
246: exn_indices[i] = readShort();
247: meth.setExceptions(exn_indices);
248: return meth.getExceptionAttr();
249: } else {
250: byte[] data = new byte[length];
251: readFully(data, 0, length);
252: return new MiscAttr(name, data);
253: }
254: }
255:
256: public void readFields() throws IOException {
257: if ((ctype.flags & ctype.ADD_FIELDS_DONE) != 0)
258: return;
259: ctype.flags |= ctype.ADD_FIELDS_DONE;
260: int nFields = readUnsignedShort();
261: ConstantPool constants = ctype.constants;
262: for (int i = 0; i < nFields; i++) {
263: int flags = readUnsignedShort();
264: int nameIndex = readUnsignedShort();
265: int descriptorIndex = readUnsignedShort();
266: Field fld = ctype.addField();
267: fld.setName(nameIndex, constants);
268: fld.setSignature(descriptorIndex, constants);
269: fld.flags = flags;
270: readAttributes(fld);
271: }
272: }
273:
274: public void readMethods() throws IOException {
275: if ((ctype.flags & ctype.ADD_METHODS_DONE) != 0)
276: return;
277: ctype.flags |= ctype.ADD_METHODS_DONE;
278: int nMethods = readUnsignedShort();
279: ConstantPool constants = ctype.constants;
280: for (int i = 0; i < nMethods; i++) {
281: int flags = readUnsignedShort();
282: int nameIndex = readUnsignedShort();
283: int descriptorIndex = readUnsignedShort();
284: Method meth = ctype.addMethod(null, flags);
285: meth.setName(nameIndex);
286: meth.setSignature(descriptorIndex);
287: readAttributes(meth);
288: }
289: }
290: }
|