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