mirror of https://github.com/apache/poi.git
sonar fixes
close resources in tests fix gradle warnings git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1892683 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
6d9b450ce3
commit
f71cebcce5
|
@ -209,7 +209,7 @@ subprojects {
|
||||||
// make XML test-results available for Jenkins CI
|
// make XML test-results available for Jenkins CI
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
reports {
|
reports {
|
||||||
junitXml.enabled = true
|
junitXml.required = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exclude some tests that are not actually tests or do not run cleanly on purpose
|
// Exclude some tests that are not actually tests or do not run cleanly on purpose
|
||||||
|
@ -238,7 +238,7 @@ subprojects {
|
||||||
"-Dversion.id=${project.version}",
|
"-Dversion.id=${project.version}",
|
||||||
'-ea',
|
'-ea',
|
||||||
'-Djunit.jupiter.execution.parallel.config.strategy=fixed',
|
'-Djunit.jupiter.execution.parallel.config.strategy=fixed',
|
||||||
'-Djunit.jupiter.execution.parallel.config.fixed.parallelism=3'
|
'-Djunit.jupiter.execution.parallel.config.fixed.parallelism=2'
|
||||||
// -Xjit:verbose={compileStart|compileEnd},vlog=build/jit.log${no.jit.sherlock} ... if ${isIBMVM}
|
// -Xjit:verbose={compileStart|compileEnd},vlog=build/jit.log${no.jit.sherlock} ... if ${isIBMVM}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ subprojects {
|
||||||
|
|
||||||
jacocoTestReport {
|
jacocoTestReport {
|
||||||
reports {
|
reports {
|
||||||
xml.enabled true
|
xml.required = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,6 +396,7 @@ subprojects {
|
||||||
|
|
||||||
spotbugs {
|
spotbugs {
|
||||||
ignoreFailures = true
|
ignoreFailures = true
|
||||||
|
showStackTraces = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,7 +537,7 @@ task replaceVersion() {
|
||||||
|
|
||||||
task zipJavadocs(type: Zip, dependsOn: allJavaDoc) {
|
task zipJavadocs(type: Zip, dependsOn: allJavaDoc) {
|
||||||
from('build/docs/javadoc/')
|
from('build/docs/javadoc/')
|
||||||
destinationDir = file('build/dist')
|
destinationDirectory = file('build/dist')
|
||||||
archiveBaseName = 'poi'
|
archiveBaseName = 'poi'
|
||||||
archiveVersion = subprojects[0].version
|
archiveVersion = subprojects[0].version
|
||||||
archiveAppendix = 'javadoc'
|
archiveAppendix = 'javadoc'
|
||||||
|
|
|
@ -65,6 +65,8 @@ task cacheJava9(type: Copy) {
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
dependsOn cacheJava9
|
||||||
|
|
||||||
destinationDirectory = file("../build/dist/maven/${project.archivesBaseName}")
|
destinationDirectory = file("../build/dist/maven/${project.archivesBaseName}")
|
||||||
|
|
||||||
if (JavaVersion.current() == JavaVersion.VERSION_1_8) {
|
if (JavaVersion.current() == JavaVersion.VERSION_1_8) {
|
||||||
|
|
|
@ -105,6 +105,8 @@ task cacheTest9(type: Copy) {
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
dependsOn cacheJava9
|
||||||
|
|
||||||
destinationDirectory = file("../build/dist/maven/${project.archivesBaseName}")
|
destinationDirectory = file("../build/dist/maven/${project.archivesBaseName}")
|
||||||
|
|
||||||
if (JavaVersion.current() == JavaVersion.VERSION_1_8) {
|
if (JavaVersion.current() == JavaVersion.VERSION_1_8) {
|
||||||
|
@ -120,7 +122,7 @@ jar {
|
||||||
|
|
||||||
// Create a separate jar for test-code to depend on it in other projects
|
// Create a separate jar for test-code to depend on it in other projects
|
||||||
// See http://stackoverflow.com/questions/5144325/gradle-test-dependency
|
// See http://stackoverflow.com/questions/5144325/gradle-test-dependency
|
||||||
task testJar(type: Jar, dependsOn: testClasses) {
|
task testJar(type: Jar, dependsOn: [ testClasses, cacheTest9 ] ) {
|
||||||
destinationDirectory = file("../build/dist/maven/${project.archivesBaseName}-tests")
|
destinationDirectory = file("../build/dist/maven/${project.archivesBaseName}-tests")
|
||||||
|
|
||||||
classifier 'tests'
|
classifier 'tests'
|
||||||
|
|
|
@ -96,7 +96,7 @@ jar {
|
||||||
|
|
||||||
// Create a separate jar for test-code to depend on it in other projects
|
// Create a separate jar for test-code to depend on it in other projects
|
||||||
// See http://stackoverflow.com/questions/5144325/gradle-test-dependency
|
// See http://stackoverflow.com/questions/5144325/gradle-test-dependency
|
||||||
task testJar(type: Jar, dependsOn: testClasses) {
|
task testJar(type: Jar, dependsOn: [ testClasses, cacheTest9 ] ) {
|
||||||
destinationDirectory = file("../build/dist/maven/${project.archivesBaseName}-tests")
|
destinationDirectory = file("../build/dist/maven/${project.archivesBaseName}-tests")
|
||||||
|
|
||||||
classifier 'tests'
|
classifier 'tests'
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
|
||||||
* types of files/exceptions, e.g. old file formats.
|
* types of files/exceptions, e.g. old file formats.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings({"java:S2187", "unused"})
|
||||||
public class BaseIntegrationTest {
|
public class BaseIntegrationTest {
|
||||||
private final File rootDir;
|
private final File rootDir;
|
||||||
private final String file;
|
private final String file;
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package org.apache.poi.stress;
|
package org.apache.poi.stress;
|
||||||
|
|
||||||
import static org.apache.commons.io.output.NullOutputStream.NULL_OUTPUT_STREAM;
|
import static org.apache.commons.io.output.NullOutputStream.NULL_OUTPUT_STREAM;
|
||||||
|
import static org.apache.poi.xssf.XSSFTestDataSamples.getSampleFile;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
@ -219,12 +221,14 @@ class XSSFFileHandler extends SpreadsheetHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testExtracting() throws Exception {
|
void testExtracting() {
|
||||||
handleExtracting(new File("test-data/spreadsheet/ref-56737.xlsx"));
|
File testFile = getSampleFile("ref-56737.xlsx");
|
||||||
|
assertDoesNotThrow(() -> handleExtracting(testFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAdditional() throws Exception {
|
void testAdditional() {
|
||||||
handleAdditional(new File("test-data/spreadsheet/poc-xmlbomb.xlsx"));
|
File testFile = getSampleFile("poc-xmlbomb.xlsx");
|
||||||
|
assertDoesNotThrow(() -> handleAdditional(testFile));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,3 +141,5 @@ jar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spotbugsTest.enabled = false
|
||||||
|
spotbugsMain.enabled = false
|
|
@ -66,13 +66,14 @@ import org.ietf.jgss.Oid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] sign() throws IOException, GeneralSecurityException {
|
public byte[] sign() throws IOException, GeneralSecurityException {
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
bos.write(getHashMagic());
|
bos.write(getHashMagic());
|
||||||
bos.write(md.digest());
|
bos.write(md.digest());
|
||||||
|
|
||||||
final Cipher cipher = CryptoFunctions.getCipher(key, CipherAlgorithm.rsa
|
final Cipher cipher = CryptoFunctions.getCipher(key, CipherAlgorithm.rsa
|
||||||
, ChainingMode.ecb, null, Cipher.ENCRYPT_MODE, "PKCS1Padding");
|
, ChainingMode.ecb, null, Cipher.ENCRYPT_MODE, "PKCS1Padding");
|
||||||
return cipher.doFinal(bos.toByteArray());
|
return cipher.doFinal(bos.toByteArray());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isMSCapi(final PrivateKey key) {
|
static boolean isMSCapi(final PrivateKey key) {
|
||||||
|
@ -91,10 +92,9 @@ import org.ietf.jgss.Oid;
|
||||||
// in an earlier release the hashMagic (aka DigestAlgorithmIdentifier) contained only
|
// in an earlier release the hashMagic (aka DigestAlgorithmIdentifier) contained only
|
||||||
// an object identifier, but to conform with the header generated by the
|
// an object identifier, but to conform with the header generated by the
|
||||||
// javax-signature API, the empty <associated parameters> are also included
|
// javax-signature API, the empty <associated parameters> are also included
|
||||||
try {
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
final byte[] oidBytes = new Oid(algo.rsaOid).getDER();
|
final byte[] oidBytes = new Oid(algo.rsaOid).getDER();
|
||||||
|
|
||||||
final UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
|
||||||
bos.write(0x30);
|
bos.write(0x30);
|
||||||
bos.write(algo.hashSize+oidBytes.length+6);
|
bos.write(algo.hashSize+oidBytes.length+6);
|
||||||
bos.write(0x30);
|
bos.write(0x30);
|
||||||
|
|
|
@ -90,12 +90,13 @@ public class OOXMLURIDereferencer implements URIDereferencer {
|
||||||
// although xmlsec has an option to ignore line breaks, currently this
|
// although xmlsec has an option to ignore line breaks, currently this
|
||||||
// only affects .rels files, so we only modify these
|
// only affects .rels files, so we only modify these
|
||||||
// http://stackoverflow.com/questions/4728300
|
// http://stackoverflow.com/questions/4728300
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
for (int ch; (ch = dataStream.read()) != -1; ) {
|
for (int ch; (ch = dataStream.read()) != -1; ) {
|
||||||
if (ch == 10 || ch == 13) continue;
|
if (ch == 10 || ch == 13) continue;
|
||||||
bos.write(ch);
|
bos.write(ch);
|
||||||
|
}
|
||||||
|
dataStream = bos.toInputStream();
|
||||||
}
|
}
|
||||||
dataStream = bos.toInputStream();
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new URIReferenceException("I/O error: " + e.getMessage(), e);
|
throw new URIReferenceException("I/O error: " + e.getMessage(), e);
|
||||||
|
|
|
@ -289,8 +289,7 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] getC14nValue(List<Node> nodeList, String c14nAlgoId) {
|
public static byte[] getC14nValue(List<Node> nodeList, String c14nAlgoId) {
|
||||||
UnsynchronizedByteArrayOutputStream c14nValue = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream c14nValue = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
try {
|
|
||||||
for (Node node : nodeList) {
|
for (Node node : nodeList) {
|
||||||
/*
|
/*
|
||||||
* Re-initialize the c14n else the namespaces will get cached
|
* Re-initialize the c14n else the namespaces will get cached
|
||||||
|
@ -299,12 +298,12 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
|
||||||
Canonicalizer c14n = Canonicalizer.getInstance(c14nAlgoId);
|
Canonicalizer c14n = Canonicalizer.getInstance(c14nAlgoId);
|
||||||
c14n.canonicalizeSubtree(node, c14nValue);
|
c14n.canonicalizeSubtree(node, c14nValue);
|
||||||
}
|
}
|
||||||
|
return c14nValue.toByteArray();
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("c14n error: " + e.getMessage(), e);
|
throw new RuntimeException("c14n error: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
return c14nValue.toByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BigInteger getCrlNumber(X509CRL crl) {
|
private BigInteger getCrlNumber(X509CRL crl) {
|
||||||
|
|
|
@ -27,34 +27,39 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCfvoType;
|
||||||
* Colour Scale change thresholds
|
* Colour Scale change thresholds
|
||||||
*/
|
*/
|
||||||
public class XSSFConditionalFormattingThreshold implements org.apache.poi.ss.usermodel.ConditionalFormattingThreshold {
|
public class XSSFConditionalFormattingThreshold implements org.apache.poi.ss.usermodel.ConditionalFormattingThreshold {
|
||||||
private CTCfvo cfvo;
|
private final CTCfvo cfvo;
|
||||||
|
|
||||||
protected XSSFConditionalFormattingThreshold(CTCfvo cfvo) {
|
protected XSSFConditionalFormattingThreshold(CTCfvo cfvo) {
|
||||||
this.cfvo = cfvo;
|
this.cfvo = cfvo;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CTCfvo getCTCfvo() {
|
protected CTCfvo getCTCfvo() {
|
||||||
return cfvo;
|
return cfvo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public RangeType getRangeType() {
|
public RangeType getRangeType() {
|
||||||
return RangeType.byName(cfvo.getType().toString());
|
return RangeType.byName(cfvo.getType().toString());
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void setRangeType(RangeType type) {
|
public void setRangeType(RangeType type) {
|
||||||
STCfvoType.Enum xtype = STCfvoType.Enum.forString(type.name);
|
STCfvoType.Enum xtype = STCfvoType.Enum.forString(type.name);
|
||||||
cfvo.setType(xtype);
|
cfvo.setType(xtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getFormula() {
|
public String getFormula() {
|
||||||
if (cfvo.getType() == STCfvoType.FORMULA) {
|
if (cfvo.getType() == STCfvoType.FORMULA) {
|
||||||
return cfvo.getVal();
|
return cfvo.getVal();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void setFormula(String formula) {
|
public void setFormula(String formula) {
|
||||||
cfvo.setVal(formula);
|
cfvo.setVal(formula);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Double getValue() {
|
public Double getValue() {
|
||||||
if (cfvo.getType() == STCfvoType.FORMULA ||
|
if (cfvo.getType() == STCfvoType.FORMULA ||
|
||||||
cfvo.getType() == STCfvoType.MIN ||
|
cfvo.getType() == STCfvoType.MIN ||
|
||||||
|
@ -67,6 +72,7 @@ public class XSSFConditionalFormattingThreshold implements org.apache.poi.ss.use
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void setValue(Double value) {
|
public void setValue(Double value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
cfvo.unsetVal();
|
cfvo.unsetVal();
|
||||||
|
|
|
@ -25,7 +25,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTIconSet;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STIconSetType;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STIconSetType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* High level representation for Icon / Multi-State Formatting
|
* High level representation for Icon / Multi-State Formatting
|
||||||
* component of Conditional Formatting settings
|
* component of Conditional Formatting settings
|
||||||
*/
|
*/
|
||||||
public class XSSFIconMultiStateFormatting implements IconMultiStateFormatting {
|
public class XSSFIconMultiStateFormatting implements IconMultiStateFormatting {
|
||||||
|
@ -35,42 +35,50 @@ public class XSSFIconMultiStateFormatting implements IconMultiStateFormatting {
|
||||||
_iconset = iconset;
|
_iconset = iconset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public IconSet getIconSet() {
|
public IconSet getIconSet() {
|
||||||
String set = _iconset.getIconSet().toString();
|
String set = _iconset.getIconSet().toString();
|
||||||
return IconSet.byName(set);
|
return IconSet.byName(set);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void setIconSet(IconSet set) {
|
public void setIconSet(IconSet set) {
|
||||||
STIconSetType.Enum xIconSet = STIconSetType.Enum.forString(set.name);
|
STIconSetType.Enum xIconSet = STIconSetType.Enum.forString(set.name);
|
||||||
_iconset.setIconSet(xIconSet);
|
_iconset.setIconSet(xIconSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isIconOnly() {
|
public boolean isIconOnly() {
|
||||||
if (_iconset.isSetShowValue())
|
if (_iconset.isSetShowValue())
|
||||||
return !_iconset.getShowValue();
|
return !_iconset.getShowValue();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void setIconOnly(boolean only) {
|
public void setIconOnly(boolean only) {
|
||||||
_iconset.setShowValue(!only);
|
_iconset.setShowValue(!only);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isReversed() {
|
public boolean isReversed() {
|
||||||
if (_iconset.isSetReverse())
|
if (_iconset.isSetReverse())
|
||||||
return _iconset.getReverse();
|
return _iconset.getReverse();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void setReversed(boolean reversed) {
|
public void setReversed(boolean reversed) {
|
||||||
_iconset.setReverse(reversed);
|
_iconset.setReverse(reversed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public XSSFConditionalFormattingThreshold[] getThresholds() {
|
public XSSFConditionalFormattingThreshold[] getThresholds() {
|
||||||
CTCfvo[] cfvos = _iconset.getCfvoArray();
|
CTCfvo[] cfvos = _iconset.getCfvoArray();
|
||||||
XSSFConditionalFormattingThreshold[] t =
|
XSSFConditionalFormattingThreshold[] t =
|
||||||
new XSSFConditionalFormattingThreshold[cfvos.length];
|
new XSSFConditionalFormattingThreshold[cfvos.length];
|
||||||
for (int i=0; i<cfvos.length; i++) {
|
for (int i=0; i<cfvos.length; i++) {
|
||||||
t[i] = new XSSFConditionalFormattingThreshold(cfvos[i]);
|
t[i] = new XSSFConditionalFormattingThreshold(cfvos[i]);
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void setThresholds(ConditionalFormattingThreshold[] thresholds) {
|
public void setThresholds(ConditionalFormattingThreshold[] thresholds) {
|
||||||
CTCfvo[] cfvos = new CTCfvo[thresholds.length];
|
CTCfvo[] cfvos = new CTCfvo[thresholds.length];
|
||||||
for (int i=0; i<thresholds.length; i++) {
|
for (int i=0; i<thresholds.length; i++) {
|
||||||
|
@ -78,6 +86,7 @@ public class XSSFIconMultiStateFormatting implements IconMultiStateFormatting {
|
||||||
}
|
}
|
||||||
_iconset.setCfvoArray(cfvos);
|
_iconset.setCfvoArray(cfvos);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public XSSFConditionalFormattingThreshold createThreshold() {
|
public XSSFConditionalFormattingThreshold createThreshold() {
|
||||||
return new XSSFConditionalFormattingThreshold(_iconset.addNewCfvo());
|
return new XSSFConditionalFormattingThreshold(_iconset.addNewCfvo());
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,6 +139,7 @@ public class XSSFWorkbookFactory implements WorkbookProvider {
|
||||||
* @throws IOException if an error occurs while reading the data
|
* @throws IOException if an error occurs while reading the data
|
||||||
* @throws EncryptedDocumentException If the wrong password is given for a protected file
|
* @throws EncryptedDocumentException If the wrong password is given for a protected file
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
@SuppressWarnings("resource")
|
@SuppressWarnings("resource")
|
||||||
public XSSFWorkbook create(File file, String password, boolean readOnly) throws IOException {
|
public XSSFWorkbook create(File file, String password, boolean readOnly) throws IOException {
|
||||||
FileMagic fm = FileMagic.valueOf(file);
|
FileMagic fm = FileMagic.valueOf(file);
|
||||||
|
|
|
@ -45,7 +45,6 @@ import org.apache.poi.xssf.XSSFTestDataSamples;
|
||||||
import org.apache.poi.xssf.model.MapInfo;
|
import org.apache.poi.xssf.model.MapInfo;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFMap;
|
import org.apache.poi.xssf.usermodel.XSSFMap;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
import org.junit.jupiter.api.Disabled;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import org.xml.sax.SAXParseException;
|
import org.xml.sax.SAXParseException;
|
||||||
|
@ -216,15 +215,13 @@ public final class TestXSSFExportToXML {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Disabled(value="Fails, but I don't know if it is ok or not...")
|
|
||||||
void testExportToXMLSingleAttributeNamespace() throws Exception {
|
void testExportToXMLSingleAttributeNamespace() throws Exception {
|
||||||
try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXMLMapping-singleattributenamespace.xlsx")) {
|
try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXMLMapping-singleattributenamespace.xlsx")) {
|
||||||
|
|
||||||
for (XSSFMap map : wb.getCustomXMLMappings()) {
|
for (XSSFMap map : wb.getCustomXMLMappings()) {
|
||||||
XSSFExportToXml exporter = new XSSFExportToXml(map);
|
XSSFExportToXml exporter = new XSSFExportToXml(map);
|
||||||
|
|
||||||
UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream();
|
UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream();
|
||||||
exporter.exportToXML(os, true);
|
SAXParseException ex = assertThrows(SAXParseException.class, () -> exporter.exportToXML(os, true));
|
||||||
|
assertEquals("schema_reference: Failed to read schema document 'Schema11', because 'file' access is not allowed due to restriction set by the accessExternalSchema property.", ex.getMessage().trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
|
public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
|
||||||
|
|
||||||
|
@ -90,112 +92,109 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void existingWorkbook() throws IOException {
|
void existingWorkbook() throws IOException {
|
||||||
XSSFWorkbook xssfWb1 = new XSSFWorkbook();
|
try (XSSFWorkbook xssfWb1 = new XSSFWorkbook()) {
|
||||||
xssfWb1.createSheet("S1");
|
xssfWb1.createSheet("S1");
|
||||||
DeferredSXSSFWorkbook wb1 = new DeferredSXSSFWorkbook(xssfWb1);
|
try (DeferredSXSSFWorkbook wb1 = new DeferredSXSSFWorkbook(xssfWb1);
|
||||||
XSSFWorkbook xssfWb2 = DeferredSXSSFITestDataProvider.instance.writeOutAndReadBack(wb1);
|
XSSFWorkbook xssfWb2 = DeferredSXSSFITestDataProvider.instance.writeOutAndReadBack(wb1)) {
|
||||||
assertTrue(wb1.dispose());
|
assertTrue(wb1.dispose());
|
||||||
|
|
||||||
DeferredSXSSFWorkbook wb2 = new DeferredSXSSFWorkbook(xssfWb2);
|
try (DeferredSXSSFWorkbook wb2 = new DeferredSXSSFWorkbook(xssfWb2)) {
|
||||||
assertEquals(1, wb2.getNumberOfSheets());
|
assertEquals(1, wb2.getNumberOfSheets());
|
||||||
Sheet sheet = wb2.getStreamingSheetAt(0);
|
Sheet sheet = wb2.getStreamingSheetAt(0);
|
||||||
assertNotNull(sheet);
|
assertNotNull(sheet);
|
||||||
assertEquals("S1", sheet.getSheetName());
|
assertEquals("S1", sheet.getSheetName());
|
||||||
assertTrue(wb2.dispose());
|
assertTrue(wb2.dispose());
|
||||||
xssfWb2.close();
|
}
|
||||||
xssfWb1.close();
|
}
|
||||||
|
}
|
||||||
wb2.close();
|
|
||||||
wb1.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void addToExistingWorkbook() throws IOException {
|
void addToExistingWorkbook() throws IOException {
|
||||||
XSSFWorkbook xssfWb1 = new XSSFWorkbook();
|
try (XSSFWorkbook xssfWb1 = new XSSFWorkbook()) {
|
||||||
xssfWb1.createSheet("S1");
|
xssfWb1.createSheet("S1");
|
||||||
Sheet sheet = xssfWb1.createSheet("S2");
|
Sheet sheet = xssfWb1.createSheet("S2");
|
||||||
Row row = sheet.createRow(1);
|
Row row = sheet.createRow(1);
|
||||||
Cell cell = row.createCell(1);
|
Cell cell = row.createCell(1);
|
||||||
cell.setCellValue("value 2_1_1");
|
cell.setCellValue("value 2_1_1");
|
||||||
DeferredSXSSFWorkbook wb1 = new DeferredSXSSFWorkbook(xssfWb1);
|
|
||||||
XSSFWorkbook xssfWb2 = DeferredSXSSFITestDataProvider.instance.writeOutAndReadBack(wb1);
|
|
||||||
assertTrue(wb1.dispose());
|
|
||||||
xssfWb1.close();
|
|
||||||
|
|
||||||
DeferredSXSSFWorkbook wb2 = new DeferredSXSSFWorkbook(xssfWb2);
|
try (DeferredSXSSFWorkbook wb1 = new DeferredSXSSFWorkbook(xssfWb1);
|
||||||
// Add a row to the existing empty sheet
|
XSSFWorkbook xssfWb2 = DeferredSXSSFITestDataProvider.instance.writeOutAndReadBack(wb1)) {
|
||||||
DeferredSXSSFSheet ssheet1 = wb2.getStreamingSheetAt(0);
|
assertTrue(wb1.dispose());
|
||||||
ssheet1.setRowGenerator((ssxSheet) -> {
|
|
||||||
Row row1_1 = ssxSheet.createRow(1);
|
|
||||||
Cell cell1_1_1 = row1_1.createCell(1);
|
|
||||||
cell1_1_1.setCellValue("value 1_1_1");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add a row to the existing non-empty sheet
|
try (DeferredSXSSFWorkbook wb2 = new DeferredSXSSFWorkbook(xssfWb2)) {
|
||||||
DeferredSXSSFSheet ssheet2 = wb2.getStreamingSheetAt(1);
|
// Add a row to the existing empty sheet
|
||||||
ssheet2.setRowGenerator((ssxSheet) -> {
|
DeferredSXSSFSheet ssheet1 = wb2.getStreamingSheetAt(0);
|
||||||
Row row2_2 = ssxSheet.createRow(2);
|
ssheet1.setRowGenerator((ssxSheet) -> {
|
||||||
Cell cell2_2_1 = row2_2.createCell(1);
|
Row row1_1 = ssxSheet.createRow(1);
|
||||||
cell2_2_1.setCellValue("value 2_2_1");
|
Cell cell1_1_1 = row1_1.createCell(1);
|
||||||
});
|
cell1_1_1.setCellValue("value 1_1_1");
|
||||||
// Add a sheet with one row
|
});
|
||||||
DeferredSXSSFSheet ssheet3 = wb2.createSheet("S3");
|
|
||||||
ssheet3.setRowGenerator((ssxSheet) -> {
|
|
||||||
Row row3_1 = ssxSheet.createRow(1);
|
|
||||||
Cell cell3_1_1 = row3_1.createCell(1);
|
|
||||||
cell3_1_1.setCellValue("value 3_1_1");
|
|
||||||
});
|
|
||||||
|
|
||||||
XSSFWorkbook xssfWb3 = DeferredSXSSFITestDataProvider.instance.writeOutAndReadBack(wb2);
|
// Add a row to the existing non-empty sheet
|
||||||
wb2.close();
|
DeferredSXSSFSheet ssheet2 = wb2.getStreamingSheetAt(1);
|
||||||
|
ssheet2.setRowGenerator((ssxSheet) -> {
|
||||||
|
Row row2_2 = ssxSheet.createRow(2);
|
||||||
|
Cell cell2_2_1 = row2_2.createCell(1);
|
||||||
|
cell2_2_1.setCellValue("value 2_2_1");
|
||||||
|
});
|
||||||
|
// Add a sheet with one row
|
||||||
|
DeferredSXSSFSheet ssheet3 = wb2.createSheet("S3");
|
||||||
|
ssheet3.setRowGenerator((ssxSheet) -> {
|
||||||
|
Row row3_1 = ssxSheet.createRow(1);
|
||||||
|
Cell cell3_1_1 = row3_1.createCell(1);
|
||||||
|
cell3_1_1.setCellValue("value 3_1_1");
|
||||||
|
});
|
||||||
|
|
||||||
assertEquals(3, xssfWb3.getNumberOfSheets());
|
try (XSSFWorkbook xssfWb3 = DeferredSXSSFITestDataProvider.instance.writeOutAndReadBack(wb2)) {
|
||||||
// Verify sheet 1
|
|
||||||
XSSFSheet sheet1 = xssfWb3.getSheetAt(0);
|
|
||||||
assertEquals("S1", sheet1.getSheetName());
|
|
||||||
assertEquals(1, sheet1.getPhysicalNumberOfRows());
|
|
||||||
XSSFRow row1_1 = sheet1.getRow(1);
|
|
||||||
assertNotNull(row1_1);
|
|
||||||
XSSFCell cell1_1_1 = row1_1.getCell(1);
|
|
||||||
assertNotNull(cell1_1_1);
|
|
||||||
assertEquals("value 1_1_1", cell1_1_1.getStringCellValue());
|
|
||||||
// Verify sheet 2
|
|
||||||
XSSFSheet sheet2 = xssfWb3.getSheetAt(1);
|
|
||||||
assertEquals("S2", sheet2.getSheetName());
|
|
||||||
assertEquals(2, sheet2.getPhysicalNumberOfRows());
|
|
||||||
Row row2_1 = sheet2.getRow(1);
|
|
||||||
assertNotNull(row2_1);
|
|
||||||
Cell cell2_1_1 = row2_1.getCell(1);
|
|
||||||
assertNotNull(cell2_1_1);
|
|
||||||
assertEquals("value 2_1_1", cell2_1_1.getStringCellValue());
|
|
||||||
XSSFRow row2_2 = sheet2.getRow(2);
|
|
||||||
assertNotNull(row2_2);
|
|
||||||
XSSFCell cell2_2_1 = row2_2.getCell(1);
|
|
||||||
assertNotNull(cell2_2_1);
|
|
||||||
assertEquals("value 2_2_1", cell2_2_1.getStringCellValue());
|
|
||||||
// Verify sheet 3
|
|
||||||
XSSFSheet sheet3 = xssfWb3.getSheetAt(2);
|
|
||||||
assertEquals("S3", sheet3.getSheetName());
|
|
||||||
assertEquals(1, sheet3.getPhysicalNumberOfRows());
|
|
||||||
XSSFRow row3_1 = sheet3.getRow(1);
|
|
||||||
assertNotNull(row3_1);
|
|
||||||
XSSFCell cell3_1_1 = row3_1.getCell(1);
|
|
||||||
assertNotNull(cell3_1_1);
|
|
||||||
assertEquals("value 3_1_1", cell3_1_1.getStringCellValue());
|
|
||||||
|
|
||||||
xssfWb2.close();
|
assertEquals(3, xssfWb3.getNumberOfSheets());
|
||||||
xssfWb3.close();
|
// Verify sheet 1
|
||||||
wb1.close();
|
XSSFSheet sheet1 = xssfWb3.getSheetAt(0);
|
||||||
|
assertEquals("S1", sheet1.getSheetName());
|
||||||
|
assertEquals(1, sheet1.getPhysicalNumberOfRows());
|
||||||
|
XSSFRow row1_1 = sheet1.getRow(1);
|
||||||
|
assertNotNull(row1_1);
|
||||||
|
XSSFCell cell1_1_1 = row1_1.getCell(1);
|
||||||
|
assertNotNull(cell1_1_1);
|
||||||
|
assertEquals("value 1_1_1", cell1_1_1.getStringCellValue());
|
||||||
|
// Verify sheet 2
|
||||||
|
XSSFSheet sheet2 = xssfWb3.getSheetAt(1);
|
||||||
|
assertEquals("S2", sheet2.getSheetName());
|
||||||
|
assertEquals(2, sheet2.getPhysicalNumberOfRows());
|
||||||
|
Row row2_1 = sheet2.getRow(1);
|
||||||
|
assertNotNull(row2_1);
|
||||||
|
Cell cell2_1_1 = row2_1.getCell(1);
|
||||||
|
assertNotNull(cell2_1_1);
|
||||||
|
assertEquals("value 2_1_1", cell2_1_1.getStringCellValue());
|
||||||
|
XSSFRow row2_2 = sheet2.getRow(2);
|
||||||
|
assertNotNull(row2_2);
|
||||||
|
XSSFCell cell2_2_1 = row2_2.getCell(1);
|
||||||
|
assertNotNull(cell2_2_1);
|
||||||
|
assertEquals("value 2_2_1", cell2_2_1.getStringCellValue());
|
||||||
|
// Verify sheet 3
|
||||||
|
XSSFSheet sheet3 = xssfWb3.getSheetAt(2);
|
||||||
|
assertEquals("S3", sheet3.getSheetName());
|
||||||
|
assertEquals(1, sheet3.getPhysicalNumberOfRows());
|
||||||
|
XSSFRow row3_1 = sheet3.getRow(1);
|
||||||
|
assertNotNull(row3_1);
|
||||||
|
XSSFCell cell3_1_1 = row3_1.getCell(1);
|
||||||
|
assertNotNull(cell3_1_1);
|
||||||
|
assertEquals("value 3_1_1", cell3_1_1.getStringCellValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void sheetdataWriter() throws IOException {
|
void sheetdataWriter() throws IOException {
|
||||||
DeferredSXSSFWorkbook wb = new DeferredSXSSFWorkbook();
|
try (DeferredSXSSFWorkbook wb = new DeferredSXSSFWorkbook()) {
|
||||||
SXSSFSheet sh = wb.createSheet();
|
SXSSFSheet sh = wb.createSheet();
|
||||||
assertSame(sh.getClass(), DeferredSXSSFSheet.class);
|
assertSame(sh.getClass(), DeferredSXSSFSheet.class);
|
||||||
SheetDataWriter wr = sh.getSheetDataWriter();
|
SheetDataWriter wr = sh.getSheetDataWriter();
|
||||||
assertNull(wr);
|
assertNull(wr);
|
||||||
wb.close();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -225,71 +224,65 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void gzipSheetdataWriter() throws IOException {
|
void gzipSheetdataWriter() throws IOException {
|
||||||
DeferredSXSSFWorkbook wb = new DeferredSXSSFWorkbook();
|
try (DeferredSXSSFWorkbook wb = new DeferredSXSSFWorkbook()) {
|
||||||
|
|
||||||
final int rowNum = 1000;
|
final int rowNum = 1000;
|
||||||
final int sheetNum = 5;
|
final int sheetNum = 5;
|
||||||
populateData(wb, 1000, 5);
|
populateData(wb);
|
||||||
|
|
||||||
XSSFWorkbook xwb = DeferredSXSSFITestDataProvider.instance.writeOutAndReadBack(wb);
|
try (XSSFWorkbook xwb = DeferredSXSSFITestDataProvider.instance.writeOutAndReadBack(wb)) {
|
||||||
for (int i = 0; i < sheetNum; i++) {
|
for (int i = 0; i < sheetNum; i++) {
|
||||||
Sheet sh = xwb.getSheetAt(i);
|
Sheet sh = xwb.getSheetAt(i);
|
||||||
assertEquals("sheet" + i, sh.getSheetName());
|
assertEquals("sheet" + i, sh.getSheetName());
|
||||||
for (int j = 0; j < rowNum; j++) {
|
for (int j = 0; j < rowNum; j++) {
|
||||||
Row row = sh.getRow(j);
|
Row row = sh.getRow(j);
|
||||||
assertNotNull(row, "row[" + j + "]");
|
assertNotNull(row, "row[" + j + "]");
|
||||||
Cell cell1 = row.getCell(0);
|
Cell cell1 = row.getCell(0);
|
||||||
assertEquals(new CellReference(cell1).formatAsString(), cell1.getStringCellValue());
|
assertEquals(new CellReference(cell1).formatAsString(), cell1.getStringCellValue());
|
||||||
|
|
||||||
Cell cell2 = row.getCell(1);
|
Cell cell2 = row.getCell(1);
|
||||||
assertEquals(i, (int) cell2.getNumericCellValue());
|
assertEquals(i, (int) cell2.getNumericCellValue());
|
||||||
|
|
||||||
Cell cell3 = row.getCell(2);
|
Cell cell3 = row.getCell(2);
|
||||||
assertEquals(j, (int) cell3.getNumericCellValue());
|
assertEquals(j, (int) cell3.getNumericCellValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(wb.dispose());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(wb.dispose());
|
|
||||||
xwb.close();
|
|
||||||
wb.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest
|
||||||
void workbookDispose() throws IOException {
|
@ValueSource(booleans = {false, true})
|
||||||
DeferredSXSSFWorkbook wb1 = new DeferredSXSSFWorkbook();
|
void workbookDispose(boolean compressTempFiles) throws IOException {
|
||||||
// the underlying writer is SheetDataWriter
|
try (DeferredSXSSFWorkbook wb = new DeferredSXSSFWorkbook()) {
|
||||||
assertWorkbookDispose(wb1);
|
// compressTempFiles == false: the underlying writer is SheetDataWriter
|
||||||
wb1.close();
|
// compressTempFiles == true: the underlying writer is GZIPSheetDataWriter
|
||||||
|
wb.setCompressTempFiles(compressTempFiles);
|
||||||
|
|
||||||
DeferredSXSSFWorkbook wb2 = new DeferredSXSSFWorkbook();
|
populateData(wb);
|
||||||
wb2.setCompressTempFiles(true);
|
|
||||||
// the underlying writer is GZIPSheetDataWriter
|
|
||||||
assertWorkbookDispose(wb2);
|
|
||||||
wb2.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void assertWorkbookDispose(DeferredSXSSFWorkbook wb) {
|
for (Sheet sheet : wb) {
|
||||||
populateData(wb, 1000, 5);
|
DeferredSXSSFSheet sxSheet = (DeferredSXSSFSheet) sheet;
|
||||||
|
assertNull(sxSheet.getSheetDataWriter());
|
||||||
|
}
|
||||||
|
|
||||||
for (Sheet sheet : wb) {
|
assertTrue(wb.dispose());
|
||||||
DeferredSXSSFSheet sxSheet = (DeferredSXSSFSheet) sheet;
|
|
||||||
assertNull(sxSheet.getSheetDataWriter());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue(wb.dispose());
|
for (Sheet sheet : wb) {
|
||||||
|
DeferredSXSSFSheet sxSheet = (DeferredSXSSFSheet) sheet;
|
||||||
for (Sheet sheet : wb) {
|
assertNull(sxSheet.getSheetDataWriter());
|
||||||
DeferredSXSSFSheet sxSheet = (DeferredSXSSFSheet) sheet;
|
}
|
||||||
assertNull(sxSheet.getSheetDataWriter());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void populateData(DeferredSXSSFWorkbook wb, final int rowNum, final int sheetNum) {
|
private static void populateData(DeferredSXSSFWorkbook wb) {
|
||||||
for (int i = 0; i < sheetNum; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
DeferredSXSSFSheet sheet = wb.createSheet("sheet" + i);
|
DeferredSXSSFSheet sheet = wb.createSheet("sheet" + i);
|
||||||
int index = i;
|
int index = i;
|
||||||
sheet.setRowGenerator((sh) -> {
|
sheet.setRowGenerator((sh) -> {
|
||||||
for (int j = 0; j < rowNum; j++) {
|
for (int j = 0; j < 1000; j++) {
|
||||||
Row row = sh.createRow(j);
|
Row row = sh.createRow(j);
|
||||||
Cell cell1 = row.createCell(0);
|
Cell cell1 = row.createCell(0);
|
||||||
cell1.setCellValue(new CellReference(cell1).formatAsString());
|
cell1.setCellValue(new CellReference(cell1).formatAsString());
|
||||||
|
@ -304,7 +297,8 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeSheetNameWithSharedFormulas() {
|
@Override
|
||||||
/* not implemented */
|
@Disabled("not implemented")
|
||||||
|
protected void changeSheetNameWithSharedFormulas() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,8 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
|
public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
|
||||||
|
|
||||||
|
@ -98,225 +100,201 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void existingWorkbook() throws IOException {
|
void existingWorkbook() throws IOException {
|
||||||
XSSFWorkbook xssfWb1 = new XSSFWorkbook();
|
try (XSSFWorkbook xssfWb1 = new XSSFWorkbook()) {
|
||||||
xssfWb1.createSheet("S1");
|
xssfWb1.createSheet("S1");
|
||||||
SXSSFWorkbook wb1 = new SXSSFWorkbook(xssfWb1);
|
try (SXSSFWorkbook wb1 = new SXSSFWorkbook(xssfWb1);
|
||||||
XSSFWorkbook xssfWb2 = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb1);
|
XSSFWorkbook xssfWb2 = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb1)) {
|
||||||
assertTrue(wb1.dispose());
|
assertTrue(wb1.dispose());
|
||||||
|
|
||||||
SXSSFWorkbook wb2 = new SXSSFWorkbook(xssfWb2);
|
try (SXSSFWorkbook wb2 = new SXSSFWorkbook(xssfWb2)) {
|
||||||
assertEquals(1, wb2.getNumberOfSheets());
|
assertEquals(1, wb2.getNumberOfSheets());
|
||||||
Sheet sheet = wb2.getSheetAt(0);
|
Sheet sheet = wb2.getSheetAt(0);
|
||||||
assertNotNull(sheet);
|
assertNotNull(sheet);
|
||||||
assertEquals("S1", sheet.getSheetName());
|
assertEquals("S1", sheet.getSheetName());
|
||||||
assertTrue(wb2.dispose());
|
assertTrue(wb2.dispose());
|
||||||
xssfWb2.close();
|
}
|
||||||
xssfWb1.close();
|
}
|
||||||
|
}
|
||||||
wb2.close();
|
|
||||||
wb1.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void useSharedStringsTable() throws Exception {
|
void useSharedStringsTable() throws Exception {
|
||||||
SXSSFWorkbook wb = new SXSSFWorkbook(null, 10, false, true);
|
try (SXSSFWorkbook wb = new SXSSFWorkbook(null, 10, false, true)) {
|
||||||
|
|
||||||
SharedStringsTable sss = wb.getSharedStringSource();
|
SharedStringsTable sss = wb.getSharedStringSource();
|
||||||
|
|
||||||
assertNotNull(sss);
|
assertNotNull(sss);
|
||||||
|
|
||||||
Row row = wb.createSheet("S1").createRow(0);
|
Row row = wb.createSheet("S1").createRow(0);
|
||||||
|
|
||||||
row.createCell(0).setCellValue("A");
|
row.createCell(0).setCellValue("A");
|
||||||
row.createCell(1).setCellValue("B");
|
row.createCell(1).setCellValue("B");
|
||||||
row.createCell(2).setCellValue("A");
|
row.createCell(2).setCellValue("A");
|
||||||
|
|
||||||
XSSFWorkbook xssfWorkbook = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb);
|
try (XSSFWorkbook xssfWorkbook = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb)) {
|
||||||
sss = wb.getSharedStringSource();
|
sss = wb.getSharedStringSource();
|
||||||
assertEquals(2, sss.getUniqueCount());
|
assertEquals(2, sss.getUniqueCount());
|
||||||
assertTrue(wb.dispose());
|
assertTrue(wb.dispose());
|
||||||
|
|
||||||
Sheet sheet1 = xssfWorkbook.getSheetAt(0);
|
Sheet sheet1 = xssfWorkbook.getSheetAt(0);
|
||||||
assertEquals("S1", sheet1.getSheetName());
|
assertEquals("S1", sheet1.getSheetName());
|
||||||
assertEquals(1, sheet1.getPhysicalNumberOfRows());
|
assertEquals(1, sheet1.getPhysicalNumberOfRows());
|
||||||
row = sheet1.getRow(0);
|
row = sheet1.getRow(0);
|
||||||
assertNotNull(row);
|
assertNotNull(row);
|
||||||
Cell cell = row.getCell(0);
|
Cell cell = row.getCell(0);
|
||||||
assertNotNull(cell);
|
assertNotNull(cell);
|
||||||
assertEquals("A", cell.getStringCellValue());
|
assertEquals("A", cell.getStringCellValue());
|
||||||
cell = row.getCell(1);
|
cell = row.getCell(1);
|
||||||
assertNotNull(cell);
|
assertNotNull(cell);
|
||||||
assertEquals("B", cell.getStringCellValue());
|
assertEquals("B", cell.getStringCellValue());
|
||||||
cell = row.getCell(2);
|
cell = row.getCell(2);
|
||||||
assertNotNull(cell);
|
assertNotNull(cell);
|
||||||
assertEquals("A", cell.getStringCellValue());
|
assertEquals("A", cell.getStringCellValue());
|
||||||
|
}
|
||||||
xssfWorkbook.close();
|
}
|
||||||
wb.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void addToExistingWorkbook() throws IOException {
|
void addToExistingWorkbook() throws IOException {
|
||||||
XSSFWorkbook xssfWb1 = new XSSFWorkbook();
|
try (XSSFWorkbook xssfWb1 = new XSSFWorkbook()) {
|
||||||
xssfWb1.createSheet("S1");
|
xssfWb1.createSheet("S1");
|
||||||
Sheet sheet = xssfWb1.createSheet("S2");
|
Sheet sheet = xssfWb1.createSheet("S2");
|
||||||
Row row = sheet.createRow(1);
|
Row row = sheet.createRow(1);
|
||||||
Cell cell = row.createCell(1);
|
Cell cell = row.createCell(1);
|
||||||
cell.setCellValue("value 2_1_1");
|
cell.setCellValue("value 2_1_1");
|
||||||
SXSSFWorkbook wb1 = new SXSSFWorkbook(xssfWb1);
|
try (SXSSFWorkbook wb1 = new SXSSFWorkbook(xssfWb1);
|
||||||
XSSFWorkbook xssfWb2 = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb1);
|
XSSFWorkbook xssfWb2 = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb1)) {
|
||||||
assertTrue(wb1.dispose());
|
assertTrue(wb1.dispose());
|
||||||
xssfWb1.close();
|
|
||||||
|
|
||||||
SXSSFWorkbook wb2 = new SXSSFWorkbook(xssfWb2);
|
try (SXSSFWorkbook wb2 = new SXSSFWorkbook(xssfWb2)) {
|
||||||
// Add a row to the existing empty sheet
|
// Add a row to the existing empty sheet
|
||||||
Sheet sheet1 = wb2.getSheetAt(0);
|
Sheet sheet1 = wb2.getSheetAt(0);
|
||||||
Row row1_1 = sheet1.createRow(1);
|
Row row1_1 = sheet1.createRow(1);
|
||||||
Cell cell1_1_1 = row1_1.createCell(1);
|
Cell cell1_1_1 = row1_1.createCell(1);
|
||||||
cell1_1_1.setCellValue("value 1_1_1");
|
cell1_1_1.setCellValue("value 1_1_1");
|
||||||
|
|
||||||
// Add a row to the existing non-empty sheet
|
// Add a row to the existing non-empty sheet
|
||||||
Sheet sheet2 = wb2.getSheetAt(1);
|
Sheet sheet2 = wb2.getSheetAt(1);
|
||||||
Row row2_2 = sheet2.createRow(2);
|
Row row2_2 = sheet2.createRow(2);
|
||||||
Cell cell2_2_1 = row2_2.createCell(1);
|
Cell cell2_2_1 = row2_2.createCell(1);
|
||||||
cell2_2_1.setCellValue("value 2_2_1");
|
cell2_2_1.setCellValue("value 2_2_1");
|
||||||
|
|
||||||
// Add a sheet with one row
|
// Add a sheet with one row
|
||||||
Sheet sheet3 = wb2.createSheet("S3");
|
Sheet sheet3 = wb2.createSheet("S3");
|
||||||
Row row3_1 = sheet3.createRow(1);
|
Row row3_1 = sheet3.createRow(1);
|
||||||
Cell cell3_1_1 = row3_1.createCell(1);
|
Cell cell3_1_1 = row3_1.createCell(1);
|
||||||
cell3_1_1.setCellValue("value 3_1_1");
|
cell3_1_1.setCellValue("value 3_1_1");
|
||||||
|
|
||||||
XSSFWorkbook xssfWb3 = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb2);
|
try (XSSFWorkbook xssfWb3 = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb2)) {
|
||||||
wb2.close();
|
assertEquals(3, xssfWb3.getNumberOfSheets());
|
||||||
|
// Verify sheet 1
|
||||||
assertEquals(3, xssfWb3.getNumberOfSheets());
|
sheet1 = xssfWb3.getSheetAt(0);
|
||||||
// Verify sheet 1
|
assertEquals("S1", sheet1.getSheetName());
|
||||||
sheet1 = xssfWb3.getSheetAt(0);
|
assertEquals(1, sheet1.getPhysicalNumberOfRows());
|
||||||
assertEquals("S1", sheet1.getSheetName());
|
row1_1 = sheet1.getRow(1);
|
||||||
assertEquals(1, sheet1.getPhysicalNumberOfRows());
|
assertNotNull(row1_1);
|
||||||
row1_1 = sheet1.getRow(1);
|
cell1_1_1 = row1_1.getCell(1);
|
||||||
assertNotNull(row1_1);
|
assertNotNull(cell1_1_1);
|
||||||
cell1_1_1 = row1_1.getCell(1);
|
assertEquals("value 1_1_1", cell1_1_1.getStringCellValue());
|
||||||
assertNotNull(cell1_1_1);
|
// Verify sheet 2
|
||||||
assertEquals("value 1_1_1", cell1_1_1.getStringCellValue());
|
sheet2 = xssfWb3.getSheetAt(1);
|
||||||
// Verify sheet 2
|
assertEquals("S2", sheet2.getSheetName());
|
||||||
sheet2 = xssfWb3.getSheetAt(1);
|
assertEquals(2, sheet2.getPhysicalNumberOfRows());
|
||||||
assertEquals("S2", sheet2.getSheetName());
|
Row row2_1 = sheet2.getRow(1);
|
||||||
assertEquals(2, sheet2.getPhysicalNumberOfRows());
|
assertNotNull(row2_1);
|
||||||
Row row2_1 = sheet2.getRow(1);
|
Cell cell2_1_1 = row2_1.getCell(1);
|
||||||
assertNotNull(row2_1);
|
assertNotNull(cell2_1_1);
|
||||||
Cell cell2_1_1 = row2_1.getCell(1);
|
assertEquals("value 2_1_1", cell2_1_1.getStringCellValue());
|
||||||
assertNotNull(cell2_1_1);
|
row2_2 = sheet2.getRow(2);
|
||||||
assertEquals("value 2_1_1", cell2_1_1.getStringCellValue());
|
assertNotNull(row2_2);
|
||||||
row2_2 = sheet2.getRow(2);
|
cell2_2_1 = row2_2.getCell(1);
|
||||||
assertNotNull(row2_2);
|
assertNotNull(cell2_2_1);
|
||||||
cell2_2_1 = row2_2.getCell(1);
|
assertEquals("value 2_2_1", cell2_2_1.getStringCellValue());
|
||||||
assertNotNull(cell2_2_1);
|
// Verify sheet 3
|
||||||
assertEquals("value 2_2_1", cell2_2_1.getStringCellValue());
|
sheet3 = xssfWb3.getSheetAt(2);
|
||||||
// Verify sheet 3
|
assertEquals("S3", sheet3.getSheetName());
|
||||||
sheet3 = xssfWb3.getSheetAt(2);
|
assertEquals(1, sheet3.getPhysicalNumberOfRows());
|
||||||
assertEquals("S3", sheet3.getSheetName());
|
row3_1 = sheet3.getRow(1);
|
||||||
assertEquals(1, sheet3.getPhysicalNumberOfRows());
|
assertNotNull(row3_1);
|
||||||
row3_1 = sheet3.getRow(1);
|
cell3_1_1 = row3_1.getCell(1);
|
||||||
assertNotNull(row3_1);
|
assertNotNull(cell3_1_1);
|
||||||
cell3_1_1 = row3_1.getCell(1);
|
assertEquals("value 3_1_1", cell3_1_1.getStringCellValue());
|
||||||
assertNotNull(cell3_1_1);
|
}
|
||||||
assertEquals("value 3_1_1", cell3_1_1.getStringCellValue());
|
}
|
||||||
|
}
|
||||||
xssfWb2.close();
|
}
|
||||||
xssfWb3.close();
|
|
||||||
wb1.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void sheetdataWriter() throws IOException{
|
void sheetdataWriter() throws IOException{
|
||||||
SXSSFWorkbook wb = new SXSSFWorkbook();
|
try (SXSSFWorkbook wb = new SXSSFWorkbook()) {
|
||||||
SXSSFSheet sh = wb.createSheet();
|
SXSSFSheet sh = wb.createSheet();
|
||||||
SheetDataWriter wr = sh.getSheetDataWriter();
|
SheetDataWriter wr = sh.getSheetDataWriter();
|
||||||
assertSame(wr.getClass(), SheetDataWriter.class);
|
assertSame(wr.getClass(), SheetDataWriter.class);
|
||||||
File tmp = wr.getTempFile();
|
File tmp = wr.getTempFile();
|
||||||
assertStartsWith(tmp.getName(), "poi-sxssf-sheet");
|
assertStartsWith(tmp.getName(), "poi-sxssf-sheet");
|
||||||
assertEndsWith(tmp.getName(), ".xml");
|
assertEndsWith(tmp.getName(), ".xml");
|
||||||
assertTrue(wb.dispose());
|
assertTrue(wb.dispose());
|
||||||
wb.close();
|
}
|
||||||
|
|
||||||
wb = new SXSSFWorkbook();
|
try (SXSSFWorkbook wb = new SXSSFWorkbook()) {
|
||||||
wb.setCompressTempFiles(true);
|
wb.setCompressTempFiles(true);
|
||||||
sh = wb.createSheet();
|
SXSSFSheet sh = wb.createSheet();
|
||||||
wr = sh.getSheetDataWriter();
|
SheetDataWriter wr = sh.getSheetDataWriter();
|
||||||
assertSame(wr.getClass(), GZIPSheetDataWriter.class);
|
assertSame(wr.getClass(), GZIPSheetDataWriter.class);
|
||||||
tmp = wr.getTempFile();
|
File tmp = wr.getTempFile();
|
||||||
assertStartsWith(tmp.getName(), "poi-sxssf-sheet-xml");
|
assertStartsWith(tmp.getName(), "poi-sxssf-sheet-xml");
|
||||||
assertEndsWith(tmp.getName(), ".gz");
|
assertEndsWith(tmp.getName(), ".gz");
|
||||||
assertTrue(wb.dispose());
|
assertTrue(wb.dispose());
|
||||||
wb.close();
|
}
|
||||||
|
|
||||||
//Test escaping of Unicode control characters
|
//Test escaping of Unicode control characters
|
||||||
wb = new SXSSFWorkbook();
|
try (SXSSFWorkbook wb = new SXSSFWorkbook()) {
|
||||||
wb.createSheet("S1").createRow(0).createCell(0).setCellValue("value\u0019");
|
wb.createSheet("S1").createRow(0).createCell(0).setCellValue("value\u0019");
|
||||||
XSSFWorkbook xssfWorkbook = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb);
|
try (XSSFWorkbook xssfWorkbook = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb)) {
|
||||||
Cell cell = xssfWorkbook.getSheet("S1").getRow(0).getCell(0);
|
Cell cell = xssfWorkbook.getSheet("S1").getRow(0).getCell(0);
|
||||||
assertEquals("value?", cell.getStringCellValue());
|
assertEquals("value?", cell.getStringCellValue());
|
||||||
|
assertTrue(wb.dispose());
|
||||||
assertTrue(wb.dispose());
|
}
|
||||||
wb.close();
|
}
|
||||||
xssfWorkbook.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void gzipSheetdataWriter() throws IOException {
|
void gzipSheetdataWriter() throws IOException {
|
||||||
SXSSFWorkbook wb = new SXSSFWorkbook();
|
try (SXSSFWorkbook wb = new SXSSFWorkbook()) {
|
||||||
wb.setCompressTempFiles(true);
|
wb.setCompressTempFiles(true);
|
||||||
|
|
||||||
final int rowNum = 1000;
|
final int rowNum = 1000;
|
||||||
final int sheetNum = 5;
|
final int sheetNum = 5;
|
||||||
populateData(wb, 1000, 5);
|
populateData(wb);
|
||||||
|
|
||||||
XSSFWorkbook xwb = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb);
|
try (XSSFWorkbook xwb = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb)) {
|
||||||
for(int i = 0; i < sheetNum; i++){
|
for (int i = 0; i < sheetNum; i++) {
|
||||||
Sheet sh = xwb.getSheetAt(i);
|
Sheet sh = xwb.getSheetAt(i);
|
||||||
assertEquals("sheet" + i, sh.getSheetName());
|
assertEquals("sheet" + i, sh.getSheetName());
|
||||||
for(int j = 0; j < rowNum; j++){
|
for (int j = 0; j < rowNum; j++) {
|
||||||
Row row = sh.getRow(j);
|
Row row = sh.getRow(j);
|
||||||
assertNotNull(row, "row[" + j + "]");
|
assertNotNull(row, "row[" + j + "]");
|
||||||
Cell cell1 = row.getCell(0);
|
Cell cell1 = row.getCell(0);
|
||||||
assertEquals(new CellReference(cell1).formatAsString(), cell1.getStringCellValue());
|
assertEquals(new CellReference(cell1).formatAsString(), cell1.getStringCellValue());
|
||||||
|
|
||||||
Cell cell2 = row.getCell(1);
|
Cell cell2 = row.getCell(1);
|
||||||
assertEquals(i, (int)cell2.getNumericCellValue());
|
assertEquals(i, (int) cell2.getNumericCellValue());
|
||||||
|
|
||||||
Cell cell3 = row.getCell(2);
|
Cell cell3 = row.getCell(2);
|
||||||
assertEquals(j, (int)cell3.getNumericCellValue());
|
assertEquals(j, (int) cell3.getNumericCellValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(wb.dispose());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(wb.dispose());
|
|
||||||
xwb.close();
|
|
||||||
wb.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertWorkbookDispose(SXSSFWorkbook wb)
|
private static void populateData(Workbook wb) {
|
||||||
{
|
for(int i = 0; i < 5; i++){
|
||||||
populateData(wb, 1000, 5);
|
|
||||||
|
|
||||||
for (Sheet sheet : wb) {
|
|
||||||
SXSSFSheet sxSheet = (SXSSFSheet) sheet;
|
|
||||||
assertTrue(sxSheet.getSheetDataWriter().getTempFile().exists());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue(wb.dispose());
|
|
||||||
|
|
||||||
for (Sheet sheet : wb) {
|
|
||||||
SXSSFSheet sxSheet = (SXSSFSheet) sheet;
|
|
||||||
assertFalse(sxSheet.getSheetDataWriter().getTempFile().exists());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void populateData(Workbook wb, final int rowNum, final int sheetNum) {
|
|
||||||
for(int i = 0; i < sheetNum; i++){
|
|
||||||
Sheet sh = wb.createSheet("sheet" + i);
|
Sheet sh = wb.createSheet("sheet" + i);
|
||||||
for(int j = 0; j < rowNum; j++){
|
for(int j = 0; j < 1000; j++){
|
||||||
Row row = sh.createRow(j);
|
Row row = sh.createRow(j);
|
||||||
Cell cell1 = row.createCell(0);
|
Cell cell1 = row.createCell(0);
|
||||||
cell1.setCellValue(new CellReference(cell1).formatAsString());
|
cell1.setCellValue(new CellReference(cell1).formatAsString());
|
||||||
|
@ -330,28 +308,40 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest
|
||||||
void workbookDispose() throws IOException {
|
@ValueSource(booleans = {false, true})
|
||||||
SXSSFWorkbook wb1 = new SXSSFWorkbook();
|
void workbookDispose(boolean compressTempFiles) throws IOException {
|
||||||
// the underlying writer is SheetDataWriter
|
try (SXSSFWorkbook wb = new SXSSFWorkbook()) {
|
||||||
assertWorkbookDispose(wb1);
|
// compressTempFiles == false: the underlying writer is SheetDataWriter
|
||||||
wb1.close();
|
// compressTempFiles == true: the underlying writer is GZIPSheetDataWriter
|
||||||
|
wb.setCompressTempFiles(compressTempFiles);
|
||||||
|
|
||||||
SXSSFWorkbook wb2 = new SXSSFWorkbook();
|
populateData(wb);
|
||||||
wb2.setCompressTempFiles(true);
|
|
||||||
// the underlying writer is GZIPSheetDataWriter
|
for (Sheet sheet : wb) {
|
||||||
assertWorkbookDispose(wb2);
|
SXSSFSheet sxSheet = (SXSSFSheet) sheet;
|
||||||
wb2.close();
|
assertTrue(sxSheet.getSheetDataWriter().getTempFile().exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(wb.dispose());
|
||||||
|
|
||||||
|
for (Sheet sheet : wb) {
|
||||||
|
SXSSFSheet sxSheet = (SXSSFSheet) sheet;
|
||||||
|
assertFalse(sxSheet.getSheetDataWriter().getTempFile().exists());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void bug53515() throws Exception {
|
void bug53515() throws Exception {
|
||||||
try (Workbook wb1 = new SXSSFWorkbook(10)) {
|
try (Workbook wb1 = new SXSSFWorkbook(10)) {
|
||||||
populateWorkbook(wb1);
|
populateWorkbook(wb1);
|
||||||
saveTwice(wb1);
|
assertDoesNotThrow(() -> wb1.write(NULL_OUTPUT_STREAM));
|
||||||
|
assertDoesNotThrow(() -> wb1.write(NULL_OUTPUT_STREAM));
|
||||||
try (Workbook wb2 = new XSSFWorkbook()) {
|
try (Workbook wb2 = new XSSFWorkbook()) {
|
||||||
populateWorkbook(wb2);
|
populateWorkbook(wb2);
|
||||||
saveTwice(wb2);
|
assertDoesNotThrow(() -> wb2.write(NULL_OUTPUT_STREAM));
|
||||||
|
assertDoesNotThrow(() -> wb2.write(NULL_OUTPUT_STREAM));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,18 +395,6 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void saveTwice(Workbook wb) throws Exception {
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
try {
|
|
||||||
wb.write(NULL_OUTPUT_STREAM);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new Exception("ERROR: failed on " + (i + 1)
|
|
||||||
+ "th time calling " + wb.getClass().getName()
|
|
||||||
+ ".write() with exception " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void closeDoesNotModifyWorkbook() throws IOException {
|
void closeDoesNotModifyWorkbook() throws IOException {
|
||||||
final String filename = "SampleSS.xlsx";
|
final String filename = "SampleSS.xlsx";
|
||||||
|
@ -460,10 +438,10 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
|
||||||
char[] useless = new char[32767];
|
char[] useless = new char[32767];
|
||||||
Arrays.fill(useless, ' ');
|
Arrays.fill(useless, ' ');
|
||||||
|
|
||||||
for (int row = 0; row < 1; row++) {
|
for (int row = 0; row < 10; row++) {
|
||||||
Row r = s.createRow(row);
|
Row r = s.createRow(row);
|
||||||
for (int col = 0; col < 10; col++) {
|
for (int col = 0; col < 10; col++) {
|
||||||
char[] prefix = Integer.toHexString(row * 1000 + col).toCharArray();
|
char[] prefix = Integer.toHexString(row * 10 + col).toCharArray();
|
||||||
Arrays.fill(useless, 0, 10, ' ');
|
Arrays.fill(useless, 0, 10, ' ');
|
||||||
System.arraycopy(prefix, 0, useless, 0, prefix.length);
|
System.arraycopy(prefix, 0, useless, 0, prefix.length);
|
||||||
String ul = new String(useless);
|
String ul = new String(useless);
|
||||||
|
@ -528,8 +506,8 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@Disabled("not implemented")
|
@Disabled("not implemented")
|
||||||
@Test
|
protected void changeSheetNameWithSharedFormulas() {
|
||||||
void changeSheetNameWithSharedFormulas() {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,6 @@ import org.apache.poi.ss.util.CellRangeAddress;
|
||||||
import org.apache.poi.ss.util.CellReference;
|
import org.apache.poi.ss.util.CellReference;
|
||||||
import org.apache.poi.ss.util.CellUtil;
|
import org.apache.poi.ss.util.CellUtil;
|
||||||
import org.apache.poi.util.LocaleUtil;
|
import org.apache.poi.util.LocaleUtil;
|
||||||
import org.apache.commons.io.output.NullOutputStream;
|
|
||||||
import org.apache.poi.util.TempFile;
|
import org.apache.poi.util.TempFile;
|
||||||
import org.apache.poi.util.XMLHelper;
|
import org.apache.poi.util.XMLHelper;
|
||||||
import org.apache.poi.xssf.SXSSFITestDataProvider;
|
import org.apache.poi.xssf.SXSSFITestDataProvider;
|
||||||
|
@ -117,7 +116,14 @@ import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.CsvSource;
|
import org.junit.jupiter.params.provider.CsvSource;
|
||||||
import org.junit.jupiter.params.provider.EnumSource;
|
import org.junit.jupiter.params.provider.EnumSource;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCalcCell;
|
||||||
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
|
||||||
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
|
||||||
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedNames;
|
||||||
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCell;
|
||||||
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCells;
|
||||||
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
|
||||||
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTFontImpl;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTFontImpl;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.SAXParseException;
|
import org.xml.sax.SAXParseException;
|
||||||
|
@ -2714,6 +2720,7 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues {
|
||||||
CellStyle style = wb.createCellStyle();
|
CellStyle style = wb.createCellStyle();
|
||||||
style.setRotation((short) -90);
|
style.setRotation((short) -90);
|
||||||
cell.setCellStyle(style);
|
cell.setCellStyle(style);
|
||||||
|
assertEquals(180, style.getRotation());
|
||||||
|
|
||||||
XSSFTestDataSamples.writeOut(wb, fileName);
|
XSSFTestDataSamples.writeOut(wb, fileName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,11 +259,11 @@ public final class TestXSSFFont extends BaseTestFont{
|
||||||
|
|
||||||
xssfFont.setUnderline(Font.U_DOUBLE);
|
xssfFont.setUnderline(Font.U_DOUBLE);
|
||||||
assertEquals(ctFont.sizeOfUArray(),1);
|
assertEquals(ctFont.sizeOfUArray(),1);
|
||||||
assertEquals(STUnderlineValues.DOUBLE,ctFont.getUArray(0).getVal());
|
assertSame(STUnderlineValues.DOUBLE,ctFont.getUArray(0).getVal());
|
||||||
|
|
||||||
xssfFont.setUnderline(FontUnderline.DOUBLE_ACCOUNTING);
|
xssfFont.setUnderline(FontUnderline.DOUBLE_ACCOUNTING);
|
||||||
assertEquals(ctFont.sizeOfUArray(),1);
|
assertEquals(ctFont.sizeOfUArray(),1);
|
||||||
assertEquals(STUnderlineValues.DOUBLE_ACCOUNTING,ctFont.getUArray(0).getVal());
|
assertSame(STUnderlineValues.DOUBLE_ACCOUNTING,ctFont.getUArray(0).getVal());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -342,7 +342,7 @@ public final class TestXSSFFont extends BaseTestFont{
|
||||||
assertEquals(FontScheme.MAJOR,font.getScheme());
|
assertEquals(FontScheme.MAJOR,font.getScheme());
|
||||||
|
|
||||||
font.setScheme(FontScheme.NONE);
|
font.setScheme(FontScheme.NONE);
|
||||||
assertEquals(STFontScheme.NONE,ctFont.getSchemeArray(0).getVal());
|
assertSame(STFontScheme.NONE,ctFont.getSchemeArray(0).getVal());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -356,17 +356,15 @@ public final class TestXSSFFont extends BaseTestFont{
|
||||||
assertEquals(Font.SS_NONE,font.getTypeOffset());
|
assertEquals(Font.SS_NONE,font.getTypeOffset());
|
||||||
|
|
||||||
font.setTypeOffset(XSSFFont.SS_SUPER);
|
font.setTypeOffset(XSSFFont.SS_SUPER);
|
||||||
assertEquals(STVerticalAlignRun.SUPERSCRIPT,ctFont.getVertAlignArray(0).getVal());
|
assertSame(STVerticalAlignRun.SUPERSCRIPT,ctFont.getVertAlignArray(0).getVal());
|
||||||
}
|
}
|
||||||
|
|
||||||
// store test from TestSheetUtil here as it uses XSSF
|
// store test from TestSheetUtil here as it uses XSSF
|
||||||
@Test
|
@Test
|
||||||
void testCanComputeWidthXSSF() throws IOException {
|
void testCanComputeWidthXSSF() throws IOException {
|
||||||
try (Workbook wb = new XSSFWorkbook()) {
|
try (Workbook wb = new XSSFWorkbook()) {
|
||||||
|
|
||||||
// cannot check on result because on some machines we get back false here!
|
// cannot check on result because on some machines we get back false here!
|
||||||
SheetUtil.canComputeColumnWidth(wb.getFontAt(0));
|
assertDoesNotThrow(() -> SheetUtil.canComputeColumnWidth(wb.getFontAt(0)));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,7 +375,7 @@ public final class TestXSSFFont extends BaseTestFont{
|
||||||
font.setFontName("some non existing font name");
|
font.setFontName("some non existing font name");
|
||||||
|
|
||||||
// Even with invalid fonts we still get back useful data most of the time...
|
// Even with invalid fonts we still get back useful data most of the time...
|
||||||
SheetUtil.canComputeColumnWidth(font);
|
assertDoesNotThrow(() -> SheetUtil.canComputeColumnWidth(font));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -252,14 +252,14 @@ public final class TestXSSFSheet extends BaseTestXSheet {
|
||||||
|
|
||||||
sheet.createFreezePane(2, 4);
|
sheet.createFreezePane(2, 4);
|
||||||
assertEquals(2.0, ctWorksheet.getSheetViews().getSheetViewArray(0).getPane().getXSplit(), 0.0);
|
assertEquals(2.0, ctWorksheet.getSheetViews().getSheetViewArray(0).getPane().getXSplit(), 0.0);
|
||||||
assertEquals(STPane.BOTTOM_RIGHT, ctWorksheet.getSheetViews().getSheetViewArray(0).getPane().getActivePane());
|
assertSame(STPane.BOTTOM_RIGHT, ctWorksheet.getSheetViews().getSheetViewArray(0).getPane().getActivePane());
|
||||||
sheet.createFreezePane(3, 6, 10, 10);
|
sheet.createFreezePane(3, 6, 10, 10);
|
||||||
assertEquals(3.0, ctWorksheet.getSheetViews().getSheetViewArray(0).getPane().getXSplit(), 0.0);
|
assertEquals(3.0, ctWorksheet.getSheetViews().getSheetViewArray(0).getPane().getXSplit(), 0.0);
|
||||||
// assertEquals(10, sheet.getTopRow());
|
// assertEquals(10, sheet.getTopRow());
|
||||||
// assertEquals(10, sheet.getLeftCol());
|
// assertEquals(10, sheet.getLeftCol());
|
||||||
sheet.createSplitPane(4, 8, 12, 12, 1);
|
sheet.createSplitPane(4, 8, 12, 12, 1);
|
||||||
assertEquals(8.0, ctWorksheet.getSheetViews().getSheetViewArray(0).getPane().getYSplit(), 0.0);
|
assertEquals(8.0, ctWorksheet.getSheetViews().getSheetViewArray(0).getPane().getYSplit(), 0.0);
|
||||||
assertEquals(STPane.BOTTOM_RIGHT, ctWorksheet.getSheetViews().getSheetViewArray(0).getPane().getActivePane());
|
assertSame(STPane.BOTTOM_RIGHT, ctWorksheet.getSheetViews().getSheetViewArray(0).getPane().getActivePane());
|
||||||
|
|
||||||
workbook.close();
|
workbook.close();
|
||||||
}
|
}
|
||||||
|
@ -1152,7 +1152,7 @@ public final class TestXSSFSheet extends BaseTestXSheet {
|
||||||
CTCalcPr calcPr = wb1.getCTWorkbook().addNewCalcPr();
|
CTCalcPr calcPr = wb1.getCTWorkbook().addNewCalcPr();
|
||||||
calcPr.setCalcMode(STCalcMode.MANUAL);
|
calcPr.setCalcMode(STCalcMode.MANUAL);
|
||||||
sheet.setForceFormulaRecalculation(true);
|
sheet.setForceFormulaRecalculation(true);
|
||||||
assertEquals(STCalcMode.AUTO, calcPr.getCalcMode());
|
assertSame(STCalcMode.AUTO, calcPr.getCalcMode());
|
||||||
|
|
||||||
// Check
|
// Check
|
||||||
sheet.setForceFormulaRecalculation(false);
|
sheet.setForceFormulaRecalculation(false);
|
||||||
|
@ -1422,350 +1422,337 @@ public final class TestXSSFSheet extends BaseTestXSheet {
|
||||||
wb.close();
|
wb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testCopyOneRow(String copyRowsTestWorkbook) throws IOException {
|
|
||||||
final double FLOAT_PRECISION = 1e-9;
|
|
||||||
final XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook(copyRowsTestWorkbook);
|
|
||||||
final XSSFSheet sheet = wb.getSheetAt(0);
|
|
||||||
final CellCopyPolicy defaultCopyPolicy = new CellCopyPolicy();
|
|
||||||
sheet.copyRows(1, 1, 6, defaultCopyPolicy);
|
|
||||||
|
|
||||||
final Row srcRow = sheet.getRow(1);
|
|
||||||
final Row destRow = sheet.getRow(6);
|
|
||||||
int col = 0;
|
|
||||||
Cell cell;
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals("Source row ->", cell.getStringCellValue());
|
|
||||||
|
|
||||||
// Style
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals("Red", cell.getStringCellValue(), "[Style] B7 cell value");
|
|
||||||
assertEquals(CellUtil.getCell(srcRow, 1).getCellStyle(), cell.getCellStyle(), "[Style] B7 cell style");
|
|
||||||
|
|
||||||
// Blank
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals(CellType.BLANK, cell.getCellType(), "[Blank] C7 cell type");
|
|
||||||
|
|
||||||
// Error
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals(CellType.ERROR, cell.getCellType(), "[Error] D7 cell type");
|
|
||||||
final FormulaError error = FormulaError.forInt(cell.getErrorCellValue());
|
|
||||||
//FIXME: XSSFCell and HSSFCell expose different interfaces. getErrorCellString would be helpful here
|
|
||||||
assertEquals(FormulaError.NA, error, "[Error] D7 cell value");
|
|
||||||
|
|
||||||
// Date
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Date] E7 cell type");
|
|
||||||
final Date date = LocaleUtil.getLocaleCalendar(2000, Calendar.JANUARY, 1).getTime();
|
|
||||||
assertEquals(date, cell.getDateCellValue(), "[Date] E7 cell value");
|
|
||||||
|
|
||||||
// Boolean
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals(CellType.BOOLEAN, cell.getCellType(), "[Boolean] F7 cell type");
|
|
||||||
assertTrue(cell.getBooleanCellValue(), "[Boolean] F7 cell value");
|
|
||||||
|
|
||||||
// String
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals(CellType.STRING, cell.getCellType(), "[String] G7 cell type");
|
|
||||||
assertEquals("Hello", cell.getStringCellValue(), "[String] G7 cell value");
|
|
||||||
|
|
||||||
// Int
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Int] H7 cell type");
|
|
||||||
assertEquals(15, (int) cell.getNumericCellValue(), "[Int] H7 cell value");
|
|
||||||
|
|
||||||
// Float
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Float] I7 cell type");
|
|
||||||
assertEquals(12.5, cell.getNumericCellValue(), FLOAT_PRECISION, "[Float] I7 cell value");
|
|
||||||
|
|
||||||
// Cell Formula
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals("Sheet1!J7", new CellReference(cell).formatAsString());
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula] J7 cell type");
|
|
||||||
assertEquals("5+2", cell.getCellFormula(), "[Cell Formula] J7 cell formula");
|
|
||||||
//System.out.println("Cell formula evaluation currently unsupported");
|
|
||||||
|
|
||||||
// Cell Formula with Reference
|
|
||||||
// Formula row references should be adjusted by destRowNum-srcRowNum
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals("Sheet1!K7", new CellReference(cell).formatAsString());
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Reference] K7 cell type");
|
|
||||||
assertEquals("J7+H$2", cell.getCellFormula(), "[Cell Formula with Reference] K7 cell formula");
|
|
||||||
|
|
||||||
// Cell Formula with Reference spanning multiple rows
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Reference spanning multiple rows] L7 cell type");
|
|
||||||
assertEquals("G7&\" \"&G8", cell.getCellFormula(), "[Cell Formula with Reference spanning multiple rows] L7 cell formula");
|
|
||||||
|
|
||||||
// Cell Formula with Reference spanning multiple rows
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Area Reference] M7 cell type");
|
|
||||||
assertEquals("SUM(H7:I8)", cell.getCellFormula(), "[Cell Formula with Area Reference] M7 cell formula");
|
|
||||||
|
|
||||||
// Array Formula
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
//System.out.println("Array formulas currently unsupported");
|
|
||||||
// FIXME: Array Formula set with Sheet.setArrayFormula() instead of cell.setFormula()
|
|
||||||
/*
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Array Formula] N7 cell type");
|
|
||||||
assertEquals("{SUM(H7:J7*{1,2,3})}", cell.getCellFormula(), "[Array Formula] N7 cell formula");
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Data Format
|
|
||||||
cell = CellUtil.getCell(destRow, col++);
|
|
||||||
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Data Format] O7 cell type");
|
|
||||||
assertEquals(100.20, cell.getNumericCellValue(), FLOAT_PRECISION, "[Data Format] O7 cell value");
|
|
||||||
//FIXME: currently fails
|
|
||||||
final String moneyFormat = "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)";
|
|
||||||
assertEquals(moneyFormat, cell.getCellStyle().getDataFormatString(), "[Data Format] O7 data format");
|
|
||||||
|
|
||||||
// Merged
|
|
||||||
cell = CellUtil.getCell(destRow, col);
|
|
||||||
assertEquals("Merged cells", cell.getStringCellValue(), "[Merged] P7:Q7 cell value");
|
|
||||||
assertTrue(sheet.getMergedRegions().contains(CellRangeAddress.valueOf("P7:Q7")), "[Merged] P7:Q7 merged region");
|
|
||||||
|
|
||||||
// Merged across multiple rows
|
|
||||||
// Microsoft Excel 2013 does not copy a merged region unless all rows of
|
|
||||||
// the source merged region are selected
|
|
||||||
// POI's behavior should match this behavior
|
|
||||||
col += 2;
|
|
||||||
cell = CellUtil.getCell(destRow, col);
|
|
||||||
// Note: this behavior deviates from Microsoft Excel,
|
|
||||||
// which will not overwrite a cell in destination row if merged region extends beyond the copied row.
|
|
||||||
// The Excel way would require:
|
|
||||||
//assertEquals("[Merged across multiple rows] R7:S8 merged region", "Should NOT be overwritten", cell.getStringCellValue());
|
|
||||||
//assertFalse("[Merged across multiple rows] R7:S8 merged region",
|
|
||||||
// sheet.getMergedRegions().contains(CellRangeAddress.valueOf("R7:S8")));
|
|
||||||
// As currently implemented, cell value is copied but merged region is not copied
|
|
||||||
assertEquals("Merged cells across multiple rows", cell.getStringCellValue(), "[Merged across multiple rows] R7:S8 cell value");
|
|
||||||
// shouldn't do 1-row merge
|
|
||||||
assertFalse(sheet.getMergedRegions().contains(CellRangeAddress.valueOf("R7:S7")), "[Merged across multiple rows] R7:S7 merged region (one row)");
|
|
||||||
//shouldn't do 2-row merge
|
|
||||||
assertFalse(sheet.getMergedRegions().contains(CellRangeAddress.valueOf("R7:S8")), "[Merged across multiple rows] R7:S8 merged region");
|
|
||||||
|
|
||||||
// Make sure other rows are blank (off-by-one errors)
|
|
||||||
assertNull(sheet.getRow(5));
|
|
||||||
assertNull(sheet.getRow(7));
|
|
||||||
|
|
||||||
wb.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testCopyMultipleRows(String copyRowsTestWorkbook) throws IOException {
|
|
||||||
final double FLOAT_PRECISION = 1e-9;
|
|
||||||
final XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook(copyRowsTestWorkbook);
|
|
||||||
final XSSFSheet sheet = wb.getSheetAt(0);
|
|
||||||
final CellCopyPolicy defaultCopyPolicy = new CellCopyPolicy();
|
|
||||||
sheet.copyRows(0, 3, 8, defaultCopyPolicy);
|
|
||||||
|
|
||||||
sheet.getRow(0);
|
|
||||||
final Row srcRow1 = sheet.getRow(1);
|
|
||||||
final Row srcRow2 = sheet.getRow(2);
|
|
||||||
final Row srcRow3 = sheet.getRow(3);
|
|
||||||
final Row destHeaderRow = sheet.getRow(8);
|
|
||||||
final Row destRow1 = sheet.getRow(9);
|
|
||||||
final Row destRow2 = sheet.getRow(10);
|
|
||||||
final Row destRow3 = sheet.getRow(11);
|
|
||||||
int col = 0;
|
|
||||||
Cell cell;
|
|
||||||
|
|
||||||
// Header row should be copied
|
|
||||||
assertNotNull(destHeaderRow);
|
|
||||||
|
|
||||||
// Data rows
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals("Source row ->", cell.getStringCellValue());
|
|
||||||
|
|
||||||
// Style
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals("Red", cell.getStringCellValue(), "[Style] B10 cell value");
|
|
||||||
assertEquals(CellUtil.getCell(srcRow1, 1).getCellStyle(), cell.getCellStyle(), "[Style] B10 cell style");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
assertEquals("Blue", cell.getStringCellValue(), "[Style] B11 cell value");
|
|
||||||
assertEquals(CellUtil.getCell(srcRow2, 1).getCellStyle(), cell.getCellStyle(), "[Style] B11 cell style");
|
|
||||||
|
|
||||||
// Blank
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals(CellType.BLANK, cell.getCellType(), "[Blank] C10 cell type");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
assertEquals(CellType.BLANK, cell.getCellType(), "[Blank] C11 cell type");
|
|
||||||
|
|
||||||
// Error
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
FormulaError error = FormulaError.forInt(cell.getErrorCellValue());
|
|
||||||
//FIXME: XSSFCell and HSSFCell expose different interfaces. getErrorCellString would be helpful here
|
|
||||||
assertEquals(CellType.ERROR, cell.getCellType(), "[Error] D10 cell type");
|
|
||||||
assertEquals(FormulaError.NA, error, "[Error] D10 cell value");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
error = FormulaError.forInt(cell.getErrorCellValue());
|
|
||||||
//FIXME: XSSFCell and HSSFCell expose different interfaces. getErrorCellString would be helpful here
|
|
||||||
assertEquals(CellType.ERROR, cell.getCellType(), "[Error] D11 cell type");
|
|
||||||
assertEquals(FormulaError.NAME, error, "[Error] D11 cell value");
|
|
||||||
|
|
||||||
// Date
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
Date date = LocaleUtil.getLocaleCalendar(2000, Calendar.JANUARY, 1).getTime();
|
|
||||||
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Date] E10 cell type");
|
|
||||||
assertEquals(date, cell.getDateCellValue(), "[Date] E10 cell value");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
date = LocaleUtil.getLocaleCalendar(2000, Calendar.JANUARY, 2).getTime();
|
|
||||||
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Date] E11 cell type");
|
|
||||||
assertEquals(date, cell.getDateCellValue(), "[Date] E11 cell value");
|
|
||||||
|
|
||||||
// Boolean
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals(CellType.BOOLEAN, cell.getCellType(), "[Boolean] F10 cell type");
|
|
||||||
assertTrue(cell.getBooleanCellValue(), "[Boolean] F10 cell value");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
assertEquals(CellType.BOOLEAN, cell.getCellType(), "[Boolean] F11 cell type");
|
|
||||||
assertFalse(cell.getBooleanCellValue(), "[Boolean] F11 cell value");
|
|
||||||
|
|
||||||
// String
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals(CellType.STRING, cell.getCellType(), "[String] G10 cell type");
|
|
||||||
assertEquals("Hello", cell.getStringCellValue(), "[String] G10 cell value");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
assertEquals(CellType.STRING, cell.getCellType(), "[String] G11 cell type");
|
|
||||||
assertEquals("World", cell.getStringCellValue(), "[String] G11 cell value");
|
|
||||||
|
|
||||||
// Int
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Int] H10 cell type");
|
|
||||||
assertEquals(15, (int) cell.getNumericCellValue(), "[Int] H10 cell value");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Int] H11 cell type");
|
|
||||||
assertEquals(42, (int) cell.getNumericCellValue(), "[Int] H11 cell value");
|
|
||||||
|
|
||||||
// Float
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Float] I10 cell type");
|
|
||||||
assertEquals(12.5, cell.getNumericCellValue(), FLOAT_PRECISION, "[Float] I10 cell value");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Float] I11 cell type");
|
|
||||||
assertEquals(5.5, cell.getNumericCellValue(), FLOAT_PRECISION, "[Float] I11 cell value");
|
|
||||||
|
|
||||||
// Cell Formula
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula] J10 cell type");
|
|
||||||
assertEquals("5+2", cell.getCellFormula(), "[Cell Formula] J10 cell formula");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula] J11 cell type");
|
|
||||||
assertEquals("6+18", cell.getCellFormula(), "[Cell Formula] J11 cell formula");
|
|
||||||
|
|
||||||
// Cell Formula with Reference
|
|
||||||
col++;
|
|
||||||
// Formula row references should be adjusted by destRowNum-srcRowNum
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Reference] K10 cell type");
|
|
||||||
assertEquals("J10+H$2", cell.getCellFormula(), "[Cell Formula with Reference] K10 cell formula");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Reference] K11 cell type");
|
|
||||||
assertEquals("J11+H$2", cell.getCellFormula(), "[Cell Formula with Reference] K11 cell formula");
|
|
||||||
|
|
||||||
// Cell Formula with Reference spanning multiple rows
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Reference spanning multiple rows] L10 cell type");
|
|
||||||
assertEquals("G10&\" \"&G11", cell.getCellFormula(), "[Cell Formula with Reference spanning multiple rows] L10 cell formula");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Reference spanning multiple rows] L11 cell type");
|
|
||||||
assertEquals("G11&\" \"&G12", cell.getCellFormula(), "[Cell Formula with Reference spanning multiple rows] L11 cell formula");
|
|
||||||
|
|
||||||
// Cell Formula with Area Reference
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Area Reference] M10 cell type");
|
|
||||||
assertEquals("SUM(H10:I11)", cell.getCellFormula(), "[Cell Formula with Area Reference] M10 cell formula");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
// Also acceptable: SUM($H10:I$3), but this AreaReference isn't in ascending order
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Area Reference] M11 cell type");
|
|
||||||
assertEquals("SUM($H$3:I10)", cell.getCellFormula(), "[Cell Formula with Area Reference] M11 cell formula");
|
|
||||||
|
|
||||||
// Array Formula
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
// System.out.println("Array formulas currently unsupported");
|
|
||||||
/*
|
|
||||||
// FIXME: Array Formula set with Sheet.setArrayFormula() instead of cell.setFormula()
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(), "[Array Formula] N10 cell type");
|
|
||||||
assertEquals("{SUM(H10:J10*{1,2,3})}", cell.getCellFormula(), "[Array Formula] N10 cell formula");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
// FIXME: Array Formula set with Sheet.setArrayFormula() instead of cell.setFormula()
|
|
||||||
assertEquals(CellType.FORMULA, cell.getCellType(). "[Array Formula] N11 cell type");
|
|
||||||
assertEquals("{SUM(H11:J11*{1,2,3})}", cell.getCellFormula(). "[Array Formula] N11 cell formula");
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Data Format
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Data Format] O10 cell type");
|
|
||||||
assertEquals(100.20, cell.getNumericCellValue(), FLOAT_PRECISION, "[Data Format] O10 cell value");
|
|
||||||
final String moneyFormat = "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)";
|
|
||||||
assertEquals(moneyFormat, cell.getCellStyle().getDataFormatString(), "[Data Format] O10 cell data format");
|
|
||||||
|
|
||||||
// Merged
|
|
||||||
col++;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals("Merged cells", cell.getStringCellValue(), "[Merged] P10:Q10 cell value");
|
|
||||||
assertTrue(sheet.getMergedRegions().contains(CellRangeAddress.valueOf("P10:Q10")), "[Merged] P10:Q10 merged region");
|
|
||||||
|
|
||||||
cell = CellUtil.getCell(destRow2, col);
|
|
||||||
assertEquals("Merged cells", cell.getStringCellValue(), "[Merged] P11:Q11 cell value");
|
|
||||||
assertTrue(sheet.getMergedRegions().contains(CellRangeAddress.valueOf("P11:Q11")), "[Merged] P11:Q11 merged region");
|
|
||||||
|
|
||||||
// Should Q10/Q11 be checked?
|
|
||||||
|
|
||||||
// Merged across multiple rows
|
|
||||||
// Microsoft Excel 2013 does not copy a merged region unless all rows of
|
|
||||||
// the source merged region are selected
|
|
||||||
// POI's behavior should match this behavior
|
|
||||||
col += 2;
|
|
||||||
cell = CellUtil.getCell(destRow1, col);
|
|
||||||
assertEquals("Merged cells across multiple rows", cell.getStringCellValue(), "[Merged across multiple rows] R10:S11 cell value");
|
|
||||||
assertTrue(sheet.getMergedRegions().contains(CellRangeAddress.valueOf("R10:S11")), "[Merged across multiple rows] R10:S11 merged region");
|
|
||||||
|
|
||||||
// Row 3 (zero-based) was empty, so Row 11 (zero-based) should be empty too.
|
|
||||||
if (srcRow3 == null) {
|
|
||||||
assertNull(destRow3, "Row 3 was empty, so Row 11 should be empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure other rows are blank (off-by-one errors)
|
|
||||||
assertNull(sheet.getRow(7), "Off-by-one lower edge case"); //one row above destHeaderRow
|
|
||||||
assertNull(sheet.getRow(12), "Off-by-one upper edge case"); //one row below destRow3
|
|
||||||
|
|
||||||
wb.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCopyOneRow() throws IOException {
|
void testCopyOneRow() throws IOException {
|
||||||
testCopyOneRow("XSSFSheet.copyRows.xlsx");
|
final double FLOAT_PRECISION = 1e-9;
|
||||||
|
try (final XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("XSSFSheet.copyRows.xlsx")) {
|
||||||
|
final XSSFSheet sheet = wb.getSheetAt(0);
|
||||||
|
final CellCopyPolicy defaultCopyPolicy = new CellCopyPolicy();
|
||||||
|
sheet.copyRows(1, 1, 6, defaultCopyPolicy);
|
||||||
|
|
||||||
|
final Row srcRow = sheet.getRow(1);
|
||||||
|
final Row destRow = sheet.getRow(6);
|
||||||
|
int col = 0;
|
||||||
|
Cell cell;
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals("Source row ->", cell.getStringCellValue());
|
||||||
|
|
||||||
|
// Style
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals("Red", cell.getStringCellValue(), "[Style] B7 cell value");
|
||||||
|
assertEquals(CellUtil.getCell(srcRow, 1).getCellStyle(), cell.getCellStyle(), "[Style] B7 cell style");
|
||||||
|
|
||||||
|
// Blank
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals(CellType.BLANK, cell.getCellType(), "[Blank] C7 cell type");
|
||||||
|
|
||||||
|
// Error
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals(CellType.ERROR, cell.getCellType(), "[Error] D7 cell type");
|
||||||
|
final FormulaError error = FormulaError.forInt(cell.getErrorCellValue());
|
||||||
|
//FIXME: XSSFCell and HSSFCell expose different interfaces. getErrorCellString would be helpful here
|
||||||
|
assertEquals(FormulaError.NA, error, "[Error] D7 cell value");
|
||||||
|
|
||||||
|
// Date
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Date] E7 cell type");
|
||||||
|
final Date date = LocaleUtil.getLocaleCalendar(2000, Calendar.JANUARY, 1).getTime();
|
||||||
|
assertEquals(date, cell.getDateCellValue(), "[Date] E7 cell value");
|
||||||
|
|
||||||
|
// Boolean
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals(CellType.BOOLEAN, cell.getCellType(), "[Boolean] F7 cell type");
|
||||||
|
assertTrue(cell.getBooleanCellValue(), "[Boolean] F7 cell value");
|
||||||
|
|
||||||
|
// String
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals(CellType.STRING, cell.getCellType(), "[String] G7 cell type");
|
||||||
|
assertEquals("Hello", cell.getStringCellValue(), "[String] G7 cell value");
|
||||||
|
|
||||||
|
// Int
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Int] H7 cell type");
|
||||||
|
assertEquals(15, (int) cell.getNumericCellValue(), "[Int] H7 cell value");
|
||||||
|
|
||||||
|
// Float
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Float] I7 cell type");
|
||||||
|
assertEquals(12.5, cell.getNumericCellValue(), FLOAT_PRECISION, "[Float] I7 cell value");
|
||||||
|
|
||||||
|
// Cell Formula
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals("Sheet1!J7", new CellReference(cell).formatAsString());
|
||||||
|
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula] J7 cell type");
|
||||||
|
assertEquals("5+2", cell.getCellFormula(), "[Cell Formula] J7 cell formula");
|
||||||
|
//System.out.println("Cell formula evaluation currently unsupported");
|
||||||
|
|
||||||
|
// Cell Formula with Reference
|
||||||
|
// Formula row references should be adjusted by destRowNum-srcRowNum
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals("Sheet1!K7", new CellReference(cell).formatAsString());
|
||||||
|
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Reference] K7 cell type");
|
||||||
|
assertEquals("J7+H$2", cell.getCellFormula(), "[Cell Formula with Reference] K7 cell formula");
|
||||||
|
|
||||||
|
// Cell Formula with Reference spanning multiple rows
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Reference spanning multiple rows] L7 cell type");
|
||||||
|
assertEquals("G7&\" \"&G8", cell.getCellFormula(), "[Cell Formula with Reference spanning multiple rows] L7 cell formula");
|
||||||
|
|
||||||
|
// Cell Formula with Reference spanning multiple rows
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Area Reference] M7 cell type");
|
||||||
|
assertEquals("SUM(H7:I8)", cell.getCellFormula(), "[Cell Formula with Area Reference] M7 cell formula");
|
||||||
|
|
||||||
|
// Array Formula
|
||||||
|
col++;
|
||||||
|
// cell = CellUtil.getCell(destRow, col++);
|
||||||
|
// Array formulas currently unsupported"
|
||||||
|
// FIXME: Array Formula set with Sheet.setArrayFormula() instead of cell.setFormula()
|
||||||
|
// assertEquals(CellType.FORMULA, cell.getCellType(), "[Array Formula] N7 cell type");
|
||||||
|
// assertEquals("{SUM(H7:J7*{1,2,3})}", cell.getCellFormula(), "[Array Formula] N7 cell formula");
|
||||||
|
|
||||||
|
// Data Format
|
||||||
|
cell = CellUtil.getCell(destRow, col++);
|
||||||
|
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Data Format] O7 cell type");
|
||||||
|
assertEquals(100.20, cell.getNumericCellValue(), FLOAT_PRECISION, "[Data Format] O7 cell value");
|
||||||
|
//FIXME: currently fails
|
||||||
|
final String moneyFormat = "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)";
|
||||||
|
assertEquals(moneyFormat, cell.getCellStyle().getDataFormatString(), "[Data Format] O7 data format");
|
||||||
|
|
||||||
|
// Merged
|
||||||
|
cell = CellUtil.getCell(destRow, col);
|
||||||
|
assertEquals("Merged cells", cell.getStringCellValue(), "[Merged] P7:Q7 cell value");
|
||||||
|
assertTrue(sheet.getMergedRegions().contains(CellRangeAddress.valueOf("P7:Q7")), "[Merged] P7:Q7 merged region");
|
||||||
|
|
||||||
|
// Merged across multiple rows
|
||||||
|
// Microsoft Excel 2013 does not copy a merged region unless all rows of
|
||||||
|
// the source merged region are selected
|
||||||
|
// POI's behavior should match this behavior
|
||||||
|
col += 2;
|
||||||
|
cell = CellUtil.getCell(destRow, col);
|
||||||
|
// Note: this behavior deviates from Microsoft Excel,
|
||||||
|
// which will not overwrite a cell in destination row if merged region extends beyond the copied row.
|
||||||
|
// The Excel way would require:
|
||||||
|
//assertEquals("[Merged across multiple rows] R7:S8 merged region", "Should NOT be overwritten", cell.getStringCellValue());
|
||||||
|
//assertFalse("[Merged across multiple rows] R7:S8 merged region",
|
||||||
|
// sheet.getMergedRegions().contains(CellRangeAddress.valueOf("R7:S8")));
|
||||||
|
// As currently implemented, cell value is copied but merged region is not copied
|
||||||
|
assertEquals("Merged cells across multiple rows", cell.getStringCellValue(), "[Merged across multiple rows] R7:S8 cell value");
|
||||||
|
// shouldn't do 1-row merge
|
||||||
|
assertFalse(sheet.getMergedRegions().contains(CellRangeAddress.valueOf("R7:S7")), "[Merged across multiple rows] R7:S7 merged region (one row)");
|
||||||
|
//shouldn't do 2-row merge
|
||||||
|
assertFalse(sheet.getMergedRegions().contains(CellRangeAddress.valueOf("R7:S8")), "[Merged across multiple rows] R7:S8 merged region");
|
||||||
|
|
||||||
|
// Make sure other rows are blank (off-by-one errors)
|
||||||
|
assertNull(sheet.getRow(5));
|
||||||
|
assertNull(sheet.getRow(7));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCopyMultipleRows() throws IOException {
|
void testCopyMultipleRows() throws IOException {
|
||||||
testCopyMultipleRows("XSSFSheet.copyRows.xlsx");
|
final double FLOAT_PRECISION = 1e-9;
|
||||||
|
try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("XSSFSheet.copyRows.xlsx")) {
|
||||||
|
final XSSFSheet sheet = wb.getSheetAt(0);
|
||||||
|
final CellCopyPolicy defaultCopyPolicy = new CellCopyPolicy();
|
||||||
|
sheet.copyRows(0, 3, 8, defaultCopyPolicy);
|
||||||
|
|
||||||
|
sheet.getRow(0);
|
||||||
|
final Row srcRow1 = sheet.getRow(1);
|
||||||
|
final Row srcRow2 = sheet.getRow(2);
|
||||||
|
final Row srcRow3 = sheet.getRow(3);
|
||||||
|
final Row destHeaderRow = sheet.getRow(8);
|
||||||
|
final Row destRow1 = sheet.getRow(9);
|
||||||
|
final Row destRow2 = sheet.getRow(10);
|
||||||
|
final Row destRow3 = sheet.getRow(11);
|
||||||
|
int col = 0;
|
||||||
|
Cell cell;
|
||||||
|
|
||||||
|
// Header row should be copied
|
||||||
|
assertNotNull(destHeaderRow);
|
||||||
|
|
||||||
|
// Data rows
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals("Source row ->", cell.getStringCellValue());
|
||||||
|
|
||||||
|
// Style
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals("Red", cell.getStringCellValue(), "[Style] B10 cell value");
|
||||||
|
assertEquals(CellUtil.getCell(srcRow1, 1).getCellStyle(), cell.getCellStyle(), "[Style] B10 cell style");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
assertEquals("Blue", cell.getStringCellValue(), "[Style] B11 cell value");
|
||||||
|
assertEquals(CellUtil.getCell(srcRow2, 1).getCellStyle(), cell.getCellStyle(), "[Style] B11 cell style");
|
||||||
|
|
||||||
|
// Blank
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals(CellType.BLANK, cell.getCellType(), "[Blank] C10 cell type");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
assertEquals(CellType.BLANK, cell.getCellType(), "[Blank] C11 cell type");
|
||||||
|
|
||||||
|
// Error
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
FormulaError error = FormulaError.forInt(cell.getErrorCellValue());
|
||||||
|
//FIXME: XSSFCell and HSSFCell expose different interfaces. getErrorCellString would be helpful here
|
||||||
|
assertEquals(CellType.ERROR, cell.getCellType(), "[Error] D10 cell type");
|
||||||
|
assertEquals(FormulaError.NA, error, "[Error] D10 cell value");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
error = FormulaError.forInt(cell.getErrorCellValue());
|
||||||
|
//FIXME: XSSFCell and HSSFCell expose different interfaces. getErrorCellString would be helpful here
|
||||||
|
assertEquals(CellType.ERROR, cell.getCellType(), "[Error] D11 cell type");
|
||||||
|
assertEquals(FormulaError.NAME, error, "[Error] D11 cell value");
|
||||||
|
|
||||||
|
// Date
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
Date date = LocaleUtil.getLocaleCalendar(2000, Calendar.JANUARY, 1).getTime();
|
||||||
|
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Date] E10 cell type");
|
||||||
|
assertEquals(date, cell.getDateCellValue(), "[Date] E10 cell value");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
date = LocaleUtil.getLocaleCalendar(2000, Calendar.JANUARY, 2).getTime();
|
||||||
|
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Date] E11 cell type");
|
||||||
|
assertEquals(date, cell.getDateCellValue(), "[Date] E11 cell value");
|
||||||
|
|
||||||
|
// Boolean
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals(CellType.BOOLEAN, cell.getCellType(), "[Boolean] F10 cell type");
|
||||||
|
assertTrue(cell.getBooleanCellValue(), "[Boolean] F10 cell value");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
assertEquals(CellType.BOOLEAN, cell.getCellType(), "[Boolean] F11 cell type");
|
||||||
|
assertFalse(cell.getBooleanCellValue(), "[Boolean] F11 cell value");
|
||||||
|
|
||||||
|
// String
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals(CellType.STRING, cell.getCellType(), "[String] G10 cell type");
|
||||||
|
assertEquals("Hello", cell.getStringCellValue(), "[String] G10 cell value");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
assertEquals(CellType.STRING, cell.getCellType(), "[String] G11 cell type");
|
||||||
|
assertEquals("World", cell.getStringCellValue(), "[String] G11 cell value");
|
||||||
|
|
||||||
|
// Int
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Int] H10 cell type");
|
||||||
|
assertEquals(15, (int) cell.getNumericCellValue(), "[Int] H10 cell value");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Int] H11 cell type");
|
||||||
|
assertEquals(42, (int) cell.getNumericCellValue(), "[Int] H11 cell value");
|
||||||
|
|
||||||
|
// Float
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Float] I10 cell type");
|
||||||
|
assertEquals(12.5, cell.getNumericCellValue(), FLOAT_PRECISION, "[Float] I10 cell value");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Float] I11 cell type");
|
||||||
|
assertEquals(5.5, cell.getNumericCellValue(), FLOAT_PRECISION, "[Float] I11 cell value");
|
||||||
|
|
||||||
|
// Cell Formula
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula] J10 cell type");
|
||||||
|
assertEquals("5+2", cell.getCellFormula(), "[Cell Formula] J10 cell formula");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula] J11 cell type");
|
||||||
|
assertEquals("6+18", cell.getCellFormula(), "[Cell Formula] J11 cell formula");
|
||||||
|
|
||||||
|
// Cell Formula with Reference
|
||||||
|
col++;
|
||||||
|
// Formula row references should be adjusted by destRowNum-srcRowNum
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Reference] K10 cell type");
|
||||||
|
assertEquals("J10+H$2", cell.getCellFormula(), "[Cell Formula with Reference] K10 cell formula");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Reference] K11 cell type");
|
||||||
|
assertEquals("J11+H$2", cell.getCellFormula(), "[Cell Formula with Reference] K11 cell formula");
|
||||||
|
|
||||||
|
// Cell Formula with Reference spanning multiple rows
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Reference spanning multiple rows] L10 cell type");
|
||||||
|
assertEquals("G10&\" \"&G11", cell.getCellFormula(), "[Cell Formula with Reference spanning multiple rows] L10 cell formula");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Reference spanning multiple rows] L11 cell type");
|
||||||
|
assertEquals("G11&\" \"&G12", cell.getCellFormula(), "[Cell Formula with Reference spanning multiple rows] L11 cell formula");
|
||||||
|
|
||||||
|
// Cell Formula with Area Reference
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Area Reference] M10 cell type");
|
||||||
|
assertEquals("SUM(H10:I11)", cell.getCellFormula(), "[Cell Formula with Area Reference] M10 cell formula");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
// Also acceptable: SUM($H10:I$3), but this AreaReference isn't in ascending order
|
||||||
|
assertEquals(CellType.FORMULA, cell.getCellType(), "[Cell Formula with Area Reference] M11 cell type");
|
||||||
|
assertEquals("SUM($H$3:I10)", cell.getCellFormula(), "[Cell Formula with Area Reference] M11 cell formula");
|
||||||
|
|
||||||
|
// Array Formula
|
||||||
|
col++;
|
||||||
|
// cell = CellUtil.getCell(destRow1, col);
|
||||||
|
// Array formulas currently unsupported
|
||||||
|
// FIXME: Array Formula set with Sheet.setArrayFormula() instead of cell.setFormula()
|
||||||
|
// assertEquals(CellType.FORMULA, cell.getCellType(), "[Array Formula] N10 cell type");
|
||||||
|
// assertEquals("{SUM(H10:J10*{1,2,3})}", cell.getCellFormula(), "[Array Formula] N10 cell formula");
|
||||||
|
|
||||||
|
// cell = CellUtil.getCell(destRow2, col);
|
||||||
|
// FIXME: Array Formula set with Sheet.setArrayFormula() instead of cell.setFormula()
|
||||||
|
// assertEquals(CellType.FORMULA, cell.getCellType(). "[Array Formula] N11 cell type");
|
||||||
|
// assertEquals("{SUM(H11:J11*{1,2,3})}", cell.getCellFormula(). "[Array Formula] N11 cell formula");
|
||||||
|
|
||||||
|
// Data Format
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
assertEquals(CellType.NUMERIC, cell.getCellType(), "[Data Format] O10 cell type");
|
||||||
|
assertEquals(100.20, cell.getNumericCellValue(), FLOAT_PRECISION, "[Data Format] O10 cell value");
|
||||||
|
final String moneyFormat = "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)";
|
||||||
|
assertEquals(moneyFormat, cell.getCellStyle().getDataFormatString(), "[Data Format] O10 cell data format");
|
||||||
|
|
||||||
|
// Merged
|
||||||
|
col++;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals("Merged cells", cell.getStringCellValue(), "[Merged] P10:Q10 cell value");
|
||||||
|
assertTrue(sheet.getMergedRegions().contains(CellRangeAddress.valueOf("P10:Q10")), "[Merged] P10:Q10 merged region");
|
||||||
|
|
||||||
|
cell = CellUtil.getCell(destRow2, col);
|
||||||
|
assertEquals("Merged cells", cell.getStringCellValue(), "[Merged] P11:Q11 cell value");
|
||||||
|
assertTrue(sheet.getMergedRegions().contains(CellRangeAddress.valueOf("P11:Q11")), "[Merged] P11:Q11 merged region");
|
||||||
|
|
||||||
|
// Should Q10/Q11 be checked?
|
||||||
|
|
||||||
|
// Merged across multiple rows
|
||||||
|
// Microsoft Excel 2013 does not copy a merged region unless all rows of
|
||||||
|
// the source merged region are selected
|
||||||
|
// POI's behavior should match this behavior
|
||||||
|
col += 2;
|
||||||
|
cell = CellUtil.getCell(destRow1, col);
|
||||||
|
assertEquals("Merged cells across multiple rows", cell.getStringCellValue(), "[Merged across multiple rows] R10:S11 cell value");
|
||||||
|
assertTrue(sheet.getMergedRegions().contains(CellRangeAddress.valueOf("R10:S11")), "[Merged across multiple rows] R10:S11 merged region");
|
||||||
|
|
||||||
|
// Row 3 (zero-based) was empty, so Row 11 (zero-based) should be empty too.
|
||||||
|
if (srcRow3 == null) {
|
||||||
|
assertNull(destRow3, "Row 3 was empty, so Row 11 should be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure other rows are blank (off-by-one errors)
|
||||||
|
assertNull(sheet.getRow(7), "Off-by-one lower edge case"); //one row above destHeaderRow
|
||||||
|
assertNull(sheet.getRow(12), "Off-by-one upper edge case"); //one row below destRow3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1998,26 +1985,34 @@ public final class TestXSSFSheet extends BaseTestXSheet {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void bug65120() throws IOException {
|
public void bug65120() throws IOException {
|
||||||
XSSFWorkbook wb = new XSSFWorkbook();
|
try (XSSFWorkbook wb = new XSSFWorkbook()) {
|
||||||
CreationHelper creationHelper = wb.getCreationHelper();
|
XSSFCreationHelper creationHelper = wb.getCreationHelper();
|
||||||
|
|
||||||
Sheet sheet1 = wb.createSheet();
|
XSSFSheet sheet1 = wb.createSheet();
|
||||||
Cell cell1 = sheet1.createRow(0).createCell(0);
|
Cell cell1 = sheet1.createRow(0).createCell(0);
|
||||||
Comment comment1 = sheet1.createDrawingPatriarch().createCellComment(creationHelper.createClientAnchor());
|
XSSFDrawing dwg1 = sheet1.createDrawingPatriarch();
|
||||||
cell1.setCellComment(comment1);
|
XSSFComment comment1 = dwg1.createCellComment(creationHelper.createClientAnchor());
|
||||||
|
cell1.setCellComment(comment1);
|
||||||
|
XSSFVMLDrawing vml0 = sheet1.getVMLDrawing(false);
|
||||||
|
assertEquals("/xl/drawings/vmlDrawing0.vml", vml0.getPackagePart().getPartName().getName());
|
||||||
|
|
||||||
Sheet sheet2 = wb.createSheet();
|
XSSFSheet sheet2 = wb.createSheet();
|
||||||
Cell cell2 = sheet2.createRow(0).createCell(0);
|
Cell cell2 = sheet2.createRow(0).createCell(0);
|
||||||
Comment comment2 = sheet2.createDrawingPatriarch().createCellComment(creationHelper.createClientAnchor());
|
XSSFDrawing dwg2 = sheet2.createDrawingPatriarch();
|
||||||
cell2.setCellComment(comment2);
|
Comment comment2 = dwg2.createCellComment(creationHelper.createClientAnchor());
|
||||||
|
cell2.setCellComment(comment2);
|
||||||
|
XSSFVMLDrawing vml1 = sheet2.getVMLDrawing(false);
|
||||||
|
assertEquals("/xl/drawings/vmlDrawing1.vml", vml1.getPackagePart().getPartName().getName());
|
||||||
|
|
||||||
wb.removeSheetAt(0);
|
wb.removeSheetAt(0);
|
||||||
|
|
||||||
Sheet sheet3 = wb.createSheet();
|
XSSFSheet sheet3 = wb.createSheet();
|
||||||
Cell cell3 = sheet3.createRow(0).createCell(0);
|
Cell cell3 = sheet3.createRow(0).createCell(0);
|
||||||
Comment comment3 = sheet3.createDrawingPatriarch().createCellComment(creationHelper.createClientAnchor());
|
XSSFDrawing dwg3 = sheet3.createDrawingPatriarch();
|
||||||
cell3.setCellComment(comment3);
|
Comment comment3 = dwg3.createCellComment(creationHelper.createClientAnchor());
|
||||||
|
cell3.setCellComment(comment3);
|
||||||
wb.close();
|
XSSFVMLDrawing vml2 = sheet3.getVMLDrawing(false);
|
||||||
|
assertEquals("/xl/drawings/vmlDrawing2.vml", vml2.getPackagePart().getPartName().getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -399,18 +399,17 @@ public class HemfPlusBrush {
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getRawData(List<? extends EmfPlusObjectData> continuedObjectData) {
|
public byte[] getRawData(List<? extends EmfPlusObjectData> continuedObjectData) {
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
try {
|
|
||||||
bos.write(getBrushBytes());
|
bos.write(getBrushBytes());
|
||||||
if (continuedObjectData != null) {
|
if (continuedObjectData != null) {
|
||||||
for (EmfPlusObjectData od : continuedObjectData) {
|
for (EmfPlusObjectData od : continuedObjectData) {
|
||||||
bos.write(((EmfPlusBrush)od).getBrushBytes());
|
bos.write(((EmfPlusBrush)od).getBrushBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return bos.toByteArray();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return bos.toByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -445,18 +445,17 @@ public class HemfPlusImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getRawData(List<? extends EmfPlusObjectData> continuedObjectData) {
|
public byte[] getRawData(List<? extends EmfPlusObjectData> continuedObjectData) {
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
try {
|
|
||||||
bos.write(getImageData());
|
bos.write(getImageData());
|
||||||
if (continuedObjectData != null) {
|
if (continuedObjectData != null) {
|
||||||
for (EmfPlusObjectData od : continuedObjectData) {
|
for (EmfPlusObjectData od : continuedObjectData) {
|
||||||
bos.write(((EmfPlusImage)od).getImageData());
|
bos.write(((EmfPlusImage)od).getImageData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return bos.toByteArray();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return bos.toByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.apache.poi.hemf.record.emf.HemfComment.EmfCommentDataMultiformats;
|
||||||
import org.apache.poi.hemf.record.emf.HemfComment.EmfCommentDataPlus;
|
import org.apache.poi.hemf.record.emf.HemfComment.EmfCommentDataPlus;
|
||||||
import org.apache.poi.hemf.record.emf.HemfComment.EmfCommentDataWMF;
|
import org.apache.poi.hemf.record.emf.HemfComment.EmfCommentDataWMF;
|
||||||
import org.apache.poi.hemf.record.emf.HemfRecord;
|
import org.apache.poi.hemf.record.emf.HemfRecord;
|
||||||
|
import org.apache.poi.hemf.record.emfplus.HemfPlusImage;
|
||||||
import org.apache.poi.hemf.record.emfplus.HemfPlusImage.EmfPlusBitmapDataType;
|
import org.apache.poi.hemf.record.emfplus.HemfPlusImage.EmfPlusBitmapDataType;
|
||||||
import org.apache.poi.hemf.record.emfplus.HemfPlusImage.EmfPlusImage;
|
import org.apache.poi.hemf.record.emfplus.HemfPlusImage.EmfPlusImage;
|
||||||
import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObject;
|
import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObject;
|
||||||
|
@ -63,6 +64,10 @@ public class HemfEmbeddedIterator implements Iterator<HwmfEmbedded> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
|
return moveNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean moveNext() {
|
||||||
if (iterStack.isEmpty()) {
|
if (iterStack.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -290,36 +295,33 @@ public class HemfEmbeddedIterator implements Iterator<HwmfEmbedded> {
|
||||||
|
|
||||||
final int objectId = epo.getObjectId();
|
final int objectId = epo.getObjectId();
|
||||||
|
|
||||||
HwmfEmbedded emb = new HwmfEmbedded();
|
final HwmfEmbedded emb = new HwmfEmbedded();
|
||||||
|
|
||||||
EmfPlusImage img = epo.getObjectData();
|
// totalSize is only set, if there are multiple chunks
|
||||||
assert(img.getImageDataType() != null);
|
final int totalSize = epo.getTotalObjectSize() == 0
|
||||||
|
? ((EmfPlusImage)epo.getObjectData()).getImageData().length
|
||||||
int totalSize = epo.getTotalObjectSize();
|
: epo.getTotalObjectSize();
|
||||||
IOUtils.safelyAllocateCheck(totalSize, MAX_RECORD_LENGTH);
|
IOUtils.safelyAllocateCheck(totalSize, MAX_RECORD_LENGTH);
|
||||||
|
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream(epo.getTotalObjectSize());
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream(totalSize)) {
|
||||||
try {
|
boolean hasNext = false;
|
||||||
for (;;) {
|
do {
|
||||||
|
EmfPlusImage img = epo.getObjectData();
|
||||||
|
assert(img.getImageDataType() != null);
|
||||||
|
assert(!hasNext || img.getImageDataType() == HemfPlusImage.EmfPlusImageDataType.CONTINUED);
|
||||||
bos.write(img.getImageData());
|
bos.write(img.getImageData());
|
||||||
|
|
||||||
current = null;
|
current = null;
|
||||||
//noinspection ConstantConditions
|
hasNext = moveNext() &&
|
||||||
if (hasNext() &&
|
|
||||||
(current instanceof EmfPlusObject) &&
|
(current instanceof EmfPlusObject) &&
|
||||||
((epo = (EmfPlusObject) current).getObjectId() == objectId) &&
|
((epo = (EmfPlusObject) current).getObjectId() == objectId) &&
|
||||||
bos.size() < totalSize-16
|
bos.size() < totalSize-16;
|
||||||
) {
|
} while (hasNext);
|
||||||
img = epo.getObjectData();
|
|
||||||
} else {
|
emb.setData(bos.toByteArray());
|
||||||
return emb;
|
return emb;
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
// UnsynchronizedByteArrayOutputStream doesn't throw IOException
|
// UnsynchronizedByteArrayOutputStream doesn't throw IOException
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
|
||||||
emb.setData(bos.toByteArray());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,9 +70,8 @@ public final class PICT extends Metafile {
|
||||||
@Override
|
@Override
|
||||||
public byte[] getData(){
|
public byte[] getData(){
|
||||||
byte[] rawdata = getRawData();
|
byte[] rawdata = getRawData();
|
||||||
try {
|
try (UnsynchronizedByteArrayOutputStream out = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
byte[] macheader = new byte[512];
|
byte[] macheader = new byte[512];
|
||||||
UnsynchronizedByteArrayOutputStream out = new UnsynchronizedByteArrayOutputStream();
|
|
||||||
out.write(macheader);
|
out.write(macheader);
|
||||||
int pos = CHECKSUM_SIZE*getUIDInstanceCount();
|
int pos = CHECKSUM_SIZE*getUIDInstanceCount();
|
||||||
byte[] pict = read(rawdata, pos);
|
byte[] pict = read(rawdata, pos);
|
||||||
|
@ -93,30 +92,33 @@ public final class PICT extends Metafile {
|
||||||
throw new EOFException();
|
throw new EOFException();
|
||||||
}
|
}
|
||||||
byte[] chunk = new byte[4096];
|
byte[] chunk = new byte[4096];
|
||||||
UnsynchronizedByteArrayOutputStream out = new UnsynchronizedByteArrayOutputStream(header.getWmfSize());
|
try (UnsynchronizedByteArrayOutputStream out = new UnsynchronizedByteArrayOutputStream(header.getWmfSize())) {
|
||||||
try (InflaterInputStream inflater = new InflaterInputStream(bis)) {
|
try (InflaterInputStream inflater = new InflaterInputStream(bis)) {
|
||||||
int count;
|
int count;
|
||||||
while ((count = inflater.read(chunk)) >= 0) {
|
while ((count = inflater.read(chunk)) >= 0) {
|
||||||
out.write(chunk, 0, count);
|
out.write(chunk, 0, count);
|
||||||
// PICT zip-stream can be erroneous, so we clear the array to determine
|
// PICT zip-stream can be erroneous, so we clear the array to determine
|
||||||
// the maximum of read bytes, after the inflater crashed
|
// the maximum of read bytes, after the inflater crashed
|
||||||
bytefill(chunk, (byte) 0);
|
bytefill(chunk, (byte) 0);
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
int lastLen;
|
|
||||||
for (lastLen = chunk.length - 1; lastLen >= 0 && chunk[lastLen] == 0; lastLen--) ;
|
|
||||||
if (++lastLen > 0) {
|
|
||||||
if (header.getWmfSize() > out.size()) {
|
|
||||||
// sometimes the wmfsize is smaller than the amount of already successfully read bytes
|
|
||||||
// in this case we take the lastLen as-is, otherwise we truncate it to the given size
|
|
||||||
lastLen = Math.min(lastLen, header.getWmfSize() - out.size());
|
|
||||||
}
|
}
|
||||||
out.write(chunk, 0, lastLen);
|
} catch (Exception e) {
|
||||||
|
int lastLen = chunk.length - 1;
|
||||||
|
while (lastLen >= 0 && chunk[lastLen] == 0) {
|
||||||
|
lastLen--;
|
||||||
|
}
|
||||||
|
if (++lastLen > 0) {
|
||||||
|
if (header.getWmfSize() > out.size()) {
|
||||||
|
// sometimes the wmfsize is smaller than the amount of already successfully read bytes
|
||||||
|
// in this case we take the lastLen as-is, otherwise we truncate it to the given size
|
||||||
|
lastLen = Math.min(lastLen, header.getWmfSize() - out.size());
|
||||||
|
}
|
||||||
|
out.write(chunk, 0, lastLen);
|
||||||
|
}
|
||||||
|
// End of picture marker for PICT is 0x00 0xFF
|
||||||
|
LOG.atError().withThrowable(e).log("PICT zip-stream is invalid, read as much as possible. Uncompressed length of header: {} / Read bytes: {}", box(header.getWmfSize()), box(out.size()));
|
||||||
}
|
}
|
||||||
// End of picture marker for PICT is 0x00 0xFF
|
return out.toByteArray();
|
||||||
LOG.atError().withThrowable(e).log("PICT zip-stream is invalid, read as much as possible. Uncompressed length of header: {} / Read bytes: {}", box(header.getWmfSize()),box(out.size()));
|
|
||||||
}
|
}
|
||||||
return out.toByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -89,12 +89,13 @@ public final class EscherTextboxWrapper extends RecordContainer {
|
||||||
// Write out our children, and stuff them into the Escher layer
|
// Write out our children, and stuff them into the Escher layer
|
||||||
|
|
||||||
// Grab the children's data
|
// Grab the children's data
|
||||||
UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
for (org.apache.poi.hslf.record.Record r : _children) r.writeOut(baos);
|
for (org.apache.poi.hslf.record.Record r : _children) {
|
||||||
byte[] data = baos.toByteArray();
|
r.writeOut(baos);
|
||||||
|
}
|
||||||
// Save in the escher layer
|
// Save in the escher layer
|
||||||
_escherRecord.setData(data);
|
_escherRecord.setData(baos.toByteArray());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,8 +27,8 @@ import java.util.function.Supplier;
|
||||||
import java.util.zip.DeflaterOutputStream;
|
import java.util.zip.DeflaterOutputStream;
|
||||||
import java.util.zip.InflaterInputStream;
|
import java.util.zip.InflaterInputStream;
|
||||||
|
|
||||||
import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
|
|
||||||
import org.apache.commons.io.input.BoundedInputStream;
|
import org.apache.commons.io.input.BoundedInputStream;
|
||||||
|
import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
|
||||||
import org.apache.poi.util.GenericRecordUtil;
|
import org.apache.poi.util.GenericRecordUtil;
|
||||||
import org.apache.poi.util.IOUtils;
|
import org.apache.poi.util.IOUtils;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
@ -124,18 +124,19 @@ public class ExOleObjStg extends PositionDependentRecordAtom implements PersistR
|
||||||
* @param data the embedded data.
|
* @param data the embedded data.
|
||||||
*/
|
*/
|
||||||
public void setData(byte[] data) throws IOException {
|
public void setData(byte[] data) throws IOException {
|
||||||
UnsynchronizedByteArrayOutputStream out = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream out = new UnsynchronizedByteArrayOutputStream();
|
||||||
//first four bytes is the length of the raw data
|
DeflaterOutputStream def = new DeflaterOutputStream(out)) {
|
||||||
byte[] b = new byte[4];
|
//first four bytes is the length of the raw data
|
||||||
LittleEndian.putInt(b, 0, data.length);
|
byte[] b = new byte[4];
|
||||||
out.write(b);
|
LittleEndian.putInt(b, 0, data.length);
|
||||||
|
out.write(b);
|
||||||
|
|
||||||
DeflaterOutputStream def = new DeflaterOutputStream(out);
|
def.write(data, 0, data.length);
|
||||||
def.write(data, 0, data.length);
|
def.finish();
|
||||||
def.finish();
|
// TODO: CHECK if it's correct that DeflaterOutputStream is only finished and not closed?
|
||||||
// TODO: CHECK if it's correct that DeflaterOutputStream is only finished and not closed?
|
_data = out.toByteArray();
|
||||||
_data = out.toByteArray();
|
LittleEndian.putInt(_header, 4, _data.length);
|
||||||
LittleEndian.putInt(_header, 4, _data.length);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -49,7 +49,7 @@ public final class PPDrawingGroup extends RecordAtom {
|
||||||
//cached dgg
|
//cached dgg
|
||||||
private EscherDggRecord dgg;
|
private EscherDggRecord dgg;
|
||||||
|
|
||||||
protected PPDrawingGroup(byte[] source, int start, int len) {
|
PPDrawingGroup(byte[] source, int start, int len) {
|
||||||
// Get the header
|
// Get the header
|
||||||
_header = Arrays.copyOfRange(source, start, start+8);
|
_header = Arrays.copyOfRange(source, start, start+8);
|
||||||
|
|
||||||
|
@ -80,44 +80,44 @@ public final class PPDrawingGroup extends RecordAtom {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeOut(OutputStream out) throws IOException {
|
public void writeOut(OutputStream out) throws IOException {
|
||||||
UnsynchronizedByteArrayOutputStream bout = new UnsynchronizedByteArrayOutputStream();
|
byte[] bstorehead = new byte[8];
|
||||||
for (EscherRecord r : dggContainer) {
|
byte[] recordBytes = new byte[36 + 8];
|
||||||
if (r.getRecordId() == EscherContainerRecord.BSTORE_CONTAINER){
|
try (UnsynchronizedByteArrayOutputStream bout = new UnsynchronizedByteArrayOutputStream();
|
||||||
EscherContainerRecord bstore = (EscherContainerRecord)r;
|
UnsynchronizedByteArrayOutputStream recordBuf = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
|
for (EscherRecord r : dggContainer) {
|
||||||
UnsynchronizedByteArrayOutputStream b2 = new UnsynchronizedByteArrayOutputStream();
|
if (r.getRecordId() == EscherContainerRecord.BSTORE_CONTAINER) {
|
||||||
for (EscherRecord br : bstore) {
|
EscherContainerRecord bstore = (EscherContainerRecord) r;
|
||||||
byte[] b = new byte[36+8];
|
recordBuf.reset();
|
||||||
br.serialize(0, b);
|
for (EscherRecord br : bstore) {
|
||||||
b2.write(b);
|
br.serialize(0, recordBytes);
|
||||||
|
recordBuf.write(recordBytes);
|
||||||
|
}
|
||||||
|
LittleEndian.putShort(bstorehead, 0, bstore.getOptions());
|
||||||
|
LittleEndian.putShort(bstorehead, 2, bstore.getRecordId());
|
||||||
|
LittleEndian.putInt(bstorehead, 4, recordBuf.size());
|
||||||
|
bout.write(bstorehead);
|
||||||
|
recordBuf.writeTo(bout);
|
||||||
|
} else {
|
||||||
|
bout.write(r.serialize());
|
||||||
}
|
}
|
||||||
byte[] bstorehead = new byte[8];
|
|
||||||
LittleEndian.putShort(bstorehead, 0, bstore.getOptions());
|
|
||||||
LittleEndian.putShort(bstorehead, 2, bstore.getRecordId());
|
|
||||||
LittleEndian.putInt(bstorehead, 4, b2.size());
|
|
||||||
bout.write(bstorehead);
|
|
||||||
bout.write(b2.toByteArray());
|
|
||||||
|
|
||||||
} else {
|
|
||||||
bout.write(r.serialize());
|
|
||||||
}
|
}
|
||||||
|
int size = bout.size();
|
||||||
|
|
||||||
|
// Update the size (header bytes 5-8)
|
||||||
|
LittleEndian.putInt(_header, 4, size + 8);
|
||||||
|
|
||||||
|
// Write out our header
|
||||||
|
out.write(_header);
|
||||||
|
|
||||||
|
byte[] dgghead = new byte[8];
|
||||||
|
LittleEndian.putShort(dgghead, 0, dggContainer.getOptions());
|
||||||
|
LittleEndian.putShort(dgghead, 2, dggContainer.getRecordId());
|
||||||
|
LittleEndian.putInt(dgghead, 4, size);
|
||||||
|
out.write(dgghead);
|
||||||
|
|
||||||
|
// Finally, write out the children
|
||||||
|
bout.writeTo(out);
|
||||||
}
|
}
|
||||||
int size = bout.size();
|
|
||||||
|
|
||||||
// Update the size (header bytes 5-8)
|
|
||||||
LittleEndian.putInt(_header,4,size+8);
|
|
||||||
|
|
||||||
// Write out our header
|
|
||||||
out.write(_header);
|
|
||||||
|
|
||||||
byte[] dgghead = new byte[8];
|
|
||||||
LittleEndian.putShort(dgghead, 0, dggContainer.getOptions());
|
|
||||||
LittleEndian.putShort(dgghead, 2, dggContainer.getRecordId());
|
|
||||||
LittleEndian.putInt(dgghead, 4, size);
|
|
||||||
out.write(dgghead);
|
|
||||||
|
|
||||||
// Finally, write out the children
|
|
||||||
bout.writeTo(out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public EscherContainerRecord getDggContainer(){
|
public EscherContainerRecord getDggContainer(){
|
||||||
|
|
|
@ -227,30 +227,30 @@ public abstract class RecordContainer extends Record
|
||||||
*/
|
*/
|
||||||
public void writeOut(byte headerA, byte headerB, long type, Record[] children, OutputStream out) throws IOException {
|
public void writeOut(byte headerA, byte headerB, long type, Record[] children, OutputStream out) throws IOException {
|
||||||
// Create a UnsynchronizedByteArrayOutputStream to hold everything in
|
// Create a UnsynchronizedByteArrayOutputStream to hold everything in
|
||||||
UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
|
|
||||||
// Write out our header, less the size
|
// Write out our header, less the size
|
||||||
baos.write(new byte[] {headerA,headerB});
|
baos.write(new byte[]{headerA, headerB});
|
||||||
byte[] typeB = new byte[2];
|
byte[] typeB = new byte[2];
|
||||||
LittleEndian.putShort(typeB,0,(short)type);
|
LittleEndian.putShort(typeB, 0, (short) type);
|
||||||
baos.write(typeB);
|
baos.write(typeB);
|
||||||
baos.write(new byte[] {0,0,0,0});
|
baos.write(new byte[]{0, 0, 0, 0});
|
||||||
|
|
||||||
// Write out our children
|
// Write out our children
|
||||||
for (Record aChildren : children) {
|
for (Record aChildren : children) {
|
||||||
aChildren.writeOut(baos);
|
aChildren.writeOut(baos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the bytes back
|
||||||
|
byte[] toWrite = baos.toByteArray();
|
||||||
|
|
||||||
|
// Update our header with the size
|
||||||
|
// Don't forget to knock 8 more off, since we don't include the header in the size
|
||||||
|
LittleEndian.putInt(toWrite, 4, (toWrite.length - 8));
|
||||||
|
|
||||||
|
// Write out the bytes
|
||||||
|
out.write(toWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the bytes back
|
|
||||||
byte[] toWrite = baos.toByteArray();
|
|
||||||
|
|
||||||
// Update our header with the size
|
|
||||||
// Don't forget to knock 8 more off, since we don't include the
|
|
||||||
// header in the size
|
|
||||||
LittleEndian.putInt(toWrite,4,(toWrite.length-8));
|
|
||||||
|
|
||||||
// Write out the bytes
|
|
||||||
out.write(toWrite);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -309,22 +309,20 @@ public final class StyleTextPropAtom extends RecordAtom {
|
||||||
*/
|
*/
|
||||||
private void updateRawContents() throws IOException {
|
private void updateRawContents() throws IOException {
|
||||||
if (initialised) {
|
if (initialised) {
|
||||||
// Only update the style bytes, if the styles have been potentially
|
// Only update the style bytes, if the styles have been potentially changed
|
||||||
// changed
|
try (UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
|
// First up, we need to serialise the paragraph properties
|
||||||
|
for (TextPropCollection tpc : paragraphStyles) {
|
||||||
|
tpc.writeOut(baos);
|
||||||
|
}
|
||||||
|
|
||||||
UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream();
|
// Now, we do the character ones
|
||||||
|
for (TextPropCollection tpc : charStyles) {
|
||||||
|
tpc.writeOut(baos);
|
||||||
|
}
|
||||||
|
|
||||||
// First up, we need to serialise the paragraph properties
|
rawContents = baos.toByteArray();
|
||||||
for(TextPropCollection tpc : paragraphStyles) {
|
|
||||||
tpc.writeOut(baos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, we do the character ones
|
|
||||||
for(TextPropCollection tpc : charStyles) {
|
|
||||||
tpc.writeOut(baos);
|
|
||||||
}
|
|
||||||
|
|
||||||
rawContents = baos.toByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now ensure that the header size is correct
|
// Now ensure that the header size is correct
|
||||||
|
|
|
@ -130,26 +130,28 @@ public final class TextSpecInfoAtom extends RecordAtom {
|
||||||
*/
|
*/
|
||||||
public void setParentSize(int size) {
|
public void setParentSize(int size) {
|
||||||
assert(size > 0);
|
assert(size > 0);
|
||||||
int covered = 0;
|
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
|
||||||
TextSpecInfoRun[] runs = getTextSpecInfoRuns();
|
|
||||||
assert(runs.length > 0);
|
|
||||||
for (int i=0; i<runs.length && covered < size; i++) {
|
|
||||||
TextSpecInfoRun run = runs[i];
|
|
||||||
if (covered + run.getLength() > size || i == runs.length-1) {
|
|
||||||
run.setLength(size-covered);
|
|
||||||
}
|
|
||||||
covered += run.getLength();
|
|
||||||
try {
|
|
||||||
run.writeOut(bos);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new HSLFException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_data = bos.toByteArray();
|
|
||||||
|
|
||||||
// Update the size (header bytes 5-8)
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
LittleEndian.putInt(_header, 4, _data.length);
|
TextSpecInfoRun[] runs = getTextSpecInfoRuns();
|
||||||
|
int remaining = size;
|
||||||
|
int idx = 0;
|
||||||
|
for (TextSpecInfoRun run : runs) {
|
||||||
|
int len = run.getLength();
|
||||||
|
if (len > remaining || idx == runs.length - 1) {
|
||||||
|
run.setLength(len = remaining);
|
||||||
|
}
|
||||||
|
remaining -= len;
|
||||||
|
run.writeOut(bos);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_data = bos.toByteArray();
|
||||||
|
|
||||||
|
// Update the size (header bytes 5-8)
|
||||||
|
LittleEndian.putInt(_header, 4, _data.length);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new HSLFException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -110,33 +110,29 @@ public class HwmfEmbeddedIterator implements Iterator<HwmfEmbedded> {
|
||||||
if (!(current instanceof HwmfEscape)) {
|
if (!(current instanceof HwmfEscape)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final HwmfEscape esc = (HwmfEscape)current;
|
|
||||||
assert(esc.getEscapeFunction() == EscapeFunction.META_ESCAPE_ENHANCED_METAFILE);
|
|
||||||
|
|
||||||
WmfEscapeEMF img = esc.getEscapeData();
|
|
||||||
assert(img.isValid());
|
|
||||||
current = null;
|
|
||||||
|
|
||||||
final HwmfEmbedded emb = new HwmfEmbedded();
|
final HwmfEmbedded emb = new HwmfEmbedded();
|
||||||
emb.setEmbeddedType(HwmfEmbeddedType.EMF);
|
emb.setEmbeddedType(HwmfEmbeddedType.EMF);
|
||||||
|
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
try {
|
WmfEscapeEMF img;
|
||||||
for (;;) {
|
do {
|
||||||
bos.write(img.getEmfData());
|
final HwmfEscape esc = (HwmfEscape)current;
|
||||||
|
assert(esc.getEscapeFunction() == EscapeFunction.META_ESCAPE_ENHANCED_METAFILE);
|
||||||
|
|
||||||
|
img = esc.getEscapeData();
|
||||||
|
assert(img.isValid());
|
||||||
|
|
||||||
|
bos.write(img.getEmfData());
|
||||||
current = null;
|
current = null;
|
||||||
if (img.getRemainingBytes() > 0 && hasNext() && (current instanceof HwmfEscape)) {
|
} while (img.getRemainingBytes() > 0 && hasNext() && (current instanceof HwmfEscape));
|
||||||
img = ((HwmfEscape)current).getEscapeData();
|
|
||||||
} else {
|
emb.setData(bos.toByteArray());
|
||||||
return emb;
|
return emb;
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
// UnsynchronizedByteArrayOutputStream doesn't throw IOException
|
// UnsynchronizedByteArrayOutputStream doesn't throw IOException
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
|
||||||
emb.setData(bos.toByteArray());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,8 @@ task cacheTest9(type: Copy) {
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
dependsOn cacheJava9
|
||||||
|
|
||||||
if (JavaVersion.current() == JavaVersion.VERSION_1_8) {
|
if (JavaVersion.current() == JavaVersion.VERSION_1_8) {
|
||||||
into('META-INF/versions/9') {
|
into('META-INF/versions/9') {
|
||||||
from JAVA9_SRC include '*.class'
|
from JAVA9_SRC include '*.class'
|
||||||
|
@ -117,7 +119,7 @@ jar {
|
||||||
|
|
||||||
// Create a separate jar for test-code to depend on it in other projects
|
// Create a separate jar for test-code to depend on it in other projects
|
||||||
// See http://stackoverflow.com/questions/5144325/gradle-test-dependency
|
// See http://stackoverflow.com/questions/5144325/gradle-test-dependency
|
||||||
task testJar(type: Jar, dependsOn: testClasses) {
|
task testJar(type: Jar, dependsOn: [ testClasses, cacheTest9 ]) {
|
||||||
destinationDirectory = file("../build/dist/maven/${project.archivesBaseName}-tests")
|
destinationDirectory = file("../build/dist/maven/${project.archivesBaseName}-tests")
|
||||||
|
|
||||||
classifier 'tests'
|
classifier 'tests'
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class ClassID implements Duplicatable, GenericRecord {
|
||||||
private final byte[] bytes = new byte[LENGTH];
|
private final byte[] bytes = new byte[LENGTH];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link ClassID} and reads its value from a byte array.
|
* Creates a ClassID and reads its value from a byte array.
|
||||||
*
|
*
|
||||||
* @param src The byte array to read from.
|
* @param src The byte array to read from.
|
||||||
* @param offset The offset of the first byte to read.
|
* @param offset The offset of the first byte to read.
|
||||||
|
@ -60,7 +60,7 @@ public class ClassID implements Duplicatable, GenericRecord {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link ClassID} and initializes its value with 0x00 bytes.
|
* Creates a ClassID and initializes its value with 0x00 bytes.
|
||||||
*/
|
*/
|
||||||
public ClassID() {
|
public ClassID() {
|
||||||
Arrays.fill(bytes, (byte)0);
|
Arrays.fill(bytes, (byte)0);
|
||||||
|
@ -77,7 +77,7 @@ public class ClassID implements Duplicatable, GenericRecord {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link ClassID} from a human-readable representation of the Class ID in standard
|
* Creates a ClassID from a human-readable representation of the Class ID in standard
|
||||||
* format {@code "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"}.
|
* format {@code "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"}.
|
||||||
*
|
*
|
||||||
* @param externalForm representation of the Class ID represented by this object.
|
* @param externalForm representation of the Class ID represented by this object.
|
||||||
|
@ -102,12 +102,11 @@ public class ClassID implements Duplicatable, GenericRecord {
|
||||||
/**
|
/**
|
||||||
* @return The number of bytes occupied by this object in the byte stream.
|
* @return The number of bytes occupied by this object in the byte stream.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("java:S1845")
|
||||||
public int length() {
|
public int length() {
|
||||||
return LENGTH;
|
return LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the bytes making out the class ID. They are returned in correct order, i.e. big-endian.
|
* Gets the bytes making out the class ID. They are returned in correct order, i.e. big-endian.
|
||||||
*
|
*
|
||||||
|
@ -117,8 +116,6 @@ public class ClassID implements Duplicatable, GenericRecord {
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the bytes making out the class ID.
|
* Sets the bytes making out the class ID.
|
||||||
*
|
*
|
||||||
|
@ -129,8 +126,6 @@ public class ClassID implements Duplicatable, GenericRecord {
|
||||||
System.arraycopy(bytes, 0, this.bytes, 0, LENGTH);
|
System.arraycopy(bytes, 0, this.bytes, 0, LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the class ID's value from a byte array by turning little-endian into big-endian.
|
* Reads the class ID's value from a byte array by turning little-endian into big-endian.
|
||||||
*
|
*
|
||||||
|
@ -249,10 +244,6 @@ public class ClassID implements Duplicatable, GenericRecord {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see Object#hashCode()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return toString().hashCode();
|
return toString().hashCode();
|
||||||
|
|
|
@ -514,51 +514,52 @@ public class PropertySet {
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] toBytes() throws WritingNotSupportedException, IOException {
|
private byte[] toBytes() throws WritingNotSupportedException, IOException {
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
||||||
LittleEndianOutputStream leos = new LittleEndianOutputStream(bos);
|
LittleEndianOutputStream leos = new LittleEndianOutputStream(bos)) {
|
||||||
|
|
||||||
/* Write the number of sections in this property set stream. */
|
/* Write the number of sections in this property set stream. */
|
||||||
final int nrSections = getSectionCount();
|
final int nrSections = getSectionCount();
|
||||||
|
|
||||||
/* Write the property set's header. */
|
/* Write the property set's header. */
|
||||||
leos.writeShort(getByteOrder());
|
leos.writeShort(getByteOrder());
|
||||||
leos.writeShort(getFormat());
|
leos.writeShort(getFormat());
|
||||||
leos.writeInt(getOSVersion());
|
leos.writeInt(getOSVersion());
|
||||||
putClassId(bos, getClassID());
|
putClassId(bos, getClassID());
|
||||||
leos.writeInt(nrSections);
|
leos.writeInt(nrSections);
|
||||||
|
|
||||||
assert(bos.size() == OFFSET_HEADER);
|
assert (bos.size() == OFFSET_HEADER);
|
||||||
|
|
||||||
final int[][] offsets = new int[getSectionCount()][2];
|
final int[][] offsets = new int[getSectionCount()][2];
|
||||||
|
|
||||||
/* Write the section list, i.e. the references to the sections. Each
|
/* Write the section list, i.e. the references to the sections. Each
|
||||||
* entry in the section list consist of the section's class ID and the
|
* entry in the section list consist of the section's class ID and the
|
||||||
* section's offset relative to the beginning of the stream. */
|
* section's offset relative to the beginning of the stream. */
|
||||||
int secCnt = 0;
|
int secCnt = 0;
|
||||||
for (final Section section : getSections()) {
|
for (final Section section : getSections()) {
|
||||||
final ClassID formatID = section.getFormatID();
|
final ClassID formatID = section.getFormatID();
|
||||||
if (formatID == null) {
|
if (formatID == null) {
|
||||||
throw new NoFormatIDException();
|
throw new NoFormatIDException();
|
||||||
|
}
|
||||||
|
putClassId(bos, formatID);
|
||||||
|
offsets[secCnt++][0] = bos.size();
|
||||||
|
// offset dummy - filled later
|
||||||
|
leos.writeInt(-1);
|
||||||
}
|
}
|
||||||
putClassId(bos, formatID);
|
|
||||||
offsets[secCnt++][0] = bos.size();
|
|
||||||
// offset dummy - filled later
|
|
||||||
leos.writeInt(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write the sections themselves. */
|
/* Write the sections themselves. */
|
||||||
secCnt = 0;
|
secCnt = 0;
|
||||||
for (final Section section : getSections()) {
|
for (final Section section : getSections()) {
|
||||||
offsets[secCnt++][1] = bos.size();
|
offsets[secCnt++][1] = bos.size();
|
||||||
section.write(bos);
|
section.write(bos);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] result = bos.toByteArray();
|
byte[] result = bos.toByteArray();
|
||||||
for (int[] off : offsets) {
|
for (int[] off : offsets) {
|
||||||
LittleEndian.putInt(result, off[0], off[1]);
|
LittleEndian.putInt(result, off[0], off[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -735,53 +735,54 @@ public class Section {
|
||||||
}
|
}
|
||||||
|
|
||||||
final int[][] offsets = new int[properties.size()][2];
|
final int[][] offsets = new int[properties.size()][2];
|
||||||
final UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
||||||
final LittleEndianOutputStream leos = new LittleEndianOutputStream(bos);
|
LittleEndianOutputStream leos = new LittleEndianOutputStream(bos)) {
|
||||||
|
|
||||||
/* Write the section's length - dummy value, fixed later */
|
/* Write the section's length - dummy value, fixed later */
|
||||||
leos.writeInt(-1);
|
|
||||||
|
|
||||||
/* Write the section's number of properties: */
|
|
||||||
leos.writeInt(properties.size());
|
|
||||||
|
|
||||||
int propCnt = 0;
|
|
||||||
for (Property p : properties.values()) {
|
|
||||||
/* Write the property list entry. */
|
|
||||||
leos.writeUInt(p.getID());
|
|
||||||
// dummy offset to be fixed later
|
|
||||||
offsets[propCnt++][0] = bos.size();
|
|
||||||
leos.writeInt(-1);
|
leos.writeInt(-1);
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Write the section's number of properties: */
|
||||||
|
leos.writeInt(properties.size());
|
||||||
|
|
||||||
/* Write the properties and the property list into their respective
|
int propCnt = 0;
|
||||||
* streams: */
|
for (Property p : properties.values()) {
|
||||||
propCnt = 0;
|
/* Write the property list entry. */
|
||||||
for (Property p : properties.values()) {
|
leos.writeUInt(p.getID());
|
||||||
offsets[propCnt++][1] = bos.size();
|
// dummy offset to be fixed later
|
||||||
/* If the property ID is not equal 0 we write the property and all
|
offsets[propCnt++][0] = bos.size();
|
||||||
* is fine. However, if it equals 0 we have to write the section's
|
leos.writeInt(-1);
|
||||||
* dictionary which has an implicit type only and an explicit
|
|
||||||
* value. */
|
|
||||||
if (p.getID() != 0) {
|
|
||||||
/* Write the property and update the position to the next
|
|
||||||
* property. */
|
|
||||||
p.write(bos, codepage);
|
|
||||||
} else {
|
|
||||||
writeDictionary(bos, codepage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write the properties and the property list into their respective
|
||||||
|
* streams: */
|
||||||
|
propCnt = 0;
|
||||||
|
for (Property p : properties.values()) {
|
||||||
|
offsets[propCnt++][1] = bos.size();
|
||||||
|
/* If the property ID is not equal 0 we write the property and all
|
||||||
|
* is fine. However, if it equals 0 we have to write the section's
|
||||||
|
* dictionary which has an implicit type only and an explicit
|
||||||
|
* value. */
|
||||||
|
if (p.getID() != 0) {
|
||||||
|
/* Write the property and update the position to the next
|
||||||
|
* property. */
|
||||||
|
p.write(bos, codepage);
|
||||||
|
} else {
|
||||||
|
writeDictionary(bos, codepage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] result = bos.toByteArray();
|
||||||
|
LittleEndian.putInt(result, 0, bos.size());
|
||||||
|
|
||||||
|
for (int[] off : offsets) {
|
||||||
|
LittleEndian.putUInt(result, off[0], off[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
out.write(result);
|
||||||
|
|
||||||
|
return bos.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] result = bos.toByteArray();
|
|
||||||
LittleEndian.putInt(result, 0, bos.size());
|
|
||||||
|
|
||||||
for (int[] off : offsets) {
|
|
||||||
LittleEndian.putUInt(result, off[0], off[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
out.write(result);
|
|
||||||
|
|
||||||
return bos.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -459,17 +459,20 @@ public final class RecordInputStream implements LittleEndianInput {
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public byte[] readAllContinuedRemainder() {
|
public byte[] readAllContinuedRemainder() {
|
||||||
UnsynchronizedByteArrayOutputStream out = new UnsynchronizedByteArrayOutputStream(2 * MAX_RECORD_DATA_SIZE);
|
try (UnsynchronizedByteArrayOutputStream out = new UnsynchronizedByteArrayOutputStream(2 * MAX_RECORD_DATA_SIZE)) {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
byte[] b = readRemainder();
|
byte[] b = readRemainder();
|
||||||
out.write(b, 0, b.length);
|
out.write(b, 0, b.length);
|
||||||
if (!isContinueNext()) {
|
if (!isContinueNext()) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
nextRecord();
|
||||||
}
|
}
|
||||||
nextRecord();
|
return out.toByteArray();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new RecordFormatException(ex);
|
||||||
}
|
}
|
||||||
return out.toByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The remaining number of bytes in the <i>current</i> record.
|
/** The remaining number of bytes in the <i>current</i> record.
|
||||||
|
|
|
@ -64,8 +64,8 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
* Only newer style formatting rules have priorities. For older ones,
|
* Only newer style formatting rules have priorities. For older ones,
|
||||||
* we don't know priority for these, other than definition/model order,
|
* we don't know priority for these, other than definition/model order,
|
||||||
* which appears to be what Excel uses.
|
* which appears to be what Excel uses.
|
||||||
* @see org.apache.poi.ss.usermodel.ConditionalFormattingRule#getPriority()
|
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int getPriority() {
|
public int getPriority() {
|
||||||
CFRule12Record rule12 = getCFRule12Record(false);
|
CFRule12Record rule12 = getCFRule12Record(false);
|
||||||
if (rule12 == null) return 0;
|
if (rule12 == null) return 0;
|
||||||
|
@ -74,8 +74,8 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Always true for HSSF files, per Microsoft Excel documentation
|
* Always true for HSSF files, per Microsoft Excel documentation
|
||||||
* @see org.apache.poi.ss.usermodel.ConditionalFormattingRule#getStopIfTrue()
|
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean getStopIfTrue() {
|
public boolean getStopIfTrue() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -95,8 +95,8 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Always null for HSSF records, until someone figures out where to find it
|
* Always null for HSSF records, until someone figures out where to find it
|
||||||
* @see org.apache.poi.ss.usermodel.ConditionalFormattingRule#getNumberFormat()
|
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public ExcelNumberFormat getNumberFormat() {
|
public ExcelNumberFormat getNumberFormat() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -112,16 +112,18 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return - font formatting object if defined, <code>null</code> otherwise
|
* @return - font formatting object if defined, {@code null} otherwise
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public HSSFFontFormatting getFontFormatting() {
|
public HSSFFontFormatting getFontFormatting() {
|
||||||
return getFontFormatting(false);
|
return getFontFormatting(false);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* create a new font formatting structure if it does not exist,
|
* create a new font formatting structure if it does not exist,
|
||||||
* otherwise just return existing object.
|
* otherwise just return existing object.
|
||||||
* @return - font formatting object, never returns <code>null</code>.
|
* @return - font formatting object, never returns {@code null}.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public HSSFFontFormatting createFontFormatting() {
|
public HSSFFontFormatting createFontFormatting() {
|
||||||
return getFontFormatting(true);
|
return getFontFormatting(true);
|
||||||
}
|
}
|
||||||
|
@ -137,16 +139,18 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return - border formatting object if defined, <code>null</code> otherwise
|
* @return - border formatting object if defined, {@code null} otherwise
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public HSSFBorderFormatting getBorderFormatting() {
|
public HSSFBorderFormatting getBorderFormatting() {
|
||||||
return getBorderFormatting(false);
|
return getBorderFormatting(false);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* create a new border formatting structure if it does not exist,
|
* create a new border formatting structure if it does not exist,
|
||||||
* otherwise just return existing object.
|
* otherwise just return existing object.
|
||||||
* @return - border formatting object, never returns <code>null</code>.
|
* @return - border formatting object, never returns {@code null}.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public HSSFBorderFormatting createBorderFormatting() {
|
public HSSFBorderFormatting createBorderFormatting() {
|
||||||
return getBorderFormatting(true);
|
return getBorderFormatting(true);
|
||||||
}
|
}
|
||||||
|
@ -162,8 +166,9 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return - pattern formatting object if defined, <code>null</code> otherwise
|
* @return - pattern formatting object if defined, {@code null} otherwise
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public HSSFPatternFormatting getPatternFormatting()
|
public HSSFPatternFormatting getPatternFormatting()
|
||||||
{
|
{
|
||||||
return getPatternFormatting(false);
|
return getPatternFormatting(false);
|
||||||
|
@ -171,8 +176,9 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
/**
|
/**
|
||||||
* create a new pattern formatting structure if it does not exist,
|
* create a new pattern formatting structure if it does not exist,
|
||||||
* otherwise just return existing object.
|
* otherwise just return existing object.
|
||||||
* @return - pattern formatting object, never returns <code>null</code>.
|
* @return - pattern formatting object, never returns {@code null}.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public HSSFPatternFormatting createPatternFormatting()
|
public HSSFPatternFormatting createPatternFormatting()
|
||||||
{
|
{
|
||||||
return getPatternFormatting(true);
|
return getPatternFormatting(true);
|
||||||
|
@ -192,8 +198,9 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return databar / data-bar formatting object if defined, <code>null</code> otherwise
|
* @return databar / data-bar formatting object if defined, {@code null} otherwise
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public HSSFDataBarFormatting getDataBarFormatting() {
|
public HSSFDataBarFormatting getDataBarFormatting() {
|
||||||
return getDataBarFormatting(false);
|
return getDataBarFormatting(false);
|
||||||
}
|
}
|
||||||
|
@ -218,8 +225,9 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return icon / multi-state formatting object if defined, <code>null</code> otherwise
|
* @return icon / multi-state formatting object if defined, {@code null} otherwise
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public HSSFIconMultiStateFormatting getMultiStateFormatting() {
|
public HSSFIconMultiStateFormatting getMultiStateFormatting() {
|
||||||
return getMultiStateFormatting(false);
|
return getMultiStateFormatting(false);
|
||||||
}
|
}
|
||||||
|
@ -245,8 +253,9 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return color scale / gradient formatting object if defined, <code>null</code> otherwise
|
* @return color scale / gradient formatting object if defined, {@code null} otherwise
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public HSSFColorScaleFormatting getColorScaleFormatting() {
|
public HSSFColorScaleFormatting getColorScaleFormatting() {
|
||||||
return getColorScaleFormatting(false);
|
return getColorScaleFormatting(false);
|
||||||
}
|
}
|
||||||
|
@ -270,12 +279,13 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* always null (not a filter condition) or {@link ConditionFilterType#FILTER} if it is.
|
* always null (not a filter condition) or {@link ConditionFilterType#FILTER} if it is.
|
||||||
* @see org.apache.poi.ss.usermodel.ConditionalFormattingRule#getConditionFilterType()
|
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public ConditionFilterType getConditionFilterType() {
|
public ConditionFilterType getConditionFilterType() {
|
||||||
return getConditionType() == ConditionType.FILTER ? ConditionFilterType.FILTER : null;
|
return getConditionType() == ConditionType.FILTER ? ConditionFilterType.FILTER : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ConditionFilterData getFilterConfiguration() {
|
public ConditionFilterData getFilterConfiguration() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -288,11 +298,13 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
return cfRuleRecord.getComparisonOperation();
|
return cfRuleRecord.getComparisonOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getFormula1()
|
public String getFormula1()
|
||||||
{
|
{
|
||||||
return toFormulaString(cfRuleRecord.getParsedExpression1());
|
return toFormulaString(cfRuleRecord.getParsedExpression1());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getFormula2() {
|
public String getFormula2() {
|
||||||
byte conditionType = cfRuleRecord.getConditionType();
|
byte conditionType = cfRuleRecord.getConditionType();
|
||||||
if (conditionType == CELL_COMPARISON) {
|
if (conditionType == CELL_COMPARISON) {
|
||||||
|
@ -306,6 +318,7 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return null; // not available here, unless it exists and is unimplemented in cfRuleRecord
|
return null; // not available here, unless it exists and is unimplemented in cfRuleRecord
|
||||||
}
|
}
|
||||||
|
@ -325,6 +338,7 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
|
||||||
* Conditional format rules don't define stripes, so always 0
|
* Conditional format rules don't define stripes, so always 0
|
||||||
* @see org.apache.poi.ss.usermodel.DifferentialStyleProvider#getStripeSize()
|
* @see org.apache.poi.ss.usermodel.DifferentialStyleProvider#getStripeSize()
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int getStripeSize() {
|
public int getStripeSize() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,32 +31,40 @@ public final class HSSFConditionalFormattingThreshold implements org.apache.poi.
|
||||||
private final HSSFSheet sheet;
|
private final HSSFSheet sheet;
|
||||||
private final HSSFWorkbook workbook;
|
private final HSSFWorkbook workbook;
|
||||||
|
|
||||||
protected HSSFConditionalFormattingThreshold(Threshold threshold, HSSFSheet sheet) {
|
HSSFConditionalFormattingThreshold(Threshold threshold, HSSFSheet sheet) {
|
||||||
this.threshold = threshold;
|
this.threshold = threshold;
|
||||||
this.sheet = sheet;
|
this.sheet = sheet;
|
||||||
this.workbook = sheet.getWorkbook();
|
this.workbook = sheet.getWorkbook();
|
||||||
}
|
}
|
||||||
protected Threshold getThreshold() {
|
|
||||||
|
Threshold getThreshold() {
|
||||||
return threshold;
|
return threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public RangeType getRangeType() {
|
public RangeType getRangeType() {
|
||||||
return RangeType.byId(threshold.getType());
|
return RangeType.byId(threshold.getType());
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void setRangeType(RangeType type) {
|
public void setRangeType(RangeType type) {
|
||||||
threshold.setType((byte)type.id);
|
threshold.setType((byte)type.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getFormula() {
|
public String getFormula() {
|
||||||
return toFormulaString(threshold.getParsedExpression(), workbook);
|
return toFormulaString(threshold.getParsedExpression(), workbook);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void setFormula(String formula) {
|
public void setFormula(String formula) {
|
||||||
threshold.setParsedExpression(parseFormula(formula, sheet));
|
threshold.setParsedExpression(parseFormula(formula, sheet));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Double getValue() {
|
public Double getValue() {
|
||||||
return threshold.getValue();
|
return threshold.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setValue(Double value) {
|
public void setValue(Double value) {
|
||||||
threshold.setValue(value);
|
threshold.setValue(value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,41 +24,46 @@ import org.apache.poi.hssf.record.cf.Threshold;
|
||||||
import org.apache.poi.ss.usermodel.ConditionalFormattingThreshold;
|
import org.apache.poi.ss.usermodel.ConditionalFormattingThreshold;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* High level representation for Icon / Multi-State Formatting
|
* High level representation for Icon / Multi-State Formatting
|
||||||
* component of Conditional Formatting settings
|
* component of Conditional Formatting settings
|
||||||
*/
|
*/
|
||||||
public final class HSSFIconMultiStateFormatting implements org.apache.poi.ss.usermodel.IconMultiStateFormatting {
|
public final class HSSFIconMultiStateFormatting implements org.apache.poi.ss.usermodel.IconMultiStateFormatting {
|
||||||
private final HSSFSheet sheet;
|
private final HSSFSheet sheet;
|
||||||
private final CFRule12Record cfRule12Record;
|
|
||||||
private final IconMultiStateFormatting iconFormatting;
|
private final IconMultiStateFormatting iconFormatting;
|
||||||
|
|
||||||
protected HSSFIconMultiStateFormatting(CFRule12Record cfRule12Record, HSSFSheet sheet) {
|
HSSFIconMultiStateFormatting(CFRule12Record cfRule12Record, HSSFSheet sheet) {
|
||||||
this.sheet = sheet;
|
this.sheet = sheet;
|
||||||
this.cfRule12Record = cfRule12Record;
|
this.iconFormatting = cfRule12Record.getMultiStateFormatting();
|
||||||
this.iconFormatting = this.cfRule12Record.getMultiStateFormatting();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public IconSet getIconSet() {
|
public IconSet getIconSet() {
|
||||||
return iconFormatting.getIconSet();
|
return iconFormatting.getIconSet();
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void setIconSet(IconSet set) {
|
public void setIconSet(IconSet set) {
|
||||||
iconFormatting.setIconSet(set);
|
iconFormatting.setIconSet(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isIconOnly() {
|
public boolean isIconOnly() {
|
||||||
return iconFormatting.isIconOnly();
|
return iconFormatting.isIconOnly();
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void setIconOnly(boolean only) {
|
public void setIconOnly(boolean only) {
|
||||||
iconFormatting.setIconOnly(only);
|
iconFormatting.setIconOnly(only);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isReversed() {
|
public boolean isReversed() {
|
||||||
return iconFormatting.isReversed();
|
return iconFormatting.isReversed();
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void setReversed(boolean reversed) {
|
public void setReversed(boolean reversed) {
|
||||||
iconFormatting.setReversed(reversed);
|
iconFormatting.setReversed(reversed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public HSSFConditionalFormattingThreshold[] getThresholds() {
|
public HSSFConditionalFormattingThreshold[] getThresholds() {
|
||||||
Threshold[] t = iconFormatting.getThresholds();
|
Threshold[] t = iconFormatting.getThresholds();
|
||||||
HSSFConditionalFormattingThreshold[] ht = new HSSFConditionalFormattingThreshold[t.length];
|
HSSFConditionalFormattingThreshold[] ht = new HSSFConditionalFormattingThreshold[t.length];
|
||||||
|
@ -68,6 +73,7 @@ public final class HSSFIconMultiStateFormatting implements org.apache.poi.ss.use
|
||||||
return ht;
|
return ht;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setThresholds(ConditionalFormattingThreshold[] thresholds) {
|
public void setThresholds(ConditionalFormattingThreshold[] thresholds) {
|
||||||
Threshold[] t = new Threshold[thresholds.length];
|
Threshold[] t = new Threshold[thresholds.length];
|
||||||
for (int i=0; i<t.length; i++) {
|
for (int i=0; i<t.length; i++) {
|
||||||
|
@ -76,6 +82,7 @@ public final class HSSFIconMultiStateFormatting implements org.apache.poi.ss.use
|
||||||
iconFormatting.setThresholds(t);
|
iconFormatting.setThresholds(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public HSSFConditionalFormattingThreshold createThreshold() {
|
public HSSFConditionalFormattingThreshold createThreshold() {
|
||||||
return new HSSFConditionalFormattingThreshold(new IconMultiStateThreshold(), sheet);
|
return new HSSFConditionalFormattingThreshold(new IconMultiStateThreshold(), sheet);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ public class HSSFWorkbookFactory implements WorkbookProvider {
|
||||||
*
|
*
|
||||||
* @return The created workbook
|
* @return The created workbook
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public HSSFWorkbook create() {
|
public HSSFWorkbook create() {
|
||||||
return new HSSFWorkbook();
|
return new HSSFWorkbook();
|
||||||
}
|
}
|
||||||
|
@ -66,6 +67,7 @@ public class HSSFWorkbookFactory implements WorkbookProvider {
|
||||||
* Note that in order to properly release resources the
|
* Note that in order to properly release resources the
|
||||||
* Workbook should be closed after use.
|
* Workbook should be closed after use.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public HSSFWorkbook create(final DirectoryNode root, String password) throws IOException {
|
public HSSFWorkbook create(final DirectoryNode root, String password) throws IOException {
|
||||||
boolean passwordSet = false;
|
boolean passwordSet = false;
|
||||||
if (password != null) {
|
if (password != null) {
|
||||||
|
@ -93,6 +95,7 @@ public class HSSFWorkbookFactory implements WorkbookProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("java:S2095")
|
||||||
public Workbook create(File file, String password, boolean readOnly) throws IOException {
|
public Workbook create(File file, String password, boolean readOnly) throws IOException {
|
||||||
boolean passwordSet = false;
|
boolean passwordSet = false;
|
||||||
if (password != null) {
|
if (password != null) {
|
||||||
|
@ -104,11 +107,8 @@ public class HSSFWorkbookFactory implements WorkbookProvider {
|
||||||
try {
|
try {
|
||||||
return new HSSFWorkbook(fs, true);
|
return new HSSFWorkbook(fs, true);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
// we need to close the filesystem
|
// we need to close the filesystem if we encounter an exception to not leak file handles
|
||||||
// if we encounter an exception to
|
|
||||||
// not leak file handles
|
|
||||||
fs.close();
|
fs.close();
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -28,7 +28,7 @@ import javax.crypto.Cipher;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
|
import org.apache.commons.io.input.BoundedInputStream;
|
||||||
import org.apache.poi.EncryptedDocumentException;
|
import org.apache.poi.EncryptedDocumentException;
|
||||||
import org.apache.poi.poifs.crypt.ChunkedCipherInputStream;
|
import org.apache.poi.poifs.crypt.ChunkedCipherInputStream;
|
||||||
import org.apache.poi.poifs.crypt.CryptoFunctions;
|
import org.apache.poi.poifs.crypt.CryptoFunctions;
|
||||||
|
@ -39,11 +39,9 @@ import org.apache.poi.poifs.crypt.EncryptionVerifier;
|
||||||
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||||
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||||
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||||
import org.apache.poi.poifs.filesystem.DocumentNode;
|
|
||||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
import org.apache.poi.util.BitField;
|
import org.apache.poi.util.BitField;
|
||||||
import org.apache.poi.util.BitFieldFactory;
|
import org.apache.poi.util.BitFieldFactory;
|
||||||
import org.apache.commons.io.input.BoundedInputStream;
|
|
||||||
import org.apache.poi.util.IOUtils;
|
import org.apache.poi.util.IOUtils;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.LittleEndianInputStream;
|
import org.apache.poi.util.LittleEndianInputStream;
|
||||||
|
@ -170,14 +168,10 @@ public class CryptoAPIDecryptor extends Decryptor {
|
||||||
*/
|
*/
|
||||||
public POIFSFileSystem getSummaryEntries(DirectoryNode root, String encryptedStream)
|
public POIFSFileSystem getSummaryEntries(DirectoryNode root, String encryptedStream)
|
||||||
throws IOException, GeneralSecurityException {
|
throws IOException, GeneralSecurityException {
|
||||||
DocumentNode es = (DocumentNode) root.getEntry(encryptedStream);
|
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
|
||||||
try (DocumentInputStream dis = root.createDocumentInputStream(es)) {
|
|
||||||
IOUtils.copy(dis, bos);
|
|
||||||
}
|
|
||||||
POIFSFileSystem fsOut = null;
|
POIFSFileSystem fsOut = null;
|
||||||
try (
|
try (
|
||||||
CryptoAPIDocumentInputStream sbis = new CryptoAPIDocumentInputStream(this, bos.toByteArray());
|
DocumentInputStream dis = root.createDocumentInputStream(root.getEntry(encryptedStream));
|
||||||
|
CryptoAPIDocumentInputStream sbis = new CryptoAPIDocumentInputStream(this, IOUtils.toByteArray(dis));
|
||||||
LittleEndianInputStream leis = new LittleEndianInputStream(sbis)
|
LittleEndianInputStream leis = new LittleEndianInputStream(sbis)
|
||||||
) {
|
) {
|
||||||
int streamDescriptorArrayOffset = (int) leis.readUInt();
|
int streamDescriptorArrayOffset = (int) leis.readUInt();
|
||||||
|
|
|
@ -68,6 +68,7 @@ import org.apache.poi.util.StringUtil;
|
||||||
*
|
*
|
||||||
* @since 3.15-beta2
|
* @since 3.15-beta2
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class VBAMacroReader implements Closeable {
|
public class VBAMacroReader implements Closeable {
|
||||||
private static final Logger LOGGER = LogManager.getLogger(VBAMacroReader.class);
|
private static final Logger LOGGER = LogManager.getLogger(VBAMacroReader.class);
|
||||||
|
|
||||||
|
@ -667,35 +668,36 @@ public class VBAMacroReader implements Closeable {
|
||||||
|
|
||||||
private static String readUnicode(InputStream is) throws IOException {
|
private static String readUnicode(InputStream is) throws IOException {
|
||||||
//reads null-terminated unicode string
|
//reads null-terminated unicode string
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
int b0 = IOUtils.readByte(is);
|
int b0 = IOUtils.readByte(is);
|
||||||
int b1 = IOUtils.readByte(is);
|
int b1 = IOUtils.readByte(is);
|
||||||
|
|
||||||
int read = 2;
|
int read = 2;
|
||||||
while ((b0 + b1) != 0 && read < MAX_STRING_LENGTH) {
|
while ((b0 + b1) != 0 && read < MAX_STRING_LENGTH) {
|
||||||
|
bos.write(b0);
|
||||||
bos.write(b0);
|
bos.write(b1);
|
||||||
bos.write(b1);
|
b0 = IOUtils.readByte(is);
|
||||||
b0 = IOUtils.readByte(is);
|
b1 = IOUtils.readByte(is);
|
||||||
b1 = IOUtils.readByte(is);
|
read += 2;
|
||||||
read += 2;
|
}
|
||||||
|
if (read >= MAX_STRING_LENGTH) {
|
||||||
|
LOGGER.atWarn().log("stopped reading unicode name after {} bytes", box(read));
|
||||||
|
}
|
||||||
|
return bos.toString(StandardCharsets.UTF_16LE);
|
||||||
}
|
}
|
||||||
if (read >= MAX_STRING_LENGTH) {
|
|
||||||
LOGGER.atWarn().log("stopped reading unicode name after {} bytes", box(read));
|
|
||||||
}
|
|
||||||
return bos.toString(StandardCharsets.UTF_16LE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String readMBCS(int firstByte, InputStream is, Charset charset) throws IOException {
|
private static String readMBCS(int firstByte, InputStream is, Charset charset) throws IOException {
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int b = firstByte;
|
int b = firstByte;
|
||||||
while (b > 0 && len < MAX_STRING_LENGTH) {
|
while (b > 0 && len < MAX_STRING_LENGTH) {
|
||||||
++len;
|
++len;
|
||||||
bos.write(b);
|
bos.write(b);
|
||||||
b = IOUtils.readByte(is);
|
b = IOUtils.readByte(is);
|
||||||
|
}
|
||||||
|
return bos.toString(charset);
|
||||||
}
|
}
|
||||||
return bos.toString(charset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -792,9 +794,7 @@ public class VBAMacroReader implements Closeable {
|
||||||
*/
|
*/
|
||||||
private static byte[] findCompressedStreamWBruteForce(InputStream is) throws IOException {
|
private static byte[] findCompressedStreamWBruteForce(InputStream is) throws IOException {
|
||||||
//buffer to memory for multiple tries
|
//buffer to memory for multiple tries
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
byte[] compressed = IOUtils.toByteArray(is);
|
||||||
IOUtils.copy(is, bos);
|
|
||||||
byte[] compressed = bos.toByteArray();
|
|
||||||
byte[] decompressed = null;
|
byte[] decompressed = null;
|
||||||
for (int i = 0; i < compressed.length; i++) {
|
for (int i = 0; i < compressed.length; i++) {
|
||||||
if (compressed[i] == 0x01 && i < compressed.length-1) {
|
if (compressed[i] == 0x01 && i < compressed.length-1) {
|
||||||
|
@ -821,12 +821,10 @@ public class VBAMacroReader implements Closeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] tryToDecompress(InputStream is) {
|
private static byte[] tryToDecompress(InputStream is) {
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
try (RLEDecompressingInputStream ris = new RLEDecompressingInputStream(is)) {
|
||||||
try {
|
return IOUtils.toByteArray(ris);
|
||||||
IOUtils.copy(new RLEDecompressingInputStream(is), bos);
|
|
||||||
} catch (IllegalArgumentException | IOException | IllegalStateException e){
|
} catch (IllegalArgumentException | IOException | IllegalStateException e){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return bos.toByteArray();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,14 +162,13 @@ public class EmbeddedExtractor implements Iterable<EmbeddedExtractor> {
|
||||||
|
|
||||||
protected EmbeddedData extract(DirectoryNode dn) throws IOException {
|
protected EmbeddedData extract(DirectoryNode dn) throws IOException {
|
||||||
assert(canExtract(dn));
|
assert(canExtract(dn));
|
||||||
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream(20000);
|
try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream(20000);
|
||||||
try (POIFSFileSystem dest = new POIFSFileSystem()) {
|
POIFSFileSystem dest = new POIFSFileSystem()) {
|
||||||
copyNodes(dn, dest.getRoot());
|
copyNodes(dn, dest.getRoot());
|
||||||
// start with a reasonable big size
|
// start with a reasonable big size
|
||||||
dest.writeFilesystem(bos);
|
dest.writeFilesystem(bos);
|
||||||
|
return new EmbeddedData(dn.getName(), bos.toByteArray(), CONTENT_TYPE_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new EmbeddedData(dn.getName(), bos.toByteArray(), CONTENT_TYPE_BYTES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected EmbeddedData extract(Picture source) throws IOException {
|
protected EmbeddedData extract(Picture source) throws IOException {
|
||||||
|
|
|
@ -27,7 +27,7 @@ package org.apache.poi.ss.usermodel;
|
||||||
* icon and which Yellow or Red.</p>
|
* icon and which Yellow or Red.</p>
|
||||||
*/
|
*/
|
||||||
public interface ConditionalFormattingThreshold {
|
public interface ConditionalFormattingThreshold {
|
||||||
public enum RangeType {
|
enum RangeType {
|
||||||
/** Number / Parameter */
|
/** Number / Parameter */
|
||||||
NUMBER(1, "num"),
|
NUMBER(1, "num"),
|
||||||
/** The minimum value from the range */
|
/** The minimum value from the range */
|
||||||
|
@ -41,16 +41,16 @@ public interface ConditionalFormattingThreshold {
|
||||||
UNALLOCATED(6, null),
|
UNALLOCATED(6, null),
|
||||||
/** Formula result */
|
/** Formula result */
|
||||||
FORMULA(7, "formula");
|
FORMULA(7, "formula");
|
||||||
|
|
||||||
/** Numeric ID of the type */
|
/** Numeric ID of the type */
|
||||||
public final int id;
|
public final int id;
|
||||||
/** Name (system) of the type */
|
/** Name (system) of the type */
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return id + " - " + name;
|
return id + " - " + name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RangeType byId(int id) {
|
public static RangeType byId(int id) {
|
||||||
return values()[id-1]; // 1-based IDs
|
return values()[id-1]; // 1-based IDs
|
||||||
}
|
}
|
||||||
|
@ -60,51 +60,51 @@ public interface ConditionalFormattingThreshold {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RangeType(int id, String name) {
|
RangeType(int id, String name) {
|
||||||
this.id = id; this.name = name;
|
this.id = id; this.name = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Range Type used
|
* Get the Range Type used
|
||||||
*/
|
*/
|
||||||
RangeType getRangeType();
|
RangeType getRangeType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the Range Type used
|
* Changes the Range Type used
|
||||||
*
|
*
|
||||||
* <p>If you change the range type, you need to
|
* <p>If you change the range type, you need to
|
||||||
* ensure that the Formula and Value parameters
|
* ensure that the Formula and Value parameters
|
||||||
* are compatible with it before saving</p>
|
* are compatible with it before saving</p>
|
||||||
*/
|
*/
|
||||||
void setRangeType(RangeType type);
|
void setRangeType(RangeType type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formula to use to calculate the threshold,
|
* Formula to use to calculate the threshold,
|
||||||
* or <code>null</code> if no formula
|
* or {@code null} if no formula
|
||||||
*/
|
*/
|
||||||
String getFormula();
|
String getFormula();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the formula used to calculate the threshold,
|
* Sets the formula used to calculate the threshold,
|
||||||
* or unsets it if <code>null</code> is given.
|
* or unsets it if {@code null} is given.
|
||||||
*/
|
*/
|
||||||
void setFormula(String formula);
|
void setFormula(String formula);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value used for the threshold, or
|
* Gets the value used for the threshold, or
|
||||||
* <code>null</code> if there isn't one.
|
* {@code null} if there isn't one.
|
||||||
*/
|
*/
|
||||||
Double getValue();
|
Double getValue();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value used for the threshold.
|
* Sets the value used for the threshold.
|
||||||
* <p>If the type is {@link RangeType#PERCENT} or
|
* <p>If the type is {@link RangeType#PERCENT} or
|
||||||
* {@link RangeType#PERCENTILE} it must be between 0 and 100.
|
* {@link RangeType#PERCENTILE} it must be between 0 and 100.
|
||||||
* <p>If the type is {@link RangeType#MIN} or {@link RangeType#MAX}
|
* <p>If the type is {@link RangeType#MIN} or {@link RangeType#MAX}
|
||||||
* or {@link RangeType#FORMULA} it shouldn't be set.
|
* or {@link RangeType#FORMULA} it shouldn't be set.
|
||||||
* <p>Use <code>null</code> to unset
|
* <p>Use {@code null} to unset
|
||||||
*/
|
*/
|
||||||
void setValue(Double value);
|
void setValue(Double value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,6 +265,7 @@ public class GenericRecordJsonWriter implements Closeable {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("java:S3516")
|
||||||
protected boolean printNumber(String name, Object o) {
|
protected boolean printNumber(String name, Object o) {
|
||||||
Number n = (Number)o;
|
Number n = (Number)o;
|
||||||
printName(name);
|
printName(name);
|
||||||
|
|
|
@ -178,29 +178,29 @@ public final class IOUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
final int len = Math.min(length, maxLength);
|
final int len = Math.min(length, maxLength);
|
||||||
UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream(len == Integer.MAX_VALUE ? 4096 : len);
|
try (UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream(len == Integer.MAX_VALUE ? 4096 : len)) {
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int totalBytes = 0, readBytes;
|
||||||
|
do {
|
||||||
|
readBytes = stream.read(buffer, 0, Math.min(buffer.length, len - totalBytes));
|
||||||
|
totalBytes += Math.max(readBytes, 0);
|
||||||
|
if (readBytes > 0) {
|
||||||
|
baos.write(buffer, 0, readBytes);
|
||||||
|
}
|
||||||
|
|
||||||
byte[] buffer = new byte[4096];
|
checkByteSizeLimit(totalBytes);
|
||||||
int totalBytes = 0, readBytes;
|
} while (totalBytes < len && readBytes > -1);
|
||||||
do {
|
|
||||||
readBytes = stream.read(buffer, 0, Math.min(buffer.length, len-totalBytes));
|
if (maxLength != Integer.MAX_VALUE && totalBytes == maxLength) {
|
||||||
totalBytes += Math.max(readBytes,0);
|
throw new IOException("MaxLength (" + maxLength + ") reached - stream seems to be invalid.");
|
||||||
if (readBytes > 0) {
|
|
||||||
baos.write(buffer, 0, readBytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkByteSizeLimit(totalBytes);
|
if (len != Integer.MAX_VALUE && totalBytes < len) {
|
||||||
} while (totalBytes < len && readBytes > -1);
|
throw new EOFException("unexpected EOF - expected len: " + len + " - actual len: " + totalBytes);
|
||||||
|
}
|
||||||
|
|
||||||
if (maxLength != Integer.MAX_VALUE && totalBytes == maxLength) {
|
return baos.toByteArray();
|
||||||
throw new IOException("MaxLength ("+maxLength+") reached - stream seems to be invalid.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len != Integer.MAX_VALUE && totalBytes < len) {
|
|
||||||
throw new EOFException("unexpected EOF - expected len: "+len+" - actual len: "+totalBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkLength(long length, int maxLength) {
|
private static void checkLength(long length, int maxLength) {
|
||||||
|
|
|
@ -25,8 +25,6 @@ import static org.hamcrest.CoreMatchers.startsWith;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
@ -47,6 +45,7 @@ import org.mockito.internal.matchers.apachecommons.ReflectionEquals;
|
||||||
* Util class for POI JUnit TestCases, which provide additional features
|
* Util class for POI JUnit TestCases, which provide additional features
|
||||||
*/
|
*/
|
||||||
@Internal
|
@Internal
|
||||||
|
@SuppressWarnings("java:S2187")
|
||||||
public final class POITestCase {
|
public final class POITestCase {
|
||||||
|
|
||||||
private POITestCase() {
|
private POITestCase() {
|
||||||
|
@ -141,68 +140,6 @@ public final class POITestCase {
|
||||||
assertTrue(new ReflectionEquals(expected, "$jacocoData").matches(actual));
|
assertTrue(new ReflectionEquals(expected, "$jacocoData").matches(actual));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Rather than adding {@literal @}Ignore to known-failing tests,
|
|
||||||
* write the test so that it notifies us if it starts passing.
|
|
||||||
* This is useful for closing related or forgotten bugs.
|
|
||||||
*
|
|
||||||
* An Example:
|
|
||||||
* <code><pre>
|
|
||||||
* public static int add(int a, int b) {
|
|
||||||
* // a known bug in behavior that has not been fixed yet
|
|
||||||
* raise UnsupportedOperationException("add");
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* {@literal @}Test
|
|
||||||
* void knownFailingUnitTest() {
|
|
||||||
* try {
|
|
||||||
* assertEquals(2, add(1,1));
|
|
||||||
* // this test fails because the assumption that this bug had not been fixed is false
|
|
||||||
* testPassesNow(12345);
|
|
||||||
* } catch (UnsupportedOperationException e) {
|
|
||||||
* // test is skipped because the assumption that this bug had not been fixed is true
|
|
||||||
* skipTest(e);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Once passing, this unit test can be rewritten as:
|
|
||||||
* {@literal @}Test
|
|
||||||
* void knownPassingUnitTest() {
|
|
||||||
* assertEquals(2, add(1,1));
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* If you have a better idea how to simplify test code while still notifying
|
|
||||||
* us when a previous known-failing test now passes, please improve these.
|
|
||||||
* As a bonus, a known-failing test that fails should not be counted as a
|
|
||||||
* passing test.
|
|
||||||
*
|
|
||||||
* One possible alternative is to expect the known exception, but without
|
|
||||||
* a clear message that it is a good thing to no longer get the expected
|
|
||||||
* exception once the test passes.
|
|
||||||
* {@literal @}Test(expected=UnsupportedOperationException.class)
|
|
||||||
* void knownFailingUnitTest() {
|
|
||||||
* assertEquals(2, add(1,1));
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @param e the exception that was caught that will no longer
|
|
||||||
* be raised when the bug is fixed
|
|
||||||
*/
|
|
||||||
public static void skipTest(Throwable e) {
|
|
||||||
assumeTrue(e != null, "This test currently fails with");
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @see #skipTest(Throwable)
|
|
||||||
*
|
|
||||||
* @param bug the bug number corresponding to a known bug in bugzilla
|
|
||||||
*/
|
|
||||||
public static void testPassesNow(int bug) {
|
|
||||||
fail("This test passes now. Please update the unit test and bug " + bug + ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void assertBetween(String message, int value, int min, int max) {
|
|
||||||
assertTrue(min <= value, message + ": " + value + " is less than the minimum value of " + min);
|
|
||||||
assertTrue(value <= max, message + ": " + value + " is greater than the maximum value of " + max);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that the temporary directory is defined and exists and
|
* Ensures that the temporary directory is defined and exists and
|
||||||
|
|
|
@ -1382,6 +1382,7 @@ public abstract class BaseTestBugzillaIssues {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@SuppressWarnings("java:S2699")
|
||||||
void test58896() throws IOException {
|
void test58896() throws IOException {
|
||||||
final int nrows = 160;
|
final int nrows = 160;
|
||||||
final int ncols = 139;
|
final int ncols = 139;
|
||||||
|
@ -1493,8 +1494,8 @@ public abstract class BaseTestBugzillaIssues {
|
||||||
|
|
||||||
// *******************************
|
// *******************************
|
||||||
// First cell of array formula, OK
|
// First cell of array formula, OK
|
||||||
int rowId = 0;
|
final int rowId = 0;
|
||||||
int cellId = 1;
|
final int cellId = 1;
|
||||||
|
|
||||||
Row row = sheet.getRow(rowId);
|
Row row = sheet.getRow(rowId);
|
||||||
Cell cell = row.getCell(cellId);
|
Cell cell = row.getCell(cellId);
|
||||||
|
@ -1507,9 +1508,6 @@ public abstract class BaseTestBugzillaIssues {
|
||||||
|
|
||||||
// *******************************
|
// *******************************
|
||||||
// Second cell of array formula, NOT OK for xlsx files
|
// Second cell of array formula, NOT OK for xlsx files
|
||||||
rowId = 1;
|
|
||||||
cellId = 1;
|
|
||||||
|
|
||||||
row = sheet.getRow(rowId);
|
row = sheet.getRow(rowId);
|
||||||
cell = row.getCell(cellId);
|
cell = row.getCell(cellId);
|
||||||
assertEquals("A1", cell.getCellFormula());
|
assertEquals("A1", cell.getCellFormula());
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
package org.apache.poi.ss.usermodel;
|
package org.apache.poi.ss.usermodel;
|
||||||
|
|
||||||
import static org.apache.poi.POITestCase.assertBetween;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
@ -50,8 +49,7 @@ import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common superclass for testing {@link org.apache.poi.hssf.usermodel.HSSFCell},
|
* Common superclass for testing {@link org.apache.poi.hssf.usermodel.HSSFCell},
|
||||||
* {@link org.apache.poi.xssf.usermodel.XSSFCell} and
|
* XSSFCell and SXSSFCell
|
||||||
* {@link org.apache.poi.xssf.streaming.SXSSFCell}
|
|
||||||
*/
|
*/
|
||||||
public abstract class BaseTestSheet {
|
public abstract class BaseTestSheet {
|
||||||
private static final int ROW_COUNT = 40000;
|
private static final int ROW_COUNT = 40000;
|
||||||
|
@ -430,7 +428,7 @@ public abstract class BaseTestSheet {
|
||||||
assertCollectionEquals(mergedRegions.values(), sheet.getMergedRegions());
|
assertCollectionEquals(mergedRegions.values(), sheet.getMergedRegions());
|
||||||
|
|
||||||
Collection<Integer> removed = Arrays.asList(0, 2, 3, 6, 8);
|
Collection<Integer> removed = Arrays.asList(0, 2, 3, 6, 8);
|
||||||
mergedRegions.keySet().removeAll(removed);
|
removed.forEach(mergedRegions.keySet()::remove);
|
||||||
sheet.removeMergedRegions(removed);
|
sheet.removeMergedRegions(removed);
|
||||||
assertCollectionEquals(mergedRegions.values(), sheet.getMergedRegions());
|
assertCollectionEquals(mergedRegions.values(), sheet.getMergedRegions());
|
||||||
}
|
}
|
||||||
|
@ -1364,4 +1362,9 @@ public abstract class BaseTestSheet {
|
||||||
assertBetween("Date column width", s.getColumnWidth(1), 4750, 7300);
|
assertBetween("Date column width", s.getColumnWidth(1), 4750, 7300);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void assertBetween(String message, int value, int min, int max) {
|
||||||
|
assertTrue(min <= value, message + ": " + value + " is less than the minimum value of " + min);
|
||||||
|
assertTrue(value <= max, message + ": " + value + " is greater than the maximum value of " + max);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -724,7 +724,7 @@ public abstract class BaseTestWorkbook {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void changeSheetNameWithSharedFormulas() throws IOException {
|
protected void changeSheetNameWithSharedFormulas() throws IOException {
|
||||||
String sampleFile = "shared_formulas.xls" + (getClass().getName().contains("xssf") ? "x" : "");
|
String sampleFile = "shared_formulas.xls" + (getClass().getName().contains("xssf") ? "x" : "");
|
||||||
|
|
||||||
try (Workbook wb = _testDataProvider.openSampleWorkbook(sampleFile)) {
|
try (Workbook wb = _testDataProvider.openSampleWorkbook(sampleFile)) {
|
||||||
|
|
Loading…
Reference in New Issue