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