This is an automated email from the ASF dual-hosted git repository.

jsorel pushed a commit to branch fix/gsf
in repository https://gitbox.apache.org/repos/asf/sis.git

commit ee71f9f491791bf1d47e02a5f1356a1654d14df9
Author: jsorel <johann.so...@geomatys.com>
AuthorDate: Tue Sep 17 16:53:25 2024 +0200

    Cleaning GSF function binding and reader, reduce memory footprint
---
 .../org.apache.sis.storage/main/module-info.java   |    1 +
 .../src/org.apache.sis.util/main/module-info.java  |    1 +
 .../main/module-info.java                          |    1 +
 .../main/module-info.java                          |    3 +
 .../main/org/apache/sis/storage/gsf/GSF.java       | 1765 ++++++--------------
 .../apache/sis/storage/gsf/GSFException.java}      |   16 +-
 .../apache/sis/storage/gsf/GSFRecordReader.java    |   92 +-
 .../main/org/apache/sis/storage/gsf/GSFStore.java  |  103 ++
 .../apache/sis/storage/gsf/GSFStoreProvider.java   |  213 +++
 9 files changed, 849 insertions(+), 1346 deletions(-)

diff --git a/endorsed/src/org.apache.sis.storage/main/module-info.java 
b/endorsed/src/org.apache.sis.storage/main/module-info.java
index 17d69b0ed1..05fc298020 100644
--- a/endorsed/src/org.apache.sis.storage/main/module-info.java
+++ b/endorsed/src/org.apache.sis.storage/main/module-info.java
@@ -58,6 +58,7 @@ module org.apache.sis.storage {
             org.apache.sis.storage.shapefile,           // In the "incubator" 
sub-project.
             org.apache.sis.storage.geopackage,          // In the "incubator" 
sub-project.
             org.apache.sis.storage.gdal,                // In the "incubator" 
sub-project.
+            org.apache.sis.storage.gsf,                 // In the "incubator" 
sub-project.
             org.apache.sis.util,                        // For the "About" 
command.
             org.apache.sis.console,
             org.apache.sis.openoffice,
diff --git a/endorsed/src/org.apache.sis.util/main/module-info.java 
b/endorsed/src/org.apache.sis.util/main/module-info.java
index 9c6a2c0b53..040cfe0af5 100644
--- a/endorsed/src/org.apache.sis.util/main/module-info.java
+++ b/endorsed/src/org.apache.sis.util/main/module-info.java
@@ -146,6 +146,7 @@ module org.apache.sis.util {
             org.apache.sis.storage.sql,
             org.apache.sis.storage.netcdf,
             org.apache.sis.storage.gdal,                // In the "incubator" 
sub-project.
+            org.apache.sis.storage.gsf,                 // In the "incubator" 
sub-project.
             org.apache.sis.portrayal,
             org.apache.sis.console,
             org.apache.sis.webapp,                      // In the "incubator" 
sub-project.
diff --git a/incubator/src/org.apache.sis.storage.gdal/main/module-info.java 
b/incubator/src/org.apache.sis.storage.gdal/main/module-info.java
index e4d87b9584..3c5d938bc2 100644
--- a/incubator/src/org.apache.sis.storage.gdal/main/module-info.java
+++ b/incubator/src/org.apache.sis.storage.gdal/main/module-info.java
@@ -53,6 +53,7 @@ module org.apache.sis.storage.gdal {
     requires transitive org.apache.sis.storage;
 
     exports org.apache.sis.storage.gdal;
+    exports org.apache.sis.storage.panama;
 
     provides org.apache.sis.storage.DataStoreProvider
             with org.apache.sis.storage.gdal.GDALStoreProvider;
diff --git a/incubator/src/org.apache.sis.storage.gsf/main/module-info.java 
b/incubator/src/org.apache.sis.storage.gsf/main/module-info.java
index b3d64887cc..0624ffd2ac 100644
--- a/incubator/src/org.apache.sis.storage.gsf/main/module-info.java
+++ b/incubator/src/org.apache.sis.storage.gsf/main/module-info.java
@@ -24,5 +24,8 @@ module org.apache.sis.storage.gsf {
     // Dependencies used in public API.
     requires transitive org.apache.sis.referencing;
     requires transitive org.apache.sis.storage;
+    requires transitive org.apache.sis.storage.gdal;
 
+    provides org.apache.sis.storage.DataStoreProvider
+            with org.apache.sis.storage.gsf.GSFStoreProvider;
 }
diff --git 
a/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSF.java
 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSF.java
index 7ed68f4d27..544a731e73 100644
--- 
a/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSF.java
+++ 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSF.java
@@ -22,995 +22,39 @@ import java.lang.foreign.FunctionDescriptor;
 import java.lang.foreign.Linker;
 import java.lang.foreign.MemoryLayout;
 import java.lang.foreign.MemorySegment;
-import java.lang.foreign.SymbolLookup;
 import java.lang.foreign.ValueLayout;
-import static java.lang.foreign.ValueLayout.JAVA_BYTE;
 import java.lang.invoke.MethodHandle;
-import java.util.Arrays;
-import java.util.stream.Collectors;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.panama.LibraryLoader;
+import org.apache.sis.storage.panama.LibraryStatus;
+import org.apache.sis.storage.panama.NativeFunctions;
+import org.apache.sis.util.logging.Logging;
 
+/**
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public class GSF extends NativeFunctions {
 
-/**
- *
- * @author Johann Sorel (Geomatys)
- */
-public final class GSF {
-
-    static final Arena LIBRARY_ARENA = Arena.ofAuto();
-    static final boolean TRACE_DOWNCALLS = 
Boolean.getBoolean("jextract.trace.downcalls");
-
-    static void traceDowncall(String name, Object... args) {
-         String traceArgs = Arrays.stream(args)
-                       .map(Object::toString)
-                       .collect(Collectors.joining(", "));
-         System.out.printf("%s(%s)\n", name, traceArgs);
-    }
-
-    public static final ValueLayout.OfBoolean C_BOOL = 
ValueLayout.JAVA_BOOLEAN;
-    public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE;
-    public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT;
-    public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT;
-    public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG;
-    public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT;
-    public static final ValueLayout.OfDouble C_DOUBLE = 
ValueLayout.JAVA_DOUBLE;
-    public static final AddressLayout C_POINTER = ValueLayout.ADDRESS
-            
.withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, 
JAVA_BYTE));
-    public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG;
-
-    static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup()
-            .or(Linker.nativeLinker().defaultLookup());
-
-    public static final MemorySegment NULL = MemorySegment.ofAddress(0L);
-    public static final int EOF = -1;
-
-
-    static MemorySegment findOrThrow(String symbol) {
-        return SYMBOL_LOOKUP.find(symbol)
-            .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " 
+ symbol));
-    }
-
-    private static class gsfOpen {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_INT,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = GSF.findOrThrow("gsfOpen");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfOpen(const char *filename, const int mode, int *handle)
-     * }
-     */
-    public static int gsfOpen(MemorySegment filename, int mode, MemorySegment 
handle) {
-        var mh$ = gsfOpen.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfOpen", filename, mode, handle);
-            }
-            return (int)mh$.invokeExact(filename, mode, handle);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfOpenBuffered {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_INT
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfOpenBuffered");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfOpenBuffered(const char *filename, const int mode, int *handle, 
int buf_size)
-     * }
-     */
-    public static int gsfOpenBuffered(MemorySegment filename, int mode, 
MemorySegment handle, int buf_size) {
-        var mh$ = gsfOpenBuffered.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfOpenBuffered", filename, mode, handle, 
buf_size);
-            }
-            return (int)mh$.invokeExact(filename, mode, handle, buf_size);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfClose {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT
-        );
-
-        public static final MemorySegment ADDR = GSF.findOrThrow("gsfClose");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfClose(const int handle)
-     * }
-     */
-    public static int gsfClose(int handle) {
-        var mh$ = gsfClose.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfClose", handle);
-            }
-            return (int)mh$.invokeExact(handle);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfSeek {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_INT
-        );
-
-        public static final MemorySegment ADDR = GSF.findOrThrow("gsfSeek");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfSeek(int handle, int option)
-     * }
-     */
-    public static int gsfSeek(int handle, int option) {
-        var mh$ = gsfSeek.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfSeek", handle, option);
-            }
-            return (int)mh$.invokeExact(handle, option);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfRead {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_POINTER,
-            GSF.C_POINTER,
-            GSF.C_INT
-        );
-
-        public static final MemorySegment ADDR = GSF.findOrThrow("gsfRead");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfRead(int handle, int desiredRecord, gsfDataID *dataID, 
gsfRecords *rec, unsigned char *stream, int max_size)
-     * }
-     */
-    public static int gsfRead(int handle, int desiredRecord, MemorySegment 
dataID, MemorySegment rec, MemorySegment stream, int max_size) {
-        var mh$ = gsfRead.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfRead", handle, desiredRecord, dataID, rec, 
stream, max_size);
-            }
-            return (int)mh$.invokeExact(handle, desiredRecord, dataID, rec, 
stream, max_size);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfWrite {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = GSF.findOrThrow("gsfWrite");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfWrite(int handle, gsfDataID *id, gsfRecords *record)
-     * }
-     */
-    public static int gsfWrite(int handle, MemorySegment id, MemorySegment 
record_) {
-        var mh$ = gsfWrite.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfWrite", handle, id, record_);
-            }
-            return (int)mh$.invokeExact(handle, id, record_);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfLoadScaleFactor {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_INT,
-            GSF.C_CHAR,
-            GSF.C_DOUBLE,
-            GSF.C_INT
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfLoadScaleFactor");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfLoadScaleFactor(gsfScaleFactors *sf, unsigned int subrecordID, 
char c_flag, double precision, int offset)
-     * }
-     */
-    public static int gsfLoadScaleFactor(MemorySegment sf, int subrecordID, 
byte c_flag, double precision, int offset) {
-        var mh$ = gsfLoadScaleFactor.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfLoadScaleFactor", sf, subrecordID, c_flag, 
precision, offset);
-            }
-            return (int)mh$.invokeExact(sf, subrecordID, c_flag, precision, 
offset);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfGetScaleFactor {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_POINTER,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfGetScaleFactor");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfGetScaleFactor(int handle, unsigned int subrecordID, unsigned 
char *c_flag, double *multiplier, double *offset)
-     * }
-     */
-    public static int gsfGetScaleFactor(int handle, int subrecordID, 
MemorySegment c_flag, MemorySegment multiplier, MemorySegment offset) {
-        var mh$ = gsfGetScaleFactor.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfGetScaleFactor", handle, subrecordID, 
c_flag, multiplier, offset);
-            }
-            return (int)mh$.invokeExact(handle, subrecordID, c_flag, 
multiplier, offset);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfFree {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.ofVoid(GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = GSF.findOrThrow("gsfFree");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * void gsfFree(gsfRecords *rec)
-     * }
-     */
-    public static void gsfFree(MemorySegment rec) {
-        var mh$ = gsfFree.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfFree", rec);
-            }
-            mh$.invokeExact(rec);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfPrintError {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.ofVoid(GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfPrintError");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * void gsfPrintError(FILE *fp)
-     * }
-     */
-    public static void gsfPrintError(MemorySegment fp) {
-        var mh$ = gsfPrintError.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfPrintError", fp);
-            }
-            mh$.invokeExact(fp);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfIntError {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT    );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfIntError");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfIntError()
-     * }
-     */
-    public static int gsfIntError() {
-        var mh$ = gsfIntError.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfIntError");
-            }
-            return (int)mh$.invokeExact();
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfStringError {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_POINTER    );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfStringError");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * const char *gsfStringError()
-     * }
-     */
-    public static MemorySegment gsfStringError() {
-        var mh$ = gsfStringError.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfStringError");
-            }
-            return (MemorySegment)mh$.invokeExact();
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfIndexTime {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfIndexTime");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfIndexTime(int handle, int recordID, int record_number, time_t 
*sec, long *nsec)
-     * }
-     */
-    public static int gsfIndexTime(int handle, int recordID, int 
record_number, MemorySegment sec, MemorySegment nsec) {
-        var mh$ = gsfIndexTime.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfIndexTime", handle, recordID, record_number, 
sec, nsec);
-            }
-            return (int)mh$.invokeExact(handle, recordID, record_number, sec, 
nsec);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfPercent {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT
-        );
-
-        public static final MemorySegment ADDR = GSF.findOrThrow("gsfPercent");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfPercent(int handle)
-     * }
-     */
-    public static int gsfPercent(int handle) {
-        var mh$ = gsfPercent.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfPercent", handle);
-            }
-            return (int)mh$.invokeExact(handle);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfGetNumberRecords {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_INT
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfGetNumberRecords");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfGetNumberRecords(int handle, int desiredRecord)
-     * }
-     */
-    public static int gsfGetNumberRecords(int handle, int desiredRecord) {
-        var mh$ = gsfGetNumberRecords.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfGetNumberRecords", handle, desiredRecord);
-            }
-            return (int)mh$.invokeExact(handle, desiredRecord);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfCopyRecords {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfCopyRecords");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfCopyRecords(gsfRecords *target, const gsfRecords *source)
-     * }
-     */
-    public static int gsfCopyRecords(MemorySegment target, MemorySegment 
source) {
-        var mh$ = gsfCopyRecords.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfCopyRecords", target, source);
-            }
-            return (int)mh$.invokeExact(target, source);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfPutMBParams {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_POINTER,
-            GSF.C_INT,
-            GSF.C_INT
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfPutMBParams");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfPutMBParams(const gsfMBParams *p, gsfRecords *rec, int handle, 
int numArrays)
-     * }
-     */
-    public static int gsfPutMBParams(MemorySegment p, MemorySegment rec, int 
handle, int numArrays) {
-        var mh$ = gsfPutMBParams.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfPutMBParams", p, rec, handle, numArrays);
-            }
-            return (int)mh$.invokeExact(p, rec, handle, numArrays);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfGetMBParams {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_POINTER,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfGetMBParams");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfGetMBParams(const gsfRecords *rec, gsfMBParams *p, int 
*numArrays)
-     * }
-     */
-    public static int gsfGetMBParams(MemorySegment rec, MemorySegment p, 
MemorySegment numArrays) {
-        var mh$ = gsfGetMBParams.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfGetMBParams", rec, p, numArrays);
-            }
-            return (int)mh$.invokeExact(rec, p, numArrays);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfGetSwathBathyBeamWidths {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_POINTER,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfGetSwathBathyBeamWidths");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfGetSwathBathyBeamWidths(const gsfRecords *data, double 
*fore_aft, double *athwartship)
-     * }
-     */
-    public static int gsfGetSwathBathyBeamWidths(MemorySegment data, 
MemorySegment fore_aft, MemorySegment athwartship) {
-        var mh$ = gsfGetSwathBathyBeamWidths.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfGetSwathBathyBeamWidths", data, fore_aft, 
athwartship);
-            }
-            return (int)mh$.invokeExact(data, fore_aft, athwartship);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfIsStarboardPing {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfIsStarboardPing");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfIsStarboardPing(const gsfRecords *data)
-     * }
-     */
-    public static int gsfIsStarboardPing(MemorySegment data) {
-        var mh$ = gsfIsStarboardPing.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfIsStarboardPing", data);
-            }
-            return (int)mh$.invokeExact(data);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfLoadDepthScaleFactorAutoOffset {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_DOUBLE,
-            GSF.C_DOUBLE,
-            GSF.C_POINTER,
-            GSF.C_CHAR,
-            GSF.C_DOUBLE
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfLoadDepthScaleFactorAutoOffset");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfLoadDepthScaleFactorAutoOffset(gsfSwathBathyPing *ping, unsigned 
int subrecordID, int reset, double min_depth, double max_depth, double 
*last_corrector, char c_flag, double precision)
-     * }
-     */
-    public static int gsfLoadDepthScaleFactorAutoOffset(MemorySegment ping, 
int subrecordID, int reset, double min_depth, double max_depth, MemorySegment 
last_corrector, byte c_flag, double precision) {
-        var mh$ = gsfLoadDepthScaleFactorAutoOffset.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfLoadDepthScaleFactorAutoOffset", ping, 
subrecordID, reset, min_depth, max_depth, last_corrector, c_flag, precision);
-            }
-            return (int)mh$.invokeExact(ping, subrecordID, reset, min_depth, 
max_depth, last_corrector, c_flag, precision);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfGetSwathBathyArrayMinMax {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfGetSwathBathyArrayMinMax");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfGetSwathBathyArrayMinMax(const gsfSwathBathyPing *ping, unsigned 
int subrecordID, double *min_value, double *max_value)
-     * }
-     */
-    public static int gsfGetSwathBathyArrayMinMax(MemorySegment ping, int 
subrecordID, MemorySegment min_value, MemorySegment max_value) {
-        var mh$ = gsfGetSwathBathyArrayMinMax.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfGetSwathBathyArrayMinMax", ping, 
subrecordID, min_value, max_value);
-            }
-            return (int)mh$.invokeExact(ping, subrecordID, min_value, 
max_value);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfGetSonarTextName {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_POINTER,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfGetSonarTextName");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * const char *gsfGetSonarTextName(const gsfSwathBathyPing *ping)
-     * }
-     */
-    public static MemorySegment gsfGetSonarTextName(MemorySegment ping) {
-        var mh$ = gsfGetSonarTextName.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfGetSonarTextName", ping);
-            }
-            return (MemorySegment)mh$.invokeExact(ping);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfFileSupportsRecalculateXYZ {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfFileSupportsRecalculateXYZ");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfFileSupportsRecalculateXYZ(int handle, int *status)
-     * }
-     */
-    public static int gsfFileSupportsRecalculateXYZ(int handle, MemorySegment 
status) {
-        var mh$ = gsfFileSupportsRecalculateXYZ.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfFileSupportsRecalculateXYZ", handle, status);
-            }
-            return (int)mh$.invokeExact(handle, status);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfFileSupportsRecalculateTPU {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfFileSupportsRecalculateTPU");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfFileSupportsRecalculateTPU(int handle, int *status)
-     * }
-     */
-    public static int gsfFileSupportsRecalculateTPU(int handle, MemorySegment 
status) {
-        var mh$ = gsfFileSupportsRecalculateTPU.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfFileSupportsRecalculateTPU", handle, status);
-            }
-            return (int)mh$.invokeExact(handle, status);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfFileSupportsRecalculateNominalDepth {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfFileSupportsRecalculateNominalDepth");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfFileSupportsRecalculateNominalDepth(int handle, int *status)
-     * }
-     */
-    public static int gsfFileSupportsRecalculateNominalDepth(int handle, 
MemorySegment status) {
-        var mh$ = gsfFileSupportsRecalculateNominalDepth.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfFileSupportsRecalculateNominalDepth", 
handle, status);
-            }
-            return (int)mh$.invokeExact(handle, status);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfFileContainsMBAmplitude {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfFileContainsMBAmplitude");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfFileContainsMBAmplitude(int handle, int *status)
-     * }
-     */
-    public static int gsfFileContainsMBAmplitude(int handle, MemorySegment 
status) {
-        var mh$ = gsfFileContainsMBAmplitude.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfFileContainsMBAmplitude", handle, status);
-            }
-            return (int)mh$.invokeExact(handle, status);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfFileContainsMBImagery {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfFileContainsMBImagery");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfFileContainsMBImagery(int handle, int *status)
-     * }
-     */
-    public static int gsfFileContainsMBImagery(int handle, MemorySegment 
status) {
-        var mh$ = gsfFileContainsMBImagery.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfFileContainsMBImagery", handle, status);
-            }
-            return (int)mh$.invokeExact(handle, status);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfIsNewSurveyLine {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_DOUBLE,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfIsNewSurveyLine");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfIsNewSurveyLine(int handle, const gsfRecords *rec, double 
azimuth_change, double *last_heading)
-     * }
-     */
-    public static int gsfIsNewSurveyLine(int handle, MemorySegment rec, double 
azimuth_change, MemorySegment last_heading) {
-        var mh$ = gsfIsNewSurveyLine.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfIsNewSurveyLine", handle, rec, 
azimuth_change, last_heading);
-            }
-            return (int)mh$.invokeExact(handle, rec, azimuth_change, 
last_heading);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfInitializeMBParams {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.ofVoid(GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfInitializeMBParams");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * void gsfInitializeMBParams(gsfMBParams *p)
-     * }
-     */
-    public static void gsfInitializeMBParams(MemorySegment p) {
-        var mh$ = gsfInitializeMBParams.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfInitializeMBParams", p);
-            }
-            mh$.invokeExact(p);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfStat {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_INT,
-            GSF.C_POINTER,
-            GSF.C_POINTER
-        );
-
-        public static final MemorySegment ADDR = GSF.findOrThrow("gsfStat");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * int gsfStat(const char *filename, long long *sz)
-     * }
-     */
-    public static int gsfStat(MemorySegment filename, MemorySegment sz) {
-        var mh$ = gsfStat.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfStat", filename, sz);
-            }
-            return (int)mh$.invokeExact(filename, sz);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfGetPositionDestination {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_POINTER,
-            Position.LAYOUT,
-            PositionOffsets.LAYOUT,
-            GSF.C_DOUBLE,
-            GSF.C_DOUBLE
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfGetPositionDestination");
-
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
-
-    /**
-     * {@snippet lang=c :
-     * GSF_POSITION *gsfGetPositionDestination(GSF_POSITION gp, 
GSF_POSITION_OFFSETS offsets, double hdg, double dist_step)
-     * }
-     */
-    public static MemorySegment gsfGetPositionDestination(MemorySegment gp, 
MemorySegment offsets, double hdg, double dist_step) {
-        var mh$ = gsfGetPositionDestination.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfGetPositionDestination", gp, offsets, hdg, 
dist_step);
-            }
-            return (MemorySegment)mh$.invokeExact(gp, offsets, hdg, dist_step);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
-
-    private static class gsfGetPositionOffsets {
-        public static final FunctionDescriptor DESC = 
FunctionDescriptor.of(GSF.C_POINTER,
-            Position.LAYOUT,
-            Position.LAYOUT,
-            GSF.C_DOUBLE,
-            GSF.C_DOUBLE
-        );
-
-        public static final MemorySegment ADDR = 
GSF.findOrThrow("gsfGetPositionOffsets");
+    public static final MemorySegment NULL = MemorySegment.ofAddress(0L);
+    public static final int EOF = -1;
 
-        public static final MethodHandle HANDLE = 
Linker.nativeLinker().downcallHandle(ADDR, DESC);
-    }
+    public static final ValueLayout.OfBoolean C_BOOL = 
ValueLayout.JAVA_BOOLEAN;
+    public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE;
+    public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT;
+    public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT;
+    public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG;
+    public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT;
+    public static final ValueLayout.OfDouble C_DOUBLE = 
ValueLayout.JAVA_DOUBLE;
+    public static final AddressLayout C_POINTER = 
ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE,
 ValueLayout.JAVA_BYTE));
