Author: tilman Date: Fri Apr 25 14:19:40 2025 New Revision: 1925264 URL: http://svn.apache.org/viewvc?rev=1925264&view=rev Log: PDFBOX-5965: combine LAST and CURRENT buffers into new LAST buffer content to avoid ArrayIndexOutOfBoundsException
Modified: pdfbox/branches/3.0/io/src/main/java/org/apache/pdfbox/io/NonSeekableRandomAccessReadInputStream.java pdfbox/branches/3.0/io/src/test/java/org/apache/pdfbox/io/NonSeekableRandomAccessReadInputStreamTest.java Modified: pdfbox/branches/3.0/io/src/main/java/org/apache/pdfbox/io/NonSeekableRandomAccessReadInputStream.java URL: http://svn.apache.org/viewvc/pdfbox/branches/3.0/io/src/main/java/org/apache/pdfbox/io/NonSeekableRandomAccessReadInputStream.java?rev=1925264&r1=1925263&r2=1925264&view=diff ============================================================================== --- pdfbox/branches/3.0/io/src/main/java/org/apache/pdfbox/io/NonSeekableRandomAccessReadInputStream.java (original) +++ pdfbox/branches/3.0/io/src/main/java/org/apache/pdfbox/io/NonSeekableRandomAccessReadInputStream.java Fri Apr 25 14:19:40 2025 @@ -190,7 +190,21 @@ public class NonSeekableRandomAccessRead { // move the current data to last to support rewind operations // right after refilling the current buffer - switchBuffers(CURRENT, LAST); + if (bufferBytes[LAST] == BUFFER_SIZE && bufferBytes[CURRENT] > 0 && bufferBytes[CURRENT] < BUFFER_SIZE) + { + // Likely EOF, we're risking losing the previous (full) buffer and get an AIOOB + // Create a new LAST buffer that combines as much as possible of CURRENT and LAST into a new LAST. + byte[] newBuffer = new byte[BUFFER_SIZE]; + System.arraycopy(buffers[LAST], bufferBytes[CURRENT], newBuffer, 0, BUFFER_SIZE - bufferBytes[CURRENT]); + System.arraycopy(buffers[CURRENT], 0, newBuffer, BUFFER_SIZE - bufferBytes[CURRENT], bufferBytes[CURRENT]); + switchBuffers(CURRENT, LAST); + buffers[LAST] = newBuffer; + bufferBytes[LAST] = BUFFER_SIZE; + } + else + { + switchBuffers(CURRENT, LAST); + } bufferBytes[CURRENT] = is.read(buffers[CURRENT]); if (bufferBytes[CURRENT] <= 0) { Modified: pdfbox/branches/3.0/io/src/test/java/org/apache/pdfbox/io/NonSeekableRandomAccessReadInputStreamTest.java URL: http://svn.apache.org/viewvc/pdfbox/branches/3.0/io/src/test/java/org/apache/pdfbox/io/NonSeekableRandomAccessReadInputStreamTest.java?rev=1925264&r1=1925263&r2=1925264&view=diff ============================================================================== --- pdfbox/branches/3.0/io/src/test/java/org/apache/pdfbox/io/NonSeekableRandomAccessReadInputStreamTest.java (original) +++ pdfbox/branches/3.0/io/src/test/java/org/apache/pdfbox/io/NonSeekableRandomAccessReadInputStreamTest.java Fri Apr 25 14:19:40 2025 @@ -221,6 +221,29 @@ class NonSeekableRandomAccessReadInputSt } } + @Test + void testRewindAcrossBuffers() throws IOException + { + byte[] ba = new byte[4096 + 5]; + int rewSize = 7; + byte testVal = 123; + ba[ba.length - rewSize] = testVal; + ByteArrayInputStream bais = new ByteArrayInputStream(ba); + try (RandomAccessRead rar = new NonSeekableRandomAccessReadInputStream(bais)) + { + int len = rar.read(new byte[ba.length - rewSize]); + assertEquals(ba.length - rewSize, len); + len = rar.read(new byte[rewSize]); + assertEquals(rewSize, len); + int by = rar.read(); + assertEquals(-1, by); + assertTrue(rar.isEOF()); + rar.rewind(len); + by = rar.read(); // went ArrayIndexOutOfBoundsException here + assertEquals(testVal, by); + } + } + private byte[] createRandomData() { final long seed = new Random().nextLong();