This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit c14f9c667295ff317fdfb8d10b70a809a2888372 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Thu Jan 6 04:53:31 2022 +0100 Provide a safer alternative to the possibly infinite loops over `Markable.reset()`. --- .../sis/internal/storage/io/ChannelData.java | 26 ++++++++++++++++++++-- .../internal/storage/io/InputStreamAdapter.java | 26 +++++++++++++++++++++- .../apache/sis/internal/storage/io/Markable.java | 12 +++++++++- .../internal/storage/io/OutputStreamAdapter.java | 15 +++++++++++-- .../org/apache/sis/storage/DataStoreProvider.java | 3 +-- .../internal/storage/xml/stream/StaxDataStore.java | 14 ++++-------- 6 files changed, 78 insertions(+), 18 deletions(-) diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelData.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelData.java index 36a1caf..adab367 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelData.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelData.java @@ -32,8 +32,8 @@ import static org.apache.sis.util.ArgumentChecks.ensureBetween; * querying or modifying the stream position. This class does not define any read or write operations. * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 - * @since 0.5 (derived from 0.3) + * @version 1.2 + * @since 0.3 * @module */ public abstract class ChannelData implements Markable { @@ -332,6 +332,28 @@ public abstract class ChannelData implements Markable { } /** + * Moves to the given position in the stream and discards all marks at or after that position. + * If a mark exists at the given position, the bit offset is also restored. + * + * @param position position where to seek. + * @throws IOException if this stream can not move to the specified mark position. + */ + @Override + public final void reset(final long position) throws IOException { + Mark lastValid = null; + while (mark != null && mark.position >= position) { + final boolean found = mark.position == position; + if (found) lastValid = mark; + mark = mark.next; // Discard all marks after the specified position. + if (found) break; + } + seek(position); + if (lastValid != null) { + setBitOffset(lastValid.bitOffset); + } + } + + /** * Invoked when an operation between the channel and the buffer transferred no byte. Note that this is unrelated * to end-of-file, in which case {@link java.nio.channels.ReadableByteChannel#read(ByteBuffer)} returns -1. * A return value of 0 happen for example if the channel is a socket in non-blocking mode and the socket buffer diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/InputStreamAdapter.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/InputStreamAdapter.java index 76ee111..c9fd626 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/InputStreamAdapter.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/InputStreamAdapter.java @@ -20,6 +20,7 @@ import java.io.InputStream; import java.io.IOException; import java.io.UncheckedIOException; import javax.imageio.stream.ImageInputStream; +import org.apache.sis.io.InvalidSeekException; import org.apache.sis.internal.storage.Resources; @@ -181,7 +182,7 @@ public final class InputStreamAdapter extends InputStream implements Markable { * were created by {@link #mark()} or {@link #mark(int)}, except that all marks created by * {@link #mark(int)} are ignored except the most recent one. * - * <p>Implementations of {@code reset()} if Java I/O package does not discard the mark. + * <p>Implementations of {@code reset()} in Java I/O package does not discard the mark. * The implementation in this {@code InputStreamAdapter} class does not discard the mark * neither if the mark done by a call to {@link #mark(int)} is the only mark remaining. * Some code depends on the ability to do many {@code reset()} for the same mark.</p> @@ -204,6 +205,29 @@ public final class InputStreamAdapter extends InputStream implements Markable { } /** + * Moves to the given position in the stream and discards all marks at or after that position. + * This convolved method exists because of the attempt to conciliate two different APIs in this class + * (see {@link #reset()}). This method does not simply call {@link ImageInputStream#seek(long)} + * because we need to keep track of the marks. + * + * @param mark position where to seek. + * @throws IOException if this stream can not move to the specified mark position. + */ + @Override + public synchronized void reset(final long mark) throws IOException { + long p; + int n; + do { + n = nestedMarks; + reset(); + p = input.getStreamPosition(); + } while (p > mark && n > 0); + if (p != mark) { + throw new InvalidSeekException(); + } + } + + /** * Returns the current byte position of the stream. * * @return the position of the stream. diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/Markable.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/Markable.java index 044df5d..2d90ee0 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/Markable.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/Markable.java @@ -35,7 +35,7 @@ import java.io.IOException; * </div> * * @author Martin Desruisseaux (Geomatys) - * @version 0.8 + * @version 1.2 * * @see Readable * @@ -82,4 +82,14 @@ public interface Markable { * @see org.apache.sis.io.InvalidSeekException */ void reset() throws IOException; + + /** + * Resets the stream position to the mark at the given position. Invoking this method is similar to + * invoking {@code seek(mark)} except that it may work on non-seekable stream if a mark has been set + * on that position. + * + * @param mark position where to seek. Should be a position where a mark has been created. + * @throws IOException if this stream can not move to the specified mark position. + */ + void reset(long mark) throws IOException; } diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/OutputStreamAdapter.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/OutputStreamAdapter.java index 5942685..d58b138 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/OutputStreamAdapter.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/OutputStreamAdapter.java @@ -24,7 +24,7 @@ import java.io.IOException; * Wraps a {@link ChannelDataOutput} as a standard {@link OutputStream}. * * @author Martin Desruisseaux (Geomatys) - * @version 0.8 + * @version 1.2 * * @see InputStreamAdapter * @@ -95,7 +95,7 @@ final class OutputStreamAdapter extends OutputStream implements Markable { } /** - * Repositions this stream to the position at the time the {@code mark} method was last called. + * Resets this stream to the position at the time the {@code mark} method was last called. * * @throws IOException if this stream can not move to the last mark position. */ @@ -105,6 +105,17 @@ final class OutputStreamAdapter extends OutputStream implements Markable { } /** + * Moves to the given position in the stream and discards all marks at or after that position. + * + * @param mark position where to seek. + * @throws IOException if this stream can not move to the specified mark position. + */ + @Override + public void reset(final long mark) throws IOException { + output.reset(mark); + } + + /** * Returns the current byte position of the stream. * * @return the position of the stream. diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java index 02bdeb3..fb6bab3 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java @@ -379,8 +379,7 @@ public abstract class DataStoreProvider { final long position = stream.getStreamPosition(); stream.mark(); result = prober.test(input); - do stream.reset(); - while (stream.getStreamPosition() != position); + stream.reset(position); } else if (input instanceof ImageInputStream) { /* * `ImageInputStream` supports an arbitrary number of marks as well, diff --git a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxDataStore.java b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxDataStore.java index 2a7b7ac..4c2295c 100644 --- a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxDataStore.java +++ b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxDataStore.java @@ -268,16 +268,10 @@ public abstract class StaxDataStore extends URIDataStore { private boolean reset() throws IOException { if (streamPosition >= 0) try { final Markable m = (Markable) stream; - long p; - do { - m.reset(); - p = m.getStreamPosition(); - } while (p > streamPosition); - if (p == streamPosition) { - m.mark(); - state = START; - return true; - } + m.reset(streamPosition); + m.mark(); + state = START; + return true; } catch (InvalidSeekException e) { listeners.warning(e); }