+    public static final ValueLayout.OfLong C_LONG = ValueLayout.JAVA_LONG;
 
-    /**
-     * {@snippet lang=c :
-     * GSF_POSITION_OFFSETS *gsfGetPositionOffsets(GSF_POSITION gp_from, 
GSF_POSITION gp_to, double hdg, double dist_step)
-     * }
-     */
-    public static MemorySegment gsfGetPositionOffsets(MemorySegment gp_from, 
MemorySegment gp_to, double hdg, double dist_step) {
-        var mh$ = gsfGetPositionOffsets.HANDLE;
-        try {
-            if (TRACE_DOWNCALLS) {
-                traceDowncall("gsfGetPositionOffsets", gp_from, gp_to, hdg, 
dist_step);
-            }
-            return (MemorySegment)mh$.invokeExact(gp_from, gp_to, hdg, 
dist_step);
-        } catch (Throwable ex$) {
-           throw new AssertionError("should not reach here", ex$);
-        }
-    }
 
     public static final int GSF_MAX_RECORD_SIZE = 524288;
     public static final int GSF_MAX_OPEN_FILES = 4;
@@ -1244,42 +288,7 @@ public final class GSF {
     public static final int FD_SETSIZE = 1024;
     public static final int NFDBITS = 64;
     public static final int __PTHREAD_RWLOCK_ELISION_EXTRA = 0;
-    /**
-     * {@snippet lang=c :
-     * #define GSF_MAJOR_VERSION "03"
-     * }
-     */
-    public static MemorySegment GSF_MAJOR_VERSION() {
-        class Holder {
-            static final MemorySegment GSF_MAJOR_VERSION
-                = GSF.LIBRARY_ARENA.allocateFrom("03");
-        }
-        return Holder.GSF_MAJOR_VERSION;
-    }
-    /**
-     * {@snippet lang=c :
-     * #define GSF_MINOR_VERSION "09"
-     * }
-     */
-    public static MemorySegment GSF_MINOR_VERSION() {
-        class Holder {
-            static final MemorySegment GSF_MINOR_VERSION
-                = GSF.LIBRARY_ARENA.allocateFrom("09");
-        }
-        return Holder.GSF_MINOR_VERSION;
-    }
-    /**
-     * {@snippet lang=c :
-     * #define GSF_VERSION "GSF-v03.09"
-     * }
-     */
-    public static MemorySegment GSF_VERSION() {
-        class Holder {
-            static final MemorySegment GSF_VERSION
-                = GSF.LIBRARY_ARENA.allocateFrom("GSF-v03.09");
-        }
-        return Holder.GSF_VERSION;
-    }
+
     public static final int GSF_RECORD_HEADER = 1;
     public static final int GSF_RECORD_SWATH_BATHYMETRY_PING = 2;
     public static final int GSF_RECORD_SOUND_VELOCITY_PROFILE = 3;
@@ -1453,335 +462,501 @@ public final class GSF {
     public static final int GSF_INTENSITY_CALIBRATED = 2;
     public static final int GSF_INTENSITY_POWER = 4;
     public static final int GSF_INTENSITY_GAIN = 8;
+
+    public static final double GSF_UNKNOWN_PARAM_VALUE = 
2.2250738585072014E-308d;
+
+    private static final Map<Integer,String> ERRORCODES;
+    static {
+        ERRORCODES = new HashMap<>();
+        ERRORCODES.put(-99,"GSF_UNKNOWN_PARAM_INT");
+        ERRORCODES.put(-1,"GSF_FOPEN_ERROR");
+        ERRORCODES.put(-2,"GSF_UNRECOGNIZED_FILE");
+        ERRORCODES.put(-3,"GSF_BAD_ACCESS_MODE");
+        ERRORCODES.put(-4,"GSF_READ_ERROR");
+        ERRORCODES.put(-5,"GSF_WRITE_ERROR");
+        ERRORCODES.put(-6,"GSF_INSUFFICIENT_SIZE");
+        ERRORCODES.put(-7,"GSF_RECORD_SIZE_ERROR");
+        ERRORCODES.put(-8,"GSF_CHECKSUM_FAILURE");
+        ERRORCODES.put(-9,"GSF_FILE_CLOSE_ERROR");
+        ERRORCODES.put(-10,"GSF_TOO_MANY_ARRAY_SUBRECORDS");
+        ERRORCODES.put(-11,"GSF_TOO_MANY_OPEN_FILES");
+        ERRORCODES.put(-12,"GSF_MEMORY_ALLOCATION_FAILED");
+        ERRORCODES.put(-13,"GSF_UNRECOGNIZED_RECORD_ID");
+        ERRORCODES.put(-14,"GSF_STREAM_DECODE_FAILURE");
+        ERRORCODES.put(-15,"GSF_BAD_SEEK_OPTION");
+        ERRORCODES.put(-16,"GSF_FILE_SEEK_ERROR");
+        ERRORCODES.put(-17,"GSF_UNRECOGNIZED_SENSOR_ID");
+        ERRORCODES.put(-18,"GSF_UNRECOGNIZED_DATA_RECORD");
+        ERRORCODES.put(-19,"GSF_UNRECOGNIZED_ARRAY_SUBRECORD_ID");
+        ERRORCODES.put(-20,"GSF_UNRECOGNIZED_SUBRECORD_ID");
+        ERRORCODES.put(-21,"GSF_ILLEGAL_SCALE_FACTOR_MULTIPLIER");
+        ERRORCODES.put(-22,"GSF_CANNOT_REPRESENT_PRECISION");
+        ERRORCODES.put(-23,"GSF_READ_TO_END_OF_FILE");
+        ERRORCODES.put(-24,"GSF_BAD_FILE_HANDLE");
+        ERRORCODES.put(-25,"GSF_HEADER_RECORD_ENCODE_OR_DECODE_FAILED");
+        ERRORCODES.put(-26,"GSF_MB_PING_RECORD_ENCODE_OR_DECODE_FAILED");
+        ERRORCODES.put(-27,"GSF_SVP_RECORD_ENCODE_OR_DECODE_FAILED");
+        ERRORCODES.put(-28,"GSF_PROCESS_PARAM_RECORD_ENCODE_OR_DECODE_FAILED");
+        ERRORCODES.put(-29,"GSF_SENSOR_PARAM_RECORD_ENCODE_OR_DECODE_FAILED");
+        ERRORCODES.put(-30,"GSF_COMMENT_RECORD_ENCODE_OR_DECODE_FAILED");
+        ERRORCODES.put(-31,"GSF_HISTORY_RECORD_ENCODE_OR_DECODE_FAILED");
+        ERRORCODES.put(-32,"GSF_NAV_ERROR_RECORD_ENCODE_OR_DECODE_FAILED");
+        ERRORCODES.put(-33,"GSF_SETVBUF_ERROR");
+        ERRORCODES.put(-34,"GSF_FLUSH_ERROR");
+        ERRORCODES.put(-35,"GSF_FILE_TELL_ERROR");
+        ERRORCODES.put(-36,"GSF_INDEX_FILE_OPEN_ERROR");
+        ERRORCODES.put(-37,"GSF_CORRUPT_INDEX_FILE_ERROR");
+        ERRORCODES.put(-38,"GSF_SCALE_INDEX_CALLOC_ERROR");
+        ERRORCODES.put(-39,"GSF_RECORD_TYPE_NOT_AVAILABLE");
+        ERRORCODES.put(-40,"GSF_SUMMARY_RECORD_DECODE_FAILED");
+        ERRORCODES.put(-41,"GSF_SUMMARY_RECORD_ENCODE_FAILED");
+        ERRORCODES.put(-42,"GSF_INVALID_NUM_BEAMS");
+        ERRORCODES.put(-43,"GSF_INVALID_RECORD_NUMBER");
+        ERRORCODES.put(-44,"GSF_INDEX_FILE_READ_ERROR");
+        ERRORCODES.put(-45,"GSF_PARAM_SIZE_FIXED");
+        ERRORCODES.put(-46,"GSF_SINGLE_BEAM_ENCODE_FAILED");
+        ERRORCODES.put(-47,"GSF_HV_NAV_ERROR_RECORD_ENCODE_FAILED");
+        ERRORCODES.put(-48,"GSF_HV_NAV_ERROR_RECORD_DECODE_FAILED");
+        ERRORCODES.put(-49,"GSF_ATTITUDE_RECORD_ENCODE_FAILED");
+        ERRORCODES.put(-50,"GSF_ATTITUDE_RECORD_DECODE_FAILED");
+        ERRORCODES.put(-51,"GSF_OPEN_TEMP_FILE_FAILED");
+        ERRORCODES.put(-52,"GSF_PARTIAL_RECORD_AT_END_OF_FILE");
+        ERRORCODES.put(-53,"GSF_QUALITY_FLAGS_DECODE_ERROR");
+        ERRORCODES.put(-55,"GSF_COMPRESSION_UNSUPPORTED");
+        ERRORCODES.put(-56,"GSF_COMPRESSION_FAILED");
+    }
+
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_UNKN "UNKN"
-     * }
+     * The global instance, created when first needed.
+     * This field shall be read and updated in a synchronized block.
+     * It may be reset to {@code null} if <abbr>GSF</abbr> reported a fatal 
error.
+     *
+     * @see #global(boolean)
      */
-    public static MemorySegment GSF_POS_TYPE_UNKN() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_UNKN
-                = GSF.LIBRARY_ARENA.allocateFrom("UNKN");
-        }
-        return Holder.GSF_POS_TYPE_UNKN;
-    }
+    private static GSF global;
+
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_GPSU "GPSU"
-     * }
+     * Whether an error occurred during initialization of {@link #global}.
+     * Shall be read and updated in the same synchronization block as {@link 
#global}.
      */
-    public static MemorySegment GSF_POS_TYPE_GPSU() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_GPSU
-                = GSF.LIBRARY_ARENA.allocateFrom("GPSU");
-        }
-        return Holder.GSF_POS_TYPE_GPSU;
-    }
+    private static LibraryStatus globalStatus;
+
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_PPSD "PPSD"
-     * }
+     * {@snippet lang=c : int gsfOpen(const char *filename, const int mode, 
int *handle) }.
      */
