package uk.kludje.experimental.property.reflect;
import uk.kludje.Ensure;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public final class ClassFileStructure implements DataWriter {
private static final Log LOG = Log.logger(ClassFileStructure.class);
public static final int MAGIC = 0xCAFEBABE;
public static final short MINOR_VERSION = 0;
public static final short MAJOR_VERSION = 52;
private final List<ClassConstant> constants;
private final byte[] remainder;
ClassFileStructure(List<ClassConstant> constants, byte[] remainder) {
this.constants = constants;
this.remainder = remainder;
}
@Override
public void writeTo(DataOutput output) throws IOException {
output.writeInt(MAGIC);
output.writeShort(MINOR_VERSION);
output.writeShort(MAJOR_VERSION);
output.writeShort(constants.size() + 1);
for (ClassConstant constant : constants) {
constant.writeTo(output);
}
output.write(remainder);
}
public String className() {
throw new UnsupportedOperationException();
}
public byte[] toBytes() {
throw new UnsupportedOperationException();
}
public static ClassFileStructure parse(DataInputStream input) throws IOException {
Ensure.that(input != null, "input != null");
Ensure.checked(input.readInt() == MAGIC, "magic == 0xCAFEBABE", IOException::new);
Ensure.checked(input.readShort() == MINOR_VERSION, "minor == 0", IOException::new);
Ensure.checked(input.readShort() == MAJOR_VERSION, "major == 52", IOException::new);
int constPoolSize = input.readUnsignedShort();
List<ClassConstant> constants = new ArrayList<>(constPoolSize);
for (int i = 0; i < constPoolSize - 1; i++) {
ClassConstant constant = ClassConstantParser.parse(input);
constants.add(constant);
LOG.debug("Constant %d: %s", i, constant);
}
ByteArrayOutputStream remainder = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int r;
while ((r = input.read(buf)) > -1) {
remainder.write(buf, 0, r);
}
return new ClassFileStructure(constants, remainder.toByteArray());
}
public static ClassFileStructure parse(URL url) throws IOException {
try (InputStream in = url.openStream();
DataInputStream data = new DataInputStream(in)) {
return parse(data);
}
}
}