Skip to content

Instantly share code, notes, and snippets.

@Xyene
Created November 30, 2013 23:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Xyene/7726044 to your computer and use it in GitHub Desktop.
Save Xyene/7726044 to your computer and use it in GitHub Desktop.
Dynamic structure allocator for JNA.
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public class Structures {
public static class AutoStructure extends Structure {
@Override
protected List getFieldOrder() {
Field[] declared = getClass().getDeclaredFields();
ArrayList<String> ordered = new ArrayList<>(declared.length);
for (Field f : declared)
ordered.add(f.getName());
return ordered;
}
}
public static Structure allocate(final String name, Class... classes) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(0xCAFEBABE);
dos.writeShort(0);
dos.writeShort(49); // Java 5
ByteArrayOutputStream constants = new ByteArrayOutputStream();
DataOutputStream con = new DataOutputStream(constants);
AtomicInteger idx = new AtomicInteger(0);
int superClass = classref(con, idx, AutoStructure.class.getName());
int thisClass = classref(con, idx, name);
ByteArrayOutputStream methods = new ByteArrayOutputStream();
DataOutputStream met = new DataOutputStream(methods);
met.writeShort(1);
met.writeShort(0x0001);
met.writeShort(utf(con, idx, "<init>"));
met.writeShort(utf(con, idx, "()V"));
met.writeShort(1);
met.writeShort(utf(con, idx, "Code"));
met.writeInt(2 + 2 + 4 + 1 + 1 + 2 + 1 + 2 + 2); // LENGTH
met.writeShort(1); // 1 stack and locals
met.writeShort(1);
met.writeInt(1 + 1 + 2 + 1);
met.writeByte(42); // aload_0
met.writeByte(183); // invokespecial super init
met.writeShort(methodref(con, idx, AutoStructure.class.getName(), "<init>", "()V"));
met.writeByte(177); // return
met.writeShort(0); // No exceptions or attributes
met.writeShort(0);
ByteArrayOutputStream fields = new ByteArrayOutputStream();
DataOutputStream fie = new DataOutputStream(fields);
fie.writeShort(classes.length);
for (Class d : classes) {
fie.writeShort(0x0001); // ACC_PUBLIC
// Random name
fie.writeShort(utf(con, idx, UUID.randomUUID().toString()));
HashMap<String, String> typeMap = new HashMap<>();
typeMap.put("int", "I");
typeMap.put("boolean", "Z");
typeMap.put("byte", "B");
typeMap.put("char", "C");
typeMap.put("short", "S");
typeMap.put("double", "D");
typeMap.put("float", "F");
typeMap.put("long", "J");
String descriptor = typeMap.get(d.getName());
if (descriptor == null)
descriptor = String.format("L%s;", d.getName().replace(".", "/"));
fie.writeShort(utf(con, idx, descriptor));
fie.writeShort(0); // No attributes
}
dos.writeShort(idx.get() + 1);
dos.write(constants.toByteArray());
// Class
dos.writeShort(0x0001); // Public
dos.writeShort(thisClass);
dos.writeShort(superClass);
dos.writeShort(0); // No implemented interfaces
dos.write(fields.toByteArray());
dos.write(methods.toByteArray());
dos.writeShort(0); // No attributes
return (Structure) new ClassLoader() {
public Class defineClass(byte[] bytes) {
return super.defineClass(name, bytes, 0, bytes.length);
}
}.defineClass(baos.toByteArray()).newInstance();
} catch (IOException | ReflectiveOperationException e) {
return null;
}
}
private static int classref(DataOutputStream out, AtomicInteger size, String id) throws IOException {
int utf = utf(out, size, id.replace(".", "/"));
out.writeByte(7); // Class pointing to ^
out.writeShort(utf);
return size.addAndGet(1);
}
private static int utf(DataOutputStream out, AtomicInteger size, String id) throws IOException {
out.writeByte(1); // UTF-8
out.writeUTF(id);
return size.addAndGet(1);
}
private static int methodref(DataOutputStream out, AtomicInteger size, String clazz, String name, String descriptor) throws IOException {
int classIdx = classref(out, size, clazz);
int descIdx = nametype(out, size, name, descriptor);
out.writeByte(10); // Methodref
out.writeShort(classIdx);
out.writeShort(descIdx);
return size.addAndGet(1);
}
private static int nametype(DataOutputStream out, AtomicInteger size, String name, String descriptor) throws IOException {
int nameIdx = utf(out, size, name);
int descIdx = utf(out, size, descriptor);
out.writeByte(12); // Nametype
out.writeShort(nameIdx);
out.writeShort(descIdx);
return size.addAndGet(1);
}
public static void main(String[] args) throws IOException, ReflectiveOperationException {
Structure c = allocate("TestCase", long.class, Pointer.class);
System.out.println(Arrays.toString(c.getClass().getDeclaredFields()));
System.out.println(c.size());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment