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