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);
         }

Reply via email to