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:
Andreas Beeker 2016-08-08 01:14:36 +00:00
parent 0bfefdfc04
commit 680683cf77
51 changed files with 1967 additions and 1249 deletions

View File

@ -17,7 +17,6 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations specific language governing permissions and limitations
under the License. under the License.
--> -->
<!-- <!--
This build was tested with ant 1.9.4 although it will probably work with 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. 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.output.test.dir" location="build/ooxml-test-classes"/>
<property name="ooxml.testokfile" location="build/ooxml-testokfile.txt"/> <property name="ooxml.testokfile" location="build/ooxml-testokfile.txt"/>
<property name="ooxml.lite.output.dir" location="build/ooxml-lite-classes"/> <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: --> <!-- XSSF/SXSSF subset of OOXML: -->
<property name="ooxml.ss.testokfile" location="build/ooxml-ss-testokfile.txt"/> <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.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.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.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 --> <!-- xml signature libs -->
<property name="dsig.xmlsec.jar" location="${compile.lib}/xmlsec-2.0.6.jar"/> <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"/> value="${repository.m2}/maven2/org/apache/xmlbeans/xmlbeans/2.6.0/xmlbeans-2.6.0.jar"/>
<!-- coverage libs --> <!-- coverage libs -->
<property name="jacoco.zip" location="${main.lib}/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.6.201602180812/jacoco-0.7.6.201602180812.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.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"/> <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> </condition>
<property name="findbugs.version" value="2.0.3" if:set="findbugs.jdk6"/> <property name="findbugs.version" value="2.0.3" if:set="findbugs.jdk6"/>
<property name="findbugs.version" value="3.0.1" unless: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.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"/> <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 --> <!-- this can be overwriten to empty when running with Java 9 -->
<property name="maxpermsize" value="-XX:MaxPermSize=256m"/> <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"> <path id="main.classpath">
<pathelement location="${main.commons-logging.jar}"/> <pathelement location="${main.commons-logging.jar}"/>
@ -310,6 +316,7 @@ under the License.
<pathelement location="${main.log4j.jar}"/> <pathelement location="${main.log4j.jar}"/>
<pathelement location="${main.junit.jar}"/> <pathelement location="${main.junit.jar}"/>
<pathelement location="${main.hamcrest.jar}"/> <pathelement location="${main.hamcrest.jar}"/>
<pathelement location="${main.commons-collections4.jar}"/>
</path> </path>
<path id="scratchpad.classpath"> <path id="scratchpad.classpath">
@ -498,9 +505,7 @@ under the License.
<attribute name="src"/> <attribute name="src"/>
<attribute name="dest"/> <attribute name="dest"/>
<sequential> <sequential>
<local name="exists"/> <!--fail
<available file="@{dest}" property="exists"/>
<!--fail unless:true="${exists}"
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"> 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> <condition>
<and> <and>
@ -509,7 +514,7 @@ under the License.
</and> </and>
</condition> </condition>
</fail--> </fail-->
<get src="@{src}" dest="@{dest}" unless:true="${exists}"/> <get src="@{src}" dest="@{dest}" skipexisting="true"/>
</sequential> </sequential>
</macrodef> </macrodef>
@ -531,12 +536,14 @@ under the License.
<include name="jacoco-0.7.2*"/> <include name="jacoco-0.7.2*"/>
<include name="jacoco-0.7.3*"/> <include name="jacoco-0.7.3*"/>
<include name="jacoco-0.7.4*"/> <include name="jacoco-0.7.4*"/>
<include name="jacoco-0.7.6*"/>
<include name="log4j-1.2.13*"/> <include name="log4j-1.2.13*"/>
<include name="org.jacoco.*-0.6.*"/> <include name="org.jacoco.*-0.6.*"/>
<include name="org.jacoco.*-0.7.1*"/> <include name="org.jacoco.*-0.7.1*"/>
<include name="org.jacoco.*-0.7.2*"/> <include name="org.jacoco.*-0.7.2*"/>
<include name="org.jacoco.*-0.7.3*"/> <include name="org.jacoco.*-0.7.3*"/>
<include name="org.jacoco.*-0.7.4*"/> <include name="org.jacoco.*-0.7.4*"/>
<include name="org.jacoco.*-0.7.6*"/>
<include name="dom4j*"/> <include name="dom4j*"/>
<include name="apache-rat-0.10*"/> <include name="apache-rat-0.10*"/>
<include name="xercesImpl-*.jar"/> <include name="xercesImpl-*.jar"/>
@ -587,6 +594,7 @@ under the License.
<available file="${dsig.bouncycastle-pkix.jar}"/> <available file="${dsig.bouncycastle-pkix.jar}"/>
<available file="${dsig.xmlsec.jar}"/> <available file="${dsig.xmlsec.jar}"/>
<available file="${dsig.sl4j-api.jar}"/> <available file="${dsig.sl4j-api.jar}"/>
<available file="${main.commons-collections4.jar}"/>
</and> </and>
<isset property="disconnected"/> <isset property="disconnected"/>
</or> </or>
@ -605,6 +613,7 @@ under the License.
<downloadfile src="${main.antlauncher.url}" dest="${main.antlauncher.jar}"/> <downloadfile src="${main.antlauncher.url}" dest="${main.antlauncher.jar}"/>
<downloadfile src="${asm.url}" dest="${asm.jar}"/> <downloadfile src="${asm.url}" dest="${asm.jar}"/>
<downloadfile src="${jacoco.url}" dest="${jacoco.zip}"/> <downloadfile src="${jacoco.url}" dest="${jacoco.zip}"/>
<downloadfile src="${main.commons-collections4.url}" dest="${main.commons-collections4.jar}"/>
<unzip src="${jacoco.zip}" dest="."> <unzip src="${jacoco.zip}" dest=".">
<patternset> <patternset>
<include name="lib/*.jar"/> <include name="lib/*.jar"/>
@ -1161,6 +1170,8 @@ under the License.
<group name="Main"> <group name="Main">
<classfiles> <classfiles>
<fileset dir="${main.output.dir}"> <fileset dir="${main.output.dir}">
<!-- exclude some generated classes -->
<exclude name="org/apache/poi/sl/draw/binding/*.class"/>
<!-- exclude large test-class --> <!-- exclude large test-class -->
<exclude name="org/apache/poi/hssf/usermodel/DummyGraphics2d.class"/> <exclude name="org/apache/poi/hssf/usermodel/DummyGraphics2d.class"/>
</fileset> </fileset>
@ -1242,6 +1253,8 @@ under the License.
<jvmarg value="-ea"/> <jvmarg value="-ea"/>
<jvmarg value="-Xmx256m"/> <jvmarg value="-Xmx256m"/>
<!-- jvmarg value="-Duser.timezone=UTC"/ --> <!-- jvmarg value="-Duser.timezone=UTC"/ -->
<jvmarg value="${java9addmods}" />
<jvmarg value="${java9addmodsvalue}" />
<formatter type="plain"/> <formatter type="plain"/>
<formatter type="xml"/> <formatter type="xml"/>
<batchtest todir="${main.reports.test}"> <batchtest todir="${main.reports.test}">
@ -1258,6 +1271,16 @@ under the License.
<antcall target="-test-main-write-testfile"/> <antcall target="-test-main-write-testfile"/>
</target> </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"> <target name="-test-property-check" unless="testcase">
<echo message="Please use -Dtestcase=org.your.testcase to run a single test"/> <echo message="Please use -Dtestcase=org.your.testcase to run a single test"/>
<fail/> <fail/>
@ -1288,6 +1311,8 @@ under the License.
<jvmarg value="-ea"/> <jvmarg value="-ea"/>
<jvmarg value="-Xmx256m"/> <jvmarg value="-Xmx256m"/>
<!-- jvmarg value="-Duser.timezone=UTC"/ --> <!-- jvmarg value="-Duser.timezone=UTC"/ -->
<jvmarg value="${java9addmods}" />
<jvmarg value="${java9addmodsvalue}" />
<formatter type="plain"/> <formatter type="plain"/>
<formatter type="xml"/> <formatter type="xml"/>
<batchtest todir="${main.reports.test}"> <batchtest todir="${main.reports.test}">
@ -1335,6 +1360,8 @@ under the License.
and on Windows with jdk-1.5.22 and on Windows with jdk-1.5.22
--> -->
<jvmarg value="-Xmx256M"/> <jvmarg value="-Xmx256M"/>
<jvmarg value="${java9addmods}" />
<jvmarg value="${java9addmodsvalue}" />
<formatter type="plain"/> <formatter type="plain"/>
<formatter type="xml"/> <formatter type="xml"/>
<batchtest todir="${scratchpad.reports.test}"> <batchtest todir="${scratchpad.reports.test}">
@ -1373,6 +1400,8 @@ under the License.
<jvmarg value="${maxpermsize}"/> <jvmarg value="${maxpermsize}"/>
<jvmarg value="-Xmx768M"/> <jvmarg value="-Xmx768M"/>
<jvmarg value="-ea"/> <jvmarg value="-ea"/>
<jvmarg value="${java9addmods}" />
<jvmarg value="${java9addmodsvalue}" />
<!-- jvmarg value="-Duser.timezone=UTC"/ --> <!-- jvmarg value="-Duser.timezone=UTC"/ -->
<formatter type="plain"/> <formatter type="plain"/>
<formatter type="xml"/> <formatter type="xml"/>
@ -1396,6 +1425,8 @@ under the License.
<syspropertyset refid="junit.properties"/> <syspropertyset refid="junit.properties"/>
<jvmarg value="-Xmx768M"/> <jvmarg value="-Xmx768M"/>
<jvmarg value="-ea"/> <jvmarg value="-ea"/>
<jvmarg value="${java9addmods}" />
<jvmarg value="${java9addmodsvalue}" />
<formatter type="plain"/> <formatter type="plain"/>
<formatter type="xml"/> <formatter type="xml"/>
<batchtest todir="${ooxml.reports.test}"> <batchtest todir="${ooxml.reports.test}">
@ -1439,6 +1470,8 @@ under the License.
<jvmarg value="${maxpermsize}"/> <jvmarg value="${maxpermsize}"/>
<jvmarg value="-Xmx768M"/> <jvmarg value="-Xmx768M"/>
<jvmarg value="-ea"/> <jvmarg value="-ea"/>
<jvmarg value="${java9addmods}" />
<jvmarg value="${java9addmodsvalue}" />
<!-- jvmarg value="-Duser.timezone=UTC"/ --> <!-- jvmarg value="-Duser.timezone=UTC"/ -->
<formatter type="plain"/> <formatter type="plain"/>
<formatter type="xml"/> <formatter type="xml"/>
@ -1485,6 +1518,8 @@ under the License.
<syspropertyset refid="junit.properties"/> <syspropertyset refid="junit.properties"/>
<jvmarg value="-ea"/> <jvmarg value="-ea"/>
<jvmarg value="-Xmx1512M"/> <jvmarg value="-Xmx1512M"/>
<jvmarg value="${java9addmods}" />
<jvmarg value="${java9addmodsvalue}" />
<formatter type="plain"/> <formatter type="plain"/>
<formatter type="xml"/> <formatter type="xml"/>
<batchtest todir="${integration.reports.test}"> <batchtest todir="${integration.reports.test}">
@ -1503,7 +1538,20 @@ under the License.
</target> </target>
<!-- Section: test-ooxml-lite --> <!-- 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"/> <property name="ooxml.lite-merged.dir" location="build/ooxml-lite-merged"/>
<mkdir dir="${ooxml.lite-merged.dir}"/> <mkdir dir="${ooxml.lite-merged.dir}"/>
@ -1522,6 +1570,8 @@ under the License.
<syspropertyset refid="junit.properties"/> <syspropertyset refid="junit.properties"/>
<jvmarg value="${maxpermsize}"/> <jvmarg value="${maxpermsize}"/>
<jvmarg value="-Xmx512m"/> <jvmarg value="-Xmx512m"/>
<jvmarg value="${java9addmods}" />
<jvmarg value="${java9addmodsvalue}" />
<arg value="-ooxml"/> <arg value="-ooxml"/>
<arg value="${ooxml.lite-merged.dir}/ooxml-lite-merged.jar"/> <arg value="${ooxml.lite-merged.dir}/ooxml-lite-merged.jar"/>
<arg value="-test"/> <arg value="-test"/>
@ -1529,6 +1579,8 @@ under the License.
<arg value="-dest"/> <arg value="-dest"/>
<arg value="${ooxml.lite.output.dir}"/> <arg value="${ooxml.lite.output.dir}"/>
</java> </java>
<echo file="${ooxml.lite.testokfile}" append="false" message="testok"/>
</target> </target>
<target name="test-ooxml-lite" depends="jacocotask,compile-ooxml-xsds,compile-ooxml-lite"> <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"/> <classpath refid="test.excelant.classpath"/>
<syspropertyset refid="junit.properties"/> <syspropertyset refid="junit.properties"/>
<jvmarg value="-ea"/> <jvmarg value="-ea"/>
<jvmarg value="${java9addmods}" />
<jvmarg value="${java9addmodsvalue}" />
<formatter type="plain"/> <formatter type="plain"/>
<formatter type="xml"/> <formatter type="xml"/>
<batchtest todir="${excelant.reports.test}"> <batchtest todir="${excelant.reports.test}">
@ -1868,6 +1922,7 @@ under the License.
<fileset dir="${main.lib}"> <fileset dir="${main.lib}">
<include name="commons-codec-*.jar"/> <include name="commons-codec-*.jar"/>
<include name="commons-logging-*.jar"/> <include name="commons-logging-*.jar"/>
<include name="commons-collections4-*.jar"/>
<include name="junit-*.jar"/> <include name="junit-*.jar"/>
<include name="log4j-*.jar"/> <include name="log4j-*.jar"/>
</fileset> </fileset>
@ -2083,7 +2138,7 @@ under the License.
</forbiddenapis> </forbiddenapis>
</target> </target>
<target name="findbugs" depends="assemble"> <target name="findbugs" depends="jar">
<downloadfile src="${findbugs.url}" dest="${findbugs.jar}"/> <downloadfile src="${findbugs.url}" dest="${findbugs.jar}"/>
<property name="findbugs.home" value="build/findbugs" /> <property name="findbugs.home" value="build/findbugs" />
@ -2103,11 +2158,13 @@ under the License.
output="xml:withMessages" output="xml:withMessages"
outputFile="build/findbugs.xml" outputFile="build/findbugs.xml"
effort="max" effort="max"
failOnError="true"
excludeFilter="src/resources/devtools/findbugs-filters.xml"> excludeFilter="src/resources/devtools/findbugs-filters.xml">
<fileset dir="${dist.dir}/maven"> <fileset dir="${dist.dir}/maven">
<include name="poi/poi-${version.id}.jar"/> <include name="poi/poi-${version.id}.jar"/>
<include name="poi-scratchpad/poi-scratchpad-${version.id}.jar"/> <include name="poi-scratchpad/poi-scratchpad-${version.id}.jar"/>
<include name="poi-ooxml/poi-ooxml-${version.id}.jar"/> <include name="poi-ooxml/poi-ooxml-${version.id}.jar"/>
<include name="poi-excelant/poi-excelant-${version.id}.jar"/>
</fileset> </fileset>
<auxClasspath path="${dsig.bouncycastle-pkix.jar}" /> <auxClasspath path="${dsig.bouncycastle-pkix.jar}" />
<auxClasspath path="${dsig.bouncycastle-prov.jar}" /> <auxClasspath path="${dsig.bouncycastle-prov.jar}" />
@ -2117,9 +2174,11 @@ under the License.
<auxClasspath path="${ooxml.security.jar}" /> <auxClasspath path="${ooxml.security.jar}" />
<auxClasspath path="${ooxml.curvesapi.jar}" /> <auxClasspath path="${ooxml.curvesapi.jar}" />
<auxClasspath path="${ooxml.xmlbeans26.jar}" /> <auxClasspath path="${ooxml.xmlbeans26.jar}" />
<auxClasspath path="${main.commons-collections4.jar}" />
<auxClasspath path="${main.commons-codec.jar}" /> <auxClasspath path="${main.commons-codec.jar}" />
<auxClasspath path="${main.commons-logging.jar}" /> <auxClasspath path="${main.commons-logging.jar}" />
<auxClasspath path="${main.junit.jar}" /> <auxClasspath path="${main.junit.jar}" />
<auxClasspath path="${main.ant.jar}" />
<sourcePath path="src/java" /> <sourcePath path="src/java" />
<sourcePath path="src/ooxml/java" /> <sourcePath path="src/ooxml/java" />
<sourcePath path="src/scratchpad/src" /> <sourcePath path="src/scratchpad/src" />

