mirror of https://github.com/apache/poi.git
merge down trunk
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hssf_cryptoapi@1755463 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
075e2bfce2
commit
885deafb94
77
build.xml
77
build.xml
|
@ -17,7 +17,6 @@ KIND, either express or implied. See the License for the
|
|||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<!--
|
||||
This build was tested with ant 1.9.4 although it will probably work with
|
||||
other versions, however at least 1.8.0 is required.
|
||||
|
@ -133,6 +132,7 @@ under the License.
|
|||
<property name="ooxml.output.test.dir" location="build/ooxml-test-classes"/>
|
||||
<property name="ooxml.testokfile" location="build/ooxml-testokfile.txt"/>
|
||||
<property name="ooxml.lite.output.dir" location="build/ooxml-lite-classes"/>
|
||||
<property name="ooxml.lite.testokfile" location="build/ooxml-lite-testokfile.txt"/>
|
||||
|
||||
<!-- XSSF/SXSSF subset of OOXML: -->
|
||||
<property name="ooxml.ss.testokfile" location="build/ooxml-ss-testokfile.txt"/>
|
||||
|
@ -169,6 +169,9 @@ under the License.
|
|||
<property name="main.ant.url" value="${repository.m2}/maven2/org/apache/ant/ant/1.9.4/ant-1.9.4.jar"/>
|
||||
<property name="main.antlauncher.jar" location="${main.lib}/ant-launcher-1.9.4.jar"/>
|
||||
<property name="main.antlauncher.url" value="${repository.m2}/maven2/org/apache/ant/ant-launcher/1.9.4/ant-launcher-1.9.4.jar"/>
|
||||
<property name="main.commons-collections4.jar" location="${main.lib}/commons-collections4-4.1.jar"/>
|
||||
<property name="main.commons-collections4.url"
|
||||
value="${repository.m2}/maven2/org/apache/commons/commons-collections4/4.1/commons-collections4-4.1.jar"/>
|
||||
|
||||
<!-- xml signature libs -->
|
||||
<property name="dsig.xmlsec.jar" location="${compile.lib}/xmlsec-2.0.6.jar"/>
|
||||
|
@ -192,8 +195,8 @@ under the License.
|
|||
value="${repository.m2}/maven2/org/apache/xmlbeans/xmlbeans/2.6.0/xmlbeans-2.6.0.jar"/>
|
||||
|
||||
<!-- coverage libs -->
|
||||
<property name="jacoco.zip" location="${main.lib}/jacoco-0.7.6.201602180812.zip"/>
|
||||
<property name="jacoco.url" value="${repository.m2}/maven2/org/jacoco/jacoco/0.7.6.201602180812/jacoco-0.7.6.201602180812.zip"/>
|
||||
<property name="jacoco.zip" location="${main.lib}/jacoco-0.7.7.201606060606.zip"/>
|
||||
<property name="jacoco.url" value="${repository.m2}/maven2/org/jacoco/jacoco/0.7.7.201606060606/jacoco-0.7.7.201606060606.zip"/>
|
||||
<property name="asm.jar" location="${main.lib}/asm-all-5.0.3.jar"/>
|
||||
<property name="asm.url" value="${repository.m2}/maven2/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar"/>
|
||||
|
||||
|
@ -285,6 +288,7 @@ under the License.
|
|||
</condition>
|
||||
<property name="findbugs.version" value="2.0.3" if:set="findbugs.jdk6"/>
|
||||
<property name="findbugs.version" value="3.0.1" unless:set="findbugs.jdk6"/>
|
||||
<echo message="Findbugs-Version: ${findbugs.version} for Java ${ant.java.version}"/>
|
||||
<property name="findbugs.url" value="http://prdownloads.sourceforge.net/findbugs/findbugs-noUpdateChecks-${findbugs.version}.zip?download"/>
|
||||
<property name="findbugs.jar" location="${main.lib}/findbugs-noUpdateChecks-${findbugs.version}.zip"/>
|
||||
|
||||
|
@ -303,6 +307,8 @@ under the License.
|
|||
|
||||
<!-- this can be overwriten to empty when running with Java 9 -->
|
||||
<property name="maxpermsize" value="-XX:MaxPermSize=256m"/>
|
||||
<property name="java9addmods" value="-Dthis.is.a.dummy=true"/>
|
||||
<property name="java9addmodsvalue" value="-Dthis.is.a.dummy=true"/>
|
||||
|
||||
<path id="main.classpath">
|
||||
<pathelement location="${main.commons-logging.jar}"/>
|
||||
|
@ -310,6 +316,7 @@ under the License.
|
|||
<pathelement location="${main.log4j.jar}"/>
|
||||
<pathelement location="${main.junit.jar}"/>
|
||||
<pathelement location="${main.hamcrest.jar}"/>
|
||||
<pathelement location="${main.commons-collections4.jar}"/>
|
||||
</path>
|
||||
|
||||
<path id="scratchpad.classpath">
|
||||
|
@ -498,9 +505,7 @@ under the License.
|
|||
<attribute name="src"/>
|
||||
<attribute name="dest"/>
|
||||
<sequential>
|
||||
<local name="exists"/>
|
||||
<available file="@{dest}" property="exists"/>
|
||||
<!--fail unless:true="${exists}"
|
||||
<!--fail
|
||||
message="Java version might be uncapable to download https URLs - see https://stackoverflow.com/questions/6851461/java-why-does-ssl-handshake-give-could-not-generate-dh-keypair-exception">
|
||||
<condition>
|
||||
<and>
|
||||
|
@ -509,7 +514,7 @@ under the License.
|
|||
</and>
|
||||
</condition>
|
||||
</fail-->
|
||||
<get src="@{src}" dest="@{dest}" unless:true="${exists}"/>
|
||||
<get src="@{src}" dest="@{dest}" skipexisting="true"/>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
|
@ -531,12 +536,14 @@ under the License.
|
|||
<include name="jacoco-0.7.2*"/>
|
||||
<include name="jacoco-0.7.3*"/>
|
||||
<include name="jacoco-0.7.4*"/>
|
||||
<include name="jacoco-0.7.6*"/>
|
||||
<include name="log4j-1.2.13*"/>
|
||||
<include name="org.jacoco.*-0.6.*"/>
|
||||
<include name="org.jacoco.*-0.7.1*"/>
|
||||
<include name="org.jacoco.*-0.7.2*"/>
|
||||
<include name="org.jacoco.*-0.7.3*"/>
|
||||
<include name="org.jacoco.*-0.7.4*"/>
|
||||
<include name="org.jacoco.*-0.7.6*"/>
|
||||
<include name="dom4j*"/>
|
||||
<include name="apache-rat-0.10*"/>
|
||||
<include name="xercesImpl-*.jar"/>
|
||||
|
@ -587,6 +594,7 @@ under the License.
|
|||
<available file="${dsig.bouncycastle-pkix.jar}"/>
|
||||
<available file="${dsig.xmlsec.jar}"/>
|
||||
<available file="${dsig.sl4j-api.jar}"/>
|
||||
<available file="${main.commons-collections4.jar}"/>
|
||||
</and>
|
||||
<isset property="disconnected"/>
|
||||
</or>
|
||||
|
@ -605,6 +613,7 @@ under the License.
|
|||
<downloadfile src="${main.antlauncher.url}" dest="${main.antlauncher.jar}"/>
|
||||
<downloadfile src="${asm.url}" dest="${asm.jar}"/>
|
||||
<downloadfile src="${jacoco.url}" dest="${jacoco.zip}"/>
|
||||
<downloadfile src="${main.commons-collections4.url}" dest="${main.commons-collections4.jar}"/>
|
||||
<unzip src="${jacoco.zip}" dest=".">
|
||||
<patternset>
|
||||
<include name="lib/*.jar"/>
|
||||
|
@ -1161,6 +1170,8 @@ under the License.
|
|||
<group name="Main">
|
||||
<classfiles>
|
||||
<fileset dir="${main.output.dir}">
|
||||
<!-- exclude some generated classes -->
|
||||
<exclude name="org/apache/poi/sl/draw/binding/*.class"/>
|
||||
<!-- exclude large test-class -->
|
||||
<exclude name="org/apache/poi/hssf/usermodel/DummyGraphics2d.class"/>
|
||||
</fileset>
|
||||
|
@ -1242,6 +1253,8 @@ under the License.
|
|||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="-Xmx256m"/>
|
||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${main.reports.test}">
|
||||
|
@ -1258,6 +1271,16 @@ under the License.
|
|||
<antcall target="-test-main-write-testfile"/>
|
||||
</target>
|
||||
|
||||
<target name="test-report" depends="init">
|
||||
<mkdir dir="build/report"/>
|
||||
<junitreport todir="build/report">
|
||||
<fileset dir="build">
|
||||
<include name="*results/**/TEST-*.xml"/>
|
||||
</fileset>
|
||||
<report format="frames" todir="build/report"/>
|
||||
</junitreport>
|
||||
</target>
|
||||
|
||||
<target name="-test-property-check" unless="testcase">
|
||||
<echo message="Please use -Dtestcase=org.your.testcase to run a single test"/>
|
||||
<fail/>
|
||||
|
@ -1288,6 +1311,8 @@ under the License.
|
|||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="-Xmx256m"/>
|
||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${main.reports.test}">
|
||||
|
@ -1335,6 +1360,8 @@ under the License.
|
|||
and on Windows with jdk-1.5.22
|
||||
-->
|
||||
<jvmarg value="-Xmx256M"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${scratchpad.reports.test}">
|
||||
|
@ -1373,6 +1400,8 @@ under the License.
|
|||
<jvmarg value="${maxpermsize}"/>
|
||||
<jvmarg value="-Xmx768M"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
|
@ -1396,6 +1425,8 @@ under the License.
|
|||
<syspropertyset refid="junit.properties"/>
|
||||
<jvmarg value="-Xmx768M"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${ooxml.reports.test}">
|
||||
|
@ -1439,6 +1470,8 @@ under the License.
|
|||
<jvmarg value="${maxpermsize}"/>
|
||||
<jvmarg value="-Xmx768M"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
|
@ -1485,6 +1518,8 @@ under the License.
|
|||
<syspropertyset refid="junit.properties"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="-Xmx1512M"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${integration.reports.test}">
|
||||
|
@ -1503,7 +1538,20 @@ under the License.
|
|||
</target>
|
||||
|
||||
<!-- Section: test-ooxml-lite -->
|
||||
<target name="compile-ooxml-lite" depends="compile-ooxml">
|
||||
<target name="-compile-ooxml-lite-check">
|
||||
<uptodate property="ooxml.lite.test.notRequired" targetfile="${ooxml.lite.testokfile}">
|
||||
<srcfiles dir="${ooxml.src}"/>
|
||||
<srcfiles dir="${ooxml.src.test}"/>
|
||||
<srcfiles file="${ooxml.xsds.jar}"/>
|
||||
<srcfiles file="${ooxml.security.jar}"/>
|
||||
</uptodate>
|
||||
</target>
|
||||
|
||||
<target name="compile-ooxml-lite" depends="-compile-ooxml-lite-check,compile-ooxml"
|
||||
unless="ooxml.lite.test.notRequired">
|
||||
<delete file="${ooxml.lite.testokfile}"/>
|
||||
<echo message="Running ooxml-lite generator"/>
|
||||
|
||||
<property name="ooxml.lite-merged.dir" location="build/ooxml-lite-merged"/>
|
||||
<mkdir dir="${ooxml.lite-merged.dir}"/>
|
||||
|
||||
|
@ -1522,6 +1570,8 @@ under the License.
|
|||
<syspropertyset refid="junit.properties"/>
|
||||
<jvmarg value="${maxpermsize}"/>
|
||||
<jvmarg value="-Xmx512m"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<arg value="-ooxml"/>
|
||||
<arg value="${ooxml.lite-merged.dir}/ooxml-lite-merged.jar"/>
|
||||
<arg value="-test"/>
|
||||
|
@ -1529,6 +1579,8 @@ under the License.
|
|||
<arg value="-dest"/>
|
||||
<arg value="${ooxml.lite.output.dir}"/>
|
||||
</java>
|
||||
|
||||
<echo file="${ooxml.lite.testokfile}" append="false" message="testok"/>
|
||||
</target>
|
||||
|
||||
<target name="test-ooxml-lite" depends="jacocotask,compile-ooxml-xsds,compile-ooxml-lite">
|
||||
|
@ -1557,6 +1609,8 @@ under the License.
|
|||
<classpath refid="test.excelant.classpath"/>
|
||||
<syspropertyset refid="junit.properties"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${excelant.reports.test}">
|
||||
|
@ -1868,6 +1922,7 @@ under the License.
|
|||
<fileset dir="${main.lib}">
|
||||
<include name="commons-codec-*.jar"/>
|
||||
<include name="commons-logging-*.jar"/>
|
||||
<include name="commons-collections4-*.jar"/>
|
||||
<include name="junit-*.jar"/>
|
||||
<include name="log4j-*.jar"/>
|
||||
</fileset>
|
||||
|
@ -2083,7 +2138,7 @@ under the License.
|
|||
</forbiddenapis>
|
||||
</target>
|
||||
|
||||
<target name="findbugs" depends="assemble">
|
||||
<target name="findbugs" depends="jar">
|
||||
<downloadfile src="${findbugs.url}" dest="${findbugs.jar}"/>
|
||||
|
||||
<property name="findbugs.home" value="build/findbugs" />
|
||||
|
@ -2103,11 +2158,13 @@ under the License.
|
|||
output="xml:withMessages"
|
||||
outputFile="build/findbugs.xml"
|
||||
effort="max"
|
||||
failOnError="true"
|
||||
excludeFilter="src/resources/devtools/findbugs-filters.xml">
|
||||
<fileset dir="${dist.dir}/maven">
|
||||
<include name="poi/poi-${version.id}.jar"/>
|
||||
<include name="poi-scratchpad/poi-scratchpad-${version.id}.jar"/>
|
||||
<include name="poi-ooxml/poi-ooxml-${version.id}.jar"/>
|
||||
<include name="poi-excelant/poi-excelant-${version.id}.jar"/>
|
||||
</fileset>
|
||||
<auxClasspath path="${dsig.bouncycastle-pkix.jar}" />
|
||||
<auxClasspath path="${dsig.bouncycastle-prov.jar}" />
|
||||
|
@ -2117,9 +2174,11 @@ under the License.
|
|||
<auxClasspath path="${ooxml.security.jar}" />
|
||||
<auxClasspath path="${ooxml.curvesapi.jar}" />
|
||||
<auxClasspath path="${ooxml.xmlbeans26.jar}" />
|
||||
<auxClasspath path="${main.commons-collections4.jar}" />
|
||||
<auxClasspath path="${main.commons-codec.jar}" />
|
||||
<auxClasspath path="${main.commons-logging.jar}" />
|
||||
<auxClasspath path="${main.junit.jar}" />
|
||||
<auxClasspath path="${main.ant.jar}" />
|
||||
<sourcePath path="src/java" />
|
||||
<sourcePath path="src/ooxml/java" />
|
||||
<sourcePath path="src/scratchpad/src" />
|
||||
|
|
|
@ -91,6 +91,11 @@
|
|||
<scope>test</scope>
|
||||
<version>4.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
<version>4.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -110,6 +110,11 @@
|
|||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
<version>4.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
|
|
|
@ -34,184 +34,184 @@ import org.apache.poi.ss.formula.FormulaShifter;
|
|||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
*/
|
||||
public final class RowRecordsAggregate extends RecordAggregate {
|
||||
private int _firstrow = -1;
|
||||
private int _lastrow = -1;
|
||||
private final Map<Integer, RowRecord> _rowRecords;
|
||||
private final ValueRecordsAggregate _valuesAgg;
|
||||
private final List<Record> _unknownRecords;
|
||||
private final SharedValueManager _sharedValueManager;
|
||||
private int _firstrow = -1;
|
||||
private int _lastrow = -1;
|
||||
private final Map<Integer, RowRecord> _rowRecords;
|
||||
private final ValueRecordsAggregate _valuesAgg;
|
||||
private final List<Record> _unknownRecords;
|
||||
private final SharedValueManager _sharedValueManager;
|
||||
|
||||
// Cache values to speed up performance of
|
||||
// Cache values to speed up performance of
|
||||
// getStartRowNumberForBlock / getEndRowNumberForBlock, see Bugzilla 47405
|
||||
private RowRecord[] _rowRecordValues = null;
|
||||
|
||||
/** Creates a new instance of ValueRecordsAggregate */
|
||||
public RowRecordsAggregate() {
|
||||
this(SharedValueManager.createEmpty());
|
||||
}
|
||||
private RowRecordsAggregate(SharedValueManager svm) {
|
||||
if (svm == null) {
|
||||
throw new IllegalArgumentException("SharedValueManager must be provided.");
|
||||
}
|
||||
_rowRecords = new TreeMap<Integer, RowRecord>();
|
||||
_valuesAgg = new ValueRecordsAggregate();
|
||||
_unknownRecords = new ArrayList<Record>();
|
||||
_sharedValueManager = svm;
|
||||
}
|
||||
/** Creates a new instance of ValueRecordsAggregate */
|
||||
public RowRecordsAggregate() {
|
||||
this(SharedValueManager.createEmpty());
|
||||
}
|
||||
private RowRecordsAggregate(SharedValueManager svm) {
|
||||
if (svm == null) {
|
||||
throw new IllegalArgumentException("SharedValueManager must be provided.");
|
||||
}
|
||||
_rowRecords = new TreeMap<Integer, RowRecord>();
|
||||
_valuesAgg = new ValueRecordsAggregate();
|
||||
_unknownRecords = new ArrayList<Record>();
|
||||
_sharedValueManager = svm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rs record stream with all {@link SharedFormulaRecord}
|
||||
* {@link ArrayRecord}, {@link TableRecord} {@link MergeCellsRecord} Records removed
|
||||
* @param svm an initialised {@link SharedValueManager} (from the shared formula, array
|
||||
* and table records of the current sheet). Never <code>null</code>.
|
||||
*/
|
||||
public RowRecordsAggregate(RecordStream rs, SharedValueManager svm) {
|
||||
this(svm);
|
||||
while(rs.hasNext()) {
|
||||
Record rec = rs.getNext();
|
||||
switch (rec.getSid()) {
|
||||
case RowRecord.sid:
|
||||
insertRow((RowRecord) rec);
|
||||
continue;
|
||||
/**
|
||||
* @param rs record stream with all {@link SharedFormulaRecord}
|
||||
* {@link ArrayRecord}, {@link TableRecord} {@link MergeCellsRecord} Records removed
|
||||
* @param svm an initialised {@link SharedValueManager} (from the shared formula, array
|
||||
* and table records of the current sheet). Never <code>null</code>.
|
||||
*/
|
||||
public RowRecordsAggregate(RecordStream rs, SharedValueManager svm) {
|
||||
this(svm);
|
||||
while(rs.hasNext()) {
|
||||
Record rec = rs.getNext();
|
||||
switch (rec.getSid()) {
|
||||
case RowRecord.sid:
|
||||
insertRow((RowRecord) rec);
|
||||
continue;
|
||||
case DConRefRecord.sid:
|
||||
addUnknownRecord(rec);
|
||||
continue;
|
||||
case DBCellRecord.sid:
|
||||
// end of 'Row Block'. Should only occur after cell records
|
||||
// ignore DBCELL records because POI generates them upon re-serialization
|
||||
continue;
|
||||
}
|
||||
if (rec instanceof UnknownRecord) {
|
||||
// might need to keep track of where exactly these belong
|
||||
addUnknownRecord(rec);
|
||||
while (rs.peekNextSid() == ContinueRecord.sid) {
|
||||
addUnknownRecord(rs.getNext());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (rec instanceof MulBlankRecord) {
|
||||
_valuesAgg.addMultipleBlanks((MulBlankRecord) rec);
|
||||
continue;
|
||||
}
|
||||
if (!(rec instanceof CellValueRecordInterface)) {
|
||||
throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")");
|
||||
}
|
||||
_valuesAgg.construct((CellValueRecordInterface)rec, rs, svm);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Handles UnknownRecords which appear within the row/cell records
|
||||
*/
|
||||
private void addUnknownRecord(Record rec) {
|
||||
// ony a few distinct record IDs are encountered by the existing POI test cases:
|
||||
// 0x1065 // many
|
||||
// 0x01C2 // several
|
||||
// 0x0034 // few
|
||||
// No documentation could be found for these
|
||||
// end of 'Row Block'. Should only occur after cell records
|
||||
// ignore DBCELL records because POI generates them upon re-serialization
|
||||
continue;
|
||||
}
|
||||
if (rec instanceof UnknownRecord) {
|
||||
// might need to keep track of where exactly these belong
|
||||
addUnknownRecord(rec);
|
||||
while (rs.peekNextSid() == ContinueRecord.sid) {
|
||||
addUnknownRecord(rs.getNext());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (rec instanceof MulBlankRecord) {
|
||||
_valuesAgg.addMultipleBlanks((MulBlankRecord) rec);
|
||||
continue;
|
||||
}
|
||||
if (!(rec instanceof CellValueRecordInterface)) {
|
||||
throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")");
|
||||
}
|
||||
_valuesAgg.construct((CellValueRecordInterface)rec, rs, svm);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Handles UnknownRecords which appear within the row/cell records
|
||||
*/
|
||||
private void addUnknownRecord(Record rec) {
|
||||
// ony a few distinct record IDs are encountered by the existing POI test cases:
|
||||
// 0x1065 // many
|
||||
// 0x01C2 // several
|
||||
// 0x0034 // few
|
||||
// No documentation could be found for these
|
||||
|
||||
// keep the unknown records for re-serialization
|
||||
_unknownRecords.add(rec);
|
||||
}
|
||||
public void insertRow(RowRecord row) {
|
||||
// Integer integer = Integer.valueOf(row.getRowNumber());
|
||||
_rowRecords.put(Integer.valueOf(row.getRowNumber()), row);
|
||||
// Clear the cached values
|
||||
_rowRecordValues = null;
|
||||
if ((row.getRowNumber() < _firstrow) || (_firstrow == -1)) {
|
||||
_firstrow = row.getRowNumber();
|
||||
}
|
||||
if ((row.getRowNumber() > _lastrow) || (_lastrow == -1)) {
|
||||
_lastrow = row.getRowNumber();
|
||||
}
|
||||
}
|
||||
// keep the unknown records for re-serialization
|
||||
_unknownRecords.add(rec);
|
||||
}
|
||||
public void insertRow(RowRecord row) {
|
||||
// Integer integer = Integer.valueOf(row.getRowNumber());
|
||||
_rowRecords.put(Integer.valueOf(row.getRowNumber()), row);
|
||||
// Clear the cached values
|
||||
_rowRecordValues = null;
|
||||
if ((row.getRowNumber() < _firstrow) || (_firstrow == -1)) {
|
||||
_firstrow = row.getRowNumber();
|
||||
}
|
||||
if ((row.getRowNumber() > _lastrow) || (_lastrow == -1)) {
|
||||
_lastrow = row.getRowNumber();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeRow(RowRecord row) {
|
||||
int rowIndex = row.getRowNumber();
|
||||
_valuesAgg.removeAllCellsValuesForRow(rowIndex);
|
||||
Integer key = Integer.valueOf(rowIndex);
|
||||
RowRecord rr = _rowRecords.remove(key);
|
||||
if (rr == null) {
|
||||
throw new RuntimeException("Invalid row index (" + key.intValue() + ")");
|
||||
}
|
||||
if (row != rr) {
|
||||
_rowRecords.put(key, rr);
|
||||
throw new RuntimeException("Attempt to remove row that does not belong to this sheet");
|
||||
}
|
||||
|
||||
// Clear the cached values
|
||||
_rowRecordValues = null;
|
||||
}
|
||||
public void removeRow(RowRecord row) {
|
||||
int rowIndex = row.getRowNumber();
|
||||
_valuesAgg.removeAllCellsValuesForRow(rowIndex);
|
||||
Integer key = Integer.valueOf(rowIndex);
|
||||
RowRecord rr = _rowRecords.remove(key);
|
||||
if (rr == null) {
|
||||
throw new RuntimeException("Invalid row index (" + key.intValue() + ")");
|
||||
}
|
||||
if (row != rr) {
|
||||
_rowRecords.put(key, rr);
|
||||
throw new RuntimeException("Attempt to remove row that does not belong to this sheet");
|
||||
}
|
||||
|
||||
// Clear the cached values
|
||||
_rowRecordValues = null;
|
||||
}
|
||||
|
||||
public RowRecord getRow(int rowIndex) {
|
||||
public RowRecord getRow(int rowIndex) {
|
||||
int maxrow = SpreadsheetVersion.EXCEL97.getLastRowIndex();
|
||||
if (rowIndex < 0 || rowIndex > maxrow) {
|
||||
throw new IllegalArgumentException("The row number must be between 0 and " + maxrow + ", but had: " + rowIndex);
|
||||
}
|
||||
return _rowRecords.get(Integer.valueOf(rowIndex));
|
||||
}
|
||||
throw new IllegalArgumentException("The row number must be between 0 and " + maxrow + ", but had: " + rowIndex);
|
||||
}
|
||||
return _rowRecords.get(Integer.valueOf(rowIndex));
|
||||
}
|
||||
|
||||
public int getPhysicalNumberOfRows()
|
||||
{
|
||||
return _rowRecords.size();
|
||||
}
|
||||
public int getPhysicalNumberOfRows()
|
||||
{
|
||||
return _rowRecords.size();
|
||||
}
|
||||
|
||||
public int getFirstRowNum()
|
||||
{
|
||||
return _firstrow;
|
||||
}
|
||||
public int getFirstRowNum()
|
||||
{
|
||||
return _firstrow;
|
||||
}
|
||||
|
||||
public int getLastRowNum()
|
||||
{
|
||||
return _lastrow;
|
||||
}
|
||||
public int getLastRowNum()
|
||||
{
|
||||
return _lastrow;
|
||||
}
|
||||
|
||||
/** Returns the number of row blocks.
|
||||
* <p/>The row blocks are goupings of rows that contain the DBCell record
|
||||
* after them
|
||||
*/
|
||||
public int getRowBlockCount() {
|
||||
int size = _rowRecords.size()/DBCellRecord.BLOCK_SIZE;
|
||||
if ((_rowRecords.size() % DBCellRecord.BLOCK_SIZE) != 0)
|
||||
size++;
|
||||
return size;
|
||||
}
|
||||
/** Returns the number of row blocks.
|
||||
* <p/>The row blocks are goupings of rows that contain the DBCell record
|
||||
* after them
|
||||
*/
|
||||
public int getRowBlockCount() {
|
||||
int size = _rowRecords.size()/DBCellRecord.BLOCK_SIZE;
|
||||
if ((_rowRecords.size() % DBCellRecord.BLOCK_SIZE) != 0)
|
||||
size++;
|
||||
return size;
|
||||
}
|
||||
|
||||
private int getRowBlockSize(int block) {
|
||||
return RowRecord.ENCODED_SIZE * getRowCountForBlock(block);
|
||||
}
|
||||
private int getRowBlockSize(int block) {
|
||||
return RowRecord.ENCODED_SIZE * getRowCountForBlock(block);
|
||||
}
|
||||
|
||||
/** Returns the number of physical rows within a block*/
|
||||
public int getRowCountForBlock(int block) {
|
||||
int startIndex = block * DBCellRecord.BLOCK_SIZE;
|
||||
int endIndex = startIndex + DBCellRecord.BLOCK_SIZE - 1;
|
||||
if (endIndex >= _rowRecords.size())
|
||||
endIndex = _rowRecords.size()-1;
|
||||
/** Returns the number of physical rows within a block*/
|
||||
public int getRowCountForBlock(int block) {
|
||||
int startIndex = block * DBCellRecord.BLOCK_SIZE;
|
||||
int endIndex = startIndex + DBCellRecord.BLOCK_SIZE - 1;
|
||||
if (endIndex >= _rowRecords.size())
|
||||
endIndex = _rowRecords.size()-1;
|
||||
|
||||
return endIndex-startIndex+1;
|
||||
}
|
||||
return endIndex-startIndex+1;
|
||||
}
|
||||
|
||||
/** Returns the physical row number of the first row in a block*/
|
||||
private int getStartRowNumberForBlock(int block) {
|
||||
int startIndex = block * DBCellRecord.BLOCK_SIZE;
|
||||
/** Returns the physical row number of the first row in a block*/
|
||||
private int getStartRowNumberForBlock(int block) {
|
||||
int startIndex = block * DBCellRecord.BLOCK_SIZE;
|
||||
|
||||
if(_rowRecordValues == null){
|
||||
if (_rowRecordValues == null) {
|
||||
_rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]);
|
||||
}
|
||||
|
||||
try {
|
||||
return _rowRecordValues[startIndex].getRowNumber();
|
||||
} catch(ArrayIndexOutOfBoundsException e) {
|
||||
throw new RuntimeException("Did not find start row for block " + block);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Did not find start row for block " + block);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the physical row number of the end row in a block*/
|
||||
private int getEndRowNumberForBlock(int block) {
|
||||
int endIndex = ((block + 1)*DBCellRecord.BLOCK_SIZE)-1;
|
||||
if (endIndex >= _rowRecords.size())
|
||||
endIndex = _rowRecords.size()-1;
|
||||
/** Returns the physical row number of the end row in a block*/
|
||||
private int getEndRowNumberForBlock(int block) {
|
||||
int endIndex = ((block + 1)*DBCellRecord.BLOCK_SIZE)-1;
|
||||
if (endIndex >= _rowRecords.size())
|
||||
endIndex = _rowRecords.size()-1;
|
||||
|
||||
if(_rowRecordValues == null){
|
||||
if (_rowRecordValues == null){
|
||||
_rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]);
|
||||
}
|
||||
|
||||
|
@ -219,287 +219,287 @@ public final class RowRecordsAggregate extends RecordAggregate {
|
|||
return _rowRecordValues[endIndex].getRowNumber();
|
||||
} catch(ArrayIndexOutOfBoundsException e) {
|
||||
throw new RuntimeException("Did not find end row for block " + block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int visitRowRecordsForBlock(int blockIndex, RecordVisitor rv) {
|
||||
final int startIndex = blockIndex*DBCellRecord.BLOCK_SIZE;
|
||||
final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE;
|
||||
private int visitRowRecordsForBlock(int blockIndex, RecordVisitor rv) {
|
||||
final int startIndex = blockIndex*DBCellRecord.BLOCK_SIZE;
|
||||
final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE;
|
||||
|
||||
Iterator<RowRecord> rowIterator = _rowRecords.values().iterator();
|
||||
Iterator<RowRecord> rowIterator = _rowRecords.values().iterator();
|
||||
|
||||
//Given that we basically iterate through the rows in order,
|
||||
//For a performance improvement, it would be better to return an instance of
|
||||
//an iterator and use that instance throughout, rather than recreating one and
|
||||
//having to move it to the right position.
|
||||
int i=0;
|
||||
for (;i<startIndex;i++)
|
||||
rowIterator.next();
|
||||
int result = 0;
|
||||
while(rowIterator.hasNext() && (i++ < endIndex)) {
|
||||
Record rec = rowIterator.next();
|
||||
result += rec.getRecordSize();
|
||||
rv.visitRecord(rec);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//Given that we basically iterate through the rows in order,
|
||||
//For a performance improvement, it would be better to return an instance of
|
||||
//an iterator and use that instance throughout, rather than recreating one and
|
||||
//having to move it to the right position.
|
||||
int i=0;
|
||||
for (;i<startIndex;i++)
|
||||
rowIterator.next();
|
||||
int result = 0;
|
||||
while(rowIterator.hasNext() && (i++ < endIndex)) {
|
||||
Record rec = rowIterator.next();
|
||||
result += rec.getRecordSize();
|
||||
rv.visitRecord(rec);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitContainedRecords(RecordVisitor rv) {
|
||||
|
||||
PositionTrackingVisitor stv = new PositionTrackingVisitor(rv, 0);
|
||||
//DBCells are serialized before row records.
|
||||
final int blockCount = getRowBlockCount();
|
||||
for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) {
|
||||
// Serialize a block of rows.
|
||||
// Hold onto the position of the first row in the block
|
||||
int pos=0;
|
||||
// Hold onto the size of this block that was serialized
|
||||
final int rowBlockSize = visitRowRecordsForBlock(blockIndex, rv);
|
||||
pos += rowBlockSize;
|
||||
// Serialize a block of cells for those rows
|
||||
final int startRowNumber = getStartRowNumberForBlock(blockIndex);
|
||||
final int endRowNumber = getEndRowNumberForBlock(blockIndex);
|
||||
DBCellRecord.Builder dbcrBuilder = new DBCellRecord.Builder();
|
||||
// Note: Cell references start from the second row...
|
||||
int cellRefOffset = (rowBlockSize - RowRecord.ENCODED_SIZE);
|
||||
for (int row = startRowNumber; row <= endRowNumber; row++) {
|
||||
if (_valuesAgg.rowHasCells(row)) {
|
||||
stv.setPosition(0);
|
||||
_valuesAgg.visitCellsForRow(row, stv);
|
||||
int rowCellSize = stv.getPosition();
|
||||
pos += rowCellSize;
|
||||
// Add the offset to the first cell for the row into the
|
||||
// DBCellRecord.
|
||||
dbcrBuilder.addCellOffset(cellRefOffset);
|
||||
cellRefOffset = rowCellSize;
|
||||
}
|
||||
}
|
||||
// Calculate Offset from the start of a DBCellRecord to the first Row
|
||||
rv.visitRecord(dbcrBuilder.build(pos));
|
||||
}
|
||||
for (Record _unknownRecord : _unknownRecords) {
|
||||
// Potentially breaking the file here since we don't know exactly where to write these records
|
||||
rv.visitRecord(_unknownRecord);
|
||||
}
|
||||
}
|
||||
PositionTrackingVisitor stv = new PositionTrackingVisitor(rv, 0);
|
||||
//DBCells are serialized before row records.
|
||||
final int blockCount = getRowBlockCount();
|
||||
for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) {
|
||||
// Serialize a block of rows.
|
||||
// Hold onto the position of the first row in the block
|
||||
int pos=0;
|
||||
// Hold onto the size of this block that was serialized
|
||||
final int rowBlockSize = visitRowRecordsForBlock(blockIndex, rv);
|
||||
pos += rowBlockSize;
|
||||
// Serialize a block of cells for those rows
|
||||
final int startRowNumber = getStartRowNumberForBlock(blockIndex);
|
||||
final int endRowNumber = getEndRowNumberForBlock(blockIndex);
|
||||
DBCellRecord.Builder dbcrBuilder = new DBCellRecord.Builder();
|
||||
// Note: Cell references start from the second row...
|
||||
int cellRefOffset = (rowBlockSize - RowRecord.ENCODED_SIZE);
|
||||
for (int row = startRowNumber; row <= endRowNumber; row++) {
|
||||
if (_valuesAgg.rowHasCells(row)) {
|
||||
stv.setPosition(0);
|
||||
_valuesAgg.visitCellsForRow(row, stv);
|
||||
int rowCellSize = stv.getPosition();
|
||||
pos += rowCellSize;
|
||||
// Add the offset to the first cell for the row into the
|
||||
// DBCellRecord.
|
||||
dbcrBuilder.addCellOffset(cellRefOffset);
|
||||
cellRefOffset = rowCellSize;
|
||||
}
|
||||
}
|
||||
// Calculate Offset from the start of a DBCellRecord to the first Row
|
||||
rv.visitRecord(dbcrBuilder.build(pos));
|
||||
}
|
||||
for (Record _unknownRecord : _unknownRecords) {
|
||||
// Potentially breaking the file here since we don't know exactly where to write these records
|
||||
rv.visitRecord(_unknownRecord);
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator<RowRecord> getIterator() {
|
||||
return _rowRecords.values().iterator();
|
||||
}
|
||||
public Iterator<RowRecord> getIterator() {
|
||||
return _rowRecords.values().iterator();
|
||||
}
|
||||
|
||||
public int findStartOfRowOutlineGroup(int row) {
|
||||
// Find the start of the group.
|
||||
RowRecord rowRecord = this.getRow( row );
|
||||
int level = rowRecord.getOutlineLevel();
|
||||
int currentRow = row;
|
||||
while (currentRow >= 0 && this.getRow( currentRow ) != null) {
|
||||
rowRecord = this.getRow( currentRow );
|
||||
if (rowRecord.getOutlineLevel() < level) {
|
||||
return currentRow + 1;
|
||||
}
|
||||
currentRow--;
|
||||
}
|
||||
public int findStartOfRowOutlineGroup(int row) {
|
||||
// Find the start of the group.
|
||||
RowRecord rowRecord = this.getRow( row );
|
||||
int level = rowRecord.getOutlineLevel();
|
||||
int currentRow = row;
|
||||
while (currentRow >= 0 && this.getRow( currentRow ) != null) {
|
||||
rowRecord = this.getRow( currentRow );
|
||||
if (rowRecord.getOutlineLevel() < level) {
|
||||
return currentRow + 1;
|
||||
}
|
||||
currentRow--;
|
||||
}
|
||||
|
||||
return currentRow + 1;
|
||||
}
|
||||
return currentRow + 1;
|
||||
}
|
||||
|
||||
public int findEndOfRowOutlineGroup(int row) {
|
||||
int level = getRow( row ).getOutlineLevel();
|
||||
int currentRow;
|
||||
for (currentRow = row; currentRow < getLastRowNum(); currentRow++) {
|
||||
if (getRow(currentRow) == null || getRow(currentRow).getOutlineLevel() < level) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
public int findEndOfRowOutlineGroup(int row) {
|
||||
int level = getRow( row ).getOutlineLevel();
|
||||
int currentRow;
|
||||
for (currentRow = row; currentRow < getLastRowNum(); currentRow++) {
|
||||
if (getRow(currentRow) == null || getRow(currentRow).getOutlineLevel() < level) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return currentRow-1;
|
||||
}
|
||||
return currentRow-1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide all rows at or below the current outline level
|
||||
* @return index of the <em>next<em> row after the last row that gets hidden
|
||||
*/
|
||||
private int writeHidden(RowRecord pRowRecord, int row) {
|
||||
int rowIx = row;
|
||||
RowRecord rowRecord = pRowRecord;
|
||||
int level = rowRecord.getOutlineLevel();
|
||||
while (rowRecord != null && getRow(rowIx).getOutlineLevel() >= level) {
|
||||
rowRecord.setZeroHeight(true);
|
||||
rowIx++;
|
||||
rowRecord = getRow(rowIx);
|
||||
}
|
||||
return rowIx;
|
||||
}
|
||||
/**
|
||||
* Hide all rows at or below the current outline level
|
||||
* @return index of the <em>next<em> row after the last row that gets hidden
|
||||
*/
|
||||
private int writeHidden(RowRecord pRowRecord, int row) {
|
||||
int rowIx = row;
|
||||
RowRecord rowRecord = pRowRecord;
|
||||
int level = rowRecord.getOutlineLevel();
|
||||
while (rowRecord != null && getRow(rowIx).getOutlineLevel() >= level) {
|
||||
rowRecord.setZeroHeight(true);
|
||||
rowIx++;
|
||||
rowRecord = getRow(rowIx);
|
||||
}
|
||||
return rowIx;
|
||||
}
|
||||
|
||||
public void collapseRow(int rowNumber) {
|
||||
public void collapseRow(int rowNumber) {
|
||||
|
||||
// Find the start of the group.
|
||||
int startRow = findStartOfRowOutlineGroup(rowNumber);
|
||||
RowRecord rowRecord = getRow(startRow);
|
||||
// Find the start of the group.
|
||||
int startRow = findStartOfRowOutlineGroup(rowNumber);
|
||||
RowRecord rowRecord = getRow(startRow);
|
||||
|
||||
// Hide all the columns until the end of the group
|
||||
int nextRowIx = writeHidden(rowRecord, startRow);
|
||||
// Hide all the columns until the end of the group
|
||||
int nextRowIx = writeHidden(rowRecord, startRow);
|
||||
|
||||
RowRecord row = getRow(nextRowIx);
|
||||
if (row == null) {
|
||||
row = createRow(nextRowIx);
|
||||
insertRow(row);
|
||||
}
|
||||
// Write collapse field
|
||||
row.setColapsed(true);
|
||||
}
|
||||
RowRecord row = getRow(nextRowIx);
|
||||
if (row == null) {
|
||||
row = createRow(nextRowIx);
|
||||
insertRow(row);
|
||||
}
|
||||
// Write collapse field
|
||||
row.setColapsed(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a row record.
|
||||
*
|
||||
* @param rowNumber row number
|
||||
* @return RowRecord created for the passed in row number
|
||||
* @see org.apache.poi.hssf.record.RowRecord
|
||||
*/
|
||||
public static RowRecord createRow(int rowNumber) {
|
||||
return new RowRecord(rowNumber);
|
||||
}
|
||||
/**
|
||||
* Create a row record.
|
||||
*
|
||||
* @param rowNumber row number
|
||||
* @return RowRecord created for the passed in row number
|
||||
* @see org.apache.poi.hssf.record.RowRecord
|
||||
*/
|
||||
public static RowRecord createRow(int rowNumber) {
|
||||
return new RowRecord(rowNumber);
|
||||
}
|
||||
|
||||
public boolean isRowGroupCollapsed(int row) {
|
||||
int collapseRow = findEndOfRowOutlineGroup(row) + 1;
|
||||
public boolean isRowGroupCollapsed(int row) {
|
||||
int collapseRow = findEndOfRowOutlineGroup(row) + 1;
|
||||
|
||||
return getRow(collapseRow) != null && getRow(collapseRow).getColapsed();
|
||||
}
|
||||
return getRow(collapseRow) != null && getRow(collapseRow).getColapsed();
|
||||
}
|
||||
|
||||
public void expandRow(int rowNumber) {
|
||||
if (rowNumber == -1)
|
||||
return;
|
||||
public void expandRow(int rowNumber) {
|
||||
if (rowNumber == -1)
|
||||
return;
|
||||
|
||||
// If it is already expanded do nothing.
|
||||
if (!isRowGroupCollapsed(rowNumber)) {
|
||||
return;
|
||||
}
|
||||
// If it is already expanded do nothing.
|
||||
if (!isRowGroupCollapsed(rowNumber)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the start of the group.
|
||||
int startIdx = findStartOfRowOutlineGroup(rowNumber);
|
||||
RowRecord row = getRow(startIdx);
|
||||
// Find the start of the group.
|
||||
int startIdx = findStartOfRowOutlineGroup(rowNumber);
|
||||
RowRecord row = getRow(startIdx);
|
||||
|
||||
// Find the end of the group.
|
||||
int endIdx = findEndOfRowOutlineGroup(rowNumber);
|
||||
// Find the end of the group.
|
||||
int endIdx = findEndOfRowOutlineGroup(rowNumber);
|
||||
|
||||
// expand:
|
||||
// collapsed bit must be unset
|
||||
// hidden bit gets unset _if_ surrounding groups are expanded you can determine
|
||||
// this by looking at the hidden bit of the enclosing group. You will have
|
||||
// to look at the start and the end of the current group to determine which
|
||||
// is the enclosing group
|
||||
// hidden bit only is altered for this outline level. ie. don't un-collapse contained groups
|
||||
if (!isRowGroupHiddenByParent(rowNumber)) {
|
||||
for (int i = startIdx; i <= endIdx; i++) {
|
||||
RowRecord otherRow = getRow(i);
|
||||
if (row.getOutlineLevel() == otherRow.getOutlineLevel() || !isRowGroupCollapsed(i)) {
|
||||
otherRow.setZeroHeight(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// expand:
|
||||
// collapsed bit must be unset
|
||||
// hidden bit gets unset _if_ surrounding groups are expanded you can determine
|
||||
// this by looking at the hidden bit of the enclosing group. You will have
|
||||
// to look at the start and the end of the current group to determine which
|
||||
// is the enclosing group
|
||||
// hidden bit only is altered for this outline level. ie. don't un-collapse contained groups
|
||||
if (!isRowGroupHiddenByParent(rowNumber)) {
|
||||
for (int i = startIdx; i <= endIdx; i++) {
|
||||
RowRecord otherRow = getRow(i);
|
||||
if (row.getOutlineLevel() == otherRow.getOutlineLevel() || !isRowGroupCollapsed(i)) {
|
||||
otherRow.setZeroHeight(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write collapse field
|
||||
getRow(endIdx + 1).setColapsed(false);
|
||||
}
|
||||
// Write collapse field
|
||||
getRow(endIdx + 1).setColapsed(false);
|
||||
}
|
||||
|
||||
public boolean isRowGroupHiddenByParent(int row) {
|
||||
// Look out outline details of end
|
||||
int endLevel;
|
||||
boolean endHidden;
|
||||
int endOfOutlineGroupIdx = findEndOfRowOutlineGroup(row);
|
||||
if (getRow(endOfOutlineGroupIdx + 1) == null) {
|
||||
endLevel = 0;
|
||||
endHidden = false;
|
||||
} else {
|
||||
endLevel = getRow(endOfOutlineGroupIdx + 1).getOutlineLevel();
|
||||
endHidden = getRow(endOfOutlineGroupIdx + 1).getZeroHeight();
|
||||
}
|
||||
public boolean isRowGroupHiddenByParent(int row) {
|
||||
// Look out outline details of end
|
||||
int endLevel;
|
||||
boolean endHidden;
|
||||
int endOfOutlineGroupIdx = findEndOfRowOutlineGroup(row);
|
||||
if (getRow(endOfOutlineGroupIdx + 1) == null) {
|
||||
endLevel = 0;
|
||||
endHidden = false;
|
||||
} else {
|
||||
endLevel = getRow(endOfOutlineGroupIdx + 1).getOutlineLevel();
|
||||
endHidden = getRow(endOfOutlineGroupIdx + 1).getZeroHeight();
|
||||
}
|
||||
|
||||
// Look out outline details of start
|
||||
int startLevel;
|
||||
boolean startHidden;
|
||||
int startOfOutlineGroupIdx = findStartOfRowOutlineGroup( row );
|
||||
if (startOfOutlineGroupIdx - 1 < 0 || getRow(startOfOutlineGroupIdx - 1) == null) {
|
||||
startLevel = 0;
|
||||
startHidden = false;
|
||||
} else {
|
||||
startLevel = getRow(startOfOutlineGroupIdx - 1).getOutlineLevel();
|
||||
startHidden = getRow(startOfOutlineGroupIdx - 1).getZeroHeight();
|
||||
}
|
||||
// Look out outline details of start
|
||||
int startLevel;
|
||||
boolean startHidden;
|
||||
int startOfOutlineGroupIdx = findStartOfRowOutlineGroup( row );
|
||||
if (startOfOutlineGroupIdx - 1 < 0 || getRow(startOfOutlineGroupIdx - 1) == null) {
|
||||
startLevel = 0;
|
||||
startHidden = false;
|
||||
} else {
|
||||
startLevel = getRow(startOfOutlineGroupIdx - 1).getOutlineLevel();
|
||||
startHidden = getRow(startOfOutlineGroupIdx - 1).getZeroHeight();
|
||||
}
|
||||
|
||||
if (endLevel > startLevel) {
|
||||
return endHidden;
|
||||
}
|
||||
if (endLevel > startLevel) {
|
||||
return endHidden;
|
||||
}
|
||||
|
||||
return startHidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator for the cell values
|
||||
*/
|
||||
public Iterator<CellValueRecordInterface> getCellValueIterator() {
|
||||
return _valuesAgg.iterator();
|
||||
}
|
||||
return startHidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator for the cell values
|
||||
*/
|
||||
public Iterator<CellValueRecordInterface> getCellValueIterator() {
|
||||
return _valuesAgg.iterator();
|
||||
}
|
||||
|
||||
public IndexRecord createIndexRecord(int indexRecordOffset, int sizeOfInitialSheetRecords) {
|
||||
IndexRecord result = new IndexRecord();
|
||||
result.setFirstRow(_firstrow);
|
||||
result.setLastRowAdd1(_lastrow + 1);
|
||||
// Calculate the size of the records from the end of the BOF
|
||||
// and up to the RowRecordsAggregate...
|
||||
public IndexRecord createIndexRecord(int indexRecordOffset, int sizeOfInitialSheetRecords) {
|
||||
IndexRecord result = new IndexRecord();
|
||||
result.setFirstRow(_firstrow);
|
||||
result.setLastRowAdd1(_lastrow + 1);
|
||||
// Calculate the size of the records from the end of the BOF
|
||||
// and up to the RowRecordsAggregate...
|
||||
|
||||
// Add the references to the DBCells in the IndexRecord (one for each block)
|
||||
// Note: The offsets are relative to the Workbook BOF. Assume that this is
|
||||
// 0 for now.....
|
||||
// Add the references to the DBCells in the IndexRecord (one for each block)
|
||||
// Note: The offsets are relative to the Workbook BOF. Assume that this is
|
||||
// 0 for now.....
|
||||
|
||||
int blockCount = getRowBlockCount();
|
||||
// Calculate the size of this IndexRecord
|
||||
int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount);
|
||||
int blockCount = getRowBlockCount();
|
||||
// Calculate the size of this IndexRecord
|
||||
int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount);
|
||||
|
||||
int currentOffset = indexRecordOffset + indexRecSize + sizeOfInitialSheetRecords;
|
||||
int currentOffset = indexRecordOffset + indexRecSize + sizeOfInitialSheetRecords;
|
||||
|
||||
for (int block = 0; block < blockCount; block++) {
|
||||
// each row-block has a DBCELL record.
|
||||
// The offset of each DBCELL record needs to be updated in the INDEX record
|
||||
for (int block = 0; block < blockCount; block++) {
|
||||
// each row-block has a DBCELL record.
|
||||
// The offset of each DBCELL record needs to be updated in the INDEX record
|
||||
|
||||
// account for row records in this row-block
|
||||
currentOffset += getRowBlockSize(block);
|
||||
// account for cell value records after those
|
||||
currentOffset += _valuesAgg.getRowCellBlockSize(
|
||||
getStartRowNumberForBlock(block), getEndRowNumberForBlock(block));
|
||||
// account for row records in this row-block
|
||||
currentOffset += getRowBlockSize(block);
|
||||
// account for cell value records after those
|
||||
currentOffset += _valuesAgg.getRowCellBlockSize(
|
||||
getStartRowNumberForBlock(block), getEndRowNumberForBlock(block));
|
||||
|
||||
// currentOffset is now the location of the DBCELL record for this row-block
|
||||
result.addDbcell(currentOffset);
|
||||
// Add space required to write the DBCELL record (whose reference was just added).
|
||||
currentOffset += (8 + (getRowCountForBlock(block) * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public void insertCell(CellValueRecordInterface cvRec) {
|
||||
_valuesAgg.insertCell(cvRec);
|
||||
}
|
||||
public void removeCell(CellValueRecordInterface cvRec) {
|
||||
if (cvRec instanceof FormulaRecordAggregate) {
|
||||
((FormulaRecordAggregate)cvRec).notifyFormulaChanging();
|
||||
}
|
||||
_valuesAgg.removeCell(cvRec);
|
||||
}
|
||||
public FormulaRecordAggregate createFormula(int row, int col) {
|
||||
FormulaRecord fr = new FormulaRecord();
|
||||
fr.setRow(row);
|
||||
fr.setColumn((short) col);
|
||||
return new FormulaRecordAggregate(fr, null, _sharedValueManager);
|
||||
}
|
||||
public void updateFormulasAfterRowShift(FormulaShifter formulaShifter, int currentExternSheetIndex) {
|
||||
_valuesAgg.updateFormulasAfterRowShift(formulaShifter, currentExternSheetIndex);
|
||||
}
|
||||
public DimensionsRecord createDimensions() {
|
||||
DimensionsRecord result = new DimensionsRecord();
|
||||
result.setFirstRow(_firstrow);
|
||||
result.setLastRow(_lastrow);
|
||||
result.setFirstCol((short) _valuesAgg.getFirstCellNum());
|
||||
result.setLastCol((short) _valuesAgg.getLastCellNum());
|
||||
return result;
|
||||
}
|
||||
// currentOffset is now the location of the DBCELL record for this row-block
|
||||
result.addDbcell(currentOffset);
|
||||
// Add space required to write the DBCELL record (whose reference was just added).
|
||||
currentOffset += (8 + (getRowCountForBlock(block) * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public void insertCell(CellValueRecordInterface cvRec) {
|
||||
_valuesAgg.insertCell(cvRec);
|
||||
}
|
||||
public void removeCell(CellValueRecordInterface cvRec) {
|
||||
if (cvRec instanceof FormulaRecordAggregate) {
|
||||
((FormulaRecordAggregate)cvRec).notifyFormulaChanging();
|
||||
}
|
||||
_valuesAgg.removeCell(cvRec);
|
||||
}
|
||||
public FormulaRecordAggregate createFormula(int row, int col) {
|
||||
FormulaRecord fr = new FormulaRecord();
|
||||
fr.setRow(row);
|
||||
fr.setColumn((short) col);
|
||||
return new FormulaRecordAggregate(fr, null, _sharedValueManager);
|
||||
}
|
||||
public void updateFormulasAfterRowShift(FormulaShifter formulaShifter, int currentExternSheetIndex) {
|
||||
_valuesAgg.updateFormulasAfterRowShift(formulaShifter, currentExternSheetIndex);
|
||||
}
|
||||
public DimensionsRecord createDimensions() {
|
||||
DimensionsRecord result = new DimensionsRecord();
|
||||
result.setFirstRow(_firstrow);
|
||||
result.setLastRow(_lastrow);
|
||||
result.setFirstCol((short) _valuesAgg.getFirstCellNum());
|
||||
result.setLastCol((short) _valuesAgg.getLastCellNum());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ package org.apache.poi.hssf.usermodel;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.ss.formula.BaseFormulaEvaluator;
|
||||
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment;
|
||||
import org.apache.poi.ss.formula.IStabilityClassifier;
|
||||
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
||||
import org.apache.poi.ss.formula.WorkbookEvaluatorProvider;
|
||||
import org.apache.poi.ss.formula.eval.BoolEval;
|
||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||
import org.apache.poi.ss.formula.eval.NumericValueEval;
|
||||
|
@ -33,8 +33,6 @@ import org.apache.poi.ss.usermodel.Cell;
|
|||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.CellValue;
|
||||
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.util.Internal;
|
||||
|
||||
|
@ -45,362 +43,251 @@ import org.apache.poi.util.Internal;
|
|||
* cell values. Be sure to call {@link #clearAllCachedResultValues()} if any workbook cells are changed between
|
||||
* calls to evaluate~ methods on this class.
|
||||
*/
|
||||
public class HSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluatorProvider {
|
||||
public class HSSFFormulaEvaluator extends BaseFormulaEvaluator {
|
||||
private final HSSFWorkbook _book;
|
||||
|
||||
private final WorkbookEvaluator _bookEvaluator;
|
||||
private final HSSFWorkbook _book;
|
||||
|
||||
public HSSFFormulaEvaluator(HSSFWorkbook workbook) {
|
||||
this(workbook, null);
|
||||
}
|
||||
/**
|
||||
* @param workbook The workbook to perform the formula evaluations in
|
||||
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
|
||||
* for the (conservative) assumption that any cell may have its definition changed after
|
||||
* evaluation begins.
|
||||
*/
|
||||
public HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier) {
|
||||
this(workbook, stabilityClassifier, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param workbook The workbook to perform the formula evaluations in
|
||||
public HSSFFormulaEvaluator(HSSFWorkbook workbook) {
|
||||
this(workbook, null);
|
||||
}
|
||||
/**
|
||||
* @param workbook The workbook to perform the formula evaluations in
|
||||
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
|
||||
* for the (conservative) assumption that any cell may have its definition changed after
|
||||
* evaluation begins.
|
||||
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
|
||||
*/
|
||||
private HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
|
||||
_book = workbook;
|
||||
_bookEvaluator = new WorkbookEvaluator(HSSFEvaluationWorkbook.create(workbook), stabilityClassifier, udfFinder);
|
||||
}
|
||||
*/
|
||||
public HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier) {
|
||||
this(workbook, stabilityClassifier, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param workbook The workbook to perform the formula evaluations in
|
||||
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
|
||||
* for the (conservative) assumption that any cell may have its definition changed after
|
||||
* evaluation begins.
|
||||
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
|
||||
*/
|
||||
public static HSSFFormulaEvaluator create(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
|
||||
return new HSSFFormulaEvaluator(workbook, stabilityClassifier, udfFinder);
|
||||
}
|
||||
/**
|
||||
* @param workbook The workbook to perform the formula evaluations in
|
||||
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
|
||||
* for the (conservative) assumption that any cell may have its definition changed after
|
||||
* evaluation begins.
|
||||
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
|
||||
*/
|
||||
private HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
|
||||
super(new WorkbookEvaluator(HSSFEvaluationWorkbook.create(workbook), stabilityClassifier, udfFinder));
|
||||
_book = workbook;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param workbook The workbook to perform the formula evaluations in
|
||||
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code>
|
||||
* for the (conservative) assumption that any cell may have its definition changed after
|
||||
* evaluation begins.
|
||||
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
|
||||
*/
|
||||
public static HSSFFormulaEvaluator create(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
|
||||
return new HSSFFormulaEvaluator(workbook, stabilityClassifier, udfFinder);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Coordinates several formula evaluators together so that formulas that involve external
|
||||
* references can be evaluated.
|
||||
* @param workbookNames the simple file names used to identify the workbooks in formulas
|
||||
* with external links (for example "MyData.xls" as used in a formula "[MyData.xls]Sheet1!A1")
|
||||
* @param evaluators all evaluators for the full set of workbooks required by the formulas.
|
||||
*/
|
||||
public static void setupEnvironment(String[] workbookNames, HSSFFormulaEvaluator[] evaluators) {
|
||||
WorkbookEvaluator[] wbEvals = new WorkbookEvaluator[evaluators.length];
|
||||
for (int i = 0; i < wbEvals.length; i++) {
|
||||
wbEvals[i] = evaluators[i]._bookEvaluator;
|
||||
}
|
||||
CollaboratingWorkbooksEnvironment.setup(workbookNames, wbEvals);
|
||||
}
|
||||
/**
|
||||
* Coordinates several formula evaluators together so that formulas that involve external
|
||||
* references can be evaluated.
|
||||
* @param workbookNames the simple file names used to identify the workbooks in formulas
|
||||
* with external links (for example "MyData.xls" as used in a formula "[MyData.xls]Sheet1!A1")
|
||||
* @param evaluators all evaluators for the full set of workbooks required by the formulas.
|
||||
*/
|
||||
public static void setupEnvironment(String[] workbookNames, HSSFFormulaEvaluator[] evaluators) {
|
||||
BaseFormulaEvaluator.setupEnvironment(workbookNames, evaluators);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public void setupReferencedWorkbooks(Map<String, FormulaEvaluator> evaluators) {
|
||||
CollaboratingWorkbooksEnvironment.setupFormulaEvaluator(evaluators);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkbookEvaluator _getWorkbookEvaluator() {
|
||||
return _bookEvaluator;
|
||||
|
||||
/**
|
||||
* Should be called to tell the cell value cache that the specified (value or formula) cell
|
||||
* has changed.
|
||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||
* of the evaluate~ methods of this class
|
||||
*/
|
||||
public void notifyUpdateCell(HSSFCell cell) {
|
||||
_bookEvaluator.notifyUpdateCell(new HSSFEvaluationCell(cell));
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called whenever there are major changes (e.g. moving sheets) to input cells
|
||||
* in the evaluated workbook. If performance is not critical, a single call to this method
|
||||
* may be used instead of many specific calls to the notify~ methods.
|
||||
*
|
||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||
* of the evaluate~ methods of this class
|
||||
*/
|
||||
@Override
|
||||
public void clearAllCachedResultValues() {
|
||||
_bookEvaluator.clearAllCachedResultValues();
|
||||
}
|
||||
/**
|
||||
* Should be called to tell the cell value cache that the specified (value or formula) cell
|
||||
* has changed.
|
||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||
* of the evaluate~ methods of this class
|
||||
*/
|
||||
public void notifyUpdateCell(HSSFCell cell) {
|
||||
_bookEvaluator.notifyUpdateCell(new HSSFEvaluationCell(cell));
|
||||
}
|
||||
@Override
|
||||
public void notifyUpdateCell(Cell cell) {
|
||||
_bookEvaluator.notifyUpdateCell(new HSSFEvaluationCell((HSSFCell)cell));
|
||||
}
|
||||
/**
|
||||
* Should be called to tell the cell value cache that the specified cell has just been
|
||||
* deleted.
|
||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||
* of the evaluate~ methods of this class
|
||||
*/
|
||||
public void notifyDeleteCell(HSSFCell cell) {
|
||||
_bookEvaluator.notifyDeleteCell(new HSSFEvaluationCell(cell));
|
||||
}
|
||||
@Override
|
||||
/**
|
||||
* Should be called to tell the cell value cache that the specified cell has just been
|
||||
* deleted.
|
||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||
* of the evaluate~ methods of this class
|
||||
*/
|
||||
public void notifyDeleteCell(HSSFCell cell) {
|
||||
_bookEvaluator.notifyDeleteCell(new HSSFEvaluationCell(cell));
|
||||
}
|
||||
@Override
|
||||
public void notifyDeleteCell(Cell cell) {
|
||||
_bookEvaluator.notifyDeleteCell(new HSSFEvaluationCell((HSSFCell)cell));
|
||||
}
|
||||
_bookEvaluator.notifyDeleteCell(new HSSFEvaluationCell((HSSFCell)cell));
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called to tell the cell value cache that the specified (value or formula) cell
|
||||
* has changed.
|
||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||
* of the evaluate~ methods of this class
|
||||
*/
|
||||
@Override
|
||||
/**
|
||||
* Should be called to tell the cell value cache that the specified (value or formula) cell
|
||||
* has changed.
|
||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||
* of the evaluate~ methods of this class
|
||||
*/
|
||||
@Override
|
||||
public void notifySetFormula(Cell cell) {
|
||||
_bookEvaluator.notifyUpdateCell(new HSSFEvaluationCell((HSSFCell)cell));
|
||||
}
|
||||
_bookEvaluator.notifyUpdateCell(new HSSFEvaluationCell((HSSFCell)cell));
|
||||
}
|
||||
|
||||
/**
|
||||
* If cell contains a formula, the formula is evaluated and returned,
|
||||
* else the CellValue simply copies the appropriate cell value from
|
||||
* the cell and also its cell type. This method should be preferred over
|
||||
* evaluateInCell() when the call should not modify the contents of the
|
||||
* original cell.
|
||||
*
|
||||
* @param cell may be <code>null</code> signifying that the cell is not present (or blank)
|
||||
* @return <code>null</code> if the supplied cell is <code>null</code> or blank
|
||||
*/
|
||||
@Override
|
||||
public CellValue evaluate(Cell cell) {
|
||||
if (cell == null) {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* If cell contains formula, it evaluates the formula, and saves the result of the formula. The
|
||||
* cell remains as a formula cell. If the cell does not contain formula, rather than throwing an
|
||||
* exception, this method returns {@link CellType#_NONE} and leaves the cell unchanged.
|
||||
*
|
||||
* Note that the type of the <em>formula result</em> is returned, so you know what kind of
|
||||
* cached formula result is also stored with the formula.
|
||||
* <pre>
|
||||
* CellType evaluatedCellType = evaluator.evaluateFormulaCell(cell);
|
||||
* </pre>
|
||||
* Be aware that your cell will hold both the formula, and the result. If you want the cell
|
||||
* replaced with the result of the formula, use {@link #evaluateInCell(org.apache.poi.ss.usermodel.Cell)}
|
||||
* @param cell The cell to evaluate
|
||||
* @return {@link CellType#_NONE} for non-formula cells, or the type of the <em>formula result</em>
|
||||
* @since POI 3.15 beta 3
|
||||
* @deprecated POI 3.15 beta 3. Will be deleted when we make the CellType enum transition. See bug 59791.
|
||||
*/
|
||||
@Internal
|
||||
@Override
|
||||
public CellType evaluateFormulaCellEnum(Cell cell) {
|
||||
if (cell == null || cell.getCellTypeEnum() != CellType.FORMULA) {
|
||||
return CellType._NONE;
|
||||
}
|
||||
CellValue cv = evaluateFormulaCellValue(cell);
|
||||
// cell remains a formula cell, but the cached value is changed
|
||||
setCellValue(cell, cv);
|
||||
return cv.getCellType();
|
||||
}
|
||||
|
||||
switch (cell.getCellTypeEnum()) {
|
||||
case BOOLEAN:
|
||||
return CellValue.valueOf(cell.getBooleanCellValue());
|
||||
case ERROR:
|
||||
return CellValue.getError(cell.getErrorCellValue());
|
||||
case FORMULA:
|
||||
return evaluateFormulaCellValue(cell);
|
||||
case NUMERIC:
|
||||
return new CellValue(cell.getNumericCellValue());
|
||||
case STRING:
|
||||
return new CellValue(cell.getRichStringCellValue().getString());
|
||||
case BLANK:
|
||||
return null;
|
||||
default:
|
||||
throw new IllegalStateException("Bad cell type (" + cell.getCellTypeEnum() + ")");
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* If cell contains formula, it evaluates the formula, and
|
||||
* puts the formula result back into the cell, in place
|
||||
* of the old formula.
|
||||
* Else if cell does not contain formula, this method leaves
|
||||
* the cell unchanged.
|
||||
* Note that the same instance of HSSFCell is returned to
|
||||
* allow chained calls like:
|
||||
* <pre>
|
||||
* int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
|
||||
* </pre>
|
||||
* Be aware that your cell value will be changed to hold the
|
||||
* result of the formula. If you simply want the formula
|
||||
* value computed for you, use {@link #evaluateFormulaCellEnum(Cell)}}
|
||||
*/
|
||||
@Override
|
||||
public HSSFCell evaluateInCell(Cell cell) {
|
||||
if (cell == null) {
|
||||
return null;
|
||||
}
|
||||
HSSFCell result = (HSSFCell) cell;
|
||||
if (cell.getCellTypeEnum() == CellType.FORMULA) {
|
||||
CellValue cv = evaluateFormulaCellValue(cell);
|
||||
setCellValue(cell, cv);
|
||||
setCellType(cell, cv); // cell will no longer be a formula cell
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void setCellValue(Cell cell, CellValue cv) {
|
||||
CellType cellType = cv.getCellType();
|
||||
switch (cellType) {
|
||||
case BOOLEAN:
|
||||
cell.setCellValue(cv.getBooleanValue());
|
||||
break;
|
||||
case ERROR:
|
||||
cell.setCellErrorValue(cv.getErrorValue());
|
||||
break;
|
||||
case NUMERIC:
|
||||
cell.setCellValue(cv.getNumberValue());
|
||||
break;
|
||||
case STRING:
|
||||
cell.setCellValue(new HSSFRichTextString(cv.getStringValue()));
|
||||
break;
|
||||
case BLANK:
|
||||
// never happens - blanks eventually get translated to zero
|
||||
case FORMULA:
|
||||
// this will never happen, we have already evaluated the formula
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If cell contains formula, it evaluates the formula, and saves the result of the formula. The
|
||||
* cell remains as a formula cell. If the cell does not contain formula, this method returns -1
|
||||
* and leaves the cell unchanged.
|
||||
*
|
||||
* Note that the type of the <em>formula result</em> is returned, so you know what kind of
|
||||
* cached formula result is also stored with the formula.
|
||||
* <pre>
|
||||
* int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
|
||||
* </pre>
|
||||
* Be aware that your cell will hold both the formula, and the result. If you want the cell
|
||||
* replaced with the result of the formula, use {@link #evaluateInCell(org.apache.poi.ss.usermodel.Cell)}
|
||||
* @param cell The cell to evaluate
|
||||
* @return -1 for non-formula cells, or the type of the <em>formula result</em>
|
||||
*/
|
||||
@Override
|
||||
public int evaluateFormulaCell(Cell cell) {
|
||||
return evaluateFormulaCellEnum(cell).getCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* If cell contains formula, it evaluates the formula, and saves the result of the formula. The
|
||||
* cell remains as a formula cell. If the cell does not contain formula, rather than throwing an
|
||||
* exception, this method returns {@link CellType#_NONE} and leaves the cell unchanged.
|
||||
*
|
||||
* Note that the type of the <em>formula result</em> is returned, so you know what kind of
|
||||
* cached formula result is also stored with the formula.
|
||||
* <pre>
|
||||
* CellType evaluatedCellType = evaluator.evaluateFormulaCell(cell);
|
||||
* </pre>
|
||||
* Be aware that your cell will hold both the formula, and the result. If you want the cell
|
||||
* replaced with the result of the formula, use {@link #evaluateInCell(org.apache.poi.ss.usermodel.Cell)}
|
||||
* @param cell The cell to evaluate
|
||||
* @return {@link CellType#_NONE} for non-formula cells, or the type of the <em>formula result</em>
|
||||
* @since POI 3.15 beta 3
|
||||
* @deprecated POI 3.15 beta 3. Will be deleted when we make the CellType enum transition. See bug 59791.
|
||||
*/
|
||||
@Internal
|
||||
@Override
|
||||
public CellType evaluateFormulaCellEnum(Cell cell) {
|
||||
if (cell == null || cell.getCellTypeEnum() != CellType.FORMULA) {
|
||||
return CellType._NONE;
|
||||
}
|
||||
CellValue cv = evaluateFormulaCellValue(cell);
|
||||
// cell remains a formula cell, but the cached value is changed
|
||||
setCellValue(cell, cv);
|
||||
return cv.getCellType();
|
||||
}
|
||||
/**
|
||||
* Loops over all cells in all sheets of the supplied
|
||||
* workbook.
|
||||
* For cells that contain formulas, their formulas are
|
||||
* evaluated, and the results are saved. These cells
|
||||
* remain as formula cells.
|
||||
* For cells that do not contain formulas, no changes
|
||||
* are made.
|
||||
* This is a helpful wrapper around looping over all
|
||||
* cells, and calling evaluateFormulaCell on each one.
|
||||
*/
|
||||
public static void evaluateAllFormulaCells(HSSFWorkbook wb) {
|
||||
evaluateAllFormulaCells(wb, new HSSFFormulaEvaluator(wb));
|
||||
}
|
||||
|
||||
/**
|
||||
* If cell contains formula, it evaluates the formula, and
|
||||
* puts the formula result back into the cell, in place
|
||||
* of the old formula.
|
||||
* Else if cell does not contain formula, this method leaves
|
||||
* the cell unchanged.
|
||||
* Note that the same instance of HSSFCell is returned to
|
||||
* allow chained calls like:
|
||||
* <pre>
|
||||
* int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
|
||||
* </pre>
|
||||
* Be aware that your cell value will be changed to hold the
|
||||
* result of the formula. If you simply want the formula
|
||||
* value computed for you, use {@link #evaluateFormulaCellEnum(Cell)}}
|
||||
*/
|
||||
@Override
|
||||
public HSSFCell evaluateInCell(Cell cell) {
|
||||
if (cell == null) {
|
||||
return null;
|
||||
}
|
||||
HSSFCell result = (HSSFCell) cell;
|
||||
if (cell.getCellTypeEnum() == CellType.FORMULA) {
|
||||
CellValue cv = evaluateFormulaCellValue(cell);
|
||||
setCellValue(cell, cv);
|
||||
setCellType(cell, cv); // cell will no longer be a formula cell
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private static void setCellType(Cell cell, CellValue cv) {
|
||||
CellType cellType = cv.getCellType();
|
||||
switch (cellType) {
|
||||
case BOOLEAN:
|
||||
case ERROR:
|
||||
case NUMERIC:
|
||||
case STRING:
|
||||
cell.setCellType(cellType);
|
||||
return;
|
||||
case BLANK:
|
||||
// never happens - blanks eventually get translated to zero
|
||||
case FORMULA:
|
||||
// this will never happen, we have already evaluated the formula
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Loops over all cells in all sheets of the supplied
|
||||
* workbook.
|
||||
* For cells that contain formulas, their formulas are
|
||||
* evaluated, and the results are saved. These cells
|
||||
* remain as formula cells.
|
||||
* For cells that do not contain formulas, no changes
|
||||
* are made.
|
||||
* This is a helpful wrapper around looping over all
|
||||
* cells, and calling evaluateFormulaCell on each one.
|
||||
*/
|
||||
public static void evaluateAllFormulaCells(Workbook wb) {
|
||||
BaseFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||
}
|
||||
|
||||
private static void setCellValue(Cell cell, CellValue cv) {
|
||||
CellType cellType = cv.getCellType();
|
||||
switch (cellType) {
|
||||
case BOOLEAN:
|
||||
cell.setCellValue(cv.getBooleanValue());
|
||||
break;
|
||||
case ERROR:
|
||||
cell.setCellErrorValue(cv.getErrorValue());
|
||||
break;
|
||||
case NUMERIC:
|
||||
cell.setCellValue(cv.getNumberValue());
|
||||
break;
|
||||
case STRING:
|
||||
cell.setCellValue(new HSSFRichTextString(cv.getStringValue()));
|
||||
break;
|
||||
case BLANK:
|
||||
// never happens - blanks eventually get translated to zero
|
||||
case FORMULA:
|
||||
// this will never happen, we have already evaluated the formula
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Loops over all cells in all sheets of the supplied
|
||||
* workbook.
|
||||
* For cells that contain formulas, their formulas are
|
||||
* evaluated, and the results are saved. These cells
|
||||
* remain as formula cells.
|
||||
* For cells that do not contain formulas, no changes
|
||||
* are made.
|
||||
* This is a helpful wrapper around looping over all
|
||||
* cells, and calling evaluateFormulaCell on each one.
|
||||
*/
|
||||
@Override
|
||||
public void evaluateAll() {
|
||||
evaluateAllFormulaCells(_book, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops over all cells in all sheets of the supplied
|
||||
* workbook.
|
||||
* For cells that contain formulas, their formulas are
|
||||
* evaluated, and the results are saved. These cells
|
||||
* remain as formula cells.
|
||||
* For cells that do not contain formulas, no changes
|
||||
* are made.
|
||||
* This is a helpful wrapper around looping over all
|
||||
* cells, and calling evaluateFormulaCell on each one.
|
||||
*/
|
||||
public static void evaluateAllFormulaCells(HSSFWorkbook wb) {
|
||||
evaluateAllFormulaCells(wb, new HSSFFormulaEvaluator(wb));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops over all cells in all sheets of the supplied
|
||||
* workbook.
|
||||
* For cells that contain formulas, their formulas are
|
||||
* evaluated, and the results are saved. These cells
|
||||
* remain as formula cells.
|
||||
* For cells that do not contain formulas, no changes
|
||||
* are made.
|
||||
* This is a helpful wrapper around looping over all
|
||||
* cells, and calling evaluateFormulaCell on each one.
|
||||
*/
|
||||
public static void evaluateAllFormulaCells(Workbook wb) {
|
||||
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
||||
evaluateAllFormulaCells(wb, evaluator);
|
||||
}
|
||||
private static void evaluateAllFormulaCells(Workbook wb, FormulaEvaluator evaluator) {
|
||||
for(int i=0; i<wb.getNumberOfSheets(); i++) {
|
||||
Sheet sheet = wb.getSheetAt(i);
|
||||
|
||||
for(Row r : sheet) {
|
||||
for (Cell c : r) {
|
||||
if (c.getCellTypeEnum() == CellType.FORMULA) {
|
||||
evaluator.evaluateFormulaCellEnum(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops over all cells in all sheets of the supplied
|
||||
* workbook.
|
||||
* For cells that contain formulas, their formulas are
|
||||
* evaluated, and the results are saved. These cells
|
||||
* remain as formula cells.
|
||||
* For cells that do not contain formulas, no changes
|
||||
* are made.
|
||||
* This is a helpful wrapper around looping over all
|
||||
* cells, and calling evaluateFormulaCell on each one.
|
||||
*/
|
||||
@Override
|
||||
public void evaluateAll() {
|
||||
evaluateAllFormulaCells(_book, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CellValue wrapper around the supplied ValueEval instance.
|
||||
* @param cell
|
||||
*/
|
||||
private CellValue evaluateFormulaCellValue(Cell cell) {
|
||||
ValueEval eval = _bookEvaluator.evaluate(new HSSFEvaluationCell((HSSFCell)cell));
|
||||
if (eval instanceof BoolEval) {
|
||||
BoolEval be = (BoolEval) eval;
|
||||
return CellValue.valueOf(be.getBooleanValue());
|
||||
}
|
||||
if (eval instanceof NumericValueEval) {
|
||||
NumericValueEval ne = (NumericValueEval) eval;
|
||||
return new CellValue(ne.getNumberValue());
|
||||
}
|
||||
if (eval instanceof StringValueEval) {
|
||||
StringValueEval ne = (StringValueEval) eval;
|
||||
return new CellValue(ne.getStringValue());
|
||||
}
|
||||
if (eval instanceof ErrorEval) {
|
||||
return CellValue.getError(((ErrorEval)eval).getErrorCode());
|
||||
}
|
||||
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
|
||||
}
|
||||
/**
|
||||
* Returns a CellValue wrapper around the supplied ValueEval instance.
|
||||
* @param cell
|
||||
*/
|
||||
protected CellValue evaluateFormulaCellValue(Cell cell) {
|
||||
ValueEval eval = _bookEvaluator.evaluate(new HSSFEvaluationCell((HSSFCell)cell));
|
||||
if (eval instanceof BoolEval) {
|
||||
BoolEval be = (BoolEval) eval;
|
||||
return CellValue.valueOf(be.getBooleanValue());
|
||||
}
|
||||
if (eval instanceof NumericValueEval) {
|
||||
NumericValueEval ne = (NumericValueEval) eval;
|
||||
return new CellValue(ne.getNumberValue());
|
||||
}
|
||||
if (eval instanceof StringValueEval) {
|
||||
StringValueEval ne = (StringValueEval) eval;
|
||||
return new CellValue(ne.getStringValue());
|
||||
}
|
||||
if (eval instanceof ErrorEval) {
|
||||
return CellValue.getError(((ErrorEval)eval).getErrorCode());
|
||||
}
|
||||
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
|
|
|
@ -92,6 +92,7 @@ import org.apache.poi.ss.formula.SheetNameFormatter;
|
|||
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
|
||||
import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
|
||||
import org.apache.poi.ss.formula.udf.UDFFinder;
|
||||
import org.apache.poi.ss.usermodel.Name;
|
||||
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
@ -548,7 +549,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||
* the 'active' sheet (which is the sheet with focus).
|
||||
* Unselects sheets that are not in <code>indexes</code>.
|
||||
*
|
||||
* @param indexes
|
||||
* @param indexes Array of sheets to select, the index is 0-based.
|
||||
*/
|
||||
public void setSelectedTabs(int[] indexes) {
|
||||
Collection<Integer> list = new ArrayList<Integer>(indexes.length);
|
||||
|
@ -563,7 +564,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||
* the 'active' sheet (which is the sheet with focus).
|
||||
* Unselects sheets that are not in <code>indexes</code>.
|
||||
*
|
||||
* @param indexes
|
||||
* @param indexes Collection of sheets to select, the index is 0-based.
|
||||
*/
|
||||
public void setSelectedTabs(Collection<Integer> indexes) {
|
||||
|
||||
|
@ -893,8 +894,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||
*/
|
||||
@Override
|
||||
public Iterator<Sheet> sheetIterator() {
|
||||
Iterator<Sheet> result = new SheetIterator<Sheet>();
|
||||
return result;
|
||||
return new SheetIterator<Sheet>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1280,9 +1280,9 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||
|
||||
/**
|
||||
* Closes the underlying {@link NPOIFSFileSystem} from which
|
||||
* the Workbook was read, if any. Has no effect on Workbooks
|
||||
* opened from an InputStream, or newly created ones.
|
||||
* <p>Once {@link #close()} has been called, no further
|
||||
* the Workbook was read, if any.
|
||||
*
|
||||
* <p>Once this has been called, no further
|
||||
* operations, updates or reads should be performed on the
|
||||
* Workbook.
|
||||
*/
|
||||
|
@ -1531,6 +1531,11 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||
return names.get(nameIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HSSFName> getAllNames() {
|
||||
return Collections.unmodifiableList(names);
|
||||
}
|
||||
|
||||
public NameRecord getNameRecord(int nameIndex) {
|
||||
return getWorkbook().getNameRecord(nameIndex);
|
||||
}
|
||||
|
@ -1702,8 +1707,9 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||
*
|
||||
* @param name the name to remove.
|
||||
*/
|
||||
void removeName(HSSFName name) {
|
||||
int index = getNameIndex(name);
|
||||
@Override
|
||||
public void removeName(Name name) {
|
||||
int index = getNameIndex((HSSFName) name);
|
||||
removeName(index);
|
||||
}
|
||||
|
||||
|
|
|
@ -374,20 +374,22 @@ public class CryptoFunctions {
|
|||
// SET Verifier TO 0x0000
|
||||
short verifier = 0;
|
||||
|
||||
// FOR EACH PasswordByte IN PasswordArray IN REVERSE ORDER
|
||||
for (int i = arrByteChars.length-1; i >= 0; i--) {
|
||||
// SET Verifier TO Intermediate3 BITWISE XOR PasswordByte
|
||||
if (!"".equals(password)) {
|
||||
// FOR EACH PasswordByte IN PasswordArray IN REVERSE ORDER
|
||||
for (int i = arrByteChars.length-1; i >= 0; i--) {
|
||||
// SET Verifier TO Intermediate3 BITWISE XOR PasswordByte
|
||||
verifier = rotateLeftBase15Bit(verifier);
|
||||
verifier ^= arrByteChars[i];
|
||||
}
|
||||
|
||||
// as we haven't prepended the password length into the input array
|
||||
// we need to do it now separately ...
|
||||
verifier = rotateLeftBase15Bit(verifier);
|
||||
verifier ^= arrByteChars[i];
|
||||
verifier ^= arrByteChars.length;
|
||||
|
||||
// RETURN Verifier BITWISE XOR 0xCE4B
|
||||
verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K')
|
||||
}
|
||||
|
||||
// as we haven't prepended the password length into the input array
|
||||
// we need to do it now separately ...
|
||||
verifier = rotateLeftBase15Bit(verifier);
|
||||
verifier ^= arrByteChars.length;
|
||||
|
||||
// RETURN Verifier BITWISE XOR 0xCE4B
|
||||
verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K')
|
||||
|
||||
return verifier & 0xFFFF;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.ss.formula;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.CellValue;
|
||||
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
/**
|
||||
* Common functionality across file formats for evaluating formula cells.<p/>
|
||||
*/
|
||||
public abstract class BaseFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluatorProvider {
|
||||
protected final WorkbookEvaluator _bookEvaluator;
|
||||
|
||||
protected BaseFormulaEvaluator(WorkbookEvaluator bookEvaluator) {
|
||||
this._bookEvaluator = bookEvaluator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Coordinates several formula evaluators together so that formulas that involve external
|
||||
* references can be evaluated.
|
||||
* @param workbookNames the simple file names used to identify the workbooks in formulas
|
||||
* with external links (for example "MyData.xls" as used in a formula "[MyData.xls]Sheet1!A1")
|
||||
* @param evaluators all evaluators for the full set of workbooks required by the formulas.
|
||||
*/
|
||||
public static void setupEnvironment(String[] workbookNames, BaseFormulaEvaluator[] evaluators) {
|
||||
WorkbookEvaluator[] wbEvals = new WorkbookEvaluator[evaluators.length];
|
||||
for (int i = 0; i < wbEvals.length; i++) {
|
||||
wbEvals[i] = evaluators[i]._bookEvaluator;
|
||||
}
|
||||
CollaboratingWorkbooksEnvironment.setup(workbookNames, wbEvals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupReferencedWorkbooks(Map<String, FormulaEvaluator> evaluators) {
|
||||
CollaboratingWorkbooksEnvironment.setupFormulaEvaluator(evaluators);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkbookEvaluator _getWorkbookEvaluator() {
|
||||
return _bookEvaluator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called whenever there are major changes (e.g. moving sheets) to input cells
|
||||
* in the evaluated workbook. If performance is not critical, a single call to this method
|
||||
* may be used instead of many specific calls to the notify~ methods.
|
||||
*
|
||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||
* of the evaluate~ methods of this class
|
||||
*/
|
||||
@Override
|
||||
public void clearAllCachedResultValues() {
|
||||
_bookEvaluator.clearAllCachedResultValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* If cell contains a formula, the formula is evaluated and returned,
|
||||
* else the CellValue simply copies the appropriate cell value from
|
||||
* the cell and also its cell type. This method should be preferred over
|
||||
* evaluateInCell() when the call should not modify the contents of the
|
||||
* original cell.
|
||||
*
|
||||
* @param cell may be <code>null</code> signifying that the cell is not present (or blank)
|
||||
* @return <code>null</code> if the supplied cell is <code>null</code> or blank
|
||||
*/
|
||||
@Override
|
||||
public CellValue evaluate(Cell cell) {
|
||||
if (cell == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (cell.getCellTypeEnum()) {
|
||||
case BOOLEAN:
|
||||
return CellValue.valueOf(cell.getBooleanCellValue());
|
||||
case ERROR:
|
||||
return CellValue.getError(cell.getErrorCellValue());
|
||||
case FORMULA:
|
||||
return evaluateFormulaCellValue(cell);
|
||||
case NUMERIC:
|
||||
return new CellValue(cell.getNumericCellValue());
|
||||
case STRING:
|
||||
return new CellValue(cell.getRichStringCellValue().getString());
|
||||
case BLANK:
|
||||
return null;
|
||||
default:
|
||||
throw new IllegalStateException("Bad cell type (" + cell.getCellTypeEnum() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract CellValue evaluateFormulaCellValue(Cell cell);
|
||||
|
||||
/**
|
||||
* If cell contains formula, it evaluates the formula, and saves the result of the formula. The
|
||||
* cell remains as a formula cell. If the cell does not contain formula, this method returns -1
|
||||
* and leaves the cell unchanged.
|
||||
*
|
||||
* Note that the type of the <em>formula result</em> is returned, so you know what kind of
|
||||
* cached formula result is also stored with the formula.
|
||||
* <pre>
|
||||
* int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
|
||||
* </pre>
|
||||
* Be aware that your cell will hold both the formula, and the result. If you want the cell
|
||||
* replaced with the result of the formula, use {@link #evaluateInCell(org.apache.poi.ss.usermodel.Cell)}
|
||||
* @param cell The cell to evaluate
|
||||
* @return -1 for non-formula cells, or the type of the <em>formula result</em>
|
||||
*/
|
||||
@Override
|
||||
public int evaluateFormulaCell(Cell cell) {
|
||||
return evaluateFormulaCellEnum(cell).getCode();
|
||||
}
|
||||
|
||||
protected static void setCellType(Cell cell, CellValue cv) {
|
||||
CellType cellType = cv.getCellType();
|
||||
switch (cellType) {
|
||||
case BOOLEAN:
|
||||
case ERROR:
|
||||
case NUMERIC:
|
||||
case STRING:
|
||||
cell.setCellType(cellType);
|
||||
return;
|
||||
case BLANK:
|
||||
// never happens - blanks eventually get translated to zero
|
||||
throw new IllegalArgumentException("This should never happen. Blanks eventually get translated to zero.");
|
||||
case FORMULA:
|
||||
// this will never happen, we have already evaluated the formula
|
||||
throw new IllegalArgumentException("This should never happen. Formulas should have already been evaluated.");
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops over all cells in all sheets of the supplied
|
||||
* workbook.
|
||||
* For cells that contain formulas, their formulas are
|
||||
* evaluated, and the results are saved. These cells
|
||||
* remain as formula cells.
|
||||
* For cells that do not contain formulas, no changes
|
||||
* are made.
|
||||
* This is a helpful wrapper around looping over all
|
||||
* cells, and calling evaluateFormulaCell on each one.
|
||||
*/
|
||||
public static void evaluateAllFormulaCells(Workbook wb) {
|
||||
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
||||
evaluateAllFormulaCells(wb, evaluator);
|
||||
}
|
||||
protected static void evaluateAllFormulaCells(Workbook wb, FormulaEvaluator evaluator) {
|
||||
for(int i=0; i<wb.getNumberOfSheets(); i++) {
|
||||
Sheet sheet = wb.getSheetAt(i);
|
||||
|
||||
for(Row r : sheet) {
|
||||
for (Cell c : r) {
|
||||
if (c.getCellTypeEnum() == CellType.FORMULA) {
|
||||
evaluator.evaluateFormulaCellEnum(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void setIgnoreMissingWorkbooks(boolean ignore){
|
||||
_bookEvaluator.setIgnoreMissingWorkbooks(ignore);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void setDebugEvaluationOutputForNextEval(boolean value){
|
||||
_bookEvaluator.setDebugEvaluationOutputForNextEval(value);
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ import org.apache.poi.ss.util.CellReference;
|
|||
/**
|
||||
* Provides Lazy Evaluation to a 3D Reference
|
||||
*/
|
||||
final class LazyRefEval extends RefEvalBase {
|
||||
public final class LazyRefEval extends RefEvalBase {
|
||||
private final SheetRangeEvaluator _evaluator;
|
||||
|
||||
public LazyRefEval(int rowIndex, int columnIndex, SheetRangeEvaluator sre) {
|
||||
|
@ -47,14 +47,17 @@ final class LazyRefEval extends RefEvalBase {
|
|||
return new LazyAreaEval(area, _evaluator);
|
||||
}
|
||||
|
||||
public boolean isSubTotal() {
|
||||
SheetRefEvaluator sheetEvaluator = _evaluator.getSheetEvaluator(getFirstSheetIndex());
|
||||
return sheetEvaluator.isSubTotal(getRow(), getColumn());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
CellReference cr = new CellReference(getRow(), getColumn());
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(getClass().getName()).append("[");
|
||||
sb.append(_evaluator.getSheetNameRange());
|
||||
sb.append('!');
|
||||
sb.append(cr.formatAsString());
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
return getClass().getName() + "[" +
|
||||
_evaluator.getSheetNameRange() +
|
||||
'!' +
|
||||
cr.formatAsString() +
|
||||
"]";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.poi.ss.formula.functions;
|
|||
|
||||
import static org.apache.poi.ss.formula.functions.AggregateFunction.subtotalInstance;
|
||||
|
||||
import org.apache.poi.ss.formula.LazyRefEval;
|
||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||
import org.apache.poi.ss.formula.eval.EvaluationException;
|
||||
import org.apache.poi.ss.formula.eval.NotImplementedException;
|
||||
|
@ -26,6 +27,11 @@ import org.apache.poi.ss.formula.eval.NotImplementedFunctionException;
|
|||
import org.apache.poi.ss.formula.eval.OperandResolver;
|
||||
import org.apache.poi.ss.formula.eval.ValueEval;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementation for the Excel function SUBTOTAL<p>
|
||||
*
|
||||
|
@ -61,7 +67,6 @@ import org.apache.poi.ss.formula.eval.ValueEval;
|
|||
public class Subtotal implements Function {
|
||||
|
||||
private static Function findFunction(int functionCode) throws EvaluationException {
|
||||
Function func;
|
||||
switch (functionCode) {
|
||||
case 1: return subtotalInstance(AggregateFunction.AVERAGE);
|
||||
case 2: return Count.subtotalInstance();
|
||||
|
@ -87,7 +92,7 @@ public class Subtotal implements Function {
|
|||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
|
||||
Function innerFunc;
|
||||
final Function innerFunc;
|
||||
try {
|
||||
ValueEval ve = OperandResolver.getSingleValue(args[0], srcRowIndex, srcColumnIndex);
|
||||
int functionCode = OperandResolver.coerceValueToInt(ve);
|
||||
|
@ -96,9 +101,24 @@ public class Subtotal implements Function {
|
|||
return e.getErrorEval();
|
||||
}
|
||||
|
||||
ValueEval[] innerArgs = new ValueEval[nInnerArgs];
|
||||
System.arraycopy(args, 1, innerArgs, 0, nInnerArgs);
|
||||
// ignore the first arg, this is the function-type, we check for the length above
|
||||
final List<ValueEval> list = new ArrayList<ValueEval>(Arrays.asList(args).subList(1, args.length));
|
||||
|
||||
return innerFunc.evaluate(innerArgs, srcRowIndex, srcColumnIndex);
|
||||
Iterator<ValueEval> it = list.iterator();
|
||||
|
||||
// See https://support.office.com/en-us/article/SUBTOTAL-function-7b027003-f060-4ade-9040-e478765b9939
|
||||
// "If there are other subtotals within ref1, ref2,... (or nested subtotals), these nested subtotals are ignored to avoid double counting."
|
||||
// For array references it is handled in other evaluation steps, but we need to handle this here for references to subtotal-functions
|
||||
while(it.hasNext()) {
|
||||
ValueEval eval = it.next();
|
||||
if(eval instanceof LazyRefEval) {
|
||||
LazyRefEval lazyRefEval = (LazyRefEval) eval;
|
||||
if(lazyRefEval.isSubTotal()) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return innerFunc.evaluate(list.toArray(new ValueEval[list.size()]), srcRowIndex, srcColumnIndex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ public interface CellStyle {
|
|||
|
||||
/**
|
||||
* vertically justified vertical alignment
|
||||
* @deprecated POI 3.15 beta 3. Use {@link VerticalAlignment#TOP} instead.
|
||||
* @deprecated POI 3.15 beta 3. Use {@link VerticalAlignment#JUSTIFY} instead.
|
||||
*/
|
||||
static final short VERTICAL_JUSTIFY = 0x3; //VerticalAlignment.JUSTIFY.getCode();
|
||||
|
||||
|
|
|
@ -341,9 +341,11 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
|
|||
|
||||
/**
|
||||
* Close the underlying input resource (File or Stream),
|
||||
* from which the Workbook was read. After closing, the
|
||||
* Workbook should no longer be used.
|
||||
* <p>This will have no effect newly created Workbooks.
|
||||
* from which the Workbook was read.
|
||||
*
|
||||
* <p>Once this has been called, no further
|
||||
* operations, updates or reads should be performed on the
|
||||
* Workbook.
|
||||
*/
|
||||
@Override
|
||||
void close() throws IOException;
|
||||
|
@ -367,6 +369,13 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
|
|||
*/
|
||||
List<? extends Name> getNames(String name);
|
||||
|
||||
/**
|
||||
* Returns all defined names.
|
||||
*
|
||||
* @return a list of the defined names. An empty list is returned if none is found.
|
||||
*/
|
||||
List<? extends Name> getAllNames();
|
||||
|
||||
/**
|
||||
* @param nameIndex position of the named range (0-based)
|
||||
* @return the defined name at the specified index
|
||||
|
@ -405,6 +414,13 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
|
|||
*/
|
||||
void removeName(String name);
|
||||
|
||||
/**
|
||||
* Remove a defined name
|
||||
*
|
||||
* @param name the name of the defined name
|
||||
*/
|
||||
void removeName(Name name);
|
||||
|
||||
/**
|
||||
* Adds the linking required to allow formulas referencing
|
||||
* the specified external workbook to be added to this one.
|
||||
|
|
|
@ -27,19 +27,13 @@ import org.apache.commons.logging.LogFactory;
|
|||
* developers to write log calls, while simultaneously making those
|
||||
* calls as cheap as possible by performing lazy evaluation of the log
|
||||
* message.<p>
|
||||
*
|
||||
* @author Marc Johnson (mjohnson at apache dot org)
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
* @author Nicola Ken Barozzi (nicolaken at apache.org)
|
||||
*/
|
||||
|
||||
public class CommonsLogger extends POILogger
|
||||
{
|
||||
|
||||
private static LogFactory _creator = LogFactory.getFactory();
|
||||
private Log log = null;
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize(final String cat)
|
||||
{
|
||||
this.log = _creator.getInstance(cat);
|
||||
|
@ -51,6 +45,7 @@ public class CommonsLogger extends POILogger
|
|||
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
|
||||
* @param obj1 The object to log.
|
||||
*/
|
||||
@Override
|
||||
public void log(final int level, final Object obj1)
|
||||
{
|
||||
if(level==FATAL)
|
||||
|
@ -104,6 +99,7 @@ public class CommonsLogger extends POILogger
|
|||
* @param obj1 The object to log. This is converted to a string.
|
||||
* @param exception An exception to be logged
|
||||
*/
|
||||
@Override
|
||||
public void log(final int level, final Object obj1,
|
||||
final Throwable exception)
|
||||
{
|
||||
|
@ -175,7 +171,7 @@ public class CommonsLogger extends POILogger
|
|||
*
|
||||
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean check(final int level)
|
||||
{
|
||||
if(level==FATAL)
|
||||
|
|
|
@ -22,14 +22,10 @@ package org.apache.poi.util;
|
|||
* developers to write log calls, while simultaneously making those
|
||||
* calls as cheap as possible by performing lazy evaluation of the log
|
||||
* message.<p>
|
||||
*
|
||||
* @author Marc Johnson (mjohnson at apache dot org)
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
* @author Nicola Ken Barozzi (nicolaken at apache.org)
|
||||
*/
|
||||
public class NullLogger extends POILogger {
|
||||
@Override
|
||||
public void initialize(final String cat){
|
||||
public void initialize(final String cat) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
@ -41,8 +37,7 @@ public class NullLogger extends POILogger {
|
|||
*/
|
||||
|
||||
@Override
|
||||
public void log(final int level, final Object obj1)
|
||||
{
|
||||
public void log(final int level, final Object obj1) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
@ -53,6 +48,7 @@ public class NullLogger extends POILogger {
|
|||
* @param obj1 The object to log. This is converted to a string.
|
||||
* @param exception An exception to be logged
|
||||
*/
|
||||
@Override
|
||||
public void log(int level, Object obj1, final Throwable exception) {
|
||||
// do nothing
|
||||
}
|
||||
|
|
|
@ -24,15 +24,12 @@ package org.apache.poi.util;
|
|||
* developers to write log calls, while simultaneously making those
|
||||
* calls as cheap as possible by performing lazy evaluation of the log
|
||||
* message.
|
||||
*
|
||||
* @author Marc Johnson (mjohnson at apache dot org)
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
* @author Nicola Ken Barozzi (nicolaken at apache.org)
|
||||
*/
|
||||
public class SystemOutLogger extends POILogger
|
||||
{
|
||||
private String _cat;
|
||||
|
||||
@Override
|
||||
public void initialize(final String cat)
|
||||
{
|
||||
this._cat=cat;
|
||||
|
@ -44,7 +41,7 @@ public class SystemOutLogger extends POILogger
|
|||
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
|
||||
* @param obj1 The object to log.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void log(final int level, final Object obj1)
|
||||
{
|
||||
log(level, obj1, null);
|
||||
|
@ -57,6 +54,7 @@ public class SystemOutLogger extends POILogger
|
|||
* @param obj1 The object to log. This is converted to a string.
|
||||
* @param exception An exception to be logged
|
||||
*/
|
||||
@Override
|
||||
@SuppressForbidden("uses printStackTrace")
|
||||
public void log(final int level, final Object obj1,
|
||||
final Throwable exception) {
|
||||
|
@ -78,6 +76,7 @@ public class SystemOutLogger extends POILogger
|
|||
* @see #ERROR
|
||||
* @see #FATAL
|
||||
*/
|
||||
@Override
|
||||
public boolean check(final int level)
|
||||
{
|
||||
int currentLevel;
|
||||
|
|
|
@ -193,8 +193,12 @@ public abstract class POIXMLDocument extends POIXMLDocumentPart implements Close
|
|||
/**
|
||||
* Closes the underlying {@link OPCPackage} from which this
|
||||
* document was read, if there is one
|
||||
*
|
||||
* @throws IOException for writable packages, if an IO exception occur during the saving process.
|
||||
*
|
||||
* <p>Once this has been called, no further
|
||||
* operations, updates or reads should be performed on the
|
||||
* document.
|
||||
*
|
||||
* @throws IOException for writable packages, if an IO exception occur during the saving process.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
|
|
@ -382,8 +382,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
|
|||
}
|
||||
|
||||
// Creates a new package
|
||||
OPCPackage pkg = null;
|
||||
pkg = new ZipPackage();
|
||||
OPCPackage pkg = new ZipPackage();
|
||||
pkg.originalPackagePath = file.getAbsolutePath();
|
||||
|
||||
configurePackage(pkg);
|
||||
|
@ -391,8 +390,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
|
|||
}
|
||||
|
||||
public static OPCPackage create(OutputStream output) {
|
||||
OPCPackage pkg = null;
|
||||
pkg = new ZipPackage();
|
||||
OPCPackage pkg = new ZipPackage();
|
||||
pkg.originalPackagePath = null;
|
||||
pkg.output = output;
|
||||
|
||||
|
@ -542,7 +540,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
|
|||
// Create the thumbnail part name
|
||||
String contentType = ContentTypes
|
||||
.getContentTypeFromFileExtension(filename);
|
||||
PackagePartName thumbnailPartName = null;
|
||||
PackagePartName thumbnailPartName;
|
||||
try {
|
||||
thumbnailPartName = PackagingURIHelper.createPartName("/docProps/"
|
||||
+ filename);
|
||||
|
|
|
@ -29,10 +29,7 @@ import java.util.TreeMap;
|
|||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||
import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
|
||||
import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
|
||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||
import org.apache.poi.openxml4j.opc.PackagePart;
|
||||
import org.apache.poi.openxml4j.opc.PackagePartName;
|
||||
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
|
||||
import org.apache.poi.openxml4j.opc.*;
|
||||
import org.apache.poi.util.DocumentHelper;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
@ -54,7 +51,7 @@ public abstract class ContentTypeManager {
|
|||
/**
|
||||
* Content type namespace
|
||||
*/
|
||||
public static final String TYPES_NAMESPACE_URI = "http://schemas.openxmlformats.org/package/2006/content-types";
|
||||
public static final String TYPES_NAMESPACE_URI = PackageNamespaces.CONTENT_TYPES;
|
||||
|
||||
/* Xml elements in content type part */
|
||||
|
||||
|
|
|
@ -304,13 +304,13 @@ implements XSLFShapeContainer, GroupShape<XSLFShape,XSLFTextParagraph> {
|
|||
@Override
|
||||
public boolean getFlipHorizontal(){
|
||||
CTGroupTransform2D xfrm = getXfrm();
|
||||
return (xfrm == null || !xfrm.isSetFlipH()) ? false : xfrm.getFlipH();
|
||||
return !(xfrm == null || !xfrm.isSetFlipH()) && xfrm.getFlipH();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getFlipVertical(){
|
||||
CTGroupTransform2D xfrm = getXfrm();
|
||||
return (xfrm == null || !xfrm.isSetFlipV()) ? false : xfrm.getFlipV();
|
||||
return !(xfrm == null || !xfrm.isSetFlipV()) && xfrm.getFlipV();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -333,7 +333,7 @@ implements XSLFShapeContainer, GroupShape<XSLFShape,XSLFTextParagraph> {
|
|||
|
||||
// recursively update each shape
|
||||
for(XSLFShape shape : gr.getShapes()) {
|
||||
XSLFShape newShape = null;
|
||||
XSLFShape newShape;
|
||||
if (shape instanceof XSLFTextBox) {
|
||||
newShape = createTextBox();
|
||||
} else if (shape instanceof XSLFAutoShape) {
|
||||
|
|
|
@ -41,7 +41,6 @@ import javax.xml.validation.Schema;
|
|||
import javax.xml.validation.SchemaFactory;
|
||||
import javax.xml.validation.Validator;
|
||||
|
||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.DateUtil;
|
||||
import org.apache.poi.util.DocumentHelper;
|
||||
|
@ -55,7 +54,6 @@ import org.apache.poi.xssf.usermodel.XSSFSheet;
|
|||
import org.apache.poi.xssf.usermodel.XSSFTable;
|
||||
import org.apache.poi.xssf.usermodel.helpers.XSSFSingleXmlCell;
|
||||
import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STXmlDataType;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
|
@ -117,8 +115,7 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||
* @param validate if true, validates the XML againts the XML Schema
|
||||
* @throws SAXException
|
||||
* @throws ParserConfigurationException
|
||||
* @throws TransformerException
|
||||
* @throws InvalidFormatException
|
||||
* @throws TransformerException
|
||||
*/
|
||||
public void exportToXML(OutputStream os, String encoding, boolean validate) throws SAXException, ParserConfigurationException, TransformerException{
|
||||
List<XSSFSingleXmlCell> singleXMLCells = map.getRelatedSingleXMLCell();
|
||||
|
@ -128,10 +125,10 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||
|
||||
Document doc = DocumentHelper.createDocument();
|
||||
|
||||
Element root = null;
|
||||
final Element root;
|
||||
|
||||
if (isNamespaceDeclared()) {
|
||||
root=doc.createElementNS(getNamespace(),rootElement);
|
||||
root = doc.createElementNS(getNamespace(),rootElement);
|
||||
} else {
|
||||
root = doc.createElementNS("", rootElement);
|
||||
}
|
||||
|
@ -152,7 +149,6 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||
tableMappings.put(commonXPath, table);
|
||||
}
|
||||
|
||||
|
||||
Collections.sort(xpaths,this);
|
||||
|
||||
for(String xpath : xpaths) {
|
||||
|
@ -167,8 +163,7 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||
XSSFCell cell = simpleXmlCell.getReferencedCell();
|
||||
if (cell!=null) {
|
||||
Node currentNode = getNodeByXPath(xpath,doc.getFirstChild(),doc,false);
|
||||
STXmlDataType.Enum dataType = simpleXmlCell.getXmlDataType();
|
||||
mapCellOnNode(cell,currentNode,dataType);
|
||||
mapCellOnNode(cell,currentNode);
|
||||
|
||||
//remove nodes which are empty in order to keep the output xml valid
|
||||
if("".equals(currentNode.getTextContent()) && currentNode.getParentNode() != null) {
|
||||
|
@ -202,22 +197,15 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||
XSSFXmlColumnPr pointer = tableColumns.get(j-startColumnIndex);
|
||||
String localXPath = pointer.getLocalXPath();
|
||||
Node currentNode = getNodeByXPath(localXPath,tableRootNode,doc,false);
|
||||
STXmlDataType.Enum dataType = pointer.getXmlDataType();
|
||||
|
||||
|
||||
mapCellOnNode(cell,currentNode,dataType);
|
||||
mapCellOnNode(cell,currentNode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
} else {
|
||||
} /*else {
|
||||
// TODO: implement filtering management in xpath
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
boolean isValid = true;
|
||||
|
@ -225,8 +213,6 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||
isValid =isValid(doc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (isValid) {
|
||||
|
||||
/////////////////
|
||||
|
@ -275,7 +261,7 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||
}
|
||||
|
||||
|
||||
private void mapCellOnNode(XSSFCell cell, Node node, STXmlDataType.Enum outputDataType) {
|
||||
private void mapCellOnNode(XSSFCell cell, Node node) {
|
||||
|
||||
String value ="";
|
||||
switch (cell.getCellTypeEnum()) {
|
||||
|
@ -349,11 +335,7 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||
}
|
||||
currentNode = selectedNode;
|
||||
} else {
|
||||
|
||||
|
||||
Node attribute = createAttribute(doc, currentNode, axisName);
|
||||
|
||||
currentNode = attribute;
|
||||
currentNode = createAttribute(doc, currentNode, axisName);
|
||||
}
|
||||
}
|
||||
return currentNode;
|
||||
|
@ -421,12 +403,11 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||
|
||||
for(int i =1;i <minLenght; i++) {
|
||||
|
||||
String leftElementName =leftTokens[i];
|
||||
String leftElementName = leftTokens[i];
|
||||
String rightElementName = rightTokens[i];
|
||||
|
||||
if (leftElementName.equals(rightElementName)) {
|
||||
Node complexType = getComplexTypeForElement(leftElementName, xmlSchema,localComplexTypeRootNode);
|
||||
localComplexTypeRootNode = complexType;
|
||||
localComplexTypeRootNode = getComplexTypeForElement(leftElementName, xmlSchema, localComplexTypeRootNode);
|
||||
} else {
|
||||
int leftIndex = indexOfElementInComplexType(leftElementName,localComplexTypeRootNode);
|
||||
int rightIndex = indexOfElementInComplexType(rightElementName,localComplexTypeRootNode);
|
||||
|
@ -436,9 +417,9 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||
}if ( leftIndex > rightIndex) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
} /*else {
|
||||
// NOTE: the xpath doesn't match correctly in the schema
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -483,7 +464,7 @@ public class XSSFExportToXml implements Comparator<String>{
|
|||
// Note: we expect that all the complex types are defined at root level
|
||||
Node complexTypeNode = null;
|
||||
if (!"".equals(complexTypeName)) {
|
||||
complexTypeNode = getComplexTypeNodeFromSchemaChildren(xmlSchema, complexTypeNode, complexTypeName);
|
||||
complexTypeNode = getComplexTypeNodeFromSchemaChildren(xmlSchema, null, complexTypeName);
|
||||
}
|
||||
|
||||
return complexTypeNode;
|
||||
|
|
|
@ -338,7 +338,11 @@ public class SXSSFCell implements Cell {
|
|||
}
|
||||
|
||||
if(_value.getType()==CellType.FORMULA)
|
||||
((StringFormulaValue)_value).setPreEvaluatedValue(value);
|
||||
if(_value instanceof NumericFormulaValue) {
|
||||
((NumericFormulaValue) _value).setPreEvaluatedValue(Double.parseDouble(value));
|
||||
} else {
|
||||
((StringFormulaValue) _value).setPreEvaluatedValue(value);
|
||||
}
|
||||
else
|
||||
((PlainStringValue)_value).setValue(value);
|
||||
} else {
|
||||
|
@ -956,6 +960,7 @@ public class SXSSFCell implements Cell {
|
|||
}
|
||||
/*package*/ void setFormulaType(CellType type)
|
||||
{
|
||||
Value prevValue = _value;
|
||||
switch(type)
|
||||
{
|
||||
case NUMERIC:
|
||||
|
@ -983,7 +988,13 @@ public class SXSSFCell implements Cell {
|
|||
throw new IllegalArgumentException("Illegal type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
// if we had a Formula before, we should copy over the _value of the formula
|
||||
if(prevValue instanceof FormulaValue) {
|
||||
((FormulaValue)_value)._value = ((FormulaValue)prevValue)._value;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: implement this correctly
|
||||
@NotImplemented
|
||||
/*package*/ CellType computeTypeFromFormula(String formula)
|
||||
|
|
|
@ -893,8 +893,11 @@ public class SXSSFWorkbook implements Workbook {
|
|||
|
||||
/**
|
||||
* Closes the underlying {@link XSSFWorkbook} and {@link OPCPackage}
|
||||
* on which this Workbook is based, if any. Has no effect on Workbooks
|
||||
* created from scratch.
|
||||
* on which this Workbook is based, if any.
|
||||
*
|
||||
* <p>Once this has been called, no further
|
||||
* operations, updates or reads should be performed on the
|
||||
* Workbook.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
@ -1003,12 +1006,25 @@ public class SXSSFWorkbook implements Workbook {
|
|||
return _wb.getNames(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all defined names
|
||||
*
|
||||
* @return all defined names
|
||||
*/
|
||||
@Override
|
||||
public List<? extends Name> getAllNames()
|
||||
{
|
||||
return _wb.getAllNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nameIndex position of the named range (0-based)
|
||||
* @return the defined name at the specified index
|
||||
* @throws IllegalArgumentException if the supplied index is invalid
|
||||
* @deprecated 3.16. New projects should avoid accessing named ranges by index.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public Name getNameAt(int nameIndex)
|
||||
{
|
||||
return _wb.getNameAt(nameIndex);
|
||||
|
@ -1033,8 +1049,12 @@ public class SXSSFWorkbook implements Workbook {
|
|||
*
|
||||
* @param name the name of the defined name
|
||||
* @return zero based index of the defined name. <code>-1</code> if not found.
|
||||
*
|
||||
* @deprecated 3.16. New projects should avoid accessing named ranges by index.
|
||||
* Use {@link #getName(String)} instead.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public int getNameIndex(String name)
|
||||
{
|
||||
return _wb.getNameIndex(name);
|
||||
|
@ -1044,8 +1064,11 @@ public class SXSSFWorkbook implements Workbook {
|
|||
* Remove the defined name at the specified index
|
||||
*
|
||||
* @param index named range index (0 based)
|
||||
*
|
||||
* @deprecated 3.16. New projects should use {@link #removeName(Name)}.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void removeName(int index)
|
||||
{
|
||||
_wb.removeName(index);
|
||||
|
@ -1054,10 +1077,24 @@ public class SXSSFWorkbook implements Workbook {
|
|||
/**
|
||||
* Remove a defined name by name
|
||||
*
|
||||
* @param name the name of the defined name
|
||||
* @param name the name of the defined name
|
||||
*
|
||||
* @deprecated 3.16. New projects should use {@link #removeName(Name)}.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void removeName(String name)
|
||||
{
|
||||
_wb.removeName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given defined name
|
||||
*
|
||||
* @param name the name to remove
|
||||
*/
|
||||
@Override
|
||||
public void removeName(Name name)
|
||||
{
|
||||
_wb.removeName(name);
|
||||
}
|
||||
|
|
|
@ -232,7 +232,7 @@ public abstract class BaseXSSFEvaluationWorkbook implements FormulaRenderingWork
|
|||
|
||||
// Otherwise, try it as a named range
|
||||
if (sheet == null) {
|
||||
if (_uBook.getNameIndex(name) > -1) {
|
||||
if (!_uBook.getNames(name).isEmpty()) {
|
||||
return new NameXPxg(null, name);
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -17,12 +17,9 @@
|
|||
|
||||
package org.apache.poi.xssf.usermodel;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment;
|
||||
import org.apache.poi.ss.formula.BaseFormulaEvaluator;
|
||||
import org.apache.poi.ss.formula.EvaluationCell;
|
||||
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
||||
import org.apache.poi.ss.formula.WorkbookEvaluatorProvider;
|
||||
import org.apache.poi.ss.formula.eval.BoolEval;
|
||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||
import org.apache.poi.ss.formula.eval.NumberEval;
|
||||
|
@ -31,28 +28,16 @@ import org.apache.poi.ss.formula.eval.ValueEval;
|
|||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.CellValue;
|
||||
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||
import org.apache.poi.util.Internal;
|
||||
|
||||
/**
|
||||
* Internal POI use only - parent of XSSF and SXSSF formula evaluators
|
||||
*/
|
||||
public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluatorProvider {
|
||||
private WorkbookEvaluator _bookEvaluator;
|
||||
|
||||
public abstract class BaseXSSFFormulaEvaluator extends BaseFormulaEvaluator {
|
||||
protected BaseXSSFFormulaEvaluator(WorkbookEvaluator bookEvaluator) {
|
||||
_bookEvaluator = bookEvaluator;
|
||||
super(bookEvaluator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called whenever there are major changes (e.g. moving sheets) to input cells
|
||||
* in the evaluated workbook.
|
||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
||||
* of the evaluate~ methods of this class
|
||||
*/
|
||||
public void clearAllCachedResultValues() {
|
||||
_bookEvaluator.clearAllCachedResultValues();
|
||||
}
|
||||
public void notifySetFormula(Cell cell) {
|
||||
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
|
||||
}
|
||||
|
@ -63,60 +48,6 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
|
|||
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
|
||||
}
|
||||
|
||||
/**
|
||||
* If cell contains a formula, the formula is evaluated and returned,
|
||||
* else the CellValue simply copies the appropriate cell value from
|
||||
* the cell and also its cell type. This method should be preferred over
|
||||
* evaluateInCell() when the call should not modify the contents of the
|
||||
* original cell.
|
||||
* @param cell
|
||||
*/
|
||||
public CellValue evaluate(Cell cell) {
|
||||
if (cell == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (cell.getCellTypeEnum()) {
|
||||
case BOOLEAN:
|
||||
return CellValue.valueOf(cell.getBooleanCellValue());
|
||||
case ERROR:
|
||||
return CellValue.getError(cell.getErrorCellValue());
|
||||
case FORMULA:
|
||||
return evaluateFormulaCellValue(cell);
|
||||
case NUMERIC:
|
||||
return new CellValue(cell.getNumericCellValue());
|
||||
case STRING:
|
||||
return new CellValue(cell.getRichStringCellValue().getString());
|
||||
case BLANK:
|
||||
return null;
|
||||
default:
|
||||
throw new IllegalStateException("Bad cell type (" + cell.getCellTypeEnum() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If cell contains formula, it evaluates the formula,
|
||||
* and saves the result of the formula. The cell
|
||||
* remains as a formula cell.
|
||||
* Else if cell does not contain formula, this method leaves
|
||||
* the cell unchanged.
|
||||
* Note that the type of the formula result is returned,
|
||||
* so you know what kind of value is also stored with
|
||||
* the formula.
|
||||
* <pre>
|
||||
* int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
|
||||
* </pre>
|
||||
* Be aware that your cell will hold both the formula,
|
||||
* and the result. If you want the cell replaced with
|
||||
* the result of the formula, use {@link #evaluate(org.apache.poi.ss.usermodel.Cell)} }
|
||||
* @param cell The cell to evaluate
|
||||
* @return The type of the formula result (the cell's type remains as CellType.FORMULA however)
|
||||
*/
|
||||
public int evaluateFormulaCell(Cell cell) {
|
||||
return evaluateFormulaCellEnum(cell).getCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* If cell contains formula, it evaluates the formula,
|
||||
* and saves the result of the formula. The cell
|
||||
|
@ -164,27 +95,6 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
|
|||
setCellValue(cell, cv);
|
||||
}
|
||||
}
|
||||
private static void setCellType(Cell cell, CellValue cv) {
|
||||
CellType cellType = cv.getCellType();
|
||||
switch (cellType) {
|
||||
case BOOLEAN:
|
||||
case ERROR:
|
||||
case NUMERIC:
|
||||
case STRING:
|
||||
cell.setCellType(cellType);
|
||||
return;
|
||||
case BLANK:
|
||||
// never happens - blanks eventually get translated to zero
|
||||
throw new IllegalArgumentException("This should never happen. Blanks eventually get translated to zero.");
|
||||
case FORMULA:
|
||||
// this will never happen, we have already evaluated the formula
|
||||
throw new IllegalArgumentException("This should never happen. Formulas should have already been evaluated.");
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void setCellValue(Cell cell, CellValue cv) {
|
||||
CellType cellType = cv.getCellType();
|
||||
|
@ -218,7 +128,7 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
|
|||
/**
|
||||
* Returns a CellValue wrapper around the supplied ValueEval instance.
|
||||
*/
|
||||
private CellValue evaluateFormulaCellValue(Cell cell) {
|
||||
protected CellValue evaluateFormulaCellValue(Cell cell) {
|
||||
EvaluationCell evalCell = toEvaluationCell(cell);
|
||||
ValueEval eval = _bookEvaluator.evaluate(evalCell);
|
||||
if (eval instanceof NumberEval) {
|
||||
|
@ -238,22 +148,4 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
|
|||
}
|
||||
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
|
||||
}
|
||||
|
||||
public void setupReferencedWorkbooks(Map<String, FormulaEvaluator> evaluators) {
|
||||
CollaboratingWorkbooksEnvironment.setupFormulaEvaluator(evaluators);
|
||||
}
|
||||
|
||||
public WorkbookEvaluator _getWorkbookEvaluator() {
|
||||
return _bookEvaluator;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void setIgnoreMissingWorkbooks(boolean ignore){
|
||||
_bookEvaluator.setIgnoreMissingWorkbooks(ignore);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void setDebugEvaluationOutputForNextEval(boolean value){
|
||||
_bookEvaluator.setDebugEvaluationOutputForNextEval(value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
package org.apache.poi.xssf.usermodel;
|
||||
|
||||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
||||
import org.apache.poi.ss.formula.BaseFormulaEvaluator;
|
||||
import org.apache.poi.ss.formula.EvaluationCell;
|
||||
import org.apache.poi.ss.formula.IStabilityClassifier;
|
||||
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
||||
|
@ -88,7 +88,7 @@ public final class XSSFFormulaEvaluator extends BaseXSSFFormulaEvaluator {
|
|||
* cells, and calling evaluateFormulaCell on each one.
|
||||
*/
|
||||
public static void evaluateAllFormulaCells(XSSFWorkbook wb) {
|
||||
HSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||
BaseFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||
}
|
||||
/**
|
||||
* Loops over all cells in all sheets of the supplied
|
||||
|
@ -102,7 +102,7 @@ public final class XSSFFormulaEvaluator extends BaseXSSFFormulaEvaluator {
|
|||
* cells, and calling evaluateFormulaCell on each one.
|
||||
*/
|
||||
public void evaluateAll() {
|
||||
HSSFFormulaEvaluator.evaluateAllFormulaCells(_book);
|
||||
evaluateAllFormulaCells(_book, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -167,19 +167,18 @@ public final class XSSFName implements Name {
|
|||
public void setNameName(String name) {
|
||||
validateName(name);
|
||||
|
||||
String oldName = getNameName();
|
||||
int sheetIndex = getSheetIndex();
|
||||
int numberOfNames = _workbook.getNumberOfNames();
|
||||
//Check to ensure no other names have the same case-insensitive name at the same scope
|
||||
for (int i = 0; i < numberOfNames; i++) {
|
||||
XSSFName nm = _workbook.getNameAt(i);
|
||||
if ((nm != this)
|
||||
&& name.equalsIgnoreCase(nm.getNameName())
|
||||
&& (sheetIndex == nm.getSheetIndex())) {
|
||||
for (XSSFName foundName : _workbook.getNames(name)) {
|
||||
if (foundName.getSheetIndex() == sheetIndex && foundName != this) {
|
||||
String msg = "The "+(sheetIndex == -1 ? "workbook" : "sheet")+" already contains this name: " + name;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
_ctName.setName(name);
|
||||
//Need to update the name -> named ranges map
|
||||
_workbook.updateName(this, oldName);
|
||||
}
|
||||
|
||||
public String getRefersToFormula() {
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
package org.apache.poi.xssf.usermodel;
|
||||
|
||||
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
||||
import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword;
|
||||
import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword;
|
||||
import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.setPassword;
|
||||
import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.validatePassword;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
package org.apache.poi.xssf.usermodel;
|
||||
|
||||
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
||||
import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword;
|
||||
import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword;
|
||||
import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.setPassword;
|
||||
import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.validatePassword;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
@ -29,16 +29,20 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.apache.commons.collections4.ListValuedMap;
|
||||
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
|
||||
import org.apache.poi.POIXMLDocument;
|
||||
import org.apache.poi.POIXMLDocumentPart;
|
||||
import org.apache.poi.POIXMLException;
|
||||
|
@ -59,6 +63,7 @@ import org.apache.poi.ss.formula.SheetNameFormatter;
|
|||
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
|
||||
import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
|
||||
import org.apache.poi.ss.formula.udf.UDFFinder;
|
||||
import org.apache.poi.ss.usermodel.Name;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
|
@ -140,6 +145,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||
*/
|
||||
private List<XSSFSheet> sheets;
|
||||
|
||||
/**
|
||||
* this holds the XSSFName objects attached to this workbook, keyed by lower-case name
|
||||
*/
|
||||
private ListValuedMap<String, XSSFName> namedRangesByName;
|
||||
|
||||
/**
|
||||
* this holds the XSSFName objects attached to this workbook
|
||||
*/
|
||||
|
@ -442,6 +452,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||
stylesSource.setWorkbook(this);
|
||||
|
||||
namedRanges = new ArrayList<XSSFName>();
|
||||
namedRangesByName = new ArrayListValuedHashMap<String, XSSFName>();
|
||||
sheets = new ArrayList<XSSFSheet>();
|
||||
pivotTables = new ArrayList<XSSFPivotTable>();
|
||||
}
|
||||
|
@ -733,8 +744,13 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||
public XSSFName createName() {
|
||||
CTDefinedName ctName = CTDefinedName.Factory.newInstance();
|
||||
ctName.setName("");
|
||||
return createAndStoreName(ctName);
|
||||
}
|
||||
|
||||
private XSSFName createAndStoreName(CTDefinedName ctName) {
|
||||
XSSFName name = new XSSFName(ctName, this);
|
||||
namedRanges.add(name);
|
||||
namedRangesByName.put(ctName.getName().toLowerCase(Locale.ENGLISH), name);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
@ -938,28 +954,47 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||
return stylesSource.getFontAt(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first named range with the given name.
|
||||
*
|
||||
* Note: names of named ranges are not unique as they are scoped by sheet.
|
||||
* {@link #getNames(String name)} returns all named ranges with the given name.
|
||||
*
|
||||
* @param name named range name
|
||||
* @return XSSFName with the given name. <code>null</code> is returned no named range could be found.
|
||||
*/
|
||||
@Override
|
||||
public XSSFName getName(String name) {
|
||||
int nameIndex = getNameIndex(name);
|
||||
if (nameIndex < 0) {
|
||||
Collection<XSSFName> list = getNames(name);
|
||||
if (list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return namedRanges.get(nameIndex);
|
||||
return list.iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the named ranges with the given name.
|
||||
* <i>Note:</i>Excel named ranges are case-insensitive and
|
||||
* this method performs a case-insensitive search.
|
||||
*
|
||||
* @param name named range name
|
||||
* @return list of XSSFNames with the given name. An empty list if no named ranges could be found
|
||||
*/
|
||||
@Override
|
||||
public List<XSSFName> getNames(String name) {
|
||||
List<XSSFName> names = new ArrayList<XSSFName>();
|
||||
for(XSSFName nr : namedRanges) {
|
||||
if(nr.getNameName().equals(name)) {
|
||||
names.add(nr);
|
||||
}
|
||||
}
|
||||
|
||||
return names;
|
||||
return Collections.unmodifiableList(namedRangesByName.get(name.toLowerCase(Locale.ENGLISH)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the named range at the given index.
|
||||
*
|
||||
* @param nameIndex the index of the named range
|
||||
* @return the XSSFName at the given index
|
||||
*
|
||||
* @deprecated 3.16. New projects should avoid accessing named ranges by index.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public XSSFName getNameAt(int nameIndex) {
|
||||
int nNames = namedRanges.size();
|
||||
if (nNames < 1) {
|
||||
|
@ -973,21 +1008,30 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the named range index by his name
|
||||
* <i>Note:</i>Excel named ranges are case-insensitive and
|
||||
* this method performs a case-insensitive search.
|
||||
* Get a list of all the named ranges in the workbook.
|
||||
*
|
||||
* @param name named range name
|
||||
* @return named range index
|
||||
* @return list of XSSFNames in the workbook
|
||||
*/
|
||||
@Override
|
||||
public List<XSSFName> getAllNames() {
|
||||
return Collections.unmodifiableList(namedRanges);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the named range index by name.
|
||||
*
|
||||
* @param name named range name
|
||||
* @return named range index. <code>-1</code> is returned if no named ranges could be found.
|
||||
*
|
||||
* @deprecated 3.16. New projects should avoid accessing named ranges by index.
|
||||
* Use {@link #getName(String)} instead.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public int getNameIndex(String name) {
|
||||
int i = 0;
|
||||
for(XSSFName nr : namedRanges) {
|
||||
if(nr.getNameName().equals(name)) {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
XSSFName nm = getName(name);
|
||||
if (nm != null) {
|
||||
return namedRanges.indexOf(nm);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -1258,22 +1302,40 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||
return getPackagePart().getContentType().equals(XSSFRelation.MACROS_WORKBOOK.getContentType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the named range at the given index.
|
||||
*
|
||||
* @param nameIndex the index of the named range name to remove
|
||||
*
|
||||
* @deprecated 3.16. New projects should use {@link #removeName(Name)}.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void removeName(int nameIndex) {
|
||||
namedRanges.remove(nameIndex);
|
||||
removeName(getNameAt(nameIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the first named range found with the given name.
|
||||
*
|
||||
* Note: names of named ranges are not unique (name + sheet
|
||||
* index is unique), so {@link #removeName(Name)} should
|
||||
* be used if possible.
|
||||
*
|
||||
* @param name the named range name to remove
|
||||
*
|
||||
* @throws IllegalArgumentException if no named range could be found
|
||||
*
|
||||
* @deprecated 3.16. New projects should use {@link #removeName(Name)}.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void removeName(String name) {
|
||||
int idx = 0;
|
||||
for (XSSFName nm : namedRanges) {
|
||||
if(nm.getNameName().equalsIgnoreCase(name)) {
|
||||
removeName(idx);
|
||||
return;
|
||||
}
|
||||
idx++;
|
||||
List<XSSFName> names = namedRangesByName.get(name.toLowerCase(Locale.ENGLISH));
|
||||
if (names.isEmpty()) {
|
||||
throw new IllegalArgumentException("Named range was not found: " + name);
|
||||
}
|
||||
throw new IllegalArgumentException("Named range was not found: " + name);
|
||||
removeName(names.get(0));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1282,13 +1344,24 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||
* (name + sheet index is unique), this method is more accurate.
|
||||
*
|
||||
* @param name the name to remove.
|
||||
*
|
||||
* @throws IllegalArgumentException if the named range is not a part of this XSSFWorkbook
|
||||
*/
|
||||
void removeName(XSSFName name) {
|
||||
if (!namedRanges.remove(name)) {
|
||||
@Override
|
||||
public void removeName(Name name) {
|
||||
if (!namedRangesByName.removeMapping(name.getNameName().toLowerCase(Locale.ENGLISH), name)
|
||||
|| !namedRanges.remove(name)) {
|
||||
throw new IllegalArgumentException("Name was not found: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
void updateName(XSSFName name, String oldName) {
|
||||
if (!namedRangesByName.removeMapping(oldName.toLowerCase(Locale.ENGLISH), name)) {
|
||||
throw new IllegalArgumentException("Name was not found: " + name);
|
||||
}
|
||||
namedRangesByName.put(name.getNameName().toLowerCase(Locale.ENGLISH), name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete the printarea for the sheet specified
|
||||
|
@ -1297,13 +1370,9 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||
*/
|
||||
@Override
|
||||
public void removePrintArea(int sheetIndex) {
|
||||
int cont = 0;
|
||||
for (XSSFName name : namedRanges) {
|
||||
if (name.getNameName().equals(XSSFName.BUILTIN_PRINT_AREA) && name.getSheetIndex() == sheetIndex) {
|
||||
namedRanges.remove(cont);
|
||||
break;
|
||||
}
|
||||
cont++;
|
||||
XSSFName name = getBuiltInName(XSSFName.BUILTIN_PRINT_AREA, sheetIndex);
|
||||
if (name != null) {
|
||||
removeName(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1369,17 +1438,20 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||
}
|
||||
|
||||
//adjust indices of names ranges
|
||||
for (Iterator<XSSFName> it = namedRanges.iterator(); it.hasNext();) {
|
||||
XSSFName nm = it.next();
|
||||
List<XSSFName> toRemove = new ArrayList<XSSFName>();
|
||||
for (XSSFName nm : namedRanges) {
|
||||
CTDefinedName ct = nm.getCTName();
|
||||
if(!ct.isSetLocalSheetId()) continue;
|
||||
if (ct.getLocalSheetId() == index) {
|
||||
it.remove();
|
||||
toRemove.add(nm);
|
||||
} else if (ct.getLocalSheetId() > index){
|
||||
// Bump down by one, so still points at the same sheet
|
||||
ct.setLocalSheetId(ct.getLocalSheetId()-1);
|
||||
}
|
||||
}
|
||||
for (XSSFName nm : toRemove) {
|
||||
removeName(nm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1514,8 +1586,8 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||
}
|
||||
|
||||
XSSFName getBuiltInName(String builtInCode, int sheetNumber) {
|
||||
for (XSSFName name : namedRanges) {
|
||||
if (name.getNameName().equalsIgnoreCase(builtInCode) && name.getSheetIndex() == sheetNumber) {
|
||||
for (XSSFName name : namedRangesByName.get(builtInCode.toLowerCase(Locale.ENGLISH))) {
|
||||
if (name.getSheetIndex() == sheetNumber) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
@ -1537,15 +1609,12 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||
nameRecord.setName(builtInName);
|
||||
nameRecord.setLocalSheetId(sheetNumber);
|
||||
|
||||
XSSFName name = new XSSFName(nameRecord, this);
|
||||
for (XSSFName nr : namedRanges) {
|
||||
if (nr.equals(name))
|
||||
throw new POIXMLException("Builtin (" + builtInName
|
||||
+ ") already exists for sheet (" + sheetNumber + ")");
|
||||
if (getBuiltInName(builtInName, sheetNumber) != null) {
|
||||
throw new POIXMLException("Builtin (" + builtInName
|
||||
+ ") already exists for sheet (" + sheetNumber + ")");
|
||||
}
|
||||
|
||||
namedRanges.add(name);
|
||||
return name;
|
||||
return createAndStoreName(nameRecord);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1665,10 +1734,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||
}
|
||||
|
||||
private void reprocessNamedRanges() {
|
||||
namedRangesByName = new ArrayListValuedHashMap<String, XSSFName>();
|
||||
namedRanges = new ArrayList<XSSFName>();
|
||||
if(workbook.isSetDefinedNames()) {
|
||||
for(CTDefinedName ctName : workbook.getDefinedNames().getDefinedNameArray()) {
|
||||
namedRanges.add(new XSSFName(ctName, this));
|
||||
createAndStoreName(ctName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,9 +65,7 @@ public final class XSSFFormulaUtils {
|
|||
*/
|
||||
public void updateSheetName(final int sheetIndex, final String oldName, final String newName) {
|
||||
// update named ranges
|
||||
final int numberOfNames = _wb.getNumberOfNames();
|
||||
for (int i = 0; i < numberOfNames; i++) {
|
||||
XSSFName nm = _wb.getNameAt(i);
|
||||
for (XSSFName nm : _wb.getAllNames()) {
|
||||
if (nm.getSheetIndex() == -1 || nm.getSheetIndex() == sheetIndex) {
|
||||
updateName(nm, oldName, newName);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
package org.apache.poi.xssf.usermodel.helpers;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.apache.poi.poifs.crypt.CryptoFunctions;
|
||||
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
|
||||
@Internal(since="3.15 beta 3")
|
||||
public final class XSSFPasswordHelper {
|
||||
private XSSFPasswordHelper() {
|
||||
// no instances of this static class
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the XORed or hashed password
|
||||
*
|
||||
* @param xobj the xmlbeans object which contains the password attributes
|
||||
* @param password the password, if null, the password attributes will be removed
|
||||
* @param hashAlgo the hash algorithm, if null the password will be XORed
|
||||
* @param prefix the prefix of the password attributes, may be null
|
||||
*/
|
||||
public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) {
|
||||
XmlCursor cur = xobj.newCursor();
|
||||
|
||||
if (password == null) {
|
||||
cur.removeAttribute(getAttrName(prefix, "password"));
|
||||
cur.removeAttribute(getAttrName(prefix, "algorithmName"));
|
||||
cur.removeAttribute(getAttrName(prefix, "hashValue"));
|
||||
cur.removeAttribute(getAttrName(prefix, "saltValue"));
|
||||
cur.removeAttribute(getAttrName(prefix, "spinCount"));
|
||||
return;
|
||||
}
|
||||
|
||||
cur.toFirstContentToken();
|
||||
if (hashAlgo == null) {
|
||||
int hash = CryptoFunctions.createXorVerifier1(password);
|
||||
cur.insertAttributeWithValue(getAttrName(prefix, "password"),
|
||||
String.format(Locale.ROOT, "%04X", hash).toUpperCase(Locale.ROOT));
|
||||
} else {
|
||||
SecureRandom random = new SecureRandom();
|
||||
byte salt[] = random.generateSeed(16);
|
||||
|
||||
// Iterations specifies the number of times the hashing function shall be iteratively run (using each
|
||||
// iteration's result as the input for the next iteration).
|
||||
int spinCount = 100000;
|
||||
|
||||
// Implementation Notes List:
|
||||
// --> In this third stage, the reversed byte order legacy hash from the second stage shall
|
||||
// be converted to Unicode hex string representation
|
||||
byte hash[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCount, false);
|
||||
|
||||
cur.insertAttributeWithValue(getAttrName(prefix, "algorithmName"), hashAlgo.jceId);
|
||||
cur.insertAttributeWithValue(getAttrName(prefix, "hashValue"), DatatypeConverter.printBase64Binary(hash));
|
||||
cur.insertAttributeWithValue(getAttrName(prefix, "saltValue"), DatatypeConverter.printBase64Binary(salt));
|
||||
cur.insertAttributeWithValue(getAttrName(prefix, "spinCount"), ""+spinCount);
|
||||
}
|
||||
cur.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the password, i.e.
|
||||
* calculates the hash of the given password and compares it against the stored hash
|
||||
*
|
||||
* @param xobj the xmlbeans object which contains the password attributes
|
||||
* @param password the password, if null the method will always return false,
|
||||
* even if there's no password set
|
||||
* @param prefix the prefix of the password attributes, may be null
|
||||
*
|
||||
* @return true, if the hashes match
|
||||
*/
|
||||
public static boolean validatePassword(XmlObject xobj, String password, String prefix) {
|
||||
// TODO: is "velvetSweatshop" the default password?
|
||||
if (password == null) return false;
|
||||
|
||||
XmlCursor cur = xobj.newCursor();
|
||||
String xorHashVal = cur.getAttributeText(getAttrName(prefix, "password"));
|
||||
String algoName = cur.getAttributeText(getAttrName(prefix, "algorithmName"));
|
||||
String hashVal = cur.getAttributeText(getAttrName(prefix, "hashValue"));
|
||||
String saltVal = cur.getAttributeText(getAttrName(prefix, "saltValue"));
|
||||
String spinCount = cur.getAttributeText(getAttrName(prefix, "spinCount"));
|
||||
cur.dispose();
|
||||
|
||||
if (xorHashVal != null) {
|
||||
int hash1 = Integer.parseInt(xorHashVal, 16);
|
||||
int hash2 = CryptoFunctions.createXorVerifier1(password);
|
||||
return hash1 == hash2;
|
||||
} else {
|
||||
if (hashVal == null || algoName == null || saltVal == null || spinCount == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte hash1[] = DatatypeConverter.parseBase64Binary(hashVal);
|
||||
HashAlgorithm hashAlgo = HashAlgorithm.fromString(algoName);
|
||||
byte salt[] = DatatypeConverter.parseBase64Binary(saltVal);
|
||||
int spinCnt = Integer.parseInt(spinCount);
|
||||
byte hash2[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCnt, false);
|
||||
return Arrays.equals(hash1, hash2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static QName getAttrName(String prefix, String name) {
|
||||
if (prefix == null || "".equals(prefix)) {
|
||||
return new QName(name);
|
||||
} else {
|
||||
return new QName(prefix+Character.toUpperCase(name.charAt(0))+name.substring(1));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,130 +1,60 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
package org.apache.poi.xssf.usermodel.helpers;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.apache.poi.poifs.crypt.CryptoFunctions;
|
||||
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
|
||||
public class XSSFPaswordHelper {
|
||||
/**
|
||||
* Sets the XORed or hashed password
|
||||
*
|
||||
* @param xobj the xmlbeans object which contains the password attributes
|
||||
* @param password the password, if null, the password attributes will be removed
|
||||
* @param hashAlgo the hash algorithm, if null the password will be XORed
|
||||
* @param prefix the prefix of the password attributes, may be null
|
||||
*/
|
||||
public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) {
|
||||
XmlCursor cur = xobj.newCursor();
|
||||
|
||||
if (password == null) {
|
||||
cur.removeAttribute(getAttrName(prefix, "password"));
|
||||
cur.removeAttribute(getAttrName(prefix, "algorithmName"));
|
||||
cur.removeAttribute(getAttrName(prefix, "hashValue"));
|
||||
cur.removeAttribute(getAttrName(prefix, "saltValue"));
|
||||
cur.removeAttribute(getAttrName(prefix, "spinCount"));
|
||||
return;
|
||||
}
|
||||
|
||||
cur.toFirstContentToken();
|
||||
if (hashAlgo == null) {
|
||||
int hash = CryptoFunctions.createXorVerifier1(password);
|
||||
cur.insertAttributeWithValue(getAttrName(prefix, "password"),
|
||||
Integer.toHexString(hash).toUpperCase(Locale.ROOT));
|
||||
} else {
|
||||
SecureRandom random = new SecureRandom();
|
||||
byte salt[] = random.generateSeed(16);
|
||||
|
||||
// Iterations specifies the number of times the hashing function shall be iteratively run (using each
|
||||
// iteration's result as the input for the next iteration).
|
||||
int spinCount = 100000;
|
||||
|
||||
// Implementation Notes List:
|
||||
// --> In this third stage, the reversed byte order legacy hash from the second stage shall
|
||||
// be converted to Unicode hex string representation
|
||||
byte hash[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCount, false);
|
||||
|
||||
cur.insertAttributeWithValue(getAttrName(prefix, "algorithmName"), hashAlgo.jceId);
|
||||
cur.insertAttributeWithValue(getAttrName(prefix, "hashValue"), DatatypeConverter.printBase64Binary(hash));
|
||||
cur.insertAttributeWithValue(getAttrName(prefix, "saltValue"), DatatypeConverter.printBase64Binary(salt));
|
||||
cur.insertAttributeWithValue(getAttrName(prefix, "spinCount"), ""+spinCount);
|
||||
}
|
||||
cur.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the password, i.e.
|
||||
* calculates the hash of the given password and compares it against the stored hash
|
||||
*
|
||||
* @param xobj the xmlbeans object which contains the password attributes
|
||||
* @param password the password, if null the method will always return false,
|
||||
* even if there's no password set
|
||||
* @param prefix the prefix of the password attributes, may be null
|
||||
*
|
||||
* @return true, if the hashes match
|
||||
*/
|
||||
public static boolean validatePassword(XmlObject xobj, String password, String prefix) {
|
||||
// TODO: is "velvetSweatshop" the default password?
|
||||
if (password == null) return false;
|
||||
|
||||
XmlCursor cur = xobj.newCursor();
|
||||
String xorHashVal = cur.getAttributeText(getAttrName(prefix, "password"));
|
||||
String algoName = cur.getAttributeText(getAttrName(prefix, "algorithmName"));
|
||||
String hashVal = cur.getAttributeText(getAttrName(prefix, "hashValue"));
|
||||
String saltVal = cur.getAttributeText(getAttrName(prefix, "saltValue"));
|
||||
String spinCount = cur.getAttributeText(getAttrName(prefix, "spinCount"));
|
||||
cur.dispose();
|
||||
|
||||
if (xorHashVal != null) {
|
||||
int hash1 = Integer.parseInt(xorHashVal, 16);
|
||||
int hash2 = CryptoFunctions.createXorVerifier1(password);
|
||||
return hash1 == hash2;
|
||||
} else {
|
||||
if (hashVal == null || algoName == null || saltVal == null || spinCount == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte hash1[] = DatatypeConverter.parseBase64Binary(hashVal);
|
||||
HashAlgorithm hashAlgo = HashAlgorithm.fromString(algoName);
|
||||
byte salt[] = DatatypeConverter.parseBase64Binary(saltVal);
|
||||
int spinCnt = Integer.parseInt(spinCount);
|
||||
byte hash2[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCnt, false);
|
||||
return Arrays.equals(hash1, hash2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static QName getAttrName(String prefix, String name) {
|
||||
if (prefix == null || "".equals(prefix)) {
|
||||
return new QName(name);
|
||||
} else {
|
||||
return new QName(prefix+Character.toUpperCase(name.charAt(0))+name.substring(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
package org.apache.poi.xssf.usermodel.helpers;
|
||||
|
||||
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.apache.poi.util.Removal;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
|
||||
/**
|
||||
* @deprecated POI 3.15 beta 3. Use {@link XSSFPasswordHelper} instead.
|
||||
*/
|
||||
@Internal(since="3.15 beta 3")
|
||||
@Deprecated
|
||||
@Removal(version="3.17")
|
||||
public class XSSFPaswordHelper {
|
||||
/**
|
||||
* Sets the XORed or hashed password
|
||||
*
|
||||
* @param xobj the xmlbeans object which contains the password attributes
|
||||
* @param password the password, if null, the password attributes will be removed
|
||||
* @param hashAlgo the hash algorithm, if null the password will be XORed
|
||||
* @param prefix the prefix of the password attributes, may be null
|
||||
*/
|
||||
public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) {
|
||||
XSSFPasswordHelper.setPassword(xobj, password, hashAlgo, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the password, i.e.
|
||||
* calculates the hash of the given password and compares it against the stored hash
|
||||
*
|
||||
* @param xobj the xmlbeans object which contains the password attributes
|
||||
* @param password the password, if null the method will always return false,
|
||||
* even if there's no password set
|
||||
* @param prefix the prefix of the password attributes, may be null
|
||||
*
|
||||
* @return true, if the hashes match
|
||||
*/
|
||||
public static boolean validatePassword(XmlObject xobj, String password, String prefix) {
|
||||
return XSSFPasswordHelper.validatePassword(xobj, password, prefix);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,9 +83,7 @@ public final class XSSFRowShifter extends RowShifter {
|
|||
public void updateNamedRanges(FormulaShifter shifter) {
|
||||
Workbook wb = sheet.getWorkbook();
|
||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create((XSSFWorkbook) wb);
|
||||
final int numberOfNames = wb.getNumberOfNames();
|
||||
for (int i = 0; i < numberOfNames; i++) {
|
||||
Name name = wb.getNameAt(i);
|
||||
for (Name name : wb.getAllNames()) {
|
||||
String formula = name.getRefersToFormula();
|
||||
int sheetIndex = name.getSheetIndex();
|
||||
final int rowIndex = -1; //don't care, named ranges are not allowed to include structured references
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.poi.openxml4j.opc.internal;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
|
@ -44,16 +45,21 @@ public final class TestContentTypeManager {
|
|||
|
||||
// Retrieves core properties part
|
||||
OPCPackage p = OPCPackage.open(filepath, PackageAccess.READ);
|
||||
PackageRelationshipCollection rels = p.getRelationshipsByType(PackageRelationshipTypes.CORE_PROPERTIES);
|
||||
PackageRelationship corePropertiesRelationship = rels.getRelationship(0);
|
||||
PackagePart coreDocument = p.getPart(corePropertiesRelationship);
|
||||
|
||||
assertEquals("application/vnd.openxmlformats-package.core-properties+xml", coreDocument.getContentType());
|
||||
try {
|
||||
PackageRelationshipCollection rels = p.getRelationshipsByType(PackageRelationshipTypes.CORE_PROPERTIES);
|
||||
PackageRelationship corePropertiesRelationship = rels.getRelationship(0);
|
||||
PackagePart coreDocument = p.getPart(corePropertiesRelationship);
|
||||
|
||||
// TODO - finish writing this test
|
||||
assumeTrue("finish writing this test", false);
|
||||
|
||||
ContentTypeManager ctm = new ZipContentTypeManager(coreDocument.getInputStream(), p);
|
||||
assertEquals("application/vnd.openxmlformats-package.core-properties+xml", coreDocument.getContentType());
|
||||
|
||||
// TODO - finish writing this test
|
||||
assumeTrue("finish writing this test", false);
|
||||
|
||||
ContentTypeManager ctm = new ZipContentTypeManager(coreDocument.getInputStream(), p);
|
||||
assertNotNull(ctm);
|
||||
} finally {
|
||||
p.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -115,25 +115,25 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues {
|
|||
assertFalse(wb.isMacroEnabled());
|
||||
assertEquals(3, wb.getNumberOfNames());
|
||||
|
||||
assertEquals(0, wb.getNameAt(0).getCTName().getLocalSheetId());
|
||||
assertFalse(wb.getNameAt(0).getCTName().isSetLocalSheetId());
|
||||
assertEquals("SheetA!$A$1", wb.getNameAt(0).getRefersToFormula());
|
||||
assertEquals("SheetA", wb.getNameAt(0).getSheetName());
|
||||
assertEquals(0, wb.getName("SheetAA1").getCTName().getLocalSheetId());
|
||||
assertFalse(wb.getName("SheetAA1").getCTName().isSetLocalSheetId());
|
||||
assertEquals("SheetA!$A$1", wb.getName("SheetAA1").getRefersToFormula());
|
||||
assertEquals("SheetA", wb.getName("SheetAA1").getSheetName());
|
||||
|
||||
assertEquals(0, wb.getNameAt(1).getCTName().getLocalSheetId());
|
||||
assertFalse(wb.getNameAt(1).getCTName().isSetLocalSheetId());
|
||||
assertEquals("SheetB!$A$1", wb.getNameAt(1).getRefersToFormula());
|
||||
assertEquals("SheetB", wb.getNameAt(1).getSheetName());
|
||||
assertEquals(0, wb.getName("SheetBA1").getCTName().getLocalSheetId());
|
||||
assertFalse(wb.getName("SheetBA1").getCTName().isSetLocalSheetId());
|
||||
assertEquals("SheetB!$A$1", wb.getName("SheetBA1").getRefersToFormula());
|
||||
assertEquals("SheetB", wb.getName("SheetBA1").getSheetName());
|
||||
|
||||
assertEquals(0, wb.getNameAt(2).getCTName().getLocalSheetId());
|
||||
assertFalse(wb.getNameAt(2).getCTName().isSetLocalSheetId());
|
||||
assertEquals("SheetC!$A$1", wb.getNameAt(2).getRefersToFormula());
|
||||
assertEquals("SheetC", wb.getNameAt(2).getSheetName());
|
||||
assertEquals(0, wb.getName("SheetCA1").getCTName().getLocalSheetId());
|
||||
assertFalse(wb.getName("SheetCA1").getCTName().isSetLocalSheetId());
|
||||
assertEquals("SheetC!$A$1", wb.getName("SheetCA1").getRefersToFormula());
|
||||
assertEquals("SheetC", wb.getName("SheetCA1").getSheetName());
|
||||
|
||||
// Save and re-load, still there
|
||||
XSSFWorkbook nwb = XSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||
assertEquals(3, nwb.getNumberOfNames());
|
||||
assertEquals("SheetA!$A$1", nwb.getNameAt(0).getRefersToFormula());
|
||||
assertEquals("SheetA!$A$1", nwb.getName("SheetAA1").getRefersToFormula());
|
||||
|
||||
nwb.close();
|
||||
wb.close();
|
||||
|
|
|
@ -154,7 +154,9 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
|||
evaluator.evaluate(cXSL_cell);
|
||||
fail("Without a fix for #56752, shouldn't be able to evaluate a " +
|
||||
"reference to a non-provided linked workbook");
|
||||
} catch(Exception e) {}
|
||||
} catch(Exception e) {
|
||||
// expected here
|
||||
}
|
||||
|
||||
// Setup the environment
|
||||
Map<String,FormulaEvaluator> evaluators = new HashMap<String, FormulaEvaluator>();
|
||||
|
@ -171,8 +173,19 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
|||
evaluator.evaluate(c);
|
||||
}
|
||||
}
|
||||
// And evaluate the other way too
|
||||
evaluator.evaluateAll();
|
||||
|
||||
// Evaluate and check results
|
||||
// Static evaluator won't work, as no references passed in
|
||||
try {
|
||||
XSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||
fail("Static method lacks references, shouldn't work");
|
||||
} catch(Exception e) {
|
||||
// expected here
|
||||
}
|
||||
|
||||
|
||||
// Evaluate specific cells and check results
|
||||
assertEquals("\"Hello!\"", evaluator.evaluate(cXSLX_cell).formatAsString());
|
||||
assertEquals("\"Test A1\"", evaluator.evaluate(cXSLX_sNR).formatAsString());
|
||||
assertEquals("142.0", evaluator.evaluate(cXSLX_gNR).formatAsString());
|
||||
|
@ -196,7 +209,9 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
|||
try {
|
||||
cXSLX_nw_cell.setCellFormula("[alt.xlsx]Sheet1!$A$1");
|
||||
fail("New workbook not linked, shouldn't be able to add");
|
||||
} catch (Exception e) {}
|
||||
} catch (Exception e) {
|
||||
// expected here
|
||||
}
|
||||
|
||||
// Link and re-try
|
||||
Workbook alt = new XSSFWorkbook();
|
||||
|
@ -651,4 +666,20 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
|||
private Cell getCell(Sheet sheet, int rowNo, int column) {
|
||||
return sheet.getRow(rowNo).getCell(column);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test59736() {
|
||||
Workbook wb = XSSFTestDataSamples.openSampleWorkbook("59736.xlsx");
|
||||
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
||||
Cell cell = wb.getSheetAt(0).getRow(0).getCell(0);
|
||||
assertEquals(1, cell.getNumericCellValue(), 0.001);
|
||||
|
||||
cell = wb.getSheetAt(0).getRow(1).getCell(0);
|
||||
CellValue value = evaluator.evaluate(cell);
|
||||
assertEquals(1, value.getNumberValue(), 0.001);
|
||||
|
||||
cell = wb.getSheetAt(0).getRow(2).getCell(0);
|
||||
value = evaluator.evaluate(cell);
|
||||
assertEquals(1, value.getNumberValue(), 0.001);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,9 +53,8 @@ public final class TestXSSFName extends BaseTestNamedRange {
|
|||
//sheet.createFreezePane(0, 3);
|
||||
}
|
||||
assertEquals(1, wb.getNumberOfNames());
|
||||
XSSFName nr1 = wb.getNameAt(0);
|
||||
XSSFName nr1 = wb.getName(XSSFName.BUILTIN_PRINT_TITLE);
|
||||
|
||||
assertEquals(XSSFName.BUILTIN_PRINT_TITLE, nr1.getNameName());
|
||||
assertEquals("'First Sheet'!$A:$A,'First Sheet'!$1:$4", nr1.getRefersToFormula());
|
||||
|
||||
//remove the columns part
|
||||
|
@ -77,9 +76,8 @@ public final class TestXSSFName extends BaseTestNamedRange {
|
|||
wb.close();
|
||||
|
||||
assertEquals(1, nwb.getNumberOfNames());
|
||||
nr1 = nwb.getNameAt(0);
|
||||
nr1 = nwb.getName(XSSFName.BUILTIN_PRINT_TITLE);
|
||||
|
||||
assertEquals(XSSFName.BUILTIN_PRINT_TITLE, nr1.getNameName());
|
||||
assertEquals("'First Sheet'!$A:$A,'First Sheet'!$1:$4", nr1.getRefersToFormula());
|
||||
|
||||
// check that setting RR&C on a second sheet causes a new Print_Titles built-in
|
||||
|
@ -89,7 +87,7 @@ public final class TestXSSFName extends BaseTestNamedRange {
|
|||
sheet2.setRepeatingColumns(CellRangeAddress.valueOf("B:C"));
|
||||
|
||||
assertEquals(2, nwb.getNumberOfNames());
|
||||
XSSFName nr2 = nwb.getNameAt(1);
|
||||
XSSFName nr2 = nwb.getNames(XSSFName.BUILTIN_PRINT_TITLE).get(1);
|
||||
|
||||
assertEquals(XSSFName.BUILTIN_PRINT_TITLE, nr2.getNameName());
|
||||
assertEquals("SecondSheet!$B:$C,SecondSheet!$1:$1", nr2.getRefersToFormula());
|
||||
|
@ -98,4 +96,38 @@ public final class TestXSSFName extends BaseTestNamedRange {
|
|||
sheet2.setRepeatingColumns(null);
|
||||
nwb.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetNameName() throws Exception {
|
||||
// Test that renaming named ranges doesn't break our new named range map
|
||||
XSSFWorkbook wb = new XSSFWorkbook();
|
||||
wb.createSheet("First Sheet");
|
||||
|
||||
// Two named ranges called "name1", one scoped to sheet1 and one globally
|
||||
XSSFName nameSheet1 = wb.createName();
|
||||
nameSheet1.setNameName("name1");
|
||||
nameSheet1.setRefersToFormula("'First Sheet'!$A$1");
|
||||
nameSheet1.setSheetIndex(0);
|
||||
|
||||
XSSFName nameGlobal = wb.createName();
|
||||
nameGlobal.setNameName("name1");
|
||||
nameGlobal.setRefersToFormula("'First Sheet'!$B$1");
|
||||
|
||||
// Rename sheet-scoped name to "name2", check everything is updated properly
|
||||
// and that the other name is unaffected
|
||||
nameSheet1.setNameName("name2");
|
||||
assertEquals(1, wb.getNames("name1").size());
|
||||
assertEquals(1, wb.getNames("name2").size());
|
||||
assertEquals(nameGlobal, wb.getName("name1"));
|
||||
assertEquals(nameSheet1, wb.getName("name2"));
|
||||
|
||||
// Rename the other name to "name" and check everything again
|
||||
nameGlobal.setNameName("name2");
|
||||
assertEquals(0, wb.getNames("name1").size());
|
||||
assertEquals(2, wb.getNames("name2").size());
|
||||
assertTrue(wb.getNames("name2").contains(nameGlobal));
|
||||
assertTrue(wb.getNames("name2").contains(nameSheet1));
|
||||
|
||||
wb.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
|
|||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnsignedShortHex;
|
||||
|
||||
|
||||
public final class TestXSSFSheet extends BaseTestXSheet {
|
||||
|
@ -1099,6 +1100,30 @@ public final class TestXSSFSheet extends BaseTestXSheet {
|
|||
wb.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void protectSheet_emptyPassword() throws IOException {
|
||||
XSSFWorkbook wb = new XSSFWorkbook();
|
||||
XSSFSheet sheet = wb.createSheet();
|
||||
CTSheetProtection pr = sheet.getCTWorksheet().getSheetProtection();
|
||||
assertNull("CTSheetProtection should be null by default", pr);
|
||||
String password = "";
|
||||
sheet.protectSheet(password);
|
||||
pr = sheet.getCTWorksheet().getSheetProtection();
|
||||
assertNotNull("CTSheetProtection should be not null", pr);
|
||||
assertTrue("sheet protection should be on", pr.isSetSheet());
|
||||
assertTrue("object protection should be on", pr.isSetObjects());
|
||||
assertTrue("scenario protection should be on", pr.isSetScenarios());
|
||||
int hashVal = CryptoFunctions.createXorVerifier1(password);
|
||||
STUnsignedShortHex xpassword = pr.xgetPassword();
|
||||
int actualVal = Integer.parseInt(xpassword.getStringValue(),16);
|
||||
assertEquals("well known value for top secret hash should match", hashVal, actualVal);
|
||||
|
||||
sheet.protectSheet(null);
|
||||
assertNull("protectSheet(null) should unset CTSheetProtection", sheet.getCTWorksheet().getSheetProtection());
|
||||
|
||||
wb.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void protectSheet_lowlevel_2013() throws IOException {
|
||||
String password = "test";
|
||||
|
|
|
@ -1140,4 +1140,44 @@ public final class TestXSSFWorkbook extends BaseTestXWorkbook {
|
|||
|
||||
wb.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveSheet() throws IOException {
|
||||
// Test removing a sheet maintains the named ranges correctly
|
||||
XSSFWorkbook wb = new XSSFWorkbook();
|
||||
wb.createSheet("Sheet1");
|
||||
wb.createSheet("Sheet2");
|
||||
|
||||
XSSFName sheet1Name = wb.createName();
|
||||
sheet1Name.setNameName("name1");
|
||||
sheet1Name.setSheetIndex(0);
|
||||
sheet1Name.setRefersToFormula("Sheet1!$A$1");
|
||||
|
||||
XSSFName sheet2Name = wb.createName();
|
||||
sheet2Name.setNameName("name1");
|
||||
sheet2Name.setSheetIndex(1);
|
||||
sheet2Name.setRefersToFormula("Sheet2!$A$1");
|
||||
|
||||
assertTrue(wb.getAllNames().contains(sheet1Name));
|
||||
assertTrue(wb.getAllNames().contains(sheet2Name));
|
||||
|
||||
assertEquals(2, wb.getNames("name1").size());
|
||||
assertEquals(sheet1Name, wb.getNames("name1").get(0));
|
||||
assertEquals(sheet2Name, wb.getNames("name1").get(1));
|
||||
|
||||
// Remove sheet1, we should only have sheet2Name now
|
||||
wb.removeSheetAt(0);
|
||||
|
||||
assertFalse(wb.getAllNames().contains(sheet1Name));
|
||||
assertTrue(wb.getAllNames().contains(sheet2Name));
|
||||
assertEquals(1, wb.getNames("name1").size());
|
||||
assertEquals(sheet2Name, wb.getNames("name1").get(0));
|
||||
|
||||
// Check by index as well for sanity
|
||||
assertEquals(1, wb.getNumberOfNames());
|
||||
assertEquals(0, wb.getNameIndex("name1"));
|
||||
assertEquals(sheet2Name, wb.getNameAt(0));
|
||||
|
||||
wb.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -571,20 +571,39 @@ public final class HWPFDocument extends HWPFDocumentCore {
|
|||
return _fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning - not currently implemented for HWPF!
|
||||
*/
|
||||
@Override
|
||||
public void write() throws IOException {
|
||||
// TODO Implement
|
||||
throw new IllegalStateException("Coming soon!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out the word file that is represented by an instance of this class.
|
||||
*
|
||||
* If the {@link File} exists, it will be replaced, otherwise a new one
|
||||
* will be created
|
||||
*
|
||||
* @param newFile The File to write to.
|
||||
* @throws IOException If there is an unexpected IOException from writing
|
||||
* to the File.
|
||||
*
|
||||
* @since 3.15 beta 3
|
||||
*/
|
||||
@Override
|
||||
public void write(File newFile) throws IOException {
|
||||
throw new IllegalStateException("Coming soon!");
|
||||
NPOIFSFileSystem pfs = POIFSFileSystem.create(newFile);
|
||||
write(pfs, true);
|
||||
pfs.writeFilesystem();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out the word file that is represented by an instance of this class.
|
||||
*
|
||||
* If {@code stream} is a {@link java.io.FileOutputStream} on a networked drive
|
||||
* or has a high cost/latency associated with each written byte,
|
||||
* For better performance when writing to files, use {@link #write(File)}.
|
||||
* If {@code stream} has a high cost/latency associated with each written byte,
|
||||
* consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream}
|
||||
* to improve write performance.
|
||||
*
|
||||
|
@ -592,9 +611,12 @@ public final class HWPFDocument extends HWPFDocumentCore {
|
|||
* @throws IOException If there is an unexpected IOException from the passed
|
||||
* in OutputStream.
|
||||
*/
|
||||
public void write(OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
public void write(OutputStream out) throws IOException {
|
||||
NPOIFSFileSystem pfs = new NPOIFSFileSystem();
|
||||
write(pfs, true);
|
||||
pfs.writeFilesystem( out );
|
||||
}
|
||||
private void write(NPOIFSFileSystem pfs, boolean copyOtherEntries) throws IOException {
|
||||
// initialize our streams for writing.
|
||||
HWPFFileSystem docSys = new HWPFFileSystem();
|
||||
HWPFOutputStream wordDocumentStream = docSys.getStream(STREAM_WORD_DOCUMENT);
|
||||
|
@ -891,7 +913,8 @@ public final class HWPFDocument extends HWPFDocumentCore {
|
|||
}
|
||||
|
||||
// create new document preserving order of entries
|
||||
NPOIFSFileSystem pfs = new NPOIFSFileSystem();
|
||||
// TODO Check "copyOtherEntries" and tweak behaviour based on that
|
||||
// TODO That's needed for in-place write
|
||||
boolean docWritten = false;
|
||||
boolean dataWritten = false;
|
||||
boolean objectPoolWritten = false;
|
||||
|
@ -967,7 +990,6 @@ public final class HWPFDocument extends HWPFDocumentCore {
|
|||
if ( !objectPoolWritten )
|
||||
_objectPool.writeTo( pfs.getRoot() );
|
||||
|
||||
pfs.writeFilesystem( out );
|
||||
this.directory = pfs.getRoot();
|
||||
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hwpf.usermodel;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
||||
import org.apache.poi.hwpf.HWPFDocument;
|
||||
import org.apache.poi.hwpf.HWPFTestCase;
|
||||
import org.apache.poi.hwpf.HWPFTestDataSamples;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.util.TempFile;
|
||||
|
||||
/**
|
||||
* Test various write situations
|
||||
*/
|
||||
public final class TestHWPFWrite extends HWPFTestCase {
|
||||
/**
|
||||
* Write to a stream
|
||||
*/
|
||||
public void testWriteStream() throws Exception {
|
||||
HWPFDocument doc = HWPFTestDataSamples.openSampleFile("SampleDoc.doc");
|
||||
|
||||
Range r = doc.getRange();
|
||||
assertEquals("I am a test document\r", r.getParagraph(0).text());
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
doc.write(baos);
|
||||
doc.close();
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
|
||||
doc = new HWPFDocument(bais);
|
||||
r = doc.getRange();
|
||||
assertEquals("I am a test document\r", r.getParagraph(0).text());
|
||||
doc.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to a new file
|
||||
*/
|
||||
public void testWriteNewFile() throws Exception {
|
||||
HWPFDocument doc = HWPFTestDataSamples.openSampleFile("SampleDoc.doc");
|
||||
|
||||
Range r = doc.getRange();
|
||||
assertEquals("I am a test document\r", r.getParagraph(0).text());
|
||||
|
||||
File file = TempFile.createTempFile("TestDocument", ".doc");
|
||||
doc.write(file);
|
||||
doc.close();
|
||||
|
||||
// Check reading from File and Stream
|
||||
doc = new HWPFDocument(new FileInputStream(file));
|
||||
r = doc.getRange();
|
||||
assertEquals("I am a test document\r", r.getParagraph(0).text());
|
||||
doc.close();
|
||||
|
||||
doc = new HWPFDocument(new POIFSFileSystem(file));
|
||||
r = doc.getRange();
|
||||
assertEquals("I am a test document\r", r.getParagraph(0).text());
|
||||
doc.close();
|
||||
}
|
||||
|
||||
// TODO In-place write positive and negative checks
|
||||
}
|
|
@ -50,14 +50,20 @@ public abstract class BaseTestSlideShow {
|
|||
@Test
|
||||
public void addPicture_Stream() throws IOException {
|
||||
SlideShow<?,?> show = createSlideShow();
|
||||
InputStream stream = slTests.openResourceAsStream("clock.jpg");
|
||||
|
||||
assertEquals(0, show.getPictureData().size());
|
||||
PictureData picture = show.addPicture(stream, PictureType.JPEG);
|
||||
assertEquals(1, show.getPictureData().size());
|
||||
assertSame(picture, show.getPictureData().get(0));
|
||||
|
||||
show.close();
|
||||
try {
|
||||
InputStream stream = slTests.openResourceAsStream("clock.jpg");
|
||||
try {
|
||||
assertEquals(0, show.getPictureData().size());
|
||||
PictureData picture = show.addPicture(stream, PictureType.JPEG);
|
||||
assertEquals(1, show.getPictureData().size());
|
||||
assertSame(picture, show.getPictureData().get(0));
|
||||
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
} finally {
|
||||
show.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.apache.poi.hssf.usermodel.HSSFRow;
|
|||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||
import org.apache.poi.ss.formula.eval.ValueEval;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.CellValue;
|
||||
|
@ -105,6 +106,7 @@ public final class TestIndirect {
|
|||
|
||||
// non-error cases
|
||||
confirm(feA, c, "INDIRECT(\"C2\")", 23);
|
||||
confirm(feA, c, "INDIRECT(\"C2\", TRUE)", 23);
|
||||
confirm(feA, c, "INDIRECT(\"$C2\")", 23);
|
||||
confirm(feA, c, "INDIRECT(\"C$2\")", 23);
|
||||
confirm(feA, c, "SUM(INDIRECT(\"Sheet2!B1:C3\"))", 351); // area ref
|
||||
|
@ -149,7 +151,7 @@ public final class TestIndirect {
|
|||
// confirm(feA, c, "INDIRECT(\"Sheet1!A65537\")", ErrorEval.REF_INVALID); // bad row
|
||||
// }
|
||||
confirm(feA, c, "INDIRECT(\"Sheet1!A 1\")", ErrorEval.REF_INVALID); // space in cell ref
|
||||
|
||||
|
||||
wbA.close();
|
||||
}
|
||||
|
||||
|
@ -203,4 +205,9 @@ public final class TestIndirect {
|
|||
+ "' but got '" + cv.formatAsString() + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidInput() {
|
||||
assertEquals(ErrorEval.VALUE_INVALID, Indirect.instance.evaluate(new ValueEval[] {}, null));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,8 @@ package org.apache.poi.ss.formula.functions;
|
|||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.formula.eval.AreaEval;
|
||||
import org.apache.poi.ss.formula.eval.NumberEval;
|
||||
import org.apache.poi.ss.formula.eval.ValueEval;
|
||||
import org.apache.poi.ss.formula.FormulaParseException;
|
||||
import org.apache.poi.ss.formula.eval.*;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
|
@ -75,7 +74,6 @@ public final class TestSubtotal extends TestCase {
|
|||
}
|
||||
|
||||
public void testAvg(){
|
||||
|
||||
Workbook wb = new HSSFWorkbook();
|
||||
|
||||
FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
|
||||
|
@ -95,16 +93,18 @@ public final class TestSubtotal extends TestCase {
|
|||
a6.setCellFormula("SUBTOTAL(1,B2:B6)*2 + 2");
|
||||
Cell a7 = sh.createRow(7).createCell(1);
|
||||
a7.setCellFormula("SUBTOTAL(1,B2:B7)");
|
||||
Cell a8 = sh.createRow(8).createCell(1);
|
||||
a8.setCellFormula("SUBTOTAL(1,B2,B3,B4,B5,B6,B7,B8)");
|
||||
|
||||
fe.evaluateAll();
|
||||
|
||||
assertEquals(2.0, a3.getNumericCellValue());
|
||||
assertEquals(8.0, a6.getNumericCellValue());
|
||||
assertEquals(3.0, a7.getNumericCellValue());
|
||||
assertEquals(3.0, a8.getNumericCellValue());
|
||||
}
|
||||
|
||||
public void testSum(){
|
||||
|
||||
Workbook wb = new HSSFWorkbook();
|
||||
|
||||
FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
|
||||
|
@ -124,12 +124,15 @@ public final class TestSubtotal extends TestCase {
|
|||
a6.setCellFormula("SUBTOTAL(9,B2:B6)*2 + 2");
|
||||
Cell a7 = sh.createRow(7).createCell(1);
|
||||
a7.setCellFormula("SUBTOTAL(9,B2:B7)");
|
||||
Cell a8 = sh.createRow(8).createCell(1);
|
||||
a8.setCellFormula("SUBTOTAL(9,B2,B3,B4,B5,B6,B7,B8)");
|
||||
|
||||
fe.evaluateAll();
|
||||
|
||||
assertEquals(4.0, a3.getNumericCellValue());
|
||||
assertEquals(26.0, a6.getNumericCellValue());
|
||||
assertEquals(12.0, a7.getNumericCellValue());
|
||||
assertEquals(12.0, a8.getNumericCellValue());
|
||||
}
|
||||
|
||||
public void testCount(){
|
||||
|
@ -147,18 +150,21 @@ public final class TestSubtotal extends TestCase {
|
|||
a3.setCellFormula("SUBTOTAL(2,B2:B3)");
|
||||
Cell a4 = sh.createRow(4).createCell(1);
|
||||
a4.setCellValue("POI"); // A4 is string and not counted
|
||||
Cell a5 = sh.createRow(5).createCell(1); // A5 is blank and not counted
|
||||
/*Cell a5 =*/ sh.createRow(5).createCell(1); // A5 is blank and not counted
|
||||
|
||||
Cell a6 = sh.createRow(6).createCell(1);
|
||||
a6.setCellFormula("SUBTOTAL(2,B2:B6)*2 + 2");
|
||||
Cell a7 = sh.createRow(7).createCell(1);
|
||||
a7.setCellFormula("SUBTOTAL(2,B2:B7)");
|
||||
Cell a8 = sh.createRow(8).createCell(1);
|
||||
a8.setCellFormula("SUBTOTAL(2,B2,B3,B4,B5,B6,B7,B8)");
|
||||
|
||||
fe.evaluateAll();
|
||||
|
||||
assertEquals(2.0, a3.getNumericCellValue());
|
||||
assertEquals(6.0, a6.getNumericCellValue());
|
||||
assertEquals(2.0, a7.getNumericCellValue());
|
||||
assertEquals(2.0, a8.getNumericCellValue());
|
||||
}
|
||||
|
||||
public void testCounta(){
|
||||
|
@ -176,18 +182,21 @@ public final class TestSubtotal extends TestCase {
|
|||
a3.setCellFormula("SUBTOTAL(3,B2:B3)");
|
||||
Cell a4 = sh.createRow(4).createCell(1);
|
||||
a4.setCellValue("POI"); // A4 is string and not counted
|
||||
Cell a5 = sh.createRow(5).createCell(1); // A5 is blank and not counted
|
||||
/*Cell a5 =*/ sh.createRow(5).createCell(1); // A5 is blank and not counted
|
||||
|
||||
Cell a6 = sh.createRow(6).createCell(1);
|
||||
a6.setCellFormula("SUBTOTAL(3,B2:B6)*2 + 2");
|
||||
Cell a7 = sh.createRow(7).createCell(1);
|
||||
a7.setCellFormula("SUBTOTAL(3,B2:B7)");
|
||||
Cell a8 = sh.createRow(8).createCell(1);
|
||||
a8.setCellFormula("SUBTOTAL(3,B2,B3,B4,B5,B6,B7,B8)");
|
||||
|
||||
fe.evaluateAll();
|
||||
|
||||
assertEquals(2.0, a3.getNumericCellValue());
|
||||
assertEquals(8.0, a6.getNumericCellValue());
|
||||
assertEquals(3.0, a7.getNumericCellValue());
|
||||
assertEquals(3.0, a8.getNumericCellValue());
|
||||
}
|
||||
|
||||
public void testMax(){
|
||||
|
@ -211,12 +220,15 @@ public final class TestSubtotal extends TestCase {
|
|||
a6.setCellFormula("SUBTOTAL(4,B2:B6)*2 + 2");
|
||||
Cell a7 = sh.createRow(7).createCell(1);
|
||||
a7.setCellFormula("SUBTOTAL(4,B2:B7)");
|
||||
Cell a8 = sh.createRow(8).createCell(1);
|
||||
a8.setCellFormula("SUBTOTAL(4,B2,B3,B4,B5,B6,B7,B8)");
|
||||
|
||||
fe.evaluateAll();
|
||||
|
||||
assertEquals(3.0, a3.getNumericCellValue());
|
||||
assertEquals(16.0, a6.getNumericCellValue());
|
||||
assertEquals(7.0, a7.getNumericCellValue());
|
||||
assertEquals(7.0, a8.getNumericCellValue());
|
||||
}
|
||||
|
||||
public void testMin(){
|
||||
|
@ -240,12 +252,15 @@ public final class TestSubtotal extends TestCase {
|
|||
a6.setCellFormula("SUBTOTAL(5,B2:B6)*2 + 2");
|
||||
Cell a7 = sh.createRow(7).createCell(1);
|
||||
a7.setCellFormula("SUBTOTAL(5,B2:B7)");
|
||||
Cell a8 = sh.createRow(8).createCell(1);
|
||||
a8.setCellFormula("SUBTOTAL(5,B2,B3,B4,B5,B6,B7,B8)");
|
||||
|
||||
fe.evaluateAll();
|
||||
|
||||
assertEquals(1.0, a3.getNumericCellValue());
|
||||
assertEquals(4.0, a6.getNumericCellValue());
|
||||
assertEquals(1.0, a7.getNumericCellValue());
|
||||
assertEquals(1.0, a8.getNumericCellValue());
|
||||
}
|
||||
|
||||
public void testStdev(){
|
||||
|
@ -269,12 +284,15 @@ public final class TestSubtotal extends TestCase {
|
|||
a6.setCellFormula("SUBTOTAL(7,B2:B6)*2 + 2");
|
||||
Cell a7 = sh.createRow(7).createCell(1);
|
||||
a7.setCellFormula("SUBTOTAL(7,B2:B7)");
|
||||
Cell a8 = sh.createRow(8).createCell(1);
|
||||
a8.setCellFormula("SUBTOTAL(7,B2,B3,B4,B5,B6,B7,B8)");
|
||||
|
||||
fe.evaluateAll();
|
||||
|
||||
assertEquals(1.41421, a3.getNumericCellValue(), 0.0001);
|
||||
assertEquals(7.65685, a6.getNumericCellValue(), 0.0001);
|
||||
assertEquals(2.82842, a7.getNumericCellValue(), 0.0001);
|
||||
assertEquals(2.82842, a8.getNumericCellValue(), 0.0001);
|
||||
}
|
||||
|
||||
public void test50209(){
|
||||
|
@ -328,4 +346,69 @@ public final class TestSubtotal extends TestCase {
|
|||
confirmExpectedResult(evaluator, "SUBTOTAL(COUNT;B2:B8,C2:C8)", cellC2, 3.0);
|
||||
confirmExpectedResult(evaluator, "SUBTOTAL(COUNTA;B2:B8,C2:C8)", cellC3, 5.0);
|
||||
}
|
||||
|
||||
public void testUnimplemented(){
|
||||
Workbook wb = new HSSFWorkbook();
|
||||
|
||||
FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
|
||||
|
||||
Sheet sh = wb.createSheet();
|
||||
Cell a3 = sh.createRow(3).createCell(1);
|
||||
a3.setCellFormula("SUBTOTAL(8,B2:B3)");
|
||||
|
||||
try {
|
||||
fe.evaluateAll();
|
||||
fail("Should catch an NotImplementedFunctionException here, adjust these tests if it was actually implemented");
|
||||
} catch (NotImplementedException e) {
|
||||
// expected here
|
||||
}
|
||||
|
||||
a3.setCellFormula("SUBTOTAL(10,B2:B3)");
|
||||
|
||||
try {
|
||||
fe.evaluateAll();
|
||||
fail("Should catch an NotImplementedFunctionException here, adjust these tests if it was actually implemented");
|
||||
} catch (NotImplementedException e) {
|
||||
// expected here
|
||||
}
|
||||
|
||||
a3.setCellFormula("SUBTOTAL(11,B2:B3)");
|
||||
|
||||
try {
|
||||
fe.evaluateAll();
|
||||
fail("Should catch an NotImplementedFunctionException here, adjust these tests if it was actually implemented");
|
||||
} catch (NotImplementedException e) {
|
||||
// expected here
|
||||
}
|
||||
|
||||
a3.setCellFormula("SUBTOTAL(107,B2:B3)");
|
||||
|
||||
try {
|
||||
fe.evaluateAll();
|
||||
fail("Should catch an NotImplementedFunctionException here, adjust these tests if it was actually implemented");
|
||||
} catch (NotImplementedException e) {
|
||||
// expected here
|
||||
}
|
||||
|
||||
a3.setCellFormula("SUBTOTAL(0,B2:B3)");
|
||||
fe.evaluateAll();
|
||||
assertEquals(FormulaError.VALUE.getCode(), a3.getErrorCellValue());
|
||||
|
||||
try {
|
||||
a3.setCellFormula("SUBTOTAL(9)");
|
||||
fail("Should catch an exception here");
|
||||
} catch (FormulaParseException e) {
|
||||
// expected here
|
||||
}
|
||||
|
||||
try {
|
||||
a3.setCellFormula("SUBTOTAL()");
|
||||
fail("Should catch an exception here");
|
||||
} catch (FormulaParseException e) {
|
||||
// expected here
|
||||
}
|
||||
|
||||
Subtotal subtotal = new Subtotal();
|
||||
assertEquals(ErrorEval.VALUE_INVALID, subtotal.evaluate(new ValueEval[] {}, 0, 0));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.ss.formula.functions;
|
||||
|
||||
import org.apache.poi.ss.formula.eval.*;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
public class TestWeekdayFunc {
|
||||
@Test
|
||||
public void testEvaluate() throws Exception {
|
||||
assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(1.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(1.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(2.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(0.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(3.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(1.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(11.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(7.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(12.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(6.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(13.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(5.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(14.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(4.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(15.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(3.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(16.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(17.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
|
||||
assertEquals(3.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(3.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(1.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(2.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(1.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(3.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(2.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(11.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(1.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(12.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(7.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(13.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(6.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(14.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(5.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(15.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(4.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(16.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
assertEquals(3.0, ((NumberEval)WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(39448.0), new NumberEval(17.0)}, 0, 0)).getNumberValue(), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateInvalid() throws Exception {
|
||||
assertEquals(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.evaluate(new ValueEval[]{}, 0, 0));
|
||||
assertEquals(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(1.0), new NumberEval(1.0)}, 0, 0));
|
||||
|
||||
assertEquals(ErrorEval.NUM_ERROR, WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(-1.0)}, 0, 0));
|
||||
assertEquals(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.evaluate(new ValueEval[]{new StringEval("")}, 0, 0));
|
||||
assertEquals(ErrorEval.VALUE_INVALID, WeekdayFunc.instance.evaluate(new ValueEval[]{new StringEval("1"), new StringEval("")}, 0, 0));
|
||||
assertEquals(ErrorEval.NUM_ERROR, WeekdayFunc.instance.evaluate(new ValueEval[]{new StringEval("2"), BlankEval.instance}, 0, 0));
|
||||
assertEquals(ErrorEval.NUM_ERROR, WeekdayFunc.instance.evaluate(new ValueEval[]{new StringEval("3"), MissingArgEval.instance}, 0, 0));
|
||||
assertEquals(ErrorEval.NUM_ERROR, WeekdayFunc.instance.evaluate(new ValueEval[]{new NumberEval(1.0), new NumberEval(18.0)}, 0, 0));
|
||||
}
|
||||
}
|
|
@ -33,9 +33,12 @@ import java.awt.font.FontRenderContext;
|
|||
import java.awt.font.TextAttribute;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.AttributedString;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
@ -1606,4 +1609,78 @@ public abstract class BaseTestBugzillaIssues {
|
|||
assertNull("Sheet0 after write", wb2.getPrintArea(0)); // CURRENTLY FAILS with "Sheet0!$A$1:$C$6"
|
||||
assertEquals("Sheet1 after write", "Sheet1!$A$1:$A$1", wb2.getPrintArea(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test55384() throws Exception {
|
||||
Workbook wb = _testDataProvider.createWorkbook();
|
||||
try {
|
||||
Sheet sh = wb.createSheet();
|
||||
for (int rownum = 0; rownum < 10; rownum++) {
|
||||
org.apache.poi.ss.usermodel.Row row = sh.createRow(rownum);
|
||||
for (int cellnum = 0; cellnum < 3; cellnum++) {
|
||||
Cell cell = row.createCell(cellnum);
|
||||
cell.setCellValue(rownum + cellnum);
|
||||
}
|
||||
}
|
||||
Row row = sh.createRow(10);
|
||||
// setting no precalculated value works just fine.
|
||||
Cell cell1 = row.createCell(0);
|
||||
cell1.setCellFormula("SUM(A1:A10)");
|
||||
|
||||
// but setting a precalculated STRING value fails totally in SXSSF
|
||||
Cell cell2 = row.createCell(1);
|
||||
cell2.setCellFormula("SUM(B1:B10)");
|
||||
cell2.setCellValue("55");
|
||||
|
||||
// setting a precalculated int value works as expected
|
||||
Cell cell3 = row.createCell(2);
|
||||
cell3.setCellFormula("SUM(C1:C10)");
|
||||
cell3.setCellValue(65);
|
||||
|
||||
assertEquals(CellType.FORMULA, cell1.getCellTypeEnum());
|
||||
assertEquals(CellType.FORMULA, cell2.getCellTypeEnum());
|
||||
assertEquals(CellType.FORMULA, cell3.getCellTypeEnum());
|
||||
|
||||
assertEquals("SUM(A1:A10)", cell1.getCellFormula());
|
||||
assertEquals("SUM(B1:B10)", cell2.getCellFormula());
|
||||
assertEquals("SUM(C1:C10)", cell3.getCellFormula());
|
||||
|
||||
/*String name = wb.getClass().getCanonicalName();
|
||||
String ext = (wb instanceof HSSFWorkbook) ? ".xls" : ".xlsx";
|
||||
OutputStream output = new FileOutputStream("/tmp" + name + ext);
|
||||
try {
|
||||
wb.write(output);
|
||||
} finally {
|
||||
output.close();
|
||||
}*/
|
||||
|
||||
Workbook wbBack = _testDataProvider.writeOutAndReadBack(wb);
|
||||
checkFormulaPreevaluatedString(wbBack);
|
||||
wbBack.close();
|
||||
} finally {
|
||||
wb.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkFormulaPreevaluatedString(Workbook readFile) {
|
||||
Sheet sheet = readFile.getSheetAt(0);
|
||||
Row row = sheet.getRow(sheet.getLastRowNum());
|
||||
assertEquals(10, row.getRowNum());
|
||||
|
||||
for (Cell cell : row) {
|
||||
String cellValue = null;
|
||||
switch (cell.getCellTypeEnum()) {
|
||||
case STRING:
|
||||
cellValue = cell.getRichStringCellValue().getString();
|
||||
break;
|
||||
case FORMULA:
|
||||
cellValue = cell.getCellFormula();
|
||||
break;
|
||||
}
|
||||
assertNotNull(cellValue);
|
||||
cellValue = cellValue.isEmpty() ? null : cellValue;
|
||||
assertNotNull(cellValue);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -201,11 +201,7 @@ public abstract class BaseTestNamedRange {
|
|||
assertEquals("The sheet already contains this name: aaa", e.getMessage());
|
||||
}
|
||||
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < wb.getNumberOfNames(); i++) {
|
||||
if("aaa".equals(wb.getNameAt(i).getNameName())) cnt++;
|
||||
}
|
||||
assertEquals(3, cnt);
|
||||
assertEquals(3, wb.getNames("aaa").size());
|
||||
|
||||
wb.close();
|
||||
}
|
||||
|
@ -250,11 +246,11 @@ public abstract class BaseTestNamedRange {
|
|||
// Write the workbook to a file
|
||||
// Read the Excel file and verify its content
|
||||
Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1);
|
||||
Name nm1 = wb2.getNameAt(wb2.getNameIndex("RangeTest1"));
|
||||
Name nm1 = wb2.getName("RangeTest1");
|
||||
assertTrue("Name is "+nm1.getNameName(),"RangeTest1".equals(nm1.getNameName()));
|
||||
assertTrue("Reference is "+nm1.getRefersToFormula(),(wb2.getSheetName(0)+"!$A$1:$L$41").equals(nm1.getRefersToFormula()));
|
||||
|
||||
Name nm2 = wb2.getNameAt(wb2.getNameIndex("RangeTest2"));
|
||||
Name nm2 = wb2.getName("RangeTest2");
|
||||
assertTrue("Name is "+nm2.getNameName(),"RangeTest2".equals(nm2.getNameName()));
|
||||
assertTrue("Reference is "+nm2.getRefersToFormula(),(wb2.getSheetName(1)+"!$A$1:$O$21").equals(nm2.getRefersToFormula()));
|
||||
|
||||
|
@ -466,11 +462,11 @@ public abstract class BaseTestNamedRange {
|
|||
wb1.getNameAt(0);
|
||||
|
||||
Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1);
|
||||
Name nm =wb2.getNameAt(wb2.getNameIndex("RangeTest"));
|
||||
Name nm =wb2.getName("RangeTest");
|
||||
assertTrue("Name is "+nm.getNameName(),"RangeTest".equals(nm.getNameName()));
|
||||
assertTrue("Reference is "+nm.getRefersToFormula(),(wb2.getSheetName(0)+"!$D$4:$E$8").equals(nm.getRefersToFormula()));
|
||||
|
||||
nm = wb2.getNameAt(wb2.getNameIndex("AnotherTest"));
|
||||
nm = wb2.getName("AnotherTest");
|
||||
assertTrue("Name is "+nm.getNameName(),"AnotherTest".equals(nm.getNameName()));
|
||||
assertTrue("Reference is "+nm.getRefersToFormula(),newNamedRange2.getRefersToFormula().equals(nm.getRefersToFormula()));
|
||||
|
||||
|
@ -499,8 +495,7 @@ public abstract class BaseTestNamedRange {
|
|||
namedCell.setRefersToFormula(reference);
|
||||
|
||||
// retrieve the newly created named range
|
||||
int namedCellIdx = wb.getNameIndex(cellName);
|
||||
Name aNamedCell = wb.getNameAt(namedCellIdx);
|
||||
Name aNamedCell = wb.getName(cellName);
|
||||
assertNotNull(aNamedCell);
|
||||
|
||||
// retrieve the cell at the named range and test its contents
|
||||
|
@ -540,8 +535,7 @@ public abstract class BaseTestNamedRange {
|
|||
namedCell.setRefersToFormula(reference);
|
||||
|
||||
// retrieve the newly created named range
|
||||
int namedCellIdx = wb.getNameIndex(cname);
|
||||
Name aNamedCell = wb.getNameAt(namedCellIdx);
|
||||
Name aNamedCell = wb.getName(cname);
|
||||
assertNotNull(aNamedCell);
|
||||
|
||||
// retrieve the cell at the named range and test its contents
|
||||
|
|
|
@ -261,17 +261,17 @@ public abstract class BaseTestSheetShiftRows {
|
|||
name4.setSheetIndex(1);
|
||||
|
||||
sheet1.shiftRows(0, 1, 2); //shift down the top row on Sheet1.
|
||||
name1 = wb.getNameAt(0);
|
||||
name1 = wb.getName("name1");
|
||||
assertEquals("Sheet1!$A$3+Sheet1!$B$3", name1.getRefersToFormula());
|
||||
|
||||
name2 = wb.getNameAt(1);
|
||||
name2 = wb.getName("name2");
|
||||
assertEquals("Sheet1!$A$3", name2.getRefersToFormula());
|
||||
|
||||
//name3 and name4 refer to Sheet2 and should not be affected
|
||||
name3 = wb.getNameAt(2);
|
||||
name3 = wb.getName("name3");
|
||||
assertEquals("Sheet2!$A$1", name3.getRefersToFormula());
|
||||
|
||||
name4 = wb.getNameAt(3);
|
||||
name4 = wb.getName("name4");
|
||||
assertEquals("A1", name4.getRefersToFormula());
|
||||
|
||||
wb.close();
|
||||
|
|
|
@ -78,14 +78,16 @@ public class BaseTestCellUtil {
|
|||
@Test(expected=RuntimeException.class)
|
||||
public void setCellStylePropertyWithInvalidValue() throws IOException {
|
||||
Workbook wb = _testDataProvider.createWorkbook();
|
||||
Sheet s = wb.createSheet();
|
||||
Row r = s.createRow(0);
|
||||
Cell c = r.createCell(0);
|
||||
try {
|
||||
Sheet s = wb.createSheet();
|
||||
Row r = s.createRow(0);
|
||||
Cell c = r.createCell(0);
|
||||
|
||||
// An invalid BorderStyle constant
|
||||
CellUtil.setCellStyleProperty(c, CellUtil.BORDER_BOTTOM, 42);
|
||||
|
||||
wb.close();
|
||||
// An invalid BorderStyle constant
|
||||
CellUtil.setCellStyleProperty(c, CellUtil.BORDER_BOTTOM, 42);
|
||||
} finally {
|
||||
wb.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test()
|
||||
|
@ -352,10 +354,8 @@ public class BaseTestCellUtil {
|
|||
CellUtil.setFont(A1, font2);
|
||||
fail("setFont not allowed if font belongs to a different workbook");
|
||||
} catch (final IllegalArgumentException e) {
|
||||
if (e.getMessage().startsWith("Font does not belong to this workbook")) {
|
||||
// expected
|
||||
}
|
||||
else {
|
||||
// one specific message is expected
|
||||
if (!e.getMessage().startsWith("Font does not belong to this workbook")) {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
|
@ -371,7 +371,7 @@ public class BaseTestCellUtil {
|
|||
*/
|
||||
// bug 55555
|
||||
@Test
|
||||
public void setFillForegroundColorBeforeFillBackgroundColor() {
|
||||
public void setFillForegroundColorBeforeFillBackgroundColor() throws IOException {
|
||||
Workbook wb1 = _testDataProvider.createWorkbook();
|
||||
Cell A1 = wb1.createSheet().createRow(0).createCell(0);
|
||||
Map<String, Object> properties = new HashMap<String, Object>();
|
||||
|
@ -386,13 +386,14 @@ public class BaseTestCellUtil {
|
|||
assertEquals("fill pattern", CellStyle.BRICKS, style.getFillPattern());
|
||||
assertEquals("fill foreground color", IndexedColors.BLUE, IndexedColors.fromInt(style.getFillForegroundColor()));
|
||||
assertEquals("fill background color", IndexedColors.RED, IndexedColors.fromInt(style.getFillBackgroundColor()));
|
||||
wb1.close();
|
||||
}
|
||||
/**
|
||||
* bug 55555
|
||||
* @since POI 3.15 beta 3
|
||||
*/
|
||||
@Test
|
||||
public void setFillForegroundColorBeforeFillBackgroundColorEnum() {
|
||||
public void setFillForegroundColorBeforeFillBackgroundColorEnum() throws IOException {
|
||||
Workbook wb1 = _testDataProvider.createWorkbook();
|
||||
Cell A1 = wb1.createSheet().createRow(0).createCell(0);
|
||||
Map<String, Object> properties = new HashMap<String, Object>();
|
||||
|
@ -407,5 +408,7 @@ public class BaseTestCellUtil {
|
|||
assertEquals("fill pattern", FillPatternType.BRICKS, style.getFillPatternEnum());
|
||||
assertEquals("fill foreground color", IndexedColors.BLUE, IndexedColors.fromInt(style.getFillForegroundColor()));
|
||||
assertEquals("fill background color", IndexedColors.RED, IndexedColors.fromInt(style.getFillBackgroundColor()));
|
||||
|
||||
wb1.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,16 +30,20 @@ public class DummyPOILogger extends POILogger {
|
|||
logged = new ArrayList<String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(int level) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(String cat) {}
|
||||
|
||||
@Override
|
||||
public void log(int level, Object obj1) {
|
||||
logged.add(level + " - " + obj1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(int level, Object obj1, Throwable exception) {
|
||||
logged.add(level + " - " + obj1 + " - " + exception);
|
||||
}
|
||||
|
|
|
@ -26,10 +26,6 @@ import org.junit.Test;
|
|||
|
||||
/**
|
||||
* Tests the log class.
|
||||
*
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
* @author Marc Johnson (mjohnson at apache dot org)
|
||||
* @author Nicola Ken Barozzi (nicolaken at apache.org)
|
||||
*/
|
||||
public final class TestPOILogger extends POILogger {
|
||||
private String lastLog = "";
|
||||
|
@ -61,20 +57,26 @@ public final class TestPOILogger extends POILogger {
|
|||
POILogFactory._loggerClassName = oldLCN;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- POI Logger methods implemented for testing ----------
|
||||
|
||||
@Override
|
||||
public void initialize(String cat) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(int level, Object obj1) {
|
||||
lastLog = (obj1 == null) ? "" : obj1.toString();
|
||||
lastEx = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(int level, Object obj1, Throwable exception) {
|
||||
lastLog = (obj1 == null) ? "" : obj1.toString();
|
||||
lastEx = exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(int level) {
|
||||
return true;
|
||||
}
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue