Skip to content

Commit

Permalink
Add basic class file parser
Browse files Browse the repository at this point in the history
  • Loading branch information
jbalint committed Dec 9, 2015
1 parent 367ede9 commit cc334df
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .project.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(:type :standard
:source "1.8"
:target "1.8"
:options "-warn:+over-ann,uselessTypeCheck -warn:-enumSwitchPedantic,switchDefault,enumSwitch -proceedOnError -maxProblems 100"

;; source directory -> class directory mappings
:paths (("src/main/java" . "build/classes/main")
("src/test/java" . "build/classes/test"))

;; library paths to check
:lib-paths ("../connector-j-jardeps" "../connector-j-jardeps/6.0"))
31 changes: 31 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "jdepend:jdepend:2.9.1"
}
}

apply plugin: "java"

compileJava.options.encoding = "UTF-8"
javadoc.options.encoding = "UTF-8"

defaultTasks "build"

repositories {
jcenter()
}

dependencies {
testCompile "junit:junit:4.12"
}

sourceSets {
main {
java {
srcDir "src/main/java"
}
}
}
29 changes: 29 additions & 0 deletions src/main/java/com/jbalint/jcfl/ClassFile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.jbalint.jcfl;

import java.util.ArrayList;
import java.util.List;

public class ClassFile {
public static class AttributeInfo {
public short attributeNameIndex;
}

public static class FieldOrMethodInfo {
public char type;
public short accessFlags;
public short nameIndex;
public short descriptorIndex;
public AttributeInfo[] attributes;
}

public int magic;
public short version; // major version, we ignore minor as it's not used in practice
public List<ConstantPoolInfo> constantPool = new ArrayList<>();
public short accessFlags;
public short thisClassIndex;
public short superClassIndex;
public List interfaces = new ArrayList<>();
public List<FieldOrMethodInfo> fields = new ArrayList<>();
public List<FieldOrMethodInfo> methods = new ArrayList<>();
public List<AttributeInfo> attributes = new ArrayList<>();
}
79 changes: 79 additions & 0 deletions src/main/java/com/jbalint/jcfl/ConstantPoolInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.jbalint.jcfl;

public class ConstantPoolInfo {
public static enum InfoType {
CLASS(7), FIELD_REF(9), METHOD_REF(10), INTERFACE_METHOD_REF(11),
STRING(8), INTEGER(3), FLOAT(4), LONG(5), DOUBLE(6), NAME_AND_TYPE(12), UTF8(1),
METHOD_HANDLE(15), METHOD_TYPE(16), INVOKE_DYNAMIC(18);

public final byte tag;

InfoType(int t) {
tag = (byte) t;
}
}

public InfoType type;

public static class ClassInfo extends ConstantPoolInfo {
public short nameIndex;
}

public static class Fieldref extends ConstantPoolInfo {
public short classIndex;
public short nameAndTypeIndex;
}

public static class Methodref extends ConstantPoolInfo {
public short classIndex;
public short nameAndTypeIndex;
}

public static class InterfaceMethodref extends ConstantPoolInfo {
public short classIndex;
public short nameAndTypeIndex;
}

public static class StringInfo extends ConstantPoolInfo {
public short index;
}

public static class IntegerInfo extends ConstantPoolInfo {
public int value;
}

public static class FloatInfo extends ConstantPoolInfo {
public float value;
}

public static class LongInfo extends ConstantPoolInfo {
public long value;
}

public static class DoubleInfo extends ConstantPoolInfo {
public double value;
}

public static class NameAndType extends ConstantPoolInfo {
public short nameIndex;
public short descriptorIndex;
}

public static class Utf8 extends ConstantPoolInfo {
public byte[] value;
}

public static class MethodHandle extends ConstantPoolInfo {
public byte referenceKind;
public short referenceIndex;
}

public static class MethodType extends ConstantPoolInfo {
public short descriptorIndex;
}

public static class InvokeDynamic extends ConstantPoolInfo {
public short bootstrapMethodAttrIndex;
public short nameAndTypeIndex;
}
}
120 changes: 120 additions & 0 deletions src/main/java/com/jbalint/jcfl/Loader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package com.jbalint.jcfl;

import java.io.*;

import com.jbalint.jcfl.ConstantPoolInfo.*;
import com.jbalint.jcfl.ClassFile.*;
import static com.jbalint.jcfl.ConstantPoolInfo.InfoType.*;

