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

commit e50aa45469a5223e9840ba92acef8cb17266bec9
Author: jsorel <johann.so...@geomatys.com>
AuthorDate: Fri Jun 14 16:39:22 2024 +0200

    Add support for gpkg geometry header detection and parsing
---
 .../sis/storage/sql/feature/GeometryGetter.java    | 38 +++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/GeometryGetter.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/GeometryGetter.java
index a34f8d1449..78c9596451 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/GeometryGetter.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/GeometryGetter.java
@@ -18,10 +18,12 @@ package org.apache.sis.storage.sql.feature;
 
 import java.util.OptionalInt;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.sql.ResultSet;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.geometry.wrapper.GeometryWrapper;
 import org.apache.sis.geometry.wrapper.Geometries;
+import org.apache.sis.storage.DataStoreContentException;
 
 
 /**
@@ -106,12 +108,46 @@ final class GeometryGetter<G, V extends G> extends 
ValueGetter<V> {
     public V getValue(final InfoStatements stmts, final ResultSet source, 
final int columnIndex) throws Exception {
         final byte[] wkb = encoding.getBytes(source, columnIndex);
         if (wkb == null) return null;
-        final GeometryWrapper geom = 
geometryFactory.parseWKB(ByteBuffer.wrap(wkb));
+        ByteBuffer buffer = ByteBuffer.wrap(wkb);
+
+        // Possible Geopackage header 
https://www.geopackage.org/spec140/index.html#gpb_spec
+        int gpkgSrid = -1;
+        if (wkb.length > 2 && wkb[0] == 'G' && wkb[1] == 'P') {
+            // Remove the header.
+            final int version = wkb[2] & 0xFF; // 8-bit unsigned integer, 0 = 
version 1
+            if (version != 0) {
+                throw new DataStoreContentException("Only version 1 of 
Geopackage WKB is supported");
+            }
+            final int flags = wkb[3];
+            final boolean bigEndian = (flags & 0b1) == 0;
+            final int envelopeType = (flags & 0b1110) >> 1;
+            final boolean isEmpty = (flags & 0b10000) != 0;
+            final boolean extendedType = (flags & 0b100000) != 0;
+
+            buffer.order(bigEndian ? ByteOrder.BIG_ENDIAN : 
ByteOrder.LITTLE_ENDIAN);
+            gpkgSrid = buffer.asIntBuffer().get(1);
+            // Skip header and envelope.
+            final int offset;
+            switch (envelopeType) {
+                case 0 : offset = 8; break;
+                case 1 : offset = 8 + 4 * Double.BYTES; break;
+                case 2 :
+                case 3 : offset = 8 + 6 * Double.BYTES; break;
+                case 4 : offset = 8 + 8 * Double.BYTES; break;
+                default : throw new DataStoreContentException("Invalid 
envelope type");
+            }
+            buffer = buffer.position(offset).limit(wkb.length-offset).slice();
+            // Result of slice is in BIG_ENDIAN.
+        }
+
+        final GeometryWrapper geom = geometryFactory.parseWKB(buffer);
         CoordinateReferenceSystem crs = defaultCRS;
         if (stmts != null) {
             final OptionalInt srid = geom.getSRID();
             if (srid.isPresent()) {
                 crs = stmts.fetchCRS(srid.getAsInt());
+            } else if (gpkgSrid != -1) {
+                crs = stmts.fetchCRS(srid.getAsInt());
             }
         }
         if (crs != null) {

Reply via email to