Search code examples
javascalajna

Passing pointer to byte array (byte**) to native function and get result array


I'm trying to use JNA to call native API in Scala. I don't know how to pass pointer of array of byte (byte**).

The signature of native API follows:

// this function mallocs some array buffer and stores it to passed pointer value
int func(byte **output);

Then I tried to pass pointer like this:

class NativeLibrary extends Library {
  def func(output: Array[Byte]) // doesn't work. thats' for byte*, not byte**
  def func(output: Array[Array[Byte]]) // doesn't work. JNA doesn't support this type
  def func(output: Memory) // works, but I don't know how to get inner array
}

Both don't seem to work, returning broken pointer value or raising SEGV.

How can I retrieve array from this native function?

Actual native function: https://github.com/VOICEVOX/voicevox_core/blob/0.13.0/core/src/core.h#L169


Solution

  • The ** represents a pointer to a pointer to a byte (the beginning of the byte array of interest), so the correct implementation is a PointerByReference:

    def func(output: PointerByReference): Int
    

    The value being returned is ultimately a Pointer. Since 'Memory' is a subclass of Pointer designed for Java-level allocation of memory. Since it's a subclass it appears to work, but is not the correct implementation.

    PointerByReference.getValue() returns the Pointer pointed to, removing one level of indirection to get you to byte*:

    // val size = size of buffer that you are passing to the actual function
    val pbr = new PointerByReference()
    // allocates the array and returns pointer to it
    val resultCode = NativeLibrary.INSTANCE.func(pbr)
    // get the pointer to the actual data
    val dataPointer = pbr.getValue()
    // get the data as a byte array
    val data = dataPointer.getByteArray(0, size)
    // later to free the `byte*`
    resultCode = voicevox_wav_free(dataPointer)