1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.bcel.internal.util;
  23 
  24 import com.sun.org.apache.bcel.internal.classfile.*;
  25 import com.sun.org.apache.bcel.internal.generic.*;
  26 import com.sun.org.apache.bcel.internal.Repository;
  27 import com.sun.org.apache.bcel.internal.Constants;
  28 import java.io.*;
  29 
  30 /**
  31  * This class takes a given JavaClass object and converts it to a
  32  * Java program that creates that very class using BCEL. This
  33  * gives new users of BCEL a useful example showing how things
  34  * are done with BCEL. It does not cover all features of BCEL,
  35  * but tries to mimic hand-written code as close as possible.
  36  *
  37  * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  38  */
  39 public class BCELifier extends com.sun.org.apache.bcel.internal.classfile.EmptyVisitor {
  40   private JavaClass         _clazz;
  41   private PrintWriter       _out;
  42   private ConstantPoolGen   _cp;
  43 
  44   /** @param clazz Java class to "decompile"
  45    * @param out where to output Java program
  46    */
  47   public BCELifier(JavaClass clazz, OutputStream out) {
  48     _clazz = clazz;
  49     _out = new PrintWriter(out);
  50     _cp = new ConstantPoolGen(_clazz.getConstantPool());
  51   }
  52 
  53   /** Start Java code generation
  54    */
  55   public void start() {
  56     visitJavaClass(_clazz);
  57     _out.flush();
  58   }
  59 
  60   public void visitJavaClass(JavaClass clazz) {
  61     String class_name   = clazz.getClassName();
  62     String super_name   = clazz.getSuperclassName();
  63     String package_name = clazz.getPackageName();
  64     String inter        = Utility.printArray(clazz.getInterfaceNames(),
  65                                              false, true);
  66     if(!"".equals(package_name)) {
  67       class_name = class_name.substring(package_name.length() + 1);
  68       _out.println("package " + package_name + ";\n");
  69      }
  70 
  71     _out.println("import com.sun.org.apache.bcel.internal.generic.*;");
  72     _out.println("import com.sun.org.apache.bcel.internal.classfile.*;");
  73     _out.println("import com.sun.org.apache.bcel.internal.*;");
  74     _out.println("import java.io.*;\n");
  75 
  76     _out.println("public class " + class_name + "Creator implements Constants {");
  77     _out.println("  private InstructionFactory _factory;");
  78     _out.println("  private ConstantPoolGen    _cp;");
  79     _out.println("  private ClassGen           _cg;\n");
  80 
  81     _out.println("  public " + class_name  + "Creator() {");
  82     _out.println("    _cg = new ClassGen(\"" +
  83                  (("".equals(package_name))? class_name :
  84                   package_name + "." + class_name) +
  85                  "\", \"" + super_name + "\", " +
  86                  "\"" + clazz.getSourceFileName() + "\", " +
  87                  printFlags(clazz.getAccessFlags(), true) + ", " +
  88                  "new String[] { " + inter + " });\n");
  89 
  90     _out.println("    _cp = _cg.getConstantPool();");
  91     _out.println("    _factory = new InstructionFactory(_cg, _cp);");
  92     _out.println("  }\n");
  93 
  94     printCreate();
  95 
  96     Field[] fields = clazz.getFields();
  97 
  98     if(fields.length > 0) {
  99       _out.println("  private void createFields() {");
 100       _out.println("    FieldGen field;");
 101 
 102       for(int i=0; i < fields.length; i++) {
 103         fields[i].accept(this);
 104       }
 105 
 106       _out.println("  }\n");
 107     }
 108 
 109     Method[] methods = clazz.getMethods();
 110 
 111     for(int i=0; i < methods.length; i++) {
 112       _out.println("  private void createMethod_" + i + "() {");
 113 
 114       methods[i].accept(this);
 115       _out.println("  }\n");
 116     }
 117 
 118     printMain();
 119     _out.println("}");
 120   }
 121 
 122   private void printCreate() {
 123     _out.println("  public void create(OutputStream out) throws IOException {");
 124 
 125     Field[] fields = _clazz.getFields();
 126     if(fields.length > 0) {
 127       _out.println("    createFields();");
 128     }
 129 
 130     Method[] methods = _clazz.getMethods();
 131     for(int i=0; i < methods.length; i++) {
 132       _out.println("    createMethod_" + i + "();");
 133     }
 134 
 135     _out.println("    _cg.getJavaClass().dump(out);");
 136 
 137     _out.println("  }\n");
 138   }
 139 
 140   private void printMain() {
 141     String   class_name   = _clazz.getClassName();
 142 
 143     _out.println("  public static void _main(String[] args) throws Exception {");
 144     _out.println("    " + class_name + "Creator creator = new " +
 145                  class_name + "Creator();");
 146     _out.println("    creator.create(new FileOutputStream(\"" + class_name +
 147                  ".class\"));");
 148     _out.println("  }");
 149   }
 150 
 151   public void visitField(Field field) {
 152     _out.println("\n    field = new FieldGen(" +
 153                  printFlags(field.getAccessFlags()) +
 154                  ", " + printType(field.getSignature()) + ", \"" +
 155                  field.getName() + "\", _cp);");
 156 
 157     ConstantValue cv = field.getConstantValue();
 158 
 159     if(cv != null) {
 160       String value = cv.toString();
 161       _out.println("    field.setInitValue(" + value + ")");
 162     }
 163 
 164     _out.println("    _cg.addField(field.getField());");
 165   }
 166 
 167   public void visitMethod(Method method) {
 168     MethodGen mg = new MethodGen(method, _clazz.getClassName(), _cp);
 169 
 170     Type   result_type = mg.getReturnType();
 171     Type[] arg_types   = mg.getArgumentTypes();
 172 
 173     _out.println("    InstructionList il = new InstructionList();");
 174     _out.println("    MethodGen method = new MethodGen(" +
 175                  printFlags(method.getAccessFlags()) +
 176                  ", " + printType(result_type) +
 177                  ", " + printArgumentTypes(arg_types) + ", " +
 178                  "new String[] { " +
 179                  Utility.printArray(mg.getArgumentNames(), false, true) +
 180                  " }, \"" + method.getName() + "\", \"" +
 181                  _clazz.getClassName() + "\", il, _cp);\n");
 182 
 183     BCELFactory factory = new BCELFactory(mg, _out);
 184     factory.start();
 185 
 186     _out.println("    method.setMaxStack();");
 187     _out.println("    method.setMaxLocals();");
 188     _out.println("    _cg.addMethod(method.getMethod());");
 189     _out.println("    il.dispose();");
 190   }
 191 
 192   static String printFlags(int flags) {
 193     return printFlags(flags, false);
 194   }
 195 
 196   static String printFlags(int flags, boolean for_class) {
 197     if(flags == 0)
 198       return "0";
 199 
 200     StringBuffer buf = new StringBuffer();
 201     for(int i=0, pow=1; i <= Constants.MAX_ACC_FLAG; i++) {
 202       if((flags & pow) != 0) {
 203         if((pow == Constants.ACC_SYNCHRONIZED) && for_class)
 204           buf.append("ACC_SUPER | ");
 205         else
 206           buf.append("ACC_" + Constants.ACCESS_NAMES[i].toUpperCase() + " | ");
 207       }
 208 
 209       pow <<= 1;
 210     }
 211 
 212     String str = buf.toString();
 213     return str.substring(0, str.length() - 3);
 214   }
 215 
 216   static String printArgumentTypes(Type[] arg_types) {
 217     if(arg_types.length == 0)
 218       return "Type.NO_ARGS";
 219 
 220     StringBuffer args = new StringBuffer();
 221 
 222     for(int i=0; i < arg_types.length; i++) {
 223       args.append(printType(arg_types[i]));
 224 
 225       if(i < arg_types.length - 1)
 226         args.append(", ");
 227     }
 228 
 229     return "new Type[] { " + args.toString() + " }";
 230   }
 231 
 232   static String printType(Type type) {
 233     return printType(type.getSignature());
 234   }
 235 
 236   static String printType(String signature) {
 237     Type type = Type.getType(signature);
 238     byte t    = type.getType();
 239 
 240     if(t <= Constants.T_VOID) {
 241       return "Type." + Constants.TYPE_NAMES[t].toUpperCase();
 242     } else if(type.toString().equals("java.lang.String")) {
 243       return "Type.STRING";
 244     } else if(type.toString().equals("java.lang.Object")) {
 245       return "Type.OBJECT";
 246     } else if(type.toString().equals("java.lang.StringBuffer")) {
 247       return "Type.STRINGBUFFER";
 248     } else if(type instanceof ArrayType) {
 249       ArrayType at = (ArrayType)type;
 250 
 251       return "new ArrayType(" + printType(at.getBasicType()) +
 252         ", " + at.getDimensions() + ")";
 253     } else {
 254       return "new ObjectType(\"" + Utility.signatureToString(signature, false) +
 255         "\")";
 256     }
 257   }
 258 
 259   /** Default _main method
 260    */
 261   public static void _main(String[] argv) throws Exception {
 262     JavaClass java_class;
 263     String    name = argv[0];
 264 
 265     if((java_class = Repository.lookupClass(name)) == null)
 266       java_class = new ClassParser(name).parse(); // May throw IOException
 267 
 268     BCELifier bcelifier = new BCELifier(java_class, System.out);
 269     bcelifier.start();
 270   }
 271 }