OSDN Git Service

save
[jcfa/jcfa.git] / jcfa / src / jp / igapyon / jcfa / JcfaParser.java
1 package jp.igapyon.jcfa;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.File;
5 import java.io.IOException;
6
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;
13
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;
23
24 public class JcfaParser {
25         protected JcfaUnit jcfaUnit = new JcfaUnit();
26
27         public JcfaUnit parseUnit(final File inputFile, final File outputDir) {
28                 try {
29                         final JavaClass jc = new ClassParser(inputFile.getCanonicalPath())
30                                         .parse();
31                         final JcfaClass jcfaClass = new JcfaClass();
32                         jcfaUnit.getClassList().add(jcfaClass);
33
34                         jcfaClass.setName(jc.getClassName());
35                         jcfaClass.setExtendsName(jc.getSuperclassName());
36
37                         jcfaClass.getComment().getCommentList()
38                                         .add("TODO import func. is missing.");
39                         jcfaClass.getComment().setJavaDoc(true);
40
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();
47                                 }
48                         }
49
50                         parseFields(jc, jcfaClass);
51                         parseMethods(jc, jcfaClass);
52
53                         jcfaUnit.setTargetFile(new File(actualyTargetDir,
54                                         split[split.length - 1] + ".jcfa"));
55                 } catch (ClassFormatException e) {
56                         e.printStackTrace();
57                 } catch (IOException e) {
58                         e.printStackTrace();
59                 }
60                 return jcfaUnit;
61         }
62
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);
68                 }
69         }
70
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);
76
77                 jcfaField.getComment().setJavaDoc(true);
78
79                 // TODO type should be more collect.
80                 jcfaField.setType(field.getType().toString());
81
82                 String access = "";
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);
91
92                 final ConstantValue cv = field.getConstantValue();
93                 if (cv != null) {
94                         jcfaField.setConstantValue("\""
95                                         + jc.getConstantPool().getConstantString(
96                                                         cv.getConstantValueIndex(),
97                                                         Constants.CONSTANT_String) + "\"");
98
99                         jcfaField
100                                         .getComment()
101                                         .getCommentList()
102                                         .add("FIXME other type support is missing. <br />Now only String.");
103                 }
104         }
105
106         private void parseMethods(final JavaClass jc, final JcfaClass jcfaClass)
107                         throws IOException {
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);
112
113                 }
114         }
115
116         /**
117          * Analyze method.
118          * 
119          * @param jc
120          * @param method
121          * @param jcfaClass
122          * @throws IOException
123          */
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);
128
129                 jcfaMethod.setName(method.getName());
130                 jcfaMethod.getComment().setJavaDoc(true);
131                 if (jcfaMethod.getName().equals("<init>")) {
132                         jcfaMethod.getComment().getCommentList()
133                                         .add("Default constructor.");
134                 } else {
135                         jcfaMethod.getComment().getCommentList().add("Method.");
136                 }
137
138                 for (Type type : method.getArgumentTypes()) {
139                         jcfaMethod.getComment().getCommentList().add(type.toString());
140                         jcfaMethod.getArugumentTypeList().add(type.toString());
141                 }
142                 jcfaMethod.setType(method.getReturnType().toString());
143
144                 final Code code = method.getCode();
145                 if (code == null) {
146                         return;
147                 }
148
149                 final byte[] codes = code.getCode();
150                 for (int pc = 0; pc < codes.length; pc++) {
151                         final int operands = parseCodes(jc, method, jcfaClass, jcfaMethod,
152                                         pc, codes);
153                         if (operands < 0) {
154                                 break;
155                         }
156
157                         pc += operands;
158                 }
159         }
160
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);
167
168                 jcfaCode.setOpcode(JcfaUtil.byte2UnsignedByte(codes[pc]));
169                 jcfaCode.getComment()
170                                 .getCommentList()
171                                 .add("" + pc + ": "
172                                                 + Constants.OPCODE_NAMES[jcfaCode.getOpcode()]);
173
174                 short operands = Constants.NO_OF_OPERANDS[jcfaCode.getOpcode()];
175                 if (operands < 0) {
176                         jcfaCode.getComment()
177                                         .getCommentList()
178                                         .add("FIXME NO_OF_OPERANDS has negative value:"
179                                                         + Constants.OPCODE_NAMES[jcfaCode.getOpcode()]
180                                                         + ": " + operands);
181                         return operands;
182                 }
183
184                 switch (jcfaCode.getOpcode()) {
185                 case Constants.RETURN:
186                         break;
187                 case Constants.GETSTATIC:
188                         break;
189                 case Constants.LDC:
190                         break;
191                 case Constants.INVOKEVIRTUAL:
192                 case Constants.INVOKESPECIAL:
193                         break;
194                 case Constants.LOOKUPSWITCH: {
195                         int result = JcfaUtil.byte2Int(codes[pc + 1], codes[pc + 2],
196                                         codes[pc + 3], codes[pc + 4]);
197                         System.out.println("  TODO skipping bytes: " + (result));
198
199                         int lookupOp = pc + 5;
200
201                         short diff = JcfaUtil.byte2UnsignedByte(codes[lookupOp++]);
202                         System.out.println("  TODO skipping bytes: " + (diff));
203
204                         int loopCount = JcfaUtil.byte2Int(codes[lookupOp++],
205                                         codes[lookupOp++], codes[lookupOp++], codes[lookupOp++]);
206
207                         short diff2 = JcfaUtil.byte2UnsignedByte(codes[lookupOp++]);
208                         jcfaCode.getComment().getCommentList()
209                                         .add("  TODO skipping bytes: " + (diff2));
210
211                         operands += (lookupOp - pc);
212                 }
213                         break;
214                 default:
215                         break;
216                 }
217
218                 {
219                         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
220                         outStream.write(codes, pc, operands + 1);
221                         outStream.flush();
222                         jcfaCode.setCodes(outStream.toByteArray());
223                 }
224                 return operands;
225         }
226 }