package jp.igapyon.jcfa;\r
\r
-import java.io.ByteArrayOutputStream;\r
import java.io.File;\r
-import java.io.IOException;\r
\r
-import jp.igapyon.jcfa.util.JcfaUtil;\r
-import jp.igapyon.jcfa.util.JcfaWriteUtil;\r
-import jp.igapyon.jcfa.vo.JcfaClass;\r
-import jp.igapyon.jcfa.vo.JcfaCode;\r
-import jp.igapyon.jcfa.vo.JcfaField;\r
-import jp.igapyon.jcfa.vo.JcfaMethod;\r
import jp.igapyon.jcfa.vo.JcfaUnit;\r
\r
-import org.apache.bcel.Constants;\r
-import org.apache.bcel.classfile.ClassFormatException;\r
-import org.apache.bcel.classfile.ClassParser;\r
-import org.apache.bcel.classfile.Code;\r
-import org.apache.bcel.classfile.ConstantValue;\r
-import org.apache.bcel.classfile.Field;\r
-import org.apache.bcel.classfile.JavaClass;\r
-import org.apache.bcel.classfile.Method;\r
-import org.apache.bcel.generic.Type;\r
-\r
public class JavaClassFileAnalyzer {\r
- protected JcfaUnit jcfaUnit = new JcfaUnit();\r
-\r
public static final void main(final String[] args) {\r
new JavaClassFileAnalyzer().parseDir(new File("./bin/test"));\r
new JavaClassFileAnalyzer().parseDir(new File(\r
}\r
\r
private final void process(final File inputFile, final File outputDir) {\r
- parseUnit(inputFile, outputDir);\r
- }\r
-\r
- private void parseUnit(final File inputFile, final File outputDir) {\r
- try {\r
- final JavaClass jc = new ClassParser(inputFile.getCanonicalPath())\r
- .parse();\r
- final JcfaClass jcfaClass = new JcfaClass();\r
- jcfaUnit.getClassList().add(jcfaClass);\r
-\r
- jcfaClass.setName(jc.getClassName());\r
- jcfaClass.setExtendsName(jc.getSuperclassName());\r
-\r
- jcfaClass.getComment().getCommentList()\r
- .add("TODO import func. is missing.");\r
- jcfaClass.getComment().setJavaDoc(true);\r
-\r
- final String[] split = jc.getClassName().split("\\.");\r
- File actualyTargetDir = outputDir;\r
- if (split.length > 1) {\r
- for (int index = 0; index < split.length - 1; index++) {\r
- actualyTargetDir = new File(actualyTargetDir, split[index]);\r
- actualyTargetDir.mkdirs();\r
- }\r
- }\r
-\r
- parseFields(jc, jcfaClass);\r
- parseMethods(jc, jcfaClass);\r
-\r
- jcfaUnit.setTargetFile(new File(actualyTargetDir,\r
- split[split.length - 1] + ".jcfa"));\r
-\r
- JcfaWriteUtil.writeToFile(jcfaUnit);\r
- } catch (ClassFormatException e) {\r
- e.printStackTrace();\r
- } catch (IOException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
-\r
- private void parseFields(final JavaClass jc, final JcfaClass jcfaClass) {\r
- final org.apache.bcel.classfile.Field[] fields = jc.getFields();\r
- for (int indexField = 0; indexField < fields.length; indexField++) {\r
- final Field field = fields[indexField];\r
- parseField(jc, field, jcfaClass);\r
- }\r
- }\r
-\r
- private void parseField(final JavaClass jc, final Field field,\r
- final JcfaClass jcfaClass) {\r
- final JcfaField jcfaField = new JcfaField();\r
- jcfaField.setName(field.getName());\r
- jcfaClass.getFieldList().add(jcfaField);\r
-\r
- jcfaField.getComment().setJavaDoc(true);\r
-\r
- // TODO type should be more collect.\r
- jcfaField.setType(field.getType().toString());\r
-\r
- String access = "";\r
- access += field.isPublic() ? "public " : "";\r
- access += field.isProtected() ? "protected " : "";\r
- access += field.isPrivate() ? "private " : "";\r
- access += field.isAbstract() ? "abstract " : "";\r
- access += field.isStatic() ? "static " : "";\r
- access += field.isVolatile() ? "volatile " : "";\r
- access += field.isFinal() ? "final " : "";\r
- jcfaField.setAccess(access);\r
-\r
- final ConstantValue cv = field.getConstantValue();\r
- if (cv != null) {\r
- jcfaField.setConstantValue("\""\r
- + jc.getConstantPool().getConstantString(\r
- cv.getConstantValueIndex(),\r
- Constants.CONSTANT_String) + "\"");\r
-\r
- jcfaField\r
- .getComment()\r
- .getCommentList()\r
- .add("FIXME other type support is missing. <br />Now only String.");\r
- }\r
- }\r
-\r
- private void parseMethods(final JavaClass jc, final JcfaClass jcfaClass)\r
- throws IOException {\r
- final org.apache.bcel.classfile.Method[] methods = jc.getMethods();\r
- for (int indexMethod = 0; indexMethod < methods.length; indexMethod++) {\r
- final Method method = methods[indexMethod];\r
- parseMethod(jc, method, jcfaClass);\r
-\r
- }\r
+ final JcfaUnit jcfaUnit = new JcfaParser().parseUnit(inputFile,\r
+ outputDir);\r
}\r
\r
- /**\r
- * Analyze method.\r
- * \r
- * @param jc\r
- * @param method\r
- * @param jcfaClass\r
- * @throws IOException\r
- */\r
- private void parseMethod(final JavaClass jc, final Method method,\r
- final JcfaClass jcfaClass) throws IOException {\r
- final JcfaMethod jcfaMethod = new JcfaMethod();\r
- jcfaClass.getMethodList().add(jcfaMethod);\r
-\r
- jcfaMethod.setName(method.getName());\r
- jcfaMethod.getComment().setJavaDoc(true);\r
- if (jcfaMethod.getName().equals("<init>")) {\r
- jcfaMethod.getComment().getCommentList()\r
- .add("Default constructor.");\r
- } else {\r
- jcfaMethod.getComment().getCommentList().add("Method.");\r
- }\r
-\r
- for (Type type : method.getArgumentTypes()) {\r
- jcfaMethod.getComment().getCommentList().add(type.toString());\r
- jcfaMethod.getArugumentTypeList().add(type.toString());\r
- }\r
- jcfaMethod.setType(method.getReturnType().toString());\r
-\r
- final Code code = method.getCode();\r
- if (code == null) {\r
- return;\r
- }\r
-\r
- final byte[] codes = code.getCode();\r
- for (int pc = 0; pc < codes.length; pc++) {\r
- final int operands = parseCodes(jc, method, jcfaClass, jcfaMethod,\r
- pc, codes);\r
- if (operands < 0) {\r
- break;\r
- }\r
-\r
- pc += operands;\r
- }\r
- }\r
-\r
- private int parseCodes(final JavaClass jc, final Method method,\r
- final JcfaClass jcfaClass, final JcfaMethod jcfaMethod,\r
- final int pc, final byte[] codes) throws IOException {\r
- final JcfaCode jcfaCode = new JcfaCode();\r
- jcfaMethod.getCodeList().add(jcfaCode);\r
- jcfaCode.setJavaClass(jc);\r
-\r
- jcfaCode.setOpcode(JcfaUtil.byte2UnsignedByte(codes[pc]));\r
- jcfaCode.getComment()\r
- .getCommentList()\r
- .add("" + pc + ": "\r
- + Constants.OPCODE_NAMES[jcfaCode.getOpcode()]);\r
-\r
- short operands = Constants.NO_OF_OPERANDS[jcfaCode.getOpcode()];\r
- if (operands < 0) {\r
- jcfaCode.getComment()\r
- .getCommentList()\r
- .add("FIXME NO_OF_OPERANDS has negative value:"\r
- + Constants.OPCODE_NAMES[jcfaCode.getOpcode()]\r
- + ": " + operands);\r
- return operands;\r
- }\r
-\r
- switch (jcfaCode.getOpcode()) {\r
- case Constants.RETURN:\r
- break;\r
- case Constants.GETSTATIC:\r
- break;\r
- case Constants.LDC:\r
- break;\r
- case Constants.INVOKEVIRTUAL:\r
- case Constants.INVOKESPECIAL:\r
- break;\r
- case Constants.LOOKUPSWITCH: {\r
- int result = JcfaUtil.byte2Int(codes[pc + 1], codes[pc + 2],\r
- codes[pc + 3], codes[pc + 4]);\r
- System.out.println(" TODO skipping bytes: " + (result));\r
-\r
- int lookupOp = pc + 5;\r
-\r
- short diff = JcfaUtil.byte2UnsignedByte(codes[lookupOp++]);\r
- System.out.println(" TODO skipping bytes: " + (diff));\r
-\r
- int loopCount = JcfaUtil.byte2Int(codes[lookupOp++],\r
- codes[lookupOp++], codes[lookupOp++], codes[lookupOp++]);\r
-\r
- short diff2 = JcfaUtil.byte2UnsignedByte(codes[lookupOp++]);\r
- jcfaCode.getComment().getCommentList()\r
- .add(" TODO skipping bytes: " + (diff2));\r
-\r
- operands += (lookupOp - pc);\r
- }\r
- break;\r
- default:\r
- break;\r
- }\r
-\r
- {\r
- final ByteArrayOutputStream outStream = new ByteArrayOutputStream();\r
- outStream.write(codes, pc, operands + 1);\r
- outStream.flush();\r
- jcfaCode.setCodes(outStream.toByteArray());\r
- }\r
- return operands;\r
- }\r
}
\ No newline at end of file
--- /dev/null
+package jp.igapyon.jcfa;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+
+import jp.igapyon.jcfa.util.JcfaUtil;
+import jp.igapyon.jcfa.util.JcfaWriteUtil;
+import jp.igapyon.jcfa.vo.JcfaClass;
+import jp.igapyon.jcfa.vo.JcfaCode;
+import jp.igapyon.jcfa.vo.JcfaField;
+import jp.igapyon.jcfa.vo.JcfaMethod;
+import jp.igapyon.jcfa.vo.JcfaUnit;
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.classfile.ClassFormatException;
+import org.apache.bcel.classfile.ClassParser;
+import org.apache.bcel.classfile.Code;
+import org.apache.bcel.classfile.ConstantValue;
+import org.apache.bcel.classfile.Field;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.classfile.Method;
+import org.apache.bcel.generic.Type;
+
+public class JcfaParser {
+ protected JcfaUnit jcfaUnit = new JcfaUnit();
+
+ public JcfaUnit parseUnit(final File inputFile, final File outputDir) {
+ try {
+ final JavaClass jc = new ClassParser(inputFile.getCanonicalPath())
+ .parse();
+ final JcfaClass jcfaClass = new JcfaClass();
+ jcfaUnit.getClassList().add(jcfaClass);
+
+ jcfaClass.setName(jc.getClassName());
+ jcfaClass.setExtendsName(jc.getSuperclassName());
+
+ jcfaClass.getComment().getCommentList()
+ .add("TODO import func. is missing.");
+ jcfaClass.getComment().setJavaDoc(true);
+
+ final String[] split = jc.getClassName().split("\\.");
+ File actualyTargetDir = outputDir;
+ if (split.length > 1) {
+ for (int index = 0; index < split.length - 1; index++) {
+ actualyTargetDir = new File(actualyTargetDir, split[index]);
+ actualyTargetDir.mkdirs();
+ }
+ }
+
+ parseFields(jc, jcfaClass);
+ parseMethods(jc, jcfaClass);
+
+ jcfaUnit.setTargetFile(new File(actualyTargetDir,
+ split[split.length - 1] + ".jcfa"));
+
+ JcfaWriteUtil.writeToFile(jcfaUnit);
+ } catch (ClassFormatException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return jcfaUnit;
+ }
+
+ private void parseFields(final JavaClass jc, final JcfaClass jcfaClass) {
+ final org.apache.bcel.classfile.Field[] fields = jc.getFields();
+ for (int indexField = 0; indexField < fields.length; indexField++) {
+ final Field field = fields[indexField];
+ parseField(jc, field, jcfaClass);
+ }
+ }
+
+ private void parseField(final JavaClass jc, final Field field,
+ final JcfaClass jcfaClass) {
+ final JcfaField jcfaField = new JcfaField();
+ jcfaField.setName(field.getName());
+ jcfaClass.getFieldList().add(jcfaField);
+
+ jcfaField.getComment().setJavaDoc(true);
+
+ // TODO type should be more collect.
+ jcfaField.setType(field.getType().toString());
+
+ String access = "";
+ access += field.isPublic() ? "public " : "";
+ access += field.isProtected() ? "protected " : "";
+ access += field.isPrivate() ? "private " : "";
+ access += field.isAbstract() ? "abstract " : "";
+ access += field.isStatic() ? "static " : "";
+ access += field.isVolatile() ? "volatile " : "";
+ access += field.isFinal() ? "final " : "";
+ jcfaField.setAccess(access);
+
+ final ConstantValue cv = field.getConstantValue();
+ if (cv != null) {
+ jcfaField.setConstantValue("\""
+ + jc.getConstantPool().getConstantString(
+ cv.getConstantValueIndex(),
+ Constants.CONSTANT_String) + "\"");
+
+ jcfaField
+ .getComment()
+ .getCommentList()
+ .add("FIXME other type support is missing. <br />Now only String.");
+ }
+ }
+
+ private void parseMethods(final JavaClass jc, final JcfaClass jcfaClass)
+ throws IOException {
+ final org.apache.bcel.classfile.Method[] methods = jc.getMethods();
+ for (int indexMethod = 0; indexMethod < methods.length; indexMethod++) {
+ final Method method = methods[indexMethod];
+ parseMethod(jc, method, jcfaClass);
+
+ }
+ }
+
+ /**
+ * Analyze method.
+ *
+ * @param jc
+ * @param method
+ * @param jcfaClass
+ * @throws IOException
+ */
+ private void parseMethod(final JavaClass jc, final Method method,
+ final JcfaClass jcfaClass) throws IOException {
+ final JcfaMethod jcfaMethod = new JcfaMethod();
+ jcfaClass.getMethodList().add(jcfaMethod);
+
+ jcfaMethod.setName(method.getName());
+ jcfaMethod.getComment().setJavaDoc(true);
+ if (jcfaMethod.getName().equals("<init>")) {
+ jcfaMethod.getComment().getCommentList()
+ .add("Default constructor.");
+ } else {
+ jcfaMethod.getComment().getCommentList().add("Method.");
+ }
+
+ for (Type type : method.getArgumentTypes()) {
+ jcfaMethod.getComment().getCommentList().add(type.toString());
+ jcfaMethod.getArugumentTypeList().add(type.toString());
+ }
+ jcfaMethod.setType(method.getReturnType().toString());
+
+ final Code code = method.getCode();
+ if (code == null) {
+ return;
+ }
+
+ final byte[] codes = code.getCode();
+ for (int pc = 0; pc < codes.length; pc++) {
+ final int operands = parseCodes(jc, method, jcfaClass, jcfaMethod,
+ pc, codes);
+ if (operands < 0) {
+ break;
+ }
+
+ pc += operands;
+ }
+ }
+
+ private int parseCodes(final JavaClass jc, final Method method,
+ final JcfaClass jcfaClass, final JcfaMethod jcfaMethod,
+ final int pc, final byte[] codes) throws IOException {
+ final JcfaCode jcfaCode = new JcfaCode();
+ jcfaMethod.getCodeList().add(jcfaCode);
+ jcfaCode.setJavaClass(jc);
+
+ jcfaCode.setOpcode(JcfaUtil.byte2UnsignedByte(codes[pc]));
+ jcfaCode.getComment()
+ .getCommentList()
+ .add("" + pc + ": "
+ + Constants.OPCODE_NAMES[jcfaCode.getOpcode()]);
+
+ short operands = Constants.NO_OF_OPERANDS[jcfaCode.getOpcode()];
+ if (operands < 0) {
+ jcfaCode.getComment()
+ .getCommentList()
+ .add("FIXME NO_OF_OPERANDS has negative value:"
+ + Constants.OPCODE_NAMES[jcfaCode.getOpcode()]
+ + ": " + operands);
+ return operands;
+ }
+
+ switch (jcfaCode.getOpcode()) {
+ case Constants.RETURN:
+ break;
+ case Constants.GETSTATIC:
+ break;
+ case Constants.LDC:
+ break;
+ case Constants.INVOKEVIRTUAL:
+ case Constants.INVOKESPECIAL:
+ break;
+ case Constants.LOOKUPSWITCH: {
+ int result = JcfaUtil.byte2Int(codes[pc + 1], codes[pc + 2],
+ codes[pc + 3], codes[pc + 4]);
+ System.out.println(" TODO skipping bytes: " + (result));
+
+ int lookupOp = pc + 5;
+
+ short diff = JcfaUtil.byte2UnsignedByte(codes[lookupOp++]);
+ System.out.println(" TODO skipping bytes: " + (diff));
+
+ int loopCount = JcfaUtil.byte2Int(codes[lookupOp++],
+ codes[lookupOp++], codes[lookupOp++], codes[lookupOp++]);
+
+ short diff2 = JcfaUtil.byte2UnsignedByte(codes[lookupOp++]);
+ jcfaCode.getComment().getCommentList()
+ .add(" TODO skipping bytes: " + (diff2));
+
+ operands += (lookupOp - pc);
+ }
+ break;
+ default:
+ break;
+ }
+
+ {
+ final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ outStream.write(codes, pc, operands + 1);
+ outStream.flush();
+ jcfaCode.setCodes(outStream.toByteArray());
+ }
+ return operands;
+ }
+}