aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build.gradle14
-rw-r--r--build.xml20
-rw-r--r--osgi/pom.xml4
-rw-r--r--poi-ooxml-lite-agent/build.gradle4
-rw-r--r--poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java20
-rw-r--r--poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFCell.java10
-rw-r--r--poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCell.java10
-rw-r--r--poi-ooxml/src/test/java/org/apache/poi/ooxml/TestPOIXMLDocument.java3
-rw-r--r--poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFBugs.java67
-rw-r--r--poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCell.java10
-rw-r--r--poi/src/main/java/org/apache/poi/util/IOUtils.java36
-rw-r--r--poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestCell.java5
-rw-r--r--poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java2
-rw-r--r--poi/src/test/java/org/apache/poi/util/TestIOUtils.java21
-rw-r--r--test-data/document/bug69628.docxbin0 -> 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',
diff --git a/build.xml b/build.xml
index d693ba7479..95c4cefcf9 100644
--- a/build.xml
+++ b/build.xml
@@ -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 &gt;0 but &lt;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
new file mode 100644
index 0000000000..359a3b3608
--- /dev/null
+++ b/test-data/document/bug69628.docx
Binary files differ