I want to access a PKCS11 library from Java via FFI/Panama. Let's say we have the following packed group layout under Windows x64:
GroupLayout groupLayout = MemoryLayout.structLayout(
MemoryLayout.sequenceLayout(64, JAVA_BYTE).withName("slotDescription"),
MemoryLayout.sequenceLayout(32, JAVA_BYTE).withName("manufacturerId"),
JAVA_INT_UNALIGNED.withName("flags"),
MemoryLayout.structLayout(
JAVA_BYTE.withName("major"),
JAVA_BYTE.withName("minor")
).withName("hardwareVersion"),
MemoryLayout.structLayout(
JAVA_BYTE.withName("major"),
JAVA_BYTE.withName("minor")
).withName("firmwareVersion")
).withName("CK_SLOT_INFO");
A naiv approach would be to write a helper method:
public static String getString(MemorySegment memorySegment, int offset, int length) {
byte[] slicedData = new byte[length];
MemorySegment slicedMemorySegment = memorySegment.asSlice(offset, length);
slicedMemorySegment.asByteBuffer().get(slicedData);
return new String(slicedData);
}
Then call it with the offset and length:
String manufacturerId = MemorySegmentUtils.getString(memorySegment, 64, 32);
Because PKCS11 uses different packing/padding, I don't want to hardcode these offsets and lengths. Using getUtf8String
like mentioned in Java VarHandle to a C string with java.lang.foreign API doesn't work because the char strings are fixed and not zero terminated.
So How can I use a MethodHandle
to read these bytes:
MethodHandle methodHandle = groupLayout.sliceHandle(MemoryLayout.PathElement.groupElement("manufacturerId"));
// What to do now?
String manufacturerId = ???
The solution looks like the following: