1 package jp.igapyon.jcfa;
\r
3 import java.io.BufferedWriter;
\r
5 import java.io.FileOutputStream;
\r
6 import java.io.IOException;
\r
7 import java.io.OutputStreamWriter;
\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
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
25 public class JavaClassFileAnalyzer {
\r
26 protected JcfaUnit jcfaUnit = new JcfaUnit();
\r
28 public static final void main(final String[] args) {
\r
29 new JavaClassFileAnalyzer().parseDir(new File("./bin/test"));
\r
32 private void parseDir(final File dir) {
\r
33 final File[] files = dir.listFiles();
\r
34 if (files == null) {
\r
37 for (File file : files) {
\r
38 if (file.isDirectory()) {
\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
50 private final void process(final File inputFile, final File outputDir) {
\r
52 final JavaClass jc = new ClassParser(inputFile.getCanonicalPath())
\r
54 final JcfaClass jcfaClass = new JcfaClass();
\r
55 jcfaUnit.getClassList().add(jcfaClass);
\r
57 jcfaClass.setName(jc.getClassName());
\r
58 jcfaClass.setExtendsName(jc.getSuperclassName());
\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
71 analyzeFields(jc, jcfaClass);
\r
72 analyzeMethods(jc, jcfaClass);
\r
74 jcfaUnit.setTargetFile(new File(actualyTargetDir,
\r
75 split[split.length - 1] + ".jcfa"));
\r
77 writeToFile(jcfaUnit);
\r
78 } catch (ClassFormatException e) {
\r
79 e.printStackTrace();
\r
80 } catch (IOException e) {
\r
81 e.printStackTrace();
\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
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
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
107 result.append("{");
\r
109 for (JcfaField jcfaField : jcfaClass.getFieldList()) {
\r
110 writeToBuffer(jcfaField, result);
\r
113 for (JcfaMethod jcfaMethod : jcfaClass.getMethodList()) {
\r
114 writeToBuffer(jcfaMethod, result);
\r
117 result.append("}");
\r
120 private void writeToBuffer(final JcfaField jcfaField,
\r
121 final StringBuffer result) {
\r
125 private void writeToBuffer(final JcfaMethod jcfaMethod,
\r
126 final StringBuffer result) {
\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
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
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
154 String constValue = null;
\r
155 final ConstantValue cv = field.getConstantValue();
\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
163 System.out.println(" " + access + field.getType().toString() + " "
\r
165 + (constValue == null ? "" : " = \"" + constValue + "\""));
\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
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
183 jcfaMethod.setName(method.getName());
\r
185 final Code code = method.getCode();
\r
186 if (code == null) {
\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
201 case Constants.RETURN: {
\r
202 System.out.println(" " + pc + ": "
\r
203 + Constants.OPCODE_NAMES[opcode]);
\r
206 case Constants.GETSTATIC: {
\r
207 System.out.println(" "
\r
210 + Constants.OPCODE_NAMES[opcode]
\r
212 + JcfaUtil.getConstantFieldrefString(jc, codes[pc + 1],
\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
222 case Constants.INVOKEVIRTUAL:
\r
223 case Constants.INVOKESPECIAL: {
\r
224 final int operand = JcfaUtil.byte2UnsignedShort(codes[pc + 1],
\r
226 System.out.println(" " + pc + ": "
\r
227 + Constants.OPCODE_NAMES[opcode] + ": "
\r
228 + JcfaUtil.getConstantMethodRefString(jc, operand));
\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
236 int lookupOp = pc + 5;
\r
238 short diff = JcfaUtil.byte2UnsignedByte(codes[lookupOp++]);
\r
239 System.out.println(" TODO skipping bytes: " + (diff));
\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
250 + (JcfaUtil.byte2Int(codes[lookupOp++],
\r
251 codes[lookupOp++], codes[lookupOp++],
\r
252 codes[lookupOp++]) + pc));
\r
255 short diff2 = JcfaUtil.byte2UnsignedByte(codes[lookupOp++]);
\r
256 System.out.println(" TODO skipping bytes: " + (diff2));
\r
258 operands += (lookupOp - pc);
\r
262 System.out.println(" " + pc + ": "
\r
263 + Constants.OPCODE_NAMES[opcode] + " (" + operands
\r