Search code examples
javaffiproject-panamajava-20

Java panama FFI, read (char **) from SDL_Vulkan_GetInstanceExtensions


This is the sample code that im trying to run, both SDL.h and SDL_Vulkan.h extracted with JExtract The problem im having is getting the pNames which is declared as char**, my understanding of java FFI is that anything that start with * or ** and so on is a ValueLayout.ADDRESS, in this case a array of strings in pointer, so to acess it i would have to first get the ADDRESS of each char array in a loop and transform it in an another ValueLayout.ADDRESS and then use getUtf8String, the problem is im getting outOfBoundException when i try to access the values in the pointer inside the loop and im out of ideas on how to access those strings

public class Test {

    public static void main(String[] args) throws NoSuchAlgorithmException {

        try (var arena = Arena.openConfined()) {

            if (SDL_Init(SDL_INIT_VIDEO()) < 0) {
                System.out.println(SDL_GetError().getUtf8String(0));
            } else {
                var window = SDL_CreateWindow(arena.allocateUtf8String("Windows"), SDL_WINDOWPOS_UNDEFINED(),
                        SDL_WINDOWPOS_UNDEFINED(), 800, 600, SDL_WINDOW_VULKAN() | SDL_WINDOW_HIDDEN());
                
                //unsigned int *pCount
                var pCount = arena.allocate(ValueLayout.ADDRESS);               
                
                var bool = SDL_Vulkan_GetInstanceExtensions(window, pCount, NULL());
                System.out.println(SDL_GetError().getUtf8String(0));
                
                //get int of count
                int inte = pCount.get(ValueLayout.JAVA_INT, 0);
                
                
                //char **
                var pNames = arena.allocate(ValueLayout.ADDRESS);
                
                var bool2 = SDL_Vulkan_GetInstanceExtensions(window, pCount, pNames);
                
                System.out.println(SDL_GetError().getUtf8String(0));
                System.out.println(inte);
                
                for (int i = 0; i < inte; i++) {
                    // char* (an element in the array)
                    var suggestion = pNames.getAtIndex(LibSDL2.C_POINTER, i);
                    // read the string
                    String pnameVk = suggestion.getUtf8String(0);
                    System.out.println(pnameVk);
                }           
            }
        }
    }
}

I`ve tried accessing pNames with offset on getUtf8String of 4 bytes but no success either

EDIT: added suggestion by Jorn Vernee, still getting error on the 2nd value, first one now shows


Solution

  • im getting outOfBoundException when i try to access the values in the pointer inside the loop

    See the section on zero-length memory segments in the javadoc of MemorySegment

    The suggestion region of memory who's address you read from the array has an unknown size, so the size of the memory segment is conservatively set to zero. To access the contents of the memory region, you either have to create a new MemorySegment with an explicit size using MemorySegment::ofAddress, or use an unbounded address layout (in Java 20) to read the address, which would give you an accessible segment in the first place.

    Jextract should already generate an unbounded address layout for you, so in this case it should be possible to use:

    var suggestion = pNames.getAtIndex(C_POINTER, i);
    

    This will make the suggestion segment have a size of Long.MAX_VALUE, which would allow you to read a string from it.