From 3573e5c44fbd48bc518baaeb7a04f08ee04312e3 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sat, 12 Mar 2022 13:57:50 +0000 Subject: [PATCH] handle case where toByteArray truncates stream because max len is less than stream len git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1898876 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/poi/util/IOUtils.java | 27 +++++++++----- .../java/org/apache/poi/util/TestIOUtils.java | 37 ++++++++++++++++++- 2 files changed, 53 insertions(+), 11 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 7e1fef8990..cf40645138 100644 --- a/poi/src/main/java/org/apache/poi/util/IOUtils.java +++ b/poi/src/main/java/org/apache/poi/util/IOUtils.java @@ -230,7 +230,7 @@ public final class IOUtils { checkLength(length, derivedMaxLength); } - final int derivedLen = Math.min(length, derivedMaxLength); + final int derivedLen = isLengthKnown ? Math.min(length, derivedMaxLength) : derivedMaxLength; final int byteArrayInitLen = calculateByteArrayInitLength(isLengthKnown, length, derivedMaxLength); final int internalBufferLen = DEFAULT_BUFFER_SIZE; try (UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream(byteArrayInitLen)) { @@ -242,18 +242,15 @@ public final class IOUtils { if (readBytes > 0) { baos.write(buffer, 0, readBytes); } - checkByteSizeLimit(totalBytes); } while (totalBytes < derivedLen && readBytes > -1); - if (checkEOFException) { - if (derivedMaxLength != Integer.MAX_VALUE && totalBytes == derivedMaxLength) { - throw new IOException("MaxLength (" + derivedMaxLength + ") reached - stream seems to be invalid."); - } + if (BYTE_ARRAY_MAX_OVERRIDE < 0 && readBytes > -1 && !isLengthKnown && stream.read() >= 0) { + throwRecordTruncationException(derivedMaxLength); + } - if (derivedLen != Integer.MAX_VALUE && totalBytes < derivedLen) { - throw new EOFException("unexpected EOF - expected len: " + derivedLen + " - actual len: " + totalBytes); - } + if (checkEOFException && derivedLen != Integer.MAX_VALUE && totalBytes < derivedLen) { + throw new EOFException("unexpected EOF - expected len: " + derivedLen + " - actual len: " + totalBytes); } return baos.toByteArray(); @@ -586,7 +583,7 @@ public final class IOUtils { * Simple utility function to check that you haven't hit EOF * when reading a byte. * - * @param is inputstream to read + * @param is input stream to read * @return byte read, unless * @throws IOException on IOException or EOF if -1 is read */ @@ -608,4 +605,14 @@ public final class IOUtils { length, maxLength)); } + + private static void throwRecordTruncationException(final int maxLength) { + throw new RecordFormatException(String.format(Locale.ROOT, "Tried to read data but the maximum length " + + "for this record type is %,d.\n" + + "If the file is not corrupt or large, please open an issue on bugzilla to request \n" + + "increasing the maximum allowable size for this record type.\n"+ + "As a temporary workaround, consider setting a higher override value with " + + "IOUtils.setByteArrayMaxOverride()", maxLength)); + + } } 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 1f55e980f6..cb335921cb 100644 --- a/poi/src/test/java/org/apache/poi/util/TestIOUtils.java +++ b/poi/src/test/java/org/apache/poi/util/TestIOUtils.java @@ -151,6 +151,30 @@ final class TestIOUtils { } } + @Test + void testToByteArrayMaxLengthWithByteArrayInitLenShort() throws IOException { + final byte[] array = new byte[]{1, 2, 3, 4, 5, 6, 7}; + IOUtils.setMaxByteArrayInitSize(2); + try (ByteArrayInputStream is = new ByteArrayInputStream(array)) { + assertEquals(2, IOUtils.getMaxByteArrayInitSize()); + assertArrayEquals(array, IOUtils.toByteArrayWithMaxLength(is, 7)); + } finally { + IOUtils.setMaxByteArrayInitSize(-1); + } + } + + @Test + void testToByteArrayMaxLengthWithByteArrayInitLenLong() throws IOException { + final byte[] array = new byte[]{1, 2, 3, 4, 5, 6, 7}; + IOUtils.setMaxByteArrayInitSize(8192); + try (ByteArrayInputStream is = new ByteArrayInputStream(array)) { + assertEquals(8192, IOUtils.getMaxByteArrayInitSize()); + assertArrayEquals(array, IOUtils.toByteArrayWithMaxLength(is, 7)); + } finally { + IOUtils.setMaxByteArrayInitSize(-1); + } + } + @Test void testToByteArrayMaxLengthLongerThanArray() throws IOException { final byte[] array = new byte[]{1, 2, 3, 4, 5, 6, 7}; @@ -163,7 +187,18 @@ final class TestIOUtils { void testToByteArrayMaxLengthShorterThanArray() throws IOException { final byte[] array = new byte[]{1, 2, 3, 4, 5, 6, 7}; try (ByteArrayInputStream is = new ByteArrayInputStream(array)) { - assertArrayEquals(new byte[]{1, 2, 3}, IOUtils.toByteArrayWithMaxLength(is, 3)); + assertThrows(RecordFormatException.class, () -> IOUtils.toByteArrayWithMaxLength(is, 3)); + } + } + + @Test + void testToByteArrayMaxLengthShorterThanArrayWithByteArrayOverride() throws IOException { + final byte[] array = new byte[]{1, 2, 3, 4, 5, 6, 7}; + IOUtils.setByteArrayMaxOverride(30 * 1024 * 1024); + try (ByteArrayInputStream is = new ByteArrayInputStream(array)) { + assertArrayEquals(array, IOUtils.toByteArrayWithMaxLength(is, 3)); + } finally { + IOUtils.setByteArrayMaxOverride(-1); } } -- 2.39.5