OSDN Git Service

save
[jcfa/jcfa.git] / jcfa / src / jp / igapyon / jcfa / JavaClassFileAnalyzer.java
1 package jp.igapyon.jcfa;\r
2 \r
3 import java.io.ByteArrayOutputStream;\r
4 import java.io.File;\r
5 import java.io.IOException;\r
6 \r
7 import jp.igapyon.jcfa.util.JcfaUtil;\r
8 import jp.igapyon.jcfa.util.JcfaWriteUtil;\r
9 import jp.igapyon.jcfa.vo.JcfaClass;\r
10 import jp.igapyon.jcfa.vo.JcfaCode;\r
11 import jp.igapyon.jcfa.vo.JcfaField;\r
12 import jp.igapyon.jcfa.vo.JcfaMethod;\r
13 import jp.igapyon.jcfa.vo.JcfaUnit;\r
14 \r
15 import org.apache.bcel.Constants;\r
16 import org.apache.bcel.classfile.ClassFormatException;\r
17 import org.apache.bcel.classfile.ClassParser;\r
18 import org.apache.bcel.classfile.Code;\r
19 import org.apache.bcel.classfile.ConstantValue;\r
20 import org.apache.bcel.classfile.Field;\r
21 import org.apache.bcel.classfile.JavaClass;\r
22 import org.apache.bcel.classfile.Method;\r
23 import org.apache.bcel.generic.Type;\r
24 \r
25 public class JavaClassFileAnalyzer {\r
26         protected JcfaUnit jcfaUnit = new JcfaUnit();\r
27 \r
28         public static final void main(final String[] args) {\r
29                 new JavaClassFileAnalyzer().parseDir(new File("./bin/test"));\r
30                 new JavaClassFileAnalyzer().parseDir(new File(\r
31                                 "./bin/jp/igapyon/jcfa/vo"));\r
32         }\r
33 \r
34         private void parseDir(final File dir) {\r
35                 final File[] files = dir.listFiles();\r
36                 if (files == null) {\r
37                         return;\r
38                 }\r
39                 for (File file : files) {\r
40                         if (file.isDirectory()) {\r
41                                 parseDir(file);\r
42                         }\r
43                         if (file.isFile()) {\r
44                                 if (file.getName().endsWith(".class")) {\r
45                                         new JavaClassFileAnalyzer().process(file, new File(\r
46                                                         "./testJavaClass/output"));\r
47                                 }\r
48                         }\r
49                 }\r
50         }\r
51 \r
52         private final void process(final File inputFile, final File outputDir) {\r
53                 try {\r
54                         final JavaClass jc = new ClassParser(inputFile.getCanonicalPath())\r
55                                         .parse();\r
56                         final JcfaClass jcfaClass = new JcfaClass();\r
57                         jcfaUnit.getClassList().add(jcfaClass);\r
58 \r
59                         jcfaClass.setName(jc.getClassName());\r
60                         jcfaClass.setExtendsName(jc.getSuperclassName());\r
61 \r
62                         jcfaClass.getComment().getCommentList()\r
63                                         .add("TODO import func. is missing.");\r
64                         jcfaClass.getComment().setJavaDoc(true);\r
65 \r
66                         final String[] split = jc.getClassName().split("\\.");\r
67                         File actualyTargetDir = outputDir;\r
68                         if (split.length > 1) {\r
69                                 for (int index = 0; index < split.length - 1; index++) {\r
70                                         actualyTargetDir = new File(actualyTargetDir, split[index]);\r
71                                         actualyTargetDir.mkdirs();\r
72                                 }\r
73                         }\r
74 \r
75                         analyzeFields(jc, jcfaClass);\r
76                         analyzeMethods(jc, jcfaClass);\r
77 \r
78                         jcfaUnit.setTargetFile(new File(actualyTargetDir,\r
79                                         split[split.length - 1] + ".jcfa"));\r
80 \r
81                         JcfaWriteUtil.writeToFile(jcfaUnit);\r
82                 } catch (ClassFormatException e) {\r
83                         e.printStackTrace();\r
84                 } catch (IOException e) {\r
85                         e.printStackTrace();\r
86                 }\r
87         }\r
88 \r
89         private void analyzeFields(final JavaClass jc, final JcfaClass jcfaClass) {\r
90                 final org.apache.bcel.classfile.Field[] fields = jc.getFields();\r
91                 for (int indexField = 0; indexField < fields.length; indexField++) {\r
92                         final Field field = fields[indexField];\r
93                         analyzeField(jc, field, jcfaClass);\r
94                 }\r
95         }\r
96 \r
97         private void analyzeField(final JavaClass jc, final Field field,\r
98                         final JcfaClass jcfaClass) {\r
99                 final JcfaField jcfaField = new JcfaField();\r
100                 jcfaField.setName(field.getName());\r
101                 jcfaClass.getFieldList().add(jcfaField);\r
102 \r
103                 jcfaField.getComment().setJavaDoc(true);\r
104 \r
105                 // TODO type should be more collect.\r
106                 jcfaField.setType(field.getType().toString());\r
107 \r
108                 String access = "";\r
109                 access += field.isPublic() ? "public " : "";\r
110                 access += field.isProtected() ? "protected " : "";\r
111                 access += field.isPrivate() ? "private " : "";\r
112                 access += field.isAbstract() ? "abstract " : "";\r
113                 access += field.isStatic() ? "static " : "";\r
114                 access += field.isVolatile() ? "volatile " : "";\r
115                 access += field.isFinal() ? "final " : "";\r
116                 jcfaField.setAccess(access);\r
117 \r
118                 final ConstantValue cv = field.getConstantValue();\r
119                 if (cv != null) {\r
120                         jcfaField.setConstantValue("\""\r
121                                         + jc.getConstantPool().getConstantString(\r
122                                                         cv.getConstantValueIndex(),\r
123                                                         Constants.CONSTANT_String) + "\"");\r
124 \r
125                         jcfaField\r
126                                         .getComment()\r
127                                         .getCommentList()\r
128                                         .add("FIXME other type support is missing. <br />Now only String.");\r
129                 }\r
130         }\r
131 \r
132         private void analyzeMethods(final JavaClass jc, final JcfaClass jcfaClass)\r
133                         throws IOException {\r
134                 final org.apache.bcel.classfile.Method[] methods = jc.getMethods();\r
135                 for (int indexMethod = 0; indexMethod < methods.length; indexMethod++) {\r
136                         final Method method = methods[indexMethod];\r
137                         analyzeMethod(jc, method, jcfaClass);\r
138 \r
139                 }\r
140         }\r
141 \r
142         /**\r
143          * Analyze method.\r
144          * \r
145          * @param jc\r
146          * @param method\r
147          * @param jcfaClass\r
148          * @throws IOException\r
149          */\r
150         private void analyzeMethod(final JavaClass jc, final Method method,\r
151                         final JcfaClass jcfaClass) throws IOException {\r
152                 final JcfaMethod jcfaMethod = new JcfaMethod();\r
153                 jcfaClass.getMethodList().add(jcfaMethod);\r
154 \r
155                 jcfaMethod.setName(method.getName());\r
156                 jcfaMethod.getComment().setJavaDoc(true);\r
157                 if (jcfaMethod.getName().equals("<init>")) {\r
158                         jcfaMethod.getComment().getCommentList()\r
159                                         .add("Default constructor.");\r
160                 } else {\r
161                         jcfaMethod.getComment().getCommentList().add("Method.");\r
162                 }\r
163 \r
164                 for (Type type : method.getArgumentTypes()) {\r
165                         jcfaMethod.getComment().getCommentList().add(type.toString());\r
166                         jcfaMethod.getArugumentTypeList().add(type.toString());\r
167                 }\r
168                 jcfaMethod.setType(method.getReturnType().toString());\r
169 \r
170                 final Code code = method.getCode();\r
171                 if (code == null) {\r
172                         return;\r
173                 }\r
174 \r
175                 final byte[] codes = code.getCode();\r
176                 for (int pc = 0; pc < codes.length; pc++) {\r
177                         final int operands = analyzeCodes(jc, method, jcfaClass,\r
178                                         jcfaMethod, pc, codes);\r
179                         if (operands < 0) {\r
180                                 break;\r
181                         }\r
182 \r
183                         pc += operands;\r
184                 }\r
185         }\r
186 \r
187         private int analyzeCodes(final JavaClass jc, final Method method,\r
188                         final JcfaClass jcfaClass, final JcfaMethod jcfaMethod,\r
189                         final int pc, final byte[] codes) throws IOException {\r
190                 final JcfaCode jcfaCode = new JcfaCode();\r
191                 jcfaMethod.getCodeList().add(jcfaCode);\r
192                 jcfaCode.setJavaClass(jc);\r
193 \r
194                 jcfaCode.setOpcode(JcfaUtil.byte2UnsignedByte(codes[pc]));\r
195                 jcfaCode.getComment()\r
196                                 .getCommentList()\r
197                                 .add("" + pc + ": "\r
198                                                 + Constants.OPCODE_NAMES[jcfaCode.getOpcode()]);\r
199 \r
200                 short operands = Constants.NO_OF_OPERANDS[jcfaCode.getOpcode()];\r
201                 if (operands < 0) {\r
202                         jcfaCode.getComment()\r
203                                         .getCommentList()\r
204                                         .add("FIXME NO_OF_OPERANDS has negative value:"\r
205                                                         + Constants.OPCODE_NAMES[jcfaCode.getOpcode()]\r
206                                                         + ": " + operands);\r
207                         return operands;\r
208                 }\r
209 \r
210                 switch (jcfaCode.getOpcode()) {\r
211                 case Constants.RETURN:\r
212                         break;\r
213                 case Constants.GETSTATIC:\r
214                         break;\r
215                 case Constants.LDC:\r
216                         break;\r
217                 case Constants.INVOKEVIRTUAL:\r
218                 case Constants.INVOKESPECIAL:\r
219                         break;\r
220                 case Constants.LOOKUPSWITCH: {\r
221                         int result = JcfaUtil.byte2Int(codes[pc + 1], codes[pc + 2],\r
222                                         codes[pc + 3], codes[pc + 4]);\r
223                         System.out.println("  TODO skipping bytes: " + (result));\r
224 \r
225                         int lookupOp = pc + 5;\r
226 \r
227                         short diff = JcfaUtil.byte2UnsignedByte(codes[lookupOp++]);\r
228                         System.out.println("  TODO skipping bytes: " + (diff));\r
229 \r
230                         int loopCount = JcfaUtil.byte2Int(codes[lookupOp++],\r
231                                         codes[lookupOp++], codes[lookupOp++], codes[lookupOp++]);\r
232 \r
233                         short diff2 = JcfaUtil.byte2UnsignedByte(codes[lookupOp++]);\r
234                         jcfaCode.getComment().getCommentList()\r
235                                         .add("  TODO skipping bytes: " + (diff2));\r
236 \r
237                         operands += (lookupOp - pc);\r
238                 }\r
239                         break;\r
240                 default:\r
241                         break;\r
242                 }\r
243 \r
244                 {\r
245                         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();\r
246                         outStream.write(codes, pc, operands + 1);\r
247                         outStream.flush();\r
248                         jcfaCode.setCodes(outStream.toByteArray());\r
249                 }\r
250                 return operands;\r
251         }\r
252 }