001: /*
002: * Copyright 2004 Brian S O'Neill
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.cojen.classfile;
018:
019: import java.io.PrintWriter;
020:
021: import org.cojen.classfile.constant.ConstantClassInfo;
022: import org.cojen.classfile.constant.ConstantDoubleInfo;
023: import org.cojen.classfile.constant.ConstantFieldInfo;
024: import org.cojen.classfile.constant.ConstantFloatInfo;
025: import org.cojen.classfile.constant.ConstantIntegerInfo;
026: import org.cojen.classfile.constant.ConstantInterfaceMethodInfo;
027: import org.cojen.classfile.constant.ConstantLongInfo;
028: import org.cojen.classfile.constant.ConstantMethodInfo;
029: import org.cojen.classfile.constant.ConstantNameAndTypeInfo;
030: import org.cojen.classfile.constant.ConstantStringInfo;
031:
032: /**
033: * Disassembles a ClassFile into a Java source file, which when run, produces
034: * the original class.
035: *
036: * @author Brian S O'Neill
037: */
038: class BuilderStylePrinter implements DisassemblyTool.Printer {
039: private PrintWriter mOut;
040:
041: private int mIndent = 0;
042: private boolean mNeedIndent = true;
043:
044: public BuilderStylePrinter() {
045: }
046:
047: public void disassemble(ClassFile cf, PrintWriter out) {
048: mOut = out;
049:
050: println("import java.io.BufferedOutputStream;");
051: println("import java.io.File;");
052: println("import java.io.FileOutputStream;");
053: println("import java.io.OutputStream;");
054: println();
055: println("import org.cojen.classfile.ClassFile;");
056: println("import org.cojen.classfile.CodeBuilder;");
057: println("import org.cojen.classfile.FieldInfo;");
058: println("import org.cojen.classfile.Label;");
059: println("import org.cojen.classfile.LocalVariable;");
060: println("import org.cojen.classfile.Location;");
061: println("import org.cojen.classfile.MethodInfo;");
062: println("import org.cojen.classfile.Modifiers;");
063: println("import org.cojen.classfile.Opcode;");
064: println("import org.cojen.classfile.TypeDesc;");
065:
066: disassemble(cf, (String) null);
067: }
068:
069: private void disassemble(ClassFile cf, String innerClassSuffix) {
070: println();
071: if (innerClassSuffix == null) {
072: println("/**");
073: println(" * Builds ClassFile for " + cf.getClassName());
074: println(" *");
075: println(" * @author auto-generated");
076: println(" */");
077: println("public class ClassFileBuilder {");
078: } else {
079: println("/**");
080: println(" * Builds ClassFile for " + cf.getClassName());
081: println(" */");
082: println("private static class InnerBuilder"
083: + innerClassSuffix + " {");
084: }
085: mIndent += 4;
086:
087: if (innerClassSuffix == null) {
088: println("public static void main(String[] args) throws Exception {");
089: mIndent += 4;
090: println("// " + cf);
091: println("ClassFile cf = createClassFile();");
092:
093: println();
094: println("if (args.length > 0) {");
095: mIndent += 4;
096: println("File file = new File(args[0]);");
097: println("if (file.isDirectory()) {");
098: mIndent += 4;
099: println("writeClassFiles(cf, file);");
100: mIndent -= 4;
101: println("} else {");
102: mIndent += 4;
103: println("OutputStream out = new BufferedOutputStream(new FileOutputStream(file));");
104: println("cf.writeTo(out);");
105: println("out.close();");
106: mIndent -= 4;
107: println("}");
108: mIndent -= 4;
109: println("}");
110: mIndent -= 4;
111: println("}");
112:
113: println();
114: println("private static void writeClassFiles(ClassFile cf, File dir) throws Exception {");
115: mIndent += 4;
116: println("File file = new File(dir, cf.getClassName().replace('.', '/') + \".class\");");
117: println("file.getParentFile().mkdirs();");
118: println("OutputStream out = new BufferedOutputStream(new FileOutputStream(file));");
119: println("cf.writeTo(out);");
120: println("out.close();");
121:
122: println();
123: println("ClassFile[] innerClasses = cf.getInnerClasses();");
124: println("for (int i=0; i<innerClasses.length; i++) {");
125: mIndent += 4;
126: println("writeClassFiles(innerClasses[i], dir);");
127: mIndent -= 4;
128: println("}");
129: mIndent -= 4;
130: println("}");
131:
132: println();
133: }
134:
135: if (innerClassSuffix == null) {
136: println("public static ClassFile createClassFile() {");
137: mIndent += 4;
138: println("ClassFile cf = new ClassFile(\""
139: + escape(cf.getClassName()) + "\", \""
140: + escape(cf.getSuperClassName()) + "\");");
141: } else {
142: println("static ClassFile createClassFile(ClassFile cf) {");
143: mIndent += 4;
144: }
145:
146: if (cf.getTarget() != null) {
147: println("cf.setTarget(\"" + escape(cf.getTarget()) + "\");");
148: }
149: println("cf.setSourceFile(\"" + escape(cf.getSourceFile())
150: + "\");");
151:
152: if (cf.isSynthetic()) {
153: println("cf.markSynthetic();");
154: }
155: if (cf.isDeprecated()) {
156: println("cf.markDeprecated();");
157: }
158:
159: if (!cf.getModifiers().equals(Modifiers.PUBLIC)) {
160: print("cf.setModifiers(");
161: printModifiers(cf);
162: println(");");
163: }
164:
165: String[] interfaces = cf.getInterfaces();
166: for (int i = 0; i < interfaces.length; i++) {
167: println("cf.addInterface(\"" + escape(interfaces[i])
168: + "\");");
169: }
170:
171: if (cf.getInitializer() != null) {
172: println();
173: println("createStaticInitializer(cf);");
174: }
175:
176: FieldInfo[] fields = cf.getFields();
177: boolean createdFieldVariable = false;
178:
179: for (int i = 0; i < fields.length; i++) {
180: if (i == 0) {
181: println();
182: println("//");
183: println("// Create fields");
184: println("//");
185: }
186:
187: println();
188:
189: FieldInfo fi = fields[i];
190: if (fi.isSynthetic() || fi.isDeprecated()
191: || fi.getConstantValue() != null) {
192: if (!createdFieldVariable) {
193: print("FieldInfo ");
194: createdFieldVariable = true;
195: }
196: print("fi = ");
197: }
198:
199: print("cf.addField(");
200: printModifiers(fi);
201: print(", ");
202: print('\"' + escape(fi.getName()) + "\", ");
203: print(fi.getType());
204: println(");");
205:
206: if (fi.getConstantValue() != null) {
207: ConstantInfo constant = fi.getConstantValue();
208: print("fi.setConstantValue(");
209: if (constant instanceof ConstantStringInfo) {
210: print("\"");
211: String value = ((ConstantStringInfo) constant)
212: .getValue();
213: print(escape(value));
214: print("\"");
215: } else if (constant instanceof ConstantIntegerInfo) {
216: print(String
217: .valueOf(((ConstantIntegerInfo) constant)
218: .getValue()));
219: } else if (constant instanceof ConstantLongInfo) {
220: print(String.valueOf(((ConstantLongInfo) constant)
221: .getValue()));
222: print("L");
223: } else if (constant instanceof ConstantFloatInfo) {
224: float value = ((ConstantFloatInfo) constant)
225: .getValue();
226: if (value != value) {
227: print("0.0f/0.0f");
228: } else if (value == Float.NEGATIVE_INFINITY) {
229: print("-1.0f/0.0f");
230: } else if (value == Float.POSITIVE_INFINITY) {
231: print("1.0f/0.0f");
232: } else {
233: print(String.valueOf(value));
234: print("f");
235: }
236: } else if (constant instanceof ConstantDoubleInfo) {
237: double value = ((ConstantDoubleInfo) constant)
238: .getValue();
239: if (value != value) {
240: print("0.0d/0.0d");
241: } else if (value == Float.NEGATIVE_INFINITY) {
242: print("-1.0d/0.0d");
243: } else if (value == Float.POSITIVE_INFINITY) {
244: print("1.0d/0.0d");
245: } else {
246: print(String.valueOf(value));
247: print("d");
248: }
249: }
250: println(");");
251: }
252: if (fi.isSynthetic()) {
253: println("fi.markSynthetic();");
254: }
255: if (fi.isDeprecated()) {
256: println("fi.markDeprecated();");
257: }
258: }
259:
260: MethodInfo[] methods = cf.getConstructors();
261: for (int i = 0; i < methods.length; i++) {
262: if (i == 0) {
263: println();
264: println("//");
265: println("// Create constructors");
266: println("//");
267: }
268: println();
269: println("// " + methods[i]);
270: println("createConstructor_" + (i + 1) + "(cf);");
271: }
272:
273: methods = cf.getMethods();
274: for (int i = 0; i < methods.length; i++) {
275: if (i == 0) {
276: println();
277: println("//");
278: println("// Create methods");
279: println("//");
280: }
281:
282: println();
283: println("// " + methods[i]);
284: println("createMethod_" + (i + 1) + "(cf);");
285: }
286:
287: final ClassFile[] innerClasses = cf.getInnerClasses();
288:
289: for (int i = 0; i < innerClasses.length; i++) {
290: if (i == 0) {
291: println();
292: println("//");
293: println("// Create inner classes");
294: println("//");
295: }
296:
297: println();
298: println("// " + innerClasses[i]);
299:
300: if (i == 0) {
301: print("ClassFile ");
302: }
303: print("innerClass = ");
304: String name = innerClasses[i].getClassName();
305: String innerName = innerClasses[i].getInnerClassName();
306: if (innerName != null) {
307: if ((cf.getClassName() + '$' + innerName).equals(name)) {
308: name = null;
309: }
310: innerName = '"' + escape(innerName) + '"';
311: }
312: if (name != null) {
313: name = '"' + escape(name) + '"';
314: }
315: println("cf.addInnerClass(" + name + ", " + innerName
316: + ", \""
317: + escape(innerClasses[i].getSuperClassName())
318: + "\");");
319: String suffix = "_" + (i + 1);
320: if (innerClassSuffix != null) {
321: suffix = innerClassSuffix + suffix;
322: }
323: println("InnerBuilder" + suffix
324: + ".createClassFile(innerClass);");
325: }
326:
327: println();
328: println("return cf;");
329:
330: mIndent -= 4;
331: println("}");
332:
333: if (cf.getInitializer() != null) {
334: println();
335: println("private static void createStaticInitializer(ClassFile cf) {");
336: mIndent += 4;
337: disassemble(cf.getInitializer());
338: mIndent -= 4;
339: println("}");
340: }
341:
342: methods = cf.getConstructors();
343: for (int i = 0; i < methods.length; i++) {
344: println();
345: println("// " + methods[i]);
346: println("private static void createConstructor_" + (i + 1)
347: + "(ClassFile cf) {");
348: mIndent += 4;
349: disassemble(methods[i]);
350: mIndent -= 4;
351: println("}");
352: }
353:
354: methods = cf.getMethods();
355: for (int i = 0; i < methods.length; i++) {
356: println();
357: println("// " + methods[i]);
358: println("private static void createMethod_" + (i + 1)
359: + "(ClassFile cf) {");
360: mIndent += 4;
361: disassemble(methods[i]);
362: mIndent -= 4;
363: println("}");
364: }
365:
366: for (int i = 0; i < innerClasses.length; i++) {
367: String suffix = "_" + (i + 1);
368: if (innerClassSuffix != null) {
369: suffix = innerClassSuffix + suffix;
370: }
371: disassemble(innerClasses[i], suffix);
372: }
373:
374: mIndent -= 4;
375: println("}");
376: }
377:
378: private void disassemble(MethodInfo mi) {
379: print("MethodInfo mi = cf.add");
380:
381: if (mi.getName().equals("<clinit>")) {
382: println("Initializer();");
383: } else if (mi.getName().equals("<init>")) {
384: print("Constructor(");
385: printModifiers(mi);
386: print(", ");
387: print(mi.getMethodDescriptor().getParameterTypes());
388: println(");");
389: } else {
390: print("Method(");
391: printModifiers(mi);
392: print(", ");
393: print("\"" + escape(mi.getName()) + "\", ");
394: print(mi.getMethodDescriptor().getReturnType());
395: print(", ");
396: print(mi.getMethodDescriptor().getParameterTypes());
397: println(");");
398: }
399:
400: if (mi.isSynthetic()) {
401: println("mi.markSynthetic();");
402: }
403: if (mi.isDeprecated()) {
404: println("mi.markDeprecated();");
405: }
406: TypeDesc[] exceptions = mi.getExceptions();
407: for (int j = 0; j < exceptions.length; j++) {
408: print("mi.addException(");
409: print(exceptions[j]);
410: println(");");
411: }
412:
413: if (mi.getCodeAttr() != null) {
414: println("CodeBuilder b = new CodeBuilder(mi);");
415: println();
416:
417: TypeDesc[] paramTypes = mi.getMethodDescriptor()
418: .getParameterTypes();
419: boolean isStatic = mi.getModifiers().isStatic();
420: String indentStr = generateIndent(mIndent);
421:
422: new CodeDisassembler(mi)
423: .disassemble(new CodeAssemblerPrinter(paramTypes,
424: isStatic, mOut, indentStr, ";", "b."));
425: }
426: }
427:
428: private String escape(String str) {
429: return CodeAssemblerPrinter.escape(str);
430: }
431:
432: private void printModifiers(ClassFile cf) {
433: printModifiers(cf.getModifiers());
434: }
435:
436: private void printModifiers(FieldInfo fi) {
437: printModifiers(fi.getModifiers());
438: }
439:
440: private void printModifiers(MethodInfo mi) {
441: printModifiers(mi.getModifiers());
442: }
443:
444: private void printModifiers(Modifiers modifiers) {
445: print("Modifiers.");
446:
447: if (modifiers.isPublic()) {
448: if (modifiers.isAbstract()) {
449: print("PUBLIC_ABSTRACT");
450: modifiers = modifiers.toAbstract(false);
451: } else if (modifiers.isStatic()) {
452: print("PUBLIC_STATIC");
453: modifiers = modifiers.toStatic(false);
454: } else {
455: print("PUBLIC");
456: }
457: modifiers = modifiers.toPublic(false);
458: } else if (modifiers.isProtected()) {
459: print("PROTECTED");
460: modifiers = modifiers.toProtected(false);
461: } else if (modifiers.isPrivate()) {
462: print("PRIVATE");
463: modifiers = modifiers.toPrivate(false);
464: } else {
465: print("NONE");
466: }
467:
468: if (modifiers.isStatic()) {
469: print(".toStatic(true)");
470: }
471: if (modifiers.isFinal()) {
472: print(".toFinal(true)");
473: }
474: if (modifiers.isSynchronized()) {
475: print(".toSynchronized(true)");
476: }
477: if (modifiers.isVolatile()) {
478: print(".toVolatile(true)");
479: }
480: if (modifiers.isTransient()) {
481: print(".toTransient(true)");
482: }
483: if (modifiers.isNative()) {
484: print(".toNative(true)");
485: }
486: if (modifiers.isInterface()) {
487: print(".toInterface(true)");
488: }
489: if (modifiers.isAbstract() && !modifiers.isInterface()) {
490: print(".toAbstract(true)");
491: }
492: if (modifiers.isStrict()) {
493: print(".toStrict(true)");
494: }
495: }
496:
497: private void print(TypeDesc type) {
498: if (type == null || type == TypeDesc.VOID) {
499: print("null");
500: return;
501: }
502:
503: if (type.isPrimitive()) {
504: print("TypeDesc.".concat(type.getFullName().toUpperCase()));
505: return;
506: } else if (type == TypeDesc.OBJECT) {
507: print("TypeDesc.OBJECT");
508: return;
509: } else if (type == TypeDesc.STRING) {
510: print("TypeDesc.STRING");
511: return;
512: }
513:
514: TypeDesc componentType = type.getComponentType();
515: if (componentType != null) {
516: print(componentType);
517: print(".toArrayType()");
518: } else {
519: print("TypeDesc.forClass(\"");
520: print(escape(type.getRootName()));
521: print("\")");
522: }
523: }
524:
525: private void print(TypeDesc[] params) {
526: if (params == null || params.length == 0) {
527: print("null");
528: return;
529: }
530:
531: print("new TypeDesc[] {");
532:
533: for (int i = 0; i < params.length; i++) {
534: if (i > 0) {
535: print(", ");
536: }
537: print(params[i]);
538: }
539:
540: print("}");
541: }
542:
543: private void print(String text) {
544: indent();
545: mOut.print(text);
546: }
547:
548: private void println(String text) {
549: print(text);
550: println();
551: }
552:
553: private void println() {
554: mOut.println();
555: mNeedIndent = true;
556: }
557:
558: private void indent() {
559: if (mNeedIndent) {
560: for (int i = mIndent; --i >= 0;) {
561: mOut.print(' ');
562: }
563: mNeedIndent = false;
564: }
565: }
566:
567: private String generateIndent(int amount) {
568: StringBuffer buf = new StringBuffer(amount);
569: for (int i = 0; i < amount; i++) {
570: buf.append(' ');
571: }
572: return buf.toString();
573: }
574: }
|