View File

@ -91,6 +91,11 @@
<scope>test</scope> <scope>test</scope>
<version>4.12</version> <version>4.12</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -110,6 +110,11 @@
</build> </build>
<dependencies> <dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
<dependency> <dependency>
<groupId>commons-codec</groupId> <groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId> <artifactId>commons-codec</artifactId>

View File

@ -194,7 +194,7 @@ public final class RowRecordsAggregate extends RecordAggregate {
private int getStartRowNumberForBlock(int block) { private int getStartRowNumberForBlock(int block) {
int startIndex = block * DBCellRecord.BLOCK_SIZE; int startIndex = block * DBCellRecord.BLOCK_SIZE;
if(_rowRecordValues == null){ if (_rowRecordValues == null) {
_rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]); _rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]);
} }
@ -211,7 +211,7 @@ public final class RowRecordsAggregate extends RecordAggregate {
if (endIndex >= _rowRecords.size()) if (endIndex >= _rowRecords.size())
endIndex = _rowRecords.size()-1; endIndex = _rowRecords.size()-1;
if(_rowRecordValues == null){ if (_rowRecordValues == null){
_rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]); _rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]);
} }

View File

@ -19,10 +19,10 @@ package org.apache.poi.hssf.usermodel;
import java.util.Map; import java.util.Map;
import org.apache.poi.ss.formula.BaseFormulaEvaluator;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment; import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment;
import org.apache.poi.ss.formula.IStabilityClassifier; import org.apache.poi.ss.formula.IStabilityClassifier;
import org.apache.poi.ss.formula.WorkbookEvaluator; 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.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.NumericValueEval; 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.CellType;
import org.apache.poi.ss.usermodel.CellValue; import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.FormulaEvaluator; 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.ss.usermodel.Workbook;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
@ -45,9 +43,7 @@ import org.apache.poi.util.Internal;
* cell values. Be sure to call {@link #clearAllCachedResultValues()} if any workbook cells are changed between * cell values. Be sure to call {@link #clearAllCachedResultValues()} if any workbook cells are changed between
* calls to evaluate~ methods on this class. * calls to evaluate~ methods on this class.
*/ */
public class HSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluatorProvider { public class HSSFFormulaEvaluator extends BaseFormulaEvaluator {
private final WorkbookEvaluator _bookEvaluator;
private final HSSFWorkbook _book; private final HSSFWorkbook _book;
public HSSFFormulaEvaluator(HSSFWorkbook workbook) { public HSSFFormulaEvaluator(HSSFWorkbook workbook) {
@ -71,8 +67,8 @@ public class HSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluator
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only) * @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
*/ */
private HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) { private HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
super(new WorkbookEvaluator(HSSFEvaluationWorkbook.create(workbook), stabilityClassifier, udfFinder));
_book = workbook; _book = workbook;
_bookEvaluator = new WorkbookEvaluator(HSSFEvaluationWorkbook.create(workbook), stabilityClassifier, udfFinder);
} }
/** /**
@ -95,11 +91,7 @@ public class HSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluator
* @param evaluators all evaluators for the full set of workbooks required by the formulas. * @param evaluators all evaluators for the full set of workbooks required by the formulas.
*/ */
public static void setupEnvironment(String[] workbookNames, HSSFFormulaEvaluator[] evaluators) { public static void setupEnvironment(String[] workbookNames, HSSFFormulaEvaluator[] evaluators) {
WorkbookEvaluator[] wbEvals = new WorkbookEvaluator[evaluators.length]; BaseFormulaEvaluator.setupEnvironment(workbookNames, evaluators);
for (int i = 0; i < wbEvals.length; i++) {
wbEvals[i] = evaluators[i]._bookEvaluator;
}
CollaboratingWorkbooksEnvironment.setup(workbookNames, wbEvals);
} }
@Override @Override
@ -107,23 +99,6 @@ public class HSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluator
CollaboratingWorkbooksEnvironment.setupFormulaEvaluator(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();
}
/** /**
* Should be called to tell the cell value cache that the specified (value or formula) cell * Should be called to tell the cell value cache that the specified (value or formula) cell
* has changed. * has changed.
@ -162,62 +137,6 @@ public class HSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluator
_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;
}
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. 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 * 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 * cell remains as a formula cell. If the cell does not contain formula, rather than throwing an
@ -275,24 +194,6 @@ public class HSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluator
} }
return result; 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 + ")");
}
}
private static void setCellValue(Cell cell, CellValue cv) { private static void setCellValue(Cell cell, CellValue cv) {
CellType cellType = cv.getCellType(); CellType cellType = cv.getCellType();
@ -345,21 +246,7 @@ public class HSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluator
* cells, and calling evaluateFormulaCell on each one. * cells, and calling evaluateFormulaCell on each one.
*/ */
public static void evaluateAllFormulaCells(Workbook wb) { public static void evaluateAllFormulaCells(Workbook wb) {
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator(); BaseFormulaEvaluator.evaluateAllFormulaCells(wb);
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);
}
}
}
}
} }
/** /**
@ -374,7 +261,7 @@ public class HSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluator
* cells, and calling evaluateFormulaCell on each one. * cells, and calling evaluateFormulaCell on each one.
*/ */
@Override @Override
public void evaluateAll() { public void evaluateAll() {
evaluateAllFormulaCells(_book, this); evaluateAllFormulaCells(_book, this);
} }
@ -382,7 +269,7 @@ public void evaluateAll() {
* Returns a CellValue wrapper around the supplied ValueEval instance. * Returns a CellValue wrapper around the supplied ValueEval instance.
* @param cell * @param cell
*/ */
private CellValue evaluateFormulaCellValue(Cell cell) { protected CellValue evaluateFormulaCellValue(Cell cell) {
ValueEval eval = _bookEvaluator.evaluate(new HSSFEvaluationCell((HSSFCell)cell)); ValueEval eval = _bookEvaluator.evaluate(new HSSFEvaluationCell((HSSFCell)cell));
if (eval instanceof BoolEval) { if (eval instanceof BoolEval) {
BoolEval be = (BoolEval) eval; BoolEval be = (BoolEval) eval;

View File

@ -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.AggregatingUDFFinder;
import org.apache.poi.ss.formula.udf.IndexedUDFFinder; import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder; 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.Row.MissingCellPolicy;
import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook; 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). * the 'active' sheet (which is the sheet with focus).
* Unselects sheets that are not in <code>indexes</code>. * 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) { public void setSelectedTabs(int[] indexes) {
Collection<Integer> list = new ArrayList<Integer>(indexes.length); 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). * the 'active' sheet (which is the sheet with focus).
* Unselects sheets that are not in <code>indexes</code>. * 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) { public void setSelectedTabs(Collection<Integer> indexes) {
@ -893,8 +894,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
*/ */
@Override @Override
public Iterator<Sheet> sheetIterator() { public Iterator<Sheet> sheetIterator() {
Iterator<Sheet> result = new SheetIterator<Sheet>(); return new SheetIterator<Sheet>();
return result;
} }
/** /**
@ -1280,9 +1280,9 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
/** /**
* Closes the underlying {@link NPOIFSFileSystem} from which * Closes the underlying {@link NPOIFSFileSystem} from which
* the Workbook was read, if any. Has no effect on Workbooks * the Workbook was read, if any.
* opened from an InputStream, or newly created ones. *
* <p>Once {@link #close()} has been called, no further * <p>Once this has been called, no further
* operations, updates or reads should be performed on the * operations, updates or reads should be performed on the
* Workbook. * Workbook.
*/ */
@ -1531,6 +1531,11 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
return names.get(nameIndex); return names.get(nameIndex);
} }
@Override
public List<HSSFName> getAllNames() {
return Collections.unmodifiableList(names);
}
public NameRecord getNameRecord(int nameIndex) { public NameRecord getNameRecord(int nameIndex) {
return getWorkbook().getNameRecord(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. * @param name the name to remove.
*/ */
void removeName(HSSFName name) { @Override
int index = getNameIndex(name); public void removeName(Name name) {
int index = getNameIndex((HSSFName) name);
removeName(index); removeName(index);
} }

View File

@ -374,6 +374,7 @@ public class CryptoFunctions {
// SET Verifier TO 0x0000 // SET Verifier TO 0x0000
short verifier = 0; short verifier = 0;
if (!"".equals(password)) {
// FOR EACH PasswordByte IN PasswordArray IN REVERSE ORDER // FOR EACH PasswordByte IN PasswordArray IN REVERSE ORDER
for (int i = arrByteChars.length-1; i >= 0; i--) { for (int i = arrByteChars.length-1; i >= 0; i--) {
// SET Verifier TO Intermediate3 BITWISE XOR PasswordByte // SET Verifier TO Intermediate3 BITWISE XOR PasswordByte
@ -388,6 +389,7 @@ public class CryptoFunctions {
// RETURN Verifier BITWISE XOR 0xCE4B // RETURN Verifier BITWISE XOR 0xCE4B
verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K') verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K')
}
return verifier & 0xFFFF; return verifier & 0xFFFF;
} }

View File

@ -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);
}
}

View File

@ -27,7 +27,7 @@ import org.apache.poi.ss.util.CellReference;
/** /**
* Provides Lazy Evaluation to a 3D Reference * Provides Lazy Evaluation to a 3D Reference
*/ */
final class LazyRefEval extends RefEvalBase { public final class LazyRefEval extends RefEvalBase {
private final SheetRangeEvaluator _evaluator; private final SheetRangeEvaluator _evaluator;
public LazyRefEval(int rowIndex, int columnIndex, SheetRangeEvaluator sre) { public LazyRefEval(int rowIndex, int columnIndex, SheetRangeEvaluator sre) {
@ -47,14 +47,17 @@ final class LazyRefEval extends RefEvalBase {
return new LazyAreaEval(area, _evaluator); return new LazyAreaEval(area, _evaluator);
} }
public boolean isSubTotal() {
SheetRefEvaluator sheetEvaluator = _evaluator.getSheetEvaluator(getFirstSheetIndex());
return sheetEvaluator.isSubTotal(getRow(), getColumn());
}
public String toString() { public String toString() {
CellReference cr = new CellReference(getRow(), getColumn()); CellReference cr = new CellReference(getRow(), getColumn());
StringBuffer sb = new StringBuffer(); return getClass().getName() + "[" +
sb.append(getClass().getName()).append("["); _evaluator.getSheetNameRange() +
sb.append(_evaluator.getSheetNameRange()); '!' +
sb.append('!'); cr.formatAsString() +
sb.append(cr.formatAsString()); "]";
sb.append("]");
return sb.toString();
} }
} }

View File

@ -19,6 +19,7 @@ package org.apache.poi.ss.formula.functions;
import static org.apache.poi.ss.formula.functions.AggregateFunction.subtotalInstance; 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.ErrorEval;
import org.apache.poi.ss.formula.eval.EvaluationException; import org.apache.poi.ss.formula.eval.EvaluationException;
import org.apache.poi.ss.formula.eval.NotImplementedException; 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.OperandResolver;
import org.apache.poi.ss.formula.eval.ValueEval; 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> * Implementation for the Excel function SUBTOTAL<p>
* *
@ -61,7 +67,6 @@ import org.apache.poi.ss.formula.eval.ValueEval;
public class Subtotal implements Function { public class Subtotal implements Function {
private static Function findFunction(int functionCode) throws EvaluationException { private static Function findFunction(int functionCode) throws EvaluationException {
Function func;
switch (functionCode) { switch (functionCode) {
case 1: return subtotalInstance(AggregateFunction.AVERAGE); case 1: return subtotalInstance(AggregateFunction.AVERAGE);
case 2: return Count.subtotalInstance(); case 2: return Count.subtotalInstance();
@ -87,7 +92,7 @@ public class Subtotal implements Function {
return ErrorEval.VALUE_INVALID; return ErrorEval.VALUE_INVALID;
} }
Function innerFunc; final Function innerFunc;
try { try {
ValueEval ve = OperandResolver.getSingleValue(args[0], srcRowIndex, srcColumnIndex); ValueEval ve = OperandResolver.getSingleValue(args[0], srcRowIndex, srcColumnIndex);
int functionCode = OperandResolver.coerceValueToInt(ve); int functionCode = OperandResolver.coerceValueToInt(ve);
@ -96,9 +101,24 @@ public class Subtotal implements Function {
return e.getErrorEval(); return e.getErrorEval();
} }
ValueEval[] innerArgs = new ValueEval[nInnerArgs]; // ignore the first arg, this is the function-type, we check for the length above
System.arraycopy(args, 1, innerArgs, 0, nInnerArgs); 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);
} }
} }

View File

@ -81,7 +81,7 @@ public interface CellStyle {
/** /**
* vertically justified vertical alignment * 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(); static final short VERTICAL_JUSTIFY = 0x3; //VerticalAlignment.JUSTIFY.getCode();

View File

@ -341,9 +341,11 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
/** /**
* Close the underlying input resource (File or Stream), * Close the underlying input resource (File or Stream),
* from which the Workbook was read. After closing, the * from which the Workbook was read.
* Workbook should no longer be used. *
* <p>This will have no effect newly created Workbooks. * <p>Once this has been called, no further
* operations, updates or reads should be performed on the
* Workbook.
*/ */
@Override @Override
void close() throws IOException; void close() throws IOException;
@ -367,6 +369,13 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
*/ */
List<? extends Name> getNames(String name); 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) * @param nameIndex position of the named range (0-based)
* @return the defined name at the specified index * @return the defined name at the specified index
@ -405,6 +414,13 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
*/ */
void removeName(String name); 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 * Adds the linking required to allow formulas referencing
* the specified external workbook to be added to this one. * the specified external workbook to be added to this one.

View File

@ -27,19 +27,13 @@ import org.apache.commons.logging.LogFactory;
* developers to write log calls, while simultaneously making those * developers to write log calls, while simultaneously making those
* calls as cheap as possible by performing lazy evaluation of the log * calls as cheap as possible by performing lazy evaluation of the log
* message.<p> * 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 public class CommonsLogger extends POILogger
{ {
private static LogFactory _creator = LogFactory.getFactory(); private static LogFactory _creator = LogFactory.getFactory();
private Log log = null; private Log log = null;
@Override
public void initialize(final String cat) public void initialize(final String cat)
{ {
this.log = _creator.getInstance(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 level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param obj1 The object to log. * @param obj1 The object to log.
*/ */
@Override
public void log(final int level, final Object obj1) public void log(final int level, final Object obj1)
{ {
if(level==FATAL) 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 obj1 The object to log. This is converted to a string.
* @param exception An exception to be logged * @param exception An exception to be logged
*/ */
@Override
public void log(final int level, final Object obj1, public void log(final int level, final Object obj1,
final Throwable exception) final Throwable exception)
{ {
@ -175,7 +171,7 @@ public class CommonsLogger extends POILogger
* *
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
*/ */
@Override
public boolean check(final int level) public boolean check(final int level)
{ {
if(level==FATAL) if(level==FATAL)

View File

@ -22,14 +22,10 @@ package org.apache.poi.util;
* developers to write log calls, while simultaneously making those * developers to write log calls, while simultaneously making those
* calls as cheap as possible by performing lazy evaluation of the log * calls as cheap as possible by performing lazy evaluation of the log
* message.<p> * 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 { public class NullLogger extends POILogger {
@Override @Override
public void initialize(final String cat){ public void initialize(final String cat) {
// do nothing // do nothing
} }
@ -41,8 +37,7 @@ public class NullLogger extends POILogger {
*/ */
@Override @Override
public void log(final int level, final Object obj1) public void log(final int level, final Object obj1) {
{
// do nothing // do nothing
} }
@ -53,6 +48,7 @@ public class NullLogger extends POILogger {
* @param obj1 The object to log. This is converted to a string. * @param obj1 The object to log. This is converted to a string.
* @param exception An exception to be logged * @param exception An exception to be logged
*/ */
@Override
public void log(int level, Object obj1, final Throwable exception) { public void log(int level, Object obj1, final Throwable exception) {
// do nothing // do nothing
} }

View File

@ -24,15 +24,12 @@ package org.apache.poi.util;
* developers to write log calls, while simultaneously making those * developers to write log calls, while simultaneously making those
* calls as cheap as possible by performing lazy evaluation of the log * calls as cheap as possible by performing lazy evaluation of the log
* message. * 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 public class SystemOutLogger extends POILogger
{ {
private String _cat; private String _cat;
@Override
public void initialize(final String cat) public void initialize(final String cat)
{ {
this._cat=cat; this._cat=cat;
@ -44,7 +41,7 @@ public class SystemOutLogger extends POILogger
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param obj1 The object to log. * @param obj1 The object to log.
*/ */
@Override
public void log(final int level, final Object obj1) public void log(final int level, final Object obj1)
{ {
log(level, obj1, null); 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 obj1 The object to log. This is converted to a string.
* @param exception An exception to be logged * @param exception An exception to be logged
*/ */
@Override
@SuppressForbidden("uses printStackTrace") @SuppressForbidden("uses printStackTrace")
public void log(final int level, final Object obj1, public void log(final int level, final Object obj1,
final Throwable exception) { final Throwable exception) {
@ -78,6 +76,7 @@ public class SystemOutLogger extends POILogger
* @see #ERROR * @see #ERROR
* @see #FATAL * @see #FATAL
*/ */
@Override
public boolean check(final int level) public boolean check(final int level)
{ {
int currentLevel; int currentLevel;

View File

@ -194,6 +194,10 @@ public abstract class POIXMLDocument extends POIXMLDocumentPart implements Close
* Closes the underlying {@link OPCPackage} from which this * Closes the underlying {@link OPCPackage} from which this
* document was read, if there is one * document was read, if there is one
* *
* <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. * @throws IOException for writable packages, if an IO exception occur during the saving process.
*/ */
@Override @Override

View File

@ -382,8 +382,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
} }
// Creates a new package // Creates a new package
OPCPackage pkg = null; OPCPackage pkg = new ZipPackage();
pkg = new ZipPackage();
pkg.originalPackagePath = file.getAbsolutePath(); pkg.originalPackagePath = file.getAbsolutePath();
configurePackage(pkg); configurePackage(pkg);
@ -391,8 +390,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
} }
public static OPCPackage create(OutputStream output) { public static OPCPackage create(OutputStream output) {
OPCPackage pkg = null; OPCPackage pkg = new ZipPackage();
pkg = new ZipPackage();
pkg.originalPackagePath = null; pkg.originalPackagePath = null;
pkg.output = output; pkg.output = output;
@ -542,7 +540,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
// Create the thumbnail part name // Create the thumbnail part name
String contentType = ContentTypes String contentType = ContentTypes
.getContentTypeFromFileExtension(filename); .getContentTypeFromFileExtension(filename);
PackagePartName thumbnailPartName = null; PackagePartName thumbnailPartName;
try { try {
thumbnailPartName = PackagingURIHelper.createPartName("/docProps/" thumbnailPartName = PackagingURIHelper.createPartName("/docProps/"
+ filename); + filename);

View File

@ -29,10 +29,7 @@ import java.util.TreeMap;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.InvalidOperationException; import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException; import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.*;
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.util.DocumentHelper; import org.apache.poi.util.DocumentHelper;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
@ -54,7 +51,7 @@ public abstract class ContentTypeManager {
/** /**
* Content type namespace * 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 */ /* Xml elements in content type part */

View File

@ -304,13 +304,13 @@ implements XSLFShapeContainer, GroupShape<XSLFShape,XSLFTextParagraph> {
@Override @Override
public boolean getFlipHorizontal(){ public boolean getFlipHorizontal(){
CTGroupTransform2D xfrm = getXfrm(); CTGroupTransform2D xfrm = getXfrm();
return (xfrm == null || !xfrm.isSetFlipH()) ? false : xfrm.getFlipH(); return !(xfrm == null || !xfrm.isSetFlipH()) && xfrm.getFlipH();
} }
@Override @Override
public boolean getFlipVertical(){ public boolean getFlipVertical(){
CTGroupTransform2D xfrm = getXfrm(); CTGroupTransform2D xfrm = getXfrm();
return (xfrm == null || !xfrm.isSetFlipV()) ? false : xfrm.getFlipV(); return !(xfrm == null || !xfrm.isSetFlipV()) && xfrm.getFlipV();
} }
@Override @Override
@ -333,7 +333,7 @@ implements XSLFShapeContainer, GroupShape<XSLFShape,XSLFTextParagraph> {
// recursively update each shape // recursively update each shape
for(XSLFShape shape : gr.getShapes()) { for(XSLFShape shape : gr.getShapes()) {
XSLFShape newShape = null; XSLFShape newShape;
if (shape instanceof XSLFTextBox) { if (shape instanceof XSLFTextBox) {
newShape = createTextBox(); newShape = createTextBox();
} else if (shape instanceof XSLFAutoShape) { } else if (shape instanceof XSLFAutoShape) {

View File

@ -41,7 +41,6 @@ import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory; import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator; 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.CellType;
import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.util.DocumentHelper; 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.XSSFTable;
import org.apache.poi.xssf.usermodel.helpers.XSSFSingleXmlCell; import org.apache.poi.xssf.usermodel.helpers.XSSFSingleXmlCell;
import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr; 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.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NamedNodeMap;
@ -118,7 +116,6 @@ public class XSSFExportToXml implements Comparator<String>{
* @throws SAXException * @throws SAXException
* @throws ParserConfigurationException * @throws ParserConfigurationException
* @throws TransformerException * @throws TransformerException
* @throws InvalidFormatException
*/ */
public void exportToXML(OutputStream os, String encoding, boolean validate) throws SAXException, ParserConfigurationException, TransformerException{ public void exportToXML(OutputStream os, String encoding, boolean validate) throws SAXException, ParserConfigurationException, TransformerException{
List<XSSFSingleXmlCell> singleXMLCells = map.getRelatedSingleXMLCell(); List<XSSFSingleXmlCell> singleXMLCells = map.getRelatedSingleXMLCell();
@ -128,10 +125,10 @@ public class XSSFExportToXml implements Comparator<String>{
Document doc = DocumentHelper.createDocument(); Document doc = DocumentHelper.createDocument();
Element root = null; final Element root;
if (isNamespaceDeclared()) { if (isNamespaceDeclared()) {
root=doc.createElementNS(getNamespace(),rootElement); root = doc.createElementNS(getNamespace(),rootElement);
} else { } else {
root = doc.createElementNS("", rootElement); root = doc.createElementNS("", rootElement);
} }
@ -152,7 +149,6 @@ public class XSSFExportToXml implements Comparator<String>{
tableMappings.put(commonXPath, table); tableMappings.put(commonXPath, table);
} }
Collections.sort(xpaths,this); Collections.sort(xpaths,this);
for(String xpath : xpaths) { for(String xpath : xpaths) {
@ -167,8 +163,7 @@ public class XSSFExportToXml implements Comparator<String>{
XSSFCell cell = simpleXmlCell.getReferencedCell(); XSSFCell cell = simpleXmlCell.getReferencedCell();
if (cell!=null) { if (cell!=null) {
Node currentNode = getNodeByXPath(xpath,doc.getFirstChild(),doc,false); Node currentNode = getNodeByXPath(xpath,doc.getFirstChild(),doc,false);
STXmlDataType.Enum dataType = simpleXmlCell.getXmlDataType(); mapCellOnNode(cell,currentNode);
mapCellOnNode(cell,currentNode,dataType);
//remove nodes which are empty in order to keep the output xml valid //remove nodes which are empty in order to keep the output xml valid
if("".equals(currentNode.getTextContent()) && currentNode.getParentNode() != null) { if("".equals(currentNode.getTextContent()) && currentNode.getParentNode() != null) {
@ -202,22 +197,15 @@ public class XSSFExportToXml implements Comparator<String>{
XSSFXmlColumnPr pointer = tableColumns.get(j-startColumnIndex); XSSFXmlColumnPr pointer = tableColumns.get(j-startColumnIndex);
String localXPath = pointer.getLocalXPath(); String localXPath = pointer.getLocalXPath();
Node currentNode = getNodeByXPath(localXPath,tableRootNode,doc,false); Node currentNode = getNodeByXPath(localXPath,tableRootNode,doc,false);
STXmlDataType.Enum dataType = pointer.getXmlDataType();
mapCellOnNode(cell,currentNode);
mapCellOnNode(cell,currentNode,dataType);
} }
} }
} }
} }
} else { } /*else {
// TODO: implement filtering management in xpath // TODO: implement filtering management in xpath
} }*/
} }
boolean isValid = true; boolean isValid = true;
@ -225,8 +213,6 @@ public class XSSFExportToXml implements Comparator<String>{
isValid =isValid(doc); isValid =isValid(doc);
} }
if (isValid) { 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 =""; String value ="";
switch (cell.getCellTypeEnum()) { switch (cell.getCellTypeEnum()) {
@ -349,11 +335,7 @@ public class XSSFExportToXml implements Comparator<String>{
} }
currentNode = selectedNode; currentNode = selectedNode;
} else { } else {
currentNode = createAttribute(doc, currentNode, axisName);
Node attribute = createAttribute(doc, currentNode, axisName);
currentNode = attribute;
} }
} }
return currentNode; return currentNode;
@ -421,12 +403,11 @@ public class XSSFExportToXml implements Comparator<String>{
for(int i =1;i <minLenght; i++) { for(int i =1;i <minLenght; i++) {
String leftElementName =leftTokens[i]; String leftElementName = leftTokens[i];
String rightElementName = rightTokens[i]; String rightElementName = rightTokens[i];
if (leftElementName.equals(rightElementName)) { if (leftElementName.equals(rightElementName)) {
Node complexType = getComplexTypeForElement(leftElementName, xmlSchema,localComplexTypeRootNode); localComplexTypeRootNode = getComplexTypeForElement(leftElementName, xmlSchema, localComplexTypeRootNode);
localComplexTypeRootNode = complexType;
} else { } else {
int leftIndex = indexOfElementInComplexType(leftElementName,localComplexTypeRootNode); int leftIndex = indexOfElementInComplexType(leftElementName,localComplexTypeRootNode);
int rightIndex = indexOfElementInComplexType(rightElementName,localComplexTypeRootNode); int rightIndex = indexOfElementInComplexType(rightElementName,localComplexTypeRootNode);
@ -436,9 +417,9 @@ public class XSSFExportToXml implements Comparator<String>{
}if ( leftIndex > rightIndex) { }if ( leftIndex > rightIndex) {
return 1; return 1;
} }
} else { } /*else {
// NOTE: the xpath doesn't match correctly in the schema // 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 // Note: we expect that all the complex types are defined at root level
Node complexTypeNode = null; Node complexTypeNode = null;
if (!"".equals(complexTypeName)) { if (!"".equals(complexTypeName)) {
complexTypeNode = getComplexTypeNodeFromSchemaChildren(xmlSchema, complexTypeNode, complexTypeName); complexTypeNode = getComplexTypeNodeFromSchemaChildren(xmlSchema, null, complexTypeName);
} }
return complexTypeNode; return complexTypeNode;

View File

@ -338,7 +338,11 @@ public class SXSSFCell implements Cell {
} }
if(_value.getType()==CellType.FORMULA) 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 else
((PlainStringValue)_value).setValue(value); ((PlainStringValue)_value).setValue(value);
} else { } else {
@ -956,6 +960,7 @@ public class SXSSFCell implements Cell {
} }
/*package*/ void setFormulaType(CellType type) /*package*/ void setFormulaType(CellType type)
{ {
Value prevValue = _value;
switch(type) switch(type)
{ {
case NUMERIC: case NUMERIC:
@ -983,7 +988,13 @@ public class SXSSFCell implements Cell {
throw new IllegalArgumentException("Illegal type " + type); 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 //TODO: implement this correctly
@NotImplemented @NotImplemented
/*package*/ CellType computeTypeFromFormula(String formula) /*package*/ CellType computeTypeFromFormula(String formula)

View File

@ -893,8 +893,11 @@ public class SXSSFWorkbook implements Workbook {
/** /**
* Closes the underlying {@link XSSFWorkbook} and {@link OPCPackage} * Closes the underlying {@link XSSFWorkbook} and {@link OPCPackage}
* on which this Workbook is based, if any. Has no effect on Workbooks * on which this Workbook is based, if any.
* created from scratch. *
* <p>Once this has been called, no further
* operations, updates or reads should be performed on the
* Workbook.
*/ */
@Override @Override
public void close() throws IOException { public void close() throws IOException {
@ -1003,12 +1006,25 @@ public class SXSSFWorkbook implements Workbook {
return _wb.getNames(name); 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) * @param nameIndex position of the named range (0-based)
* @return the defined name at the specified index * @return the defined name at the specified index
* @throws IllegalArgumentException if the supplied index is invalid * @throws IllegalArgumentException if the supplied index is invalid
* @deprecated 3.16. New projects should avoid accessing named ranges by index.
*/ */
@Override @Override
@Deprecated
public Name getNameAt(int nameIndex) public Name getNameAt(int nameIndex)
{ {
return _wb.getNameAt(nameIndex); return _wb.getNameAt(nameIndex);
@ -1033,8 +1049,12 @@ public class SXSSFWorkbook implements Workbook {
* *
* @param name the name of the defined name * @param name the name of the defined name
* @return zero based index of the defined name. <code>-1</code> if not found. * @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 @Override
@Deprecated
public int getNameIndex(String name) public int getNameIndex(String name)
{ {
return _wb.getNameIndex(name); return _wb.getNameIndex(name);
@ -1044,8 +1064,11 @@ public class SXSSFWorkbook implements Workbook {
* Remove the defined name at the specified index * Remove the defined name at the specified index
* *
* @param index named range index (0 based) * @param index named range index (0 based)
*
* @deprecated 3.16. New projects should use {@link #removeName(Name)}.
*/ */
@Override @Override
@Deprecated
public void removeName(int index) public void removeName(int index)
{ {
_wb.removeName(index); _wb.removeName(index);
@ -1055,9 +1078,23 @@ public class SXSSFWorkbook implements Workbook {
* Remove a defined name by name * 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 @Override
@Deprecated
public void removeName(String name) 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); _wb.removeName(name);
} }

View File

@ -232,7 +232,7 @@ public abstract class BaseXSSFEvaluationWorkbook implements FormulaRenderingWork
// Otherwise, try it as a named range // Otherwise, try it as a named range
if (sheet == null) { if (sheet == null) {
if (_uBook.getNameIndex(name) > -1) { if (!_uBook.getNames(name).isEmpty()) {
return new NameXPxg(null, name); return new NameXPxg(null, name);
} }
return null; return null;

View File

@ -17,12 +17,9 @@
package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.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.EvaluationCell; import org.apache.poi.ss.formula.EvaluationCell;
import org.apache.poi.ss.formula.WorkbookEvaluator; 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.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.NumberEval; 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.Cell;
import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.CellValue; import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
/** /**
* Internal POI use only - parent of XSSF and SXSSF formula evaluators * Internal POI use only - parent of XSSF and SXSSF formula evaluators
*/ */
public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluatorProvider { public abstract class BaseXSSFFormulaEvaluator extends BaseFormulaEvaluator {
private WorkbookEvaluator _bookEvaluator;
protected BaseXSSFFormulaEvaluator(WorkbookEvaluator bookEvaluator) { 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) { public void notifySetFormula(Cell cell) {
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell)); _bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
} }
@ -63,60 +48,6 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell)); _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, * If cell contains formula, it evaluates the formula,
* and saves the result of the formula. The cell * and saves the result of the formula. The cell
@ -164,27 +95,6 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
setCellValue(cell, cv); 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) { private static void setCellValue(Cell cell, CellValue cv) {
CellType cellType = cv.getCellType(); CellType cellType = cv.getCellType();
@ -218,7 +128,7 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
/** /**
* Returns a CellValue wrapper around the supplied ValueEval instance. * Returns a CellValue wrapper around the supplied ValueEval instance.
*/ */
private CellValue evaluateFormulaCellValue(Cell cell) { protected CellValue evaluateFormulaCellValue(Cell cell) {
EvaluationCell evalCell = toEvaluationCell(cell); EvaluationCell evalCell = toEvaluationCell(cell);
ValueEval eval = _bookEvaluator.evaluate(evalCell); ValueEval eval = _bookEvaluator.evaluate(evalCell);
if (eval instanceof NumberEval) { if (eval instanceof NumberEval) {
@ -238,22 +148,4 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
} }
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")"); 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);
}
} }

View File

@ -17,7 +17,7 @@
package org.apache.poi.xssf.usermodel; 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.EvaluationCell;
import org.apache.poi.ss.formula.IStabilityClassifier; import org.apache.poi.ss.formula.IStabilityClassifier;
import org.apache.poi.ss.formula.WorkbookEvaluator; import org.apache.poi.ss.formula.WorkbookEvaluator;
@ -88,7 +88,7 @@ public final class XSSFFormulaEvaluator extends BaseXSSFFormulaEvaluator {
* cells, and calling evaluateFormulaCell on each one. * cells, and calling evaluateFormulaCell on each one.
*/ */
public static void evaluateAllFormulaCells(XSSFWorkbook wb) { public static void evaluateAllFormulaCells(XSSFWorkbook wb) {
HSSFFormulaEvaluator.evaluateAllFormulaCells(wb); BaseFormulaEvaluator.evaluateAllFormulaCells(wb);
} }
/** /**
* Loops over all cells in all sheets of the supplied * 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. * cells, and calling evaluateFormulaCell on each one.
*/ */
public void evaluateAll() { public void evaluateAll() {
HSSFFormulaEvaluator.evaluateAllFormulaCells(_book); evaluateAllFormulaCells(_book, this);
} }
/** /**

View File

@ -167,19 +167,18 @@ public final class XSSFName implements Name {
public void setNameName(String name) { public void setNameName(String name) {
validateName(name); validateName(name);
String oldName = getNameName();
int sheetIndex = getSheetIndex(); int sheetIndex = getSheetIndex();
int numberOfNames = _workbook.getNumberOfNames();
//Check to ensure no other names have the same case-insensitive name at the same scope //Check to ensure no other names have the same case-insensitive name at the same scope
for (int i = 0; i < numberOfNames; i++) { for (XSSFName foundName : _workbook.getNames(name)) {
XSSFName nm = _workbook.getNameAt(i); if (foundName.getSheetIndex() == sheetIndex && foundName != this) {
if ((nm != this)
&& name.equalsIgnoreCase(nm.getNameName())
&& (sheetIndex == nm.getSheetIndex())) {
String msg = "The "+(sheetIndex == -1 ? "workbook" : "sheet")+" already contains this name: " + name; String msg = "The "+(sheetIndex == -1 ? "workbook" : "sheet")+" already contains this name: " + name;
throw new IllegalArgumentException(msg); throw new IllegalArgumentException(msg);
} }
} }
_ctName.setName(name); _ctName.setName(name);
//Need to update the name -> named ranges map
_workbook.updateName(this, oldName);
} }
public String getRefersToFormula() { public String getRefersToFormula() {

View File

@ -18,8 +18,8 @@
package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.usermodel;
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; 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.XSSFPasswordHelper.setPassword;
import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword; import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.validatePassword;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;

View File

@ -18,8 +18,8 @@
package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.usermodel;
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; 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.XSSFPasswordHelper.setPassword;
import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword; import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.validatePassword;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -29,16 +29,20 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.xml.namespace.QName; 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.POIXMLDocument;
import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException; 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.AggregatingUDFFinder;
import org.apache.poi.ss.formula.udf.IndexedUDFFinder; import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder; 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;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Sheet;
@ -140,6 +145,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
*/ */
private List<XSSFSheet> sheets; 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 * this holds the XSSFName objects attached to this workbook
*/ */
@ -442,6 +452,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
stylesSource.setWorkbook(this); stylesSource.setWorkbook(this);
namedRanges = new ArrayList<XSSFName>(); namedRanges = new ArrayList<XSSFName>();
namedRangesByName = new ArrayListValuedHashMap<String, XSSFName>();
sheets = new ArrayList<XSSFSheet>(); sheets = new ArrayList<XSSFSheet>();
pivotTables = new ArrayList<XSSFPivotTable>(); pivotTables = new ArrayList<XSSFPivotTable>();
} }
@ -733,8 +744,13 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
public XSSFName createName() { public XSSFName createName() {
CTDefinedName ctName = CTDefinedName.Factory.newInstance(); CTDefinedName ctName = CTDefinedName.Factory.newInstance();
ctName.setName(""); ctName.setName("");
return createAndStoreName(ctName);
}
private XSSFName createAndStoreName(CTDefinedName ctName) {
XSSFName name = new XSSFName(ctName, this); XSSFName name = new XSSFName(ctName, this);
namedRanges.add(name); namedRanges.add(name);
namedRangesByName.put(ctName.getName().toLowerCase(Locale.ENGLISH), name);
return name; return name;
} }
@ -938,28 +954,47 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
return stylesSource.getFontAt(idx); 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 @Override
public XSSFName getName(String name) { public XSSFName getName(String name) {
int nameIndex = getNameIndex(name); Collection<XSSFName> list = getNames(name);
if (nameIndex < 0) { if (list.isEmpty()) {
return null; 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 @Override
public List<XSSFName> getNames(String name) { public List<XSSFName> getNames(String name) {
List<XSSFName> names = new ArrayList<XSSFName>(); return Collections.unmodifiableList(namedRangesByName.get(name.toLowerCase(Locale.ENGLISH)));
for(XSSFName nr : namedRanges) {
if(nr.getNameName().equals(name)) {
names.add(nr);
}
}
return names;
} }
/**
* 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 @Override
@Deprecated
public XSSFName getNameAt(int nameIndex) { public XSSFName getNameAt(int nameIndex) {
int nNames = namedRanges.size(); int nNames = namedRanges.size();
if (nNames < 1) { if (nNames < 1) {
@ -973,21 +1008,30 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
/** /**
* Gets the named range index by his name * Get a list of all the named ranges in the workbook.
* <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 in the workbook
* @return named range index
*/ */
@Override @Override
public int getNameIndex(String name) { public List<XSSFName> getAllNames() {
int i = 0; return Collections.unmodifiableList(namedRanges);
for(XSSFName nr : namedRanges) {
if(nr.getNameName().equals(name)) {
return i;
} }
i++;
/**
* 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) {
XSSFName nm = getName(name);
if (nm != null) {
return namedRanges.indexOf(nm);
} }
return -1; return -1;
} }
@ -1258,23 +1302,41 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
return getPackagePart().getContentType().equals(XSSFRelation.MACROS_WORKBOOK.getContentType()); 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 @Override
@Deprecated
public void removeName(int nameIndex) { 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 @Override
@Deprecated
public void removeName(String name) { public void removeName(String name) {
int idx = 0; List<XSSFName> names = namedRangesByName.get(name.toLowerCase(Locale.ENGLISH));
for (XSSFName nm : namedRanges) { if (names.isEmpty()) {
if(nm.getNameName().equalsIgnoreCase(name)) {
removeName(idx);
return;
}
idx++;
}
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. * (name + sheet index is unique), this method is more accurate.
* *
* @param name the name to remove. * @param name the name to remove.
*
* @throws IllegalArgumentException if the named range is not a part of this XSSFWorkbook
*/ */
void removeName(XSSFName name) { @Override
if (!namedRanges.remove(name)) { 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); 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 * Delete the printarea for the sheet specified
@ -1297,13 +1370,9 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
*/ */
@Override @Override
public void removePrintArea(int sheetIndex) { public void removePrintArea(int sheetIndex) {
int cont = 0; XSSFName name = getBuiltInName(XSSFName.BUILTIN_PRINT_AREA, sheetIndex);
for (XSSFName name : namedRanges) { if (name != null) {
if (name.getNameName().equals(XSSFName.BUILTIN_PRINT_AREA) && name.getSheetIndex() == sheetIndex) { removeName(name);
namedRanges.remove(cont);
break;
}
cont++;
} }
} }
@ -1369,17 +1438,20 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
//adjust indices of names ranges //adjust indices of names ranges
for (Iterator<XSSFName> it = namedRanges.iterator(); it.hasNext();) { List<XSSFName> toRemove = new ArrayList<XSSFName>();
XSSFName nm = it.next(); for (XSSFName nm : namedRanges) {
CTDefinedName ct = nm.getCTName(); CTDefinedName ct = nm.getCTName();
if(!ct.isSetLocalSheetId()) continue; if(!ct.isSetLocalSheetId()) continue;
if (ct.getLocalSheetId() == index) { if (ct.getLocalSheetId() == index) {
it.remove(); toRemove.add(nm);
} else if (ct.getLocalSheetId() > index){ } else if (ct.getLocalSheetId() > index){
// Bump down by one, so still points at the same sheet // Bump down by one, so still points at the same sheet
ct.setLocalSheetId(ct.getLocalSheetId()-1); 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) { XSSFName getBuiltInName(String builtInCode, int sheetNumber) {
for (XSSFName name : namedRanges) { for (XSSFName name : namedRangesByName.get(builtInCode.toLowerCase(Locale.ENGLISH))) {
if (name.getNameName().equalsIgnoreCase(builtInCode) && name.getSheetIndex() == sheetNumber) { if (name.getSheetIndex() == sheetNumber) {
return name; return name;
} }
} }
@ -1537,15 +1609,12 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
nameRecord.setName(builtInName); nameRecord.setName(builtInName);
nameRecord.setLocalSheetId(sheetNumber); nameRecord.setLocalSheetId(sheetNumber);
XSSFName name = new XSSFName(nameRecord, this); if (getBuiltInName(builtInName, sheetNumber) != null) {
for (XSSFName nr : namedRanges) {
if (nr.equals(name))
throw new POIXMLException("Builtin (" + builtInName throw new POIXMLException("Builtin (" + builtInName
+ ") already exists for sheet (" + sheetNumber + ")"); + ") already exists for sheet (" + sheetNumber + ")");
} }
namedRanges.add(name); return createAndStoreName(nameRecord);
return name;
} }
/** /**
@ -1665,10 +1734,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
private void reprocessNamedRanges() { private void reprocessNamedRanges() {
namedRangesByName = new ArrayListValuedHashMap<String, XSSFName>();
namedRanges = new ArrayList<XSSFName>(); namedRanges = new ArrayList<XSSFName>();
if(workbook.isSetDefinedNames()) { if(workbook.isSetDefinedNames()) {
for(CTDefinedName ctName : workbook.getDefinedNames().getDefinedNameArray()) { for(CTDefinedName ctName : workbook.getDefinedNames().getDefinedNameArray()) {
namedRanges.add(new XSSFName(ctName, this)); createAndStoreName(ctName);
} }
} }
} }

View File

@ -65,9 +65,7 @@ public final class XSSFFormulaUtils {
*/ */
public void updateSheetName(final int sheetIndex, final String oldName, final String newName) { public void updateSheetName(final int sheetIndex, final String oldName, final String newName) {
// update named ranges // update named ranges
final int numberOfNames = _wb.getNumberOfNames(); for (XSSFName nm : _wb.getAllNames()) {
for (int i = 0; i < numberOfNames; i++) {
XSSFName nm = _wb.getNameAt(i);
if (nm.getSheetIndex() == -1 || nm.getSheetIndex() == sheetIndex) { if (nm.getSheetIndex() == -1 || nm.getSheetIndex() == sheetIndex) {
updateName(nm, oldName, newName); updateName(nm, oldName, newName);
} }

View File

@ -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));
}
}
}

View File

@ -19,18 +19,17 @@
package org.apache.poi.xssf.usermodel.helpers; 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.poifs.crypt.HashAlgorithm;
import org.apache.xmlbeans.XmlCursor; import org.apache.poi.util.Internal;
import org.apache.poi.util.Removal;
import org.apache.xmlbeans.XmlObject; 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 { public class XSSFPaswordHelper {
/** /**
* Sets the XORed or hashed password * Sets the XORed or hashed password
@ -41,41 +40,7 @@ public class XSSFPaswordHelper {
* @param prefix the prefix of the password attributes, may be null * @param prefix the prefix of the password attributes, may be null
*/ */
public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) { public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) {
XmlCursor cur = xobj.newCursor(); XSSFPasswordHelper.setPassword(xobj, password, hashAlgo, prefix);
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();
} }
/** /**
@ -90,41 +55,6 @@ public class XSSFPaswordHelper {
* @return true, if the hashes match * @return true, if the hashes match
*/ */
public static boolean validatePassword(XmlObject xobj, String password, String prefix) { public static boolean validatePassword(XmlObject xobj, String password, String prefix) {
// TODO: is "velvetSweatshop" the default password? return XSSFPasswordHelper.validatePassword(xobj, password, prefix);
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));
}
} }
} }

View File

@ -83,9 +83,7 @@ public final class XSSFRowShifter extends RowShifter {
public void updateNamedRanges(FormulaShifter shifter) { public void updateNamedRanges(FormulaShifter shifter) {
Workbook wb = sheet.getWorkbook(); Workbook wb = sheet.getWorkbook();
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create((XSSFWorkbook) wb); XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create((XSSFWorkbook) wb);
final int numberOfNames = wb.getNumberOfNames(); for (Name name : wb.getAllNames()) {
for (int i = 0; i < numberOfNames; i++) {
Name name = wb.getNameAt(i);
String formula = name.getRefersToFormula(); String formula = name.getRefersToFormula();
int sheetIndex = name.getSheetIndex(); int sheetIndex = name.getSheetIndex();
final int rowIndex = -1; //don't care, named ranges are not allowed to include structured references final int rowIndex = -1; //don't care, named ranges are not allowed to include structured references

View File

@ -18,6 +18,7 @@
package org.apache.poi.openxml4j.opc.internal; package org.apache.poi.openxml4j.opc.internal;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue; import static org.junit.Assume.assumeTrue;
@ -44,6 +45,7 @@ public final class TestContentTypeManager {
// Retrieves core properties part // Retrieves core properties part
OPCPackage p = OPCPackage.open(filepath, PackageAccess.READ); OPCPackage p = OPCPackage.open(filepath, PackageAccess.READ);
try {
PackageRelationshipCollection rels = p.getRelationshipsByType(PackageRelationshipTypes.CORE_PROPERTIES); PackageRelationshipCollection rels = p.getRelationshipsByType(PackageRelationshipTypes.CORE_PROPERTIES);
PackageRelationship corePropertiesRelationship = rels.getRelationship(0); PackageRelationship corePropertiesRelationship = rels.getRelationship(0);
PackagePart coreDocument = p.getPart(corePropertiesRelationship); PackagePart coreDocument = p.getPart(corePropertiesRelationship);
@ -54,6 +56,10 @@ public final class TestContentTypeManager {
assumeTrue("finish writing this test", false); assumeTrue("finish writing this test", false);
ContentTypeManager ctm = new ZipContentTypeManager(coreDocument.getInputStream(), p); ContentTypeManager ctm = new ZipContentTypeManager(coreDocument.getInputStream(), p);
assertNotNull(ctm);
} finally {
p.close();
}
} }
/** /**

View File

@ -115,25 +115,25 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues {
assertFalse(wb.isMacroEnabled()); assertFalse(wb.isMacroEnabled());
assertEquals(3, wb.getNumberOfNames()); assertEquals(3, wb.getNumberOfNames());
assertEquals(0, wb.getNameAt(0).getCTName().getLocalSheetId()); assertEquals(0, wb.getName("SheetAA1").getCTName().getLocalSheetId());
assertFalse(wb.getNameAt(0).getCTName().isSetLocalSheetId()); assertFalse(wb.getName("SheetAA1").getCTName().isSetLocalSheetId());
assertEquals("SheetA!$A$1", wb.getNameAt(0).getRefersToFormula()); assertEquals("SheetA!$A$1", wb.getName("SheetAA1").getRefersToFormula());
assertEquals("SheetA", wb.getNameAt(0).getSheetName()); assertEquals("SheetA", wb.getName("SheetAA1").getSheetName());
assertEquals(0, wb.getNameAt(1).getCTName().getLocalSheetId()); assertEquals(0, wb.getName("SheetBA1").getCTName().getLocalSheetId());
assertFalse(wb.getNameAt(1).getCTName().isSetLocalSheetId()); assertFalse(wb.getName("SheetBA1").getCTName().isSetLocalSheetId());
assertEquals("SheetB!$A$1", wb.getNameAt(1).getRefersToFormula()); assertEquals("SheetB!$A$1", wb.getName("SheetBA1").getRefersToFormula());
assertEquals("SheetB", wb.getNameAt(1).getSheetName()); assertEquals("SheetB", wb.getName("SheetBA1").getSheetName());
assertEquals(0, wb.getNameAt(2).getCTName().getLocalSheetId()); assertEquals(0, wb.getName("SheetCA1").getCTName().getLocalSheetId());
assertFalse(wb.getNameAt(2).getCTName().isSetLocalSheetId()); assertFalse(wb.getName("SheetCA1").getCTName().isSetLocalSheetId());
assertEquals("SheetC!$A$1", wb.getNameAt(2).getRefersToFormula()); assertEquals("SheetC!$A$1", wb.getName("SheetCA1").getRefersToFormula());
assertEquals("SheetC", wb.getNameAt(2).getSheetName()); assertEquals("SheetC", wb.getName("SheetCA1").getSheetName());
// Save and re-load, still there // Save and re-load, still there
XSSFWorkbook nwb = XSSFTestDataSamples.writeOutAndReadBack(wb); XSSFWorkbook nwb = XSSFTestDataSamples.writeOutAndReadBack(wb);
assertEquals(3, nwb.getNumberOfNames()); assertEquals(3, nwb.getNumberOfNames());
assertEquals("SheetA!$A$1", nwb.getNameAt(0).getRefersToFormula()); assertEquals("SheetA!$A$1", nwb.getName("SheetAA1").getRefersToFormula());
nwb.close(); nwb.close();
wb.close(); wb.close();

View File

@ -154,7 +154,9 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
evaluator.evaluate(cXSL_cell); evaluator.evaluate(cXSL_cell);
fail("Without a fix for #56752, shouldn't be able to evaluate a " + fail("Without a fix for #56752, shouldn't be able to evaluate a " +
"reference to a non-provided linked workbook"); "reference to a non-provided linked workbook");
} catch(Exception e) {} } catch(Exception e) {
// expected here
}
// Setup the environment // Setup the environment
Map<String,FormulaEvaluator> evaluators = new HashMap<String, FormulaEvaluator>(); Map<String,FormulaEvaluator> evaluators = new HashMap<String, FormulaEvaluator>();
@ -171,8 +173,19 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
evaluator.evaluate(c); 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("\"Hello!\"", evaluator.evaluate(cXSLX_cell).formatAsString());
assertEquals("\"Test A1\"", evaluator.evaluate(cXSLX_sNR).formatAsString()); assertEquals("\"Test A1\"", evaluator.evaluate(cXSLX_sNR).formatAsString());
assertEquals("142.0", evaluator.evaluate(cXSLX_gNR).formatAsString()); assertEquals("142.0", evaluator.evaluate(cXSLX_gNR).formatAsString());
@ -196,7 +209,9 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
try { try {
cXSLX_nw_cell.setCellFormula("[alt.xlsx]Sheet1!$A$1"); cXSLX_nw_cell.setCellFormula("[alt.xlsx]Sheet1!$A$1");
fail("New workbook not linked, shouldn't be able to add"); fail("New workbook not linked, shouldn't be able to add");
} catch (Exception e) {} } catch (Exception e) {
// expected here
}
// Link and re-try // Link and re-try
Workbook alt = new XSSFWorkbook(); Workbook alt = new XSSFWorkbook();
@ -651,4 +666,20 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
private Cell getCell(Sheet sheet, int rowNo, int column) { private Cell getCell(Sheet sheet, int rowNo, int column) {
return sheet.getRow(rowNo).getCell(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);
}
} }

View File

@ -53,9 +53,8 @@ public final class TestXSSFName extends BaseTestNamedRange {
//sheet.createFreezePane(0, 3); //sheet.createFreezePane(0, 3);
} }
assertEquals(1, wb.getNumberOfNames()); 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()); assertEquals("'First Sheet'!$A:$A,'First Sheet'!$1:$4", nr1.getRefersToFormula());
//remove the columns part //remove the columns part
@ -77,9 +76,8 @@ public final class TestXSSFName extends BaseTestNamedRange {
wb.close(); wb.close();
assertEquals(1, nwb.getNumberOfNames()); 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()); 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 // 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")); sheet2.setRepeatingColumns(CellRangeAddress.valueOf("B:C"));
assertEquals(2, nwb.getNumberOfNames()); 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(XSSFName.BUILTIN_PRINT_TITLE, nr2.getNameName());
assertEquals("SecondSheet!$B:$C,SecondSheet!$1:$1", nr2.getRefersToFormula()); assertEquals("SecondSheet!$B:$C,SecondSheet!$1:$1", nr2.getRefersToFormula());
@ -98,4 +96,38 @@ public final class TestXSSFName extends BaseTestNamedRange {
sheet2.setRepeatingColumns(null); sheet2.setRepeatingColumns(null);
nwb.close(); 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();
}
} }

View File

@ -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.CTXf;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode; import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane; import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnsignedShortHex;
public final class TestXSSFSheet extends BaseTestXSheet { public final class TestXSSFSheet extends BaseTestXSheet {
@ -1099,6 +1100,30 @@ public final class TestXSSFSheet extends BaseTestXSheet {
wb.close(); 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 @Test
public void protectSheet_lowlevel_2013() throws IOException { public void protectSheet_lowlevel_2013() throws IOException {
String password = "test"; String password = "test";

View File

@ -1140,4 +1140,44 @@ public final class TestXSSFWorkbook extends BaseTestXWorkbook {
wb.close(); 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();
}
} }

View File

@ -571,20 +571,39 @@ public final class HWPFDocument extends HWPFDocumentCore {
return _fields; return _fields;
} }
/**
* Warning - not currently implemented for HWPF!
*/
@Override @Override
public void write() throws IOException { public void write() throws IOException {
throw new IllegalStateException("Coming soon!"); // TODO Implement
}
@Override
public void write(File newFile) throws IOException {
throw new IllegalStateException("Coming soon!"); throw new IllegalStateException("Coming soon!");
} }
/** /**
* Writes out the word file that is represented by an instance of this class. * 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 * If the {@link File} exists, it will be replaced, otherwise a new one
* or has a high cost/latency associated with each written byte, * 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 {
NPOIFSFileSystem pfs = POIFSFileSystem.create(newFile);
write(pfs, true);
pfs.writeFilesystem();
}
/**
* Writes out the word file that is represented by an instance of this class.
*
* 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} * consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream}
* to improve write performance. * 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 * @throws IOException If there is an unexpected IOException from the passed
* in OutputStream. * in OutputStream.
*/ */
public void write(OutputStream out) public void write(OutputStream out) throws IOException {
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. // initialize our streams for writing.
HWPFFileSystem docSys = new HWPFFileSystem(); HWPFFileSystem docSys = new HWPFFileSystem();
HWPFOutputStream wordDocumentStream = docSys.getStream(STREAM_WORD_DOCUMENT); HWPFOutputStream wordDocumentStream = docSys.getStream(STREAM_WORD_DOCUMENT);
@ -891,7 +913,8 @@ public final class HWPFDocument extends HWPFDocumentCore {
} }
// create new document preserving order of entries // 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 docWritten = false;
boolean dataWritten = false; boolean dataWritten = false;
boolean objectPoolWritten = false; boolean objectPoolWritten = false;
@ -967,7 +990,6 @@ public final class HWPFDocument extends HWPFDocumentCore {
if ( !objectPoolWritten ) if ( !objectPoolWritten )
_objectPool.writeTo( pfs.getRoot() ); _objectPool.writeTo( pfs.getRoot() );
pfs.writeFilesystem( out );
this.directory = pfs.getRoot(); this.directory = pfs.getRoot();
/* /*

View File

@ -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
}

View File

@ -50,15 +50,21 @@ public abstract class BaseTestSlideShow {
@Test @Test
public void addPicture_Stream() throws IOException { public void addPicture_Stream() throws IOException {
SlideShow<?,?> show = createSlideShow(); SlideShow<?,?> show = createSlideShow();
try {
InputStream stream = slTests.openResourceAsStream("clock.jpg"); InputStream stream = slTests.openResourceAsStream("clock.jpg");
try {
assertEquals(0, show.getPictureData().size()); assertEquals(0, show.getPictureData().size());
PictureData picture = show.addPicture(stream, PictureType.JPEG); PictureData picture = show.addPicture(stream, PictureType.JPEG);
assertEquals(1, show.getPictureData().size()); assertEquals(1, show.getPictureData().size());
assertSame(picture, show.getPictureData().get(0)); assertSame(picture, show.getPictureData().get(0));
} finally {
stream.close();
}
} finally {
show.close(); show.close();
} }
}
@Test @Test
public void addPicture_ByteArray() throws IOException { public void addPicture_ByteArray() throws IOException {

View File

@ -27,6 +27,7 @@ import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.eval.ErrorEval; 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.Cell;
import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.CellValue; import org.apache.poi.ss.usermodel.CellValue;
@ -105,6 +106,7 @@ public final class TestIndirect {
// non-error cases // non-error cases
confirm(feA, c, "INDIRECT(\"C2\")", 23); confirm(feA, c, "INDIRECT(\"C2\")", 23);
confirm(feA, c, "INDIRECT(\"C2\", TRUE)", 23);
confirm(feA, c, "INDIRECT(\"$C2\")", 23); confirm(feA, c, "INDIRECT(\"$C2\")", 23);
confirm(feA, c, "INDIRECT(\"C$2\")", 23); confirm(feA, c, "INDIRECT(\"C$2\")", 23);
confirm(feA, c, "SUM(INDIRECT(\"Sheet2!B1:C3\"))", 351); // area ref confirm(feA, c, "SUM(INDIRECT(\"Sheet2!B1:C3\"))", 351); // area ref
@ -203,4 +205,9 @@ public final class TestIndirect {
+ "' but got '" + cv.formatAsString() + "'."); + "' but got '" + cv.formatAsString() + "'.");
} }
} }
@Test
public void testInvalidInput() {
assertEquals(ErrorEval.VALUE_INVALID, Indirect.instance.evaluate(new ValueEval[] {}, null));
}
} }

View File

@ -20,9 +20,8 @@ package org.apache.poi.ss.formula.functions;
import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.eval.AreaEval; import org.apache.poi.ss.formula.FormulaParseException;
import org.apache.poi.ss.formula.eval.NumberEval; import org.apache.poi.ss.formula.eval.*;
import org.apache.poi.ss.formula.eval.ValueEval;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.*;
@ -75,7 +74,6 @@ public final class TestSubtotal extends TestCase {
} }
public void testAvg(){ public void testAvg(){
Workbook wb = new HSSFWorkbook(); Workbook wb = new HSSFWorkbook();
FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator(); FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
@ -95,16 +93,18 @@ public final class TestSubtotal extends TestCase {
a6.setCellFormula("SUBTOTAL(1,B2:B6)*2 + 2"); a6.setCellFormula("SUBTOTAL(1,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1); Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(1,B2:B7)"); 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(); fe.evaluateAll();
assertEquals(2.0, a3.getNumericCellValue()); assertEquals(2.0, a3.getNumericCellValue());
assertEquals(8.0, a6.getNumericCellValue()); assertEquals(8.0, a6.getNumericCellValue());
assertEquals(3.0, a7.getNumericCellValue()); assertEquals(3.0, a7.getNumericCellValue());
assertEquals(3.0, a8.getNumericCellValue());
} }
public void testSum(){ public void testSum(){
Workbook wb = new HSSFWorkbook(); Workbook wb = new HSSFWorkbook();
FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator(); FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
@ -124,12 +124,15 @@ public final class TestSubtotal extends TestCase {
a6.setCellFormula("SUBTOTAL(9,B2:B6)*2 + 2"); a6.setCellFormula("SUBTOTAL(9,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1); Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(9,B2:B7)"); 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(); fe.evaluateAll();
assertEquals(4.0, a3.getNumericCellValue()); assertEquals(4.0, a3.getNumericCellValue());
assertEquals(26.0, a6.getNumericCellValue()); assertEquals(26.0, a6.getNumericCellValue());
assertEquals(12.0, a7.getNumericCellValue()); assertEquals(12.0, a7.getNumericCellValue());
assertEquals(12.0, a8.getNumericCellValue());
} }
public void testCount(){ public void testCount(){
@ -147,18 +150,21 @@ public final class TestSubtotal extends TestCase {
a3.setCellFormula("SUBTOTAL(2,B2:B3)"); a3.setCellFormula("SUBTOTAL(2,B2:B3)");
Cell a4 = sh.createRow(4).createCell(1); Cell a4 = sh.createRow(4).createCell(1);
a4.setCellValue("POI"); // A4 is string and not counted 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); Cell a6 = sh.createRow(6).createCell(1);
a6.setCellFormula("SUBTOTAL(2,B2:B6)*2 + 2"); a6.setCellFormula("SUBTOTAL(2,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1); Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(2,B2:B7)"); 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(); fe.evaluateAll();
assertEquals(2.0, a3.getNumericCellValue()); assertEquals(2.0, a3.getNumericCellValue());
assertEquals(6.0, a6.getNumericCellValue()); assertEquals(6.0, a6.getNumericCellValue());
assertEquals(2.0, a7.getNumericCellValue()); assertEquals(2.0, a7.getNumericCellValue());
assertEquals(2.0, a8.getNumericCellValue());
} }
public void testCounta(){ public void testCounta(){
@ -176,18 +182,21 @@ public final class TestSubtotal extends TestCase {
a3.setCellFormula("SUBTOTAL(3,B2:B3)"); a3.setCellFormula("SUBTOTAL(3,B2:B3)");
Cell a4 = sh.createRow(4).createCell(1); Cell a4 = sh.createRow(4).createCell(1);
a4.setCellValue("POI"); // A4 is string and not counted 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); Cell a6 = sh.createRow(6).createCell(1);
a6.setCellFormula("SUBTOTAL(3,B2:B6)*2 + 2"); a6.setCellFormula("SUBTOTAL(3,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1); Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(3,B2:B7)"); 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(); fe.evaluateAll();
assertEquals(2.0, a3.getNumericCellValue()); assertEquals(2.0, a3.getNumericCellValue());
assertEquals(8.0, a6.getNumericCellValue()); assertEquals(8.0, a6.getNumericCellValue());
assertEquals(3.0, a7.getNumericCellValue()); assertEquals(3.0, a7.getNumericCellValue());
assertEquals(3.0, a8.getNumericCellValue());
} }
public void testMax(){ public void testMax(){
@ -211,12 +220,15 @@ public final class TestSubtotal extends TestCase {
a6.setCellFormula("SUBTOTAL(4,B2:B6)*2 + 2"); a6.setCellFormula("SUBTOTAL(4,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1); Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(4,B2:B7)"); 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(); fe.evaluateAll();
assertEquals(3.0, a3.getNumericCellValue()); assertEquals(3.0, a3.getNumericCellValue());
assertEquals(16.0, a6.getNumericCellValue()); assertEquals(16.0, a6.getNumericCellValue());
assertEquals(7.0, a7.getNumericCellValue()); assertEquals(7.0, a7.getNumericCellValue());
assertEquals(7.0, a8.getNumericCellValue());
} }
public void testMin(){ public void testMin(){
@ -240,12 +252,15 @@ public final class TestSubtotal extends TestCase {
a6.setCellFormula("SUBTOTAL(5,B2:B6)*2 + 2"); a6.setCellFormula("SUBTOTAL(5,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1); Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(5,B2:B7)"); 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(); fe.evaluateAll();
assertEquals(1.0, a3.getNumericCellValue()); assertEquals(1.0, a3.getNumericCellValue());
assertEquals(4.0, a6.getNumericCellValue()); assertEquals(4.0, a6.getNumericCellValue());
assertEquals(1.0, a7.getNumericCellValue()); assertEquals(1.0, a7.getNumericCellValue());
assertEquals(1.0, a8.getNumericCellValue());
} }
public void testStdev(){ public void testStdev(){
@ -269,12 +284,15 @@ public final class TestSubtotal extends TestCase {
a6.setCellFormula("SUBTOTAL(7,B2:B6)*2 + 2"); a6.setCellFormula("SUBTOTAL(7,B2:B6)*2 + 2");
Cell a7 = sh.createRow(7).createCell(1); Cell a7 = sh.createRow(7).createCell(1);
a7.setCellFormula("SUBTOTAL(7,B2:B7)"); 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(); fe.evaluateAll();
assertEquals(1.41421, a3.getNumericCellValue(), 0.0001); assertEquals(1.41421, a3.getNumericCellValue(), 0.0001);
assertEquals(7.65685, a6.getNumericCellValue(), 0.0001); assertEquals(7.65685, a6.getNumericCellValue(), 0.0001);
assertEquals(2.82842, a7.getNumericCellValue(), 0.0001); assertEquals(2.82842, a7.getNumericCellValue(), 0.0001);
assertEquals(2.82842, a8.getNumericCellValue(), 0.0001);
} }
public void test50209(){ 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(COUNT;B2:B8,C2:C8)", cellC2, 3.0);
confirmExpectedResult(evaluator, "SUBTOTAL(COUNTA;B2:B8,C2:C8)", cellC3, 5.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));
}
} }

View File

@ -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));
}
}

View File

@ -33,9 +33,12 @@ import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute; import java.awt.font.TextAttribute;
import java.awt.font.TextLayout; import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.text.AttributedString; import java.text.AttributedString;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import static org.junit.Assert.*; 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" 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)); 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);
}
}
} }

View File

@ -201,11 +201,7 @@ public abstract class BaseTestNamedRange {
assertEquals("The sheet already contains this name: aaa", e.getMessage()); assertEquals("The sheet already contains this name: aaa", e.getMessage());
} }
int cnt = 0; assertEquals(3, wb.getNames("aaa").size());
for (int i = 0; i < wb.getNumberOfNames(); i++) {
if("aaa".equals(wb.getNameAt(i).getNameName())) cnt++;
}
assertEquals(3, cnt);
wb.close(); wb.close();
} }
@ -250,11 +246,11 @@ public abstract class BaseTestNamedRange {
// Write the workbook to a file // Write the workbook to a file
// Read the Excel file and verify its content // Read the Excel file and verify its content
Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1); 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("Name is "+nm1.getNameName(),"RangeTest1".equals(nm1.getNameName()));
assertTrue("Reference is "+nm1.getRefersToFormula(),(wb2.getSheetName(0)+"!$A$1:$L$41").equals(nm1.getRefersToFormula())); 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("Name is "+nm2.getNameName(),"RangeTest2".equals(nm2.getNameName()));
assertTrue("Reference is "+nm2.getRefersToFormula(),(wb2.getSheetName(1)+"!$A$1:$O$21").equals(nm2.getRefersToFormula())); 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); wb1.getNameAt(0);
Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1); 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("Name is "+nm.getNameName(),"RangeTest".equals(nm.getNameName()));
assertTrue("Reference is "+nm.getRefersToFormula(),(wb2.getSheetName(0)+"!$D$4:$E$8").equals(nm.getRefersToFormula())); 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("Name is "+nm.getNameName(),"AnotherTest".equals(nm.getNameName()));
assertTrue("Reference is "+nm.getRefersToFormula(),newNamedRange2.getRefersToFormula().equals(nm.getRefersToFormula())); assertTrue("Reference is "+nm.getRefersToFormula(),newNamedRange2.getRefersToFormula().equals(nm.getRefersToFormula()));
@ -499,8 +495,7 @@ public abstract class BaseTestNamedRange {
namedCell.setRefersToFormula(reference); namedCell.setRefersToFormula(reference);
// retrieve the newly created named range // retrieve the newly created named range
int namedCellIdx = wb.getNameIndex(cellName); Name aNamedCell = wb.getName(cellName);
Name aNamedCell = wb.getNameAt(namedCellIdx);
assertNotNull(aNamedCell); assertNotNull(aNamedCell);
// retrieve the cell at the named range and test its contents // retrieve the cell at the named range and test its contents
@ -540,8 +535,7 @@ public abstract class BaseTestNamedRange {
namedCell.setRefersToFormula(reference); namedCell.setRefersToFormula(reference);
// retrieve the newly created named range // retrieve the newly created named range
int namedCellIdx = wb.getNameIndex(cname); Name aNamedCell = wb.getName(cname);
Name aNamedCell = wb.getNameAt(namedCellIdx);
assertNotNull(aNamedCell); assertNotNull(aNamedCell);
// retrieve the cell at the named range and test its contents // retrieve the cell at the named range and test its contents

View File

@ -261,17 +261,17 @@ public abstract class BaseTestSheetShiftRows {
name4.setSheetIndex(1); name4.setSheetIndex(1);
sheet1.shiftRows(0, 1, 2); //shift down the top row on Sheet1. 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()); assertEquals("Sheet1!$A$3+Sheet1!$B$3", name1.getRefersToFormula());
name2 = wb.getNameAt(1); name2 = wb.getName("name2");
assertEquals("Sheet1!$A$3", name2.getRefersToFormula()); assertEquals("Sheet1!$A$3", name2.getRefersToFormula());
//name3 and name4 refer to Sheet2 and should not be affected //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()); assertEquals("Sheet2!$A$1", name3.getRefersToFormula());
name4 = wb.getNameAt(3); name4 = wb.getName("name4");
assertEquals("A1", name4.getRefersToFormula()); assertEquals("A1", name4.getRefersToFormula());
wb.close(); wb.close();

View File

@ -78,15 +78,17 @@ public class BaseTestCellUtil {
@Test(expected=RuntimeException.class) @Test(expected=RuntimeException.class)
public void setCellStylePropertyWithInvalidValue() throws IOException { public void setCellStylePropertyWithInvalidValue() throws IOException {
Workbook wb = _testDataProvider.createWorkbook(); Workbook wb = _testDataProvider.createWorkbook();
try {
Sheet s = wb.createSheet(); Sheet s = wb.createSheet();
Row r = s.createRow(0); Row r = s.createRow(0);
Cell c = r.createCell(0); Cell c = r.createCell(0);
// An invalid BorderStyle constant // An invalid BorderStyle constant
CellUtil.setCellStyleProperty(c, CellUtil.BORDER_BOTTOM, 42); CellUtil.setCellStyleProperty(c, CellUtil.BORDER_BOTTOM, 42);
} finally {
wb.close(); wb.close();
} }
}
@Test() @Test()
public void setCellStylePropertyBorderWithShortAndEnum() throws IOException { public void setCellStylePropertyBorderWithShortAndEnum() throws IOException {
@ -352,10 +354,8 @@ public class BaseTestCellUtil {
CellUtil.setFont(A1, font2); CellUtil.setFont(A1, font2);
fail("setFont not allowed if font belongs to a different workbook"); fail("setFont not allowed if font belongs to a different workbook");
} catch (final IllegalArgumentException e) { } catch (final IllegalArgumentException e) {
if (e.getMessage().startsWith("Font does not belong to this workbook")) { // one specific message is expected
// expected if (!e.getMessage().startsWith("Font does not belong to this workbook")) {
}
else {
throw e; throw e;
} }
} finally { } finally {
@ -371,7 +371,7 @@ public class BaseTestCellUtil {
*/ */
// bug 55555 // bug 55555
@Test @Test
public void setFillForegroundColorBeforeFillBackgroundColor() { public void setFillForegroundColorBeforeFillBackgroundColor() throws IOException {
Workbook wb1 = _testDataProvider.createWorkbook(); Workbook wb1 = _testDataProvider.createWorkbook();
Cell A1 = wb1.createSheet().createRow(0).createCell(0); Cell A1 = wb1.createSheet().createRow(0).createCell(0);
Map<String, Object> properties = new HashMap<String, Object>(); Map<String, Object> properties = new HashMap<String, Object>();
@ -386,13 +386,14 @@ public class BaseTestCellUtil {
assertEquals("fill pattern", CellStyle.BRICKS, style.getFillPattern()); assertEquals("fill pattern", CellStyle.BRICKS, style.getFillPattern());
assertEquals("fill foreground color", IndexedColors.BLUE, IndexedColors.fromInt(style.getFillForegroundColor())); assertEquals("fill foreground color", IndexedColors.BLUE, IndexedColors.fromInt(style.getFillForegroundColor()));
assertEquals("fill background color", IndexedColors.RED, IndexedColors.fromInt(style.getFillBackgroundColor())); assertEquals("fill background color", IndexedColors.RED, IndexedColors.fromInt(style.getFillBackgroundColor()));
wb1.close();
} }
/** /**
* bug 55555 * bug 55555
* @since POI 3.15 beta 3 * @since POI 3.15 beta 3
*/ */
@Test @Test
public void setFillForegroundColorBeforeFillBackgroundColorEnum() { public void setFillForegroundColorBeforeFillBackgroundColorEnum() throws IOException {
Workbook wb1 = _testDataProvider.createWorkbook(); Workbook wb1 = _testDataProvider.createWorkbook();
Cell A1 = wb1.createSheet().createRow(0).createCell(0); Cell A1 = wb1.createSheet().createRow(0).createCell(0);
Map<String, Object> properties = new HashMap<String, Object>(); Map<String, Object> properties = new HashMap<String, Object>();
@ -407,5 +408,7 @@ public class BaseTestCellUtil {
assertEquals("fill pattern", FillPatternType.BRICKS, style.getFillPatternEnum()); assertEquals("fill pattern", FillPatternType.BRICKS, style.getFillPatternEnum());
assertEquals("fill foreground color", IndexedColors.BLUE, IndexedColors.fromInt(style.getFillForegroundColor())); assertEquals("fill foreground color", IndexedColors.BLUE, IndexedColors.fromInt(style.getFillForegroundColor()));
assertEquals("fill background color", IndexedColors.RED, IndexedColors.fromInt(style.getFillBackgroundColor())); assertEquals("fill background color", IndexedColors.RED, IndexedColors.fromInt(style.getFillBackgroundColor()));
wb1.close();
} }
} }

View File

@ -30,16 +30,20 @@ public class DummyPOILogger extends POILogger {
logged = new ArrayList<String>(); logged = new ArrayList<String>();
} }
@Override
public boolean check(int level) { public boolean check(int level) {
return true; return true;
} }
@Override
public void initialize(String cat) {} public void initialize(String cat) {}
@Override
public void log(int level, Object obj1) { public void log(int level, Object obj1) {
logged.add(level + " - " + obj1); logged.add(level + " - " + obj1);
} }
@Override
public void log(int level, Object obj1, Throwable exception) { public void log(int level, Object obj1, Throwable exception) {
logged.add(level + " - " + obj1 + " - " + exception); logged.add(level + " - " + obj1 + " - " + exception);
} }

View File

@ -26,10 +26,6 @@ import org.junit.Test;
/** /**
* Tests the log class. * 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 { public final class TestPOILogger extends POILogger {
private String lastLog = ""; private String lastLog = "";
@ -62,19 +58,25 @@ public final class TestPOILogger extends POILogger {
} }
} }
// ---------- POI Logger methods implemented for testing ----------
@Override
public void initialize(String cat) { public void initialize(String cat) {
} }
@Override
public void log(int level, Object obj1) { public void log(int level, Object obj1) {
lastLog = (obj1 == null) ? "" : obj1.toString(); lastLog = (obj1 == null) ? "" : obj1.toString();
lastEx = null; lastEx = null;
} }
@Override
public void log(int level, Object obj1, Throwable exception) { public void log(int level, Object obj1, Throwable exception) {
lastLog = (obj1 == null) ? "" : obj1.toString(); lastLog = (obj1 == null) ? "" : obj1.toString();
lastEx = exception; lastEx = exception;
} }
@Override
public boolean check(int level) { public boolean check(int level) {
return true; return true;
} }

Binary file not shown.