Skip to content
This repository was archived by the owner on Feb 17, 2022. It is now read-only.

Commit ddbfaef

Browse files
committed
Start attributes
1 parent acfa97d commit ddbfaef

File tree

7 files changed

+162
-5
lines changed

7 files changed

+162
-5
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.github.seggan.javaclasslib;
2+
3+
import java.util.Arrays;
4+
5+
public enum ClassAccessFlags {
6+
PUBLIC(0x0001),
7+
FINAL(0x0010),
8+
SUPER(0x0020),
9+
INTERFACE(0x0200),
10+
ABSTRACT(0x0400),
11+
SYNTHETIC(0x1000),
12+
ANNOTATION(0x2000),
13+
ENUM(0x4000);
14+
15+
private final int value;
16+
17+
ClassAccessFlags(int value) {
18+
this.value = value;
19+
}
20+
21+
public static int combine(ClassAccessFlags... flags) {
22+
return Arrays.stream(flags).mapToInt(ClassAccessFlags::getValue).sum();
23+
}
24+
25+
public int getValue() {
26+
return value;
27+
}
28+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,72 @@
11
package io.github.seggan.javaclasslib;
22

3+
import io.github.seggan.javaclasslib.constantpool.ClassEntry;
34
import io.github.seggan.javaclasslib.constantpool.ConstantPoolEntry;
5+
import io.github.seggan.javaclasslib.constantpool.UTF8Entry;
46

7+
import javax.annotation.Nonnull;
8+
import java.io.IOException;
9+
import java.io.OutputStream;
510
import java.util.LinkedList;
611
import java.util.List;
12+
import java.util.regex.Pattern;
713

814
public final class JavaClass {
915

16+
private static final Pattern PERIOD = Pattern.compile("\\.");
17+
private static final byte[] START_BYTES = new byte[]{(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE, 0, 0};
18+
1019
private final List<ConstantPoolEntry> constantPool = new LinkedList<>();
20+
21+
private final ClassEntry thisClass;
22+
private final ClassEntry superClass;
23+
private final int classVersion;
24+
25+
private ClassAccessFlags[] classAccessFlags = new ClassAccessFlags[0];
26+
27+
public JavaClass(@Nonnull String name, @Nonnull String superclass, int javaVersion) {
28+
if (javaVersion < 8) throw new IllegalArgumentException();
29+
classVersion = javaVersion + 44;
30+
31+
UTF8Entry utf8Name = new UTF8Entry(constantPool, PERIOD.matcher(name).replaceAll("/"));
32+
this.thisClass = new ClassEntry(constantPool, utf8Name);
33+
UTF8Entry superName = new UTF8Entry(constantPool, PERIOD.matcher(superclass).replaceAll("/"));
34+
this.superClass = new ClassEntry(constantPool, superName);
35+
}
36+
37+
public void write(@Nonnull OutputStream out) throws IOException {
38+
out.write(START_BYTES);
39+
out.write(ByteUtils.twoBytesFromInt(classVersion));
40+
out.write(ByteUtils.twoBytesFromInt(constantPool.size() + 1));
41+
for (ConstantPoolEntry entry : constantPool) {
42+
out.write(entry.getBytes());
43+
}
44+
out.write(ByteUtils.twoBytesFromInt(ClassAccessFlags.combine(classAccessFlags)));
45+
out.write(thisClass.getIndexBytes());
46+
out.write(superClass.getIndexBytes());
47+
}
48+
49+
public List<ConstantPoolEntry> getConstantPool() {
50+
return constantPool;
51+
}
52+
53+
public ClassEntry getThisClass() {
54+
return thisClass;
55+
}
56+
57+
public ClassEntry getSuperClass() {
58+
return superClass;
59+
}
60+
61+
public int getClassVersion() {
62+
return classVersion;
63+
}
64+
65+
public ClassAccessFlags[] getClassAccessFlags() {
66+
return classAccessFlags;
67+
}
68+
69+
public void setClassAccessFlags(ClassAccessFlags... classAccessFlags) {
70+
this.classAccessFlags = classAccessFlags;
71+
}
1172
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package io.github.seggan.javaclasslib.attributes;
2+
3+
import io.github.seggan.javaclasslib.constantpool.UTF8Entry;
4+
5+
public abstract class Attribute {
6+
7+
private final UTF8Entry nameIndex;
8+
private final int length;
9+
10+
public Attribute(UTF8Entry nameIndex, int length) {
11+
this.nameIndex = nameIndex;
12+
this.length = length;
13+
}
14+
15+
public abstract byte[] getBytes();
16+
17+
public UTF8Entry getNameIndex() {
18+
return nameIndex;
19+
}
20+
21+
public int getLength() {
22+
return length;
23+
}
24+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.github.seggan.javaclasslib.attributes;
2+
3+
import io.github.seggan.javaclasslib.constantpool.UTF8Entry;
4+
5+
public final class CodeAttribute extends Attribute {
6+
7+
public CodeAttribute(UTF8Entry nameIndex, int length) {
8+
super(nameIndex, length);
9+
}
10+
11+
@Override
12+
public byte[] getBytes() {
13+
return new byte[0];
14+
}
15+
}

src/main/java/io/github/seggan/javaclasslib/constantpool/ConstantPoolEntry.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,29 @@ public final ConstantPoolTag getTag() {
2424
return tag;
2525
}
2626

27+
/**
28+
* Returns the index of this entry in the constant pool. Not to be confused with {@link #getIndexBytes()}
29+
*
30+
* @return the index of this constant pool entry
31+
*/
2732
public final int getIndex() {
2833
return constantPool.indexOf(this);
2934
}
3035

36+
/**
37+
* Returns the bytes that make up the index of this entry in the constant pool. Not to
38+
* be confused with {@link #getIndex()}
39+
*
40+
* @return a byte array of size 2 representing the index of this constant pool entry
41+
*/
3142
@Nonnull
3243
public final byte[] getIndexBytes() {
3344
return ByteUtils.twoBytesFromInt(getIndex());
3445
}
3546

47+
/**
48+
* Converts this constant pool entry into its byte representation in a class file
49+
*/
3650
@Nonnull
3751
public abstract byte[] getBytes();
3852

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.github.seggan.javaclasslib.tests;
2+
3+
import io.github.seggan.javaclasslib.ClassAccessFlags;
4+
import org.junit.jupiter.api.Assertions;
5+
import org.junit.jupiter.api.Test;
6+
7+
public class TestAccess {
8+
9+
@Test
10+
public void testAccess() {
11+
Assertions.assertEquals("401", Integer.toHexString(ClassAccessFlags.combine(ClassAccessFlags.PUBLIC, ClassAccessFlags.ABSTRACT)));
12+
}
13+
14+
public static String byteArrayToHex(byte[] a) {
15+
StringBuilder sb = new StringBuilder(a.length * 2);
16+
for(byte b: a)
17+
sb.append(String.format("%02x ", b));
18+
return sb.toString();
19+
}
20+
}

src/test/java/io/github/seggan/javaclasslib/tests/TestByteUtils.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,6 @@ public void testIntToByte() {
2626
ByteUtils.intToBytes(16));
2727
}
2828

29-
@Test
30-
public void testDoubleToByte() {
31-
System.out.println(byteArrayToHex(ByteBuffer.allocate(8).order(ByteOrder.BIG_ENDIAN).putDouble(1.22).array()));
32-
}
33-
3429
public static String byteArrayToHex(byte[] a) {
3530
StringBuilder sb = new StringBuilder(a.length * 2);
3631
for(byte b: a)

0 commit comments

Comments
 (0)