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

jsorel pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 7bdaab6a29 Decode OGR vector layers, rebuild FeatureTypes
7bdaab6a29 is described below

commit 7bdaab6a292822f9c7700c4cfc99f26fa8b1e0c3
Author: jsorel <johann.so...@geomatys.com>
AuthorDate: Wed Oct 9 10:55:36 2024 +0200

    Decode OGR vector layers, rebuild FeatureTypes
---
 .../org.apache.sis.feature/main/module-info.java   |   1 +
 optional/build.gradle.kts                          |   2 +
 .../org.apache.sis.storage.DataStoreProvider       |   2 +-
 .../main/module-info.java                          |   4 +
 .../main/org/apache/sis/storage/gdal/GDAL.java     | 269 +++++++++++++++++++++
 .../org/apache/sis/storage/gdal/GDALStore.java     |   5 +-
 .../org/apache/sis/storage/gdal/OGRFeatureSet.java | 184 ++++++++++++++
 .../org/apache/sis/storage/gdal/OGRFieldType.java  |  84 +++++++
 .../apache/sis/storage/gdal/OGRwkbByteOrder.java   |  36 +++
 .../sis/storage/gdal/OGRwkbGeometryType.java       | 185 ++++++++++++++
 .../apache/sis/storage/gdal/OgrGeometryReader.java | 206 ++++++++++++++++
 .../apache/sis/storage/gdal/OgrSpliterator.java    | 133 ++++++++++
 .../main/org/apache/sis/storage/gdal/Opener.java   |   2 +-
 .../org/apache/sis/storage/gdal/SpatialRef.java    |  13 +
 14 files changed, 1123 insertions(+), 3 deletions(-)