public class Loader {
private static ConstantPoolInfo parseConstantPoolInfo(DataInputStream is) throws IOException {
int tag = is.read();
if (tag == CLASS.tag) {
ClassInfo info = new ClassInfo();
info.nameIndex = is.readShort();
return info;
} else if (tag == FIELD_REF.tag) {
Fieldref info = new Fieldref();
info.classIndex = is.readShort();
info.nameAndTypeIndex = is.readShort();
return info;
} else if (tag == METHOD_REF.tag) {
Methodref info = new Methodref();
info.classIndex = is.readShort();
info.nameAndTypeIndex = is.readShort();
return info;
} else if (tag == INTERFACE_METHOD_REF.tag) {
InterfaceMethodref info = new InterfaceMethodref();
info.classIndex = is.readShort();
info.nameAndTypeIndex = is.readShort();
return info;
} else if (tag == STRING.tag) {
StringInfo info = new StringInfo();
info.index = is.readShort();
return info;
} else if (tag == INTEGER.tag) {
IntegerInfo info = new IntegerInfo();
info.value = is.readInt();
return info;
} else if (tag == FLOAT.tag) {
FloatInfo info = new FloatInfo();
info.value = is.readFloat();
return info;
} else if (tag == LONG.tag) {
LongInfo info = new LongInfo();
info.value = is.readLong();
return info;
} else if (tag == DOUBLE.tag) {
DoubleInfo info = new DoubleInfo();
info.value = is.readDouble();
return info;
} else if (tag == NAME_AND_TYPE.tag) {
NameAndType info = new NameAndType();
info.nameIndex = is.readShort();
info.descriptorIndex = is.readShort();
return info;
} else if (tag == UTF8.tag) {
Utf8 info = new Utf8();
int len = is.readShort();
info.value = new byte[len];
is.readFully(info.value);
System.err.println("UTF8:" + new String(info.value, java.nio.charset.Charset.forName("UTF-8")));
return info;
} else if (tag == METHOD_HANDLE.tag) {
MethodHandle info = new MethodHandle();
info.referenceKind = (byte) is.read();
info.referenceIndex = is.readShort();
return info;
} else if (tag == METHOD_TYPE.tag) {
MethodType info = new MethodType();
info.descriptorIndex = is.readShort();
return info;
// TODO: } else if (tag == INVOKE_DYNAMIC.tag) {
}
throw new IllegalArgumentException("Unknown constant pool tag: " + tag);
}

private static FieldOrMethodInfo parseFieldOrMethodInfo(DataInputStream is) throws IOException {
FieldOrMethodInfo info = new FieldOrMethodInfo();
info.type = 'F';
info.accessFlags = is.readShort();
return info;
}

// alias shell='java -Xcheck:jni -esa -agentlib:yt -classpath build/classes/main java.util.prefs.Base64'
public static ClassFile load(File physicalFile) throws IOException {
ClassFile cf = new ClassFile();
try (DataInputStream is = new DataInputStream(new FileInputStream(physicalFile))) {
cf.magic = is.readInt();
is.readShort(); // ignored
cf.version = is.readShort();
int constantPoolCount = is.readShort() - 1;
System.err.println("Reading " + constantPoolCount + " constants");
cf.constantPool.add(new ConstantPoolInfo()); // so CP indexes are exact
for (int i = 0; i < 3075/*constantPoolCount*/; ++i) {
cf.constantPool.add(parseConstantPoolInfo(is));
System.err.println("Added: " + cf.constantPool.get(cf.constantPool.size() - 1) + " (" + cf.constantPool.size() + ")");
}
cf.accessFlags = is.readShort();
cf.thisClassIndex = is.readShort();
cf.superClassIndex = is.readShort();
int interfacesCount = is.readShort();
for (int i = 0; i < interfacesCount; ++i) {
cf.interfaces.add(cf.constantPool.get(is.readShort()));
System.err.println("Implements: " + cf.interfaces.get(cf.interfaces.size()-1));
}
int fieldsCount = is.readShort();
for (int i = 0; i < fieldsCount; ++i) {
cf.fields.add(parseFieldOrMethodInfo(is));
}
int methodsCount = is.readShort();
for (int i = 0; i < methodsCount; ++i) {
cf.fields.add(parseFieldOrMethodInfo(is));
}
int attributesCount = is.readShort();
for (int i = 0; i < attributesCount; ++i) {
}
}
return cf;
}
}

0 comments on commit cc334df

Please sign in to comment.