diff options
-rw-r--r-- | build.gradle | 14 | ||||
-rw-r--r-- | build.xml | 20 | ||||
-rw-r--r-- | osgi/pom.xml | 4 | ||||
-rw-r--r-- | poi-ooxml-lite-agent/build.gradle | 4 | ||||
-rw-r--r-- | poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java | 20 | ||||
-rw-r--r-- | poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFCell.java | 10 | ||||
-rw-r--r-- | poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCell.java | 10 | ||||
-rw-r--r-- | poi-ooxml/src/test/java/org/apache/poi/ooxml/TestPOIXMLDocument.java | 3 | ||||
-rw-r--r-- | poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFBugs.java | 67 | ||||
-rw-r--r-- | poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCell.java | 10 | ||||
-rw-r--r-- | poi/src/main/java/org/apache/poi/util/IOUtils.java | 36 | ||||
-rw-r--r-- | poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestCell.java | 5 | ||||
-rw-r--r-- | poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java | 2 | ||||
-rw-r--r-- | poi/src/test/java/org/apache/poi/util/TestIOUtils.java | 21 | ||||
-rw-r--r-- | test-data/document/bug69628.docx | bin | 0 -> 7510 bytes |
15 files changed, 164 insertions, 62 deletions
diff --git a/build.gradle b/build.gradle index 482a717567..1ce6a29e5c 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,7 @@ buildscript { plugins { id 'base' - id 'com.dorongold.task-tree' version '2.1.1' + id 'com.dorongold.task-tree' version '4.0.1' id 'org.nosphere.apache.rat' version '0.8.1' id 'distribution' id "com.github.spotbugs" version '6.0.27' @@ -67,7 +67,7 @@ configurations { } dependencies { - antLibs("org.junit.jupiter:junit-jupiter:5.12.0") + antLibs("org.junit.jupiter:junit-jupiter:5.12.1") antLibs("org.apache.ant:ant-junitlauncher:1.10.15") } @@ -89,7 +89,7 @@ allprojects { // apply plugin: 'eclipse' apply plugin: 'idea' - version = '5.4.1-SNAPSHOT' + version = '5.4.1' } /** @@ -112,13 +112,13 @@ subprojects { commonsCompressVersion = '1.27.1' commonsIoVersion = '2.18.0' commonsMathVersion = '3.6.1' - junitVersion = '5.12.0' + junitVersion = '5.12.1' log4jVersion = '2.24.3' mockitoVersion = '4.11.0' hamcrestVersion = '3.0' xmlbeansVersion = '5.3.0' batikVersion = '1.18' - graphics2dVersion = '3.0.2' + graphics2dVersion = '3.0.3' pdfboxVersion = '3.0.4' saxonVersion = '12.5' xmlSecVersion = '3.0.5' @@ -172,7 +172,7 @@ subprojects { dependencies { testImplementation "org.junit.jupiter:junit-jupiter:${junitVersion}" - testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.12.0' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.12.1' testImplementation "org.mockito:mockito-core:${mockitoVersion}" testImplementation "org.hamcrest:hamcrest:${hamcrestVersion}" testImplementation "org.apache.logging.log4j:log4j-core:${log4jVersion}" @@ -422,7 +422,7 @@ subprojects { jvmArgs += [ // see https://github.com/java9-modularity/gradle-modules-plugin/issues/97 // opposed to the recommendation there, it doesn't work to add ... to the dependencies - // testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.12.0' + // testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.12.1' // gradles gradle-worker.jar is still not a JPMS module and thus runs as unnamed module '--add-exports','org.junit.platform.commons/org.junit.platform.commons.util=org.apache.poi.poi', '--add-exports','org.junit.platform.commons/org.junit.platform.commons.util=ALL-UNNAMED', @@ -42,7 +42,7 @@ under the License. <description>The Apache POI project Ant build.</description> - <property name="version.id" value="5.4.1-SNAPSHOT"/> + <property name="version.id" value="5.4.1"/> <property name="release.rc" value=""/> <property environment="env"/> @@ -270,14 +270,14 @@ under the License. <dependency prefix="main.com.zaxxer" artifact="com.zaxxer:SparseBitSet:1.3" usage="main"/> <dependency prefix="main.log4j-api" artifact="org.apache.logging.log4j:log4j-api:2.24.3" usage="main"/> - <dependency prefix="main.junit-api" artifact="org.junit.jupiter:junit-jupiter-api:5.12.0" usage="main-tests"/> - <dependency prefix="main.junit-jengine" artifact="org.junit.jupiter:junit-jupiter-engine:5.12.0" usage="main-tests"/> - <dependency prefix="main.junit-params" artifact="org.junit.jupiter:junit-jupiter-params:5.12.0" usage="main-tests"/> + <dependency prefix="main.junit-api" artifact="org.junit.jupiter:junit-jupiter-api:5.12.1" usage="main-tests"/> + <dependency prefix="main.junit-jengine" artifact="org.junit.jupiter:junit-jupiter-engine:5.12.1" usage="main-tests"/> + <dependency prefix="main.junit-params" artifact="org.junit.jupiter:junit-jupiter-params:5.12.1" usage="main-tests"/> <dependency prefix="main.junit-opentest4j" artifact="org.opentest4j:opentest4j:1.2.0" usage="main-tests"/> <dependency prefix="main.junit-apiguardian" artifact="org.apiguardian:apiguardian-api:1.1.2" usage="main-tests"/> - <dependency prefix="main.junit-pcommons" artifact="org.junit.platform:junit-platform-commons:1.12.0" usage="main-tests"/> - <dependency prefix="main.junit-pengine" artifact="org.junit.platform:junit-platform-engine:1.12.0" usage="main-tests"/> - <dependency prefix="main.junit-plauncher" artifact="org.junit.platform:junit-platform-launcher:1.12.0" usage="main-tests"/> + <dependency prefix="main.junit-pcommons" artifact="org.junit.platform:junit-platform-commons:1.12.1" usage="main-tests"/> + <dependency prefix="main.junit-pengine" artifact="org.junit.platform:junit-platform-engine:1.12.1" usage="main-tests"/> + <dependency prefix="main.junit-plauncher" artifact="org.junit.platform:junit-platform-launcher:1.12.1" usage="main-tests"/> <dependency prefix="main.jmh" artifact="org.openjdk.jmh:jmh-core:1.35" usage="main-tests"/> @@ -285,8 +285,8 @@ under the License. <dependency prefix="main.hamcrest" artifact="org.hamcrest:hamcrest:3.0" usage="main-tests"/> <dependency prefix="main.xmlunit" artifact="org.xmlunit:xmlunit-core:2.10.0" usage="main-tests"/> <dependency prefix="main.mockito" artifact="org.mockito:mockito-core:4.11.0" usage="main-tests"/> - <dependency prefix="main.byte-buddy" artifact="net.bytebuddy:byte-buddy:1.17.0" usage="main-tests"/> - <dependency prefix="main.byte-buddy-agent" artifact="net.bytebuddy:byte-buddy-agent:1.17.0" usage="main-tests"/> + <dependency prefix="main.byte-buddy" artifact="net.bytebuddy:byte-buddy:1.17.5" usage="main-tests"/> + <dependency prefix="main.byte-buddy-agent" artifact="net.bytebuddy:byte-buddy-agent:1.17.5" usage="main-tests"/> <dependency prefix="main.objenesis" artifact="org.objenesis:objenesis:3.1" usage="main-tests"/> <dependency prefix="main.log4j-core" artifact="org.apache.logging.log4j:log4j-core:2.24.3" usage="main-tests"/> <dependency prefix="main.commons-logging" artifact="commons-logging:commons-logging:1.2" usage="main-tests"/> @@ -328,7 +328,7 @@ under the License. <dependency prefix="pdf.pdfbox" artifact="org.apache.pdfbox:pdfbox:3.0.4" usage="ooxml-provided"/> <dependency prefix="pdf.pdfbox.io" artifact="org.apache.pdfbox:pdfbox-io:3.0.4" usage="ooxml-provided"/> <dependency prefix="pdf.fontbox" artifact="org.apache.pdfbox:fontbox:3.0.4" usage="ooxml-provided"/> - <dependency prefix="pdf.graphics2d" artifact="de.rototor.pdfbox:graphics2d:3.0.2" usage="ooxml-provided"/> + <dependency prefix="pdf.graphics2d" artifact="de.rototor.pdfbox:graphics2d:3.0.3" usage="ooxml-provided"/> <!-- jars in the ooxml-lib directory, see the fetch-ooxml-jars target--> <dependency prefix="ooxml.curvesapi" artifact="com.github.virtuald:curvesapi:1.08" usage="ooxml"/> diff --git a/osgi/pom.xml b/osgi/pom.xml index c4854f4c12..cb6c157c2c 100644 --- a/osgi/pom.xml +++ b/osgi/pom.xml @@ -24,12 +24,12 @@ <groupId>org.apache.poi</groupId> <artifactId>poi-bundle</artifactId> <packaging>bundle</packaging> - <version>5.4.1-SNAPSHOT</version> + <version>5.4.1</version> <name>Apache POI OSGi bundle</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <poi.version>5.4.1-SNAPSHOT</poi.version> + <poi.version>5.4.1</poi.version> <pax.exam.version>4.14.0</pax.exam.version> </properties> diff --git a/poi-ooxml-lite-agent/build.gradle b/poi-ooxml-lite-agent/build.gradle index f598b6358e..fef003b327 100644 --- a/poi-ooxml-lite-agent/build.gradle +++ b/poi-ooxml-lite-agent/build.gradle @@ -22,8 +22,8 @@ sourceSets { } dependencies { - api 'net.bytebuddy:byte-buddy:1.17.0' - api 'net.bytebuddy:byte-buddy-agent:1.17.0' + api 'net.bytebuddy:byte-buddy:1.17.5' + api 'net.bytebuddy:byte-buddy-agent:1.17.5' api "org.apache.xmlbeans:xmlbeans:${xmlbeansVersion}" } diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java index a10e43c277..9648476001 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java +++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java @@ -35,7 +35,7 @@ import org.apache.poi.util.TempFile; * close this as soon as you can! * @see ZipInputStreamZipEntrySource#setThresholdBytesForTempFiles(int) */ -/* package */ class ZipArchiveFakeEntry extends ZipArchiveEntry implements Closeable { +public final class ZipArchiveFakeEntry extends ZipArchiveEntry implements Closeable { private static final Logger LOG = PoiLogManager.getLogger(ZipArchiveFakeEntry.class); // how large a single entry in a zip-file should become at max @@ -43,12 +43,22 @@ import org.apache.poi.util.TempFile; private static final int DEFAULT_MAX_ENTRY_SIZE = 100_000_000; private static int MAX_ENTRY_SIZE = DEFAULT_MAX_ENTRY_SIZE; + /** + * Set the maximum size of a single entry in a zip-file. + * @param maxEntrySize number of bytes at which a zip entry is regarded as too large for holding in memory + * - defaults to 100_000_000 (approx 100Mb). A value of -1 means the default value is used. + */ public static void setMaxEntrySize(int maxEntrySize) { - MAX_ENTRY_SIZE = maxEntrySize; + if(maxEntrySize < 0) { + MAX_ENTRY_SIZE = DEFAULT_MAX_ENTRY_SIZE; + } else { + MAX_ENTRY_SIZE = maxEntrySize; + } } public static int getMaxEntrySize() { - return MAX_ENTRY_SIZE; + final int ioMaxSize = IOUtils.getByteArrayMaxOverride(); + return ioMaxSize < 0 ? MAX_ENTRY_SIZE : Math.min(MAX_ENTRY_SIZE, ioMaxSize); } private byte[] data; @@ -61,7 +71,7 @@ import org.apache.poi.util.TempFile; final long entrySize = entry.getSize(); final int threshold = ZipInputStreamZipEntrySource.getThresholdBytesForTempFiles(); - if (threshold >= 0 && entrySize >= threshold) { + if (threshold >= 0 && (entrySize >= threshold || entrySize == -1)) { if (ZipInputStreamZipEntrySource.shouldEncryptTempFiles()) { encryptedTempData = new EncryptedTempData(); try (OutputStream os = encryptedTempData.getOutputStream()) { @@ -80,7 +90,7 @@ import org.apache.poi.util.TempFile; // Grab the de-compressed contents for later data = (entrySize == -1) ? IOUtils.toByteArrayWithMaxLength(inp, getMaxEntrySize()) : - IOUtils.toByteArray(inp, (int)entrySize, getMaxEntrySize()); + IOUtils.toByteArray(inp, entrySize, getMaxEntrySize()); } } diff --git a/poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFCell.java b/poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFCell.java index 20689d5696..50f87b0d5b 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFCell.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFCell.java @@ -721,8 +721,6 @@ public class SXSSFCell extends CellBase { } //end of interface implementation - private static final DataFormatter DATA_FORMATTER = new DataFormatter(); - /** * Returns a string representation of the cell * <p> @@ -743,8 +741,14 @@ public class SXSSFCell extends CellBase { case FORMULA: return getCellFormula(); case NUMERIC: + if (DateUtil.isCellDateFormatted(this)) { + DataFormatter df = new DataFormatter(); + df.setUseCachedValuesForFormulaCells(true); + return df.formatCellValue(this); + } + return Double.toString(getNumericCellValue()); case STRING: - return DATA_FORMATTER.formatCellValue(this); + return getRichStringCellValue().toString(); default: return "Unknown Cell Type: " + getCellType(); } diff --git a/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCell.java b/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCell.java index 5ef93237fa..29088a5b48 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCell.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCell.java @@ -924,8 +924,6 @@ public final class XSSFCell extends CellBase { } } - private static final DataFormatter DATA_FORMATTER = new DataFormatter(); - /** * Returns a string representation of the cell * <p> @@ -938,8 +936,14 @@ public final class XSSFCell extends CellBase { public String toString() { switch (getCellType()) { case NUMERIC: + if (DateUtil.isCellDateFormatted(this)) { + DataFormatter df = new DataFormatter(); + df.setUseCachedValuesForFormulaCells(true); + return df.formatCellValue(this); + } + return Double.toString(getNumericCellValue()); case STRING: - return DATA_FORMATTER.formatCellValue(this); + return getRichStringCellValue().toString(); case FORMULA: return getCellFormula(); case BLANK: diff --git a/poi-ooxml/src/test/java/org/apache/poi/ooxml/TestPOIXMLDocument.java b/poi-ooxml/src/test/java/org/apache/poi/ooxml/TestPOIXMLDocument.java index cc22c41ca9..ad08156874 100644 --- a/poi-ooxml/src/test/java/org/apache/poi/ooxml/TestPOIXMLDocument.java +++ b/poi-ooxml/src/test/java/org/apache/poi/ooxml/TestPOIXMLDocument.java @@ -136,8 +136,7 @@ public final class TestPOIXMLDocument { // see {@link org.apache.poi.openxml4j.opc.ZipPackage#saveImpl(java.io.OutputStream)} OpenXML4JRuntimeException e = assertThrows(OpenXML4JRuntimeException.class, () -> doc.write(out), "Should not be able to write to an output stream that has been closed."); - assertTrue(e.getMessage().matches("Fail to save: an error occurs while saving the package : " + - "The part .+ failed to be saved in the stream with marshaller .+")); + assertEquals("Failed to save: content types part", e.getMessage()); // Should not be able to write a document that has been closed doc.close(); diff --git a/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFBugs.java b/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFBugs.java index 8afaaecb2d..4846e7a402 100644 --- a/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFBugs.java +++ b/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFBugs.java @@ -28,6 +28,9 @@ import java.io.IOException; import java.math.BigInteger; import java.util.List; +import org.apache.poi.openxml4j.util.ZipArchiveFakeEntry; +import org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource; +import org.apache.poi.util.IOUtils; import org.apache.poi.util.Units; import org.apache.poi.xwpf.XWPFTestDataSamples; import org.apache.poi.xwpf.usermodel.XWPFRun.FontCharRange; @@ -149,22 +152,22 @@ class TestXWPFBugs { } } - /** - * Removing a run needs to take into account position of run if paragraph contains hyperlink runs - */ - @Test - void test58618() throws IOException { - try (XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("58618.docx")) { - XWPFParagraph para = (XWPFParagraph) doc.getBodyElements().get(0); - assertNotNull(para); - assertEquals("Some text some hyper links link link and some text.....", para.getText()); - XWPFRun run = para.insertNewRun(para.getRuns().size()); - run.setText("New Text"); - assertEquals("Some text some hyper links link link and some text.....New Text", para.getText()); - para.removeRun(para.getRuns().size() - 2); - assertEquals("Some text some hyper links link linkNew Text", para.getText()); - } - } + /** + * Removing a run needs to take into account position of run if paragraph contains hyperlink runs + */ + @Test + void test58618() throws IOException { + try (XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("58618.docx")) { + XWPFParagraph para = (XWPFParagraph) doc.getBodyElements().get(0); + assertNotNull(para); + assertEquals("Some text some hyper links link link and some text.....", para.getText()); + XWPFRun run = para.insertNewRun(para.getRuns().size()); + run.setText("New Text"); + assertEquals("Some text some hyper links link link and some text.....New Text", para.getText()); + para.removeRun(para.getRuns().size() - 2); + assertEquals("Some text some hyper links link linkNew Text", para.getText()); + } + } @Test void test59378() throws IOException { @@ -329,7 +332,7 @@ class TestXWPFBugs { } } - private static void addNumberingWithAbstractId(XWPFNumbering documentNumbering, int id){ + private static void addNumberingWithAbstractId(XWPFNumbering documentNumbering, int id) { // create a numbering scheme CTAbstractNum cTAbstractNum = CTAbstractNum.Factory.newInstance(); // give the scheme an ID @@ -340,4 +343,34 @@ class TestXWPFBugs { documentNumbering.addNum(abstractNumID); } + + @Test + void testBug69628() throws IOException { + final int expectedParagraphs = 24; + // bug69628.docx has -1 entry sizes in the zip data + try (XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("bug69628.docx")) { + assertEquals(expectedParagraphs, doc.getParagraphs().size()); + } + // test again with smaller byte array max + ZipArchiveFakeEntry.setMaxEntrySize(30 * 1024 * 1024); + try (XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("bug69628.docx")) { + assertEquals(expectedParagraphs, doc.getParagraphs().size()); + } finally { + ZipArchiveFakeEntry.setMaxEntrySize(-1); + } + // test again with smaller byte array max + IOUtils.setByteArrayMaxOverride(30 * 1024 * 1024); + try (XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("bug69628.docx")) { + assertEquals(expectedParagraphs, doc.getParagraphs().size()); + } finally { + IOUtils.setByteArrayMaxOverride(-1); + } + // test again but temp files enabled + ZipInputStreamZipEntrySource.setThresholdBytesForTempFiles(1000); + try (XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("bug69628.docx")) { + assertEquals(expectedParagraphs, doc.getParagraphs().size()); + } finally { + ZipInputStreamZipEntrySource.setThresholdBytesForTempFiles(-1); + } + } } diff --git a/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCell.java index 1569553682..fd4f97365d 100644 --- a/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCell.java +++ b/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCell.java @@ -1020,8 +1020,6 @@ public class HSSFCell extends CellBase { _sheet.getSheet().setActiveCellCol(col); } - private static final DataFormatter DATA_FORMATTER = new DataFormatter(); - /** * Returns a string representation of the cell * @@ -1045,8 +1043,14 @@ public class HSSFCell extends CellBase { case FORMULA: return getCellFormula(); case NUMERIC: + if (DateUtil.isCellDateFormatted(this)) { + DataFormatter df = new DataFormatter(); + df.setUseCachedValuesForFormulaCells(true); + return df.formatCellValue(this); + } + return Double.toString(getNumericCellValue()); case STRING: - return DATA_FORMATTER.formatCellValue(this); + return getRichStringCellValue().toString(); default: return "Unknown Cell Type: " + getCellType(); } 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 430e895557..ff86043a54 100644 --- a/poi/src/main/java/org/apache/poi/util/IOUtils.java +++ b/poi/src/main/java/org/apache/poi/util/IOUtils.java @@ -108,6 +108,14 @@ public final class IOUtils { } /** + * @return The maximum number of bytes that should be possible to be allocated in one step. + * @since 5.4.1 + */ + public static int getByteArrayMaxOverride() { + return BYTE_ARRAY_MAX_OVERRIDE; + } + + /** * Peeks at the first 8 bytes of the stream. Returns those bytes, but * with the stream unaffected. Requires a stream that supports mark/reset, * or a PushbackInputStream. If the stream has >0 but <8 bytes, @@ -209,6 +217,27 @@ public final class IOUtils { } /** + * Reads up to {@code length} bytes from the input stream, and returns the bytes read. + * + * @param stream The byte stream of data to read. + * @param length The maximum length to read, use {@link Integer#MAX_VALUE} to read the stream + * until EOF + * @param maxLength if the input is equal to/longer than {@code maxLength} bytes, + * then throw an {@link IOException} complaining about the length. + * use {@link Integer#MAX_VALUE} to disable the check - if {@link #setByteArrayMaxOverride(int)} is + * set then that max of that value and this maxLength is used + * @return A byte array with the read bytes. + * @throws IOException If reading data fails or EOF is encountered too early for the given length. + * @throws RecordFormatException If the requested length is invalid. + * @since POI 5.4.1 + */ + public static byte[] toByteArray(InputStream stream, final long length, final int maxLength) throws IOException { + return toByteArray(stream, + length > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) length, + maxLength, true, length != Integer.MAX_VALUE); + } + + /** * Reads the input stream, and returns the bytes read. * * @param stream The byte stream of data to read. @@ -227,15 +256,12 @@ public final class IOUtils { private static byte[] toByteArray(InputStream stream, final int length, final int maxLength, final boolean checkEOFException, final boolean isLengthKnown) throws IOException { - if (length < 0 || maxLength < 0) { - throw new RecordFormatException("Can't allocate an array of length < 0"); - } final int derivedMaxLength = Math.max(maxLength, BYTE_ARRAY_MAX_OVERRIDE); if ((length != Integer.MAX_VALUE) || (derivedMaxLength != Integer.MAX_VALUE)) { checkLength(length, derivedMaxLength); } - final int derivedLen = isLengthKnown ? Math.min(length, derivedMaxLength) : derivedMaxLength; + final int derivedLen = isLengthKnown && length >= 0 ? Math.min(length, derivedMaxLength) : derivedMaxLength; final int byteArrayInitLen = calculateByteArrayInitLength(isLengthKnown, length, derivedMaxLength); final int internalBufferLen = DEFAULT_BUFFER_SIZE; try (UnsynchronizedByteArrayOutputStream baos = UnsynchronizedByteArrayOutputStream.builder().setBufferSize(byteArrayInitLen).get()) { @@ -254,7 +280,7 @@ public final class IOUtils { throwRecordTruncationException(derivedMaxLength); } - if (checkEOFException && derivedLen != Integer.MAX_VALUE && totalBytes < derivedLen) { + if (checkEOFException && length >= 0 && derivedLen != Integer.MAX_VALUE && totalBytes < derivedLen) { throw new EOFException("unexpected EOF - expected len: " + derivedLen + " - actual len: " + totalBytes); } diff --git a/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestCell.java b/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestCell.java index de2c4ad7c6..ceef38cd18 100644 --- a/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestCell.java +++ b/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestCell.java @@ -365,6 +365,9 @@ public abstract class BaseTestCell { dateStyle.setDataFormat(formatId); r.getCell(7).setCellStyle(dateStyle); + // null rich text + r.createCell(8).setCellValue(factory.createRichTextString(null)); // blank + assertEquals("FALSE", r.getCell(0).toString(), "Boolean"); assertEquals("TRUE", r.getCell(1).toString(), "Boolean"); assertEquals("1.5", r.getCell(2).toString(), "Numeric"); @@ -375,6 +378,7 @@ public abstract class BaseTestCell { // toString on a date-formatted cell displays dates as dd-MMM-yyyy, which has locale problems with the month String dateCell1 = r.getCell(7).toString(); assertEquals("2/2/10 0:00", dateCell1); + assertEquals("", r.getCell(8).toString(), "Blank"); //Write out the file, read it in, and then check cell values try (Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1)) { @@ -388,6 +392,7 @@ public abstract class BaseTestCell { assertEquals("", r.getCell(6).toString(), "Blank"); String dateCell2 = r.getCell(7).toString(); assertEquals(dateCell1, dateCell2, "Date"); + assertEquals("", r.getCell(8).toString(), "Blank"); } } } diff --git a/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java b/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java index 29f62da235..64f585608a 100644 --- a/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java +++ b/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java @@ -531,7 +531,7 @@ public abstract class BaseTestConditionalFormatting { // Sanity check data assertEquals("Values", s.getRow(0).getCell(0).toString()); - assertEquals("10", s.getRow(2).getCell(0).toString()); + assertEquals(10.0, s.getRow(2).getCell(0).getNumericCellValue()); // Check we found all the conditional formatting rules we should have SheetConditionalFormatting sheetCF = s.getSheetConditionalFormatting(); 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 bb12f9932e..7f026adc74 100644 --- a/poi/src/test/java/org/apache/poi/util/TestIOUtils.java +++ b/poi/src/test/java/org/apache/poi/util/TestIOUtils.java @@ -110,8 +110,25 @@ final class TestIOUtils { } @Test - void testToByteArrayNegativeLength() { - assertThrows(RecordFormatException.class, () -> IOUtils.toByteArray(data123(), -1)); + void testToByteArrayNegativeLength() 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.toByteArray(is, -1, 100)); + } finally { + IOUtils.setByteArrayMaxOverride(-1); + } + } + + @Test + void testToByteArrayNegativeLength2() 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.toByteArray(is, -1)); + } finally { + IOUtils.setByteArrayMaxOverride(-1); + } } @Test diff --git a/test-data/document/bug69628.docx b/test-data/document/bug69628.docx Binary files differnew file mode 100644 index 0000000000..359a3b3608 --- /dev/null +++ b/test-data/document/bug69628.docx |