diff --git a/endorsed/src/org.apache.sis.feature/main/module-info.java 
b/endorsed/src/org.apache.sis.feature/main/module-info.java
index a99f398169..0fa39a382d 100644
--- a/endorsed/src/org.apache.sis.feature/main/module-info.java
+++ b/endorsed/src/org.apache.sis.feature/main/module-info.java
@@ -55,6 +55,7 @@ module org.apache.sis.feature {
             org.apache.sis.storage.shapefile,       // In the "incubator" 
sub-project.
             org.apache.sis.portrayal,
             org.apache.sis.portrayal.map,           // In the "incubator" 
sub-project.
+            org.apache.sis.storage.gdal,            // In the "optional" 
sub-project.
             org.apache.sis.gui;                     // In the "optional" 
sub-project.
 
     exports org.apache.sis.geometry.wrapper to
diff --git a/optional/build.gradle.kts b/optional/build.gradle.kts
index dbcd427a82..79fd1f326b 100644
--- a/optional/build.gradle.kts
+++ b/optional/build.gradle.kts
@@ -50,6 +50,8 @@ dependencies {
     // Mandatory dependencies
     api           (libs.units)
     api           (libs.geoapi)
+    api                  (libs.jts.core)                  // Should be an 
optional dependency.
+    api                  (libs.esri.geometry)             // Idem.
     implementation(libs.jaxb.api)                  // Transitive dependency.
     runtimeOnly   (libs.jaxb.impl)
     api           (files(File(pathToFX, "javafx.base.jar")))
diff --git 
a/optional/src/org.apache.sis.storage.gdal/main/META-INF.services/org.apache.sis.storage.DataStoreProvider
 
b/optional/src/org.apache.sis.storage.gdal/main/META-INF.services/org.apache.sis.storage.DataStoreProvider
index 25f274232b..fe0f6d43f6 100644
--- 
a/optional/src/org.apache.sis.storage.gdal/main/META-INF.services/org.apache.sis.storage.DataStoreProvider
+++ 
b/optional/src/org.apache.sis.storage.gdal/main/META-INF.services/org.apache.sis.storage.DataStoreProvider
@@ -1,4 +1,4 @@
 # Workaround for Maven bug https://issues.apache.org/jira/browse/MNG-7855
 # The content of this file is automatically derived from module-info.class 
file.
 # Should be used only if the JAR file was on class-path rather than 
module-path.
-org.apache.sis.storage.gdal.GdalStoreProvider
+org.apache.sis.storage.gdal.GDALStoreProvider
diff --git a/optional/src/org.apache.sis.storage.gdal/main/module-info.java 
b/optional/src/org.apache.sis.storage.gdal/main/module-info.java
index e4d87b9584..c7c98de106 100644
--- a/optional/src/org.apache.sis.storage.gdal/main/module-info.java
+++ b/optional/src/org.apache.sis.storage.gdal/main/module-info.java
@@ -52,6 +52,10 @@ module org.apache.sis.storage.gdal {
     requires transitive org.apache.sis.referencing;
     requires transitive org.apache.sis.storage;
 
+    // Optional dependencies to be provided by user.
+    requires static esri.geometry.api;
+    requires static org.locationtech.jts;
+    
     exports org.apache.sis.storage.gdal;
 
     provides org.apache.sis.storage.DataStoreProvider
diff --git 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDAL.java
 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDAL.java
index c70763fc39..cf6d50abd9 100644
--- 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDAL.java
+++ 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDAL.java
@@ -274,6 +274,183 @@ final class GDAL extends NativeFunctions {
      */
     final MethodHandle adviseRead;
 
+    /**
+     * <abbr>GDAL</abbr> {@code CPLErr GDALDatasetGetLayerCount(Pointer hDS)}.
+     * Get the number of layers in this dataset.
+     */
+    final MethodHandle datasetGetLayerCount;
+
+    /**
+     * <abbr>GDAL</abbr> {@code CPLErr GDALDatasetGetLayer(Pointer hDS, int 
index)}.
+     * Fetch a layer by index.
+     */
+    final MethodHandle datasetGetLayer;
+
+    /**
+     * <abbr>OGR</abbr> {@code Pointer CPLErr OGR_L_GetLayerDefn(Pointer hDS)}.
+     * Fetch the schema information for this layer.
+     */
+    final MethodHandle ogrLayerGetLayerDefn;
+
+    /**
+     * <abbr>OGR</abbr> {@code Pointer CPLErr OGR_L_GetName(Pointer hDS)}.
+     * Return the layer name.
+     */
+    final MethodHandle ogrLayerGetName;
+
+    /**
+     * <abbr>OGR</abbr> {@code GIntBig CPL_DLL 
OGR_L_GetFeatureCount(OGRLayerH, int)}.
+     * Fetch the feature count in this layer.
+     */
+    final MethodHandle ogrLayerGetFeatureCount;
+
+    /**
+     * <abbr>OGR</abbr> {@code OGRErr CPL_DLL OGR_L_GetExtent(OGRLayerH, 
OGREnvelope *, int)}.
+     * Fetch spatial extent.
+     */
+    final MethodHandle ogrLayerGetExtent;
+
+    /**
+     * <abbr>OGR</abbr> {@code OGRFeatureH CPL_DLL 
OGR_L_GetNextFeature(OGRLayerH) CPL_WARN_UNUSED_RESULT}.
+     * Fetch the next available feature from this layer.
+     */
+    final MethodHandle ogrLayerGetNextFeature;
+
+    /**
+     * <abbr>OGR</abbr> {@code GIntBig CPL_DLL OGR_F_GetFID(OGRFeatureH)}.
+     * Get feature identifier.
+     */
+    final MethodHandle ogrFeatureGetFid;
+
+    /**
+     * <abbr>OGR</abbr> {@code int CPL_DLL 
OGR_F_GetFieldAsInteger(OGRFeatureH, int)}.
+     * Fetch field value as integer.
+     */
+    final MethodHandle ogrFeatureGetFieldAsInteger;
+
+    /**
+     * <abbr>OGR</abbr> {@code GIntBig CPL_DLL 
OGR_F_GetFieldAsInteger64(OGRFeatureH, int)}.
+     * Fetch field value as integer 64 bit.
+     */
+    final MethodHandle ogrFeatureGetFieldAsInteger64;
+
+    /**
+     * <abbr>OGR</abbr> {@code double CPL_DLL 
OGR_F_GetFieldAsDouble(OGRFeatureH, int)}.
+     * Fetch field value as a double.
+     */
+    final MethodHandle ogrFeatureGetFieldAsDouble;
+
+    /**
+     * <abbr>OGR</abbr> {@code const char CPL_DLL 
*OGR_F_GetFieldAsString(OGRFeatureH, int)}.
+     * Fetch field value as a string.
+     */
+    final MethodHandle ogrFeatureGetFieldAsString;
+
+    /**
+     * <abbr>OGR</abbr> {@code OGRGeometryH OGR_F_GetGeometryRef(OGRFeatureH 
hFeat)}.
+     * Fetch a handle to feature geometry.
+     */
+    final MethodHandle ogrFeatureGetGeometryRef;
+
+    /**
+     * <abbr>OGR</abbr> {@code void OGR_F_Destroy(OGRFeatureH hFeat)}.
+     * Destroy feature.
+     */
+    final MethodHandle ogrFeatureDestroy;
+
+    /**
+     * <abbr>OGR</abbr> {@code void OGR_DS_Destroy(OGRDataSourceH hDS)}.
+     * Closes opened datasource and releases allocated resources.
+     */
+    final MethodHandle ogrDataSourceDestroy;
+
+    /**
+     * <abbr>OGR</abbr> {@code const char * OGR_G_GetGeometryName(OGRGeometryH 
hGeom)}.
+     * Fetch WKT name for geometry type.
+     */
+    final MethodHandle ogrGeometryGetGeometryName;
+
+    /**
+     * <abbr>OGR</abbr> {@code int CPL_DLL OGR_G_GetPoints(OGRGeometryH hGeom, 
void *pabyX, int nXStride,
+     *                                  void *pabyY, int nYStride, void 
*pabyZ, int nZStride);}.
+     * Returns all points of line string.
+     */
+    final MethodHandle ogrGeometryGetPoints;
+
+    /**
+     * <abbr>OGR</abbr> {@code int OGR_G_GetPointCount(OGRGeometryH hGeom)}.
+     * Fetch number of points from a Point or a LineString/LinearRing geometry.
+     */
+    final MethodHandle ogrGeometryGetPointCount;
+
+    /**
+     * <abbr>OGR</abbr> {@code int OGR_G_GetGeometryCount(OGRGeometryH hGeom)}.
+     * Fetch the number of elements in a geometry or number of geometries in 
container.
+     */
+    final MethodHandle ogrGeometryGetGeometryCount;
+
+    /**
+     * <abbr>OGR</abbr> {@code OGRGeometryH OGR_G_GetGeometryRef(OGRGeometryH 
hGeom, int iSubGeom)}.
+     * Fetch geometry from a geometry container.
+     */
+    final MethodHandle ogrGeometryGetGeometryRef;
+
+    /**
+     * <abbr>OGR</abbr> {@code Pointer CPLErr OGR_FD_GetFieldCount(Pointer 
hDS)}.
+     * Fetch number of fields on the passed feature definition.
+     */
+    final MethodHandle ogrFeatureDefinitionGetFieldCount;
+
+    /**
+     * <abbr>OGR</abbr> {@code Pointer CPLErr OGR_FD_GetFieldDefn(Pointer 
hDS)}.
+     * Fetch field definition of the passed feature definition.
+     */
+    final MethodHandle ogrFeatureDefinitionGetFieldDefinition;
+
+    /**
+     * <abbr>OGR</abbr> {@code int CPLErr OGR_Fld_GetType(Pointer hDS, int 
index)}.
+     * Fetch type of this field.
+     */
+    final MethodHandle ogrFeatureDefinitionGetFieldType;
+
+    /**
+     * <abbr>OGR</abbr> {@code Pointer CPLErr OGR_Fld_GetNameRef(Pointer hDS)}.
+     * Fetch name of this field.
+     */
+    final MethodHandle ogrFeatureDefinitionGetFieldName;
+
+    /**
+     * <abbr>OGR</abbr> {@code int CPLErr OGR_FD_GetGeomFieldCount(Pointer 
hDS)}.
+     * Fetch number of geometry fields on this feature.
+     */
+    final MethodHandle ogrFeatureDefinitionGetGeomFieldCount;
+
+    /**
+     * <abbr>OGR</abbr> {@code OGRGeomFieldDefnH 
OGR_FD_GetGeomFieldDefn(OGRFeatureDefnH hDefn, int iGeomField)}.
+     * Fetch geometry field definition of the passed feature definition.
+     */
+    final MethodHandle ogrFeatureDefinitionGetGeomFieldDefinition;
+
+    /**
+     * <abbr>OGR</abbr> {@code int CPLErr OGR_Fld_GetType(Pointer hDS, int 
index)}.
+     * Fetch geometry type of this field.
+     */
+    final MethodHandle ogrFeatureDefinitionGetGeomFieldType;
+
+    /**
+     * <abbr>OGR</abbr> {@code OGRwkbGeometryType   CPL_DLL OGR_GFld_GetType( 
OGRGeomFieldDefnH )}.
+     * Fetch name of this field.
+     */
+    final MethodHandle ogrFeatureDefinitionGetGeomFieldName;
+
+    /**
+     * <abbr>OGR</abbr> {@code OGRSpatialReferenceH CPL_DLL 
OGR_GFld_GetSpatialRef(OGRGeomFieldDefnH)}.
+     * Fetch spatial reference system of this field.
+     */
+    final MethodHandle ogrFeatureDefinitionGetGeomFieldSpatialRef;
+
+
+
     /**
      * Creates the handles for all <abbr>GDAL</abbr> functions which will be 
needed.
      *
@@ -288,6 +465,7 @@ final class GDAL extends NativeFunctions {
         final var acceptPointerReturnInt     = 
FunctionDescriptor.of(ValueLayout.JAVA_INT,    ValueLayout.ADDRESS);
         final var acceptTwoPtrsReturnDouble  = 
FunctionDescriptor.of(ValueLayout.JAVA_DOUBLE, ValueLayout.ADDRESS, 
ValueLayout.ADDRESS);
         final var acceptTwoPtrsReturnPointer = 
FunctionDescriptor.of(ValueLayout.ADDRESS,     ValueLayout.ADDRESS, 
ValueLayout.ADDRESS);
+        final var acceptPointerAndIntReturnPointer = 
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, 
ValueLayout.JAVA_INT);
 
         // Memory management
         free    = lookup("VSIFree",    
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS));
@@ -394,6 +572,97 @@ final class GDAL extends NativeFunctions {
                 ValueLayout.JAVA_INT,       // GDALDataType eBDataType
                 ValueLayout.ADDRESS));      // CSLConstList papszOptions
 
+        // Dataset layer API
+        datasetGetLayerCount = lookup("GDALDatasetGetLayerCount",  
acceptPointerReturnInt);
+
+        datasetGetLayer = lookup("GDALDatasetGetLayer",  
acceptPointerAndIntReturnPointer);
+
+        // OGR API
+        ogrLayerGetLayerDefn = lookup("OGR_L_GetLayerDefn",  
acceptPointerReturnPointer);
+
+        ogrLayerGetName = lookup("OGR_L_GetName",  acceptPointerReturnPointer);
+
+        ogrLayerGetFeatureCount = lookup("OGR_L_GetFeatureCount",  
FunctionDescriptor.of(
+                ValueLayout.JAVA_LONG,
+                ValueLayout.ADDRESS,
+                ValueLayout.JAVA_INT)); //flag to force computtion
+
+        ogrLayerGetExtent = lookup("OGR_L_GetExtent",  FunctionDescriptor.of(
+                ValueLayout.JAVA_INT,
+                ValueLayout.ADDRESS,
+                ValueLayout.ADDRESS,
+                ValueLayout.JAVA_INT));
+
+        ogrLayerGetNextFeature = lookup("OGR_L_GetNextFeature",  
acceptPointerReturnPointer);
+
+        ogrFeatureGetFid = lookup("OGR_F_GetFID",  FunctionDescriptor.of(
+                ValueLayout.JAVA_LONG,
+                ValueLayout.ADDRESS));
+
+        ogrFeatureDefinitionGetFieldCount = lookup("OGR_FD_GetFieldCount",  
acceptPointerReturnInt);
+
+        ogrFeatureDefinitionGetFieldDefinition = lookup("OGR_FD_GetFieldDefn", 
 acceptPointerAndIntReturnPointer);
+
+        ogrFeatureDefinitionGetFieldType = lookup("OGR_Fld_GetType",  
acceptPointerReturnInt);
+
+        ogrFeatureDefinitionGetFieldName = lookup("OGR_Fld_GetNameRef",  
acceptPointerReturnPointer);
+
+        ogrFeatureDefinitionGetGeomFieldCount = 
lookup("OGR_FD_GetGeomFieldCount",  acceptPointerReturnInt);
+
+        ogrFeatureDefinitionGetGeomFieldDefinition = 
lookup("OGR_FD_GetGeomFieldDefn",  acceptPointerAndIntReturnPointer);
+
+        ogrFeatureDefinitionGetGeomFieldType = lookup("OGR_GFld_GetType",  
acceptPointerReturnInt);
+
+        ogrFeatureDefinitionGetGeomFieldName = lookup("OGR_GFld_GetNameRef",  
acceptPointerReturnPointer);
+
+        ogrFeatureDefinitionGetGeomFieldSpatialRef = 
lookup("OGR_GFld_GetSpatialRef",  acceptPointerReturnPointer);
+
+        ogrFeatureGetFieldAsInteger = lookup("OGR_F_GetFieldAsInteger",  
FunctionDescriptor.of(
+                ValueLayout.JAVA_INT,
+                ValueLayout.ADDRESS,
+                ValueLayout.JAVA_INT));
+
+        ogrFeatureGetFieldAsInteger64 = lookup("OGR_F_GetFieldAsInteger64",  
FunctionDescriptor.of(
+                ValueLayout.JAVA_LONG,
+                ValueLayout.ADDRESS,
+                ValueLayout.JAVA_INT));
+
+        ogrFeatureGetFieldAsDouble = lookup("OGR_F_GetFieldAsDouble",  
FunctionDescriptor.of(
+                ValueLayout.JAVA_DOUBLE,
+                ValueLayout.ADDRESS,
+                ValueLayout.JAVA_INT));
+
+        ogrFeatureGetFieldAsString = lookup("OGR_F_GetFieldAsString",  
FunctionDescriptor.of(
+                ValueLayout.ADDRESS,
+                ValueLayout.ADDRESS,
+                ValueLayout.JAVA_INT));
+
+        ogrFeatureGetGeometryRef = lookup("OGR_F_GetGeometryRef",  
acceptPointerReturnPointer);
+
+        ogrFeatureDestroy = lookup("OGR_F_Destroy",  
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS));
+
+        ogrDataSourceDestroy = lookup("OGR_DS_Destroy",  
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS));
+
+        ogrGeometryGetGeometryName = lookup("OGR_G_GetGeometryName",  
acceptPointerReturnPointer);
+
+        ogrGeometryGetPoints = lookup("OGR_G_GetPoints",  
FunctionDescriptor.of(
+                ValueLayout.JAVA_INT,
+                ValueLayout.ADDRESS,
+                ValueLayout.ADDRESS,
+                ValueLayout.JAVA_INT,
+                ValueLayout.ADDRESS,
+                ValueLayout.JAVA_INT,
+                ValueLayout.ADDRESS,
+                ValueLayout.JAVA_INT));
+
+        ogrGeometryGetPointCount = lookup("OGR_G_GetPointCount",  
acceptPointerReturnInt);
+
+        ogrGeometryGetGeometryCount = lookup("OGR_G_GetGeometryCount",  
acceptPointerReturnInt);
+
+        ogrGeometryGetGeometryRef = lookup("OGR_G_GetGeometryRef",  
acceptPointerAndIntReturnPointer);
+
+
+
         // Set error handling first in order to redirect initialization 
warnings.
         setErrorHandler(null);
 
diff --git 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStore.java
 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStore.java
index 748dc7d15c..2aa49d6ccb 100644
--- 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStore.java
+++ 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStore.java
@@ -50,6 +50,7 @@ import org.apache.sis.util.privy.Constants;
 import org.apache.sis.util.privy.UnmodifiableArrayList;
 import org.apache.sis.util.iso.DefaultNameFactory;
 import org.apache.sis.system.Cleaners;
+import org.apache.sis.util.ArraysExt;
 
 
 /**
@@ -373,7 +374,9 @@ public class GDALStore extends DataStore implements 
Aggregate {
             if (subdatasets != null && !subdatasets.isEmpty()) {
                 components = subdatasets;
             } else {
-                components = 
UnmodifiableArrayList.wrap(TiledResource.groupBySizeAndType(this, gdal, 
handle()));
+                final TiledResource[] rasters = 
TiledResource.groupBySizeAndType(this, gdal, handle());
+                final OGRFeatureSet[] vectors = 
OGRFeatureSet.listVectors(this, gdal, handle());
+                components = 
UnmodifiableArrayList.wrap(ArraysExt.concatenate(new Resource[0], rasters, 
vectors));
             }
         } finally {
             ErrorHandler.throwOnFailure(this, "components");
diff --git 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRFeatureSet.java
 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRFeatureSet.java
new file mode 100644
index 0000000000..639f108e2f
--- /dev/null
+++ 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRFeatureSet.java
@@ -0,0 +1,184 @@
+/*
+ * 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.gdal;
+
+import java.lang.foreign.Arena;
+import java.lang.foreign.MemorySegment;
+import java.nio.DoubleBuffer;
+import java.util.Optional;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import org.apache.sis.feature.builder.AttributeRole;
+import org.apache.sis.feature.builder.AttributeTypeBuilder;
+import org.apache.sis.feature.builder.FeatureTypeBuilder;
+import org.apache.sis.feature.privy.AttributeConvention;
+import org.apache.sis.geometry.GeneralEnvelope;
+import org.apache.sis.referencing.crs.AbstractCRS;
+import org.apache.sis.referencing.cs.AxesConvention;
+import org.apache.sis.storage.AbstractFeatureSet;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.panama.NativeFunctions;
+import org.locationtech.jts.geom.LineString;
+import org.locationtech.jts.geom.MultiLineString;
+import org.locationtech.jts.geom.MultiPolygon;
+import org.locationtech.jts.geom.Polygon;
+import org.opengis.feature.Feature;
+import org.opengis.feature.FeatureType;
+import org.opengis.geometry.Envelope;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+/**
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+final class OGRFeatureSet extends AbstractFeatureSet {
+
+    final GDALStore store;
+    final GDAL gdal;
+    final MemorySegment dataset;
+    final MemorySegment layer;
+
+    //computed after a getType() call
+    FeatureType type;
+    CoordinateReferenceSystem crs;
+    String[] fields;
+    String[] geomFields;
+    OGRFieldType[] fieldEncs;
+
+    OGRFeatureSet(final GDALStore store, final GDAL gdal, final MemorySegment 
dataset, MemorySegment layer) {
+        super(store);
+        this.store = store;
+        this.gdal = gdal;
+        this.dataset = dataset;
+        this.layer = layer;
+    }
+
+    @Override
+    public synchronized FeatureType getType() throws DataStoreException {
+        if (type != null) return type;
+
+        try {
+            final MemorySegment driver = (MemorySegment) 
gdal.getDatasetDriver.invokeExact(dataset);
+            final String driverName = NativeFunctions.toString((MemorySegment) 
gdal.getName.invokeExact(driver));
+
+            final MemorySegment layerDef = (MemorySegment) 
gdal.ogrLayerGetLayerDefn.invokeExact(layer);
+            final String name = NativeFunctions.toString( ((MemorySegment) 
gdal.ogrLayerGetName.invokeExact(layer)));
+
+            final FeatureTypeBuilder ftb =  new FeatureTypeBuilder();
+            
ftb.addAttribute(Long.class).setName(AttributeConvention.IDENTIFIER_PROPERTY);
+            ftb.setName(name);
+
+            // List feature type fields
+            fields = new 
String[(int)gdal.ogrFeatureDefinitionGetFieldCount.invokeExact(layerDef)];
+            fieldEncs = new OGRFieldType[fields.length];
+            for (int i = 0 ; i<fields.length; i++) {
+                final MemorySegment fieldDef  = (MemorySegment) 
gdal.ogrFeatureDefinitionGetFieldDefinition.invokeExact(layerDef,i);
+                final OGRFieldType type = OGRFieldType.valueOf((int) 
gdal.ogrFeatureDefinitionGetFieldType.invokeExact(fieldDef));
+                final String fieldName  = NativeFunctions.toString( 
(MemorySegment)gdal.ogrFeatureDefinitionGetFieldName.invokeExact(fieldDef));
+                final Class<?> valueClass  = type.getJavaClass();
+                ftb.addAttribute(valueClass).setName(fieldName);
+                fields[i] = fieldName;
+                fieldEncs[i] = type;
+            }
+
+            // List geometric feature type fields
+            geomFields = new String[(int) 
gdal.ogrFeatureDefinitionGetGeomFieldCount.invokeExact(layerDef)];
+            for(int i=0; i<geomFields.length; i++) {
+                final MemorySegment ogrGeomFieldDefnH = (MemorySegment) 
gdal.ogrFeatureDefinitionGetGeomFieldDefinition.invokeExact(layerDef,i);
+                final OGRwkbGeometryType typrgeom = 
OGRwkbGeometryType.valueOf( (int) 
gdal.ogrFeatureDefinitionGetGeomFieldType.invokeExact(ogrGeomFieldDefnH));
+                geomFields[i]      = 
NativeFunctions.toString((MemorySegment)gdal.ogrFeatureDefinitionGetGeomFieldName.invokeExact(ogrGeomFieldDefnH));
+                if(geomFields[i].isEmpty()) geomFields[i] = "geometry"+i;
+
+                //read CRS
+                final MemorySegment crsRef  = (MemorySegment) 
gdal.ogrFeatureDefinitionGetGeomFieldSpatialRef.invokeExact(ogrGeomFieldDefnH);
+                final SpatialRef spatialRef = 
SpatialRef.createWithHandle(store, gdal, crsRef);
+                crs = spatialRef.parseCRS("listVectors");
+                //force longitude first
+                crs = 
((AbstractCRS)crs).forConvention(AxesConvention.RIGHT_HANDED);
+
+                Class<?> geomClass = typrgeom.getJavaClass();
+                if (driverName.toLowerCase().contains("shapefile")) {
+                    //OGR Hack : shapefile geometry type is not correctly 
detected
+                    //this seems to be because ogr shp driver do not make a 
difference betwen geom types
+                    //https://code.djangoproject.com/ticket/7218
+                    if (Polygon.class.equals(geomClass)) geomClass = 
MultiPolygon.class;
+                    if (LineString.class.equals(geomClass)) geomClass = 
MultiLineString.class;
+                }
+
+                final AttributeTypeBuilder<?> attBuilder = 
ftb.addAttribute(geomClass).setName(geomFields[i]).setCRS(crs);
+                if (i == 0) 
attBuilder.addRole(AttributeRole.DEFAULT_GEOMETRY);     // first geometry as 
default
+            }
+            type = ftb.build();
+        } catch (Throwable e) {
+            throw GDAL.propagate(e);
+        }
+        return type;
+    }
+
+    @Override
+    public Optional<Envelope> getEnvelope() throws DataStoreException {
+        // use ogr provided envelope
+        try (Arena arena = Arena.ofConfined()) {
+            final MemorySegment extent = arena.allocate(8*4);
+            int error = (int) gdal.ogrLayerGetExtent.invokeExact(layer, 
extent, 1);
+            if (error != 0) {
+                throw new DataStoreException("Failed to calculate envelope for 
type "+ getIdentifier().get());
+            }
+            final DoubleBuffer db = extent.asByteBuffer().asDoubleBuffer();
+            final GeneralEnvelope env = new GeneralEnvelope(crs);
+            env.setRange(0, db.get(0), db.get(1));
+            env.setRange(1, db.get(2), db.get(3));
+            return Optional.of(env);
+        } catch (Throwable e) {
+            throw GDAL.propagate(e);
+        }
+    }
+
+    public long getCount() throws DataStoreException {
+        try {
+            final Long nb = (Long) 
gdal.ogrLayerGetFeatureCount.invokeExact(layer, 1);
+            return nb != null ? nb : -1;
+        } catch (Throwable e) {
+            throw GDAL.propagate(e);
+        }
+    }
+
+    @Override
+    public Stream<Feature> features(boolean parallel) throws 
DataStoreException {
+        final OgrSpliterator ite = new OgrSpliterator(this, getType());
+        return StreamSupport.stream(ite, parallel);
+    }
+
+    /**
+     * Returns featuresets found.
+     *
+     * @throws DataStoreException if an error occurred.
+     */
+    static OGRFeatureSet[] listVectors(final GDALStore parent, final GDAL 
gdal, final MemorySegment dataset)
+        throws DataStoreException {
+        try {
+            final OGRFeatureSet[] array = new OGRFeatureSet[(int) 
gdal.datasetGetLayerCount.invokeExact(dataset)];
+            for (int iLayer = 0; iLayer < array.length ; iLayer++) {
+                final MemorySegment layer = (MemorySegment) 
gdal.datasetGetLayer.invokeExact(dataset, iLayer);
+                array[iLayer] = new OGRFeatureSet(parent, gdal, dataset, 
layer);
+            }
+            return array;
+        } catch (Throwable e) {
+            throw GDAL.propagate(e);
+        }
+    }
+}
diff --git 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRFieldType.java
 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRFieldType.java
new file mode 100644
index 0000000000..9559127e58
--- /dev/null
+++ 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRFieldType.java
@@ -0,0 +1,84 @@
+/*
+ * 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.gdal;
+
+/**
+ *
+ * @author Hilmi Bouallegue (Geomatys)
+ */
+enum OGRFieldType {
+    /** Simple 32bit integer */
+    OFTInteger(Integer.class),
+    /** List of 32bit integers */
+    OFTIntegerList(Object.class),
+    /** Double Precision floating point */
+    OFTReal(Double.class),
+    /** List of doubles */
+    OFTRealList(Object.class),
+    /** String of ASCII chars */
+    OFTString(String.class),
+    /** Array of strings */
+    OFTStringList(Object.class),
+    /** deprecated */
+    OFTWideString(String.class),
+    /** deprecated */
+    OFTWideStringList(Object.class),
+    /** Raw Binary data */
+    OFTBinary(Object.class),
+    /** Date */
+    OFTDate(Object.class),
+    /** Time */
+    OFTTime(Object.class),
+    /** Date and Time */
+    OFTDateTime(Object.class),
+    /** Single 64bit integer */
+    OFTInteger64(Long.class),
+    /** List of 64bit integers */
+    OFTInteger64List(Object.class),
+    OFTMaxType(Object.class);
+
+    private final Class javaClass;
+
+    OGRFieldType(Class javaClass){
+        this.javaClass =javaClass;
+    }
+
+    public Class getJavaClass(){
+        return javaClass;
+    }
+
+    public static OGRFieldType valueOf(int value) {
+        switch (value) {
+            case 0 : return OFTInteger;
+            case 1 : return OFTIntegerList;
+            case 2 : return OFTReal;
+            case 3 : return OFTRealList;
+            case 4 : return OFTString;
+            case 5 : return OFTStringList;
+            case 6 : return OFTWideString;
+            case 7 : return OFTWideStringList;
+            case 8 : return OFTBinary;
+            case 9 : return OFTDate;
+            case 10 : return OFTTime;
+            case 11 : return OFTDateTime;
+            case 12 : return OFTInteger64;
+            case 13 : return OFTInteger64List;
+        }
+        throw new IllegalArgumentException("Unknown type " + value);
+    }
+
+}
diff --git 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRwkbByteOrder.java
 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRwkbByteOrder.java
new file mode 100644
index 0000000000..6cacfa2312
--- /dev/null
+++ 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRwkbByteOrder.java
@@ -0,0 +1,36 @@
+/*
+ * 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.gdal;
+
+/**
+ *
+ * @author Hilmi Bouallegue (Geomatys)
+ */
+enum OGRwkbByteOrder {
+    /** MSB/Sun/Motoroloa: Most Significant Byte First. */
+    wkbXDR,
+    /** LSB/Intel/Vax: Least Significant Byte First. */
+    wkbNDR;
+
+    public static OGRwkbByteOrder valueOf(int value) {
+        switch (value) {
+            case 0 : return wkbXDR;
+            case 1 : return wkbNDR;
+        }
+        throw new IllegalArgumentException("Unknown type " + value);
+    }
+}
diff --git 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRwkbGeometryType.java
 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRwkbGeometryType.java
new file mode 100644
index 0000000000..5f81883227
--- /dev/null
+++ 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRwkbGeometryType.java
@@ -0,0 +1,185 @@
+/*
+ * 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.gdal;
+
+import org.locationtech.jts.geom.*;
+
+
+/**
+ *
+ * @author Hilmi Bouallegue (Geomatys)
+ */
+public enum OGRwkbGeometryType {
+    wkbUnknown(Geometry.class),
+    wkbPoint(Point.class),
+    wkbLineString(LineString.class),
+    wkbPolygon(Polygon.class),
+    wkbMultiPoint(MultiPoint.class),
+    wkbMultiLineString(MultiLineString.class),
+    wkbMultiPolygon(MultiPolygon.class),
+    wkbGeometryCollection(GeometryCollection.class),
+    wkbCircularString(Geometry.class),
+    wkbCompoundCurve(Geometry.class),
+    wkbCurvePolygon(Geometry.class),
+    wkbMultiCurve(Geometry.class),
+    wkbMultiSurface(Geometry.class),
+    wkbCurve(Geometry.class),
+    wkbSurface(Geometry.class),
+    wkbPolyhedralSurface(Geometry.class),
+    wkbTIN(Geometry.class),
+    wkbTriangle(Geometry.class),
+    wkbNone(Geometry.class),
+    wkbLinearRing(Geometry.class),
+    wkbCircularStringZ(Geometry.class),
+    wkbCompoundCurveZ(Geometry.class),
+    wkbCurvePolygonZ(Geometry.class),
+    wkbMultiCurveZ(Geometry.class),
+    wkbMultiSurfaceZ(Geometry.class),
+    wkbCurveZ(Geometry.class),
+    wkbSurfaceZ(Geometry.class),
+    wkbPolyhedralSurfaceZ(Geometry.class),
+    wkbTINZ(Geometry.class),
+    wkbTriangleZ(Geometry.class),
+    wkbPointM(Geometry.class),
+    wkbLineStringM(Geometry.class),
+    wkbPolygonM(Geometry.class),
+    wkbMultiPointM(Geometry.class),
+    wkbMultiLineStringM(Geometry.class),
+    wkbMultiPolygonM(Geometry.class),
+    wkbGeometryCollectionM(Geometry.class),
+    wkbCircularStringM(Geometry.class),
+    wkbCompoundCurveM(Geometry.class),
+    wkbCurvePolygonM(Geometry.class),
+    wkbMultiCurveM(Geometry.class),
+    wkbMultiSurfaceM(Geometry.class),
+    wkbCurveM(Geometry.class),
+    wkbSurfaceM(Geometry.class),
+    wkbPolyhedralSurfaceM(Geometry.class),
+    wkbTINM(Geometry.class),
+    wkbTriangleM(Geometry.class),
+    wkbPointZM(Geometry.class),
+    wkbLineStringZM(Geometry.class),
+    wkbPolygonZM(Geometry.class),
+    wkbMultiPointZM(Geometry.class),
+    wkbMultiLineStringZM(Geometry.class),
+    wkbMultiPolygonZM(Geometry.class),
+    wkbGeometryCollectionZM(Geometry.class),
+    wkbCircularStringZM(Geometry.class),
+    wkbCompoundCurveZM(Geometry.class),
+    wkbCurvePolygonZM(Geometry.class),
+    wkbMultiCurveZM(Geometry.class),
+    wkbMultiSurfaceZM(Geometry.class),
+    wkbCurveZM(Geometry.class),
+    wkbSurfaceZM(Geometry.class),
+    wkbPolyhedralSurfaceZM(Geometry.class),
+    wkbTINZM(Geometry.class),
+    wkbTriangleZM(Geometry.class),
+    wkbPoint25D(Geometry.class),
+    wkbLineString25D(Geometry.class),
+    wkbPolygon25D(Geometry.class),
+    wkbMultiPoint25D(Geometry.class),
+    wkbMultiLineString25D(Geometry.class),
+    wkbMultiPolygon25D(Geometry.class),
+    wkbGeometryCollection25D(Geometry.class);
+
+    private final Class javaClass;
+
+    OGRwkbGeometryType(Class javaClass){
+        this.javaClass =javaClass;
+    }
+
+    public Class getJavaClass(){
+        return javaClass;
+    }
+
+    public static OGRwkbGeometryType valueOf(int value) {
+        switch (value) {
+            case 0 : return wkbUnknown;
+            case 1 : return wkbPoint;
+            case 2 : return wkbLineString;
+            case 3 : return wkbPolygon;
+            case 4 : return wkbMultiPoint;
+            case 5 : return wkbMultiLineString;
+            case 6 : return wkbMultiPolygon;
+            case 7 : return wkbGeometryCollection;
+            case 8 : return wkbCircularString;
+            case 9 : return wkbCompoundCurve;
+            case 10 : return wkbCurvePolygon;
+            case 11 : return wkbMultiCurve;
+            case 12 : return wkbMultiSurface;
+            case 13 : return wkbCurve;
+            case 14 : return wkbSurface;
+            case 15 : return wkbPolyhedralSurface;
+            case 16 : return wkbTIN;
+            case 17 : return wkbTriangle;
+            case 18 : return wkbNone;
+            case 19 : return wkbLinearRing;
+            case 20 : return wkbCircularStringZ;
+            case 21 : return wkbCompoundCurveZ;
+            case 22 : return wkbCurvePolygonZ;
+            case 23 : return wkbMultiCurveZ;
+            case 24 : return wkbMultiSurfaceZ;
+            case 25 : return wkbCurveZ;
+            case 26 : return wkbSurfaceZ;
+            case 27 : return wkbPolyhedralSurfaceZ;
+            case 28 : return wkbTINZ;
+            case 29 : return wkbTriangleZ;
+            case 30 : return wkbPointM;
+            case 31 : return wkbLineStringM;
+            case 32 : return wkbPolygonM;
+            case 33 : return wkbMultiPointM;
+            case 34 : return wkbMultiLineStringM;
+            case 35 : return wkbMultiPolygonM;
+            case 36 : return wkbGeometryCollectionM;
+            case 37 : return wkbCircularStringM;
+            case 38 : return wkbCompoundCurveM;
+            case 39 : return wkbCurvePolygonM;
+            case 40 : return wkbMultiCurveM;
+            case 41 : return wkbMultiSurfaceM;
+            case 42 : return wkbCurveM;
+            case 43 : return wkbSurfaceM;
+            case 44 : return wkbPolyhedralSurfaceM;
+            case 45 : return wkbTINM;
+            case 46 : return wkbTriangleM;
+            case 47 : return wkbPointZM;
+            case 48 : return wkbLineStringZM;
+            case 49 : return wkbPolygonZM;
+            case 50 : return wkbMultiPointZM;
+            case 51 : return wkbMultiLineStringZM;
+            case 52 : return wkbMultiPolygonZM;
+            case 53 : return wkbGeometryCollectionZM;
+            case 54 : return wkbCircularStringZM;
+            case 55 : return wkbCompoundCurveZM;
+            case 56 : return wkbCurvePolygonZM;
+            case 57 : return wkbMultiCurveZM;
+            case 58 : return wkbMultiSurfaceZM;
+            case 59 : return wkbCurveZM;
+            case 60 : return wkbSurfaceZM;
+            case 61 : return wkbPolyhedralSurfaceZM;
+            case 62 : return wkbTINZM;
+            case 63 : return wkbTriangleZM;
+            case 64 : return wkbPoint25D;
+            case 65 : return wkbLineString25D;
+            case 66 : return wkbPolygon25D;
+            case 67 : return wkbMultiPoint25D;
+            case 68 : return wkbMultiLineString25D;
+            case 69 : return wkbMultiPolygon25D;
+            case 70 : return wkbGeometryCollection25D;
+        }
+        throw new IllegalArgumentException("Unknown type " + value);
+    }
+}
diff --git 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OgrGeometryReader.java
 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OgrGeometryReader.java
new file mode 100644
index 0000000000..2bbe4aade8
--- /dev/null
+++ 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OgrGeometryReader.java
@@ -0,0 +1,206 @@
+/*
+ * 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.gdal;
+
+import java.lang.foreign.Arena;
+import java.lang.foreign.MemorySegment;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.panama.NativeFunctions;
+import org.locationtech.jts.geom.CoordinateSequence;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.LineString;
+import org.locationtech.jts.geom.LinearRing;
+import org.locationtech.jts.geom.Polygon;
+import org.locationtech.jts.geom.impl.PackedCoordinateSequence;
+
+/**
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+final class OgrGeometryReader implements AutoCloseable {
+
+    private static final GeometryFactory GF = new GeometryFactory();
+    //reuse direct buffer for better performances
+    private MemorySegment px;
+    private MemorySegment py;
+    private ByteBuffer bufferx;
+    private ByteBuffer buffery;
+
+    private final Arena arena = Arena.ofConfined();
+    private final GDAL gdal;
+
+    OgrGeometryReader(GDAL gdal) {
+        this.gdal = gdal;
+    }
+
+    private void resizeBuffer(int nbPoint){
+        final int size = nbPoint*2*8;
+        if (px == null || px.byteSize() < size) {
+            px = arena.allocate(size);
+            py = px.asSlice(8);
+            bufferx = px.asByteBuffer();
+            buffery = py.asByteBuffer();
+        }
+    }
+
+    public Geometry toGeometry(MemorySegment ogrGeom) throws 
DataStoreException {
+        if (ogrGeom == null) return null;
+
+        try {
+            MemorySegment NULL = MemorySegment.ofAddress(0);
+            final String type = NativeFunctions.toString( 
(MemorySegment)gdal.ogrGeometryGetGeometryName.invokeExact(ogrGeom));
+
+            switch (type) {
+                case "POINT" : {
+                    final double[] coords = new double[2];
+                    resizeBuffer(1);
+                    final int returnedNbPoints = (int) 
gdal.ogrGeometryGetPoints.invokeExact(ogrGeom,px,16,py,16,NULL,0);
+
+                    bufferx.position(0);
+                    
bufferx.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer().get(coords);
+
+                    final CoordinateSequence cs = new 
PackedCoordinateSequence.Double(coords,2,0);
+                    return GF.createPoint(cs);
+                }
+                case "MULTIPOINT" : {
+                    final int nbPoint = (int) 
gdal.ogrGeometryGetPointCount.invokeExact(ogrGeom);
+                    final double[] coords = new double[nbPoint*2];
+                    if (nbPoint != 0) {
+                        resizeBuffer(nbPoint);
+                        final int returnedNbPoints = (int) 
gdal.ogrGeometryGetPoints.invokeExact(ogrGeom,px,16,py,16,NULL,0);
+
+                        bufferx.position(0);
+                        
bufferx.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer().get(coords);
+                    }
+                    final CoordinateSequence cs = new 
PackedCoordinateSequence.Double(coords,2,0);
+                    return GF.createMultiPoint(cs);
+                }
+                case "LINESTRING" : {
+                    final int nbPoint = (int) 
gdal.ogrGeometryGetPointCount.invokeExact(ogrGeom);
+                    final double[] coords = new double[nbPoint*2];
+                    resizeBuffer(nbPoint);
+                    final int returnedNbPoints = (int) 
gdal.ogrGeometryGetPoints.invokeExact(ogrGeom,px,16,py,16,NULL,0);
+
+                    bufferx.position(0);
+                    
bufferx.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer().get(coords);
+
+                    if (nbPoint==1) {
+                        //duplicate first point, JTS need at least 2 
coordinates
+                        final double[] cp = new 
double[]{coords[0],coords[1],coords[0],coords[1]};
+                        final CoordinateSequence cs = new 
PackedCoordinateSequence.Double(cp,2,0);
+                        return GF.createLineString(cs);
+                    } else {
+                        final CoordinateSequence cs = new 
PackedCoordinateSequence.Double(coords,2,0);
+                        return GF.createLineString(cs);
+                    }
+                }
+                case "LINEARRING" : {
+                    final int nbPoint = (int) 
gdal.ogrGeometryGetPointCount.invokeExact(ogrGeom);
+                    double[] coords = new double[(nbPoint+1)*2];
+                    resizeBuffer(nbPoint+1);
+                    final int returnedNbPoints = (int) 
gdal.ogrGeometryGetPoints.invokeExact(ogrGeom,px,16,py,16,NULL,0);
+
+                    bufferx.position(0);
+                    
bufferx.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer().get(coords,0,nbPoint*2);
+
+                    //JTS needs at least 3+1 points
+                    if (coords.length<8) {
+                        double[] cs = Arrays.copyOf(coords, 8);
+                        for(int i=nbPoint;i<4;i++){
+                            cs[i*2+0] = coords[0];
+                            cs[i*2+1] = coords[1];
+                        }
+                        coords = cs;
+                    }
+
+                    //duplicate first to last point this is a JTS constraint
+                    coords[coords.length-2] = coords[0];
+                    coords[coords.length-1] = coords[1];
+
+                    final CoordinateSequence cs = new 
PackedCoordinateSequence.Double(coords,2,0);
+                    return GF.createLinearRing(cs);
+                }
+                case "MULTILINESTRING" : {
+                    final int nbGeom = (int) 
gdal.ogrGeometryGetGeometryCount.invokeExact(ogrGeom);
+                    final LineString[] children = new LineString[nbGeom];
+                    for (int i=0;i<nbGeom;i++) {
+                        final MemorySegment sub = (MemorySegment) 
gdal.ogrGeometryGetGeometryRef.invokeExact(ogrGeom, i);
+                        children[i] = (LineString) toGeometry(sub);
+                    }
+                    return GF.createMultiLineString(children);
+                }
+                case "POLYGON" : {
+                    final int nbGeom = (int) 
gdal.ogrGeometryGetGeometryCount.invokeExact(ogrGeom);
+                    //first is the exterior ring, next ones are the interiors
+                    LinearRing exterior = null;
+                    final LinearRing[] interiors = new LinearRing[nbGeom-1];
+                    for (int i=0;i<nbGeom;i++) {
+                        final MemorySegment sub = (MemorySegment) 
gdal.ogrGeometryGetGeometryRef.invokeExact(ogrGeom, i);
+                        if (i==0) exterior = (LinearRing) toGeometry(sub);
+                        else interiors[i-1] = (LinearRing) toGeometry(sub);
+                    }
+                    return GF.createPolygon(exterior,interiors);
+                }
+                case "MULTIPOLYGON" : {
+                    final int nbGeom = (int) 
gdal.ogrGeometryGetGeometryCount.invokeExact(ogrGeom);
+                    final Polygon[] children = new Polygon[nbGeom];
+                    for (int i=0;i<nbGeom;i++) {
+                        final MemorySegment sub = (MemorySegment) 
gdal.ogrGeometryGetGeometryRef.invokeExact(ogrGeom, i);
+                        children[i] = (Polygon) toGeometry(sub);
+                    }
+                    return GF.createMultiPolygon(children);
+                }
+                case "GEOMETRYCOLLECTION" : {
+                    final int nbGeom = (int) 
gdal.ogrGeometryGetGeometryCount.invokeExact(ogrGeom);
+                    final Geometry[] children = new Geometry[nbGeom];
+                    for (int i=0;i<nbGeom;i++) {
+                        final MemorySegment sub = (MemorySegment) 
gdal.ogrGeometryGetGeometryRef.invokeExact(ogrGeom, i);
+                        children[i] = toGeometry(sub);
+                    }
+                    return GF.createGeometryCollection(children);
+                }
+                case "GEOMETRY" :
+                case "CIRCULARSTRING" :
+                case "COMPOUNDCURVE" :
+                case "CURVEPOLYGON" :
+                case "MULTICURVE" :
+                case "MULTISURFACE" :
+                case "CURVE" :
+                case "SURFACE" :
+                case "POLYHEDRALSURFACE" :
+                case "TIN" :
+                case "TRIANGLE" :
+                default : {
+                    throw new DataStoreException("Unsupported geometry type 
"+type);
+                }
+            }
+        } catch (Throwable e) {
+            throw GDAL.propagate(e);
+        }
+
+    }
+
+    @Override
+    public void close() {
+        arena.close();
+    }
+
+}
diff --git 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OgrSpliterator.java
 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OgrSpliterator.java
new file mode 100644
index 0000000000..a293d52327
--- /dev/null
+++ 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OgrSpliterator.java
@@ -0,0 +1,133 @@
+/*
+ * 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.gdal;
+
+import java.lang.foreign.MemorySegment;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import org.apache.sis.feature.privy.AttributeConvention;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.panama.NativeFunctions;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.LineString;
+import org.locationtech.jts.geom.MultiLineString;
+import org.locationtech.jts.geom.MultiPolygon;
+import org.locationtech.jts.geom.Polygon;
+import org.opengis.feature.AttributeType;
+import org.opengis.feature.Feature;
+import org.opengis.feature.FeatureType;
+
+
+/**
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+final class OgrSpliterator implements Spliterator<Feature>{
+
+    private final OGRFeatureSet fs;
+    private final OgrGeometryReader geomReader;
+    private final FeatureType type;
+    private boolean closed = false;
+    private final GDAL gdal;
+
+    OgrSpliterator(OGRFeatureSet fs, FeatureType type) throws 
DataStoreException {
+        this.fs = fs;
+        this.type = type;
+        gdal = fs.gdal;
+        geomReader = new OgrGeometryReader(gdal);
+    }
+
+    @Override
+    public Spliterator<Feature> trySplit() {
+        return null;
+    }
+
+    @Override
+    public long estimateSize() {
+        return Long.MAX_VALUE;
+    }
+
+    @Override
+    public int characteristics() {
+        return NONNULL;
+    }
+
+    @Override
+    public boolean tryAdvance(Consumer<? super Feature> action) {
+        //Reading the features of the layer
+        try {
+            final MemorySegment featurePt = (MemorySegment) 
gdal.ogrLayerGetNextFeature.invokeExact(fs.layer);
+            if (featurePt == null || featurePt.address() == 0L) {
+                return false;
+            }
+
+            final Feature feature = type.newInstance();
+            feature.setPropertyValue(AttributeConvention.IDENTIFIER, (long) 
gdal.ogrFeatureGetFid.invokeExact(featurePt));
+            //Loop for all the features of the layer
+            for (int i = 0; i < fs.fields.length; i++) {
+                OGRFieldType fieldType = fs.fieldEncs[i];
+                String propName = fs.fields[i];
+                if (fieldType == OGRFieldType.OFTInteger) {
+                    feature.setPropertyValue(propName, (int) 
gdal.ogrFeatureGetFieldAsInteger.invokeExact(featurePt, i));
+                } else if (fieldType == OGRFieldType.OFTInteger64) {
+                    feature.setPropertyValue(propName, (long) 
gdal.ogrFeatureGetFieldAsInteger64.invokeExact(featurePt, i));
+                } else if (fieldType == OGRFieldType.OFTReal) {
+                    feature.setPropertyValue(propName, (double) 
gdal.ogrFeatureGetFieldAsDouble.invokeExact(featurePt, i));
+                } else if (fieldType == OGRFieldType.OFTString) {
+                    feature.setPropertyValue(propName, 
NativeFunctions.toString( (MemorySegment) 
gdal.ogrFeatureGetFieldAsString.invokeExact(featurePt, i)));
+                } else {
+                    feature.setPropertyValue(propName, 
NativeFunctions.toString( (MemorySegment) 
gdal.ogrFeatureGetFieldAsString.invokeExact(featurePt, i)));
+                }
+            }
+            // read geometry
+            if (fs.geomFields.length > 0) {
+                //TODO loop on all geometries
+                final MemorySegment ogrGeom = (MemorySegment) 
gdal.ogrFeatureGetGeometryRef.invokeExact(featurePt);
+                Geometry geom = geomReader.toGeometry(ogrGeom);
+                final AttributeType geomType = (AttributeType) 
type.getProperty(fs.geomFields[0]);
+
+                //shapefile mix LineString with MultiLineString and Polygon 
with MultiPolygon, but not JTS
+                if (geom instanceof LineString) {
+                    final MultiLineString ml = 
geom.getFactory().createMultiLineString(new LineString[]{(LineString) geom});
+                    ml.setUserData(geom.getUserData());
+                    geom = ml;
+                } else if (geom instanceof Polygon) {
+                    final MultiPolygon mp = 
geom.getFactory().createMultiPolygon(new Polygon[]{(Polygon) geom});
+                    mp.setUserData(geom.getUserData());
+                    geom = mp;
+                }
+                geom.setUserData(fs.crs);
+                feature.setPropertyValue(fs.geomFields[0], geom);
+            }
+            //release memory
+            gdal.ogrFeatureDestroy.invokeExact(featurePt);
+
+            action.accept(feature);
+            return true;
+        }  catch (Throwable e) {
+            throw GDAL.propagate(e);
+        }
+    }
+
+    public synchronized void close() {
+        if (closed) {
+            return;
+        }
+        closed = true;
+    }
+
+}
diff --git 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/Opener.java
 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/Opener.java
index 4b737797ec..59b699c11a 100644
--- 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/Opener.java
+++ 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/Opener.java
@@ -69,7 +69,7 @@ final class Opener implements Runnable {
      * @throws DataStoreException if <var>GDAL</var> cannot open the data set.
      */
     Opener(final GDALStoreProvider owner, final String url, final String... 
allowedDrivers) throws DataStoreException {
-        this(owner, url, new OpenFlag[] {OpenFlag.RASTER, OpenFlag.SHARED}, 
allowedDrivers, null, null);
+        this(owner, url, new OpenFlag[] {OpenFlag.RASTER, OpenFlag.VECTOR, 
OpenFlag.SHARED}, allowedDrivers, null, null);
     }
 
     /**
diff --git 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/SpatialRef.java
 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/SpatialRef.java
index 912c6a1707..813108973c 100644
--- 
a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/SpatialRef.java
+++ 
b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/SpatialRef.java
@@ -97,6 +97,19 @@ final class SpatialRef {
         return new SpatialRef(owner, gdal, handle);
     }
 
+    /**
+     * Creates a new instance.
+     *
+     * @param  owner    the dataset which is providing the <abbr>CRS</abbr> 
definition.
+     * @param  gdal     sets of handles for invoking <abbr>GDAL</abbr> 
functions.
+     * @param  spatialRefHandle  pointer to native SpatialRef.
+     * @return wrapper for the <abbr>CRS</abbr> definition provided by 
<abbr>GDAL</abbr>, or {@code null} if none.
+     * @throws DataStoreException if an error occurred while fetching 
information from <abbr>GDAL</abbr>.
+     */
+    static SpatialRef createWithHandle(final GDALStore owner, final GDAL gdal, 
final MemorySegment spatialRefHandle) throws DataStoreException {
+        return new SpatialRef(owner, gdal, spatialRefHandle);
+    }
+
     /**
      * Parses the <abbr>CRS</abbr> of the data set by parsing its 
<abbr>WKT</abbr> representation.
      * This method must be invoked from a method synchronized on {@link 
GDALStore}.

Reply via email to