如何通过Java java.lang.foreign API访问本机字节数组

问题描述 投票:0回答:1

我想通过 FFI/Panama 从 Java 访问 PKCS11 库。假设我们在 Windows x64 下有以下 1 字节打包组布局:

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");

一个简单的方法是编写一个辅助方法:

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);
}

然后用偏移量和长度调用它:

String manufacturerId = MemorySegmentUtils.getString(memorySegment, 64, 32);

因为 PKCS11 使用不同的打包/填充,我不想对这些偏移量和长度进行硬编码。使用

getUtf8String
(如 Java VarHandle 中提到的使用 java.lang.foreign API 来处理 C 字符串)不起作用,因为字符字符串是固定的且不是以零结尾的。

那么我如何使用

MethodHandle
来读取这些字节:

MethodHandle methodHandle = groupLayout.sliceHandle(MemoryLayout.PathElement.groupElement("manufacturerId"));

// What to do now?
String manufacturerId = ???
java java-native-interface project-panama java-21
1个回答
0
投票

解决方案如下所示:

String slotDescription = MemorySegmentUtils.getFixedString(memorySegment, groupLayout, "slotDescription");
String manufacturerId = MemorySegmentUtils.getFixedString(memorySegment, groupLayout, "manufacturerId");

以及辅助方法:

public static byte[] getBytes(MemorySegment memorySegment) {
    byte[] data = new byte[(int) memorySegment.byteSize()];
    memorySegment.asByteBuffer().get(data);
    return data;
}

public static String getFixedString(MemorySegment memorySegment, GroupLayout groupLayout, String name) throws Throwable {
    MethodHandle methodHandle = groupLayout.sliceHandle(MemoryLayout.PathElement.groupElement(name));
    MemorySegment namedMemorySegment = (MemorySegment) methodHandle.invokeExact(memorySegment);
    return new String(MemorySegmentUtils.getBytes(namedMemorySegment));
}
© www.soinside.com 2019 - 2024. All rights reserved.