-    public static MemorySegment GSF_POS_TYPE_PPSD() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_PPSD
-                = GSF.LIBRARY_ARENA.allocateFrom("PPSD");
-        }
-        return Holder.GSF_POS_TYPE_PPSD;
-    }
+    final MethodHandle gsfOpen;
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_PPSK "PPSK"
-     * }
+     * {@snippet lang=c : int gsfOpenBuffered(const char *filename, const int 
mode, int *handle, int buf_size) }
      */
-    public static MemorySegment GSF_POS_TYPE_PPSK() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_PPSK
-                = GSF.LIBRARY_ARENA.allocateFrom("PPSK");
-        }
-        return Holder.GSF_POS_TYPE_PPSK;
-    }
+    final MethodHandle gsfOpenBuffered;
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_PPSS "PPSS"
-     * }
+     * {@snippet lang=c : int gsfClose(const int handle) }
      */
-    public static MemorySegment GSF_POS_TYPE_PPSS() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_PPSS
-                = GSF.LIBRARY_ARENA.allocateFrom("PPSS");
-        }
-        return Holder.GSF_POS_TYPE_PPSS;
-    }
+    final MethodHandle gsfClose;
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_PPSG "PPSG"
-     * }
+     * {@snippet lang=c : int gsfSeek(int handle, int option)}
      */
