Skip to content

Commit

Permalink
1.0.0 release
Browse files Browse the repository at this point in the history
  • Loading branch information
Wdestroier committed Jul 10, 2021
1 parent db4aa92 commit eab6440
Show file tree
Hide file tree
Showing 380 changed files with 14,012 additions and 0 deletions.
26 changes: 26 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.github.wdestroier</groupId>
<artifactId>chamomile</artifactId>
<version>1.0.0</version>
<name>Chamomile assembler/disassembler</name>
<description>A Java Virtual Machine class file assembler and disassembler</description>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.github.wdestroier.chamomile;

import java.io.BufferedInputStream;
import java.util.ArrayList;
import java.util.List;

import com.github.wdestroier.chamomile.instruction.Instruction;
import com.github.wdestroier.chamomile.instruction.InstructionFactory;
import com.github.wdestroier.chamomile.io.Endianness;
import com.github.wdestroier.chamomile.io.MultiEndianInputStream;
import com.github.wdestroier.chamomile.io.ShortArrayInputStream;

import lombok.AllArgsConstructor;

@AllArgsConstructor
public class LinearSweepDisassembler {

private InstructionFactory instructionFactory;

public LinearSweepDisassembler() {
this(new InstructionFactory());
}

public List<Instruction<?>> disassemble(MultiEndianInputStream input) {
var bytesRead = input.getBytesRead();

// Needs to be aligned to read the Tableswitch and Tablelookup instructions
input.setBytesRead(0);

var instructions = new ArrayList<Instruction<?>>();

while (input.available() > 0) {
instructions.add(instructionFactory.getInstruction(input));
}

input.setBytesRead(input.getBytesRead() + bytesRead);

return instructions;
}

public List<Instruction<?>> disassemble(short... code) {
return disassemble(new MultiEndianInputStream(new BufferedInputStream(
new ShortArrayInputStream(code)), Endianness.BIG_ENDIAN));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.github.wdestroier.chamomile;

import java.util.List;

import com.github.wdestroier.chamomile.instruction.Instruction;
import com.github.wdestroier.chamomile.io.Endianness;
import com.github.wdestroier.chamomile.io.MultiEndianOutputStream;
import com.github.wdestroier.chamomile.io.ShortArrayOutputStream;

public class SinglePassAssembler {

public void assemble(List<Instruction<?>> instructions, MultiEndianOutputStream output) {
instructions.forEach(instruction -> instruction.write(output));
}

public short[] assemble(List<Instruction<?>> instructions) {
var output = new ShortArrayOutputStream();

assemble(instructions, new MultiEndianOutputStream(output, Endianness.BIG_ENDIAN));

return output.toUnsignedByteArray();
}

}
152 changes: 152 additions & 0 deletions src/main/java/com/github/wdestroier/chamomile/classfile/ClassFile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package com.github.wdestroier.chamomile.classfile;

import com.github.wdestroier.chamomile.classfile.attributeinfo.AttributeInfoFactory;
import com.github.wdestroier.chamomile.classfile.constantkind.ConstantDouble;
import com.github.wdestroier.chamomile.classfile.constantkind.ConstantLong;
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructure;
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructureFactory;
import com.github.wdestroier.chamomile.io.MultiEndianInputStream;
import com.github.wdestroier.chamomile.io.MultiEndianOutputStream;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ClassFile implements PseudoStructure<ClassFile> {

private long magic;
private int minorVersion;
private int majorVersion;
private int constantPoolCount;
private PseudoStructure<?>[] constantPool;
private int accessFlags;
private int thisClass;
private int superClass;
private int interfacesCount;
private int[] interfaces;
private int fieldsCount;
private FieldInfo[] fields;
private int methodsCount;
private MethodInfo[] methods;
private int attributesCount;
private PseudoStructure<?>[] attributes;

@Override
public ClassFile read(MultiEndianInputStream input, PseudoStructureFactory pseudoStructureFactory) {
//TODO ClassFileVerifier, MethodInfoVerifier ...

magic = input.readUnsignedInt();
minorVersion = input.readUnsignedShort();
majorVersion = input.readUnsignedShort();
constantPoolCount = input.readUnsignedShort();

constantPool = new PseudoStructure<?>[constantPoolCount];

/*
* cpInfo[0] is reserved
*
* https://stackoverflow.com/questions/56808432/why-is-the-constant-pool-in-java-classfile-indexed-from-1-and-not-0-what-is#:~:text=%22%5BI%5Dndexed%20from%201,index%20into%20the%20constant%20pool.
* https://stackoverflow.com/questions/56808432/why-is-the-constant-pool-in-java-classfile-indexed-from-1-and-not-0-what-is#:~:text=2%20Answers&text=They%20skipped%20index%200%20so,%22catch%20all%22%20exception%20handlers.
*/
for (var i = 1; i < constantPoolCount; i++) {
var constantKind = constantPool[i] = pseudoStructureFactory.getConstantKind(input);

// All 8-byte constants take up two entries in the constant_pool
if (constantKind instanceof ConstantLong || constantKind instanceof ConstantDouble) {
constantPool[++i] = null;
}
}

accessFlags = input.readUnsignedShort();

/*
* Must be a valid index in the constant pool table to a ConstantClass structure,
* representing the class or interface defined by the class file
*/
thisClass = input.readUnsignedShort();
superClass = input.readUnsignedShort();
interfacesCount = input.readUnsignedShort();

interfaces = new int[interfacesCount];

for (var i = 0; i < interfacesCount; i++) {
interfaces[i] = input.readUnsignedShort();
}

fieldsCount = input.readUnsignedShort();

pseudoStructureFactory.setAttributeInfoFactory(
new AttributeInfoFactory(pseudoStructureFactory, this));

fields = new FieldInfo[fieldsCount];

for (var i = 0; i < fieldsCount; i++) {
fields[i] = new FieldInfo().read(input, pseudoStructureFactory);
}

methodsCount = input.readUnsignedShort();

methods = new MethodInfo[methodsCount];

for (var i = 0; i < methodsCount; i++) {
methods[i] = new MethodInfo().read(input, pseudoStructureFactory);
}

attributesCount = input.readUnsignedShort();

attributes = new PseudoStructure<?>[attributesCount];

for (var i = 0; i < attributesCount; i++) {
attributes[i] = pseudoStructureFactory.getAttributeInfo(input);
}

return this;
}

@Override
public void write(MultiEndianOutputStream output) {
output.writeUnsignedInt(magic);
output.writeUnsignedShort(minorVersion);
output.writeUnsignedShort(majorVersion);
output.writeUnsignedShort(constantPoolCount);

for (var constant : constantPool) {
if (constant != null) {
constant.write(output);
}
}

output.writeUnsignedShort(accessFlags);
output.writeUnsignedShort(thisClass);
output.writeUnsignedShort(superClass);
output.writeUnsignedShort(interfacesCount);

for (var i : interfaces) {
output.writeUnsignedShort(i);
}

output.writeUnsignedShort(fieldsCount);

for (var field : fields) {
field.write(output);
}

output.writeUnsignedShort(methodsCount);

for (var method : methods) {
method.write(output);
}

output.writeUnsignedShort(attributesCount);

for (var attribute : attributes) {
if (attribute != null) {
attribute.write(output);
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.github.wdestroier.chamomile.classfile;

import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructure;
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructureFactory;
import com.github.wdestroier.chamomile.io.MultiEndianInputStream;
import com.github.wdestroier.chamomile.io.MultiEndianOutputStream;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class FieldInfo implements PseudoStructure<FieldInfo> {

private int accessFlags;
private int nameIndex;
private int descriptorIndex;
private int attributesCount;
private PseudoStructure<?>[] attributes;

@Override
public FieldInfo read(MultiEndianInputStream input, PseudoStructureFactory pseudoStructureFactory) {
accessFlags = input.readUnsignedShort();
nameIndex = input.readUnsignedShort();
descriptorIndex = input.readUnsignedShort();
attributesCount = input.readUnsignedShort();
attributes = new PseudoStructure<?>[attributesCount];

for (var i = 0; i < attributesCount; i++) {
attributes[i] = pseudoStructureFactory.getAttributeInfo(input);
}

return this;
}

@Override
public void write(MultiEndianOutputStream output) {
output.writeUnsignedShort(accessFlags);
output.writeUnsignedShort(nameIndex);
output.writeUnsignedShort(descriptorIndex);
output.writeUnsignedShort(attributesCount);

for (var attribute : attributes) {
if (attribute != null) {
attribute.write(output);
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.github.wdestroier.chamomile.classfile;

import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructure;
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructureFactory;
import com.github.wdestroier.chamomile.io.MultiEndianInputStream;
import com.github.wdestroier.chamomile.io.MultiEndianOutputStream;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MethodInfo implements PseudoStructure<MethodInfo> {

private int accessFlags;
private int nameIndex;
private int descriptorIndex;
private int attributesCount;
private PseudoStructure<?>[] attributes;

@Override
public MethodInfo read(MultiEndianInputStream input, PseudoStructureFactory pseudoStructureFactory) {
accessFlags = input.readUnsignedShort();
nameIndex = input.readUnsignedShort();
descriptorIndex = input.readUnsignedShort();
attributesCount = input.readUnsignedShort();
attributes = new PseudoStructure<?>[attributesCount];

for (var i = 0; i < attributesCount; i++) {
attributes[i] = pseudoStructureFactory.getAttributeInfo(input);
}

return this;
}

@Override
public void write(MultiEndianOutputStream output) {
output.writeUnsignedShort(accessFlags);
output.writeUnsignedShort(nameIndex);
output.writeUnsignedShort(descriptorIndex);
output.writeUnsignedShort(attributesCount);

for (var attribute : attributes) {
if (attribute != null) {
attribute.write(output);
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.github.wdestroier.chamomile.classfile.attributeinfo;

import com.github.wdestroier.chamomile.classfile.attributeinfo.annotation.ElementValue;
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructure;
import com.github.wdestroier.chamomile.classfile.pseudostructure.PseudoStructureFactory;
import com.github.wdestroier.chamomile.io.MultiEndianInputStream;
import com.github.wdestroier.chamomile.io.MultiEndianOutputStream;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class AnnotationDefaultAttribute implements PseudoStructure<AnnotationDefaultAttribute> {

private int attributeNameIndex;
private long attributeLength;
private ElementValue defaultValue;

@Override
public AnnotationDefaultAttribute read(MultiEndianInputStream input, PseudoStructureFactory pseudoStructureFactory) {
attributeNameIndex = input.readUnsignedShort();
attributeLength = input.readUnsignedInt();
defaultValue = new ElementValue().read(input, pseudoStructureFactory);

return this;
}

@Override
public void write(MultiEndianOutputStream output) {
output.writeUnsignedShort(attributeNameIndex);
output.writeUnsignedInt(attributeLength);
defaultValue.write(output);
}

}
Loading

0 comments on commit eab6440

Please sign in to comment.