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

bchapuis pushed a commit to branch flatgeobuf
in repository https://gitbox.apache.org/repos/asf/incubator-baremaps.git

commit 9cfaf568433a1bf5306189b08ba2709c8de2b32c
Author: Bertil Chapuis <[email protected]>
AuthorDate: Tue Jun 18 14:25:37 2024 +0200

    Improve implementation
---
 .../src/main/{resources => }/fbs/feature.fbs       |   0
 .../src/main/{resources => }/fbs/header.fbs        |   0
 .../baremaps/flatgeobuf/BoundedInputStream.java    |  74 ----------
 .../org/apache/baremaps/flatgeobuf/Constants.java  |  37 -----
 .../org/apache/baremaps/flatgeobuf/FlatGeoBuf.java | 128 +++-------------
 .../{FlatGeoBuf.java => FlatGeoBufMapper.java}     | 163 +++++++--------------
 .../baremaps/flatgeobuf/FlatGeoBufReader.java      | 121 ++++++++-------
 .../baremaps/flatgeobuf/GeometryConversions.java   |   2 +-
 .../apache/baremaps/flatgeobuf/FlatGeoBufTest.java |  38 +++--
 9 files changed, 165 insertions(+), 398 deletions(-)

diff --git a/baremaps-flatgeobuf/src/main/resources/fbs/feature.fbs 
b/baremaps-flatgeobuf/src/main/fbs/feature.fbs
similarity index 100%
rename from baremaps-flatgeobuf/src/main/resources/fbs/feature.fbs
rename to baremaps-flatgeobuf/src/main/fbs/feature.fbs
diff --git a/baremaps-flatgeobuf/src/main/resources/fbs/header.fbs 
b/baremaps-flatgeobuf/src/main/fbs/header.fbs
similarity index 100%
rename from baremaps-flatgeobuf/src/main/resources/fbs/header.fbs
rename to baremaps-flatgeobuf/src/main/fbs/header.fbs
diff --git 
a/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/BoundedInputStream.java
 
b/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/BoundedInputStream.java
deleted file mode 100644
index 38b91bf5..00000000
--- 
a/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/BoundedInputStream.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.baremaps.flatgeobuf;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public class BoundedInputStream extends InputStream {
-  private final InputStream in;
-  private long remaining;
-
-  public BoundedInputStream(InputStream in, long size) {
-    this.in = in;
-    this.remaining = size;
-  }
-
-  @Override
-  public int read() throws IOException {
-    if (remaining == 0) {
-      return -1;
-    }
-    int result = in.read();
-    if (result != -1) {
-      remaining--;
-    }
-    return result;
-  }
-
-  @Override
-  public int read(byte[] b, int off, int len) throws IOException {
-    if (remaining == 0) {
-      return -1;
-    }
-    int toRead = (int) Math.min(len, remaining);
-    int result = in.read(b, off, toRead);
-    if (result != -1) {
-      remaining -= result;
-    }
-    return result;
-  }
-
-  @Override
-  public long skip(long n) throws IOException {
-    long toSkip = Math.min(n, remaining);
-    long skipped = in.skip(toSkip);
-    remaining -= skipped;
-    return skipped;
-  }
-
-  @Override
-  public int available() throws IOException {
-    return (int) Math.min(in.available(), remaining);
-  }
-
-  @Override
-  public void close() throws IOException {
-    in.close();
-  }
-}
diff --git 
a/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/Constants.java
 
