001:
002:package sli.kim.classfile;
003:
004:import java.io.*;
005:
006:/**
007:* This class parses java class files and stores the information in a ClassInfo object.
008:*
009:* @see ClassInfo
010:*/
011:public class ClassFileReader implements AccessFlags {
012: /**
013: * Read in and parse a java class file.
014: *
015: * @param in a DataInput stream to read in the class file.
016: * @param classInfo a ClassInfo to consume the class information.
017: * @throws ClassFileParseException if the class file is corrupt.
018: * @throws IOException if the InputStream throws an IOException.
019: */
020: public void read(InputStream in, ClassInfo classInfo)
021: throws ClassFileParseException, IOException
022: {
023: readClass(new DataInputStream(new BufferedInputStream(in)), classInfo);
024: }
025:
026: private void readClass(DataInput in, ClassInfo classInfo)
027: throws ClassFileParseException, IOException
028: {
029: short count;
030:
031: // Magic And Version Numbers
032: {
033: int magic = in.readInt();
034: if (magic != 0xCAFEBABE)
035: throw new ClassFileParseException("Invalid classfile magic number" +
036: ": expected 0xCAFEBABE, found 0x" + Integer.toHexString(magic));
037: short major = in.readShort(), minor = in.readShort();
038: // assume we can handle changes to the minor version number
039: if (major != 0x003)
040: throw new ClassFileParseException("Unrecognized classfile version " +
041: major + "." + minor);
042: }
043:
044: // Constant Pool
045: ConstPool cp = new ConstPool();
046: cp.read(in);
047: classInfo.setConstPool(cp);
048:
049: // General Class Info
050: {
051: short flags = in.readShort();
052: short classIndex = in.readShort();
053: short super ClassIndex = in.readShort();
054: short classNameIndex = cp.getEntryAtIndex(classIndex).getClassNameIndex();
055: short super ClassNameIndex = cp.getEntryAtIndex(super ClassIndex).getClassNameIndex();
056: String className = cp.getEntryAtIndex(classNameIndex).getString();
057: String super ClassName = cp.getEntryAtIndex(super ClassNameIndex).getString();
058:
059: if (Debug.readClass != null) Debug.println(Debug.readClass,
060: "flags=" + flags +
061: "; class index=" + classIndex +
062: "; super class index=" + super ClassIndex);
063:
064: classInfo.setAccessFlags(flags);
065: classInfo.setName(className);
066: classInfo.setSuperClassName(super ClassName);
067: }
068:
069: // Interfaces
070: count = in.readShort();
071: if (Debug.readClass != null) Debug.println(Debug.readClass,
072: "#interfaces=" + count);
073: Debug.indent();
074: for (int i = 0; i < count; i++)
075: classInfo.addInterface(readInterface(cp, in));
076: Debug.outdent();
077:
078: // Fields
079: count = in.readShort();
080: if (Debug.readClass != null) Debug.println(Debug.readClass,
081: "#fields=" + count);
082: Debug.indent();
083: for (int i = 0; i < count; i++)
084: classInfo.addField(readField(cp, in));
085: Debug.outdent();
086:
087: // Methods
088: count = in.readShort();
089: if (Debug.readClass != null) Debug.println(Debug.readClass,
090: "#methods=" + count);
091: Debug.indent();
092: for (int i = 0; i < count; i++)
093: classInfo.addMethod(readMethod(cp, in));
094: Debug.outdent();
095:
096: // Attributes
097: count = in.readShort();
098: if (Debug.readClass != null) Debug.println(Debug.readClass,
099: "#attributes=" + count);
100: Debug.indent();
101: for (int i = 0; i < count; i++)
102: readClassAttribute(classInfo, cp, in);
103: Debug.outdent();
104: }
105:
106: private String readInterface(ConstPool cp, DataInput in)
107: throws IOException
108: {
109: short classIndex = in.readShort();
110: if (Debug.readInterface != null) Debug.println(Debug.readInterface,
111: "class index=" + classIndex);
112: short nameIndex = cp.getEntryAtIndex(classIndex).getClassNameIndex();
113: return cp.getEntryAtIndex(nameIndex).getString();
114: }
115:
116: private FieldInfo readField(ConstPool cp, DataInput in)
117: throws ClassFileParseException, IOException
118: {
119: FieldInfo result;
120:
121: // General Field Info
122: {
123: short flags = in.readShort();
124: short nameIndex = in.readShort();
125: short signatureIndex = in.readShort();
126:
127: if (Debug.readField != null) Debug.println(Debug.readField,
128: "flags=" + flags +
129: "; name index=" + nameIndex +
130: "; signature index=" + signatureIndex);
131:
132: result = new FieldInfo(flags, cp.getEntryAtIndex(nameIndex).getString(),
133: cp.getEntryAtIndex(signatureIndex).getString());
134: }
135:
136: // Field Attributes
137: short numAttributes = in.readShort();
138: if (Debug.readField != null) Debug.println(Debug.readField,
139: "#attributes=" + numAttributes);
140: Debug.indent();
141: for (int i = 0; i < numAttributes; i++)
142: readFieldAttribute(result, cp, in);
143: Debug.outdent();
144:
145: return result;
146: }
147:
148: private MethodInfo readMethod(ConstPool cp, DataInput in)
149: throws ClassFileParseException, IOException
150: {
151: MethodInfo result;
152:
153: // General Method Info
154: {
155: short flags = in.readShort();
156: short nameIndex = in.readShort();
157: short signatureIndex = in.readShort();
158: String methodName = cp.getEntryAtIndex(nameIndex).getString();
159: String methodSignature = cp.getEntryAtIndex(signatureIndex).getString();
160:
161: if (Debug.readMethod != null) Debug.println(Debug.readMethod,
162: "flags=" + flags +
163: "; name index=" + nameIndex +
164: "; signature index=" + signatureIndex);
165:
166: result = new MethodInfo(flags, methodName, methodSignature);
167: }
168:
169: // Method Attributes
170: short methodAttrCount = in.readShort();
171: if (Debug.readMethod != null) Debug.println(Debug.readMethod,
172: "#attributes=" + methodAttrCount);
173: Debug.indent();
174:
175: for (int iMethodAttr = 0; iMethodAttr < methodAttrCount; iMethodAttr++)
176: readMethodAttribute(result, cp, in);
177:
178: Debug.outdent();
179:
180: return result;
181: }
182:
183: private void readClassAttribute(ClassInfo classInfo, ConstPool cp,
184: DataInput in) throws IOException
185: {
186: short nameIndex = in.readShort();
187: int length = in.readInt();
188:
189: // make sure we read the entire attribute -- if it has bad data,
190: // an exception might get thrown before we've read it all
191: byte[] bytes = new byte[length];
192: in.readFully(bytes);
193: in = new DataInputStream(new ByteArrayInputStream(bytes));
194:
195: if (Debug.readClass != null) Debug.println(Debug.readClass,
196: "attribute name index=" + nameIndex +
197: "; length=" + length);
198: Debug.indent();
199:
200: try {
201:
202: String name = cp.getEntryAtIndex(nameIndex).getString();
203:
204: // SourceFile Attribute
205: if (name.equals("SourceFile")) {
206: short filenameIndex = in.readShort();
207: if (Debug.readClass != null) Debug.println(Debug.readClass,
208: "filename index=" + filenameIndex);
209: classInfo.setSourceFile(cp.getEntryAtIndex(filenameIndex).getString());
210: }
211:
212: else if (name.equals("InnerClasses"))
213: classInfo.setInnerClasses(readInnerClasses(cp, in));
214:
215: else
216: classInfo.addAttribute(readUnknownAttribute(name, length, in));
217:
218: } catch (ConstPoolEntryError e) {
219: if (Debug.readBadData != null) Debug.println(Debug.readBadData,
220: "class attribute name index=" + nameIndex);
221: }
222:
223: Debug.outdent();
224: }
225:
226: private void readFieldAttribute(FieldInfo fieldInfo, ConstPool cp,
227: DataInput in) throws IOException
228: {
229: short nameIndex = in.readShort();
230: String name = cp.getEntryAtIndex(nameIndex).getString();
231: int length = in.readInt();
232:
233: // make sure we read the entire attribute -- if it has bad data,
234: // an exception might get thrown before we've read it all
235: byte[] bytes = new byte[length];
236: in.readFully(bytes);
237: in = new DataInputStream(new ByteArrayInputStream(bytes));
238:
239: if (Debug.readField != null) Debug.println(Debug.readField,
240: "attribute name index=" + nameIndex +
241: "; length=" + length);
242: Debug.indent();
243:
244: try {
245:
246: // ConstantValue Attribute
247: if (name.equals("ConstantValue")) {
248: short cvIndex = in.readShort();
249: if (Debug.readField != null) Debug.println(Debug.readField,
250: "constant value index=" + cvIndex);
251: fieldInfo.setConstantValue(cp.getEntryAtIndex(cvIndex).getPrimitiveTypeValue());
252: }
253:
254: else if (name.equals("Synthetic")) {
255: if (Debug.readField != null) Debug.println(Debug.readField,
256: "synthetic");
257: fieldInfo.setSynthetic(true);
258: }
259:
260: else
261: fieldInfo.addAttribute(readUnknownAttribute(name, length, in));
262:
263: } catch (ConstPoolEntryError e) {
264: if (Debug.readBadData != null) Debug.println(Debug.readBadData,
265: "field attribute name index=" + nameIndex);
266: }
267:
268: Debug.outdent();
269: }
270:
271: private void readMethodAttribute(MethodInfo methodInfo, ConstPool cp,
272: DataInput in) throws IOException
273: {
274: short nameIndex = in.readShort();
275: int length = in.readInt();
276:
277: // make sure we read the entire attribute -- if it has bad data,
278: // an exception might get thrown before we've read it all
279: byte[] bytes = new byte[length];
280: in.readFully(bytes);
281: in = new DataInputStream(new ByteArrayInputStream(bytes));
282:
283: if (Debug.readMethod != null) Debug.println(Debug.readMethod,
284: "attribute name index=" + nameIndex +
285: "; length=" + length);
286: Debug.indent();
287:
288: try {
289:
290: String name = cp.getEntryAtIndex(nameIndex).getString();
291: if (name.equals("Exceptions")) {
292: int count = in.readShort();
293: for (int i = 0; i < count; i++) {
294: short exceptionClassIndex = in.readShort();
295: short exceptionClassNameIndex = cp.getEntryAtIndex(exceptionClassIndex).getClassNameIndex();
296: String exceptionName = cp.getEntryAtIndex(exceptionClassNameIndex). getString();
297: methodInfo.addException(exceptionName);
298: }
299: }
300:
301: else if (name.equals("Code"))
302: methodInfo.setCodeInfo(readCode(cp, in));
303:
304: else if (name.equals("Deprecated")) {
305: if (Debug.readMethod != null) Debug.println(Debug.readMethod,
306: "deprecated");
307: methodInfo.setDeprecated(true);
308: }
309:
310: else
311: methodInfo.addAttribute(readUnknownAttribute(name, length, in));
312:
313: } catch (ConstPoolEntryError e) {
314: if (Debug.readBadData != null) Debug.println(Debug.readBadData,
315: "method attribute name index=" + nameIndex);
316: }
317:
318: Debug.outdent();
319: }
320:
321: private CodeInfo readCode(ConstPool cp, DataInput in)
322: throws IOException
323: {
324: // General Code Info
325: short maxStack = in.readShort();
326: short maxLocals = in.readShort();
327: byte[] bytecode = new byte[in.readInt()];
328:
329: if (Debug.readCode != null) Debug.println(Debug.readCode,
330: "maxStack=" + maxStack +
331: "; maxLocals=" + maxLocals +
332: "; bytecode length=" + bytecode.length);
333:
334: in.readFully(bytecode);
335:
336: // Exception Table
337: ExceptionInfo[] exceptionTable = new ExceptionInfo[in.readShort()];
338: if (Debug.readCode != null) Debug.println(Debug.readCode,
339: "exception table length=" + exceptionTable.length);
340: Debug.indent();
341: for (int i = 0; i < exceptionTable.length; i++) {
342: short startPC = in.readShort();
343: short endPC = in.readShort();
344: short handlerPC = in.readShort();
345: short catchTypeIndex = in.readShort();
346:
347: if (Debug.readCode != null) Debug.println(Debug.readCode,
348: "startPC=" + startPC +
349: "; endPC=" + endPC +
350: "; handlerPC=" + handlerPC +
351: "; catchTypeIndex=" + catchTypeIndex);
352:
353: String catchType = null;
354: if (catchTypeIndex != 0) { // index is null for finally blocks
355: short catchTypeNameIndex =
356: cp.getEntryAtIndex(catchTypeIndex).getClassNameIndex();
357: catchType = cp.getEntryAtIndex(catchTypeNameIndex).getString();
358: }
359: exceptionTable[i] =
360: new ExceptionInfo(startPC, endPC, handlerPC, catchType);
361: }
362: Debug.outdent();
363:
364: CodeInfo codeInfo =
365: new CodeInfo(maxStack, maxLocals, bytecode, exceptionTable);
366:
367: // Code Attributes
368: short codeAttrCount = in.readShort();
369: if (Debug.readCode != null) Debug.println(Debug.readCode,
370: "#attributes=" + codeAttrCount);
371: Debug.indent();
372: for (int iCodeAttr = 0; iCodeAttr < codeAttrCount; iCodeAttr++)
373: readCodeAttribute(codeInfo, cp, in);
374: Debug.outdent();
375:
376: return codeInfo;
377: }
378:
379: private void readCodeAttribute(CodeInfo codeInfo, ConstPool cp,
380: DataInput in) throws IOException
381: {
382: short nameIndex = in.readShort();
383: int length = in.readInt();
384:
385: // make sure we read the entire attribute -- if it has bad data,
386: // an exception might get thrown before we've read it all
387: byte[] bytes = new byte[length];
388: in.readFully(bytes);
389: in = new DataInputStream(new ByteArrayInputStream(bytes));
390:
391: if (Debug.readCode != null) Debug.println(Debug.readCode,
392: "code attribute name index=" + nameIndex +
393: "; length=" + length);
394: Debug.indent();
395:
396: try {
397:
398: String name = cp.getEntryAtIndex(nameIndex).getString();
399: if (name.equals("LineNumberTable"))
400: codeInfo.setLineNumberTable(readLineNumberTable(in));
401: else if (name.equals("LocalVariableTable"))
402: codeInfo.setLocalVariableTable(readLocalVariableTable(cp, in));
403: else
404: codeInfo.addAttribute(readUnknownAttribute(name, length, in));
405:
406: } catch (ConstPoolEntryError e) {
407: if (Debug.readBadData != null) Debug.println(Debug.readBadData,
408: "code attribute name index=" + nameIndex);
409: }
410:
411: Debug.outdent();
412: }
413:
414: private InnerClassInfo[] readInnerClasses(ConstPool cp, DataInput in)
415: throws IOException
416: {
417: short rows = in.readShort();
418: if (Debug.readInnerClasses != null) Debug.println(Debug.readInnerClasses,
419: "#inner classes=" + rows);
420: InnerClassInfo[] classes = new InnerClassInfo[rows];
421: for (int i = 0; i < rows; i++) {
422: short innerClassIndex = in.readShort();
423: short outerClassIndex = in.readShort();
424: short simpleNameIndex = in.readShort();
425: short flags = in.readShort();
426:
427: if (Debug.readInnerClasses != null) Debug.println(Debug.readInnerClasses,
428: "inner class index=" + innerClassIndex +
429: "; outer class index=" + outerClassIndex +
430: "; simple name index=" + simpleNameIndex +
431: "; flags=" + flags);
432:
433: short innerClassNameIndex = cp.getEntryAtIndex(innerClassIndex).getClassNameIndex();
434: String innerClassName = cp.getEntryAtIndex(innerClassNameIndex).getString();
435: String outerClassName = null;
436: if (outerClassIndex != 0) {
437: short outerClassNameIndex = cp.getEntryAtIndex(outerClassIndex).getClassNameIndex();
438: outerClassName = cp.getEntryAtIndex(outerClassNameIndex).getString();
439: }
440: String simpleName = null;
441: if (simpleNameIndex != 0)
442: simpleName = cp.getEntryAtIndex(simpleNameIndex).getString();
443:
444: classes[i] = new InnerClassInfo(innerClassName, outerClassName, simpleName, flags);
445: }
446: return classes;
447: }
448:
449: private LocalVariableInfo[] readLocalVariableTable(ConstPool cp, DataInput in)
450: throws IOException
451: {
452: LocalVariableInfo[] table = new LocalVariableInfo[in.readShort()];
453: if (Debug.readLocalVariables != null) Debug.println(Debug.readLocalVariables,
454: "#local variables=" + table.length);
455: for (int i = 0; i < table.length; i++) {
456: short startPC = in.readShort();
457: short length = in.readShort();
458: short nameIndex = in.readShort();
459: short signatureIndex = in.readShort();
460: short slot= in.readShort();
461: if (Debug.readLocalVariables != null) Debug.println(Debug.readLocalVariables,
462: "start PC=" + startPC +
463: "; length=" + length +
464: "; name index=" + nameIndex +
465: "; signature index=" + signatureIndex +
466: "; slot=" + slot);
467:
468: String name = cp.getEntryAtIndex(nameIndex).getString();
469: String signature = cp.getEntryAtIndex(signatureIndex).getString();
470: table[i] = new LocalVariableInfo(startPC, length, name, signature, slot);
471: }
472: return table;
473: }
474:
475: private LineNumberInfo[] readLineNumberTable(DataInput in)
476: throws IOException
477: {
478: LineNumberInfo[] table = new LineNumberInfo[in.readShort()];
479: if (Debug.readLineNumbers != null) Debug.println(Debug.readLineNumbers,
480: "#line numbers=" + table.length);
481: for (int i = 0; i < table.length; i++) {
482: short startPC = in.readShort();
483: short lineNumber = in.readShort();
484:
485: if (Debug.readLineNumbers != null) Debug.println(Debug.readLineNumbers,
486: "start PC=" + startPC +
487: "; line number=" + lineNumber);
488:
489: table[i] = new LineNumberInfo(startPC, lineNumber);
490: }
491: return table;
492: }
493:
494: private AttributeInfo readUnknownAttribute(String name, int length, DataInput in)
495: throws IOException
496: {
497: if (Debug.readUnknownAttribute != null) Debug.println(Debug.readUnknownAttribute,
498: "attribute name=\"" + name + "\"");
499: byte[] data = new byte[length];
500: in.readFully(data);
501: return new AttributeInfo(name, data);
502: }
503:}
504:
|