-    public static MemorySegment GSF_POS_TYPE_PPSG() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_PPSG
-                = GSF.LIBRARY_ARENA.allocateFrom("PPSG");
-        }
-        return Holder.GSF_POS_TYPE_PPSG;
-    }
+    final MethodHandle gsfSeek;
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_SPSD "SPSD"
-     * }
+     * {@snippet lang=c : int gsfRead(int handle, int desiredRecord, gsfDataID 
*dataID, gsfRecords *rec, unsigned char *stream, int max_size) }
      */
-    public static MemorySegment GSF_POS_TYPE_SPSD() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_SPSD
-                = GSF.LIBRARY_ARENA.allocateFrom("SPSD");
-        }
-        return Holder.GSF_POS_TYPE_SPSD;
-    }
+    final MethodHandle gsfRead;
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_SPSK "SPSK"
-     * }
+     * {@snippet lang=c : int gsfWrite(int handle, gsfDataID *id, gsfRecords 
*record) }
      */
-    public static MemorySegment GSF_POS_TYPE_SPSK() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_SPSK
-                = GSF.LIBRARY_ARENA.allocateFrom("SPSK");
-        }
-        return Holder.GSF_POS_TYPE_SPSK;
-    }
+    final MethodHandle gsfWrite;
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_SPSS "SPSS"
-     * }
+     * {@snippet lang=c : int gsfLoadScaleFactor(gsfScaleFactors *sf, unsigned 
int subrecordID, char c_flag, double precision, int offset) }
      */
-    public static MemorySegment GSF_POS_TYPE_SPSS() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_SPSS
-                = GSF.LIBRARY_ARENA.allocateFrom("SPSS");
-        }
-        return Holder.GSF_POS_TYPE_SPSS;
-    }
+    final MethodHandle gsfLoadScaleFactor;
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_SPSG "SPSG"
-     * }
+     * {@snippet lang=c : int gsfGetScaleFactor(int handle, unsigned int 
subrecordID, unsigned char *c_flag, double *multiplier, double *offset) }
      */
-    public static MemorySegment GSF_POS_TYPE_SPSG() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_SPSG
-                = GSF.LIBRARY_ARENA.allocateFrom("SPSG");
-        }
-        return Holder.GSF_POS_TYPE_SPSG;
-    }
+    final MethodHandle gsfGetScaleFactor;
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_GPPP "GPPP"
-     * }
+     * {@snippet lang=c : void gsfFree(gsfRecords *rec) }
+     * <p>
+     * This function frees all dynamically allocated memory from a gsfRecords 
data structure, and then clears
+     * all the data elements in the structure.
      */
-    public static MemorySegment GSF_POS_TYPE_GPPP() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_GPPP
-                = GSF.LIBRARY_ARENA.allocateFrom("GPPP");
-        }
-        return Holder.GSF_POS_TYPE_GPPP;
-    }
+    final MethodHandle gsfFree;
     /**
-     * {@snippet lang=c :
-     * #define GPS_POS_TYPE_GPPK "GPPK"
-     * }
+     * {@snippet lang=c : void gsfPrintError(FILE *fp) }
      */
-    public static MemorySegment GPS_POS_TYPE_GPPK() {
-        class Holder {
-            static final MemorySegment GPS_POS_TYPE_GPPK
-                = GSF.LIBRARY_ARENA.allocateFrom("GPPK");
-        }
-        return Holder.GPS_POS_TYPE_GPPK;
-    }
+    final MethodHandle gsfPrintError;
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_INUA "INUA"
-     * }
+     * {@snippet lang=c : int gsfIntError() }
      */
-    public static MemorySegment GSF_POS_TYPE_INUA() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_INUA
-                = GSF.LIBRARY_ARENA.allocateFrom("INUA");
-        }
-        return Holder.GSF_POS_TYPE_INUA;
-    }
+    final MethodHandle gsfIntError;
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_INVA "INVA"
-     * }
+     * {@snippet lang=c : const char *gsfStringError() }
      */
-    public static MemorySegment GSF_POS_TYPE_INVA() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_INVA
-                = GSF.LIBRARY_ARENA.allocateFrom("INVA");
-        }
-        return Holder.GSF_POS_TYPE_INVA;
-    }
+    final MethodHandle gsfStringError;
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_INWA "INWA"
-     * }
+     * {@snippet lang=c : int gsfIndexTime(int handle, int recordID, int 
record_number, time_t *sec, long *nsec) }
      */
-    public static MemorySegment GSF_POS_TYPE_INWA() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_INWA
-                = GSF.LIBRARY_ARENA.allocateFrom("INWA");
-        }
-        return Holder.GSF_POS_TYPE_INWA;
-    }
+    final MethodHandle gsfIndexTime;
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_LBLN "LBLN"
-     * }
+     * {@snippet lang=c : int gsfPercent(int handle) }
      */
