You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by fa...@apache.org on 2026/10/11 12:46:55 UTC

(poi) branch trunk updated: IOUtils.skipFully: size the skip buffer to the skip (#1375)

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

pjfanning pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/poi.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 3f99aeae99 IOUtils.skipFully: size the skip buffer to the skip (#1375)
3f99aeae99 is described below

commit 3f99aeae99219a9a76ddad46fbaa27d79eda5740
Author: PJ Fanning <pj...@users.noreply.github.com>
AuthorDate: Sun Oct 11 13:46:48 2026 +0100

    IOUtils.skipFully: size the skip buffer to the skip (#1375)
    
    Most callers skip a few bytes (padding, short headers) but each call
    allocated a 2 KB buffer.
    
    Co-authored-by: Claude Opus 5.5 <no...@anthropic.com>
---
 poi/src/main/java/org/apache/poi/util/IOUtils.java     |  7 ++++---
 poi/src/test/java/org/apache/poi/util/TestIOUtils.java | 18 ++++++++++++++++++
 2 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/poi/src/main/java/org/apache/poi/util/IOUtils.java b/poi/src/main/java/org/apache/poi/util/IOUtils.java
index cb272f6f41..43873a943e 100644
--- a/poi/src/main/java/org/apache/poi/util/IOUtils.java
+++ b/poi/src/main/java/org/apache/poi/util/IOUtils.java
@@ -690,13 +690,14 @@ public final class IOUtils {
         if (toSkip == 0) {
             return 0L;
         }
-        // use dedicated buffer to avoid having other threads possibly access the bytes in a shared byte array
-        final byte[] skipBuffer = new byte[SKIP_BUFFER_SIZE];
+        // use dedicated buffer to avoid having other threads possibly access the bytes in a shared byte array,
+        // but no larger than needed, as most skips are only a few bytes
+        final byte[] skipBuffer = new byte[(int) Math.min(toSkip, SKIP_BUFFER_SIZE)];
         long remain = toSkip;
         while (remain > 0) {
             // See https://issues.apache.org/jira/browse/IO-203 for why we use read() rather than delegating to skip()
             final long n = input.read(
-                    skipBuffer, 0, Math.toIntExact(Math.min(remain, SKIP_BUFFER_SIZE)));
+                    skipBuffer, 0, Math.toIntExact(Math.min(remain, skipBuffer.length)));
             if (n < 0) { // EOF
                 break;
             }
diff --git a/poi/src/test/java/org/apache/poi/util/TestIOUtils.java b/poi/src/test/java/org/apache/poi/util/TestIOUtils.java
index 3871016387..ab15d1ed21 100644
--- a/poi/src/test/java/org/apache/poi/util/TestIOUtils.java
+++ b/poi/src/test/java/org/apache/poi/util/TestIOUtils.java
@@ -418,6 +418,24 @@ final class TestIOUtils {
         assertEquals(10000, skipped);
     }
 
+    @Test
+    void testSkipFullySmallSkip() throws IOException {
+        int[] maxRequested = {0};
+        InputStream is = new ByteArrayInputStream(new byte[100]) {
+            @Override
+            public synchronized int read(byte[] b, int off, int len) {
+                maxRequested[0] = Math.max(maxRequested[0], len);
+                // the buffer must be big enough for the request
+                assertTrue(off + len <= b.length);
+                return super.read(b, off, len);
+            }
+        };
+        assertEquals(3, IOUtils.skipFully(is, 3));
+        assertEquals(3, maxRequested[0]);
+        assertEquals(97, IOUtils.skipFully(is, 5000));
+        assertEquals(-1, IOUtils.skipFully(is, 1));
+    }
+
     @Test
     void testSetMaxOverride() throws IOException {
         ByteArrayInputStream stream = new ByteArrayInputStream("abc".getBytes(StandardCharsets.UTF_8));


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org