KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > sli > kim > classfile > ClassFileWriter


1 package sli.kim.classfile;
2
3 import java.util.*;
4 import java.io.*;
5
6 /**
7 * This class gets information from a ClassInfo and writes it out in the
8 * java classfile format.
9 *
10 * @see ClassInfo
11 */

12 public class ClassFileWriter {
13     /**
14     * Write a ClassInfo out to a stream in the java classfile format.
15     * @throws ClassFileWriteException if there is incorrect or missing
16     * information in the ClassInfo.
17     * @throws IOException if the OutputStream throws an IOException.
18     */

19     public void write(ClassInfo classInfo, OutputStream out)
20         throws IOException, ClassFileWriteException
21     {
22         ConstPool cp = classInfo.getConstPool();
23         if (cp == null)
24             cp = new ConstPool();
25         // do a dry run to make sure ConstPool has all the entries it needs.
26
boolean debugEnabled = Debug.isEnabled();
27         Debug.setEnabled(false);
28         writeClass(cp, classInfo, new NullOutputStream());
29         Debug.setEnabled(debugEnabled);
30         // now do the real write
31
BufferedOutputStream bos = new BufferedOutputStream(out);
32         DataOutputStream dos = new DataOutputStream(bos);
33         writeClass(cp, classInfo, dos);
34         dos.flush(); dos.close();
35         bos.flush(); bos.close();
36     }
37
38     private void writeClass(ConstPool cp, ClassInfo classInfo, DataOutput out)
39         throws IOException, ClassFileWriteException
40     {
41         out.writeInt(0xCAFEBABE);
42         out.writeInt(0x0003002D);
43
44         cp.write(out);
45
46         // General Class Info
47
{
48             short flags = classInfo.getAccessFlags();
49             short classIndex = cp.getIndexOfClassAdd(classInfo.getName());
50             short superClassIndex = cp.getIndexOfClassAdd(classInfo.getSuperClassName());
51
52             if (Debug.writeClass != null) Debug.println(Debug.writeClass,
53                 "flags=" + flags +
54                 "; class index=" + classIndex +
55                 "; super class index=" + superClassIndex);
56
57             out.writeShort(flags);
58             out.writeShort(classIndex);
59             out.writeShort(superClassIndex);
60         }
61
62         // Interfaces
63
String JavaDoc[] interfaces = classInfo.getInterfaces();
64         if (Debug.writeClass != null) Debug.println(Debug.writeClass,
65             "#interfaces=" + interfaces.length);
66         Debug.indent();
67             out.writeShort(interfaces.length);
68             for (int i = 0; i < interfaces.length; i++)
69                 writeInterface(interfaces[i], cp, out);
70         Debug.outdent();
71
72         // Fields
73
FieldInfo[] fields = classInfo.getFields();
74         if (Debug.writeClass != null) Debug.println(Debug.writeClass,
75             "#fields=" + fields.length);
76         Debug.indent();
77             out.writeShort(fields.length);
78             for (int i = 0; i < fields.length; i++)
79                 writeField(fields[i], cp, out);
80         Debug.outdent();
81
82         // Methods
83
MethodInfo[] methods = classInfo.getMethods();
84         if (Debug.writeClass != null) Debug.println(Debug.writeClass,
85             "#methods=" + methods.length);
86         Debug.indent();
87             out.writeShort(methods.length);
88             for (int i = 0; i < methods.length; i++)
89                 writeMethod(methods[i], cp, out);
90         Debug.outdent();
91
92         // Attributes
93
AttributeInfo[] attributes = classInfo.getAttributes();
94         String JavaDoc sourceFile = classInfo.getSourceFile();
95         InnerClassInfo[] innerClasses = classInfo.getInnerClasses();
96         int numAttributes = attributes.length + (sourceFile != null ? 1 : 0) +
97             (innerClasses != null ? 1 : 0);
98
99         if (Debug.writeClass != null) Debug.println(Debug.writeClass,
100             "#attributes=" + numAttributes);
101         Debug.indent();
102
103         out.writeShort(numAttributes);
104
105         // SourceFile Attribute
106
if (sourceFile != null)
107             writeSourceFile(sourceFile, cp, out);
108
109         // InnerClasses Attribute
110
if (innerClasses != null)
111             writeInnerClasses(innerClasses, cp, out);
112
113         // Other Attributes
114
writeUnknownAttributes(attributes, cp, out);
115
116         Debug.outdent();
117     }
118
119     private void writeInterface(String JavaDoc className, ConstPool cp, DataOutput out)
120         throws IOException
121     {
122         short classIndex = cp.getIndexOfClassAdd(className);
123         if (Debug.writeInterface != null) Debug.println(Debug.writeInterface,
124             "class index=" + classIndex);
125         out.writeShort(classIndex);
126     }
127
128     private void writeField(FieldInfo fieldInfo, ConstPool cp, DataOutput out)
129         throws IOException, ClassFileWriteException
130     {
131         // General Field Info
132
{
133             short flags = fieldInfo.getAccessFlags();
134             short nameIndex = cp.getIndexOfUTFAdd(fieldInfo.getName());
135             short signatureIndex = cp.getIndexOfUTFAdd(fieldInfo.getSignature());
136
137             if (Debug.writeField != null) Debug.println(Debug.writeField,
138                 "flags=" + flags +
139                 "; name index=" + nameIndex +
140                 "; signature index=" + signatureIndex);
141
142             out.writeShort(flags);
143             out.writeShort(nameIndex);
144             out.writeShort(signatureIndex);
145         }
146         
147         // Field Attributes
148
AttributeInfo[] attributes = fieldInfo.getAttributes();
149         Object JavaDoc constValue = fieldInfo.getConstantValue();
150         int numAttributes = (constValue != null ? 1 : 0) + attributes.length;
151
152         if (Debug.writeField != null) Debug.println(Debug.writeField,
153             "#attributes=" + numAttributes);
154         Debug.indent();
155
156         out.writeShort((short)numAttributes);
157
158         // ConstantValue Attribute
159
if (constValue != null)
160             writeConstantValue(constValue, cp, out);
161
162         // Synthetic Attribute
163
if (fieldInfo.isSynthetic()) {
164             writeAttributeNameIndex("Synthetic", Debug.writeField, cp, out);
165             out.writeInt(0); // length == 0
166
}
167
168         // Other Attributes
169
writeUnknownAttributes(fieldInfo.getAttributes(), cp, out);
170
171         Debug.outdent();
172     }
173
174     private void writeMethod(MethodInfo methodInfo, ConstPool cp,
175         DataOutput out) throws IOException
176     {
177         // General Method Info
178
{
179             short flags = methodInfo.getAccessFlags();
180             short nameIndex = cp.getIndexOfUTFAdd(methodInfo.getName());
181             short signatureIndex = cp.getIndexOfUTFAdd(methodInfo.getSignature());
182
183             if (Debug.writeMethod != null) Debug.println(Debug.writeMethod,
184                 "flags=" + flags +
185                 "; name index=" + nameIndex +
186                 "; signature index=" + signatureIndex);
187
188             out.writeShort(flags);
189             out.writeShort(nameIndex);
190             out.writeShort(signatureIndex);
191         }
192
193         // Method Attributes
194
AttributeInfo[] methodAttributes = methodInfo.getAttributes();
195         String JavaDoc[] exceptions = methodInfo.getExceptions();
196         boolean deprecated = methodInfo.isDeprecated();
197         if (exceptions.length == 0)
198             exceptions = null;
199         CodeInfo codeInfo = methodInfo.getCodeInfo();
200         int numAttributes = (exceptions != null ? 1 : 0) + (codeInfo != null ? 1 : 0) +
201             (deprecated ? 1 : 0) + methodAttributes.length;
202
203         if (Debug.writeMethod != null) Debug.println(Debug.writeMethod,
204             "#attributes=" + numAttributes);
205         Debug.indent();
206
207         out.writeShort((short)numAttributes);
208
209         // Exceptions Attribute
210
if (exceptions != null)
211             writeExceptions(exceptions, cp, out);
212
213         // Code Attribute
214
if (codeInfo != null)
215             writeCode(codeInfo, cp, out);
216
217         // Deprecated Attribute
218
if (deprecated) {
219             writeAttributeNameIndex("Deprecated", Debug.writeMethod, cp, out);
220             out.writeInt(0); // length == 0
221
}
222
223         // Other Method Attributes
224
writeUnknownAttributes(methodAttributes, cp, out);
225
226         Debug.outdent();
227     }
228
229     private void writeCode(CodeInfo codeInfo, ConstPool cp, DataOutput out)
230         throws IOException
231     {
232         writeAttributeNameIndex("Code", Debug.writeMethod, cp, out);
233         out = new LengthFirstOS(out);
234
235         // General Code Info
236
{
237             short maxStack = codeInfo.getMaxStack();
238             short maxLocals = codeInfo.getMaxLocals();
239             byte[] bytecode = codeInfo.getBytecode();
240
241             if (Debug.writeCode != null) Debug.println(Debug.writeCode,
242                 "maxStack=" + maxStack +
243                 "; maxLocals=" + maxLocals +
244                 "; bytecode length=" + bytecode.length);
245
246             out.writeShort(maxStack);
247             out.writeShort(maxLocals);
248             out.writeInt(bytecode.length);
249             out.write(bytecode);
250         }
251
252         // Exception Table
253
ExceptionInfo[] exceptionTable = codeInfo.getExceptionTable();
254
255         if (Debug.writeCode != null) Debug.println(Debug.writeCode,
256             "exception table length=" + exceptionTable.length);
257         Debug.indent();
258
259         out.writeShort(exceptionTable.length);
260         for (int i = 0; i < exceptionTable.length; i++) {
261             short startPC = exceptionTable[i].startPC;
262             short endPC = exceptionTable[i].endPC;
263             short handlerPC = exceptionTable[i].handlerPC;
264             String JavaDoc catchType = exceptionTable[i].catchType;
265             short catchTypeIndex = 0;
266             if (catchType != null) // catch type is null for finally blocks
267
cp.getIndexOfClassAdd(exceptionTable[i].catchType);
268
269             if (Debug.writeCode != null) Debug.println(Debug.writeCode,
270                 "startPC = " + startPC +
271                 "; endPC = " + endPC +
272                 "; handlerPC = " + handlerPC +
273                 "; catch type index=" + catchTypeIndex);
274
275             out.writeShort(startPC);
276             out.writeShort(endPC);
277             out.writeShort(handlerPC);
278             out.writeShort(catchTypeIndex);
279         }
280
281         Debug.outdent();
282
283         // Code Attributes
284
AttributeInfo[] codeAttributes = codeInfo.getAttributes();
285         LineNumberInfo[] lineNumberTable = codeInfo.getLineNumberTable();
286         LocalVariableInfo[] localVariableTable = codeInfo.getLocalVariableTable();
287         int numCodeAttributes = (lineNumberTable != null ? 1 : 0) +
288             (localVariableTable != null ? 1 : 0) + codeAttributes.length;
289
290         if (Debug.writeCode != null) Debug.println(Debug.writeCode,
291             "#attributes=" + numCodeAttributes);
292         Debug.indent();
293
294         out.writeShort(numCodeAttributes);
295
296         // LineNumberTable Attribute
297
if (lineNumberTable != null)
298             writeLineNumberTable(lineNumberTable, cp, out);
299
300         // LocalVariableTable Attribute
301
if (localVariableTable != null)
302             writeLocalVariableTable(localVariableTable, cp, out);
303
304         // Other Code Attributes
305
writeUnknownAttributes(codeAttributes, cp, out);
306         ((LengthFirstOS)out).close();
307
308         Debug.outdent();
309     }
310
311     private void writeSourceFile(String JavaDoc filename, ConstPool cp, DataOutput out)
312         throws IOException
313     {
314         writeAttributeNameIndex("SourceFile", Debug.writeClass, cp, out);
315
316         out.writeInt(2); // length of attribute
317
short filenameIndex = cp.getIndexOfUTFAdd(filename);
318
319         Debug.indent();
320         if (Debug.writeClass != null) Debug.println(Debug.writeClass,
321             "source file index=" + filenameIndex);
322         Debug.outdent();
323
324         out.writeShort(filenameIndex);
325     }
326
327     private void writeConstantValue(Object JavaDoc constValue, ConstPool cp, DataOutput out)
328         throws IOException, ClassFileWriteException
329     {
330         writeAttributeNameIndex("ConstantValue", Debug.writeField, cp, out);
331         out = new LengthFirstOS(out);
332         ConstPoolEntry searchEntry = new ConstPoolEntry();
333         if (constValue instanceof String JavaDoc)
334             searchEntry.setString(cp.getIndexOfUTFAdd((String JavaDoc)constValue));
335         else if (constValue instanceof Integer JavaDoc)
336             searchEntry.setInt(((Integer JavaDoc)constValue).intValue());
337         else if (constValue instanceof Long JavaDoc)
338             searchEntry.setLong(((Long JavaDoc)constValue).longValue());
339         else if (constValue instanceof Float JavaDoc)
340             searchEntry.setFloat(((Float JavaDoc)constValue).floatValue());
341         else if (constValue instanceof Double JavaDoc)
342             searchEntry.setDouble(((Double JavaDoc)constValue).doubleValue());
343         else
344             throw new ClassFileWriteException("Unrecognized constant value " + constValue);
345         short cvIndex = cp.getIndexOfEntryAdd(searchEntry);
346
347         Debug.indent();
348         if (Debug.writeField != null) Debug.println(Debug.writeField,
349             "constant value index=" + cvIndex);
350         Debug.outdent();
351
352         out.writeShort(cvIndex);
353         ((LengthFirstOS)out).close();
354     }
355
356     private void writeExceptions(String JavaDoc[] exceptions, ConstPool cp,
357         DataOutput out) throws IOException
358     {
359         writeAttributeNameIndex("Exceptions", Debug.writeMethod, cp, out);
360         out = new LengthFirstOS(out);
361
362         if (Debug.writeMethod != null) Debug.println(Debug.writeMethod,
363             "#exceptions=" + exceptions.length);
364         Debug.indent();
365
366         out.writeShort(exceptions.length);
367         for (int i = 0; i < exceptions.length; i++) {
368             short classIndex = cp.getIndexOfClassAdd(exceptions[i]);
369
370             if (Debug.writeMethod != null) Debug.println(Debug.writeMethod,
371                 "exception class index = " + classIndex);
372
373             out.writeShort(classIndex);
374         }
375
376         Debug.outdent();
377
378         ((LengthFirstOS)out).close();
379     }
380
381     private void writeLocalVariableTable(LocalVariableInfo[] localVariableTable,
382         ConstPool cp, DataOutput out) throws IOException
383     {
384         writeAttributeNameIndex("LocalVariableTable", Debug.writeCode, cp, out);
385         out = new LengthFirstOS(out);
386
387         Debug.indent();
388         if (Debug.writeLocalVariables != null) Debug.println(Debug.writeLocalVariables,
389             "#local variables=" + localVariableTable.length);
390
391         out.writeShort(localVariableTable.length);
392         for (int i = 0; i < localVariableTable.length; i++) {
393             short startPC = localVariableTable[i].startPC;
394             short length = localVariableTable[i].length;
395             short nameIndex = cp.getIndexOfUTFAdd(localVariableTable[i].name);
396             short signatureIndex = cp.getIndexOfUTFAdd(localVariableTable[i].signature);
397             short slot = localVariableTable[i].slot;
398
399             if (Debug.writeLocalVariables != null) Debug.println(Debug.writeLocalVariables,
400                 "startPC=" + startPC +
401                 "; length=" + length +
402                 "; nameIndex=" + nameIndex +
403                 "; signatureIndex=" + signatureIndex +
404                 "; slot=" + slot);
405
406             out.writeShort(startPC);
407             out.writeShort(length);
408             out.writeShort(nameIndex);
409             out.writeShort(signatureIndex);
410             out.writeShort(slot);
411         }
412         ((LengthFirstOS)out).close();
413
414         Debug.outdent();
415     }
416
417     private void writeLineNumberTable(LineNumberInfo[] lineNumberTable,
418         ConstPool cp, DataOutput out) throws IOException
419     {
420         writeAttributeNameIndex("LineNumberTable", Debug.writeCode, cp, out);
421         out = new LengthFirstOS(out);
422
423         Debug.indent();
424         if (Debug.writeLineNumbers != null) Debug.println(Debug.writeLineNumbers,
425             "#line numbers=" + lineNumberTable.length);
426
427         out.writeShort(lineNumberTable.length);
428         for (int i = 0; i < lineNumberTable.length; i++) {
429             short startPC = lineNumberTable[i].startPC;
430             short lineNumber = lineNumberTable[i].lineNumber;
431
432             if (Debug.writeLineNumbers != null) Debug.println(Debug.writeLineNumbers,
433                 "startPC=" + startPC +
434                 "; lineNumber=" + lineNumber);
435
436             out.writeShort(startPC);
437             out.writeShort(lineNumber);
438         }
439         ((LengthFirstOS)out).close();
440
441         Debug.outdent();
442     }
443
444     private void writeInnerClasses(InnerClassInfo[] innerClasses, ConstPool cp,
445         DataOutput out) throws IOException
446     {
447         writeAttributeNameIndex("InnerClasses", Debug.writeClass, cp, out);
448         out = new LengthFirstOS(out);
449
450         Debug.indent();
451         if (Debug.writeInnerClasses != null) Debug.println(Debug.writeInnerClasses,
452             "#inner classes=" + innerClasses.length);
453
454         out.writeShort(innerClasses.length);
455         for (int i = 0; i < innerClasses.length; i++) {
456             short innerClassIndex = cp.getIndexOfClassAdd(innerClasses[i].innerClass);
457             short outerClassIndex = 0;
458             if (innerClasses[i].outerClass != null) // can be null if non-member class
459
outerClassIndex = cp.getIndexOfClassAdd(innerClasses[i].outerClass);
460             short simpleNameIndex = 0;
461             if (innerClasses[i].simpleName != null) // can be null if anonymous class
462
simpleNameIndex = cp.getIndexOfUTFAdd(innerClasses[i].simpleName);
463             short flags = innerClasses[i].flags;
464
465             if (Debug.writeInnerClasses != null) Debug.println(Debug.writeInnerClasses,
466                 "inner class index=" + innerClassIndex +
467                 "; outer class index=" + outerClassIndex +
468                 "; simple name index=" + simpleNameIndex +
469                 "; flags=" + flags);
470
471             out.writeShort(innerClassIndex);
472             out.writeShort(outerClassIndex);
473             out.writeShort(simpleNameIndex);
474             out.writeShort(flags);
475         }
476         ((LengthFirstOS)out).close();
477
478         Debug.outdent();
479     }
480
481     private void writeAttributeNameIndex(String JavaDoc attrName, String JavaDoc debugMsg,
482         ConstPool cp, DataOutput out) throws IOException
483     {
484         short index = cp.getIndexOfUTFAdd(attrName);
485
486         if (debugMsg != null) Debug.println(debugMsg,
487             "attribute name index=" + index);
488
489         out.writeShort(index);
490     }
491
492     private void writeUnknownAttributes(AttributeInfo[] attributes,
493         ConstPool cp, DataOutput out) throws IOException
494     {
495         for (int i = 0; i < attributes.length; i++) {
496             short attrNameIndex = cp.getIndexOfUTFAdd(attributes[i].getName());
497             byte[] data = attributes[i].getData();
498
499             if (Debug.writeUnknownAttribute != null) Debug.println(Debug.writeUnknownAttribute,
500                 "attribute name index=" + attrNameIndex +
501                 "; attribute length=" + data.length);
502
503             out.writeShort(attrNameIndex);
504             out.writeInt(data.length);
505             out.write(data);
506         }
507     }
508 }
509
510 // Special output stream to help with writing attributes.
511
// When we write attributes, we need to know the size of the entire
512
// attribute before we write its data, and figuring that out can be
513
// awkward. This class acts like an output stream, but it stores all
514
// output into a byte array, and when closed, it writes out the size of
515
// the stored data followed by the data itself.
516
class LengthFirstOS implements DataOutput {
517     DataOutput realOut;
518     ByteArrayOutputStream baos = new ByteArrayOutputStream();
519     DataOutputStream dos = new DataOutputStream(baos);
520
521     public LengthFirstOS(DataOutput realOut) {
522         this.realOut = realOut;
523     }
524     public void write(byte b[]) throws IOException {
525         dos.write(b);
526     }
527     public void write(byte b[], int off, int len) throws IOException {
528         dos.write(b, off, len);
529     }
530     public void write(int b) throws IOException {
531         dos.write(b);
532     }
533     public void writeBoolean(boolean v) throws IOException {
534         dos.writeBoolean(v);
535     }
536     public void writeByte(int v) throws IOException {
537         dos.writeByte(v);
538     }
539     public void writeBytes(String JavaDoc s) throws IOException {
540         dos.writeBytes(s);
541     }
542     public void writeChar(int v) throws IOException {
543         dos.writeChar(v);
544     }
545     public void writeChars(String JavaDoc s) throws IOException {
546         dos.writeChars(s);
547     }
548     public void writeDouble(double v) throws IOException {
549         dos.writeDouble(v);
550     }
551     public void writeFloat(float v) throws IOException {
552         dos.writeFloat(v);
553     }
554     public void writeInt(int v) throws IOException {
555         dos.writeInt(v);
556     }
557     public void writeLong(long v) throws IOException {
558         dos.writeLong(v);
559     }
560     public void writeShort(int v) throws IOException {
561         dos.writeShort(v);
562     }
563     public void writeUTF(String JavaDoc str) throws IOException {
564         dos.writeUTF(str);
565     }
566     public void close() throws IOException {
567         dos.flush(); dos.close();
568         baos.flush(); baos.close();
569         byte[] data = baos.toByteArray();
570         realOut.writeInt((short)data.length);
571         realOut.write(data);
572     }
573 }
574
Popular Tags