-    public static MemorySegment GSF_POS_TYPE_LBLN() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_LBLN
-                = GSF.LIBRARY_ARENA.allocateFrom("LBLN");
-        }
-        return Holder.GSF_POS_TYPE_LBLN;
+    final MethodHandle gsfPercent;
+    /**
+     * {@snippet lang=c : int gsfGetNumberRecords(int handle, int 
desiredRecord) }
+     */
+    final MethodHandle gsfGetNumberRecords;
+    /**
+     * {@snippet lang=c : int gsfCopyRecords(gsfRecords *target, const 
gsfRecords *source) }
+     */
+    final MethodHandle gsfCopyRecords;
+    /**
+     * {@snippet lang=c : int gsfPutMBParams(const gsfMBParams *p, gsfRecords 
*rec, int handle, int numArrays) }
+     */
+    final MethodHandle gsfPutMBParams;
+    /**
+     * {@snippet lang=c : int gsfGetMBParams(const gsfRecords *rec, 
gsfMBParams *p, int *numArrays) }
+     */
+    final MethodHandle gsfGetMBParams;
+    /**
+     * {@snippet lang=c : int gsfGetSwathBathyBeamWidths(const gsfRecords 
*data, double *fore_aft, double *athwartship) }
+     */
+    final MethodHandle gsfGetSwathBathyBeamWidths;
+    /**
+     * {@snippet lang=c : int gsfIsStarboardPing(const gsfRecords *data) }
+     */
+    final MethodHandle gsfIsStarboardPing;
+    /**
+     * {@snippet lang=c : int 
gsfLoadDepthScaleFactorAutoOffset(gsfSwathBathyPing *ping, unsigned int 
subrecordID, int reset, double min_depth, double max_depth, double 
*last_corrector, char c_flag, double precision) }
+     */
+    final MethodHandle gsfLoadDepthScaleFactorAutoOffset;
+    /**
+     * {@snippet lang=c : int gsfGetSwathBathyArrayMinMax(const 
gsfSwathBathyPing *ping, unsigned int subrecordID, double *min_value, double 
*max_value) }
+     */
+    final MethodHandle gsfGetSwathBathyArrayMinMax;
+    /**
+     * {@snippet lang=c : const char *gsfGetSonarTextName(const 
gsfSwathBathyPing *ping) }
+     */
+    final MethodHandle gsfGetSonarTextName;
+    /**
+     * {@snippet lang=c : int gsfFileSupportsRecalculateXYZ(int handle, int 
*status) }
+     */
+    final MethodHandle gsfFileSupportsRecalculateXYZ;
+    /**
+     * {@snippet lang=c : int gsfFileSupportsRecalculateTPU(int handle, int 
*status) }
+     */
+    final MethodHandle gsfFileSupportsRecalculateTPU;
+    /**
+     * {@snippet lang=c : int gsfFileSupportsRecalculateNominalDepth(int 
handle, int *status) }
+     */
+    final MethodHandle gsfFileSupportsRecalculateNominalDepth;
+    /**
+     * {@snippet lang=c : int gsfFileContainsMBAmplitude(int handle, int 
*status) }
+     */
+    final MethodHandle gsfFileContainsMBAmplitude;
+    /**
+     * {@snippet lang=c : int gsfFileContainsMBImagery(int handle, int 
*status) }
+     */
+    final MethodHandle gsfFileContainsMBImagery;
+    /**
+     * {@snippet lang=c : int gsfIsNewSurveyLine(int handle, const gsfRecords 
*rec, double azimuth_change, double *last_heading) }
+     */
+    final MethodHandle gsfIsNewSurveyLine;
+    /**
+     * {@snippet lang=c : void gsfInitializeMBParams(gsfMBParams *p) }
+     */
+    final MethodHandle gsfInitializeMBParams;
+    /**
+     * {@snippet lang=c : int gsfStat(const char *filename, long long *sz) }
+     */
+    final MethodHandle gsfStat;
+    /**
+     * {@snippet lang=c : GSF_POSITION *gsfGetPositionDestination(GSF_POSITION 
gp, GSF_POSITION_OFFSETS offsets, double hdg, double dist_step) }
+     */
+    final MethodHandle gsfGetPositionDestination;
+    /**
+     * {@snippet lang=c : GSF_POSITION_OFFSETS 
*gsfGetPositionOffsets(GSF_POSITION gp_from, GSF_POSITION gp_to, double hdg, 
double dist_step) }
+     */
+    final MethodHandle gsfGetPositionOffsets;
+
+    /**
+     * Creates the handles for all <abbr>GSF</abbr> functions which will be 
needed.
+     *
+     * @param  loader  the object used for loading the library.
+     * @throws NoSuchElementException if a <abbr>GSF</abbr> function has not 
been found in the library.
+     */
+    private GSF(final LibraryLoader<GSF> loader) {
+        super(loader);
+        final Linker linker = Linker.nativeLinker();
+
+        final FunctionDescriptor p = FunctionDescriptor.of(GSF.C_POINTER);
+        final FunctionDescriptor i_i = FunctionDescriptor.of(GSF.C_INT, 
GSF.C_INT);
+        final FunctionDescriptor i_i_i = FunctionDescriptor.of(GSF.C_INT, 
GSF.C_INT, GSF.C_INT);
+        final FunctionDescriptor i_p_p = FunctionDescriptor.of(GSF.C_INT, 
GSF.C_POINTER, GSF.C_POINTER);
+        final FunctionDescriptor i_p_p_p = FunctionDescriptor.of(GSF.C_INT, 
GSF.C_POINTER, GSF.C_POINTER, GSF.C_POINTER);
+        final FunctionDescriptor i_i_p = FunctionDescriptor.of(GSF.C_INT, 
GSF.C_INT, GSF.C_POINTER);
+
+        gsfOpen                                 = lookup(linker, "gsfOpen",    
                             FunctionDescriptor.of(GSF.C_INT, GSF.C_POINTER, 
GSF.C_INT, GSF.C_POINTER));
+        gsfOpenBuffered                         = lookup(linker, 
"gsfOpenBuffered",                         FunctionDescriptor.of(GSF.C_INT, 
GSF.C_POINTER, GSF.C_INT, GSF.C_POINTER, GSF.C_INT));
+        gsfClose                                = lookup(linker, "gsfClose",   
                             i_i);
+        gsfSeek                                 = lookup(linker, "gsfSeek",    
                             i_i_i);
+        gsfRead                                 = lookup(linker, "gsfRead",    
                             FunctionDescriptor.of(GSF.C_INT, GSF.C_INT, 
GSF.C_INT, GSF.C_POINTER, GSF.C_POINTER, GSF.C_POINTER, GSF.C_INT));
+        gsfWrite                                = lookup(linker, "gsfWrite",   
                             FunctionDescriptor.of(GSF.C_INT, GSF.C_INT, 
GSF.C_POINTER, GSF.C_POINTER));
+        gsfLoadScaleFactor                      = lookup(linker, 
"gsfLoadScaleFactor",                      FunctionDescriptor.of(GSF.C_INT, 
GSF.C_POINTER, GSF.C_INT, GSF.C_CHAR, GSF.C_DOUBLE, GSF.C_INT));
+        gsfGetScaleFactor                       = lookup(linker, 
"gsfGetScaleFactor",                       FunctionDescriptor.of(GSF.C_INT, 
GSF.C_INT, GSF.C_INT, GSF.C_POINTER, GSF.C_POINTER, GSF.C_POINTER));
+        gsfFree                                 = lookup(linker, "gsfFree",    
                             p);
+        gsfPrintError                           = lookup(linker, 
"gsfPrintError",                           p);
+        gsfIntError                             = lookup(linker, 
"gsfIntError",                             FunctionDescriptor.of(GSF.C_INT));
+        gsfStringError                          = lookup(linker, 
"gsfStringError",                          p);
+        gsfIndexTime                            = lookup(linker, 
"gsfIndexTime",                            FunctionDescriptor.of(GSF.C_INT, 
GSF.C_INT, GSF.C_INT, GSF.C_INT, GSF.C_POINTER, GSF.C_POINTER));
+        gsfPercent                              = lookup(linker, "gsfPercent", 
                             i_i);
+        gsfGetNumberRecords                     = lookup(linker, 
"gsfGetNumberRecords",                     i_i_i);
+        gsfCopyRecords                          = lookup(linker, 
"gsfCopyRecords",                          i_p_p);
+        gsfPutMBParams                          = lookup(linker, 
"gsfPutMBParams",                          FunctionDescriptor.of(GSF.C_INT, 
GSF.C_POINTER, GSF.C_POINTER, GSF.C_INT, GSF.C_INT));
+        gsfGetMBParams                          = lookup(linker, 
"gsfGetMBParams",                          i_p_p_p);
+        gsfGetSwathBathyBeamWidths              = lookup(linker, 
"gsfGetSwathBathyBeamWidths",              i_p_p_p);
+        gsfIsStarboardPing                      = lookup(linker, 
"gsfIsStarboardPing",                      FunctionDescriptor.of(GSF.C_INT, 
GSF.C_POINTER));
+        gsfLoadDepthScaleFactorAutoOffset       = lookup(linker, 
"gsfLoadDepthScaleFactorAutoOffset",       FunctionDescriptor.of(GSF.C_INT, 
GSF.C_POINTER, GSF.C_INT, GSF.C_INT, GSF.C_DOUBLE, GSF.C_DOUBLE, GSF.C_POINTER, 
GSF.C_CHAR, GSF.C_DOUBLE));
+        gsfGetSwathBathyArrayMinMax             = lookup(linker, 
"gsfGetSwathBathyArrayMinMax",             FunctionDescriptor.of(GSF.C_INT, 
GSF.C_POINTER, GSF.C_INT, GSF.C_POINTER, GSF.C_POINTER));
+        gsfGetSonarTextName                     = lookup(linker, 
"gsfGetSonarTextName",                     FunctionDescriptor.of(GSF.C_POINTER, 
GSF.C_POINTER));
+        gsfFileSupportsRecalculateXYZ           = lookup(linker, 
"gsfFileSupportsRecalculateXYZ",           i_i_p);
+        gsfFileSupportsRecalculateTPU           = lookup(linker, 
"gsfFileSupportsRecalculateTPU",           i_i_p);
+        gsfFileSupportsRecalculateNominalDepth  = lookup(linker, 
"gsfFileSupportsRecalculateNominalDepth",  i_i_p);
+        gsfFileContainsMBAmplitude              = lookup(linker, 
"gsfFileContainsMBAmplitude",              i_i_p);
+        gsfFileContainsMBImagery                = lookup(linker, 
"gsfFileContainsMBImagery",                i_i_p);
+        gsfIsNewSurveyLine                      = lookup(linker, 
"gsfIsNewSurveyLine",                      FunctionDescriptor.of(GSF.C_INT, 
GSF.C_INT, GSF.C_POINTER, GSF.C_DOUBLE, GSF.C_POINTER));
+        gsfInitializeMBParams                   = lookup(linker, 
"gsfInitializeMBParams",                   p);
+        gsfStat                                 = lookup(linker, "gsfStat",    
                             i_p_p);
+        gsfGetPositionDestination               = lookup(linker, 
"gsfGetPositionDestination",               FunctionDescriptor.of(GSF.C_POINTER, 
Position.LAYOUT, PositionOffsets.LAYOUT, GSF.C_DOUBLE, GSF.C_DOUBLE));
+        gsfGetPositionOffsets                   = lookup(linker, 
"gsfGetPositionOffsets",                   FunctionDescriptor.of(GSF.C_POINTER, 
Position.LAYOUT, Position.LAYOUT, GSF.C_DOUBLE, GSF.C_DOUBLE));
+    }
+
+    public Arena getArena() {
+        return arena();
+    }
+
+    public int open(MemorySegment filename, int mode, MemorySegment handle) 
throws Throwable {
+        return (int) gsfOpen.invokeExact(filename, mode, handle);
+    }
+
+    public int openBuffered(MemorySegment filename, int mode, MemorySegment 
handle, int buf_size) throws Throwable {
+        return (int)gsfOpenBuffered.invokeExact(filename, mode, handle, 
buf_size);
+    }
+
+    public int close(int handle) throws Throwable {
+        return (int) gsfClose.invokeExact(handle);
+    }
+
+    public int seek(int handle, int option) throws Throwable {
+        return (int)gsfSeek.invokeExact(handle, option);
+    }
+
+    public int read(int handle, int desiredRecord, MemorySegment dataID, 
MemorySegment rec, MemorySegment stream, int max_size) throws Throwable {
+        return (int)gsfRead.invokeExact(handle, desiredRecord, dataID, rec, 
stream, max_size);
+    }
+
+    public int write(int handle, MemorySegment id, MemorySegment record_) 
throws Throwable {
+        return (int)gsfWrite.invokeExact(handle, id, record_);
+    }
+
+    public int loadScaleFactor(MemorySegment sf, int subrecordID, byte c_flag, 
double precision, int offset) throws Throwable {
+        return (int)gsfLoadScaleFactor.invokeExact(sf, subrecordID, c_flag, 
precision, offset);
+    }
+
+    public int getScaleFactor(int handle, int subrecordID, MemorySegment 
c_flag, MemorySegment multiplier, MemorySegment offset) throws Throwable {
+        return (int)gsfGetScaleFactor.invokeExact(handle, subrecordID, c_flag, 
multiplier, offset);
+    }
+
+    public void free(MemorySegment rec) throws Throwable {
+        gsfFree.invokeExact(rec);
+    }
+
+    public void printError(MemorySegment fp) throws Throwable {
+        gsfPrintError.invokeExact(fp);
+    }
+
+    public int intError() throws Throwable {
+        return (int)gsfIntError.invokeExact();
+    }
+
+    public MemorySegment stringError() throws Throwable {
+        return (MemorySegment)gsfStringError.invokeExact();
+    }
+
+    public int indexTime(int handle, int recordID, int record_number, 
MemorySegment sec, MemorySegment nsec) throws Throwable {
+        return (int)gsfIndexTime.invokeExact(handle, recordID, record_number, 
sec, nsec);
+    }
+
+    public int percent(int handle) throws Throwable {
+        return (int)gsfPercent.invokeExact(handle);
+    }
+
+    public int getNumberRecords(int handle, int desiredRecord) throws 
Throwable {
+        return (int)gsfGetNumberRecords.invokeExact(handle, desiredRecord);
+    }
+
+    public int copyRecords(MemorySegment target, MemorySegment source) throws 
Throwable {
+        return (int)gsfCopyRecords.invokeExact(target, source);
+    }
+
+    public int putMBParams(MemorySegment p, MemorySegment rec, int handle, int 
numArrays) throws Throwable {
+        return (int)gsfPutMBParams.invokeExact(p, rec, handle, numArrays);
+    }
+
+    public int getMBParams(MemorySegment rec, MemorySegment p, MemorySegment 
numArrays) throws Throwable {
+        return (int)gsfGetMBParams.invokeExact(rec, p, numArrays);
+    }
+
+    public int getSwathBathyBeamWidths(MemorySegment data, MemorySegment 
fore_aft, MemorySegment athwartship) throws Throwable {
+        return (int)gsfGetSwathBathyBeamWidths.invokeExact(data, fore_aft, 
athwartship);
+    }
+
+    public int isStarboardPing(MemorySegment data) throws Throwable {
+        return (int)gsfIsStarboardPing.invokeExact(data);
+    }
+
+    public int loadDepthScaleFactorAutoOffset(MemorySegment ping, int 
subrecordID, int reset, double min_depth, double max_depth, MemorySegment 
last_corrector, byte c_flag, double precision) throws Throwable {
+        return (int)gsfLoadDepthScaleFactorAutoOffset.invokeExact(ping, 
subrecordID, reset, min_depth, max_depth, last_corrector, c_flag, precision);
+    }
+
+    public int getSwathBathyArrayMinMax(MemorySegment ping, int subrecordID, 
MemorySegment min_value, MemorySegment max_value) throws Throwable {
+        return (int)gsfGetSwathBathyArrayMinMax.invokeExact(ping, subrecordID, 
min_value, max_value);
+    }
+
+    public MemorySegment getSonarTextName(MemorySegment ping) throws Throwable 
{
+        return (MemorySegment)gsfGetSonarTextName.invokeExact(ping);
+    }
+
+    public int fileSupportsRecalculateXYZ(int handle, MemorySegment status) 
throws Throwable {
+        return (int)gsfFileSupportsRecalculateXYZ.invokeExact(handle, status);
+    }
+
+    public int fileSupportsRecalculateTPU(int handle, MemorySegment status) 
throws Throwable {
+        return (int)gsfFileSupportsRecalculateTPU.invokeExact(handle, status);
+    }
+
+    public int fileSupportsRecalculateNominalDepth(int handle, MemorySegment 
status) throws Throwable {
+        return (int)gsfFileSupportsRecalculateNominalDepth.invokeExact(handle, 
status);
+    }
+
+    public int fileContainsMBAmplitude(int handle, MemorySegment status) 
throws Throwable {
+        return (int)gsfFileContainsMBAmplitude.invokeExact(handle, status);
+    }
+
+    public int fileContainsMBImagery(int handle, MemorySegment status) throws 
Throwable {
+        return (int)gsfFileContainsMBImagery.invokeExact(handle, status);
+    }
+
+    public int isNewSurveyLine(int handle, MemorySegment rec, double 
azimuth_change, MemorySegment last_heading) throws Throwable {
+        return (int)gsfIsNewSurveyLine.invokeExact(handle, rec, 
azimuth_change, last_heading);
+    }
+
+    public void initializeMBParams(MemorySegment p) throws Throwable {
+        gsfInitializeMBParams.invokeExact(p);
+    }
+
+    public int stat(MemorySegment filename, MemorySegment sz) throws Throwable 
{
+        return (int)gsfStat.invokeExact(filename, sz);
+    }
+
+    public MemorySegment getPositionDestination(MemorySegment gp, 
MemorySegment offsets, double hdg, double dist_step) throws Throwable {
+        return (MemorySegment)gsfGetPositionDestination.invokeExact(gp, 
offsets, hdg, dist_step);
+    }
+
+    public MemorySegment getPositionOffsets(MemorySegment gp_from, 
MemorySegment gp_to, double hdg, double dist_step) throws Throwable {
+        return (MemorySegment)gsfGetPositionOffsets.invokeExact(gp_from, 
gp_to, hdg, dist_step);
     }