b/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/Constants.java
deleted file mode 100644
index 1a15e1b7..00000000
--- 
a/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/Constants.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.baremaps.flatgeobuf;
-
-import java.nio.ByteBuffer;
-
-public class Constants {
-
-  public static final byte[] MAGIC_BYTES =
-      new byte[] {0x66, 0x67, 0x62, 0x03, 0x66, 0x67, 0x62, 0x00};
-
-  public static boolean isFlatgeobuf(ByteBuffer bb) {
-    return bb.get() == MAGIC_BYTES[0] &&
-        bb.get() == MAGIC_BYTES[1] &&
-        bb.get() == MAGIC_BYTES[2] &&
-        bb.get() == MAGIC_BYTES[3] &&
-        bb.get() == MAGIC_BYTES[4] &&
-        bb.get() == MAGIC_BYTES[5] &&
-        bb.get() == MAGIC_BYTES[6] &&
-        bb.get() == MAGIC_BYTES[7];
-  }
-}
diff --git 
a/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBuf.java
 
b/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBuf.java
index 0a07db14..1712b321 100644
--- 
a/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBuf.java
+++ 
b/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBuf.java
@@ -18,20 +18,30 @@
 package org.apache.baremaps.flatgeobuf;
 
 import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
 import java.util.List;
-import java.util.stream.IntStream;
-import org.apache.baremaps.flatgeobuf.FlatGeoBuf.Header.Feature;
 import org.locationtech.jts.geom.Geometry;
 
 public class FlatGeoBuf {
 
-  private FlatGeoBuf() {
+    public static final byte[] MAGIC_BYTES =
+        new byte[] {0x66, 0x67, 0x62, 0x03, 0x66, 0x67, 0x62, 0x00};
+
+    private FlatGeoBuf() {
     // Prevent instantiation
   }
 
-  // Geometry type enumeration
+    public static boolean isFlatgeobuf(ByteBuffer bb) {
+      return bb.get() == MAGIC_BYTES[0] &&
+          bb.get() == MAGIC_BYTES[1] &&
+          bb.get() == MAGIC_BYTES[2] &&
+          bb.get() == MAGIC_BYTES[3] &&
+          bb.get() == MAGIC_BYTES[4] &&
+          bb.get() == MAGIC_BYTES[5] &&
+          bb.get() == MAGIC_BYTES[6] &&
+          bb.get() == MAGIC_BYTES[7];
+    }
+
+    // Geometry type enumeration
   public enum GeometryType {
     UNKNOWN(0),
     POINT(1),
@@ -122,110 +132,10 @@ public class FlatGeoBuf {
     public Header {
       indexNodeSize = indexNodeSize == 0 ? 16 : indexNodeSize;
     }
-
-    public record Feature(
-        Geometry geometry,
-        List<Object> properties) {
-    }
-  }
-
-  public static Header 
asHeaderRecord(org.apache.baremaps.flatgeobuf.generated.Header header) {
-    return new Header(
-        header.name(),
-        new double[] {
-            header.envelope(0),
-            header.envelope(1),
-            header.envelope(2),
-            header.envelope(3)
-        },
-        GeometryType.values()[header.geometryType()],
-        header.hasZ(),
-        header.hasM(),
-        header.hasT(),
-        header.hasTm(),
-        IntStream.range(0, header.columnsLength())
-            .mapToObj(header::columns)
-            .map(column -> new Column(
-                column.name(),
-                ColumnType.values()[column.type()],
-                column.title(),
-                column.description(),
-                column.width(),
-                column.precision(),
-                column.scale(),
-                column.nullable(),
-                column.unique(),
-                column.primaryKey(),
-                column.metadata()))
-            .toList(),
-        header.featuresCount(),
-        header.indexNodeSize(),
-        new Crs(
-            header.crs().org(),
-            header.crs().code(),
-            header.crs().name(),
-            header.crs().description(),
-            header.crs().wkt(),
-            header.crs().codeString()),
-        header.title(),
-        header.description(),
-        header.metadata());
-  }
-
-  public static Feature 
asFeatureRecord(org.apache.baremaps.flatgeobuf.generated.Header header,
-      org.apache.baremaps.flatgeobuf.generated.Feature feature) {
-    var values = new ArrayList<>();
-    if (feature.propertiesLength() > 0) {
-      var propertiesBuffer = feature.propertiesAsByteBuffer();
-      while (propertiesBuffer.hasRemaining()) {
-        var columnPosition = propertiesBuffer.getShort();
-        var columnType = header.columns(columnPosition);
-        var columnValue = readValue(propertiesBuffer, columnType);
-        values.add(columnValue);
-      }
-    }
-    return new Feature(
-        GeometryConversions.readGeometry(feature.geometry(), 
header.geometryType()),
-        values);
-  }
-
-  private static Object readValue(ByteBuffer buffer,
-      org.apache.baremaps.flatgeobuf.generated.Column column) {
-    return switch (ColumnType.values()[column.type()]) {
-      case BYTE -> buffer.get();
-      case UBYTE -> buffer.get();
-      case BOOL -> buffer.get() == 1;
-      case SHORT -> buffer.getShort();
-      case USHORT -> buffer.getShort();
-      case INT -> buffer.getInt();
-      case UINT -> buffer.getInt();
-      case LONG -> buffer.getLong();
-      case ULONG -> buffer.getLong();
-      case FLOAT -> buffer.getFloat();
-      case DOUBLE -> buffer.getDouble();
-      case STRING -> readString(buffer);
-      case JSON -> readJson(buffer);
-      case DATETIME -> readDateTime(buffer);
-      case BINARY -> readBinary(buffer);
-    };
-  }
-
-  private static Object readString(ByteBuffer buffer) {
-    var length = buffer.getInt();
-    var bytes = new byte[length];
-    buffer.get(bytes);
-    return new String(bytes, StandardCharsets.UTF_8);
-  }
-
-  private static Object readJson(ByteBuffer buffer) {
-    throw new UnsupportedOperationException();
-  }
-
-  private static Object readDateTime(ByteBuffer buffer) {
-    throw new UnsupportedOperationException();
   }
 
-  private static Object readBinary(ByteBuffer buffer) {
-    throw new UnsupportedOperationException();
+  public record Feature(
+      Geometry geometry,
+      List<Object> properties) {
   }
 }
diff --git 
a/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBuf.java
 
b/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBufMapper.java
similarity index 60%
copy from 
baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBuf.java
copy to 
baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBufMapper.java
index 0a07db14..81165398 100644
--- 
a/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBuf.java
+++ 
b/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBufMapper.java
@@ -14,123 +14,67 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.baremaps.flatgeobuf;
 
+import com.google.flatbuffers.FlatBufferBuilder;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
-import java.util.List;
 import java.util.stream.IntStream;
-import org.apache.baremaps.flatgeobuf.FlatGeoBuf.Header.Feature;
-import org.locationtech.jts.geom.Geometry;
+import org.apache.baremaps.flatgeobuf.generated.Column;
+import org.apache.baremaps.flatgeobuf.generated.Feature;
+import org.apache.baremaps.flatgeobuf.generated.Header;
 
-public class FlatGeoBuf {
+public class FlatGeoBufMapper {
 
-  private FlatGeoBuf() {
+  private FlatGeoBufMapper() {
     // Prevent instantiation
   }
 
-  // Geometry type enumeration
-  public enum GeometryType {
-    UNKNOWN(0),
-    POINT(1),
-    LINESTRING(2),
-    POLYGON(3),
-    MULTIPOINT(4),
-    MULTILINESTRING(5),
-    MULTIPOLYGON(6),
-    GEOMETRYCOLLECTION(7),
-    CIRCULARSTRING(8),
-    COMPOUNDCURVE(9),
-    CURVEPOLYGON(10),
-    MULTICURVE(11),
-    MULTISURFACE(12),
-    CURVE(13),
-    SURFACE(14),
-    POLYHEDRALSURFACE(15),
-    TIN(16),
-    TRIANGLE(17);
-
-    private final int value;
-
-    GeometryType(int value) {
-      this.value = value;
+  public static Header asHeaderFlatGeoBuf(FlatGeoBuf.Header header) {
+    var builder = new FlatBufferBuilder();
+    int[] columnsArray = header.columns().stream().mapToInt(c -> {
+      int nameOffset = builder.createString(c.name());
+      int type = c.type().ordinal();
+      return org.apache.baremaps.flatgeobuf.generated.Column.createColumn(
+          builder, nameOffset, type, 0, 0, c.width(), c.precision(), 
c.scale(), c.nullable(),
+          c.unique(),
+          c.primaryKey(), 0);
+    }).toArray();
+    int columnsOffset =
+        
org.apache.baremaps.flatgeobuf.generated.Header.createColumnsVector(builder, 
columnsArray);
+
+    int nameOffset = 0;
+    if (header.name() != null) {
+      nameOffset = builder.createString(header.name());
     }
-
-    public int getValue() {
-      return value;
-    }
-  }
-
-  public enum ColumnType {
-    BYTE,
-    UBYTE,
-    BOOL,
-    SHORT,
-    USHORT,
-    INT,
-    UINT,
-    LONG,
-    ULONG,
-    FLOAT,
-    DOUBLE,
-    STRING,
-    JSON,
-    DATETIME,
-    BINARY
-  }
-
-  public record Column(
-      String name,
-      ColumnType type,
-      String title,
-      String description,
-      int width,
-      int precision,
-      int scale,
-      boolean nullable,
-      boolean unique,
-      boolean primaryKey,
-      String metadata) {
-  }
-
-  public record Crs(
-      String org,
-      int code,
-      String name,
-      String description,
-      String wkt,
-      String codeString) {
-  }
-
-  public record Header(
-      String name,
-      double[] envelope,
-      GeometryType geometryType,
-      boolean hasZ,
-      boolean hasM,
-      boolean hasT,
-      boolean hasTM,
-      List<Column> columns,
-      long featuresCount,
-      int indexNodeSize,
-      Crs crs,
-      String title,
-      String description,
-      String metadata) {
-    public Header {
-      indexNodeSize = indexNodeSize == 0 ? 16 : indexNodeSize;
+    int crsOffset = 0;
+    if (header.crs().code() != 0) {
+      org.apache.baremaps.flatgeobuf.generated.Crs.startCrs(builder);
+      org.apache.baremaps.flatgeobuf.generated.Crs.addCode(builder, 
header.crs().code());
+      crsOffset = org.apache.baremaps.flatgeobuf.generated.Crs.endCrs(builder);
     }
-
-    public record Feature(
-        Geometry geometry,
-        List<Object> properties) {
+    int envelopeOffset = 0;
+    if (header.envelope() != null) {
+      envelopeOffset = Header.createEnvelopeVector(builder, header.envelope());
     }
+    Header.startHeader(builder);
+    Header.addGeometryType(builder, header.geometryType().getValue());
+    Header.addIndexNodeSize(builder, header.indexNodeSize());
+    Header.addColumns(builder, columnsOffset);
+    Header.addEnvelope(builder, envelopeOffset);
+    Header.addName(builder, nameOffset);
+    Header.addCrs(builder, crsOffset);
+    Header.addFeaturesCount(builder, header.featuresCount());
+    int offset = Header.endHeader(builder);
+
+    builder.finishSizePrefixed(offset);
+
+    return Header.getRootAsHeader(builder.dataBuffer());
   }
 
-  public static Header 
asHeaderRecord(org.apache.baremaps.flatgeobuf.generated.Header header) {
-    return new Header(
+  public static FlatGeoBuf.Header asHeaderRecord(Header header) {
+    return new FlatGeoBuf.Header(
         header.name(),
         new double[] {
             header.envelope(0),
@@ -138,16 +82,16 @@ public class FlatGeoBuf {
             header.envelope(2),
             header.envelope(3)
         },
-        GeometryType.values()[header.geometryType()],
+        FlatGeoBuf.GeometryType.values()[header.geometryType()],
         header.hasZ(),
         header.hasM(),
         header.hasT(),
         header.hasTm(),
         IntStream.range(0, header.columnsLength())
             .mapToObj(header::columns)
-            .map(column -> new Column(
+            .map(column -> new FlatGeoBuf.Column(
                 column.name(),
-                ColumnType.values()[column.type()],
+                FlatGeoBuf.ColumnType.values()[column.type()],
                 column.title(),
                 column.description(),
                 column.width(),
@@ -160,7 +104,7 @@ public class FlatGeoBuf {
             .toList(),
         header.featuresCount(),
         header.indexNodeSize(),
-        new Crs(
+        new FlatGeoBuf.Crs(
             header.crs().org(),
             header.crs().code(),
             header.crs().name(),
@@ -172,8 +116,7 @@ public class FlatGeoBuf {
         header.metadata());
   }
 
-  public static Feature 
asFeatureRecord(org.apache.baremaps.flatgeobuf.generated.Header header,
-      org.apache.baremaps.flatgeobuf.generated.Feature feature) {
+  public static FlatGeoBuf.Feature asFeatureRecord(Header header, Feature 
feature) {
     var values = new ArrayList<>();
     if (feature.propertiesLength() > 0) {
       var propertiesBuffer = feature.propertiesAsByteBuffer();
@@ -184,14 +127,14 @@ public class FlatGeoBuf {
         values.add(columnValue);
       }
     }
-    return new Feature(
+    return new FlatGeoBuf.Feature(
         GeometryConversions.readGeometry(feature.geometry(), 
header.geometryType()),
         values);
   }
 
   private static Object readValue(ByteBuffer buffer,
-      org.apache.baremaps.flatgeobuf.generated.Column column) {
-    return switch (ColumnType.values()[column.type()]) {
+      Column column) {
+    return switch (FlatGeoBuf.ColumnType.values()[column.type()]) {
       case BYTE -> buffer.get();
       case UBYTE -> buffer.get();
       case BOOL -> buffer.get() == 1;
diff --git 
a/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBufReader.java
 
b/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBufReader.java
index f59b9397..2b62cf3f 100644
--- 
a/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBufReader.java
+++ 
b/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/FlatGeoBufReader.java
@@ -19,6 +19,7 @@ package org.apache.baremaps.flatgeobuf;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.channels.Channels;
@@ -34,7 +35,7 @@ public class FlatGeoBufReader {
     // Check if the file is a flatgeobuf
     ByteBuffer buffer = BufferUtil.createByteBuffer(12, 
ByteOrder.LITTLE_ENDIAN);
     BufferUtil.readBytes(channel, buffer, 12);
-    if (!Constants.isFlatgeobuf(buffer)) {
+    if (!FlatGeoBuf.isFlatgeobuf(buffer)) {
       throw new IOException("This is not a flatgeobuf!");
     }
 
@@ -54,7 +55,6 @@ public class FlatGeoBufReader {
   public static ByteBuffer readIndexAsBuffer(ReadableByteChannel channel, 
Header header)
       throws IOException {
     long indexSize = PackedRTree.calcSize(header.featuresCount(), 
header.indexNodeSize());
-
     if (indexSize > 1L << 31) {
       throw new IOException("Index size is greater than 2GB!");
     }
@@ -71,61 +71,68 @@ public class FlatGeoBufReader {
 
   public static Feature readFeature(ReadableByteChannel channel, ByteBuffer 
buffer)
       throws IOException {
-    ByteBuffer newBuffer = BufferUtil.readBytes(channel, buffer, 4);
-    int featureSize = newBuffer.getInt();
-    newBuffer = BufferUtil.readBytes(channel, buffer, featureSize);
-    Feature feature = Feature.getRootAsFeature(newBuffer);
-    buffer.position(buffer.position() + featureSize);
-    return feature;
+    try {
+      ByteBuffer newBuffer = BufferUtil.readBytes(channel, buffer, 4);
+      int featureSize = newBuffer.getInt();
+      newBuffer = BufferUtil.readBytes(channel, buffer, featureSize);
+      Feature feature = Feature.getRootAsFeature(newBuffer);
+      buffer.position(buffer.position() + featureSize);
+      return feature;
+    } catch (IOException | BufferUnderflowException e) {
+      throw new IOException("Error reading feature", e);
+    }
   }
 
-  // var geometryBuffer = feature.geometry();
-  // var geometry = GeometryConversions.readGeometry(geometryBuffer, 
geometryBuffer.type());
-  // var properties = new ArrayList<>();
-  // if (feature.propertiesLength() > 0) {
-  // var propertiesBuffer = feature.propertiesAsByteBuffer();
-  // while (propertiesBuffer.hasRemaining()) {
-  // var type = propertiesBuffer.getShort();
-  // var column = header.columns.get(type);
-  // var value = readColumnValue(propertiesBuffer, column);
-  // properties.add(value);
-  // }
-  // }
-  // }
-  //
-  // public static Object readColumnValue(ByteBuffer buffer, ColumnMeta 
column) {
-  // return switch (column.type()) {
-  // case ColumnType.Byte -> buffer.get();
-  // case ColumnType.Bool -> buffer.get() == 1;
-  // case ColumnType.Short -> buffer.getShort();
-  // case ColumnType.Int -> buffer.getInt();
-  // case ColumnType.Long -> buffer.getLong();
-  // case ColumnType.Float -> buffer.getFloat();
-  // case ColumnType.Double -> buffer.getDouble();
-  // case ColumnType.String -> readColumnString(buffer);
-  // case ColumnType.Json -> readColumnJson(buffer);
-  // case ColumnType.DateTime -> readColumnDateTime(buffer);
-  // case ColumnType.Binary -> readColumnBinary(buffer);
-  // default -> null;
-  // };
-  // }
-  //
-  // public static Object readColumnString(ByteBuffer buffer) {
-  // var length = buffer.getInt();
-  // var bytes = new byte[length];
-  // buffer.get(bytes);
-  // return new String(bytes, StandardCharsets.UTF_8);
-  // }
-  //
-  // public static Object readColumnJson(ByteBuffer buffer) {
-  // throw new UnsupportedOperationException();
-  // }
-  //
-  // public static Object readColumnDateTime(ByteBuffer buffer) {
-  // throw new UnsupportedOperationException();
-  // }
-  //
-  // public static Object readColumnBinary(ByteBuffer buffer) {
-  // throw new UnsupportedOperationException();
-  // }
+  private static class BoundedInputStream extends InputStream {
+    private final InputStream in;
+    private long remaining;
+
+    private BoundedInputStream(InputStream in, long size) {
+      this.in = in;
+      this.remaining = size;
+    }
+
+    @Override
+    public int read() throws IOException {
+      if (remaining == 0) {
+        return -1;
+      }
+      int result = in.read();
+      if (result != -1) {
+        remaining--;
+      }
+      return result;
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+      if (remaining == 0) {
+        return -1;
+      }
+      int toRead = (int) Math.min(len, remaining);
+      int result = in.read(b, off, toRead);
+      if (result != -1) {
+        remaining -= result;
+      }
+      return result;
+    }
+
+    @Override
+    public long skip(long n) throws IOException {
+      long toSkip = Math.min(n, remaining);
+      long skipped = in.skip(toSkip);
+      remaining -= skipped;
+      return skipped;
+    }
+
+    @Override
+    public int available() throws IOException {
+      return (int) Math.min(in.available(), remaining);
+    }
+
+    @Override
+    public void close() throws IOException {
+      in.close();
+    }
+  }
 }
diff --git 
a/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/GeometryConversions.java
 
b/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/GeometryConversions.java
index 359b9e79..7d6efeab 100644
--- 
a/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/GeometryConversions.java
+++ 
b/baremaps-flatgeobuf/src/main/java/org/apache/baremaps/flatgeobuf/GeometryConversions.java
@@ -31,7 +31,7 @@ public class GeometryConversions {
   public static GeometryOffsets writeGeometryPart(
       FlatBufferBuilder builder,
       org.locationtech.jts.geom.Geometry geometry,
-      int geometryType) throws IOException {
+      int geometryType) {
 
     GeometryOffsets go = new GeometryOffsets();
 
diff --git 
a/baremaps-flatgeobuf/src/test/java/org/apache/baremaps/flatgeobuf/FlatGeoBufTest.java
 
b/baremaps-flatgeobuf/src/test/java/org/apache/baremaps/flatgeobuf/FlatGeoBufTest.java
index 03401dd5..cbcb949d 100644
--- 
a/baremaps-flatgeobuf/src/test/java/org/apache/baremaps/flatgeobuf/FlatGeoBufTest.java
+++ 
b/baremaps-flatgeobuf/src/test/java/org/apache/baremaps/flatgeobuf/FlatGeoBufTest.java
@@ -17,14 +17,15 @@
 
 package org.apache.baremaps.flatgeobuf;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.*;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.channels.FileChannel;
 import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.List;
 import org.apache.baremaps.flatgeobuf.generated.Feature;
 import org.apache.baremaps.flatgeobuf.generated.Header;
 import org.apache.baremaps.testing.TestFiles;
@@ -52,25 +53,42 @@ public class FlatGeoBufTest {
       assertNotNull(header);
       assertEquals(179, header.featuresCount());
 
+      FlatGeoBuf.Header headerRecord = FlatGeoBufMapper.asHeaderRecord(header);
+      assertNotNull(headerRecord);
+      assertEquals(179, headerRecord.featuresCount());
+
       // Read the index
       FlatGeoBufReader.skipIndex(channel, header);
 
       // Read the first feature
       ByteBuffer buffer = BufferUtil.createByteBuffer(1 << 16, 
ByteOrder.LITTLE_ENDIAN);
+      List<FlatGeoBuf.Feature> featureList = new ArrayList<>();
       for (int i = 0; i < header.featuresCount(); i++) {
         Feature feature = FlatGeoBufReader.readFeature(channel, buffer);
-
-        System.out.println(FlatGeoBuf.asFeatureRecord(header, feature));
-
+        featureList.add(FlatGeoBufMapper.asFeatureRecord(header, feature));
         assertNotNull(feature);
       }
-    }
-  }
 
+      // Check the first feature
+      FlatGeoBuf.Feature firstFeature = featureList.get(0);
+      assertNotNull(firstFeature);
+      assertEquals(2, firstFeature.properties().size());
+      assertEquals("ATA", firstFeature.properties().get(0));
+      assertEquals("Antarctica", firstFeature.properties().get(1));
+      assertNotNull(firstFeature.geometry());
+      assertEquals(658, firstFeature.geometry().getNumPoints());
+
+      // Check the last feature
+      FlatGeoBuf.Feature lastFeature = featureList.get(178);
+      assertNotNull(lastFeature);
+      assertEquals(2, lastFeature.properties().size());
+      assertEquals("FLK", lastFeature.properties().get(0));
+      assertEquals("Falkland Islands", lastFeature.properties().get(1));
+      assertNotNull(lastFeature.geometry());
+      assertEquals(10, lastFeature.geometry().getNumPoints());
 
-  public static void main(String... args) {
-    System.out.println(Long.MAX_VALUE);
-    System.out.println(Long.MAX_VALUE >> 32);
+      assertThrows(IOException.class, () -> 
FlatGeoBufReader.readFeature(channel, buffer));
+    }
   }
 
 }

Reply via email to