git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1848906 13f79535-47bb-0310-9956-ffa450edef68pull/133/head
@@ -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,14 +101,12 @@ 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() | |||
*/ | |||
public final boolean isFirstCell(int rowIx, int colIx) { |
@@ -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,10 +61,10 @@ public class DrawBackground extends DrawShape { | |||
if(fill != null) { | |||
graphics.setRenderingHint(Drawable.GRADIENT_SHAPE, anchor); | |||
graphics.setPaint(fill); | |||
graphics.fill(anchor2); | |||
fillPaintWorkaround(graphics, anchor2); | |||
} | |||
} | |||
protected Background<?,?> getShape() { | |||
return (Background<?,?>)shape; | |||
} |
@@ -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 | |||
return safeFractions(PathGradientPaint::new, fill); | |||
} | |||
private Paint safeFractions(BiFunction<float[],Color[],Paint> init, GradientPaint fill) { | |||
float[] fractions = fill.getGradientFractions(); | |||
Color[] colors = new Color[fractions.length]; | |||
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]))); | |||
} | |||
final Color[] colors = new Color[m.size()]; | |||
if (fractions.length != m.size()) { | |||
fractions = new float[m.size()]; | |||
} | |||
int i=0; | |||
for (ColorStyle fc : fill.getGradientColors()) { | |||
colors[i++] = applyColorTransform(fc); | |||
for (Map.Entry<Float,Color> me : m.entrySet()) { | |||
fractions[i] = me.getKey(); | |||
colors[i] = me.getValue(); | |||
i++; | |||
} | |||
return new PathGradientPaint(colors, fractions); | |||
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,8 +85,8 @@ 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); | |||
if (stroke == null) { |
@@ -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,27 +61,30 @@ 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++; | |||
if(containsKey(name)) { | |||
LOG.log(POILogger.WARN, "Duplicate definition of " + name); | |||
// JAXB: | |||
JAXBContext jaxbContext = JAXBContext.newInstance(BINDING_PACKAGE); | |||
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); | |||
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 = "?"; | |||
@@ -127,7 +127,7 @@ public class Units { | |||
points /= MASTER_DPI; | |||
return points; | |||
} | |||
public static int pointsToMaster(double points) { | |||
points *= MASTER_DPI; | |||
points /= POINT_DPI; |
@@ -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 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); | |||
File f = new File(arg); | |||
System.out.println(f); | |||
POITextExtractor extractor = | |||
ExtractorFactory.createExtractor(f); | |||
try { | |||
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(); | |||
} | |||
} | |||
} | |||
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); | |||
} | |||
for (String arg : args) { | |||
System.out.println(DIVIDER); | |||
File f = new File(arg); | |||
System.out.println(f); | |||
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"); | |||
} | |||
} | |||
} | |||
} |
@@ -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; | |||
@@ -306,14 +308,13 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> { | |||
throw new IllegalArgumentException("pictureData needs to be of type XSLFPictureData"); | |||
} | |||
RelationPart rp = addRelation(null, XSLFRelation.IMAGES, (XSLFPictureData)pictureData); | |||
XSLFObjectShape sh = getDrawing().createOleShape(rp.getRelationship().getId()); | |||
CTOleObject oleObj = sh.getCTOleObject(); | |||
Dimension dim = pictureData.getImageDimension(); | |||
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; | |||
@@ -34,7 +35,7 @@ import org.junit.Test; | |||
* @author Yegor Kozlov | |||
*/ | |||
public class TestXSLFSlide { | |||
@Test | |||
public void testReadShapes() throws IOException { | |||
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx"); | |||
@@ -101,7 +102,7 @@ public class TestXSLFSlide { | |||
XSLFTable tbl = (XSLFTable)shapes4.get(0); | |||
assertEquals(3, tbl.getNumberOfColumns()); | |||
assertEquals(6, tbl.getNumberOfRows()); | |||
ppt.close(); | |||
} | |||
@@ -116,7 +117,7 @@ public class TestXSLFSlide { | |||
assertFalse(slide.getFollowMasterGraphics()); | |||
slide.setFollowMasterGraphics(true); | |||
assertTrue(slide.getFollowMasterGraphics()); | |||
ppt.close(); | |||
} | |||
@@ -174,7 +175,7 @@ public class TestXSLFSlide { | |||
XSLFPictureShape sh4 = (XSLFPictureShape)shapes2.get(1); | |||
XSLFPictureShape srcPic = (XSLFPictureShape)src.getSlides().get(4).getShapes().get(1); | |||
assertArrayEquals(sh4.getPictureData().getData(), srcPic.getPictureData().getData()); | |||
ppt.close(); | |||
} | |||
@@ -191,7 +192,23 @@ public class TestXSLFSlide { | |||
} | |||
} | |||
assertEquals(30, ppt.getSlides().size()); | |||
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 | |||
*/ | |||
@@ -415,10 +414,10 @@ public final class HSLFFill { | |||
AbstractEscherOptRecord opt = shape.getEscherOptRecord(); | |||
EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST); | |||
int propVal = (p == null) ? 0 : p.getPropertyValue(); | |||
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(); | |||
public Path2D getPath(){ | |||
Path2D path2D = new Path2D.Double(); | |||
getGeometry(path2D); | |||
//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(); | |||
} | |||
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)); | |||
} | |||
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); | |||
path2D.transform(at); | |||
return path2D; | |||
} | |||
// 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; | |||
} | |||