+
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_USBL "USBL"
-     * }
+     * Raise an exception if code is an error code.
      */
-    public static MemorySegment GSF_POS_TYPE_USBL() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_USBL
-                = GSF.LIBRARY_ARENA.allocateFrom("USBL");
-        }
-        return Holder.GSF_POS_TYPE_USBL;
+    public void catchError(int error) throws GSFException {
+        if (error == 0) return;
+        String message = ERRORCODES.get(error);
+        if (message == null) message = "UNKNOWN ERROR CODE";
+        throw new GSFException(error, message);
     }
+
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_PIUA "PIUA"
-     * }
+     * Returns the helper class for loading the <abbr>GDAL</abbr> library.
+     * If {@code def} is true, then this method tries to load the library
+     * now and stores the result in {@link #global} and {@link #globalStatus}.
+     *
+     * @param  now  whether this method is invoked for the default (global) 
library.
+     *         In such case, the caller must be synchronized and {@link 
#global} must be initially null.
+     * @return the library loader for <abbr>GDAL</abbr>.
      */
-    public static MemorySegment GSF_POS_TYPE_PIUA() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_PIUA
-                = GSF.LIBRARY_ARENA.allocateFrom("PIUA");
+    private static LibraryLoader<GSF> load(final boolean now) {
+        final var loader = new LibraryLoader<>(GSF::new);
+        if (now) {
+            try {
+                global = loader.global("gsf");
+            } finally {
+                globalStatus = loader.status();
+            }
+            if (global != null) {
+                if (GSFStoreProvider.LOGGER.isLoggable(Level.CONFIG)) {
+                    log("open", new LogRecord(Level.CONFIG, "Opening LibGSF"));
+                }
+            }
         }
-        return Holder.GSF_POS_TYPE_PIUA;
+        return loader;
     }
+
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_PIVA "PIVA"
-     * }
+     * Loads the <abbr>GDAL</abbr> library from the given file.
+     * Callers should register the returned instance in a {@link 
java.lang.ref.Cleaner}.
+     *
+     * @param  library  the library to load.
+     * @return handles to native functions needed by this module.
+     * @throws IllegalArgumentException if the GDAL library has not been found.
+     * @throws NoSuchElementException if a <abbr>GDAL</abbr> function has not 
been found in the library.
+     * @throws IllegalCallerException if this Apache SIS module is not 
authorized to call native methods.
      */
-    public static MemorySegment GSF_POS_TYPE_PIVA() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_PIVA
-                = GSF.LIBRARY_ARENA.allocateFrom("PIVA");
-        }
-        return Holder.GSF_POS_TYPE_PIVA;
+    static GSF load(final Path library) {
+        return load(false).load(library);
     }
