OSDN Git Service

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