mirror of https://github.com/apache/poi.git
merge trunk
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1848906 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
11cbe34ee5
commit
fce876b4ef
387
build.xml
387
build.xml
|
@ -60,6 +60,10 @@ under the License.
|
|||
<property name="jdk.version.class" value="1.8" description="JDK version of generated class files"/>
|
||||
<property name="compile.debug" value="true"/>
|
||||
|
||||
<condition property="isIBMVM">
|
||||
<contains string="${java.vendor}" substring="IBM" casesensitive="false"/>
|
||||
</condition>
|
||||
|
||||
<!--
|
||||
Logging is suppressed by default.
|
||||
To redirect log output to console, run ant with -Dorg.apache.poi.util.POILogger=org.apache.poi.util.SystemOutLogger
|
||||
|
@ -342,17 +346,6 @@ under the License.
|
|||
<propertyref name="scratchpad.ignore"/>
|
||||
</propertyset>
|
||||
|
||||
<!-- these need to be set differently when running with Java 9 -->
|
||||
<property name="java9addmods" value="-Dthis.is.a.dummy=true"/>
|
||||
<property name="javadoc9addmods" value="-J-Dthis.is.a.dummy=true"/>
|
||||
<property name="java9addmodsvalue" value="-Dthis.is.a.dummy=true"/>
|
||||
<property name="java9addopens1" value="-Dthis.is.a.dummy=true"/>
|
||||
<property name="java9addopens2" value="-Dthis.is.a.dummy=true"/>
|
||||
<property name="java9addopens3" value="-Dthis.is.a.dummy=true"/>
|
||||
<property name="java9addopens4" value="-Dthis.is.a.dummy=true"/>
|
||||
<property name="java9addopens5" value="-Dthis.is.a.dummy=true"/>
|
||||
<property name="java9addopens6" value="-Dthis.is.a.dummy=true"/>
|
||||
|
||||
<path id="main.classpath">
|
||||
<pathelement location="${main.commons-logging.jar}"/>
|
||||
<pathelement location="${main.commons-codec.jar}"/>
|
||||
|
@ -1180,6 +1173,59 @@ under the License.
|
|||
</copy>
|
||||
</target>
|
||||
|
||||
<macrodef name="poiunit" xmlns:jacoco="antlib:org.jacoco.ant">
|
||||
<attribute name="failureproperty"/>
|
||||
<attribute name="heap" default="512"/>
|
||||
<attribute name="showoutput" default="false"/>
|
||||
<attribute name="jacocodest" default="build/jacoco-dest.exec"/>
|
||||
<element name="elements" implicit="true"/>
|
||||
<sequential>
|
||||
<local name="no.jit.sherlock"/>
|
||||
<!-- see http://www-01.ibm.com/support/docview.wss?uid=swg21294023 on how to determine the method strings -->
|
||||
<property name="no.jit.sherlock">
|
||||
sun/java2d/pipe/AAShapePipe.renderTiles(Lsun/java2d/SunGraphics2D;Ljava/awt/Shape;Lsun/java2d/pipe/AATileGenerator;[I)V
|
||||
sun/java2d/pipe/AlphaPaintPipe.renderPathTile(Ljava/lang/Object;[BIIIIII)V
|
||||
java/awt/TexturePaintContext.getRaster(IIII)Ljava/awt/image/Raster;
|
||||
</property>
|
||||
<script language="javascript">
|
||||
var before = project.getProperty("no.jit.sherlock");
|
||||
project.setProperty("no.jit.sherlock", before.trim().replace(/ *(\S+) */g,"exclude={$1}").replace(/\s/g,","));
|
||||
</script>
|
||||
|
||||
<local name="ooxml.lite.agent.exists"/>
|
||||
<available property="ooxml.lite.agent.exists" file="${ooxml.lite.agent}"/>
|
||||
|
||||
<jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="@{jacocodest}">
|
||||
<junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
|
||||
failureproperty="@{failureproperty}" showoutput="@{showoutput}">
|
||||
<syspropertyset refid="junit.properties"/>
|
||||
<sysproperty key="java.io.tmpdir" value="${tempdir}"/>
|
||||
<jvmarg value="-Xmx@{heap}M"/>
|
||||
<jvmarg value="-ea"/>
|
||||
|
||||
<!-- these need to be set differently when running with Java 9 -->
|
||||
<jvmarg value="${java9addmods}" if:set="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" if:set="${java9addmodsvalue}" />
|
||||
<jvmarg value="${java9addopens1}" if:set="${java9addopens1}" />
|
||||
<jvmarg value="${java9addopens2}" if:set="${java9addopens2}" />
|
||||
<jvmarg value="${java9addopens3}" if:set="${java9addopens3}" />
|
||||
<jvmarg value="${java9addopens4}" if:set="${java9addopens4}" />
|
||||
<jvmarg value="${java9addopens5}" if:set="${java9addopens5}" />
|
||||
<jvmarg value="${java9addopens6}" if:set="${java9addopens6}" />
|
||||
|
||||
<jvmarg value="-javaagent:${ooxml.lite.agent}=${ooxml.lite.report}|${ooxml.lite.includes}" if:true="${ooxml.lite.agent.exists}"/>
|
||||
|
||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||
<jvmarg value="${file.leak.detector}" />
|
||||
<jvmarg value="-Xjit:verbose={compileStart|compileEnd},vlog=build/jit.log,${no.jit.sherlock}" if:true="${isIBMVM}"/>
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<elements/>
|
||||
</junit>
|
||||
</jacoco:coverage>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<target name="retest-ooxml" depends="jar">
|
||||
<delete dir="${ooxml.reports.test}"/>
|
||||
<delete dir="${ooxml.output.test.dir}"/>
|
||||
|
@ -1219,39 +1265,23 @@ under the License.
|
|||
<copy todir="${ooxml.output.dir}">
|
||||
<fileset dir="${ooxml.resource1.dir}"/>
|
||||
</copy>
|
||||
<junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
|
||||
failureproperty="ooxml.test.failed">
|
||||
|
||||
<poiunit failureproperty="ooxml.test.failed" heap="768">
|
||||
<classpath>
|
||||
<path refid="test.ooxml.lite.verify.classpath"/>
|
||||
<path refid="test.jar.classpath"/>
|
||||
</classpath>
|
||||
<syspropertyset refid="junit.properties"/>
|
||||
<sysproperty key="java.io.tmpdir" value="${tempdir}"/>
|
||||
<jvmarg value="-Xmx768M"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<jvmarg value="${java9addopens1}" />
|
||||
<jvmarg value="${java9addopens2}" />
|
||||
<jvmarg value="${java9addopens3}" />
|
||||
<jvmarg value="${java9addopens4}" />
|
||||
<jvmarg value="${java9addopens5}" />
|
||||
<jvmarg value="${java9addopens6}" />
|
||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||
<jvmarg value="${file.leak.detector}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${ooxml.reports.test}">
|
||||
<fileset dir="${ooxml.src.test}">
|
||||
<include name="**/${testpattern}.java"/>
|
||||
<exclude name="**/TestUnfixedBugs.java"/>
|
||||
<exclude name="**/All*Tests.java"/>
|
||||
<exclude name="**/TestSignatureInfo.java"/>
|
||||
<exclude name="**/${testexcludepattern}.java"/>
|
||||
<patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
|
||||
<include name="**/${testpattern}.java"/>
|
||||
<exclude name="**/TestUnfixedBugs.java"/>
|
||||
<exclude name="**/All*Tests.java"/>
|
||||
<exclude name="**/TestSignatureInfo.java"/>
|
||||
<exclude name="**/${testexcludepattern}.java"/>
|
||||
<patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
</poiunit>
|
||||
</target>
|
||||
|
||||
<target name="compile-excelant" depends="compile-main,compile-ooxml">
|
||||
|
@ -1306,6 +1336,7 @@ under the License.
|
|||
<pathelement location="${main.ant.jar}"/>
|
||||
<pathelement location="${scratchpad.output.dir}"/>
|
||||
</classpath>
|
||||
<exclude name="**/HeapDump**" if:true="${isIBMVM}"/>
|
||||
</javac>
|
||||
<!--copy todir="${integration.output.dir}">
|
||||
<fileset dir="${integration.resource1.dir}"/>
|
||||
|
@ -1436,39 +1467,22 @@ under the License.
|
|||
<target name="test-main" unless="main.test.notRequired"
|
||||
depends="compile-main, -test-main-check,jacocotask" xmlns:jacoco="antlib:org.jacoco.ant"
|
||||
description="tests POI classes that deal with the Microsoft Office binary (BIFF8) file formats (excludes OOXML)">
|
||||
<jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-main.exec">
|
||||
<junit fork="yes" forkmode="once" printsummary="yes" haltonfailure="${halt.on.test.failure}"
|
||||
failureproperty="main.test.failed" showoutput="true">
|
||||
<classpath refid="test.classpath"/>
|
||||
<classpath refid="test.jar.classpath"/>
|
||||
<syspropertyset refid="junit.properties"/>
|
||||
<sysproperty key="java.io.tmpdir" value="${tempdir}"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="-Xmx256m"/>
|
||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<jvmarg value="${java9addopens1}" />
|
||||
<jvmarg value="${java9addopens2}" />
|
||||
<jvmarg value="${java9addopens3}" />
|
||||
<jvmarg value="${java9addopens4}" />
|
||||
<jvmarg value="${java9addopens5}" />
|
||||
<jvmarg value="${java9addopens6}" />
|
||||
<jvmarg value="${file.leak.detector}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${main.reports.test}">
|
||||
<fileset dir="${main.src.test}">
|
||||
<include name="**/${testpattern}.java"/>
|
||||
<exclude name="**/All*Tests.java"/>
|
||||
<exclude name="**/TestUnfixedBugs.java"/>
|
||||
<exclude name="**/TestcaseRecordInputStream.java"/>
|
||||
<exclude name="**/${testexcludepattern}.java"/>
|
||||
<patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
</jacoco:coverage>
|
||||
<poiunit failureproperty="main.test.failed" heap="256" showoutput="true" jacocodest="build/jacoco-main.exec">
|
||||
<classpath>
|
||||
<path refid="test.classpath"/>
|
||||
<path refid="test.jar.classpath"/>
|
||||
</classpath>
|
||||
<batchtest todir="${main.reports.test}">
|
||||
<fileset dir="${main.src.test}">
|
||||
<include name="**/${testpattern}.java"/>
|
||||
<exclude name="**/All*Tests.java"/>
|
||||
<exclude name="**/TestUnfixedBugs.java"/>
|
||||
<exclude name="**/TestcaseRecordInputStream.java"/>
|
||||
<exclude name="**/${testexcludepattern}.java"/>
|
||||
<patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</poiunit>
|
||||
<delete file="${main.testokfile}"/>
|
||||
<antcall target="-test-main-write-testfile"/>
|
||||
</target>
|
||||
|
@ -1500,45 +1514,23 @@ under the License.
|
|||
</uptodate>
|
||||
</target>
|
||||
|
||||
<target name="test-scratchpad" depends="compile-main,compile-scratchpad,-test-scratchpad-check,jacocotask,test-scratchpad-download-resources"
|
||||
<target name="test-scratchpad" depends="compile-main,compile-scratchpad,-test-scratchpad-check,test-scratchpad-download-resources"
|
||||
unless="scratchpad.test.notRequired" xmlns:jacoco="antlib:org.jacoco.ant"
|
||||
description="test non-OOXML scratchpad classes">
|
||||
<jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-scratchpad.exec">
|
||||
<junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
|
||||
failureproperty="scratchpad.test.failed">
|
||||
<classpath refid="test.scratchpad.classpath"/>
|
||||
<classpath refid="test.jar.classpath"/>
|
||||
<syspropertyset refid="junit.properties"/>
|
||||
<sysproperty key="java.io.tmpdir" value="${tempdir}"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||
<jvmarg value="${file.leak.detector}" />
|
||||
<!--
|
||||
YK: ensure that JUnit has enough memory to run tests.
|
||||
Without the line below tests fail on Mac OS X with jdk-1.6.26
|
||||
and on Windows with jdk-1.5.22
|
||||
-->
|
||||
<jvmarg value="-Xmx512m"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<jvmarg value="${java9addopens1}" />
|
||||
<jvmarg value="${java9addopens2}" />
|
||||
<jvmarg value="${java9addopens3}" />
|
||||
<jvmarg value="${java9addopens4}" />
|
||||
<jvmarg value="${java9addopens5}" />
|
||||
<jvmarg value="${java9addopens6}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${scratchpad.reports.test}">
|
||||
<fileset dir="${scratchpad.src.test}">
|
||||
<include name="**/${testpattern}.java"/>
|
||||
<exclude name="**/AllTests.java"/>
|
||||
<exclude name="**/${testexcludepattern}.java"/>
|
||||
<patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
</jacoco:coverage>
|
||||
<poiunit failureproperty="scratchpad.test.failed" heap="512" jacocodest="build/jacoco-scratchpad.exec">
|
||||
<classpath>
|
||||
<path refid="test.scratchpad.classpath"/>
|
||||
<path refid="test.jar.classpath"/>
|
||||
</classpath>
|
||||
<batchtest todir="${scratchpad.reports.test}">
|
||||
<fileset dir="${scratchpad.src.test}">
|
||||
<include name="**/${testpattern}.java"/>
|
||||
<exclude name="**/AllTests.java"/>
|
||||
<exclude name="**/${testexcludepattern}.java"/>
|
||||
<patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</poiunit>
|
||||
<delete file="${scratchpad.testokfile}"/>
|
||||
<antcall target="-test-scratchpad-write-testfile"/>
|
||||
</target>
|
||||
|
@ -1559,72 +1551,35 @@ under the License.
|
|||
<attribute name="classpath"/>
|
||||
<attribute name="type"/>
|
||||
<sequential>
|
||||
<jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-@{type}.exec">
|
||||
<junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
|
||||
failureproperty="ooxml.test.failed">
|
||||
<classpath>
|
||||
<path refid="@{classpath}"/>
|
||||
<path refid="test.jar.classpath"/>
|
||||
</classpath>
|
||||
<syspropertyset refid="junit.properties"/>
|
||||
<sysproperty key="java.io.tmpdir" value="${tempdir}"/>
|
||||
<jvmarg value="-Xmx768M"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="-javaagent:${ooxml.lite.agent}=${ooxml.lite.report}|${ooxml.lite.includes}"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<jvmarg value="${java9addopens1}" />
|
||||
<jvmarg value="${java9addopens2}" />
|
||||
<jvmarg value="${java9addopens3}" />
|
||||
<jvmarg value="${java9addopens4}" />
|
||||
<jvmarg value="${java9addopens5}" />
|
||||
<jvmarg value="${java9addopens6}" />
|
||||
<!-- jvmarg value="-Duser.timezone=UTC"/ -->
|
||||
<jvmarg value="${file.leak.detector}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${ooxml.reports.test}">
|
||||
<fileset dir="${ooxml.src.test}">
|
||||
<include name="**/${testpattern}.java"/>
|
||||
<exclude name="**/TestUnfixedBugs.java"/>
|
||||
<exclude name="**/All*Tests.java"/>
|
||||
<exclude name="**/TestSignatureInfo.java"/>
|
||||
<exclude name="**/${testexcludepattern}.java"/>
|
||||
<patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
</jacoco:coverage>
|
||||
<jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-@{type}-xmlsec.exec">
|
||||
<junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
|
||||
failureproperty="ooxml.xmlsec.test.failed">
|
||||
<classpath>
|
||||
<path refid="@{classpath}"/>
|
||||
<path refid="test.jar.classpath"/>
|
||||
<path refid="ooxml.xmlsec.classpath"/>
|
||||
</classpath>
|
||||
<syspropertyset refid="junit.properties"/>
|
||||
<sysproperty key="java.io.tmpdir" value="${tempdir}"/>
|
||||
<jvmarg value="-javaagent:${ooxml.lite.agent}=${ooxml.lite.report}|${ooxml.lite.includes}"/>
|
||||
<jvmarg value="-Xmx768M"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<jvmarg value="${java9addopens1}" />
|
||||
<jvmarg value="${java9addopens2}" />
|
||||
<jvmarg value="${java9addopens3}" />
|
||||
<jvmarg value="${java9addopens4}" />
|
||||
<jvmarg value="${java9addopens5}" />
|
||||
<jvmarg value="${java9addopens6}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${ooxml.reports.test}">
|
||||
<fileset dir="${ooxml.src.test}">
|
||||
<include name="**/TestSignatureInfo.java"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
</jacoco:coverage>
|
||||
<poiunit failureproperty="ooxml.test.failed" heap="768" jacocodest="build/jacoco-@{type}.exec">
|
||||
<classpath>
|
||||
<path refid="@{classpath}"/>
|
||||
<path refid="test.jar.classpath"/>
|
||||
</classpath>
|
||||
<batchtest todir="${ooxml.reports.test}">
|
||||
<fileset dir="${ooxml.src.test}">
|
||||
<include name="**/${testpattern}.java"/>
|
||||
<exclude name="**/TestUnfixedBugs.java"/>
|
||||
<exclude name="**/All*Tests.java"/>
|
||||
<exclude name="**/TestSignatureInfo.java"/>
|
||||
<exclude name="**/${testexcludepattern}.java"/>
|
||||
<patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</poiunit>
|
||||
|
||||
<poiunit failureproperty="ooxml.xmlsec.test.failed" heap="768" jacocodest="build/jacoco-@{type}-xmlsec.exec">
|
||||
<classpath>
|
||||
<path refid="@{classpath}"/>
|
||||
<path refid="test.jar.classpath"/>
|
||||
<path refid="ooxml.xmlsec.classpath"/>
|
||||
</classpath>
|
||||
<batchtest todir="${ooxml.reports.test}">
|
||||
<fileset dir="${ooxml.src.test}">
|
||||
<include name="**/TestSignatureInfo.java"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</poiunit>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
|
@ -1650,34 +1605,16 @@ under the License.
|
|||
unless="integration.test.notRequired" xmlns:jacoco="antlib:org.jacoco.ant">
|
||||
<propertyreset name="org.apache.poi.util.POILogger" value="org.apache.poi.util.CommonsLogger"/>
|
||||
<delete dir="build" includes="test-integration.log*"/>
|
||||
<jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-integration.exec">
|
||||
<junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
|
||||
failureproperty="integration.test.failed" showoutput="true">
|
||||
<classpath refid="test.integration.classpath"/>
|
||||
<syspropertyset refid="junit.properties"/>
|
||||
<sysproperty key="java.io.tmpdir" value="${tempdir}"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="-Xmx1512M"/>
|
||||
<jvmarg value="-javaagent:${ooxml.lite.agent}=${ooxml.lite.report}|${ooxml.lite.includes}"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<jvmarg value="${java9addopens1}" />
|
||||
<jvmarg value="${java9addopens2}" />
|
||||
<jvmarg value="${java9addopens3}" />
|
||||
<jvmarg value="${java9addopens4}" />
|
||||
<jvmarg value="${java9addopens5}" />
|
||||
<jvmarg value="${java9addopens6}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${integration.reports.test}">
|
||||
<fileset dir="${integration.src.test}">
|
||||
<include name="**/${testpattern}.java"/>
|
||||
<exclude name="**/${testexcludepattern}.java"/>
|
||||
<patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
</jacoco:coverage>
|
||||
<poiunit failureproperty="integration.test.failed" heap="1512" showoutput="true" jacocodest="build/jacoco-integration.exec">
|
||||
<classpath refid="test.integration.classpath"/>
|
||||
<batchtest todir="${integration.reports.test}">
|
||||
<fileset dir="${integration.src.test}">
|
||||
<include name="**/${testpattern}.java"/>
|
||||
<exclude name="**/${testexcludepattern}.java"/>
|
||||
<patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</poiunit>
|
||||
<delete file="${integration.testokfile}"/>
|
||||
<antcall target="-test-integration-write-testfile"/>
|
||||
</target>
|
||||
|
@ -1739,33 +1676,16 @@ under the License.
|
|||
|
||||
<target name="test-excelant" depends="compile-excelant,-test-excelant-check,jacocotask"
|
||||
unless="excelant.test.notRequired" xmlns:jacoco="antlib:org.jacoco.ant">
|
||||
<jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-excelant.exec">
|
||||
<junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
|
||||
failureproperty="excelant.test.failed">
|
||||
<classpath refid="test.excelant.classpath"/>
|
||||
<syspropertyset refid="junit.properties"/>
|
||||
<sysproperty key="java.io.tmpdir" value="${tempdir}"/>
|
||||
<jvmarg value="-ea"/>
|
||||
<jvmarg value="${java9addmods}" />
|
||||
<jvmarg value="${java9addmodsvalue}" />
|
||||
<jvmarg value="${java9addopens1}" />
|
||||
<jvmarg value="${java9addopens2}" />
|
||||
<jvmarg value="${java9addopens3}" />
|
||||
<jvmarg value="${java9addopens4}" />
|
||||
<jvmarg value="${java9addopens5}" />
|
||||
<jvmarg value="${java9addopens6}" />
|
||||
<jvmarg value="${file.leak.detector}" />
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
<batchtest todir="${excelant.reports.test}">
|
||||
<fileset dir="${excelant.src.test}">
|
||||
<include name="**/${testpattern}.java"/>
|
||||
<exclude name="**/${testexcludepattern}.java"/>
|
||||
<patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
</jacoco:coverage>
|
||||
<poiunit failureproperty="excelant.test.failed" jacocodest="build/jacoco-excelant.exec">
|
||||
<classpath refid="test.excelant.classpath"/>
|
||||
<batchtest todir="${excelant.reports.test}">
|
||||
<fileset dir="${excelant.src.test}">
|
||||
<include name="**/${testpattern}.java"/>
|
||||
<exclude name="**/${testexcludepattern}.java"/>
|
||||
<patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</poiunit>
|
||||
<delete file="${excelant.testokfile}"/>
|
||||
<antcall target="-test-excelant-write-testfile"/>
|
||||
</target>
|
||||
|
@ -1791,6 +1711,9 @@ under the License.
|
|||
<target name="docs" depends="init, -check-forrest-installed, -check-docs, javadocs, -forrest-docs"
|
||||
unless="main.docs.notRequired"
|
||||
description="Builds the POI website" />
|
||||
|
||||
<target name="site" depends="-forrest-docs"/>
|
||||
|
||||
<target name="-forrest-docs" depends="-check-forrest-installed, -check-docs"
|
||||
unless="main.docs.notRequired" description="Builds the HTML pages of the POI website">
|
||||
<exec executable="${env.FORREST_HOME}/bin/forrest" osfamily="unix"/>
|
||||
|
@ -1828,7 +1751,7 @@ under the License.
|
|||
<include name="org/apache/poi/**"/>
|
||||
</packageset>
|
||||
|
||||
<arg value="${javadoc9addmods}"/>
|
||||
<arg value="${javadoc9addmods}" if:set="${javadoc9addmods}"/>
|
||||
|
||||
<doctitle><![CDATA[<h1>POI API Documentation</h1>]]></doctitle>
|
||||
<bottom>
|
||||
|
@ -2113,6 +2036,7 @@ under the License.
|
|||
sonar/*/src/**,
|
||||
compile-lib/**,
|
||||
ooxml-lib/**,
|
||||
ooxml-testlib/**,
|
||||
scripts/**,
|
||||
TEST*,
|
||||
*.ipr,
|
||||
|
@ -2303,7 +2227,10 @@ under the License.
|
|||
</forbiddenapis>
|
||||
</target>
|
||||
|
||||
<target name="findbugs" depends="jar">
|
||||
<!-- disabling findbugs until jenkins is updated to a current IBM JDK
|
||||
see https://stackoverflow.com/a/48561534/2066598
|
||||
this should be replaced by spotbugs when available in the jenkins warnings plugin -->
|
||||
<target name="findbugs" depends="jar" unless="${isIBMVM}">
|
||||
<downloadfile src="${findbugs.url}" dest="${findbugs.jar}"/>
|
||||
|
||||
<property name="findbugs.home" value="build/findbugs" />
|
||||
|
@ -2453,7 +2380,7 @@ under the License.
|
|||
<copy todir="${repo}">
|
||||
<mappedresources>
|
||||
<!-- add sha-512 when nexus rules are updated (1/2) -->
|
||||
<fileset dir="build/dist/maven" includes="@{artifactId}/**" excludes="**/*.sha512"/>
|
||||
<fileset dir="build/dist/maven" includes="@{artifactId}/**" excludes="**/*.sha512,**/*.sha256"/>
|
||||
<regexpmapper from="^([^/]+)/(.*)$$" to="org/apache/poi/\1/${version.id}/\2" handledirsep="true"/>
|
||||
</mappedresources>
|
||||
</copy>
|
||||
|
|
|
@ -35,6 +35,13 @@
|
|||
<programming-language>Java</programming-language>
|
||||
<category rdf:resource="https://projects.apache.org/category/content" />
|
||||
<category rdf:resource="https://projects.apache.org/category/library" />
|
||||
<release>
|
||||
<Version>
|
||||
<name>Apache POI 4.0.1</name>
|
||||
<created>2018-12-03</created>
|
||||
<revision>4.0.1</revision>
|
||||
</Version>
|
||||
</release>
|
||||
<release>
|
||||
<Version>
|
||||
<name>Apache POI 4.0.0</name>
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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.xslf.usermodel;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
|
||||
import org.apache.poi.xddf.usermodel.chart.AxisPosition;
|
||||
import org.apache.poi.xddf.usermodel.chart.BarDirection;
|
||||
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
|
||||
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFChart;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFChartAxis;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
|
||||
|
||||
/**
|
||||
* Build a chart without reading template file
|
||||
*/
|
||||
public class ChartFromScratch {
|
||||
private static void usage(){
|
||||
System.out.println("Usage: BarChartExample <bar-chart-data.txt>");
|
||||
System.out.println(" bar-chart-data.txt the model to set. First line is chart title, " +
|
||||
"then go pairs {axis-label value}");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if(args.length < 1) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
try (BufferedReader modelReader = new BufferedReader(new FileReader(args[0]))) {
|
||||
|
||||
String chartTitle = modelReader.readLine(); // first line is chart title
|
||||
String[] series = modelReader.readLine().split(",");
|
||||
|
||||
// Category Axis Data
|
||||
List<String> listLanguages = new ArrayList<>(10);
|
||||
|
||||
// Values
|
||||
List<Double> listCountries = new ArrayList<>(10);
|
||||
List<Double> listSpeakers = new ArrayList<>(10);
|
||||
|
||||
// set model
|
||||
String ln;
|
||||
while((ln = modelReader.readLine()) != null) {
|
||||
String[] vals = ln.split(",");
|
||||
listCountries.add(Double.valueOf(vals[0]));
|
||||
listSpeakers.add(Double.valueOf(vals[1]));
|
||||
listLanguages.add(vals[2]);
|
||||
}
|
||||
|
||||
String[] categories = listLanguages.toArray(new String[listLanguages.size()]);
|
||||
Double[] values1 = listCountries.toArray(new Double[listCountries.size()]);
|
||||
Double[] values2 = listSpeakers.toArray(new Double[listSpeakers.size()]);
|
||||
|
||||
try {
|
||||
|
||||
XMLSlideShow ppt = new XMLSlideShow();
|
||||
XSLFSlide slide = ppt.createSlide();
|
||||
XSLFChart chart = ppt.createChart();
|
||||
Rectangle2D rect2D = new java.awt.Rectangle(XDDFChart.DEFAULT_X, XDDFChart.DEFAULT_Y,
|
||||
XDDFChart.DEFAULT_WIDTH, XDDFChart.DEFAULT_HEIGHT);
|
||||
slide.addChart(chart, rect2D);
|
||||
setBarData(chart, chartTitle, series, categories, values1, values2);
|
||||
// save the result
|
||||
try (OutputStream out = new FileOutputStream("bar-chart-demo-output.pptx")) {
|
||||
ppt.write(out);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
System.out.println("Done");
|
||||
}
|
||||
|
||||
private static void setBarData(XSLFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
|
||||
// Use a category axis for the bottom axis.
|
||||
XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
|
||||
bottomAxis.setTitle(series[2]);
|
||||
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
|
||||
leftAxis.setTitle(series[0]+","+series[1]);
|
||||
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
|
||||
|
||||
final int numOfPoints = categories.length;
|
||||
final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
|
||||
final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
|
||||
final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
|
||||
final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
|
||||
final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, 1);
|
||||
values1[6] = 16.0; // if you ever want to change the underlying data
|
||||
final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);
|
||||
|
||||
|
||||
XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
|
||||
XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData);
|
||||
series1.setTitle(series[0], chart.setSheetTitle(series[0], 1));
|
||||
|
||||
XDDFBarChartData.Series series2 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData2);
|
||||
series2.setTitle(series[1], chart.setSheetTitle(series[1], 2));
|
||||
|
||||
bar.setVaryColors(true);
|
||||
bar.setBarDirection(BarDirection.COL);
|
||||
chart.plot(bar);
|
||||
|
||||
XDDFChartLegend legend = chart.getOrAddLegend();
|
||||
legend.setPosition(LegendPosition.LEFT);
|
||||
legend.setOverlay(false);
|
||||
|
||||
chart.setTitleText(chartTitle);
|
||||
chart.setTitleOverlay(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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.xwpf.usermodel.examples;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
|
||||
import org.apache.poi.xddf.usermodel.chart.AxisPosition;
|
||||
import org.apache.poi.xddf.usermodel.chart.BarDirection;
|
||||
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
|
||||
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFChart;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFChartAxis;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFChart;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||
|
||||
/**
|
||||
* Build a chart without reading template file
|
||||
*/
|
||||
public class ChartFromScratch {
|
||||
private static void usage(){
|
||||
System.out.println("Usage: BarChartExample <bar-chart-data.txt>");
|
||||
System.out.println(" bar-chart-data.txt the model to set. First line is chart title, " +
|
||||
"then go pairs {axis-label value}");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if(args.length < 1) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
try (BufferedReader modelReader = new BufferedReader(new FileReader(args[0]))) {
|
||||
|
||||
String chartTitle = modelReader.readLine(); // first line is chart title
|
||||
String[] series = modelReader.readLine().split(",");
|
||||
|
||||
// Category Axis Data
|
||||
List<String> listLanguages = new ArrayList<>(10);
|
||||
|
||||
// Values
|
||||
List<Double> listCountries = new ArrayList<>(10);
|
||||
List<Double> listSpeakers = new ArrayList<>(10);
|
||||
|
||||
// set model
|
||||
String ln;
|
||||
while((ln = modelReader.readLine()) != null) {
|
||||
String[] vals = ln.split(",");
|
||||
listCountries.add(Double.valueOf(vals[0]));
|
||||
listSpeakers.add(Double.valueOf(vals[1]));
|
||||
listLanguages.add(vals[2]);
|
||||
}
|
||||
|
||||
String[] categories = listLanguages.toArray(new String[listLanguages.size()]);
|
||||
Double[] values1 = listCountries.toArray(new Double[listCountries.size()]);
|
||||
Double[] values2 = listSpeakers.toArray(new Double[listSpeakers.size()]);
|
||||
|
||||
try (XWPFDocument doc = new XWPFDocument()) {
|
||||
XWPFChart chart = doc.createChart(XDDFChart.DEFAULT_WIDTH, XDDFChart.DEFAULT_HEIGHT);
|
||||
setBarData(chart, chartTitle, series, categories, values1, values2);
|
||||
// save the result
|
||||
try (OutputStream out = new FileOutputStream("bar-chart-demo-output.docx")) {
|
||||
doc.write(out);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
System.out.println("Done");
|
||||
}
|
||||
|
||||
private static void setBarData(XWPFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
|
||||
// Use a category axis for the bottom axis.
|
||||
XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
|
||||
bottomAxis.setTitle(series[2]);
|
||||
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
|
||||
leftAxis.setTitle(series[0]+","+series[1]);
|
||||
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
|
||||
|
||||
final int numOfPoints = categories.length;
|
||||
final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
|
||||
final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
|
||||
final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
|
||||
final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
|
||||
final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, 1);
|
||||
values1[6] = 16.0; // if you ever want to change the underlying data
|
||||
final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);
|
||||
|
||||
|
||||
XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
|
||||
XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData);
|
||||
series1.setTitle(series[0], chart.setSheetTitle(series[0], 1));
|
||||
|
||||
XDDFBarChartData.Series series2 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData2);
|
||||
series2.setTitle(series[1], chart.setSheetTitle(series[1], 2));
|
||||
|
||||
bar.setVaryColors(true);
|
||||
bar.setBarDirection(BarDirection.COL);
|
||||
chart.plot(bar);
|
||||
|
||||
XDDFChartLegend legend = chart.getOrAddLegend();
|
||||
legend.setPosition(LegendPosition.LEFT);
|
||||
legend.setOverlay(false);
|
||||
|
||||
chart.setTitleText(chartTitle);
|
||||
chart.setTitleOverlay(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -289,6 +289,7 @@ public class TestAllFiles {
|
|||
"document/Bug50955.doc",
|
||||
"document/57843.doc",
|
||||
"slideshow/PPT95.ppt",
|
||||
"slideshow/pp40only.ppt",
|
||||
"slideshow/Divino_Revelado.pptx",
|
||||
"openxml4j/OPCCompliance_CoreProperties_DCTermsNamespaceLimitedUseFAIL.docx",
|
||||
"openxml4j/OPCCompliance_CoreProperties_DoNotUseCompatibilityMarkupFAIL.docx",
|
||||
|
|
|
@ -35,7 +35,6 @@ import java.util.Iterator;
|
|||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
|
||||
import org.apache.poi.EncryptedDocumentException;
|
||||
|
@ -148,7 +147,7 @@ public class XSSFFileHandler extends SpreadsheetHandler {
|
|||
}
|
||||
|
||||
private void exportToXML(XSSFWorkbook wb) throws SAXException,
|
||||
ParserConfigurationException, TransformerException {
|
||||
TransformerException {
|
||||
for (XSSFMap map : wb.getCustomXMLMappings()) {
|
||||
XSSFExportToXml exporter = new XSSFExportToXml(map);
|
||||
|
||||
|
@ -165,7 +164,6 @@ public class XSSFFileHandler extends SpreadsheetHandler {
|
|||
// zip-bomb
|
||||
EXPECTED_ADDITIONAL_FAILURES.add("spreadsheet/54764.xlsx");
|
||||
EXPECTED_ADDITIONAL_FAILURES.add("spreadsheet/54764-2.xlsx");
|
||||
EXPECTED_ADDITIONAL_FAILURES.add("spreadsheet/54764.xlsx");
|
||||
EXPECTED_ADDITIONAL_FAILURES.add("spreadsheet/poc-xmlbomb.xlsx");
|
||||
EXPECTED_ADDITIONAL_FAILURES.add("spreadsheet/poc-xmlbomb-empty.xlsx");
|
||||
// strict OOXML
|
||||
|
@ -185,18 +183,19 @@ public class XSSFFileHandler extends SpreadsheetHandler {
|
|||
public void handleAdditional(File file) throws Exception {
|
||||
// redirect stdout as the examples often write lots of text
|
||||
PrintStream oldOut = System.out;
|
||||
String testFile = file.getParentFile().getName() + "/" + file.getName();
|
||||
try {
|
||||
System.setOut(new NullPrintStream());
|
||||
FromHowTo.main(new String[]{file.getAbsolutePath()});
|
||||
XLSX2CSV.main(new String[]{file.getAbsolutePath()});
|
||||
|
||||
assertFalse("Expected Extraction to fail for file " + file + " and handler " + this + ", but did not fail!",
|
||||
EXPECTED_ADDITIONAL_FAILURES.contains(file.getParentFile().getName() + "/" + file.getName()));
|
||||
EXPECTED_ADDITIONAL_FAILURES.contains(testFile));
|
||||
|
||||
} catch (OLE2NotOfficeXmlFileException e) {
|
||||
// we have some files that are not actually OOXML and thus cannot be tested here
|
||||
} catch (IllegalArgumentException | InvalidFormatException | POIXMLException | IOException e) {
|
||||
if(!EXPECTED_ADDITIONAL_FAILURES.contains(file.getParentFile().getName() + "/" + file.getName())) {
|
||||
if(!EXPECTED_ADDITIONAL_FAILURES.contains(testFile)) {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.Map;
|
|||
*
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public final class EscherProperties {
|
||||
|
||||
// Property constants
|
||||
|
@ -117,6 +118,15 @@ public final class EscherProperties {
|
|||
public static final short GEOMETRY__ADJUST8VALUE = 334;
|
||||
public static final short GEOMETRY__ADJUST9VALUE = 335;
|
||||
public static final short GEOMETRY__ADJUST10VALUE = 336;
|
||||
public static final short GEOMETRY__PCONNECTIONSITES = 337;
|
||||
public static final short GEOMETRY__PCONNECTIONSITESDIR = 338;
|
||||
public static final short GEOMETRY__XLIMO = 339;
|
||||
public static final short GEOMETRY__YLIMO = 340;
|
||||
public static final short GEOMETRY__PADJUSTHANDLES = 341;
|
||||
public static final short GEOMETRY__PGUIDES = 342;
|
||||
public static final short GEOMETRY__PINSCRIBE = 343;
|
||||
public static final short GEOMETRY__CXK = 344;
|
||||
public static final short GEOMETRY__PFRAGMENTS = 345;
|
||||
public static final short GEOMETRY__SHADOWok = 378;
|
||||
public static final short GEOMETRY__3DOK = 379;
|
||||
public static final short GEOMETRY__LINEOK = 380;
|
||||
|
@ -333,6 +343,9 @@ public final class EscherProperties {
|
|||
|
||||
private static final Map<Short, EscherPropertyMetaData> properties = initProps();
|
||||
|
||||
private EscherProperties() {
|
||||
}
|
||||
|
||||
private static Map<Short, EscherPropertyMetaData> initProps() {
|
||||
Map<Short, EscherPropertyMetaData> m = new HashMap<>();
|
||||
addProp(m, TRANSFORM__ROTATION, "transform.rotation");
|
||||
|
@ -423,6 +436,15 @@ public final class EscherProperties {
|
|||
addProp(m, GEOMETRY__ADJUST8VALUE, "geometry.adjust8value");
|
||||
addProp(m, GEOMETRY__ADJUST9VALUE, "geometry.adjust9value");
|
||||
addProp(m, GEOMETRY__ADJUST10VALUE, "geometry.adjust10value");
|
||||
addProp(m, GEOMETRY__PCONNECTIONSITES, "geometry.pConnectionSites");
|
||||
addProp(m, GEOMETRY__PCONNECTIONSITESDIR, "geometry.pConnectionSitesDir");
|
||||
addProp(m, GEOMETRY__XLIMO, "geometry.xLimo");
|
||||
addProp(m, GEOMETRY__YLIMO, "geometry.yLimo");
|
||||
addProp(m, GEOMETRY__PADJUSTHANDLES, "geometry.pAdjustHandles");
|
||||
addProp(m, GEOMETRY__PGUIDES, "geometry.pGuides");
|
||||
addProp(m, GEOMETRY__PINSCRIBE, "geometry.pInscribe");
|
||||
addProp(m, GEOMETRY__CXK, "geometry.cxk");
|
||||
addProp(m, GEOMETRY__PFRAGMENTS, "geometry.pFragments");
|
||||
addProp(m, GEOMETRY__SHADOWok, "geometry.shadowOK");
|
||||
addProp(m, GEOMETRY__3DOK, "geometry.3dok");
|
||||
addProp(m, GEOMETRY__LINEOK, "geometry.lineok");
|
||||
|
@ -641,20 +663,20 @@ public final class EscherProperties {
|
|||
}
|
||||
|
||||
private static void addProp(Map<Short, EscherPropertyMetaData> m, int s, String propName) {
|
||||
m.put(Short.valueOf((short) s), new EscherPropertyMetaData(propName));
|
||||
m.put((short) s, new EscherPropertyMetaData(propName));
|
||||
}
|
||||
|
||||
private static void addProp(Map<Short, EscherPropertyMetaData> m, int s, String propName, byte type) {
|
||||
m.put(Short.valueOf((short) s), new EscherPropertyMetaData(propName, type));
|
||||
m.put((short) s, new EscherPropertyMetaData(propName, type));
|
||||
}
|
||||
|
||||
public static String getPropertyName(short propertyId) {
|
||||
EscherPropertyMetaData o = properties.get(Short.valueOf(propertyId));
|
||||
EscherPropertyMetaData o = properties.get(propertyId);
|
||||
return o == null ? "unknown" : o.getDescription();
|
||||
}
|
||||
|
||||
public static byte getPropertyType(short propertyId) {
|
||||
EscherPropertyMetaData escherPropertyMetaData = properties.get(Short.valueOf(propertyId));
|
||||
EscherPropertyMetaData escherPropertyMetaData = properties.get(propertyId);
|
||||
return escherPropertyMetaData == null ? 0 : escherPropertyMetaData.getType();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ import org.apache.poi.util.POILogger;
|
|||
* Supports reading and writing of variant data.<p>
|
||||
*
|
||||
* <strong>FIXME (3):</strong> Reading and writing should be made more
|
||||
* uniform than it is now. The following items should be resolved:<p>
|
||||
* uniform than it is now. The following items should be resolved:
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
|
|
|
@ -33,8 +33,11 @@ import org.apache.poi.hpsf.SummaryInformation;
|
|||
* The methods {@link #getSummaryInformationProperties} and {@link
|
||||
* #getDocumentSummaryInformationProperties} return singleton {@link
|
||||
* PropertyIDMap}s. An application that wants to extend these maps
|
||||
* should treat them as unmodifiable, copy them and modifiy the
|
||||
* should treat them as unmodifiable, copy them and modify the
|
||||
* copies.
|
||||
*
|
||||
* Trying to modify the map directly will cause exceptions
|
||||
* {@link UnsupportedOperationException} to be thrown.
|
||||
*/
|
||||
public class PropertyIDMap implements Map<Long,String> {
|
||||
|
||||
|
@ -490,11 +493,13 @@ public class PropertyIDMap implements Map<Long,String> {
|
|||
|
||||
@Override
|
||||
public String put(Long key, String value) {
|
||||
//noinspection ConstantConditions
|
||||
return idMap.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String remove(Object key) {
|
||||
//noinspection ConstantConditions
|
||||
return idMap.remove(key);
|
||||
}
|
||||
|
||||
|
|
|
@ -2276,6 +2276,8 @@ public final class InternalWorkbook {
|
|||
|
||||
/**
|
||||
* Only for internal calls - code based on this is not supported ...
|
||||
*
|
||||
* @return The list of records.
|
||||
*/
|
||||
@Internal
|
||||
public WorkbookRecordList getWorkbookRecordList() {
|
||||
|
|
|
@ -33,8 +33,9 @@ import org.apache.poi.util.LittleEndianInputStream;
|
|||
import org.apache.poi.util.RecordFormatException;
|
||||
|
||||
/**
|
||||
* Title: Record Input Stream<P>
|
||||
* Description: Wraps a stream and provides helper methods for the construction of records.<P>
|
||||
* Title: Record Input Stream
|
||||
*
|
||||
* Description: Wraps a stream and provides helper methods for the construction of records.
|
||||
*/
|
||||
public final class RecordInputStream implements LittleEndianInput {
|
||||
|
||||
|
@ -142,6 +143,15 @@ public final class RecordInputStream implements LittleEndianInput {
|
|||
_nextSid = readNextSid();
|
||||
}
|
||||
|
||||
static LittleEndianInput getLEI(InputStream is) {
|
||||
if (is instanceof LittleEndianInput) {
|
||||
// accessing directly is an optimisation
|
||||
return (LittleEndianInput) is;
|
||||
}
|
||||
// less optimal, but should work OK just the same. Often occurs in junit tests.
|
||||
return new LittleEndianInputStream(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of bytes available in the current BIFF record
|
||||
* @see #remaining()
|
||||
|
@ -295,12 +305,9 @@ public final class RecordInputStream implements LittleEndianInput {
|
|||
return _dataInput.readUShort();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return a double - might return NaN
|
||||
*/
|
||||
@Override
|
||||
public double readDouble() {
|
||||
// YK: Excel doesn't write NaN but instead converts the cell type into {@link CellType#ERROR}.
|
||||
return Double.longBitsToDouble(readLong());
|
||||
}
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ public final class SSTRecord extends ContinuableRecord {
|
|||
* <P>
|
||||
* The data consists of sets of string data. This string data is
|
||||
* arranged as follows:
|
||||
* <P>
|
||||
* </P><P>
|
||||
* <pre>
|
||||
* short string_length; // length of string data
|
||||
* byte string_flag; // flag specifying special string
|
||||
|
@ -176,9 +176,9 @@ public final class SSTRecord extends ContinuableRecord {
|
|||
* byte[] extension; // optional extension (length of array
|
||||
* // is extend_length)
|
||||
* </pre>
|
||||
* <P>
|
||||
* </P><P>
|
||||
* The string_flag is bit mapped as follows:
|
||||
* <P>
|
||||
* </P><P>
|
||||
* <TABLE summary="string_flag mapping">
|
||||
* <TR>
|
||||
* <TH>Bit number</TH>
|
||||
|
@ -232,7 +232,7 @@ public final class SSTRecord extends ContinuableRecord {
|
|||
* associated data. The UnicodeString class can handle the byte[]
|
||||
* vs short[] nature of the actual string data
|
||||
*
|
||||
* @param in the RecordInputstream to read the record from
|
||||
* @param in the RecordInputStream to read the record from
|
||||
*/
|
||||
public SSTRecord(RecordInputStream in) {
|
||||
// this method is ALWAYS called after construction -- using
|
||||
|
|
|
@ -77,7 +77,7 @@ public final class SharedFormulaRecord extends SharedValueRecordBase {
|
|||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
buffer.append("[SHARED FORMULA (").append(HexDump.intToHex(sid)).append("]\n");
|
||||
buffer.append(" .range = ").append(getRange()).append("\n");
|
||||
|
@ -99,6 +99,10 @@ public final class SharedFormulaRecord extends SharedValueRecordBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Convert formula into an array of {@link Ptg} tokens.
|
||||
*
|
||||
* @param formula The record to break into tokens, cannot be null
|
||||
*
|
||||
* @return the equivalent {@link Ptg} array that the formula would have, were it not shared.
|
||||
*/
|
||||
public Ptg[] getFormulaTokens(FormulaRecord formula) {
|
||||
|
|
|
@ -42,6 +42,8 @@ public abstract class SharedValueRecordBase extends StandardRecord {
|
|||
|
||||
/**
|
||||
* reads only the range (1 {@link CellRangeAddress8Bit}) from the stream
|
||||
*
|
||||
* @param in The interface for reading the record data.
|
||||
*/
|
||||
public SharedValueRecordBase(LittleEndianInput in) {
|
||||
_range = new CellRangeAddress8Bit(in);
|
||||
|
@ -99,13 +101,11 @@ public abstract class SharedValueRecordBase extends StandardRecord {
|
|||
&& r.getLastColumn() >= colIx;
|
||||
}
|
||||
/**
|
||||
* @return {@code true} if (rowIx, colIx) describes the first cell in this shared value
|
||||
* object's range
|
||||
*
|
||||
* @param rowIx the row index
|
||||
* @param colIx the column index
|
||||
*
|
||||
* @return {@code true} if its the first cell in this shared value object range
|
||||
* @return {@code true} if (rowIx, colIx) describes the first cell in this shared value
|
||||
* object's range
|
||||
*
|
||||
* @see #getRange()
|
||||
*/
|
||||
|
|
|
@ -99,6 +99,13 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream {
|
|||
return initCipherForBlock(cipher, block, lastChunk);
|
||||
}
|
||||
|
||||
// helper method to break a recursion loop introduced because of an IBMJCE bug, i.e. not resetting on Cipher.doFinal()
|
||||
@Internal
|
||||
protected Cipher initCipherForBlockNoFlush(Cipher existing, int block, boolean lastChunk)
|
||||
throws IOException, GeneralSecurityException {
|
||||
return initCipherForBlock(cipher, block, lastChunk);
|
||||
}
|
||||
|
||||
protected abstract Cipher initCipherForBlock(Cipher existing, int block, boolean lastChunk)
|
||||
throws IOException, GeneralSecurityException;
|
||||
|
||||
|
@ -212,13 +219,30 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream {
|
|||
* @throws IllegalBlockSizeException
|
||||
* @throws ShortBufferException
|
||||
*/
|
||||
protected int invokeCipher(int posInChunk, boolean doFinal) throws GeneralSecurityException {
|
||||
protected int invokeCipher(int posInChunk, boolean doFinal) throws GeneralSecurityException, IOException {
|
||||
byte plain[] = (plainByteFlags.isEmpty()) ? null : chunk.clone();
|
||||
|
||||
int ciLen = (doFinal)
|
||||
? cipher.doFinal(chunk, 0, posInChunk, chunk)
|
||||
: cipher.update(chunk, 0, posInChunk, chunk);
|
||||
|
||||
if (doFinal && "IBMJCE".equals(cipher.getProvider().getName()) && "RC4".equals(cipher.getAlgorithm())) {
|
||||
// workaround for IBMs cipher not resetting on doFinal
|
||||
|
||||
int index = (int)(pos >> chunkBits);
|
||||
boolean lastChunk;
|
||||
if (posInChunk==0) {
|
||||
index--;
|
||||
posInChunk = chunk.length;
|
||||
lastChunk = false;
|
||||
} else {
|
||||
// pad the last chunk
|
||||
lastChunk = true;
|
||||
}
|
||||
|
||||
cipher = initCipherForBlockNoFlush(cipher, index, lastChunk);
|
||||
}
|
||||
|
||||
if (plain != null) {
|
||||
int i = plainByteFlags.nextSetBit(0);
|
||||
while (i >= 0 && i < posInChunk) {
|
||||
|
|
|
@ -207,9 +207,15 @@ public class CryptoAPIEncryptor extends Encryptor implements Cloneable {
|
|||
protected Cipher initCipherForBlock(Cipher cipher, int block, boolean lastChunk)
|
||||
throws IOException, GeneralSecurityException {
|
||||
flush();
|
||||
return initCipherForBlockNoFlush(cipher, block, lastChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Cipher initCipherForBlockNoFlush(Cipher existing, int block, boolean lastChunk)
|
||||
throws GeneralSecurityException {
|
||||
EncryptionInfo ei = getEncryptionInfo();
|
||||
SecretKey sk = getSecretKey();
|
||||
return CryptoAPIDecryptor.initCipherForBlock(cipher, block, ei, sk, Cipher.ENCRYPT_MODE);
|
||||
return CryptoAPIDecryptor.initCipherForBlock(existing, block, ei, sk, Cipher.ENCRYPT_MODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -78,7 +78,7 @@ public enum FileMagic {
|
|||
/** PDF document */
|
||||
PDF("%PDF"),
|
||||
/** Some different HTML documents */
|
||||
HTML("<!DOCTYP".getBytes(UTF_8), "<html".getBytes(UTF_8)),
|
||||
HTML("<!DOCTYP".getBytes(UTF_8), "<html".getBytes(UTF_8), "<HTML".getBytes(UTF_8)),
|
||||
WORD2(new byte[]{ (byte)0xdb, (byte)0xa5, 0x2d, 0x00}),
|
||||
// keep UNKNOWN always as last enum!
|
||||
/** UNKNOWN magic */
|
||||
|
@ -101,17 +101,8 @@ public enum FileMagic {
|
|||
|
||||
public static FileMagic valueOf(byte[] magic) {
|
||||
for (FileMagic fm : values()) {
|
||||
int i=0;
|
||||
boolean found = true;
|
||||
for (byte[] ma : fm.magic) {
|
||||
for (byte m : ma) {
|
||||
byte d = magic[i++];
|
||||
if (!(d == m || (m == 0x70 && (d == 0x10 || d == 0x20 || d == 0x40)))) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
if (findMagic(ma, magic)) {
|
||||
return fm;
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +110,17 @@ public enum FileMagic {
|
|||
return UNKNOWN;
|
||||
}
|
||||
|
||||
private static boolean findMagic(byte[] cmp, byte[] actual) {
|
||||
int i=0;
|
||||
for (byte m : cmp) {
|
||||
byte d = actual[i++];
|
||||
if (!(d == m || (m == 0x70 && (d == 0x10 || d == 0x20 || d == 0x40)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the file magic of the supplied {@link File}<p>
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
package org.apache.poi.sl.draw;
|
||||
|
||||
import static org.apache.poi.sl.draw.DrawPaint.fillPaintWorkaround;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Paint;
|
||||
|
@ -59,7 +61,7 @@ public class DrawBackground extends DrawShape {
|
|||
if(fill != null) {
|
||||
graphics.setRenderingHint(Drawable.GRADIENT_SHAPE, anchor);
|
||||
graphics.setPaint(fill);
|
||||
graphics.fill(anchor2);
|
||||
fillPaintWorkaround(graphics, anchor2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,43 +17,11 @@
|
|||
|
||||
package org.apache.poi.sl.draw;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.sl.draw.geom.Outline;
|
||||
import org.apache.poi.sl.draw.geom.Path;
|
||||
import org.apache.poi.sl.usermodel.*;
|
||||
import org.apache.poi.sl.usermodel.FreeformShape;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class DrawFreeformShape extends DrawAutoShape {
|
||||
public DrawFreeformShape(FreeformShape<?,?> shape) {
|
||||
super(shape);
|
||||
}
|
||||
|
||||
protected Collection<Outline> computeOutlines(Graphics2D graphics) {
|
||||
List<Outline> lst = new ArrayList<>();
|
||||
FreeformShape<?,?> fsh = (FreeformShape<?, ?>) getShape();
|
||||
Path2D sh = fsh.getPath();
|
||||
|
||||
AffineTransform tx = (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);
|
||||
if (tx == null) {
|
||||
tx = new AffineTransform();
|
||||
}
|
||||
|
||||
java.awt.Shape canvasShape = tx.createTransformedShape(sh);
|
||||
|
||||
FillStyle fs = fsh.getFillStyle();
|
||||
StrokeStyle ss = fsh.getStrokeStyle();
|
||||
Path path = new Path(fs != null, ss != null);
|
||||
lst.add(new Outline(canvasShape, path));
|
||||
return lst;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TextShape<?,? extends TextParagraph<?,?,? extends TextRun>> getShape() {
|
||||
return (TextShape<?,? extends TextParagraph<?,?,? extends TextRun>>)shape;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,13 +23,17 @@ import java.awt.Graphics2D;
|
|||
import java.awt.LinearGradientPaint;
|
||||
import java.awt.Paint;
|
||||
import java.awt.RadialGradientPaint;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.apache.poi.sl.usermodel.AbstractColorStyle;
|
||||
import org.apache.poi.sl.usermodel.ColorStyle;
|
||||
|
@ -197,28 +201,17 @@ public class DrawPaint {
|
|||
|
||||
@Override
|
||||
public int getShade() {
|
||||
int shade = orig.getShade();
|
||||
switch (modifier) {
|
||||
case DARKEN:
|
||||
return Math.min(100000, Math.max(0,shade)+40000);
|
||||
case DARKEN_LESS:
|
||||
return Math.min(100000, Math.max(0,shade)+20000);
|
||||
default:
|
||||
return shade;
|
||||
}
|
||||
return scale(orig.getShade(), PaintModifier.DARKEN_LESS, PaintModifier.DARKEN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTint() {
|
||||
int tint = orig.getTint();
|
||||
switch (modifier) {
|
||||
case LIGHTEN:
|
||||
return Math.min(100000, Math.max(0,tint)+40000);
|
||||
case LIGHTEN_LESS:
|
||||
return Math.min(100000, Math.max(0,tint)+20000);
|
||||
default:
|
||||
return tint;
|
||||
}
|
||||
return scale(orig.getTint(), PaintModifier.LIGHTEN_LESS, PaintModifier.LIGHTEN);
|
||||
}
|
||||
|
||||
private int scale(int value, PaintModifier lessModifier, PaintModifier moreModifier) {
|
||||
int delta = (modifier == lessModifier ? 20000 : (modifier == moreModifier ? 40000 : 0));
|
||||
return Math.min(100000, Math.max(0,value)+delta);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -300,7 +293,7 @@ public class DrawPaint {
|
|||
Color result = color.getColor();
|
||||
|
||||
double alpha = getAlpha(result, color);
|
||||
double hsl[] = RGB2HSL(result); // values are in the range [0..100] (usually ...)
|
||||
double[] hsl = RGB2HSL(result); // values are in the range [0..100] (usually ...)
|
||||
applyHslModOff(hsl, 0, color.getHueMod(), color.getHueOff());
|
||||
applyHslModOff(hsl, 1, color.getSatMod(), color.getSatOff());
|
||||
applyHslModOff(hsl, 2, color.getLumMod(), color.getLumOff());
|
||||
|
@ -344,7 +337,7 @@ public class DrawPaint {
|
|||
* @param mod the modulation adjustment
|
||||
* @param off the offset adjustment
|
||||
*/
|
||||
private static void applyHslModOff(double hsl[], int hslPart, int mod, int off) {
|
||||
private static void applyHslModOff(double[] hsl, int hslPart, int mod, int off) {
|
||||
if (mod == -1) {
|
||||
mod = 100000;
|
||||
}
|
||||
|
@ -363,7 +356,7 @@ public class DrawPaint {
|
|||
*
|
||||
* For a shade, the equation is luminance * %tint.
|
||||
*/
|
||||
private static void applyShade(double hsl[], ColorStyle fc) {
|
||||
private static void applyShade(double[] hsl, ColorStyle fc) {
|
||||
int shade = fc.getShade();
|
||||
if (shade == -1) {
|
||||
return;
|
||||
|
@ -380,7 +373,7 @@ public class DrawPaint {
|
|||
* For a tint, the equation is luminance * %tint + (1-%tint).
|
||||
* (Note that 1-%tint is equal to the lumOff value in DrawingML.)
|
||||
*/
|
||||
private static void applyTint(double hsl[], ColorStyle fc) {
|
||||
private static void applyTint(double[] hsl, ColorStyle fc) {
|
||||
int tint = fc.getTint();
|
||||
if (tint == -1) {
|
||||
return;
|
||||
|
@ -403,70 +396,63 @@ public class DrawPaint {
|
|||
}
|
||||
|
||||
Rectangle2D anchor = DrawShape.getAnchor(graphics, shape);
|
||||
final double h = anchor.getHeight(), w = anchor.getWidth(), x = anchor.getX(), y = anchor.getY();
|
||||
|
||||
AffineTransform at = AffineTransform.getRotateInstance(Math.toRadians(angle), anchor.getCenterX(), anchor.getCenterY());
|
||||
|
||||
double diagonal = Math.sqrt(h * h + w * w);
|
||||
Point2D p1 = new Point2D.Double(x + w / 2 - diagonal / 2, y + h / 2);
|
||||
p1 = at.transform(p1, null);
|
||||
|
||||
Point2D p2 = new Point2D.Double(x + w, y + h / 2);
|
||||
p2 = at.transform(p2, null);
|
||||
double diagonal = Math.sqrt(Math.pow(anchor.getWidth(),2) + Math.pow(anchor.getHeight(),2));
|
||||
final Point2D p1 = at.transform(new Point2D.Double(anchor.getCenterX() - diagonal / 2, anchor.getCenterY()), null);
|
||||
final Point2D p2 = at.transform(new Point2D.Double(anchor.getMaxX(), anchor.getCenterY()), null);
|
||||
|
||||
// snapToAnchor(p1, anchor);
|
||||
// snapToAnchor(p2, anchor);
|
||||
|
||||
if (p1.equals(p2)) {
|
||||
// gradient paint on the same point throws an exception ... and doesn't make sense
|
||||
return null;
|
||||
}
|
||||
|
||||
float[] fractions = fill.getGradientFractions();
|
||||
Color[] colors = new Color[fractions.length];
|
||||
|
||||
int i = 0;
|
||||
for (ColorStyle fc : fill.getGradientColors()) {
|
||||
// if fc is null, use transparent color to get color of background
|
||||
colors[i++] = (fc == null) ? TRANSPARENT : applyColorTransform(fc);
|
||||
}
|
||||
|
||||
return new LinearGradientPaint(p1, p2, fractions, colors);
|
||||
// gradient paint on the same point throws an exception ... and doesn't make sense
|
||||
return (p1.equals(p2)) ? null : safeFractions((f,c)->new LinearGradientPaint(p1,p2,f,c), fill);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected Paint createRadialGradientPaint(GradientPaint fill, Graphics2D graphics) {
|
||||
Rectangle2D anchor = DrawShape.getAnchor(graphics, shape);
|
||||
|
||||
Point2D pCenter = new Point2D.Double(anchor.getX() + anchor.getWidth()/2,
|
||||
anchor.getY() + anchor.getHeight()/2);
|
||||
final Point2D pCenter = new Point2D.Double(anchor.getCenterX(), anchor.getCenterY());
|
||||
|
||||
float radius = (float)Math.max(anchor.getWidth(), anchor.getHeight());
|
||||
final float radius = (float)Math.max(anchor.getWidth(), anchor.getHeight());
|
||||
|
||||
float[] fractions = fill.getGradientFractions();
|
||||
Color[] colors = new Color[fractions.length];
|
||||
|
||||
int i=0;
|
||||
for (ColorStyle fc : fill.getGradientColors()) {
|
||||
colors[i++] = applyColorTransform(fc);
|
||||
}
|
||||
|
||||
return new RadialGradientPaint(pCenter, radius, fractions, colors);
|
||||
return safeFractions((f,c)->new RadialGradientPaint(pCenter,radius,f,c), fill);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
protected Paint createPathGradientPaint(GradientPaint fill, Graphics2D graphics) {
|
||||
// currently we ignore an eventually center setting
|
||||
|
||||
float[] fractions = fill.getGradientFractions();
|
||||
Color[] colors = new Color[fractions.length];
|
||||
return safeFractions(PathGradientPaint::new, fill);
|
||||
}
|
||||
|
||||
int i=0;
|
||||
for (ColorStyle fc : fill.getGradientColors()) {
|
||||
colors[i++] = applyColorTransform(fc);
|
||||
private Paint safeFractions(BiFunction<float[],Color[],Paint> init, GradientPaint fill) {
|
||||
float[] fractions = fill.getGradientFractions();
|
||||
final ColorStyle[] styles = fill.getGradientColors();
|
||||
|
||||
// need to remap the fractions, because Java doesn't like repeating fraction values
|
||||
Map<Float,Color> m = new TreeMap<>();
|
||||
for (int i = 0; i<fractions.length; i++) {
|
||||
// if fc is null, use transparent color to get color of background
|
||||
m.put(fractions[i], (styles[i] == null ? TRANSPARENT : applyColorTransform(styles[i])));
|
||||
}
|
||||
|
||||
return new PathGradientPaint(colors, fractions);
|
||||
final Color[] colors = new Color[m.size()];
|
||||
if (fractions.length != m.size()) {
|
||||
fractions = new float[m.size()];
|
||||
}
|
||||
|
||||
int i=0;
|
||||
for (Map.Entry<Float,Color> me : m.entrySet()) {
|
||||
fractions[i] = me.getKey();
|
||||
colors[i] = me.getValue();
|
||||
i++;
|
||||
}
|
||||
|
||||
return init.apply(fractions, colors);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -620,4 +606,19 @@ public class DrawPaint {
|
|||
return (float)(1.055d * Math.pow(linRGB / 100000d, 1.0d/2.4d) - 0.055d);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void fillPaintWorkaround(Graphics2D graphics, Shape shape) {
|
||||
// the ibm jdk has a rendering/JIT bug, which throws an AIOOBE in
|
||||
// TexturePaintContext$Int.setRaster(TexturePaintContext.java:476)
|
||||
// this usually doesn't happen while debugging, because JIT doesn't jump in then.
|
||||
try {
|
||||
graphics.fill(shape);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
LOG.log(POILogger.WARN, "IBM JDK failed with TexturePaintContext AIOOBE - try adding the following to the VM parameter:\n" +
|
||||
"-Xjit:exclude={sun/java2d/pipe/AlphaPaintPipe.renderPathTile(Ljava/lang/Object;[BIIIIII)V} and " +
|
||||
"search for 'JIT Problem Determination for IBM SDK using -Xjit' (http://www-01.ibm.com/support/docview.wss?uid=swg21294023) " +
|
||||
"for how to add/determine further excludes", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
package org.apache.poi.sl.draw;
|
||||
|
||||
import static org.apache.poi.sl.draw.DrawPaint.fillPaintWorkaround;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
|
@ -87,7 +89,7 @@ public class DrawSimpleShape extends DrawShape {
|
|||
graphics.setPaint(fillMod);
|
||||
java.awt.Shape s = o.getOutline();
|
||||
graphics.setRenderingHint(Drawable.GRADIENT_SHAPE, s);
|
||||
graphics.fill(s);
|
||||
fillPaintWorkaround(graphics, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -327,7 +329,7 @@ public class DrawSimpleShape extends DrawShape {
|
|||
graphics.setPaint(shadowColor);
|
||||
|
||||
if(fill != null && p.isFilled()){
|
||||
graphics.fill(s);
|
||||
fillPaintWorkaround(graphics, s);
|
||||
} else if (line != null && p.isStroked()) {
|
||||
graphics.draw(s);
|
||||
}
|
||||
|
@ -410,14 +412,20 @@ public class DrawSimpleShape extends DrawShape {
|
|||
}
|
||||
for (Path p : geom) {
|
||||
|
||||
double w = p.getW(), h = p.getH(), scaleX = Units.toPoints(1), scaleY = scaleX;
|
||||
double w = p.getW(), h = p.getH(), scaleX, scaleY;
|
||||
if (w == -1) {
|
||||
w = Units.toEMU(anchor.getWidth());
|
||||
scaleX = Units.toPoints(1);
|
||||
} else if (anchor.getWidth() == 0) {
|
||||
scaleX = 1;
|
||||
} else {
|
||||
scaleX = anchor.getWidth() / w;
|
||||
}
|
||||
if (h == -1) {
|
||||
h = Units.toEMU(anchor.getHeight());
|
||||
scaleY = Units.toPoints(1);
|
||||
} else if (anchor.getHeight() == 0) {
|
||||
scaleY = 1;
|
||||
} else {
|
||||
scaleY = anchor.getHeight() / h;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
package org.apache.poi.sl.draw;
|
||||
|
||||
import static org.apache.poi.sl.draw.DrawPaint.fillPaintWorkaround;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Paint;
|
||||
|
@ -83,7 +85,7 @@ public class DrawTableShape extends DrawShape {
|
|||
Paint fillPaint = drawPaint.getPaint(graphics, tc.getFillStyle().getPaint());
|
||||
graphics.setPaint(fillPaint);
|
||||
Rectangle2D cellAnc = tc.getAnchor();
|
||||
graphics.fill(cellAnc);
|
||||
fillPaintWorkaround(graphics, cellAnc);
|
||||
|
||||
for (BorderEdge edge : BorderEdge.values()) {
|
||||
StrokeStyle stroke = tc.getBorderStyle(edge);
|
||||
|
|
|
@ -23,21 +23,24 @@ import java.awt.MultipleGradientPaint.CycleMethod;
|
|||
import java.awt.geom.*;
|
||||
import java.awt.image.*;
|
||||
|
||||
import org.apache.poi.util.Internal;
|
||||
|
||||
@Internal
|
||||
class PathGradientPaint implements Paint {
|
||||
|
||||
// http://asserttrue.blogspot.de/2010/01/how-to-iimplement-custom-paint-in-50.html
|
||||
protected final Color colors[];
|
||||
protected final float fractions[];
|
||||
protected final int capStyle;
|
||||
protected final int joinStyle;
|
||||
protected final int transparency;
|
||||
private final Color[] colors;
|
||||
private final float[] fractions;
|
||||
private final int capStyle;
|
||||
private final int joinStyle;
|
||||
private final int transparency;
|
||||
|
||||
|
||||
public PathGradientPaint(Color colors[], float fractions[]) {
|
||||
this(colors,fractions,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
|
||||
PathGradientPaint(float[] fractions, Color[] colors) {
|
||||
this(fractions,colors,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
|
||||
}
|
||||
|
||||
public PathGradientPaint(Color colors[], float fractions[], int capStyle, int joinStyle) {
|
||||
private PathGradientPaint(float[] fractions, Color[] colors, int capStyle, int joinStyle) {
|
||||
this.colors = colors.clone();
|
||||
this.fractions = fractions.clone();
|
||||
this.capStyle = capStyle;
|
||||
|
@ -66,26 +69,26 @@ class PathGradientPaint implements Paint {
|
|||
}
|
||||
|
||||
class PathGradientContext implements PaintContext {
|
||||
protected final Rectangle deviceBounds;
|
||||
protected final Rectangle2D userBounds;
|
||||
final Rectangle deviceBounds;
|
||||
final Rectangle2D userBounds;
|
||||
protected final AffineTransform xform;
|
||||
protected final RenderingHints hints;
|
||||
final RenderingHints hints;
|
||||
|
||||
/**
|
||||
* for POI: the shape will be only known when the subclasses determines the concrete implementation
|
||||
* in the draw/-content method, so we need to postpone the setting/creation as long as possible
|
||||
**/
|
||||
protected final Shape shape;
|
||||
protected final PaintContext pCtx;
|
||||
protected final int gradientSteps;
|
||||
final PaintContext pCtx;
|
||||
final int gradientSteps;
|
||||
WritableRaster raster;
|
||||
|
||||
public PathGradientContext(
|
||||
ColorModel cm
|
||||
, Rectangle deviceBounds
|
||||
, Rectangle2D userBounds
|
||||
, AffineTransform xform
|
||||
, RenderingHints hints
|
||||
PathGradientContext(
|
||||
ColorModel cm
|
||||
, Rectangle deviceBounds
|
||||
, Rectangle2D userBounds
|
||||
, AffineTransform xform
|
||||
, RenderingHints hints
|
||||
) {
|
||||
shape = (Shape)hints.get(Drawable.GRADIENT_SHAPE);
|
||||
if (shape == null) {
|
||||
|
@ -139,7 +142,7 @@ class PathGradientPaint implements Paint {
|
|||
return childRaster;
|
||||
}
|
||||
|
||||
protected int getGradientSteps(Shape gradientShape) {
|
||||
int getGradientSteps(Shape gradientShape) {
|
||||
Rectangle rect = gradientShape.getBounds();
|
||||
int lower = 1;
|
||||
int upper = (int)(Math.max(rect.getWidth(),rect.getHeight())/2.0);
|
||||
|
@ -158,7 +161,7 @@ class PathGradientPaint implements Paint {
|
|||
|
||||
|
||||
|
||||
protected void createRaster() {
|
||||
void createRaster() {
|
||||
ColorModel cm = getColorModel();
|
||||
raster = cm.createCompatibleWritableRaster((int)deviceBounds.getWidth(), (int)deviceBounds.getHeight());
|
||||
BufferedImage img = new BufferedImage(cm, raster, false, null);
|
||||
|
@ -168,7 +171,7 @@ class PathGradientPaint implements Paint {
|
|||
graphics.transform(xform);
|
||||
|
||||
Raster img2 = pCtx.getRaster(0, 0, gradientSteps, 1);
|
||||
int rgb[] = new int[cm.getNumComponents()];
|
||||
int[] rgb = new int[cm.getNumComponents()];
|
||||
|
||||
for (int i = gradientSteps-1; i>=0; i--) {
|
||||
img2.getPixel(i, 0, rgb);
|
||||
|
|
|
@ -22,11 +22,18 @@ package org.apache.poi.sl.draw.geom;
|
|||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Context {
|
||||
final Map<String, Double> _ctx = new HashMap<>();
|
||||
final IAdjustableShape _props;
|
||||
final Rectangle2D _anchor;
|
||||
private static final Pattern DOUBLE_PATTERN = Pattern.compile(
|
||||
"[\\x00-\\x20]*[+-]?(NaN|Infinity|((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)" +
|
||||
"([eE][+-]?(\\p{Digit}+))?)|(\\.(\\p{Digit}+)([eE][+-]?(\\p{Digit}+))?)|" +
|
||||
"(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)?(\\.)(\\p{XDigit}+)))" +
|
||||
"[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*");
|
||||
|
||||
private final Map<String, Double> _ctx = new HashMap<>();
|
||||
private final IAdjustableShape _props;
|
||||
private final Rectangle2D _anchor;
|
||||
|
||||
public Context(CustomGeometry geom, Rectangle2D anchor, IAdjustableShape props){
|
||||
_props = props;
|
||||
|
@ -39,23 +46,22 @@ public class Context {
|
|||
}
|
||||
}
|
||||
|
||||
public Rectangle2D getShapeAnchor(){
|
||||
Rectangle2D getShapeAnchor(){
|
||||
return _anchor;
|
||||
}
|
||||
|
||||
public Guide getAdjustValue(String name){
|
||||
Guide getAdjustValue(String name){
|
||||
// ignore HSLF props for now ... the results with default value are usually better - see #59004
|
||||
return (_props.getClass().getName().contains("hslf")) ? null : _props.getAdjustValue(name);
|
||||
}
|
||||
|
||||
public double getValue(String key){
|
||||
if(key.matches("(\\+|-)?\\d+")){
|
||||
if(DOUBLE_PATTERN.matcher(key).matches()){
|
||||
return Double.parseDouble(key);
|
||||
}
|
||||
|
||||
Double val = _ctx.get(key);
|
||||
// BuiltInGuide throws IllegalArgumentException if key is not defined
|
||||
return (val != null) ? val : evaluate(BuiltInGuide.valueOf("_"+key));
|
||||
return _ctx.containsKey(key) ? _ctx.get(key) : evaluate(BuiltInGuide.valueOf("_"+key));
|
||||
}
|
||||
|
||||
public double evaluate(Formula fmla){
|
||||
|
|
|
@ -27,12 +27,12 @@ import javax.xml.bind.JAXBElement;
|
|||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.stream.EventFilter;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamConstants;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.apache.poi.sl.draw.binding.CTCustomGeometry2D;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
|
@ -61,26 +61,29 @@ public class PresetGeometries extends LinkedHashMap<String, CustomGeometry> {
|
|||
};
|
||||
|
||||
XMLInputFactory staxFactory = StaxHelper.newXMLInputFactory();
|
||||
XMLEventReader staxReader = staxFactory.createXMLEventReader(is);
|
||||
XMLEventReader staxFiltRd = staxFactory.createFilteredReader(staxReader, startElementFilter);
|
||||
// ignore StartElement:
|
||||
/* XMLEvent evDoc = */ staxFiltRd.nextEvent();
|
||||
// JAXB:
|
||||
JAXBContext jaxbContext = JAXBContext.newInstance(BINDING_PACKAGE);
|
||||
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
|
||||
XMLStreamReader streamReader = staxFactory.createXMLStreamReader(new StreamSource(is));
|
||||
try {
|
||||
// ignore StartElement:
|
||||
streamReader.nextTag();
|
||||
|
||||
long cntElem = 0;
|
||||
while (staxFiltRd.peek() != null) {
|
||||
StartElement evRoot = (StartElement)staxFiltRd.peek();
|
||||
String name = evRoot.getName().getLocalPart();
|
||||
JAXBElement<CTCustomGeometry2D> el = unmarshaller.unmarshal(staxReader, CTCustomGeometry2D.class);
|
||||
CTCustomGeometry2D cus = el.getValue();
|
||||
cntElem++;
|
||||
// JAXB:
|
||||
JAXBContext jaxbContext = JAXBContext.newInstance(BINDING_PACKAGE);
|
||||
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
|
||||
|
||||
if(containsKey(name)) {
|
||||
LOG.log(POILogger.WARN, "Duplicate definition of " + name);
|
||||
long cntElem = 0;
|
||||
while (streamReader.hasNext() && streamReader.nextTag() == XMLStreamConstants.START_ELEMENT) {
|
||||
String name = streamReader.getLocalName();
|
||||
JAXBElement<CTCustomGeometry2D> el = unmarshaller.unmarshal(streamReader, CTCustomGeometry2D.class);
|
||||
CTCustomGeometry2D cus = el.getValue();
|
||||
cntElem++;
|
||||
|
||||
if (containsKey(name)) {
|
||||
LOG.log(POILogger.WARN, "Duplicate definition of " + name);
|
||||
}
|
||||
put(name, new CustomGeometry(cus));
|
||||
}
|
||||
put(name, new CustomGeometry(cus));
|
||||
} finally {
|
||||
streamReader.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,16 +24,15 @@ public interface FreeformShape<
|
|||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> extends AutoShape<S,P> {
|
||||
/**
|
||||
* Gets the shape path.
|
||||
* <p>
|
||||
* The path is translated in the shape's coordinate system, i.e.
|
||||
* freeform.getPath().getBounds2D() equals to freeform.getAnchor()
|
||||
* (small discrepancies are possible due to rounding errors)
|
||||
* </p>
|
||||
* Gets the shape path.<p>
|
||||
*
|
||||
* The path is translated in the shape's coordinate system, i.e.
|
||||
* freeform.getPath2D().getBounds2D() equals to freeform.getAnchor()
|
||||
* (small discrepancies are possible due to rounding errors)
|
||||
*
|
||||
* @return the path
|
||||
*/
|
||||
Path2D.Double getPath();
|
||||
Path2D getPath();
|
||||
|
||||
/**
|
||||
* Set the shape path
|
||||
|
@ -41,5 +40,5 @@ public interface FreeformShape<
|
|||
* @param path shape outline
|
||||
* @return the number of points written
|
||||
*/
|
||||
int setPath(Path2D.Double path);
|
||||
int setPath(Path2D path);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ public final class SheetNameFormatter {
|
|||
* @param rawSheetName - sheet name
|
||||
* @deprecated use <code>appendFormat(StringBuilder out, String rawSheetName)</code> instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static void appendFormat(StringBuffer out, String rawSheetName) {
|
||||
boolean needsQuotes = needsDelimiting(rawSheetName);
|
||||
if(needsQuotes) {
|
||||
|
@ -73,6 +74,7 @@ public final class SheetNameFormatter {
|
|||
/**
|
||||
* @deprecated use <code>appendFormat(StringBuilder out, String workbookName, String rawSheetName)</code> instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static void appendFormat(StringBuffer out, String workbookName, String rawSheetName) {
|
||||
boolean needsQuotes = needsDelimiting(workbookName) || needsDelimiting(rawSheetName);
|
||||
if(needsQuotes) {
|
||||
|
@ -123,7 +125,7 @@ public final class SheetNameFormatter {
|
|||
}
|
||||
}
|
||||
|
||||
private static void appendAndEscape(Appendable sb, String rawSheetName) {
|
||||
static void appendAndEscape(Appendable sb, String rawSheetName) {
|
||||
int len = rawSheetName.length();
|
||||
for(int i=0; i<len; i++) {
|
||||
char ch = rawSheetName.charAt(i);
|
||||
|
@ -139,7 +141,12 @@ public final class SheetNameFormatter {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean needsDelimiting(String rawSheetName) {
|
||||
/**
|
||||
* Tell if the given raw sheet name needs screening/delimiting.
|
||||
* @param rawSheetName the sheet name.
|
||||
* @return true if the given raw sheet name needs screening/delimiting, false otherwise.
|
||||
*/
|
||||
static boolean needsDelimiting(String rawSheetName) {
|
||||
int len = rawSheetName.length();
|
||||
if(len < 1) {
|
||||
throw new RuntimeException("Zero length string is an invalid sheet name");
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/* ====================================================================
|
||||
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;
|
||||
|
||||
public class SheetRangeAndWorkbookIndexFormatter {
|
||||
private SheetRangeAndWorkbookIndexFormatter() {
|
||||
}
|
||||
|
||||
public static String format(StringBuilder sb, int workbookIndex, String firstSheetName, String lastSheetName) {
|
||||
if (anySheetNameNeedsEscaping(firstSheetName, lastSheetName)) {
|
||||
return formatWithDelimiting(sb, workbookIndex, firstSheetName, lastSheetName);
|
||||
} else {
|
||||
return formatWithoutDelimiting(sb, workbookIndex, firstSheetName, lastSheetName);
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatWithDelimiting(StringBuilder sb, int workbookIndex, String firstSheetName, String lastSheetName) {
|
||||
sb.append('\'');
|
||||
if (workbookIndex >= 0) {
|
||||
sb.append('[');
|
||||
sb.append(workbookIndex);
|
||||
sb.append(']');
|
||||
}
|
||||
|
||||
SheetNameFormatter.appendAndEscape(sb, firstSheetName);
|
||||
|
||||
if (lastSheetName != null) {
|
||||
sb.append(':');
|
||||
SheetNameFormatter.appendAndEscape(sb, lastSheetName);
|
||||
}
|
||||
|
||||
sb.append('\'');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String formatWithoutDelimiting(StringBuilder sb, int workbookIndex, String firstSheetName, String lastSheetName) {
|
||||
if (workbookIndex >= 0) {
|
||||
sb.append('[');
|
||||
sb.append(workbookIndex);
|
||||
sb.append(']');
|
||||
}
|
||||
|
||||
sb.append(firstSheetName);
|
||||
|
||||
if (lastSheetName != null) {
|
||||
sb.append(':');
|
||||
sb.append(lastSheetName);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static boolean anySheetNameNeedsEscaping(String firstSheetName, String lastSheetName) {
|
||||
boolean anySheetNameNeedsDelimiting = firstSheetName != null && SheetNameFormatter.needsDelimiting(firstSheetName);
|
||||
anySheetNameNeedsDelimiting |= lastSheetName != null && SheetNameFormatter.needsDelimiting(lastSheetName);
|
||||
return anySheetNameNeedsDelimiting;
|
||||
}
|
||||
}
|
|
@ -63,7 +63,7 @@ public abstract class MatrixFunction implements Function{
|
|||
i = 0;
|
||||
j++;
|
||||
}
|
||||
matrix[j][i++] = aVector;
|
||||
if (j < matrix.length) matrix[j][i++] = aVector;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.poi.ss.formula.ptg;
|
|||
import org.apache.poi.ss.SpreadsheetVersion;
|
||||
import org.apache.poi.ss.formula.SheetIdentifier;
|
||||
import org.apache.poi.ss.formula.SheetNameFormatter;
|
||||
import org.apache.poi.ss.formula.SheetRangeAndWorkbookIndexFormatter;
|
||||
import org.apache.poi.ss.formula.SheetRangeIdentifier;
|
||||
import org.apache.poi.ss.util.AreaReference;
|
||||
import org.apache.poi.util.LittleEndianOutput;
|
||||
|
@ -102,16 +103,8 @@ public final class Area3DPxg extends AreaPtgBase implements Pxg3D {
|
|||
|
||||
public String toFormulaString() {
|
||||
StringBuilder sb = new StringBuilder(64);
|
||||
if (externalWorkbookNumber >= 0) {
|
||||
sb.append('[');
|
||||
sb.append(externalWorkbookNumber);
|
||||
sb.append(']');
|
||||
}
|
||||
SheetNameFormatter.appendFormat(sb, firstSheetName);
|
||||
if (lastSheetName != null) {
|
||||
sb.append(':');
|
||||
SheetNameFormatter.appendFormat(sb, lastSheetName);
|
||||
}
|
||||
|
||||
SheetRangeAndWorkbookIndexFormatter.format(sb, externalWorkbookNumber, firstSheetName, lastSheetName);
|
||||
sb.append('!');
|
||||
sb.append(formatReferenceAsString());
|
||||
return sb.toString();
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
package org.apache.poi.ss.formula.ptg;
|
||||
|
||||
import org.apache.poi.ss.formula.SheetIdentifier;
|
||||
import org.apache.poi.ss.formula.SheetNameFormatter;
|
||||
import org.apache.poi.ss.formula.SheetRangeAndWorkbookIndexFormatter;
|
||||
import org.apache.poi.ss.formula.SheetRangeIdentifier;
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
import org.apache.poi.util.LittleEndianOutput;
|
||||
|
@ -101,18 +101,8 @@ public final class Ref3DPxg extends RefPtgBase implements Pxg3D {
|
|||
|
||||
public String toFormulaString() {
|
||||
StringBuilder sb = new StringBuilder(64);
|
||||
if (externalWorkbookNumber >= 0) {
|
||||
sb.append('[');
|
||||
sb.append(externalWorkbookNumber);
|
||||
sb.append(']');
|
||||
}
|
||||
if (firstSheetName != null) {
|
||||
SheetNameFormatter.appendFormat(sb, firstSheetName);
|
||||
}
|
||||
if (lastSheetName != null) {
|
||||
sb.append(':');
|
||||
SheetNameFormatter.appendFormat(sb, lastSheetName);
|
||||
}
|
||||
|
||||
SheetRangeAndWorkbookIndexFormatter.format(sb, externalWorkbookNumber, firstSheetName, lastSheetName);
|
||||
sb.append('!');
|
||||
sb.append(formatReferenceAsString());
|
||||
return sb.toString();
|
||||
|
|
|
@ -45,8 +45,8 @@ public class RecordFormatException
|
|||
* be thrown. If assertTrue is <code>false</code>, this will throw this
|
||||
* exception with the message.
|
||||
*
|
||||
* @param assertTrue
|
||||
* @param message
|
||||
* @param assertTrue If false, the exception is thrown, if true, no action is performed
|
||||
* @param message The message to include in the thrown exception
|
||||
*/
|
||||
public static void check(boolean assertTrue, String message) {
|
||||
if (! assertTrue) {
|
||||
|
|
|
@ -698,7 +698,7 @@ public class StringUtil {
|
|||
final String prefix;
|
||||
|
||||
// #61881 - for now we only check the first char
|
||||
if (len > 0 && string[offset] == 0 && string[offset+1] == 0) {
|
||||
if (len > 0 && offset < (string.length - 1) && string[offset] == 0 && string[offset+1] == 0) {
|
||||
newOffset = offset+2;
|
||||
prefix = "?";
|
||||
|
||||
|
|
|
@ -615,7 +615,7 @@ public class POIXMLDocumentPart {
|
|||
protected void read(POIXMLFactory factory, Map<PackagePart, POIXMLDocumentPart> context) throws OpenXML4JException {
|
||||
PackagePart pp = getPackagePart();
|
||||
|
||||
if (pp.getContentType().equals(XWPFRelation.TEMPLATE.getContentType())) {
|
||||
if (pp.getContentType().equals(XWPFRelation.GLOSSARY_DOCUMENT.getContentType())) {
|
||||
logger.log(POILogger.WARN,
|
||||
"POI does not currently support template.main+xml (glossary) parts. " +
|
||||
"Skipping this part for now.");
|
||||
|
|
|
@ -22,41 +22,37 @@ import org.apache.poi.extractor.POITextExtractor;
|
|||
|
||||
/**
|
||||
* A command line wrapper around {@link ExtractorFactory}, useful
|
||||
* for when debugging.
|
||||
* for when debugging.
|
||||
*/
|
||||
public class CommandLineTextExtractor {
|
||||
public static final String DIVIDER = "=======================";
|
||||
public static final String DIVIDER = "=======================";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if(args.length < 1) {
|
||||
System.err.println("Use:");
|
||||
System.err.println(" CommandLineTextExtractor <filename> [filename] [filename]");
|
||||
System.exit(1);
|
||||
}
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length < 1) {
|
||||
System.err.println("Use:");
|
||||
System.err.println(" CommandLineTextExtractor <filename> [filename] [filename]");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
for (String arg : args) {
|
||||
System.out.println(DIVIDER);
|
||||
for (String arg : args) {
|
||||
System.out.println(DIVIDER);
|
||||
|
||||
File f = new File(arg);
|
||||
System.out.println(f);
|
||||
File f = new File(arg);
|
||||
System.out.println(f);
|
||||
|
||||
POITextExtractor extractor =
|
||||
ExtractorFactory.createExtractor(f);
|
||||
try {
|
||||
POITextExtractor metadataExtractor =
|
||||
extractor.getMetadataTextExtractor();
|
||||
try (POITextExtractor extractor = ExtractorFactory.createExtractor(f)) {
|
||||
POITextExtractor metadataExtractor =
|
||||
extractor.getMetadataTextExtractor();
|
||||
|
||||
System.out.println(" " + DIVIDER);
|
||||
String metaData = metadataExtractor.getText();
|
||||
System.out.println(metaData);
|
||||
System.out.println(" " + DIVIDER);
|
||||
String text = extractor.getText();
|
||||
System.out.println(text);
|
||||
System.out.println(DIVIDER);
|
||||
System.out.println("Had " + metaData.length() + " characters of metadata and " + text.length() + " characters of text");
|
||||
} finally {
|
||||
extractor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(" " + DIVIDER);
|
||||
String metaData = metadataExtractor.getText();
|
||||
System.out.println(metaData);
|
||||
System.out.println(" " + DIVIDER);
|
||||
String text = extractor.getText();
|
||||
System.out.println(text);
|
||||
System.out.println(DIVIDER);
|
||||
System.out.println("Had " + metaData.length() + " characters of metadata and " + text.length() + " characters of text");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.poi.ooxml.util;
|
|||
public class POIXMLConstants {
|
||||
public static final String FEATURE_LOAD_DTD_GRAMMAR = "http://apache.org/xml/features/nonvalidating/load-dtd-grammar";
|
||||
public static final String FEATURE_LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
|
||||
public static final String FEATURE_DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl";
|
||||
public static final String PROPERTY_ENTITY_EXPANSION_LIMIT = "http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit";
|
||||
public static final String PROPERTY_SECURITY_MANAGER = "http://apache.org/xml/properties/security-manager";
|
||||
}
|
||||
|
|
|
@ -154,8 +154,6 @@ public final class ZipHelper {
|
|||
"The supplied data appears to be a raw XML file. " +
|
||||
"Formats such as Office 2003 XML are not supported");
|
||||
default:
|
||||
case OOXML:
|
||||
case UNKNOWN:
|
||||
// Don't check for a Zip header, as to maintain backwards
|
||||
// compatibility we need to let them seek over junk at the
|
||||
// start before beginning processing.
|
||||
|
|
|
@ -38,7 +38,7 @@ public class ZipInputStreamZipEntrySource implements ZipEntrySource {
|
|||
|
||||
/**
|
||||
* Reads all the entries from the ZipInputStream
|
||||
* into memory, and closes the source stream.
|
||||
* into memory, and don't close (since POI 4.0.1) the source stream.
|
||||
* We'll then eat lots of memory, but be able to
|
||||
* work with the entries at-will.
|
||||
*/
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.poi.poifs.crypt.dsig;
|
|||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Security;
|
||||
import java.security.Signature;
|
||||
import java.security.SignatureException;
|
||||
|
||||
|
@ -35,7 +36,12 @@ import org.apache.poi.poifs.crypt.HashAlgorithm;
|
|||
@Override
|
||||
public void init() throws GeneralSecurityException {
|
||||
final String provider = isMSCapi(key) ? "SunMSCAPI" : "SunRsaSign";
|
||||
signature = Signature.getInstance(algo.ecmaString+"withRSA", provider);
|
||||
if (Security.getProvider(provider) != null) {
|
||||
signature = Signature.getInstance(algo.ecmaString + "withRSA", provider);
|
||||
} else {
|
||||
signature = Signature.getInstance(algo.ecmaString + "withRSA");
|
||||
}
|
||||
|
||||
signature.initSign(key);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
|
|||
import org.apache.poi.xssf.usermodel.XSSFCell;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFTable;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.apache.xmlbeans.XmlException;
|
||||
import org.apache.xmlbeans.XmlOptions;
|
||||
|
@ -81,6 +82,27 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumns;
|
|||
|
||||
@Beta
|
||||
public abstract class XDDFChart extends POIXMLDocumentPart implements TextContainer {
|
||||
|
||||
/**
|
||||
* default width of chart in emu
|
||||
*/
|
||||
public static final int DEFAULT_WIDTH = 500000;
|
||||
|
||||
/**
|
||||
* default height of chart in emu
|
||||
*/
|
||||
public static final int DEFAULT_HEIGHT = 500000;
|
||||
|
||||
/**
|
||||
* default x-coordinate of chart in emu
|
||||
*/
|
||||
public static final int DEFAULT_X = 10;
|
||||
|
||||
/**
|
||||
* default y-coordinate value of chart in emu
|
||||
*/
|
||||
public static final int DEFAULT_Y = 10;
|
||||
|
||||
/**
|
||||
* Underlying workbook
|
||||
*/
|
||||
|
@ -712,10 +734,29 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
|
|||
XSSFRow row = this.getRow(sheet, 0);
|
||||
XSSFCell cell = this.getCell(row, column);
|
||||
cell.setCellValue(title);
|
||||
this.updateSheetTable(sheet.getTables().get(0).getCTTable(), title, column);
|
||||
|
||||
CTTable ctTable = this.getSheetTable(sheet);
|
||||
|
||||
this.updateSheetTable(ctTable, title, column);
|
||||
return new CellReference(sheet.getSheetName(), 0, column, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* this method will check whether sheet have table
|
||||
* in case table size zero then create new table and add table columns element
|
||||
* @param sheet
|
||||
* @return table object
|
||||
*/
|
||||
private CTTable getSheetTable(XSSFSheet sheet) {
|
||||
if(sheet.getTables().size() == 0)
|
||||
{
|
||||
XSSFTable newTable = sheet.createTable(null);
|
||||
newTable.getCTTable().addNewTableColumns();
|
||||
sheet.getTables().add(newTable);
|
||||
}
|
||||
return sheet.getTables().get(0).getCTTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* this method update column header of sheet into table
|
||||
*
|
||||
|
@ -729,7 +770,8 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
|
|||
private void updateSheetTable(CTTable ctTable, String title, int index) {
|
||||
CTTableColumns tableColumnList = ctTable.getTableColumns();
|
||||
CTTableColumn column = null;
|
||||
for( int i = 0; tableColumnList.getCount() < index; i++) {
|
||||
int columnCount = tableColumnList.getTableColumnList().size()-1;
|
||||
for( int i = columnCount; i < index; i++) {
|
||||
column = tableColumnList.addNewTableColumn();
|
||||
column.setId(i);
|
||||
}
|
||||
|
|
|
@ -302,14 +302,23 @@ public class XMLSlideShow extends POIXMLDocument
|
|||
* Create a blank chart on the given slide.
|
||||
*/
|
||||
public XSLFChart createChart(XSLFSlide slide) {
|
||||
XSLFChart chart = createChart();
|
||||
slide.addRelation(null, XSLFRelation.CHART, chart);
|
||||
return chart;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to create template for chart XML.
|
||||
* @return Xslf chart object
|
||||
* @since POI 4.0.2
|
||||
*/
|
||||
public XSLFChart createChart() {
|
||||
int chartIdx = findNextAvailableFileNameIndex(XSLFRelation.CHART, _charts.size() + 1);
|
||||
XSLFChart chart = (XSLFChart) createRelationship(XSLFRelation.CHART, XSLFFactory.getInstance(), chartIdx, true).getDocumentPart();
|
||||
slide.addRelation(null, XSLFRelation.CHART, chart);
|
||||
chart.setChartIndex(chartIdx);
|
||||
_charts.add(chart);
|
||||
return chart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return notes slide for the specified slide or create new if it does not exist yet.
|
||||
*/
|
||||
|
@ -416,7 +425,7 @@ public class XMLSlideShow extends POIXMLDocument
|
|||
* Return all the charts in the slideshow
|
||||
*/
|
||||
public List<XSLFChart> getCharts() {
|
||||
return _charts;
|
||||
return Collections.unmodifiableList(_charts);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,16 +19,28 @@
|
|||
|
||||
package org.apache.poi.xslf.usermodel;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.apache.poi.ooxml.POIXMLFactory;
|
||||
import org.apache.poi.ooxml.POIXMLRelation;
|
||||
import org.apache.poi.openxml4j.opc.PackagePart;
|
||||
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
|
||||
import org.apache.poi.util.Beta;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFChart;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.apache.xmlbeans.XmlException;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.chart.CTTitle;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrameNonVisual;
|
||||
|
||||
/**
|
||||
* Represents a Chart in a .pptx presentation
|
||||
|
@ -36,6 +48,8 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
|
|||
@Beta
|
||||
public final class XSLFChart extends XDDFChart {
|
||||
|
||||
private static String CHART_URI = "http://schemas.openxmlformats.org/drawingml/2006/chart";
|
||||
|
||||
/**
|
||||
* Construct a PresentationML chart.
|
||||
*/
|
||||
|
@ -90,4 +104,47 @@ public final class XSLFChart extends XDDFChart {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* method to add graphic frame for XSLF chart
|
||||
*
|
||||
* @param shapeId shape id
|
||||
* @param rID relation id
|
||||
* @param anchor size and location of chart
|
||||
* @return graphic frame object
|
||||
* @since POI 4.0.2
|
||||
*/
|
||||
static CTGraphicalObjectFrame prototype(int shapeId, String rID, Rectangle2D anchor) {
|
||||
CTGraphicalObjectFrame frame = CTGraphicalObjectFrame.Factory.newInstance();
|
||||
CTGraphicalObjectFrameNonVisual nvGr = frame.addNewNvGraphicFramePr();
|
||||
|
||||
CTNonVisualDrawingProps cnv = nvGr.addNewCNvPr();
|
||||
cnv.setName("Chart " + shapeId);
|
||||
cnv.setId(shapeId);
|
||||
nvGr.addNewCNvGraphicFramePr().addNewGraphicFrameLocks().setNoGrp(true);
|
||||
nvGr.addNewNvPr();
|
||||
|
||||
CTTransform2D xfrm = frame.addNewXfrm();
|
||||
|
||||
CTPoint2D off = xfrm.addNewOff();
|
||||
off.setX((int)anchor.getX());
|
||||
off.setY((int)anchor.getY());
|
||||
|
||||
CTPositiveSize2D ext = xfrm.addNewExt();
|
||||
ext.setCx((int)anchor.getWidth());
|
||||
ext.setCy((int)anchor.getHeight());
|
||||
|
||||
xfrm.setExt(ext);
|
||||
xfrm.setOff(off);
|
||||
|
||||
CTGraphicalObjectData gr = frame.addNewGraphic().addNewGraphicData();
|
||||
XmlCursor grCur = gr.newCursor();
|
||||
grCur.toNextToken();
|
||||
grCur.beginElement(new QName(CHART_URI, "chart"));
|
||||
grCur.insertAttributeWithValue("id", PackageRelationshipTypes.CORE_PROPERTIES_ECMA376_NS, rID);
|
||||
grCur.dispose();
|
||||
|
||||
gr.setUri(CHART_URI);
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,6 +107,19 @@ public class XSLFDrawing {
|
|||
return shape;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will add chart into slide's graphic frame
|
||||
*
|
||||
* @param rID relation id of chart
|
||||
* @param rect2D Chart Bounding values
|
||||
* @since POI 4.0.2
|
||||
*/
|
||||
public void addChart(String rID, Rectangle2D rect2D) {
|
||||
CTGraphicalObjectFrame sp = _spTree.addNewGraphicFrame();
|
||||
sp.set(XSLFChart.prototype(_sheet.allocateShapeId(), rID, rect2D));
|
||||
}
|
||||
|
||||
|
||||
public XSLFObjectShape createOleShape(String pictureRel) {
|
||||
CTGraphicalObjectFrame sp = _spTree.addNewGraphicFrame();
|
||||
sp.set(XSLFObjectShape.prototype(_sheet.allocateShapeId(), pictureRel));
|
||||
|
|
|
@ -24,6 +24,12 @@ import java.awt.geom.Path2D;
|
|||
import java.awt.geom.PathIterator;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
|
||||
import org.apache.poi.ooxml.POIXMLTypeLoader;
|
||||
import org.apache.poi.sl.draw.geom.CustomGeometry;
|
||||
import org.apache.poi.sl.draw.geom.PresetGeometries;
|
||||
import org.apache.poi.sl.usermodel.FreeformShape;
|
||||
import org.apache.poi.util.Beta;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
|
@ -31,6 +37,7 @@ import org.apache.poi.util.POILogger;
|
|||
import org.apache.poi.util.Units;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
import org.apache.xmlbeans.XmlOptions;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTAdjPoint2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTCustomGeometry2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomRect;
|
||||
|
@ -61,7 +68,7 @@ public class XSLFFreeformShape extends XSLFAutoShape
|
|||
}
|
||||
|
||||
@Override
|
||||
public int setPath(final Path2D.Double path) {
|
||||
public int setPath(final Path2D path) {
|
||||
final CTPath2D ctPath = CTPath2D.Factory.newInstance();
|
||||
|
||||
final Rectangle2D bounds = path.getBounds2D();
|
||||
|
@ -117,6 +124,30 @@ public class XSLFFreeformShape extends XSLFAutoShape
|
|||
return numPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return definition of the shape geometry
|
||||
*/
|
||||
@Override
|
||||
public CustomGeometry getGeometry() {
|
||||
final XmlObject xo = getShapeProperties();
|
||||
if (!(xo instanceof CTShapeProperties)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
XmlOptions xop = new XmlOptions(POIXMLTypeLoader.DEFAULT_XML_OPTIONS);
|
||||
xop.setSaveOuter();
|
||||
|
||||
XMLStreamReader staxReader = ((CTShapeProperties)xo).getCustGeom().newXMLStreamReader(xop);
|
||||
CustomGeometry custGeo = PresetGeometries.convertCustomGeometry(staxReader);
|
||||
try {
|
||||
staxReader.close();
|
||||
} catch (XMLStreamException e) {
|
||||
LOG.log(POILogger.WARN,
|
||||
"An error occurred while closing a Custom Geometry XML Stream Reader: " + e.getMessage());
|
||||
}
|
||||
|
||||
return custGeo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path2D.Double getPath() {
|
||||
|
|
|
@ -20,6 +20,7 @@ import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
|||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -52,6 +53,7 @@ import org.apache.poi.util.IOUtils;
|
|||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.util.Units;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFChart;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.apache.xmlbeans.XmlException;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
|
@ -313,7 +315,6 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
|
|||
oleObj.setImgW(Units.toEMU(dim.getWidth()));
|
||||
oleObj.setImgH(Units.toEMU(dim.getHeight()));
|
||||
|
||||
|
||||
getShapes().add(sh);
|
||||
sh.setParent(this);
|
||||
return sh;
|
||||
|
@ -719,4 +720,28 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
|
|||
return (ph == null) ? null : new XSLFPlaceholderDetails(ph);
|
||||
}
|
||||
|
||||
/**
|
||||
* this method will add chart into slide
|
||||
* with default height, width, x and y
|
||||
* @param chart xslf chart object
|
||||
* @since POI 4.0.2
|
||||
*/
|
||||
public void addChart(XSLFChart chart) {
|
||||
Rectangle2D rect2D = new java.awt.Rectangle(XDDFChart.DEFAULT_X, XDDFChart.DEFAULT_Y,
|
||||
XDDFChart.DEFAULT_WIDTH, XDDFChart.DEFAULT_HEIGHT);
|
||||
|
||||
this.addChart(chart, rect2D);
|
||||
}
|
||||
|
||||
/**
|
||||
* this method will add chart into slide
|
||||
* with given height, width, x and y
|
||||
* @param chart xslf chart object
|
||||
* @since POI 4.0.2
|
||||
*/
|
||||
public void addChart(XSLFChart chart, Rectangle2D rect2D) {
|
||||
RelationPart rp = addRelation(null, XSLFRelation.CHART, chart);
|
||||
getDrawing().addChart(rp.getRelationship().getId(), rect2D);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -716,7 +716,6 @@ public abstract class XSLFSimpleShape extends XSLFShape
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return definition of the shape geometry
|
||||
*/
|
||||
@Override
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.apache.commons.compress.archivers.zip.Zip64Mode;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
|
||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||
|
@ -51,13 +52,7 @@ import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
|
|||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.SheetVisibility;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.apache.poi.util.NotImplemented;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.util.Removal;
|
||||
import org.apache.poi.util.TempFile;
|
||||
import org.apache.poi.util.*;
|
||||
import org.apache.poi.xssf.model.SharedStringsTable;
|
||||
import org.apache.poi.xssf.usermodel.XSSFChartSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
|
@ -117,6 +112,8 @@ public class SXSSFWorkbook implements Workbook {
|
|||
*/
|
||||
private final SharedStringsTable _sharedStringSource;
|
||||
|
||||
private Zip64Mode zip64Mode = Zip64Mode.AsNeeded;
|
||||
|
||||
/**
|
||||
* Construct a new workbook with default row window size
|
||||
*/
|
||||
|
@ -250,6 +247,7 @@ public class SXSSFWorkbook implements Workbook {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an empty workbook and specify the window for row access.
|
||||
* <p>
|
||||
|
@ -290,6 +288,16 @@ public class SXSSFWorkbook implements Workbook {
|
|||
_randomAccessWindowSize = rowAccessWindowSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param zip64Mode {@link Zip64Mode}
|
||||
*
|
||||
* @since 4.0.3
|
||||
*/
|
||||
@Beta
|
||||
public void setZip64Mode(Zip64Mode zip64Mode) {
|
||||
this.zip64Mode = zip64Mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether temp files should be compressed.
|
||||
*
|
||||
|
@ -298,6 +306,7 @@ public class SXSSFWorkbook implements Workbook {
|
|||
public boolean isCompressTempFiles() {
|
||||
return _compressTmpFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether temp files should be compressed.
|
||||
* <p>
|
||||
|
@ -377,6 +386,7 @@ public class SXSSFWorkbook implements Workbook {
|
|||
|
||||
protected void injectData(ZipEntrySource zipEntrySource, OutputStream out) throws IOException {
|
||||
ZipArchiveOutputStream zos = new ZipArchiveOutputStream(out);
|
||||
zos.setUseZip64(zip64Mode);
|
||||
try {
|
||||
Enumeration<? extends ZipArchiveEntry> en = zipEntrySource.getEntries();
|
||||
while (en.hasMoreElements()) {
|
||||
|
|
|
@ -39,12 +39,12 @@ public class XWPFChart extends XDDFChart {
|
|||
/**
|
||||
* default width of chart in emu
|
||||
*/
|
||||
public static final int DEFAULT_WIDTH = 500000;
|
||||
public static final int DEFAULT_WIDTH = XDDFChart.DEFAULT_WIDTH;
|
||||
|
||||
/**
|
||||
* default height of chart in emu
|
||||
*/
|
||||
public static final int DEFAULT_HEIGHT = 500000;
|
||||
public static final int DEFAULT_HEIGHT = XDDFChart.DEFAULT_HEIGHT;
|
||||
|
||||
// lazy initialization
|
||||
private Long checksum;
|
||||
|
|
|
@ -58,6 +58,7 @@ import org.apache.poi.util.Internal;
|
|||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.wp.usermodel.HeaderFooterType;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFChart;
|
||||
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.apache.xmlbeans.XmlException;
|
||||
|
@ -1672,7 +1673,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody {
|
|||
* @since POI 4.0.0
|
||||
*/
|
||||
public XWPFChart createChart() throws InvalidFormatException, IOException {
|
||||
return createChart(XWPFChart.DEFAULT_WIDTH, XWPFChart.DEFAULT_HEIGHT);
|
||||
return createChart(XDDFChart.DEFAULT_WIDTH, XDDFChart.DEFAULT_HEIGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.poi.ooxml;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
@ -89,7 +90,7 @@ public final class TestPOIXMLProperties {
|
|||
XSSFWorkbook newWorkbook =
|
||||
XSSFTestDataSamples.writeOutAndReadBack(workbook);
|
||||
workbook.close();
|
||||
assertTrue(workbook != newWorkbook);
|
||||
assertNotSame(workbook, newWorkbook);
|
||||
|
||||
|
||||
POIXMLProperties newProps = newWorkbook.getProperties();
|
||||
|
@ -158,7 +159,7 @@ public final class TestPOIXMLProperties {
|
|||
p = ctProps.getPropertyArray(3);
|
||||
assertEquals("{D5CDD505-2E9C-101B-9397-08002B2CF9AE}", p.getFmtid());
|
||||
assertEquals("test-4", p.getName());
|
||||
assertEquals(true, p.getBool());
|
||||
assertTrue(p.getBool());
|
||||
assertEquals(5, p.getPid());
|
||||
|
||||
wb2.close();
|
||||
|
|
|
@ -60,6 +60,7 @@ import javax.xml.crypto.dsig.CanonicalizationMethod;
|
|||
import javax.xml.crypto.dsig.dom.DOMSignContext;
|
||||
|
||||
import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
|
||||
import org.apache.poi.EncryptedDocumentException;
|
||||
import org.apache.poi.POIDataSamples;
|
||||
import org.apache.poi.POITestCase;
|
||||
import org.apache.poi.ooxml.util.DocumentHelper;
|
||||
|
@ -682,6 +683,8 @@ public class TestSignatureInfo {
|
|||
si.confirmSignature();
|
||||
boolean b = si.verifySignature();
|
||||
assertTrue("Signature not correctly calculated for " + ha, b);
|
||||
} catch (EncryptedDocumentException e) {
|
||||
Assume.assumeTrue(e.getMessage().startsWith("Export Restrictions"));
|
||||
} finally {
|
||||
if (pkg != null) {
|
||||
pkg.close();
|
||||
|
|
|
@ -87,6 +87,10 @@ public class TestNecessaryOOXMLClasses {
|
|||
Assert.assertNotNull(ctLblAlgn);
|
||||
CTDashStopList ctDashStopList = CTDashStopList.Factory.newInstance();
|
||||
Assert.assertNotNull(ctDashStopList);
|
||||
STDispBlanksAs stDashBlanksAs = STDispBlanksAs.Factory.newInstance();
|
||||
Assert.assertNotNull(stDashBlanksAs);
|
||||
CTDispBlanksAs ctDashBlanksAs = CTDispBlanksAs.Factory.newInstance();
|
||||
Assert.assertNotNull(ctDashBlanksAs);
|
||||
|
||||
STLblAlgn.Enum e1 = STLblAlgn.Enum.forString("ctr");
|
||||
Assert.assertNotNull(e1);
|
||||
|
@ -100,6 +104,8 @@ public class TestNecessaryOOXMLClasses {
|
|||
Assert.assertNotNull(e5);
|
||||
STMarkerStyle.Enum e6 = STMarkerStyle.Enum.forString("circle");
|
||||
Assert.assertNotNull(e6);
|
||||
STDispBlanksAs.Enum e7 = STDispBlanksAs.Enum.forString("span");
|
||||
Assert.assertNotNull(e7);
|
||||
|
||||
CTTextBulletTypefaceFollowText ctTextBulletTypefaceFollowText = CTTextBulletTypefaceFollowText.Factory.newInstance();
|
||||
Assert.assertNotNull(ctTextBulletTypefaceFollowText);
|
||||
|
|
|
@ -42,7 +42,7 @@ public class TestXDGFVisioExtractor {
|
|||
}
|
||||
|
||||
@After
|
||||
public void closeResoures() throws IOException {
|
||||
public void closeResources() throws IOException {
|
||||
if(xml != null) {
|
||||
xml.close();
|
||||
}
|
||||
|
|
|
@ -47,7 +47,9 @@ public class TestPPTX2PNG {
|
|||
private static final POIDataSamples samples = POIDataSamples.getSlideShowInstance();
|
||||
private static final File basedir = null;
|
||||
private static final String files =
|
||||
"53446.ppt, alterman_security.ppt, alterman_security.pptx, KEY02.pptx, themes.pptx, backgrounds.pptx, layouts.pptx, sample.pptx, shapes.pptx, 54880_chinese.ppt";
|
||||
"53446.ppt, alterman_security.ppt, alterman_security.pptx, KEY02.pptx, themes.pptx, " +
|
||||
"backgrounds.pptx, layouts.pptx, sample.pptx, shapes.pptx, 54880_chinese.ppt, keyframes.pptx," +
|
||||
"customGeo.pptx, customGeo.ppt";
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import static org.apache.poi.sl.TestCommonSL.sameColor;
|
|||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
@ -194,4 +195,20 @@ public class TestXSLFSlide {
|
|||
|
||||
ppt.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateChart() throws IOException {
|
||||
XMLSlideShow ppt = new XMLSlideShow();
|
||||
XSLFSlide slide = ppt.createSlide();
|
||||
XSLFChart chart = ppt.createChart();
|
||||
assertNotNull(chart);
|
||||
|
||||
slide.addChart(chart);
|
||||
assertEquals(XSLFRelation.CHART.getContentType(), chart.getPackagePart().getContentType());
|
||||
|
||||
String partName = slide.getRelationPartById("rId2").getDocumentPart().getPackagePart().getPartName().getName();
|
||||
assertEquals(partName, chart.getPackagePart().getPartName().getName());
|
||||
|
||||
ppt.close();
|
||||
}
|
||||
}
|
|
@ -70,7 +70,7 @@ public class XSSFTestDataSamples {
|
|||
* @param wb the workbook to write
|
||||
* @param testName a fragment of the filename
|
||||
* @return the location where the workbook was saved
|
||||
* @throws IOException
|
||||
* @throws IOException If writing the file fails
|
||||
*/
|
||||
public static <R extends Workbook> File writeOut(R wb, String testName) throws IOException {
|
||||
final File file = getOutputFile(testName);
|
||||
|
@ -104,7 +104,9 @@ public class XSSFTestDataSamples {
|
|||
file = TempFile.createTempFile(testName, ".xlsx");
|
||||
}
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
if(!file.delete()) {
|
||||
throw new IOException("Could not delete file " + file);
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
@ -114,7 +116,7 @@ public class XSSFTestDataSamples {
|
|||
*
|
||||
* @param wb the workbook to write
|
||||
* @return the memory buffer
|
||||
* @throws IOException
|
||||
* @throws IOException If writing the file fails
|
||||
*/
|
||||
public static <R extends Workbook> ByteArrayOutputStream writeOut(R wb) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(8192);
|
||||
|
@ -137,7 +139,7 @@ public class XSSFTestDataSamples {
|
|||
* to avoid creating a temporary file. However, this may complicate the calling
|
||||
* code to avoid having the workbook, BAOS, and BAIS open at the same time.
|
||||
*
|
||||
* @param wb
|
||||
* @param wb The workbook to write out, it is closed after the call.
|
||||
* @param testName file name to be used to write to a file. This file will be cleaned up by a call to readBack(String)
|
||||
* @return workbook location
|
||||
* @throws RuntimeException if {@link #TEST_OUTPUT_DIR} System property is not set
|
||||
|
@ -161,18 +163,13 @@ public class XSSFTestDataSamples {
|
|||
*
|
||||
* @param wb the workbook to write
|
||||
* @return the memory buffer
|
||||
* @throws IOException
|
||||
* @throws RuntimeException If writing the file fails
|
||||
*/
|
||||
public static <R extends Workbook> ByteArrayOutputStream writeOutAndClose(R wb) {
|
||||
try {
|
||||
ByteArrayOutputStream out = writeOut(wb);
|
||||
// Do not close the workbook if there was a problem writing the workbook
|
||||
wb.close();
|
||||
return out;
|
||||
}
|
||||
catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
public static <R extends Workbook> ByteArrayOutputStream writeOutAndClose(R wb) throws IOException {
|
||||
ByteArrayOutputStream out = writeOut(wb);
|
||||
// Do not close the workbook if there was a problem writing the workbook
|
||||
wb.close();
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -183,12 +180,14 @@ public class XSSFTestDataSamples {
|
|||
*
|
||||
* @param file the workbook file to read and delete
|
||||
* @return the read back workbook
|
||||
* @throws IOException
|
||||
* @throws IOException If reading or deleting the file fails
|
||||
*/
|
||||
public static XSSFWorkbook readBackAndDelete(File file) throws IOException {
|
||||
XSSFWorkbook wb = readBack(file);
|
||||
// do not delete the file if there's an error--might be helpful for debugging
|
||||
file.delete();
|
||||
if(!file.delete()) {
|
||||
throw new IOException("Could not delete file " + file + " after reading");
|
||||
}
|
||||
return wb;
|
||||
}
|
||||
|
||||
|
@ -198,16 +197,12 @@ public class XSSFTestDataSamples {
|
|||
*
|
||||
* @param file the workbook file to read
|
||||
* @return the read back workbook
|
||||
* @throws IOException
|
||||
* @throws IOException If reading the file fails
|
||||
*/
|
||||
public static XSSFWorkbook readBack(File file) throws IOException {
|
||||
InputStream in = new FileInputStream(file);
|
||||
try {
|
||||
try (InputStream in = new FileInputStream(file)) {
|
||||
return new XSSFWorkbook(in);
|
||||
}
|
||||
finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -216,17 +211,13 @@ public class XSSFTestDataSamples {
|
|||
*
|
||||
* @param out the output stream to read back from
|
||||
* @return the read back workbook
|
||||
* @throws IOException
|
||||
* @throws IOException If reading the file fails
|
||||
*/
|
||||
public static XSSFWorkbook readBack(ByteArrayOutputStream out) throws IOException {
|
||||
InputStream is = new ByteArrayInputStream(out.toByteArray());
|
||||
out.close();
|
||||
try {
|
||||
try (InputStream is = new ByteArrayInputStream(out.toByteArray())) {
|
||||
out.close();
|
||||
return new XSSFWorkbook(is);
|
||||
}
|
||||
finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -452,4 +452,12 @@ public class TestXWPFWordExtractor extends TestCase {
|
|||
//once we add processing for this, we can change this to contains
|
||||
assertNotContained(txt, "table rows");
|
||||
}
|
||||
|
||||
public void testPartsInTemplate() throws IOException {
|
||||
XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("60316b.dotx");
|
||||
XWPFWordExtractor extractor = new XWPFWordExtractor(doc);
|
||||
String txt = extractor.getText();
|
||||
assertContains(txt, "header 2");
|
||||
assertContains(txt, "footer 1");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
package org.apache.poi.hslf.record;
|
||||
|
||||
import static org.apache.poi.hslf.usermodel.HSLFSlideShow.PP95_DOCUMENT;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -143,7 +145,7 @@ public class CurrentUserAtom
|
|||
// See how long it is. If it's under 28 bytes long, we can't
|
||||
// read it
|
||||
if(_contents.length < 28) {
|
||||
boolean isPP95 = dir.hasEntry("PP40");
|
||||
boolean isPP95 = dir.hasEntry(PP95_DOCUMENT);
|
||||
// PPT95 has 4 byte size, then data
|
||||
if (!isPP95 && _contents.length >= 4) {
|
||||
int size = LittleEndian.getInt(_contents);
|
||||
|
|
|
@ -17,21 +17,122 @@
|
|||
|
||||
package org.apache.poi.hslf.usermodel;
|
||||
|
||||
import java.awt.geom.Arc2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.ddf.AbstractEscherOptRecord;
|
||||
import org.apache.poi.ddf.EscherArrayProperty;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherProperties;
|
||||
import org.apache.poi.sl.usermodel.*;
|
||||
import org.apache.poi.ddf.EscherProperty;
|
||||
import org.apache.poi.ddf.EscherSimpleProperty;
|
||||
import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
|
||||
import org.apache.poi.sl.draw.binding.CTCustomGeometry2D;
|
||||
import org.apache.poi.sl.draw.binding.CTPath2D;
|
||||
import org.apache.poi.sl.draw.binding.CTPath2DArcTo;
|
||||
import org.apache.poi.sl.draw.binding.CTPath2DCubicBezierTo;
|
||||
import org.apache.poi.sl.draw.binding.CTPath2DLineTo;
|
||||
import org.apache.poi.sl.draw.binding.CTPath2DList;
|
||||
import org.apache.poi.sl.draw.binding.CTPath2DMoveTo;
|
||||
import org.apache.poi.sl.draw.binding.ObjectFactory;
|
||||
import org.apache.poi.sl.draw.geom.CustomGeometry;
|
||||
import org.apache.poi.sl.usermodel.AutoShape;
|
||||
import org.apache.poi.sl.usermodel.ShapeContainer;
|
||||
import org.apache.poi.sl.usermodel.ShapeType;
|
||||
import org.apache.poi.sl.usermodel.VerticalAlignment;
|
||||
import org.apache.poi.ss.usermodel.ShapeTypes;
|
||||
import org.apache.poi.util.BitField;
|
||||
import org.apache.poi.util.BitFieldFactory;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
/**
|
||||
* Represents an AutoShape.
|
||||
* <p>
|
||||
* Represents an AutoShape.<p>
|
||||
*
|
||||
* AutoShapes are drawing objects with a particular shape that may be customized through smart resizing and adjustments.
|
||||
* See {@link ShapeTypes}
|
||||
* </p>
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,HSLFTextParagraph> {
|
||||
private static final POILogger LOG = POILogFactory.getLogger(HSLFAutoShape.class);
|
||||
|
||||
static final byte[] SEGMENTINFO_MOVETO = new byte[]{0x00, 0x40};
|
||||
static final byte[] SEGMENTINFO_LINETO = new byte[]{0x00, (byte)0xAC};
|
||||
static final byte[] SEGMENTINFO_ESCAPE = new byte[]{0x01, 0x00};
|
||||
static final byte[] SEGMENTINFO_ESCAPE2 = new byte[]{0x01, 0x20};
|
||||
static final byte[] SEGMENTINFO_CUBICTO = new byte[]{0x00, (byte)0xAD};
|
||||
// OpenOffice inserts 0xB3 instead of 0xAD.
|
||||
// protected static final byte[] SEGMENTINFO_CUBICTO2 = new byte[]{0x00, (byte)0xB3};
|
||||
static final byte[] SEGMENTINFO_CLOSE = new byte[]{0x01, (byte)0x60};
|
||||
static final byte[] SEGMENTINFO_END = new byte[]{0x00, (byte)0x80};
|
||||
|
||||
private static final BitField PATH_INFO = BitFieldFactory.getInstance(0xE000);
|
||||
private static final BitField ESCAPE_INFO = BitFieldFactory.getInstance(0x1F00);
|
||||
|
||||
enum PathInfo {
|
||||
lineTo(0),curveTo(1),moveTo(2),close(3),end(4),escape(5),clientEscape(6);
|
||||
private final int flag;
|
||||
PathInfo(int flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
public int getFlag() {
|
||||
return flag;
|
||||
}
|
||||
static PathInfo valueOf(int flag) {
|
||||
for (PathInfo v : values()) {
|
||||
if (v.flag == flag) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
enum EscapeInfo {
|
||||
EXTENSION(0x0000),
|
||||
ANGLE_ELLIPSE_TO(0x0001),
|
||||
ANGLE_ELLIPSE(0x0002),
|
||||
ARC_TO(0x0003),
|
||||
ARC(0x0004),
|
||||
CLOCKWISE_ARC_TO(0x0005),
|
||||
CLOCKWISE_ARC(0x0006),
|
||||
ELLIPTICAL_QUADRANT_X(0x0007),
|
||||
ELLIPTICAL_QUADRANT_Y(0x0008),
|
||||
QUADRATIC_BEZIER(0x0009),
|
||||
NO_FILL(0X000A),
|
||||
NO_LINE(0X000B),
|
||||
AUTO_LINE(0X000C),
|
||||
AUTO_CURVE(0X000D),
|
||||
CORNER_LINE(0X000E),
|
||||
CORNER_CURVE(0X000F),
|
||||
SMOOTH_LINE(0X0010),
|
||||
SMOOTH_CURVE(0X0011),
|
||||
SYMMETRIC_LINE(0X0012),
|
||||
SYMMETRIC_CURVE(0X0013),
|
||||
FREEFORM(0X0014),
|
||||
FILL_COLOR(0X0015),
|
||||
LINE_COLOR(0X0016);
|
||||
|
||||
private final int flag;
|
||||
EscapeInfo(int flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
public int getFlag() {
|
||||
return flag;
|
||||
}
|
||||
static EscapeInfo valueOf(int flag) {
|
||||
for (EscapeInfo v : values()) {
|
||||
if (v.flag == flag) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected HSLFAutoShape(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
|
||||
super(escherRecord, parent);
|
||||
|
@ -72,13 +173,11 @@ public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets adjust value which controls smart resizing of the auto-shape.
|
||||
* Gets adjust value which controls smart resizing of the auto-shape.<p>
|
||||
*
|
||||
* <p>
|
||||
* The adjustment values are given in shape coordinates:
|
||||
* the origin is at the top-left, positive-x is to the right, positive-y is down.
|
||||
* The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant).
|
||||
* </p>
|
||||
*
|
||||
* @param idx the adjust index in the [0, 9] range
|
||||
* @return the adjustment value
|
||||
|
@ -90,13 +189,11 @@ public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets adjust value which controls smart resizing of the auto-shape.
|
||||
* Sets adjust value which controls smart resizing of the auto-shape.<p>
|
||||
*
|
||||
* <p>
|
||||
* The adjustment values are given in shape coordinates:
|
||||
* the origin is at the top-left, positive-x is to the right, positive-y is down.
|
||||
* The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant).
|
||||
* </p>
|
||||
*
|
||||
* @param idx the adjust index in the [0, 9] range
|
||||
* @param val the adjustment value
|
||||
|
@ -106,4 +203,278 @@ public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,
|
|||
|
||||
setEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx), val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomGeometry getGeometry() {
|
||||
return getGeometry(new Path2D.Double());
|
||||
}
|
||||
|
||||
CustomGeometry getGeometry(Path2D path2D) {
|
||||
final ObjectFactory of = new ObjectFactory();
|
||||
final CTCustomGeometry2D cusGeo = of.createCTCustomGeometry2D();
|
||||
cusGeo.setAvLst(of.createCTGeomGuideList());
|
||||
cusGeo.setGdLst(of.createCTGeomGuideList());
|
||||
cusGeo.setAhLst(of.createCTAdjustHandleList());
|
||||
cusGeo.setCxnLst(of.createCTConnectionSiteList());
|
||||
|
||||
final AbstractEscherOptRecord opt = getEscherOptRecord();
|
||||
|
||||
EscherArrayProperty verticesProp = getShapeProp(opt, EscherProperties.GEOMETRY__VERTICES);
|
||||
EscherArrayProperty segmentsProp = getShapeProp(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
|
||||
|
||||
// return empty path if either GEOMETRY__VERTICES or GEOMETRY__SEGMENTINFO is missing, see Bugzilla 54188
|
||||
|
||||
//sanity check
|
||||
if(verticesProp == null) {
|
||||
LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES ");
|
||||
return super.getGeometry();
|
||||
}
|
||||
if(segmentsProp == null) {
|
||||
LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO ");
|
||||
return super.getGeometry();
|
||||
}
|
||||
|
||||
final Iterator<byte[]> vertIter = verticesProp.iterator();
|
||||
final Iterator<byte[]> segIter = segmentsProp.iterator();
|
||||
final int[] xyPoints = new int[2];
|
||||
boolean isClosed = false;
|
||||
|
||||
final CTPath2DList pathLst = of.createCTPath2DList();
|
||||
final CTPath2D pathCT = of.createCTPath2D();
|
||||
final List<Object> moveLst = pathCT.getCloseOrMoveToOrLnTo();
|
||||
pathLst.getPath().add(pathCT);
|
||||
cusGeo.setPathLst(pathLst);
|
||||
|
||||
while (segIter.hasNext()) {
|
||||
byte[] segElem = segIter.next();
|
||||
HSLFFreeformShape.PathInfo pi = getPathInfo(segElem);
|
||||
if (pi == null) {
|
||||
continue;
|
||||
}
|
||||
switch (pi) {
|
||||
case escape: {
|
||||
handleEscapeInfo(pathCT, path2D, segElem, vertIter);
|
||||
break;
|
||||
}
|
||||
case moveTo:
|
||||
if (vertIter.hasNext()) {
|
||||
final CTPath2DMoveTo m = of.createCTPath2DMoveTo();
|
||||
m.setPt(fillPoint(vertIter.next(), xyPoints));
|
||||
moveLst.add(m);
|
||||
path2D.moveTo(xyPoints[0], xyPoints[1]);
|
||||
}
|
||||
break;
|
||||
case lineTo:
|
||||
if (vertIter.hasNext()) {
|
||||
final CTPath2DLineTo m = of.createCTPath2DLineTo();
|
||||
m.setPt(fillPoint(vertIter.next(), xyPoints));
|
||||
moveLst.add(m);
|
||||
path2D.lineTo(xyPoints[0], xyPoints[1]);
|
||||
}
|
||||
break;
|
||||
case curveTo: {
|
||||
final CTPath2DCubicBezierTo m = of.createCTPath2DCubicBezierTo();
|
||||
List<CTAdjPoint2D> mLst = m.getPt();
|
||||
|
||||
int[] pts = new int[6];
|
||||
|
||||
for (int i=0; vertIter.hasNext() && i<3; i++) {
|
||||
mLst.add(fillPoint(vertIter.next(), xyPoints));
|
||||
pts[i*2] = xyPoints[0];
|
||||
pts[i*2+1] = xyPoints[1];
|
||||
if (i == 2) {
|
||||
moveLst.add(m);
|
||||
path2D.curveTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case close:
|
||||
moveLst.add(of.createCTPath2DClose());
|
||||
path2D.closePath();
|
||||
isClosed = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EscherSimpleProperty shapePath = getShapeProp(opt, EscherProperties.GEOMETRY__SHAPEPATH);
|
||||
HSLFFreeformShape.ShapePath sp = HSLFFreeformShape.ShapePath.valueOf(shapePath == null ? 1 : shapePath.getPropertyValue());
|
||||
if ((sp == HSLFFreeformShape.ShapePath.LINES_CLOSED || sp == HSLFFreeformShape.ShapePath.CURVES_CLOSED) && !isClosed) {
|
||||
moveLst.add(of.createCTPath2DClose());
|
||||
path2D.closePath();
|
||||
}
|
||||
|
||||
EscherSimpleProperty geoLeft = getShapeProp(opt, EscherProperties.GEOMETRY__LEFT);
|
||||
EscherSimpleProperty geoRight = getShapeProp(opt, EscherProperties.GEOMETRY__RIGHT);
|
||||
EscherSimpleProperty geoTop = getShapeProp(opt, EscherProperties.GEOMETRY__TOP);
|
||||
EscherSimpleProperty geoBottom = getShapeProp(opt, EscherProperties.GEOMETRY__BOTTOM);
|
||||
|
||||
final Rectangle2D bounds;
|
||||
if (geoLeft != null && geoRight != null && geoTop != null && geoBottom != null) {
|
||||
bounds = new Rectangle2D.Double();
|
||||
bounds.setFrameFromDiagonal(
|
||||
new Point2D.Double(geoLeft.getPropertyValue(), geoTop.getPropertyValue()),
|
||||
new Point2D.Double(geoRight.getPropertyValue(), geoBottom.getPropertyValue())
|
||||
);
|
||||
} else {
|
||||
bounds = path2D.getBounds2D();
|
||||
}
|
||||
|
||||
pathCT.setW((int)Math.rint(bounds.getWidth()));
|
||||
pathCT.setH((int)Math.rint(bounds.getHeight()));
|
||||
|
||||
return new CustomGeometry(cusGeo);
|
||||
}
|
||||
|
||||
private void handleEscapeInfo(CTPath2D pathCT, Path2D path2D, byte[] segElem, Iterator<byte[]> vertIter) {
|
||||
final ObjectFactory of = new ObjectFactory();
|
||||
HSLFFreeformShape.EscapeInfo ei = getEscapeInfo(segElem);
|
||||
switch (ei) {
|
||||
case EXTENSION:
|
||||
break;
|
||||
case ANGLE_ELLIPSE_TO:
|
||||
break;
|
||||
case ANGLE_ELLIPSE:
|
||||
break;
|
||||
case ARC_TO: {
|
||||
// The first two POINT values specify the bounding rectangle of the ellipse.
|
||||
// The second two POINT values specify the radial vectors for the ellipse.
|
||||
// The radial vectors are cast from the center of the bounding rectangle.
|
||||
// The path starts at the POINT where the first radial vector intersects the
|
||||
// bounding rectangle and goes to the POINT where the second radial vector
|
||||
// intersects the bounding rectangle. The drawing direction is always counterclockwise.
|
||||
// If the path has already been started, a line is drawn from the last POINT to
|
||||
// the starting POINT of the arc; otherwise, a new path is started.
|
||||
// The number of arc segments drawn equals the number of segments divided by four.
|
||||
|
||||
int[] r1 = new int[2], r2 = new int[2], start = new int[2], end = new int[2];
|
||||
fillPoint(vertIter.next(), r1);
|
||||
fillPoint(vertIter.next(), r2);
|
||||
fillPoint(vertIter.next(), start);
|
||||
fillPoint(vertIter.next(), end);
|
||||
|
||||
Arc2D arc2D = new Arc2D.Double();
|
||||
Rectangle2D.Double bounds = new Rectangle2D.Double();
|
||||
bounds.setFrameFromDiagonal(xy2p(r1), xy2p(r2));
|
||||
arc2D.setFrame(bounds);
|
||||
arc2D.setAngles(xy2p(start), xy2p(end));
|
||||
path2D.append(arc2D, true);
|
||||
|
||||
|
||||
CTPath2DArcTo arcTo = of.createCTPath2DArcTo();
|
||||
arcTo.setHR(d2s(bounds.getHeight()/2.0));
|
||||
arcTo.setWR(d2s(bounds.getWidth()/2.0));
|
||||
|
||||
arcTo.setStAng(d2s(-arc2D.getAngleStart()*60000.));
|
||||
arcTo.setSwAng(d2s(-arc2D.getAngleExtent()*60000.));
|
||||
|
||||
pathCT.getCloseOrMoveToOrLnTo().add(arcTo);
|
||||
|
||||
break;
|
||||
}
|
||||
case ARC:
|
||||
break;
|
||||
case CLOCKWISE_ARC_TO:
|
||||
break;
|
||||
case CLOCKWISE_ARC:
|
||||
break;
|
||||
case ELLIPTICAL_QUADRANT_X:
|
||||
break;
|
||||
case ELLIPTICAL_QUADRANT_Y:
|
||||
break;
|
||||
case QUADRATIC_BEZIER:
|
||||
break;
|
||||
case NO_FILL:
|
||||
break;
|
||||
case NO_LINE:
|
||||
break;
|
||||
case AUTO_LINE:
|
||||
break;
|
||||
case AUTO_CURVE:
|
||||
break;
|
||||
case CORNER_LINE:
|
||||
break;
|
||||
case CORNER_CURVE:
|
||||
break;
|
||||
case SMOOTH_LINE:
|
||||
break;
|
||||
case SMOOTH_CURVE:
|
||||
break;
|
||||
case SYMMETRIC_LINE:
|
||||
break;
|
||||
case SYMMETRIC_CURVE:
|
||||
break;
|
||||
case FREEFORM:
|
||||
break;
|
||||
case FILL_COLOR:
|
||||
break;
|
||||
case LINE_COLOR:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static String d2s(double d) {
|
||||
return Integer.toString((int)Math.rint(d));
|
||||
}
|
||||
|
||||
private static Point2D xy2p(int[] xyPoints) {
|
||||
return new Point2D.Double(xyPoints[0],xyPoints[1]);
|
||||
}
|
||||
|
||||
private static HSLFFreeformShape.PathInfo getPathInfo(byte[] elem) {
|
||||
int elemUS = LittleEndian.getUShort(elem, 0);
|
||||
int pathInfo = PATH_INFO.getValue(elemUS);
|
||||
return HSLFFreeformShape.PathInfo.valueOf(pathInfo);
|
||||
}
|
||||
|
||||
private static HSLFFreeformShape.EscapeInfo getEscapeInfo(byte[] elem) {
|
||||
int elemUS = LittleEndian.getUShort(elem, 0);
|
||||
int escInfo = ESCAPE_INFO.getValue(elemUS);
|
||||
return HSLFFreeformShape.EscapeInfo.valueOf(escInfo);
|
||||
}
|
||||
|
||||
|
||||
private static <T extends EscherProperty> T getShapeProp(AbstractEscherOptRecord opt, int propId) {
|
||||
T prop = getEscherProperty(opt, (short)(propId + 0x4000));
|
||||
if (prop == null) {
|
||||
prop = getEscherProperty(opt, propId);
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
private CTAdjPoint2D fillPoint(byte[] xyMaster, int[] xyPoints) {
|
||||
if (xyMaster == null || xyPoints == null) {
|
||||
LOG.log(POILogger.WARN, "Master bytes or points not set - ignore point");
|
||||
return null;
|
||||
}
|
||||
if ((xyMaster.length != 4 && xyMaster.length != 8) || xyPoints.length != 2) {
|
||||
LOG.log(POILogger.WARN, "Invalid number of master bytes for a single point - ignore point");
|
||||
return null;
|
||||
}
|
||||
|
||||
int x, y;
|
||||
if (xyMaster.length == 4) {
|
||||
x = LittleEndian.getShort(xyMaster, 0);
|
||||
y = LittleEndian.getShort(xyMaster, 2);
|
||||
} else {
|
||||
x = LittleEndian.getInt(xyMaster, 0);
|
||||
y = LittleEndian.getInt(xyMaster, 4);
|
||||
}
|
||||
|
||||
xyPoints[0] = x;
|
||||
xyPoints[1] = y;
|
||||
|
||||
return toPoint(xyPoints);
|
||||
}
|
||||
|
||||
private static CTAdjPoint2D toPoint(int[] xyPoints) {
|
||||
CTAdjPoint2D pt = new CTAdjPoint2D();
|
||||
pt.setX(Integer.toString(xyPoints[0]));
|
||||
pt.setY(Integer.toString(xyPoints[1]));
|
||||
return pt;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,60 +49,61 @@ import org.apache.poi.util.Units;
|
|||
/**
|
||||
* Represents functionality provided by the 'Fill Effects' dialog in PowerPoint.
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public final class HSLFFill {
|
||||
private static final POILogger LOG = POILogFactory.getLogger(HSLFFill.class);
|
||||
|
||||
/**
|
||||
* Fill with a solid color
|
||||
*/
|
||||
public static final int FILL_SOLID = 0;
|
||||
static final int FILL_SOLID = 0;
|
||||
|
||||
/**
|
||||
* Fill with a pattern (bitmap)
|
||||
*/
|
||||
public static final int FILL_PATTERN = 1;
|
||||
static final int FILL_PATTERN = 1;
|
||||
|
||||
/**
|
||||
* A texture (pattern with its own color map)
|
||||
*/
|
||||
public static final int FILL_TEXTURE = 2;
|
||||
static final int FILL_TEXTURE = 2;
|
||||
|
||||
/**
|
||||
* Center a picture in the shape
|
||||
*/
|
||||
public static final int FILL_PICTURE = 3;
|
||||
static final int FILL_PICTURE = 3;
|
||||
|
||||
/**
|
||||
* Shade from start to end points
|
||||
*/
|
||||
public static final int FILL_SHADE = 4;
|
||||
static final int FILL_SHADE = 4;
|
||||
|
||||
/**
|
||||
* Shade from bounding rectangle to end point
|
||||
*/
|
||||
public static final int FILL_SHADE_CENTER = 5;
|
||||
static final int FILL_SHADE_CENTER = 5;
|
||||
|
||||
/**
|
||||
* Shade from shape outline to end point
|
||||
*/
|
||||
public static final int FILL_SHADE_SHAPE = 6;
|
||||
static final int FILL_SHADE_SHAPE = 6;
|
||||
|
||||
/**
|
||||
* Similar to FILL_SHADE, but the fill angle
|
||||
* is additionally scaled by the aspect ratio of
|
||||
* the shape. If shape is square, it is the same as FILL_SHADE
|
||||
*/
|
||||
public static final int FILL_SHADE_SCALE = 7;
|
||||
static final int FILL_SHADE_SCALE = 7;
|
||||
|
||||
/**
|
||||
* shade to title
|
||||
*/
|
||||
public static final int FILL_SHADE_TITLE = 8;
|
||||
static final int FILL_SHADE_TITLE = 8;
|
||||
|
||||
/**
|
||||
* Use the background fill color/pattern
|
||||
*/
|
||||
public static final int FILL_BACKGROUND = 9;
|
||||
static final int FILL_BACKGROUND = 9;
|
||||
|
||||
/**
|
||||
* A bit that specifies whether the RecolorFillAsPicture bit is set.
|
||||
|
@ -214,7 +215,7 @@ public final class HSLFFill {
|
|||
private HSLFShape shape;
|
||||
|
||||
/**
|
||||
* Construct a <code>Fill</code> object for a shape.
|
||||
* Construct a {@code Fill} object for a shape.
|
||||
* Fill information will be read from shape's escher properties.
|
||||
*
|
||||
* @param shape the shape this background applies to
|
||||
|
@ -279,7 +280,7 @@ public final class HSLFFill {
|
|||
|
||||
@Override
|
||||
public ColorStyle[] getGradientColors() {
|
||||
ColorStyle cs[];
|
||||
ColorStyle[] cs;
|
||||
if (colorCnt == 0) {
|
||||
cs = new ColorStyle[2];
|
||||
cs[0] = wrapColor(getBackgroundColor());
|
||||
|
@ -288,7 +289,7 @@ public final class HSLFFill {
|
|||
cs = new ColorStyle[colorCnt];
|
||||
int idx = 0;
|
||||
// TODO: handle palette colors and alpha(?) value
|
||||
for (byte data[] : ep) {
|
||||
for (byte[] data : ep) {
|
||||
EscherColorRef ecr = new EscherColorRef(data, 0, 4);
|
||||
cs[idx++] = wrapColor(shape.getColor(ecr));
|
||||
}
|
||||
|
@ -302,13 +303,13 @@ public final class HSLFFill {
|
|||
|
||||
@Override
|
||||
public float[] getGradientFractions() {
|
||||
float frc[];
|
||||
float[] frc;
|
||||
if (colorCnt == 0) {
|
||||
frc = new float[]{0, 1};
|
||||
} else {
|
||||
frc = new float[colorCnt];
|
||||
int idx = 0;
|
||||
for (byte data[] : ep) {
|
||||
for (byte[] data : ep) {
|
||||
double pos = Units.fixedPointToDouble(LittleEndian.getInt(data, 4));
|
||||
frc[idx++] = (float)pos;
|
||||
}
|
||||
|
@ -354,7 +355,7 @@ public final class HSLFFill {
|
|||
|
||||
/**
|
||||
* Returns fill type.
|
||||
* Must be one of the <code>FILL_*</code> constants defined in this class.
|
||||
* Must be one of the {@code FILL_*} constants defined in this class.
|
||||
*
|
||||
* @return type of fill
|
||||
*/
|
||||
|
@ -364,9 +365,7 @@ public final class HSLFFill {
|
|||
return prop == null ? FILL_SOLID : prop.getPropertyValue();
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
protected void afterInsert(HSLFSheet sh){
|
||||
void afterInsert(HSLFSheet sh){
|
||||
AbstractEscherOptRecord opt = shape.getEscherOptRecord();
|
||||
EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
|
||||
if(p != null) {
|
||||
|
@ -379,7 +378,7 @@ public final class HSLFFill {
|
|||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
protected EscherBSERecord getEscherBSERecord(int idx){
|
||||
EscherBSERecord getEscherBSERecord(int idx){
|
||||
HSLFSheet sheet = shape.getSheet();
|
||||
if(sheet == null) {
|
||||
LOG.log(POILogger.DEBUG, "Fill has not yet been assigned to a sheet");
|
||||
|
@ -399,7 +398,7 @@ public final class HSLFFill {
|
|||
|
||||
/**
|
||||
* Sets fill type.
|
||||
* Must be one of the <code>FILL_*</code> constants defined in this class.
|
||||
* Must be one of the {@code FILL_*} constants defined in this class.
|
||||
*
|
||||
* @param type type of the fill
|
||||
*/
|
||||
|
@ -418,7 +417,7 @@ public final class HSLFFill {
|
|||
|
||||
return (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal))
|
||||
? null
|
||||
: shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY, -1);
|
||||
: shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -462,7 +461,7 @@ public final class HSLFFill {
|
|||
|
||||
return (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal))
|
||||
? null
|
||||
: shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY, -1);
|
||||
: shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -480,7 +479,7 @@ public final class HSLFFill {
|
|||
}
|
||||
|
||||
/**
|
||||
* <code>PictureData</code> object used in a texture, pattern of picture fill.
|
||||
* {@code PictureData} object used in a texture, pattern of picture fill.
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public HSLFPictureData getPictureData(){
|
||||
|
|
|
@ -23,20 +23,16 @@ import java.awt.geom.PathIterator;
|
|||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.ddf.AbstractEscherOptRecord;
|
||||
import org.apache.poi.ddf.EscherArrayProperty;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherProperties;
|
||||
import org.apache.poi.ddf.EscherProperty;
|
||||
import org.apache.poi.ddf.EscherSimpleProperty;
|
||||
import org.apache.poi.sl.usermodel.FreeformShape;
|
||||
import org.apache.poi.sl.usermodel.ShapeContainer;
|
||||
import org.apache.poi.sl.usermodel.ShapeType;
|
||||
import org.apache.poi.util.BitField;
|
||||
import org.apache.poi.util.BitFieldFactory;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
@ -53,79 +49,6 @@ import org.apache.poi.util.Units;
|
|||
public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformShape<HSLFShape,HSLFTextParagraph> {
|
||||
private static final POILogger LOG = POILogFactory.getLogger(HSLFFreeformShape.class);
|
||||
|
||||
private static final byte[] SEGMENTINFO_MOVETO = new byte[]{0x00, 0x40};
|
||||
private static final byte[] SEGMENTINFO_LINETO = new byte[]{0x00, (byte)0xAC};
|
||||
private static final byte[] SEGMENTINFO_ESCAPE = new byte[]{0x01, 0x00};
|
||||
private static final byte[] SEGMENTINFO_ESCAPE2 = new byte[]{0x01, 0x20};
|
||||
private static final byte[] SEGMENTINFO_CUBICTO = new byte[]{0x00, (byte)0xAD};
|
||||
// OpenOffice inserts 0xB3 instead of 0xAD.
|
||||
// private static final byte[] SEGMENTINFO_CUBICTO2 = new byte[]{0x00, (byte)0xB3};
|
||||
private static final byte[] SEGMENTINFO_CLOSE = new byte[]{0x01, (byte)0x60};
|
||||
private static final byte[] SEGMENTINFO_END = new byte[]{0x00, (byte)0x80};
|
||||
|
||||
private static final BitField PATH_INFO = BitFieldFactory.getInstance(0xE000);
|
||||
// private static final BitField ESCAPE_INFO = BitFieldFactory.getInstance(0x1F00);
|
||||
|
||||
enum PathInfo {
|
||||
lineTo(0),curveTo(1),moveTo(2),close(3),end(4),escape(5),clientEscape(6);
|
||||
private final int flag;
|
||||
PathInfo(int flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
public int getFlag() {
|
||||
return flag;
|
||||
}
|
||||
static PathInfo valueOf(int flag) {
|
||||
for (PathInfo v : values()) {
|
||||
if (v.flag == flag) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
enum EscapeInfo {
|
||||
EXTENSION(0x0000),
|
||||
ANGLE_ELLIPSE_TO(0x0001),
|
||||
ANGLE_ELLIPSE(0x0002),
|
||||
ARC_TO(0x0003),
|
||||
ARC(0x0004),
|
||||
CLOCKWISE_ARC_TO(0x0005),
|
||||
CLOCKWISE_ARC(0x0006),
|
||||
ELLIPTICAL_QUADRANT_X(0x0007),
|
||||
ELLIPTICAL_QUADRANT_Y(0x0008),
|
||||
QUADRATIC_BEZIER(0x0009),
|
||||
NO_FILL(0X000A),
|
||||
NO_LINE(0X000B),
|
||||
AUTO_LINE(0X000C),
|
||||
AUTO_CURVE(0X000D),
|
||||
CORNER_LINE(0X000E),
|
||||
CORNER_CURVE(0X000F),
|
||||
SMOOTH_LINE(0X0010),
|
||||
SMOOTH_CURVE(0X0011),
|
||||
SYMMETRIC_LINE(0X0012),
|
||||
SYMMETRIC_CURVE(0X0013),
|
||||
FREEFORM(0X0014),
|
||||
FILL_COLOR(0X0015),
|
||||
LINE_COLOR(0X0016);
|
||||
|
||||
private final int flag;
|
||||
EscapeInfo(int flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
public int getFlag() {
|
||||
return flag;
|
||||
}
|
||||
static EscapeInfo valueOf(int flag) {
|
||||
for (EscapeInfo v : values()) {
|
||||
if (v.flag == flag) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
enum ShapePath {
|
||||
LINES(0),
|
||||
|
@ -182,9 +105,9 @@ public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformSh
|
|||
}
|
||||
|
||||
@Override
|
||||
public int setPath(Path2D.Double path) {
|
||||
public int setPath(Path2D path) {
|
||||
Rectangle2D bounds = path.getBounds2D();
|
||||
PathIterator it = path.getPathIterator(new AffineTransform());
|
||||
PathIterator it = path.getPathIterator(null);
|
||||
|
||||
List<byte[]> segInfo = new ArrayList<>();
|
||||
List<Point2D.Double> pntInfo = new ArrayList<>();
|
||||
|
@ -275,187 +198,24 @@ public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformSh
|
|||
}
|
||||
|
||||
@Override
|
||||
public Path2D.Double getPath(){
|
||||
AbstractEscherOptRecord opt = getEscherOptRecord();
|
||||
|
||||
EscherArrayProperty verticesProp = getShapeProp(opt, EscherProperties.GEOMETRY__VERTICES);
|
||||
EscherArrayProperty segmentsProp = getShapeProp(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
|
||||
|
||||
// return empty path if either GEOMETRY__VERTICES or GEOMETRY__SEGMENTINFO is missing, see Bugzilla 54188
|
||||
Path2D.Double path = new Path2D.Double();
|
||||
|
||||
//sanity check
|
||||
if(verticesProp == null) {
|
||||
LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES ");
|
||||
return path;
|
||||
}
|
||||
if(segmentsProp == null) {
|
||||
LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO ");
|
||||
return path;
|
||||
}
|
||||
|
||||
Iterator<byte[]> vertIter = verticesProp.iterator();
|
||||
Iterator<byte[]> segIter = segmentsProp.iterator();
|
||||
double xyPoints[] = new double[2];
|
||||
|
||||
while (vertIter.hasNext() && segIter.hasNext()) {
|
||||
byte[] segElem = segIter.next();
|
||||
PathInfo pi = getPathInfo(segElem);
|
||||
if (pi != null) {
|
||||
switch (pi) {
|
||||
case escape: {
|
||||
// handleEscapeInfo(path, segElem, vertIter);
|
||||
break;
|
||||
}
|
||||
case moveTo: {
|
||||
fillPoint(vertIter.next(), xyPoints);
|
||||
double x = xyPoints[0];
|
||||
double y = xyPoints[1];
|
||||
path.moveTo(x, y);
|
||||
break;
|
||||
}
|
||||
case curveTo: {
|
||||
fillPoint(vertIter.next(), xyPoints);
|
||||
double x1 = xyPoints[0];
|
||||
double y1 = xyPoints[1];
|
||||
fillPoint(vertIter.next(), xyPoints);
|
||||
double x2 = xyPoints[0];
|
||||
double y2 = xyPoints[1];
|
||||
fillPoint(vertIter.next(), xyPoints);
|
||||
double x3 = xyPoints[0];
|
||||
double y3 = xyPoints[1];
|
||||
path.curveTo(x1, y1, x2, y2, x3, y3);
|
||||
break;
|
||||
}
|
||||
case lineTo:
|
||||
if (vertIter.hasNext()) {
|
||||
fillPoint(vertIter.next(), xyPoints);
|
||||
double x = xyPoints[0];
|
||||
double y = xyPoints[1];
|
||||
path.lineTo(x, y);
|
||||
}
|
||||
break;
|
||||
case close:
|
||||
path.closePath();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EscherSimpleProperty shapePath = getShapeProp(opt, EscherProperties.GEOMETRY__SHAPEPATH);
|
||||
ShapePath sp = ShapePath.valueOf(shapePath == null ? 1 : shapePath.getPropertyValue());
|
||||
if (sp == ShapePath.LINES_CLOSED || sp == ShapePath.CURVES_CLOSED) {
|
||||
path.closePath();
|
||||
}
|
||||
public Path2D getPath(){
|
||||
Path2D path2D = new Path2D.Double();
|
||||
getGeometry(path2D);
|
||||
|
||||
Rectangle2D bounds = path2D.getBounds2D();
|
||||
Rectangle2D anchor = getAnchor();
|
||||
Rectangle2D bounds = path.getBounds2D();
|
||||
AffineTransform at = new AffineTransform();
|
||||
at.translate(anchor.getX(), anchor.getY());
|
||||
at.scale(
|
||||
anchor.getWidth()/bounds.getWidth(),
|
||||
anchor.getHeight()/bounds.getHeight()
|
||||
);
|
||||
return new Path2D.Double(at.createTransformedShape(path));
|
||||
|
||||
path2D.transform(at);
|
||||
|
||||
|
||||
return path2D;
|
||||
}
|
||||
|
||||
private void fillPoint(byte xyMaster[], double xyPoints[]) {
|
||||
if (xyMaster == null || xyPoints == null) {
|
||||
LOG.log(POILogger.WARN, "Master bytes or points not set - ignore point");
|
||||
return;
|
||||
}
|
||||
if ((xyMaster.length != 4 && xyMaster.length != 8) || xyPoints.length != 2) {
|
||||
LOG.log(POILogger.WARN, "Invalid number of master bytes for a single point - ignore point");
|
||||
return;
|
||||
}
|
||||
|
||||
int x, y;
|
||||
if (xyMaster.length == 4) {
|
||||
x = LittleEndian.getShort(xyMaster, 0);
|
||||
y = LittleEndian.getShort(xyMaster, 2);
|
||||
} else {
|
||||
x = LittleEndian.getInt(xyMaster, 0);
|
||||
y = LittleEndian.getInt(xyMaster, 4);
|
||||
}
|
||||
|
||||
xyPoints[0] = Units.masterToPoints(x);
|
||||
xyPoints[1] = Units.masterToPoints(y);
|
||||
}
|
||||
|
||||
private static <T extends EscherProperty> T getShapeProp(AbstractEscherOptRecord opt, int propId) {
|
||||
T prop = getEscherProperty(opt, (short)(propId + 0x4000));
|
||||
if (prop == null) {
|
||||
prop = getEscherProperty(opt, propId);
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
// private void handleEscapeInfo(Path2D path, byte segElem[], Iterator<byte[]> vertIter) {
|
||||
// EscapeInfo ei = getEscapeInfo(segElem);
|
||||
// switch (ei) {
|
||||
// case EXTENSION:
|
||||
// break;
|
||||
// case ANGLE_ELLIPSE_TO:
|
||||
// break;
|
||||
// case ANGLE_ELLIPSE:
|
||||
// break;
|
||||
// case ARC_TO:
|
||||
// break;
|
||||
// case ARC:
|
||||
// break;
|
||||
// case CLOCKWISE_ARC_TO:
|
||||
// break;
|
||||
// case CLOCKWISE_ARC:
|
||||
// break;
|
||||
// case ELLIPTICAL_QUADRANT_X:
|
||||
// break;
|
||||
// case ELLIPTICAL_QUADRANT_Y:
|
||||
// break;
|
||||
// case QUADRATIC_BEZIER:
|
||||
// break;
|
||||
// case NO_FILL:
|
||||
// break;
|
||||
// case NO_LINE:
|
||||
// break;
|
||||
// case AUTO_LINE:
|
||||
// break;
|
||||
// case AUTO_CURVE:
|
||||
// break;
|
||||
// case CORNER_LINE:
|
||||
// break;
|
||||
// case CORNER_CURVE:
|
||||
// break;
|
||||
// case SMOOTH_LINE:
|
||||
// break;
|
||||
// case SMOOTH_CURVE:
|
||||
// break;
|
||||
// case SYMMETRIC_LINE:
|
||||
// break;
|
||||
// case SYMMETRIC_CURVE:
|
||||
// break;
|
||||
// case FREEFORM:
|
||||
// break;
|
||||
// case FILL_COLOR:
|
||||
// break;
|
||||
// case LINE_COLOR:
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
private static PathInfo getPathInfo(byte elem[]) {
|
||||
int elemUS = LittleEndian.getUShort(elem, 0);
|
||||
int pathInfo = PATH_INFO.getValue(elemUS);
|
||||
return PathInfo.valueOf(pathInfo);
|
||||
}
|
||||
|
||||
// private static EscapeInfo getEscapeInfo(byte elem[]) {
|
||||
// int elemUS = LittleEndian.getUShort(elem, 0);
|
||||
// int escInfo = ESCAPE_INFO.getValue(elemUS);
|
||||
// return EscapeInfo.valueOf(escInfo);
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -358,17 +358,18 @@ public abstract class HSLFShape implements Shape<HSLFShape,HSLFTextParagraph> {
|
|||
_sheet = sheet;
|
||||
}
|
||||
|
||||
Color getColor(short colorProperty, short opacityProperty, int defaultColor){
|
||||
AbstractEscherOptRecord opt = getEscherOptRecord();
|
||||
EscherSimpleProperty p = getEscherProperty(opt, colorProperty);
|
||||
if(p == null && defaultColor == -1) return null;
|
||||
|
||||
int val = (p == null) ? defaultColor : p.getPropertyValue();
|
||||
|
||||
EscherColorRef ecr = new EscherColorRef(val);
|
||||
Color col = getColor(ecr);
|
||||
if (col == null) {
|
||||
return null;
|
||||
Color getColor(short colorProperty, short opacityProperty){
|
||||
final AbstractEscherOptRecord opt = getEscherOptRecord();
|
||||
final EscherSimpleProperty colProp = getEscherProperty(opt, colorProperty);
|
||||
final Color col;
|
||||
if (colProp == null) {
|
||||
col = Color.WHITE;
|
||||
} else {
|
||||
EscherColorRef ecr = new EscherColorRef(colProp.getPropertyValue());
|
||||
col = getColor(ecr);
|
||||
if (col == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
double alpha = getAlpha(opacityProperty);
|
||||
|
|
|
@ -164,7 +164,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
|
|||
return null;
|
||||
}
|
||||
|
||||
Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY, -1);
|
||||
Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY);
|
||||
return clr == null ? null : clr;
|
||||
}
|
||||
|
||||
|
@ -179,7 +179,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
|
|||
return null;
|
||||
}
|
||||
|
||||
Color clr = getColor(EscherProperties.LINESTYLE__BACKCOLOR, EscherProperties.LINESTYLE__OPACITY, -1);
|
||||
Color clr = getColor(EscherProperties.LINESTYLE__BACKCOLOR, EscherProperties.LINESTYLE__OPACITY);
|
||||
return clr == null ? null : clr;
|
||||
}
|
||||
|
||||
|
@ -385,7 +385,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
|
|||
* @return color of the line. If color is not set returns <code>java.awt.Color.black</code>
|
||||
*/
|
||||
public Color getShadowColor(){
|
||||
Color clr = getColor(EscherProperties.SHADOWSTYLE__COLOR, EscherProperties.SHADOWSTYLE__OPACITY, -1);
|
||||
Color clr = getColor(EscherProperties.SHADOWSTYLE__COLOR, EscherProperties.SHADOWSTYLE__OPACITY);
|
||||
return clr == null ? Color.black : clr;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
|
|||
|
||||
/** Powerpoint document entry/stream name */
|
||||
public static final String POWERPOINT_DOCUMENT = "PowerPoint Document";
|
||||
public static final String PP95_DOCUMENT = "PP40";
|
||||
|
||||
enum LoadSavePhase {
|
||||
INIT, LOADED
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
package org.apache.poi.hslf.usermodel;
|
||||
|
||||
import static org.apache.poi.hslf.usermodel.HSLFSlideShow.POWERPOINT_DOCUMENT;
|
||||
import static org.apache.poi.hslf.usermodel.HSLFSlideShow.PP95_DOCUMENT;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
|
@ -35,6 +38,7 @@ import java.util.TreeMap;
|
|||
import org.apache.poi.POIDocument;
|
||||
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import org.apache.poi.hslf.exceptions.OldPowerPointFormatException;
|
||||
import org.apache.poi.hslf.record.CurrentUserAtom;
|
||||
import org.apache.poi.hslf.record.DocumentEncryptionAtom;
|
||||
import org.apache.poi.hslf.record.ExOleObjStg;
|
||||
|
@ -183,13 +187,18 @@ public final class HSLFSlideShowImpl extends POIDocument implements Closeable {
|
|||
* @throws IOException when the powerpoint can't be read
|
||||
*/
|
||||
private void readPowerPointStream() throws IOException {
|
||||
final DirectoryNode dir = getDirectory();
|
||||
|
||||
if (!dir.hasEntry(POWERPOINT_DOCUMENT) && dir.hasEntry(PP95_DOCUMENT)) {
|
||||
throw new OldPowerPointFormatException("You seem to have supplied a PowerPoint95 file, which isn't supported");
|
||||
}
|
||||
|
||||
// Get the main document stream
|
||||
DocumentEntry docProps =
|
||||
(DocumentEntry) getDirectory().getEntry(HSLFSlideShow.POWERPOINT_DOCUMENT);
|
||||
DocumentEntry docProps = (DocumentEntry)dir.getEntry(POWERPOINT_DOCUMENT);
|
||||
|
||||
// Grab the document stream
|
||||
int len = docProps.getSize();
|
||||
try (InputStream is = getDirectory().createDocumentInputStream(HSLFSlideShow.POWERPOINT_DOCUMENT)) {
|
||||
try (InputStream is = dir.createDocumentInputStream(docProps)) {
|
||||
_docstream = IOUtils.toByteArray(is, len);
|
||||
}
|
||||
}
|
||||
|
@ -665,8 +674,8 @@ public final class HSLFSlideShowImpl extends POIDocument implements Closeable {
|
|||
|
||||
// Write the PPT stream into the POIFS layer
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(_docstream);
|
||||
outFS.createOrUpdateDocument(bais, HSLFSlideShow.POWERPOINT_DOCUMENT);
|
||||
writtenEntries.add(HSLFSlideShow.POWERPOINT_DOCUMENT);
|
||||
outFS.createOrUpdateDocument(bais, POWERPOINT_DOCUMENT);
|
||||
writtenEntries.add(POWERPOINT_DOCUMENT);
|
||||
|
||||
currentUser.setEncrypted(encryptedSS.getDocumentEncryptionAtom() != null);
|
||||
currentUser.writeToFS(outFS);
|
||||
|
|
|
@ -25,7 +25,6 @@ import org.junit.runners.Suite;
|
|||
*/
|
||||
@RunWith(Suite.class)
|
||||
@Suite.SuiteClasses({
|
||||
TestBackground.class,
|
||||
TestFreeform.class,
|
||||
TestHeadersFooters.class,
|
||||
TestHyperlink.class,
|
||||
|
|
|
@ -87,7 +87,7 @@ public final class TestFreeform {
|
|||
public void test54188() {
|
||||
|
||||
HSLFFreeformShape p = new HSLFFreeformShape();
|
||||
Path2D.Double path = p.getPath();
|
||||
Path2D path = p.getPath();
|
||||
Path2D.Double emptyPath = new Path2D.Double();
|
||||
assertEquals(emptyPath.getBounds2D(), path.getBounds2D());
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.junit.runners.Suite;
|
|||
@RunWith(Suite.class)
|
||||
@Suite.SuiteClasses({
|
||||
TestAddingSlides.class,
|
||||
TestBackground.class,
|
||||
TestBugs.class,
|
||||
TestCounts.class,
|
||||
TestMostRecentRecords.class,
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hslf.model;
|
||||
package org.apache.poi.hslf.usermodel;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
|
@ -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.poifs.filesystem;
|
||||
|
||||
import org.apache.commons.codec.Charsets;
|
||||
import org.apache.poi.POIDataSamples;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class TestFileMagic {
|
||||
@Test
|
||||
public void testFileMagic() {
|
||||
assertEquals(FileMagic.XML, FileMagic.valueOf("XML"));
|
||||
assertEquals(FileMagic.XML, FileMagic.valueOf("<?xml".getBytes(Charsets.UTF_8)));
|
||||
|
||||
assertEquals(FileMagic.HTML, FileMagic.valueOf("HTML"));
|
||||
assertEquals(FileMagic.HTML, FileMagic.valueOf("<!DOCTYP".getBytes(Charsets.UTF_8)));
|
||||
assertEquals(FileMagic.HTML, FileMagic.valueOf("<!DOCTYPE".getBytes(Charsets.UTF_8)));
|
||||
assertEquals(FileMagic.HTML, FileMagic.valueOf("<html".getBytes(Charsets.UTF_8)));
|
||||
|
||||
try {
|
||||
FileMagic.valueOf("some string");
|
||||
fail("Should catch exception here");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// expected here
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileMagicFile() throws IOException {
|
||||
assertEquals(FileMagic.OLE2, FileMagic.valueOf(POIDataSamples.getSpreadSheetInstance().getFile("SampleSS.xls")));
|
||||
assertEquals(FileMagic.OOXML, FileMagic.valueOf(POIDataSamples.getSpreadSheetInstance().getFile("SampleSS.xlsx")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileMagicStream() throws IOException {
|
||||
try (InputStream stream = new BufferedInputStream(new FileInputStream(POIDataSamples.getSpreadSheetInstance().getFile("SampleSS.xls")))) {
|
||||
assertEquals(FileMagic.OLE2, FileMagic.valueOf(stream));
|
||||
}
|
||||
try (InputStream stream = new BufferedInputStream(new FileInputStream(POIDataSamples.getSpreadSheetInstance().getFile("SampleSS.xlsx")))) {
|
||||
assertEquals(FileMagic.OOXML, FileMagic.valueOf(stream));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrepare() throws IOException {
|
||||
try (InputStream stream = new BufferedInputStream(new FileInputStream(POIDataSamples.getSpreadSheetInstance().getFile("SampleSS.xlsx")))) {
|
||||
assertSame(stream, FileMagic.prepareToCheckMagic(stream));
|
||||
}
|
||||
|
||||
try (InputStream stream = new InputStream() {
|
||||
@Override
|
||||
public int read() {
|
||||
return 0;
|
||||
}
|
||||
}) {
|
||||
assertNotSame(stream, FileMagic.prepareToCheckMagic(stream));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.apache.poi.poifs.filesystem;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
@ -278,4 +279,18 @@ public final class TestPOIFSFileSystem {
|
|||
private static InputStream openSampleStream(String sampleFileName) {
|
||||
return HSSFTestDataSamples.openSampleFileStream(sampleFileName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileMagics() {
|
||||
for (FileMagic fm : FileMagic.values()) {
|
||||
if (fm == FileMagic.UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
for (byte[] b : fm.magic) {
|
||||
assertEquals(fm, FileMagic.valueOf(b));
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(FileMagic.UNKNOWN, FileMagic.valueOf("foobaa".getBytes(UTF_8)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class SheetRangeAndWorkbookIndexFormatterTest {
|
||||
@Test
|
||||
public void noDelimiting_ifASingleSheetNameDoesntNeedDelimiting() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String result = SheetRangeAndWorkbookIndexFormatter.format(sb, 0, "noDelimiting", null);
|
||||
assertEquals("[0]noDelimiting", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void everythingIsScreened_ifASingleSheetNameNeedsDelimiting() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String result = SheetRangeAndWorkbookIndexFormatter.format(sb, 0, "1delimiting", null);
|
||||
assertEquals("'[0]1delimiting'", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noDelimiting_ifBothSheetNamesDontNeedDelimiting() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String result = SheetRangeAndWorkbookIndexFormatter.format(sb, 0, "noDelimiting1", "noDelimiting2");
|
||||
assertEquals("[0]noDelimiting1:noDelimiting2", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void everythingIsScreened_ifFirstSheetNamesNeedsDelimiting() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String result = SheetRangeAndWorkbookIndexFormatter.format(sb, 0, "1delimiting", "noDelimiting");
|
||||
assertEquals("'[0]1delimiting:noDelimiting'", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void everythingIsScreened_ifLastSheetNamesNeedsDelimiting() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String result = SheetRangeAndWorkbookIndexFormatter.format(sb, 0, "noDelimiting", "1delimiting");
|
||||
assertEquals("'[0]noDelimiting:1delimiting'", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void everythingIsScreened_ifBothSheetNamesNeedDelimiting() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String result = SheetRangeAndWorkbookIndexFormatter.format(sb, 0, "1delimiting", "2delimiting");
|
||||
assertEquals("'[0]1delimiting:2delimiting'", result);
|
||||
}
|
||||
}
|
|
@ -91,9 +91,9 @@ public class TestExcelStyleDateFormatter {
|
|||
*/
|
||||
private int localeIndex(Locale locale) {
|
||||
final String provider = System.getProperty("java.locale.providers");
|
||||
return jreVersion < 12 ||
|
||||
return jreVersion < 9 ||
|
||||
!locale.equals (Locale.CHINESE) ||
|
||||
(provider != null && provider.startsWith("JRE"))
|
||||
(provider != null && (provider.startsWith("JRE") || provider.startsWith("COMPAT")))
|
||||
? 0 : 1;
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue