0

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

YShow
  • 3
  • 2

1 Answers1

0

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.

Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93
  • Using C_POINTER in the loop im able to get the first value VK_KHR_surface, the problem now is the second value, the SDL function returned 2 values( var inte = 2 ) that are in the char** array, the second value im still getting outOfBoundException – YShow Aug 25 '23 at 16:46
  • As a side note, i tried using your other answer (https://stackoverflow.com/questions/71250218/java-project-panama-and-how-to-deal-with-hunspell-suggest-result) to try to get the pointer but it didnt work – YShow Aug 25 '23 at 17:10
  • @YShow Yes, the old API with `MemoryAddress` allowed accessing memory without the separate step to resize the segment. – Jorn Vernee Aug 25 '23 at 17:16
  • @YShow For the second element issue is that you allocate a `pNames` array of only a single element: `var pNames = arena.allocate(ValueLayout.ADDRESS);`. I think you want [`allocateArray(ADDRESS, inte)`](https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/lang/foreign/SegmentAllocator.html#allocateArray(java.lang.foreign.MemoryLayout,long)) instead. – Jorn Vernee Aug 25 '23 at 17:18
  • Ohh that was for java-19, my bad then, still im getting OOBE on the second value in the array – YShow Aug 25 '23 at 17:20
  • You suggestions worked perfectly, thank you for you help – YShow Aug 25 '23 at 17:21