1 package jp.igapyon.jcfa;
3 import java.io.ByteArrayOutputStream;
5 import java.io.IOException;
7 import jp.igapyon.jcfa.util.JcfaUtil;
8 import jp.igapyon.jcfa.vo.JcfaClass;
9 import jp.igapyon.jcfa.vo.JcfaCode;
10 import jp.igapyon.jcfa.vo.JcfaField;
11 import jp.igapyon.jcfa.vo.JcfaMethod;
12 import jp.igapyon.jcfa.vo.JcfaUnit;
14 import org.apache.bcel.Constants;
15 import org.apache.bcel.classfile.ClassFormatException;
16 import org.apache.bcel.classfile.ClassParser;
17 import org.apache.bcel.classfile.Code;
18 import org.apache.bcel.classfile.ConstantValue;
19 import org.apache.bcel.classfile.Field;
20 import org.apache.bcel.classfile.JavaClass;
21 import org.apache.bcel.classfile.Method;
22 import org.apache.bcel.generic.Type;
24 public class JcfaParser {
25 protected JcfaUnit jcfaUnit = new JcfaUnit();
27 public JcfaUnit parseUnit(final File inputFile, final File outputDir) {
29 final JavaClass jc = new ClassParser(inputFile.getCanonicalPath())
31 final JcfaClass jcfaClass = new JcfaClass();
32 jcfaUnit.getClassList().add(jcfaClass);
34 jcfaClass.setName(jc.getClassName());
35 jcfaClass.setExtendsName(jc.getSuperclassName());
37 jcfaClass.getComment().getCommentList()
38 .add("TODO import func. is missing.");
39 jcfaClass.getComment().setJavaDoc(true);
41 final String[] split = jc.getClassName().split("\\.");
42 File actualyTargetDir = outputDir;
43 if (split.length > 1) {
44 for (int index = 0; index < split.length - 1; index++) {
45 actualyTargetDir = new File(actualyTargetDir, split[index]);
46 actualyTargetDir.mkdirs();
50 parseFields(jc, jcfaClass);
51 parseMethods(jc, jcfaClass);
53 jcfaUnit.setTargetFile(new File(actualyTargetDir,
54 split[split.length - 1] + ".jcfa"));
55 } catch (ClassFormatException e) {
57 } catch (IOException e) {
63 private void parseFields(final JavaClass jc, final JcfaClass jcfaClass) {
64 final org.apache.bcel.classfile.Field[] fields = jc.getFields();
65 for (int indexField = 0; indexField < fields.length; indexField++) {
66 final Field field = fields[indexField];
67 parseField(jc, field, jcfaClass);
71 private void parseField(final JavaClass jc, final Field field,
72 final JcfaClass jcfaClass) {
73 final JcfaField jcfaField = new JcfaField();
74 jcfaField.setName(field.getName());
75 jcfaClass.getFieldList().add(jcfaField);
77 jcfaField.getComment().setJavaDoc(true);
79 // TODO type should be more collect.
80 jcfaField.setType(field.getType().toString());
83 access += field.isPublic() ? "public " : "";
84 access += field.isProtected() ? "protected " : "";
85 access += field.isPrivate() ? "private " : "";
86 access += field.isAbstract() ? "abstract " : "";
87 access += field.isStatic() ? "static " : "";
88 access += field.isVolatile() ? "volatile " : "";
89 access += field.isFinal() ? "final " : "";
90 jcfaField.setAccess(access);
92 final ConstantValue cv = field.getConstantValue();
94 jcfaField.setConstantValue("\""
95 + jc.getConstantPool().getConstantString(
96 cv.getConstantValueIndex(),
97 Constants.CONSTANT_String) + "\"");
102 .add("FIXME other type support is missing. <br />Now only String.");
106 private void parseMethods(final JavaClass jc, final JcfaClass jcfaClass)
108 final org.apache.bcel.classfile.Method[] methods = jc.getMethods();
109 for (int indexMethod = 0; indexMethod < methods.length; indexMethod++) {
110 final Method method = methods[indexMethod];
111 parseMethod(jc, method, jcfaClass);
122 * @throws IOException
124 private void parseMethod(final JavaClass jc, final Method method,
125 final JcfaClass jcfaClass) throws IOException {
126 final JcfaMethod jcfaMethod = new JcfaMethod();
127 jcfaClass.getMethodList().add(jcfaMethod);
129 jcfaMethod.setName(method.getName());
130 jcfaMethod.getComment().setJavaDoc(true);
131 if (jcfaMethod.getName().equals("<init>")) {
132 jcfaMethod.getComment().getCommentList()
133 .add("Default constructor.");
135 jcfaMethod.getComment().getCommentList().add("Method.");
138 for (Type type : method.getArgumentTypes()) {
139 jcfaMethod.getComment().getCommentList().add(type.toString());
140 jcfaMethod.getArugumentTypeList().add(type.toString());
142 jcfaMethod.setType(method.getReturnType().toString());
144 final Code code = method.getCode();
149 final byte[] codes = code.getCode();
150 for (int pc = 0; pc < codes.length; pc++) {
151 final int operands = parseCodes(jc, method, jcfaClass, jcfaMethod,
161 private int parseCodes(final JavaClass jc, final Method method,
162 final JcfaClass jcfaClass, final JcfaMethod jcfaMethod,
163 final int pc, final byte[] codes) throws IOException {
164 final JcfaCode jcfaCode = new JcfaCode();
165 jcfaMethod.getCodeList().add(jcfaCode);
166 jcfaCode.setJavaClass(jc);
168 jcfaCode.setOpcode(JcfaUtil.byte2UnsignedByte(codes[pc]));
169 jcfaCode.getComment()
172 + Constants.OPCODE_NAMES[jcfaCode.getOpcode()]);
174 short operands = Constants.NO_OF_OPERANDS[jcfaCode.getOpcode()];
175 if (operands == Constants.UNPREDICTABLE) {
176 switch (jcfaCode.getOpcode()) {
177 case Constants.TABLESWITCH: {
178 jcfaCode.getComment().getCommentList()
179 .add(" TODO no support opecode and operands");
180 return Constants.UNPREDICTABLE;
182 case Constants.LOOKUPSWITCH: {
183 int result = JcfaUtil.byte2Int(codes[pc + 1], codes[pc + 2],
184 codes[pc + 3], codes[pc + 4]);
185 jcfaCode.getComment().getCommentList()
186 .add(" TODO skipping operands: why?: " + result);
188 int lookupOp = pc + 5;
190 short diff = JcfaUtil.byte2UnsignedByte(codes[lookupOp++]);
192 int loopCount = JcfaUtil
193 .byte2Int(codes[lookupOp++], codes[lookupOp++],
194 codes[lookupOp++], codes[lookupOp++]);
195 // switch table on loopCount.
197 short diff2 = JcfaUtil.byte2UnsignedByte(codes[lookupOp++]);
198 jcfaCode.getComment().getCommentList()
199 .add(" TODO skipping bytes: " + (diff2));
201 operands += (lookupOp - pc);
204 case Constants.WIDE: {
205 jcfaCode.getComment().getCommentList()
206 .add(" TODO no support opecode and operands");
207 return Constants.UNPREDICTABLE;
213 final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
214 outStream.write(codes, pc, operands + 1);
216 jcfaCode.setCodes(outStream.toByteArray());