From aad5901d92893b95d867b3d3397a378f79316f0d Mon Sep 17 00:00:00 2001 From: Kristin Cowalcijk Date: Fri, 14 Jul 2023 13:12:46 +0800 Subject: [PATCH] Fix resource leaks in raster constructors RS_FromGeoTiff and RS_FromArcInfoAsciiGrid --- .../common/raster/RasterConstructors.java | 17 ++-- .../ByteArrayImageInputStream.java | 81 +++++++++++++++++++ 2 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 common/src/main/java/org/apache/sedona/common/raster/inputstream/ByteArrayImageInputStream.java diff --git a/common/src/main/java/org/apache/sedona/common/raster/RasterConstructors.java b/common/src/main/java/org/apache/sedona/common/raster/RasterConstructors.java index 245cc0a43e..0a2aab003a 100644 --- a/common/src/main/java/org/apache/sedona/common/raster/RasterConstructors.java +++ b/common/src/main/java/org/apache/sedona/common/raster/RasterConstructors.java @@ -13,6 +13,7 @@ */ package org.apache.sedona.common.raster; +import org.apache.sedona.common.raster.inputstream.ByteArrayImageInputStream; import org.geotools.coverage.CoverageFactoryFinder; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.coverage.grid.GridCoverageFactory; @@ -29,27 +30,20 @@ import org.opengis.referencing.operation.MathTransform; import javax.media.jai.RasterFactory; - import java.awt.image.DataBuffer; import java.awt.image.WritableRaster; -import java.io.ByteArrayInputStream; import java.io.IOException; public class RasterConstructors { - public static GridCoverage2D fromArcInfoAsciiGrid(byte[] bytes) throws IOException { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) { - ArcGridReader reader = new ArcGridReader(inputStream); - return reader.read(null); - } + ArcGridReader reader = new ArcGridReader(new ByteArrayImageInputStream(bytes)); + return reader.read(null); } public static GridCoverage2D fromGeoTiff(byte[] bytes) throws IOException { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) { - GeoTiffReader geoTiffReader = new GeoTiffReader(inputStream); - return geoTiffReader.read(null); - } + GeoTiffReader geoTiffReader = new GeoTiffReader(new ByteArrayImageInputStream(bytes)); + return geoTiffReader.read(null); } /** @@ -105,7 +99,6 @@ public static GridCoverage2D makeEmptyRaster(int numBand, int widthInPixel, int if (scaleY == Integer.MAX_VALUE) { actualScaleY = scaleX; } - System.out.println("makeEmptyRaster: " + numBand + ", " + widthInPixel + ", " + heightInPixel + ", " + upperLeftX + ", " + upperLeftY + ", " + scaleX + ", " + actualScaleY + ", " + skewX + ", " + skewY + ", " + srid); // Create a new empty raster WritableRaster raster = RasterFactory.createBandedRaster(DataBuffer.TYPE_DOUBLE, widthInPixel, heightInPixel, numBand, null); MathTransform transform = new AffineTransform2D(scaleX, skewY, skewX, -actualScaleY, upperLeftX + scaleX / 2, upperLeftY - actualScaleY / 2); diff --git a/common/src/main/java/org/apache/sedona/common/raster/inputstream/ByteArrayImageInputStream.java b/common/src/main/java/org/apache/sedona/common/raster/inputstream/ByteArrayImageInputStream.java new file mode 100644 index 0000000000..b4171f8b54 --- /dev/null +++ b/common/src/main/java/org/apache/sedona/common/raster/inputstream/ByteArrayImageInputStream.java @@ -0,0 +1,81 @@ +/* + * 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.sedona.common.raster.inputstream; + +import java.io.IOException; +import javax.imageio.stream.ImageInputStreamImpl; + +public class ByteArrayImageInputStream extends ImageInputStreamImpl { + + private final byte[] bytes; + + public ByteArrayImageInputStream(byte[] bytes) { + this.bytes = bytes; + } + + @Override + public int read() throws IOException { + checkClosed(); + bitOffset = 0; + if (streamPos >= bytes.length) { + return -1; + } + byte b = bytes[(int) streamPos++]; + return b & 0xFF; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + checkClosed(); + + if (b == null) { + throw new NullPointerException("b == null!"); + } + if (off < 0 || len < 0 || off + len > b.length || off + len < 0) { + throw new IndexOutOfBoundsException + ("off < 0 || len < 0 || off+len > b.length || off+len < 0!"); + } + + bitOffset = 0; + + if (len == 0) { + return 0; + } + + int remaining = (int) (bytes.length - streamPos); + len = Math.min(len, remaining); + if (len <= 0) { + return -1; + } + + System.arraycopy(bytes, (int) streamPos, b, off, len); + streamPos += len; + return len; + } + + @Override + public boolean isCached() { + return true; + } + + @Override + public boolean isCachedMemory() { + return true; + } +}