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