+
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_PIWA "PIWA"
-     * }
+     * Returns an instance using the <abbr>GDAL</abbr> library loaded from the 
default library path.
+     * The handles are valid for the Java Virtual Machine lifetime, i.e. it 
uses the global arena.
+     * If this method has already been invoked, this method returns the 
previously created instance.
+     *
+     * <p>If the <abbr>GDAL</abbr> library is not found, the current default 
is {@link SymbolLookup#loaderLookup()}
+     * for allowing users to invoke {@link System#loadLibrary(String)} as a 
fallback. This policy may be revised in
+     * any future version of Apache <abbr>SIS</abbr>.</p>
+     *
+     * @return handles to native functions needed by this module.
+     * @throws DataStoreException if the native library has not been found or 
if SIS is not allowed to call
+     *         native functions, and {@code onError} is null.
      */
-    public static MemorySegment GSF_POS_TYPE_PIWA() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_PIWA
-                = GSF.LIBRARY_ARENA.allocateFrom("PIWA");
+    static synchronized GSF global() throws DataStoreException {
+        if (globalStatus == null) {
+            load(true).validate();
         }
-        return Holder.GSF_POS_TYPE_PIWA;
+        globalStatus.report(null);
+        return global;
     }
+
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_PLBL "PLBL"
-     * }
+     * Same as {@link #global}, but logs a warning instead of throwing an 
exception in case of error.
+     *
+     * @param  caller  the name of the method which is invoking this method.
+     * @return handles to native functions needed by this module, or empty if 
not available.
      */
-    public static MemorySegment GSF_POS_TYPE_PLBL() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_PLBL
-                = GSF.LIBRARY_ARENA.allocateFrom("PLBL");
+    static synchronized Optional<GSF> tryGlobal(final String caller) {
+        if (globalStatus == null) {
+            load(true).getError(GSFStoreProvider.NAME).ifPresent((record) -> 
log(caller, record));
         }
-        return Holder.GSF_POS_TYPE_PLBL;
+        return Optional.ofNullable(global);
     }
+
     /**
-     * {@snippet lang=c :
-     * #define GSF_POS_TYPE_PSBL "PSBL"
-     * }
+     * Logs the given record as if was produced by the {@link 
GDALStoreProvider}, which is the public class.
+     *
+     * @param  caller  the method name to report as the caller.
+     * @param  record  the error to log.
      */
-    public static MemorySegment GSF_POS_TYPE_PSBL() {
-        class Holder {
-            static final MemorySegment GSF_POS_TYPE_PSBL
-                = GSF.LIBRARY_ARENA.allocateFrom("PSBL");
-        }
-        return Holder.GSF_POS_TYPE_PSBL;
+    private static void log(final String caller, final LogRecord record) {
+        Logging.completeAndLog(GSFStoreProvider.LOGGER, 
GSFStoreProvider.class, caller, record);
     }
-    public static final double GSF_UNKNOWN_PARAM_VALUE = 
2.2250738585072014E-308d;
-    public static final int GSF_UNKNOWN_PARAM_INT = -99;
-    public static final int GSF_FOPEN_ERROR = -1;
-    public static final int GSF_UNRECOGNIZED_FILE = -2;
-    public static final int GSF_BAD_ACCESS_MODE = -3;
-    public static final int GSF_READ_ERROR = -4;
-    public static final int GSF_WRITE_ERROR = -5;
-    public static final int GSF_INSUFFICIENT_SIZE = -6;
-    public static final int GSF_RECORD_SIZE_ERROR = -7;
-    public static final int GSF_CHECKSUM_FAILURE = -8;
-    public static final int GSF_FILE_CLOSE_ERROR = -9;
-    public static final int GSF_TOO_MANY_ARRAY_SUBRECORDS = -10;
-    public static final int GSF_TOO_MANY_OPEN_FILES = -11;
-    public static final int GSF_MEMORY_ALLOCATION_FAILED = -12;
-    public static final int GSF_UNRECOGNIZED_RECORD_ID = -13;
-    public static final int GSF_STREAM_DECODE_FAILURE = -14;
-    public static final int GSF_BAD_SEEK_OPTION = -15;
-    public static final int GSF_FILE_SEEK_ERROR = -16;
-    public static final int GSF_UNRECOGNIZED_SENSOR_ID = -17;
-    public static final int GSF_UNRECOGNIZED_DATA_RECORD = -18;
-    public static final int GSF_UNRECOGNIZED_ARRAY_SUBRECORD_ID = -19;
-    public static final int GSF_UNRECOGNIZED_SUBRECORD_ID = -20;
-    public static final int GSF_ILLEGAL_SCALE_FACTOR_MULTIPLIER = -21;
-    public static final int GSF_CANNOT_REPRESENT_PRECISION = -22;
-    public static final int GSF_READ_TO_END_OF_FILE = -23;
-    public static final int GSF_BAD_FILE_HANDLE = -24;
-    public static final int GSF_HEADER_RECORD_DECODE_FAILED = -25;
-    public static final int GSF_MB_PING_RECORD_DECODE_FAILED = -26;
-    public static final int GSF_SVP_RECORD_DECODE_FAILED = -27;
-    public static final int GSF_PROCESS_PARAM_RECORD_DECODE_FAILED = -28;
-    public static final int GSF_SENSOR_PARAM_RECORD_DECODE_FAILED = -29;
-    public static final int GSF_COMMENT_RECORD_DECODE_FAILED = -30;
-    public static final int GSF_HISTORY_RECORD_DECODE_FAILED = -31;
-    public static final int GSF_NAV_ERROR_RECORD_DECODE_FAILED = -32;
-    public static final int GSF_HEADER_RECORD_ENCODE_FAILED = -25;
-    public static final int GSF_MB_PING_RECORD_ENCODE_FAILED = -26;
-    public static final int GSF_SVP_RECORD_ENCODE_FAILED = -27;
-    public static final int GSF_PROCESS_PARAM_RECORD_ENCODE_FAILED = -28;
-    public static final int GSF_SENSOR_PARAM_RECORD_ENCODE_FAILED = -29;
-    public static final int GSF_COMMENT_RECORD_ENCODE_FAILED = -30;
-    public static final int GSF_HISTORY_RECORD_ENCODE_FAILED = -31;
-    public static final int GSF_NAV_ERROR_RECORD_ENCODE_FAILED = -32;
-    public static final int GSF_SETVBUF_ERROR = -33;
-    public static final int GSF_FLUSH_ERROR = -34;
-    public static final int GSF_FILE_TELL_ERROR = -35;
-    public static final int GSF_INDEX_FILE_OPEN_ERROR = -36;
-    public static final int GSF_CORRUPT_INDEX_FILE_ERROR = -37;
-    public static final int GSF_SCALE_INDEX_CALLOC_ERROR = -38;
-    public static final int GSF_RECORD_TYPE_NOT_AVAILABLE = -39;
-    public static final int GSF_SUMMARY_RECORD_DECODE_FAILED = -40;
-    public static final int GSF_SUMMARY_RECORD_ENCODE_FAILED = -41;
-    public static final int GSF_INVALID_NUM_BEAMS = -42;
-    public static final int GSF_INVALID_RECORD_NUMBER = -43;
-    public static final int GSF_INDEX_FILE_READ_ERROR = -44;
-    public static final int GSF_PARAM_SIZE_FIXED = -45;
-    public static final int GSF_SINGLE_BEAM_ENCODE_FAILED = -46;
-    public static final int GSF_HV_NAV_ERROR_RECORD_ENCODE_FAILED = -47;
-    public static final int GSF_HV_NAV_ERROR_RECORD_DECODE_FAILED = -48;
-    public static final int GSF_ATTITUDE_RECORD_ENCODE_FAILED = -49;
-    public static final int GSF_ATTITUDE_RECORD_DECODE_FAILED = -50;
-    public static final int GSF_OPEN_TEMP_FILE_FAILED = -51;
-    public static final int GSF_PARTIAL_RECORD_AT_END_OF_FILE = -52;
-    public static final int GSF_QUALITY_FLAGS_DECODE_ERROR = -53;
-    public static final int GSF_COMPRESSION_UNSUPPORTED = -55;
-    public static final int GSF_COMPRESSION_FAILED = -56;
 
 }
-
diff --git a/incubator/src/org.apache.sis.storage.gsf/main/module-info.java 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFException.java
similarity index 73%
copy from incubator/src/org.apache.sis.storage.gsf/main/module-info.java
copy to 
incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFException.java
index b3d64887cc..5edddac68f 100644
--- a/incubator/src/org.apache.sis.storage.gsf/main/module-info.java
+++ 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFException.java
@@ -14,15 +14,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.sis.storage.gsf;
+
+import org.apache.sis.storage.DataStoreException;
 
 /**
- * LibGSF Panama binding.
  *
  * @author Johann Sorel (Geomatys)
  */
-module org.apache.sis.storage.gsf {
-    // Dependencies used in public API.
-    requires transitive org.apache.sis.referencing;
-    requires transitive org.apache.sis.storage;
+public final class GSFException extends DataStoreException{
+
+    public final int errorCode;
+
+    public GSFException(int code, String message) {
+        super(message + "(" + code + ")");
+        this.errorCode = code;
+    }
 
 }
diff --git 
a/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFRecordReader.java
 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFRecordReader.java
index bdb57a9749..a7e6eda5cc 100644
--- 
a/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFRecordReader.java
+++ 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFRecordReader.java
@@ -21,69 +21,69 @@ import java.lang.foreign.MemorySegment;
 import java.lang.foreign.ValueLayout;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Path;
-import java.util.Iterator;
-import java.util.Spliterator;
-import java.util.Spliterators;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
 import org.apache.sis.storage.DataStoreException;
-import org.apache.sis.util.privy.AbstractIterator;
 
 
 /**
  *
  * @author Johann Sorel (Geomatys)
  */
-public class GSFRecordReader {
+public final class GSFRecordReader implements AutoCloseable {
 
+    private final GSFStore store;
     private final Path file;
+    private final GSF gsf;
+    private final Arena arena;
 
-    public GSFRecordReader(Path file) {
-        this.file = file;
-    }
+    private final MemorySegment handle;
+    private final int handleId;
+
+    //singleton instance for iteration
+    private final DataID dataId;
+    private final Records records;
+
+    public GSFRecordReader(GSFStore store) throws DataStoreException {
+        this.store = store;
+        this.file = store.getComponentFiles()[0];
+        this.gsf = store.getProvider().GSF();
+        this.arena = Arena.ofShared();
 
-    public Stream<Records> records() throws DataStoreException{
+        dataId = new DataID(arena);
+        records = new Records(arena);
+        records.setDataId(dataId);
 
-        final Arena arena = Arena.ofShared();
         final MemorySegment address = 
arena.allocateFrom(file.toFile().toString(), StandardCharsets.UTF_8);
-        final MemorySegment handle = arena.allocate(4);
-        final int error = GSF.gsfOpen(address, GSF.GSF_READONLY, handle);
-        if (error != 0) {
-            arena.close();
-            throw new DataStoreException("GSF open error " + 
GSF.gsfIntError());
+        handle = arena.allocate(4);
+        handleId = handle.getAtIndex(ValueLayout.JAVA_INT, 0);
+        try {
+            final int error = gsf.open(address, GSF.GSF_READONLY, handle);
+            if (error != 0) {
+                arena.close();
+                gsf.catchError(error);
+            }
+        } catch (Throwable ex) {
+            throw new DataStoreException("Error while executing a GSFLib 
call.", ex);
         }
-        final int handleId = handle.getAtIndex(ValueLayout.JAVA_INT, 0);
+    }
 
-        final Iterator ite = new AbstractIterator() {
-            @Override
-            public boolean hasNext() {
-                if (next != null) return true;
-                final DataID dataId = new DataID(arena);
-                final Records records = new Records(arena);
-                records.setDataId(dataId);
-                final int error = GSF.gsfRead(handleId, GSF.GSF_NEXT_RECORD, 
dataId.getMemorySegment(), records.getMemorySegment(), MemorySegment.NULL, 0);
-                if (error < 0) {
-                    int errorCode = GSF.gsfIntError();
-                    if (errorCode == GSF.GSF_READ_TO_END_OF_FILE) {
-                        return false;
-                    } else {
-                        throw new RuntimeException(error + " GSF read error " 
+ errorCode);
-                    }
-                }
-                next = records;
-                return true;
-            }
-        };
+    public Records next() throws DataStoreException {
+        try {
+            gsf.free(records.getMemorySegment());
+            gsf.free(dataId.getMemorySegment());
 
-        final Spliterator<Records> spliterator = 
Spliterators.spliteratorUnknownSize(ite, Spliterator.ORDERED);
-        final Stream<Records> stream = StreamSupport.stream(spliterator, 
false);
-        return stream.onClose(new Runnable() {
-            @Override
-            public void run() {
-                GSF.gsfClose(handleId);
-                arena.close();
+            final int error = gsf.read(handleId, GSF.GSF_NEXT_RECORD, 
dataId.getMemorySegment(), records.getMemorySegment(), MemorySegment.NULL, 0);
+            if (error == -23 /*GSF_READ_TO_END_OF_FILE*/) {
+                return null;
             }
-        });
+            gsf.catchError(error);
+            return records;
+        } catch (Throwable ex) {
+            throw new DataStoreException("Error while executing a GSFLib 
call.", ex);
+        }
     }
 
+    @Override
+    public void close() {
+        this.arena.close();
+    }
 }
diff --git 
a/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFStore.java
 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFStore.java
new file mode 100644
index 0000000000..bb70c1158d
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFStore.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.gsf;
+
+import java.net.URI;
+import java.nio.file.Path;
+import java.util.Optional;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.storage.DataStore;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.base.MetadataBuilder;
+import org.apache.sis.storage.base.ResourceOnFileSystem;
+import org.apache.sis.storage.base.URIDataStore;
+import org.opengis.metadata.Metadata;
+import org.opengis.parameter.ParameterValueGroup;
+
+/**
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public final class GSFStore extends DataStore implements ResourceOnFileSystem {
+    /**
+     * The {@link GSFStoreProvider#LOCATION} parameter value, or {@code null} 
if none.
+     *
+     * @see #getOpenParameters()
+     */
+    private final URI location;
+    /**
+     * Path of the file opened by this data store, or {@code null} if none.
+     *
+     * @see #getComponentFiles()
+     */
+    private final Path path;
+    /**
+     * A description of this resource as an unmodifiable metadata, or {@code 
null} if not yet computed.
+     *
+     * @see #getMetadata()
+     */
+    private Metadata metadata;
+
+    GSFStore(GSFStoreProvider provider, StorageConnector connector) throws 
DataStoreException {
+        super(provider, connector);
+        path     = connector.getStorageAs(Path.class);
+        location = connector.commit(URI.class, GSFStoreProvider.NAME);
+    }
+
+    /**
+     * Returns the factory that created this {@code DataStore} instance.
+     * The provider determines which <abbr>GSF</abbr> library is used.
+     *
+     * @return the factory that created this {@code DataStore} instance.
+     */
+    @Override
+    public final GSFStoreProvider getProvider() {
+        return (GSFStoreProvider) super.getProvider();
+    }
+
+    @Override
+    public Optional<ParameterValueGroup> getOpenParameters() {
+        final Parameters param = 
Parameters.castOrWrap(URIDataStore.parameters(provider, location));
+        return Optional.ofNullable(param);
+    }
+
+    @Override
+    public Metadata getMetadata() throws DataStoreException {
+        if (metadata == null) {
+            final var builder = new MetadataBuilder();
+            builder.addIdentifier(getIdentifier().orElse(null), 
MetadataBuilder.Scope.RESOURCE);
+            // TODO: add more information.
+            return builder.buildAndFreeze();
+        }
+        return metadata;
+    }
+
+    public GSFRecordReader openReader() throws DataStoreException {
+        return new GSFRecordReader(this);
+    }
+
+    @Override
+    public Path[] getComponentFiles() throws DataStoreException {
+        return new Path[]{path};
+    }
+
+    @Override
+    public void close() throws DataStoreException {
+    }
+
+}
diff --git 
a/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFStoreProvider.java
 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFStoreProvider.java
new file mode 100644
index 0000000000..bfcc8888bc
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFStoreProvider.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.gsf;
+
+import java.net.URI;
+import java.util.Optional;
+import java.util.logging.Logger;
+import java.nio.file.Path;
+import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.parameter.ParameterValueGroup;
+import org.apache.sis.storage.DataStore;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.DataStoreProvider;
+import org.apache.sis.storage.ProbeResult;
+import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.base.StoreMetadata;
+import org.apache.sis.storage.base.Capability;
+import org.apache.sis.storage.base.URIDataStoreProvider;
+import org.apache.sis.storage.panama.LibraryStatus;
+import org.apache.sis.parameter.ParameterBuilder;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.system.Cleaners;
+
+
+/**
+ * The provider of {@code GFSStore} instances.
+ * Given a {@link StorageConnector} input, this class tries to instantiate a 
{@link GFSStore}.
+ * This data store uses the <abbr>GSF</abbr> native library for loading data.
+ *
+ * <p>Each {@code GSFStoreProvider} instance is linked to a <abbr>GSF</abbr> 
library specified
+ * at construction time, or to a <abbr>JVM</abbr>-wide shared <abbr>GSF</abbr> 
library if the
+ * no-argument constructor is used. In the non-shared case, <abbr>GSF</abbr> 
will be unloaded
+ * when this {@code GSFStoreProvider} instance is garbage collected.</p>
+ *
+ * @author  Johann Sorel (Geomatys)
+ * @version 1.5
+ * @since   1.5
+ */
+@StoreMetadata(formatName    = GSFStoreProvider.NAME,
+               capabilities  = {Capability.READ},
+               resourceTypes = {},
+               yieldPriority = true)    // For trying Java implementations 
before GSF.
+public class GSFStoreProvider extends DataStoreProvider {
+    /**
+     * The name of this data store provider.
+     */
+    static final String NAME = "GSF";
+
+    /**
+     * The logger used by <abbr>GSF</abbr> stores.
+     *
+     * @see #getLogger()
+     */
+    static final Logger LOGGER = 
Logger.getLogger("org.apache.sis.storage.gsf");
+
+    /**
+     * The parameter descriptor to be returned by {@link #getOpenParameters()}.
+     */
+    private static final ParameterDescriptorGroup OPEN_DESCRIPTOR;
+    static {
+        final var builder = new ParameterBuilder();
+        OPEN_DESCRIPTOR = 
builder.addName(NAME).createGroup(URIDataStoreProvider.LOCATION_PARAM);
+    }
+
+    /**
+     * Handles to <abbr>GSF</abbr> native functions, or {@code null} for 
global.
+     * Can also be reset to {@code null} if <abbr>GSF</abbr> reported a fatal 
error.
+     */
+    private GSF nativeFunctions;
+
+    /**
+     * The status of {@link #nativeFunctions}, or {@code null} if the global 
set of functions is used.
+     */
+    private LibraryStatus status;
+
+    /**
+     * Creates a new provider which will load the <abbr>GSF</abbr> library 
from the default library path.
+     */
+    public GSFStoreProvider() {
+    }
+
+    /**
+     * Creates a new provider which will load the <abbr>GSF</abbr> library 
from the specified file.
+     * The library will be unloaded when this provider will be 
garbage-collected.
+     *
+     * @throws IllegalArgumentException if the GSF library has not been found.
+     * @throws NoSuchElementException if a <abbr>GSF</abbr> function has not 
been found in the library.
+     * @throws IllegalCallerException if this Apache SIS module is not 
authorized to call native methods.
+     */
+    @SuppressWarnings("this-escape")
+    public GSFStoreProvider(final Path library) {
+        Cleaners.SHARED.register(this, nativeFunctions = GSF.load(library));
+        status = LibraryStatus.LOADED;
+    }
+
+    /**
+     * Returns the set of <abbr>GSF</abbr> native functions.
+     *
+     * @return the set of native functions.
+     * @throws DataStoreException if the native library is not available.
+     */
+    final synchronized GSF GSF() throws DataStoreException {
+        if (status == null) {
+            return GSF.global();       // Fetch each time (no cache) because 
may have changed outside this class.
+        }
+        status.report(null);            // Should never return if 
`nativeFunctions` is null.
+        return nativeFunctions;
+    }
+
+    /**
+     * Tries to load <abbr>GSF</abbr> if not already done, without throwing an 
exception in case of error.
+     * Instead, the error is logged and {@code null} is returned. This is used 
for probing.
+     *
+     * @param  caller  the name of the method which is invoking this method.
+     * @return the set of native functions, or {@code null} if not available.
+     */
+    final synchronized Optional<GSF> tryGSF(final String caller) {
+        if (status == null) {
+            return GSF.tryGlobal(caller);
+        }
+        return Optional.ofNullable(nativeFunctions);
+    }
+
+    /**
+     * Returns a generic name for this data store, used mostly in warnings or 
error messages.
+     *
+     * @return a short name or abbreviation for the data store.
+     */
+    @Override
+    public String getShortName() {
+        return NAME;
+    }
+
+    /**
+     * Returns a description of all parameters accepted by this provider for 
opening a file with GSF.
+     *
+     * @return description of available parameters for opening a file with 
<abbr>GSF</abbr>.
+     */
+    @Override
+    public ParameterDescriptorGroup getOpenParameters() {
+        return OPEN_DESCRIPTOR;
+    }
+
+    /**
+     * Returns the MIME type if the given storage appears to be supported by 
this data store.
+     * A {@linkplain ProbeResult#isSupported() supported} status does not 
guarantee that reading
+     * or writing will succeed, only that there appears to be a reasonable 
chance according GDAL.
+     *
+     * @param  connector  information about the storage (URL, stream, 
<i>etc</i>).
+     * @return a {@linkplain ProbeResult#isSupported() supported} status with 
the MIME type
+     *         if the given storage seems to be readable by {@code GDALStore} 
instances.
+     * @throws DataStoreException if an I/O error occurred.
+     */
+    @Override
+    public ProbeResult probeContent(final StorageConnector connector) throws 
DataStoreException {
+        final URI url = connector.getStorageAs(URI.class);
+        if (url != null && url.toString().toLowerCase().endsWith(".gsf")) {
+            final GSF gsf = tryGSF("probeContent").orElse(null);
+            if (gsf != null) {
+                return new ProbeResult(true, "application/gsf", null);
+            }
+        }
+        return ProbeResult.UNSUPPORTED_STORAGE;
+    }
+
+    /**
+     * Creates a {@code GSFStore} instance associated with this provider.
+     *
+     * @param  connector  information about the storage (URL, stream, 
<i>etc</i>).
+     * @return a data store implementation associated with this provider for 
the given storage.
+     * @throws DataStoreException if an error occurred while creating the data 
store instance.
+     */
+    @Override
+    public DataStore open(final StorageConnector connector) throws 
DataStoreException {
+        return new GSFStore(this, connector);
+    }
+
+    /**
+     * Creates a {@code GSFStore} instance from the given parameters.
+     *
+     * @param  parameters  opening parameters as defined by {@link 
#getOpenParameters()}.
+     * @return a data store instance associated with this provider for the 
given parameters.
+     * @throws DataStoreException if an error occurred while creating the data 
store instance.
+     */
+    @Override
+    public DataStore open(final ParameterValueGroup parameters) throws 
DataStoreException {
+        final var p = Parameters.castOrWrap(parameters);
+        final var connector = new 
StorageConnector(p.getValue(URIDataStoreProvider.LOCATION_PARAM));
+        return open(connector);
+    }
+
+    /**
+     * Returns the logger used by <abbr>GSF</abbr> stores.
+     */
+    @Override
+    public Logger getLogger() {
+        return LOGGER;
+    }
+}

Reply via email to