]> source.dussan.org Git - poi.git/commitdiff
merge trunk
authorAndreas Beeker <kiwiwings@apache.org>
Fri, 14 Dec 2018 00:44:40 +0000 (00:44 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Fri, 14 Dec 2018 00:44:40 +0000 (00:44 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1848906 13f79535-47bb-0310-9956-ffa450edef68

81 files changed:
build.xml
doap_POI.rdf
src/examples/src/org/apache/poi/xslf/usermodel/ChartFromScratch.java [new file with mode: 0644]
src/examples/src/org/apache/poi/xwpf/usermodel/examples/ChartFromScratch.java [new file with mode: 0644]
src/integrationtest/org/apache/poi/TestAllFiles.java
src/integrationtest/org/apache/poi/stress/XSSFFileHandler.java
src/java/org/apache/poi/ddf/EscherProperties.java
src/java/org/apache/poi/hpsf/VariantSupport.java
src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java
src/java/org/apache/poi/hssf/model/InternalWorkbook.java
src/java/org/apache/poi/hssf/record/RecordInputStream.java
src/java/org/apache/poi/hssf/record/SSTRecord.java
src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java
src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java
src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java
src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java
src/java/org/apache/poi/poifs/filesystem/FileMagic.java
src/java/org/apache/poi/sl/draw/DrawBackground.java
src/java/org/apache/poi/sl/draw/DrawFreeformShape.java
src/java/org/apache/poi/sl/draw/DrawPaint.java
src/java/org/apache/poi/sl/draw/DrawSimpleShape.java
src/java/org/apache/poi/sl/draw/DrawTableShape.java
src/java/org/apache/poi/sl/draw/PathGradientPaint.java
src/java/org/apache/poi/sl/draw/geom/Context.java
src/java/org/apache/poi/sl/draw/geom/PresetGeometries.java
src/java/org/apache/poi/sl/usermodel/FreeformShape.java
src/java/org/apache/poi/ss/formula/SheetNameFormatter.java
src/java/org/apache/poi/ss/formula/SheetRangeAndWorkbookIndexFormatter.java [new file with mode: 0644]
src/java/org/apache/poi/ss/formula/functions/MatrixFunction.java
src/java/org/apache/poi/ss/formula/ptg/Area3DPxg.java
src/java/org/apache/poi/ss/formula/ptg/Ref3DPxg.java
src/java/org/apache/poi/util/RecordFormatException.java
src/java/org/apache/poi/util/StringUtil.java
src/java/org/apache/poi/util/Units.java
src/ooxml/java/org/apache/poi/ooxml/POIXMLDocumentPart.java
src/ooxml/java/org/apache/poi/ooxml/extractor/CommandLineTextExtractor.java
src/ooxml/java/org/apache/poi/ooxml/util/POIXMLConstants.java
src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java
src/ooxml/java/org/apache/poi/openxml4j/util/ZipInputStreamZipEntrySource.java
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureOutputStream.java
src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFChart.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFChart.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFChart.java
src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java
src/ooxml/testcases/org/apache/poi/ooxml/TestPOIXMLProperties.java
src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java
src/ooxml/testcases/org/apache/poi/xddf/usermodel/TestNecessaryOOXMLClasses.java
src/ooxml/testcases/org/apache/poi/xdgf/extractor/TestXDGFVisioExtractor.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlide.java
src/ooxml/testcases/org/apache/poi/xssf/XSSFTestDataSamples.java
src/ooxml/testcases/org/apache/poi/xwpf/extractor/TestXWPFWordExtractor.java
src/scratchpad/src/org/apache/poi/hslf/record/CurrentUserAtom.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowImpl.java
src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java
src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java [deleted file]
src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/AllHSLFUserModelTests.java
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBackground.java [new file with mode: 0644]
src/testcases/org/apache/poi/poifs/filesystem/TestFileMagic.java [new file with mode: 0644]
src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java
src/testcases/org/apache/poi/ss/formula/SheetRangeAndWorkbookIndexFormatterTest.java [new file with mode: 0644]
src/testcases/org/apache/poi/ss/usermodel/TestExcelStyleDateFormatter.java
test-data/document/60316.docx [new file with mode: 0644]
test-data/document/60316b.dotx [new file with mode: 0644]
test-data/slideshow/customGeo.ppt [new file with mode: 0644]
test-data/slideshow/customGeo.pptx [new file with mode: 0644]
test-data/slideshow/keyframes.pptx [new file with mode: 0644]
test-data/slideshow/pp40only.ppt [new file with mode: 0644]

index 207acc4c6848c63c56cba184029283ea5a1b19e7..ce3c83c860849a7fae72ceaefdfb36d98b8dae52 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -60,6 +60,10 @@ under the License.
     <property name="jdk.version.class" value="1.8" description="JDK version of generated class files"/>
     <property name="compile.debug" value="true"/>
 
+    <condition property="isIBMVM">
+        <contains string="${java.vendor}" substring="IBM" casesensitive="false"/>
+    </condition>
+
     <!--
         Logging is suppressed by default.
         To redirect log output to console, run ant with -Dorg.apache.poi.util.POILogger=org.apache.poi.util.SystemOutLogger
@@ -342,17 +346,6 @@ under the License.
         <propertyref name="scratchpad.ignore"/>
     </propertyset>
 
-    <!-- these need to be set differently when running with Java 9 -->
-    <property name="java9addmods" value="-Dthis.is.a.dummy=true"/>
-    <property name="javadoc9addmods" value="-J-Dthis.is.a.dummy=true"/>
-    <property name="java9addmodsvalue" value="-Dthis.is.a.dummy=true"/>
-    <property name="java9addopens1" value="-Dthis.is.a.dummy=true"/>
-    <property name="java9addopens2" value="-Dthis.is.a.dummy=true"/>
-    <property name="java9addopens3" value="-Dthis.is.a.dummy=true"/>
-    <property name="java9addopens4" value="-Dthis.is.a.dummy=true"/>
-    <property name="java9addopens5" value="-Dthis.is.a.dummy=true"/>
-    <property name="java9addopens6" value="-Dthis.is.a.dummy=true"/>
-
     <path id="main.classpath">
         <pathelement location="${main.commons-logging.jar}"/>
         <pathelement location="${main.commons-codec.jar}"/>
@@ -1180,6 +1173,59 @@ under the License.
         </copy>
     </target>
 
+    <macrodef name="poiunit" xmlns:jacoco="antlib:org.jacoco.ant">
+        <attribute name="failureproperty"/>
+        <attribute name="heap" default="512"/>
+        <attribute name="showoutput" default="false"/>
+        <attribute name="jacocodest" default="build/jacoco-dest.exec"/>
+        <element name="elements" implicit="true"/>
+        <sequential>
+            <local name="no.jit.sherlock"/>
+            <!-- see http://www-01.ibm.com/support/docview.wss?uid=swg21294023 on how to determine the method strings -->
+            <property name="no.jit.sherlock">
+                sun/java2d/pipe/AAShapePipe.renderTiles(Lsun/java2d/SunGraphics2D;Ljava/awt/Shape;Lsun/java2d/pipe/AATileGenerator;[I)V
+                sun/java2d/pipe/AlphaPaintPipe.renderPathTile(Ljava/lang/Object;[BIIIIII)V
+                java/awt/TexturePaintContext.getRaster(IIII)Ljava/awt/image/Raster;
+            </property>
+            <script language="javascript">
+                var before = project.getProperty("no.jit.sherlock");
+                project.setProperty("no.jit.sherlock", before.trim().replace(/ *(\S+) */g,"exclude={$1}").replace(/\s/g,","));
+            </script>
+
+            <local name="ooxml.lite.agent.exists"/>
+            <available property="ooxml.lite.agent.exists" file="${ooxml.lite.agent}"/>
+
+            <jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="@{jacocodest}">
+                <junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
+                       failureproperty="@{failureproperty}" showoutput="@{showoutput}">
+                    <syspropertyset refid="junit.properties"/>
+                    <sysproperty key="java.io.tmpdir" value="${tempdir}"/>
+                    <jvmarg value="-Xmx@{heap}M"/>
+                    <jvmarg value="-ea"/>
+
+                    <!-- these need to be set differently when running with Java 9 -->
+                    <jvmarg value="${java9addmods}" if:set="${java9addmods}" />
+                    <jvmarg value="${java9addmodsvalue}" if:set="${java9addmodsvalue}" />
+                    <jvmarg value="${java9addopens1}" if:set="${java9addopens1}" />
+                    <jvmarg value="${java9addopens2}" if:set="${java9addopens2}" />
+                    <jvmarg value="${java9addopens3}" if:set="${java9addopens3}" />
+                    <jvmarg value="${java9addopens4}" if:set="${java9addopens4}" />
+                    <jvmarg value="${java9addopens5}" if:set="${java9addopens5}" />
+                    <jvmarg value="${java9addopens6}" if:set="${java9addopens6}" />
+
+                    <jvmarg value="-javaagent:${ooxml.lite.agent}=${ooxml.lite.report}|${ooxml.lite.includes}" if:true="${ooxml.lite.agent.exists}"/>
+
+                    <!-- jvmarg value="-Duser.timezone=UTC"/ -->
+                    <jvmarg value="${file.leak.detector}" />
+                    <jvmarg value="-Xjit:verbose={compileStart|compileEnd},vlog=build/jit.log,${no.jit.sherlock}" if:true="${isIBMVM}"/>
+                    <formatter type="plain"/>
+                    <formatter type="xml"/>
+                    <elements/>
+                </junit>
+            </jacoco:coverage>
+        </sequential>
+    </macrodef>
+
     <target name="retest-ooxml" depends="jar">
         <delete dir="${ooxml.reports.test}"/>
         <delete dir="${ooxml.output.test.dir}"/>
@@ -1219,39 +1265,23 @@ under the License.
         <copy todir="${ooxml.output.dir}">
             <fileset dir="${ooxml.resource1.dir}"/>
         </copy>
-        <junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
-               failureproperty="ooxml.test.failed">
+
+        <poiunit failureproperty="ooxml.test.failed" heap="768">
             <classpath>
                 <path refid="test.ooxml.lite.verify.classpath"/>
                 <path refid="test.jar.classpath"/>
             </classpath>
-            <syspropertyset refid="junit.properties"/>
-            <sysproperty key="java.io.tmpdir" value="${tempdir}"/>
-            <jvmarg value="-Xmx768M"/>
-            <jvmarg value="-ea"/>
-            <jvmarg value="${java9addmods}" />
-            <jvmarg value="${java9addmodsvalue}" />
-            <jvmarg value="${java9addopens1}" />
-            <jvmarg value="${java9addopens2}" />
-            <jvmarg value="${java9addopens3}" />
-            <jvmarg value="${java9addopens4}" />
-            <jvmarg value="${java9addopens5}" />
-            <jvmarg value="${java9addopens6}" />
-            <!-- jvmarg value="-Duser.timezone=UTC"/ -->
-            <jvmarg value="${file.leak.detector}" />
-            <formatter type="plain"/>
-            <formatter type="xml"/>
             <batchtest todir="${ooxml.reports.test}">
                 <fileset dir="${ooxml.src.test}">
-                     <include name="**/${testpattern}.java"/>
-                     <exclude name="**/TestUnfixedBugs.java"/>
-                     <exclude name="**/All*Tests.java"/>
-                     <exclude name="**/TestSignatureInfo.java"/>
-                     <exclude name="**/${testexcludepattern}.java"/>
-                     <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
+                    <include name="**/${testpattern}.java"/>
+                    <exclude name="**/TestUnfixedBugs.java"/>
+                    <exclude name="**/All*Tests.java"/>
+                    <exclude name="**/TestSignatureInfo.java"/>
+                    <exclude name="**/${testexcludepattern}.java"/>
+                    <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
                 </fileset>
             </batchtest>
-        </junit>
+        </poiunit>
     </target>
 
     <target name="compile-excelant" depends="compile-main,compile-ooxml">
@@ -1306,6 +1336,7 @@ under the License.
                 <pathelement location="${main.ant.jar}"/>
                 <pathelement location="${scratchpad.output.dir}"/>
             </classpath>
+            <exclude name="**/HeapDump**" if:true="${isIBMVM}"/>
         </javac>
         <!--copy todir="${integration.output.dir}">
             <fileset dir="${integration.resource1.dir}"/>
@@ -1436,39 +1467,22 @@ under the License.
     <target name="test-main" unless="main.test.notRequired"
             depends="compile-main, -test-main-check,jacocotask" xmlns:jacoco="antlib:org.jacoco.ant"
             description="tests POI classes that deal with the Microsoft Office binary (BIFF8) file formats (excludes OOXML)">
-        <jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-main.exec">
-            <junit fork="yes" forkmode="once" printsummary="yes" haltonfailure="${halt.on.test.failure}"
-                   failureproperty="main.test.failed" showoutput="true">
-                <classpath refid="test.classpath"/>
-                <classpath refid="test.jar.classpath"/>
-                <syspropertyset refid="junit.properties"/>
-                <sysproperty key="java.io.tmpdir" value="${tempdir}"/>
-                <jvmarg value="-ea"/>
-                <jvmarg value="-Xmx256m"/>
-                <!-- jvmarg value="-Duser.timezone=UTC"/ -->
-                <jvmarg value="${java9addmods}" />
-                <jvmarg value="${java9addmodsvalue}" />
-                <jvmarg value="${java9addopens1}" />
-                <jvmarg value="${java9addopens2}" />
-                <jvmarg value="${java9addopens3}" />
-                <jvmarg value="${java9addopens4}" />
-                <jvmarg value="${java9addopens5}" />
-                <jvmarg value="${java9addopens6}" />
-                <jvmarg value="${file.leak.detector}" />
-                <formatter type="plain"/>
-                <formatter type="xml"/>
-                <batchtest todir="${main.reports.test}">
-                    <fileset dir="${main.src.test}">
-                        <include name="**/${testpattern}.java"/>
-                        <exclude name="**/All*Tests.java"/>
-                        <exclude name="**/TestUnfixedBugs.java"/>
-                        <exclude name="**/TestcaseRecordInputStream.java"/>
-                        <exclude name="**/${testexcludepattern}.java"/>
-                        <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
-                    </fileset>
-                </batchtest>
-            </junit>
-        </jacoco:coverage>
+        <poiunit failureproperty="main.test.failed" heap="256" showoutput="true" jacocodest="build/jacoco-main.exec">
+            <classpath>
+                <path refid="test.classpath"/>
+                <path refid="test.jar.classpath"/>
+            </classpath>
+            <batchtest todir="${main.reports.test}">
+                <fileset dir="${main.src.test}">
+                    <include name="**/${testpattern}.java"/>
+                    <exclude name="**/All*Tests.java"/>
+                    <exclude name="**/TestUnfixedBugs.java"/>
+                    <exclude name="**/TestcaseRecordInputStream.java"/>
+                    <exclude name="**/${testexcludepattern}.java"/>
+                    <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
+                </fileset>
+            </batchtest>
+        </poiunit>
         <delete file="${main.testokfile}"/>
         <antcall target="-test-main-write-testfile"/>
     </target>
@@ -1500,45 +1514,23 @@ under the License.
         </uptodate>
     </target>
 
-    <target name="test-scratchpad" depends="compile-main,compile-scratchpad,-test-scratchpad-check,jacocotask,test-scratchpad-download-resources"
+    <target name="test-scratchpad" depends="compile-main,compile-scratchpad,-test-scratchpad-check,test-scratchpad-download-resources"
             unless="scratchpad.test.notRequired" xmlns:jacoco="antlib:org.jacoco.ant"
             description="test non-OOXML scratchpad classes">
-        <jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-scratchpad.exec">
-            <junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
-                   failureproperty="scratchpad.test.failed">
-                <classpath refid="test.scratchpad.classpath"/>
-                <classpath refid="test.jar.classpath"/>
-                <syspropertyset refid="junit.properties"/>
-                <sysproperty key="java.io.tmpdir" value="${tempdir}"/>
-                <jvmarg value="-ea"/>
-                <!-- jvmarg value="-Duser.timezone=UTC"/ -->
-                <jvmarg value="${file.leak.detector}" />
-                <!--
-                  YK: ensure that JUnit has enough memory to run tests.
-                  Without the line below tests fail on Mac OS X with jdk-1.6.26
-                  and on Windows with jdk-1.5.22
-                -->
-                <jvmarg value="-Xmx512m"/>
-                <jvmarg value="${java9addmods}" />
-                <jvmarg value="${java9addmodsvalue}" />
-                <jvmarg value="${java9addopens1}" />
-                <jvmarg value="${java9addopens2}" />
-                <jvmarg value="${java9addopens3}" />
-                <jvmarg value="${java9addopens4}" />
-                <jvmarg value="${java9addopens5}" />
-                <jvmarg value="${java9addopens6}" />
-                <formatter type="plain"/>
-                <formatter type="xml"/>
-                <batchtest todir="${scratchpad.reports.test}">
-                    <fileset dir="${scratchpad.src.test}">
-                        <include name="**/${testpattern}.java"/>
-                        <exclude name="**/AllTests.java"/>
-                        <exclude name="**/${testexcludepattern}.java"/>
-                        <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
-                    </fileset>
-                </batchtest>
-            </junit>
-        </jacoco:coverage>
+        <poiunit failureproperty="scratchpad.test.failed" heap="512" jacocodest="build/jacoco-scratchpad.exec">
+            <classpath>
+                <path refid="test.scratchpad.classpath"/>
+                <path refid="test.jar.classpath"/>
+            </classpath>
+            <batchtest todir="${scratchpad.reports.test}">
+                <fileset dir="${scratchpad.src.test}">
+                    <include name="**/${testpattern}.java"/>
+                    <exclude name="**/AllTests.java"/>
+                    <exclude name="**/${testexcludepattern}.java"/>
+                    <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
+                </fileset>
+            </batchtest>
+        </poiunit>
         <delete file="${scratchpad.testokfile}"/>
         <antcall target="-test-scratchpad-write-testfile"/>
     </target>
@@ -1559,72 +1551,35 @@ under the License.
         <attribute name="classpath"/>
         <attribute name="type"/>
         <sequential>
-            <jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-@{type}.exec">
-              <junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
-                     failureproperty="ooxml.test.failed">
-                  <classpath>
-                      <path refid="@{classpath}"/>
-                      <path refid="test.jar.classpath"/>
-                  </classpath>
-                  <syspropertyset refid="junit.properties"/>
-                  <sysproperty key="java.io.tmpdir" value="${tempdir}"/>
-                  <jvmarg value="-Xmx768M"/>
-                  <jvmarg value="-ea"/>
-                  <jvmarg value="-javaagent:${ooxml.lite.agent}=${ooxml.lite.report}|${ooxml.lite.includes}"/>
-                  <jvmarg value="${java9addmods}" />
-                  <jvmarg value="${java9addmodsvalue}" />
-                  <jvmarg value="${java9addopens1}" />
-                  <jvmarg value="${java9addopens2}" />
-                  <jvmarg value="${java9addopens3}" />
-                  <jvmarg value="${java9addopens4}" />
-                  <jvmarg value="${java9addopens5}" />
-                  <jvmarg value="${java9addopens6}" />
-                  <!-- jvmarg value="-Duser.timezone=UTC"/ -->
-                  <jvmarg value="${file.leak.detector}" />
-                  <formatter type="plain"/>
-                  <formatter type="xml"/>
-                  <batchtest todir="${ooxml.reports.test}">
-                      <fileset dir="${ooxml.src.test}">
-                          <include name="**/${testpattern}.java"/>
-                          <exclude name="**/TestUnfixedBugs.java"/>
-                          <exclude name="**/All*Tests.java"/>
-                          <exclude name="**/TestSignatureInfo.java"/>
-                          <exclude name="**/${testexcludepattern}.java"/>
-                          <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
-                      </fileset>
-                  </batchtest>
-              </junit>
-            </jacoco:coverage>
-            <jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-@{type}-xmlsec.exec">
-              <junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
-                     failureproperty="ooxml.xmlsec.test.failed">
-                  <classpath>
-                      <path refid="@{classpath}"/>
-                      <path refid="test.jar.classpath"/>
-                      <path refid="ooxml.xmlsec.classpath"/>
-                  </classpath>
-                  <syspropertyset refid="junit.properties"/>
-                  <sysproperty key="java.io.tmpdir" value="${tempdir}"/>
-                  <jvmarg value="-javaagent:${ooxml.lite.agent}=${ooxml.lite.report}|${ooxml.lite.includes}"/>
-                  <jvmarg value="-Xmx768M"/>
-                  <jvmarg value="-ea"/>
-                  <jvmarg value="${java9addmods}" />
-                  <jvmarg value="${java9addmodsvalue}" />
-                  <jvmarg value="${java9addopens1}" />
-                  <jvmarg value="${java9addopens2}" />
-                  <jvmarg value="${java9addopens3}" />
-                  <jvmarg value="${java9addopens4}" />
-                  <jvmarg value="${java9addopens5}" />
-                  <jvmarg value="${java9addopens6}" />
-                  <formatter type="plain"/>
-                  <formatter type="xml"/>
-                  <batchtest todir="${ooxml.reports.test}">
-                      <fileset dir="${ooxml.src.test}">
-                            <include name="**/TestSignatureInfo.java"/>
-                      </fileset>
-                  </batchtest>
-              </junit>
-            </jacoco:coverage>
+            <poiunit failureproperty="ooxml.test.failed" heap="768" jacocodest="build/jacoco-@{type}.exec">
+                <classpath>
+                    <path refid="@{classpath}"/>
+                    <path refid="test.jar.classpath"/>
+                </classpath>
+                <batchtest todir="${ooxml.reports.test}">
+                    <fileset dir="${ooxml.src.test}">
+                        <include name="**/${testpattern}.java"/>
+                        <exclude name="**/TestUnfixedBugs.java"/>
+                        <exclude name="**/All*Tests.java"/>
+                        <exclude name="**/TestSignatureInfo.java"/>
+                        <exclude name="**/${testexcludepattern}.java"/>
+                        <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
+                    </fileset>
+                </batchtest>
+            </poiunit>
+
+            <poiunit failureproperty="ooxml.xmlsec.test.failed" heap="768" jacocodest="build/jacoco-@{type}-xmlsec.exec">
+                <classpath>
+                    <path refid="@{classpath}"/>
+                    <path refid="test.jar.classpath"/>
+                    <path refid="ooxml.xmlsec.classpath"/>
+                </classpath>
+                <batchtest todir="${ooxml.reports.test}">
+                    <fileset dir="${ooxml.src.test}">
+                        <include name="**/TestSignatureInfo.java"/>
+                    </fileset>
+                </batchtest>
+            </poiunit>
         </sequential>
     </macrodef>
 
@@ -1650,34 +1605,16 @@ under the License.
             unless="integration.test.notRequired" xmlns:jacoco="antlib:org.jacoco.ant">
         <propertyreset name="org.apache.poi.util.POILogger" value="org.apache.poi.util.CommonsLogger"/>
         <delete dir="build" includes="test-integration.log*"/>
-        <jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-integration.exec">
-            <junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
-                   failureproperty="integration.test.failed" showoutput="true">
-                <classpath refid="test.integration.classpath"/>
-                <syspropertyset refid="junit.properties"/>
-                <sysproperty key="java.io.tmpdir" value="${tempdir}"/>
-                <jvmarg value="-ea"/>
-                <jvmarg value="-Xmx1512M"/>
-                <jvmarg value="-javaagent:${ooxml.lite.agent}=${ooxml.lite.report}|${ooxml.lite.includes}"/>
-                <jvmarg value="${java9addmods}" />
-                <jvmarg value="${java9addmodsvalue}" />
-                <jvmarg value="${java9addopens1}" />
-                <jvmarg value="${java9addopens2}" />
-                <jvmarg value="${java9addopens3}" />
-                <jvmarg value="${java9addopens4}" />
-                <jvmarg value="${java9addopens5}" />
-                <jvmarg value="${java9addopens6}" />
-                <formatter type="plain"/>
-                <formatter type="xml"/>
-                <batchtest todir="${integration.reports.test}">
-                    <fileset dir="${integration.src.test}">
-                        <include name="**/${testpattern}.java"/>
-                        <exclude name="**/${testexcludepattern}.java"/>
-                        <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
-                    </fileset>
-                </batchtest>
-            </junit>
-        </jacoco:coverage>
+        <poiunit failureproperty="integration.test.failed" heap="1512" showoutput="true" jacocodest="build/jacoco-integration.exec">
+            <classpath refid="test.integration.classpath"/>
+            <batchtest todir="${integration.reports.test}">
+                <fileset dir="${integration.src.test}">
+                    <include name="**/${testpattern}.java"/>
+                    <exclude name="**/${testexcludepattern}.java"/>
+                    <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
+                </fileset>
+            </batchtest>
+        </poiunit>
         <delete file="${integration.testokfile}"/>
         <antcall target="-test-integration-write-testfile"/>
     </target>
@@ -1739,33 +1676,16 @@ under the License.
 
     <target name="test-excelant" depends="compile-excelant,-test-excelant-check,jacocotask"
             unless="excelant.test.notRequired" xmlns:jacoco="antlib:org.jacoco.ant">
-        <jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-excelant.exec">
-            <junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
-                   failureproperty="excelant.test.failed">
-                <classpath refid="test.excelant.classpath"/>
-                <syspropertyset refid="junit.properties"/>
-                <sysproperty key="java.io.tmpdir" value="${tempdir}"/>
-                <jvmarg value="-ea"/>
-                <jvmarg value="${java9addmods}" />
-                <jvmarg value="${java9addmodsvalue}" />
-                <jvmarg value="${java9addopens1}" />
-                <jvmarg value="${java9addopens2}" />
-                <jvmarg value="${java9addopens3}" />
-                <jvmarg value="${java9addopens4}" />
-                <jvmarg value="${java9addopens5}" />
-                <jvmarg value="${java9addopens6}" />
-                <jvmarg value="${file.leak.detector}" />
-                <formatter type="plain"/>
-                <formatter type="xml"/>
-                <batchtest todir="${excelant.reports.test}">
-                    <fileset dir="${excelant.src.test}">
-                        <include name="**/${testpattern}.java"/>
-                        <exclude name="**/${testexcludepattern}.java"/>
-                        <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
-                    </fileset>
-                </batchtest>
-            </junit>
-        </jacoco:coverage>
+        <poiunit failureproperty="excelant.test.failed" jacocodest="build/jacoco-excelant.exec">
+            <classpath refid="test.excelant.classpath"/>
+            <batchtest todir="${excelant.reports.test}">
+                <fileset dir="${excelant.src.test}">
+                    <include name="**/${testpattern}.java"/>
+                    <exclude name="**/${testexcludepattern}.java"/>
+                    <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
+                </fileset>
+            </batchtest>
+        </poiunit>
         <delete file="${excelant.testokfile}"/>
         <antcall target="-test-excelant-write-testfile"/>
     </target>
@@ -1791,6 +1711,9 @@ under the License.
     <target name="docs" depends="init, -check-forrest-installed, -check-docs, javadocs, -forrest-docs"
             unless="main.docs.notRequired" 
             description="Builds the POI website" />
+
+    <target name="site" depends="-forrest-docs"/>
+
     <target name="-forrest-docs" depends="-check-forrest-installed, -check-docs"
             unless="main.docs.notRequired" description="Builds the HTML pages of the POI website">
         <exec executable="${env.FORREST_HOME}/bin/forrest" osfamily="unix"/>
@@ -1828,7 +1751,7 @@ under the License.
                 <include name="org/apache/poi/**"/>
             </packageset>
             
-            <arg value="${javadoc9addmods}"/>
+            <arg value="${javadoc9addmods}" if:set="${javadoc9addmods}"/>
 
             <doctitle><![CDATA[<h1>POI API Documentation</h1>]]></doctitle>
             <bottom>
@@ -2113,6 +2036,7 @@ under the License.
                       sonar/*/src/**,
                       compile-lib/**,
                       ooxml-lib/**,
+                      ooxml-testlib/**,
                       scripts/**,
                       TEST*,
                       *.ipr,
@@ -2303,7 +2227,10 @@ under the License.
         </forbiddenapis>
     </target>
 
-    <target name="findbugs" depends="jar">
+    <!-- disabling findbugs until jenkins is updated to a current IBM JDK
+         see https://stackoverflow.com/a/48561534/2066598
+         this should be replaced by spotbugs when available in the jenkins warnings plugin -->
+    <target name="findbugs" depends="jar" unless="${isIBMVM}">
         <downloadfile src="${findbugs.url}" dest="${findbugs.jar}"/>
 
         <property name="findbugs.home" value="build/findbugs" />
@@ -2453,7 +2380,7 @@ under the License.
             <copy todir="${repo}">
                 <mappedresources>
                     <!-- add sha-512 when nexus rules are updated (1/2) -->
-                    <fileset dir="build/dist/maven" includes="@{artifactId}/**" excludes="**/*.sha512"/>
+                    <fileset dir="build/dist/maven" includes="@{artifactId}/**" excludes="**/*.sha512,**/*.sha256"/>
                     <regexpmapper from="^([^/]+)/(.*)$$" to="org/apache/poi/\1/${version.id}/\2" handledirsep="true"/>
                 </mappedresources>
             </copy>
index f1d21a8ceeee6ec28d36568b5b33a20817a90827..88ba48f04de27965956182848df9d34c5376c099 100644 (file)
     <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>
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/ChartFromScratch.java b/src/examples/src/org/apache/poi/xslf/usermodel/ChartFromScratch.java
new file mode 100644 (file)
index 0000000..12f96fa
--- /dev/null
@@ -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);
+    }
+}
+
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/ChartFromScratch.java b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/ChartFromScratch.java
new file mode 100644 (file)
index 0000000..4a1a781
--- /dev/null
@@ -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);
+    }
+}
+
index 61c47b9e8875e0a8aad7c6e7e62d4a94c5d61cfe..40f19f9c859545b4b342140f1d60c52dedeb0c8f 100644 (file)
@@ -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",
index 5c47d9af7e459766f346f45804c60f7af55ab0b0..48a30a256902d1bc784f6b2c54b2a2028b9634af 100644 (file)
@@ -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 {
index acff6241c2ee4100a03d9f6310005757c38464a3..482bce95c5e896f2ed5b40b0cda45ace31b7fdcd 100644 (file)
@@ -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();
        }
 }
index e60679027d9b1f26460924b12952dc6d79512e9a..0e8dc08c6e3d3b1ff097f40f13d6f163f4038677 100644 (file)
@@ -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>
  *
index 130408e7b5dd7e35470f05c106ca8b86d5ef088c..c01ded7fe8d3ed48cad6ef3118c5f4ee16b3b7a9 100644 (file)
@@ -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);
     }
 
index 46d867822944b939c38e27c7f36099370d7c6d9a..4ff370125ca8c658ad792fe3d9d09ccd328e9fc6 100644 (file)
@@ -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() {
index 3c9b977c799c13eed7ade5a0cce0f08ca7c80361..400553721e21c2db18ee0e4f026ffafcda3dea81 100644 (file)
@@ -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());
        }
        
index 20d99319d664ad9fc78d801aa3a06f128624161f..1de2fe4fc23fae4b0674cf4710749612167f8c40 100644 (file)
@@ -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
index 770f740a09f4e4080ee0b55ba1b5f86e58c4314f..328402db80a7e97dd5933780714a5a78b1b92cc8 100644 (file)
@@ -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) {
index a5035303a3daed14e35bfd9d0d1c21fe4335c18c..51fe091808eb1176f094460eca8406e4253474de 100644 (file)
@@ -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) {
index 9da03cf2e2609d575f5f68460d81af59ebbaa9eb..0aa73fd670a3fca74104069d739b4948217e9074 100644 (file)
@@ -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) {
index b412585261c46f8805e10303b9e93817510611e9..9221d4a3900446d49b3c9f7d18a0f69fdbf23e45 100644 (file)
@@ -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
index 4ac616082e08a0c099a9fa1e9129a9be6f7a061c..bab62c6437b3337b51594a7a3dc72ea4063143d8 100644 (file)
@@ -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>
index 1e9d5945b35eaacbad0b5fd6bb3ed23f3f4c5315..c61f6dbb79c0dbcb438b359cc4aece37c6482de3 100644 (file)
@@ -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;
     }
index 6eb60dfb52e24e55f6bbf49040655ab4fef84869..be18f037ab3b6ae0ad6292c81f8a716193c3f518 100644 (file)
 
 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;
-    }
 }
index d6986f3023e78ebd2f718282ec3ae6ffc4f585c3..80c5bcb00bdec831b4bc2b022e0cf245856388d8 100644 (file)
@@ -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);
+        }
+    }
 }
index 7ed1d35da2c9ab42647793cd765feb2069169754..a8d6fb534e7d5a777579dc53b8c4ad899d39c312 100644 (file)
@@ -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;
             }
index 905196fc903251b461b717a7f12961e7c5841f56..703fb04d829b667dfa82e93460e2de1a85cbbf4e 100644 (file)
@@ -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) {
index d4a2a5fa5fd7b2ff57ba41bd67ce79cbe8b3b32d..2281bbff83ade7f8449a9b2f8b4540b50d32a8c6 100644 (file)
@@ -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);
index 31847ceeff03f1b8063d5dc3da8aed0482b03589..3ed84b3d184dcc923773fb72ec25b3d0b95084ab 100644 (file)
@@ -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){
index a188e6e255ed77f1a1742e9ba4a0463291b74d01..f8b461f929437d16d7ab3ae763338fd263b727ae 100644 (file)
@@ -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();
+        }
     }
     
     /**
index 2a1580a7da4b1ccd2acbcff070291fe765cdbd98..42ae10ae9a1fc01541f8fdb907e541c9a0835529 100644 (file)
@@ -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);
 }
index c6e13c311069ca6bcb933640b2859a2078d37129..6e10e67c584621daf28f1eb469146a752429b1f4 100644 (file)
@@ -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");
diff --git a/src/java/org/apache/poi/ss/formula/SheetRangeAndWorkbookIndexFormatter.java b/src/java/org/apache/poi/ss/formula/SheetRangeAndWorkbookIndexFormatter.java
new file mode 100644 (file)
index 0000000..24d39cf
--- /dev/null
@@ -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;
+    }
+}
index 6b111cfc1ab51f05acfb12f06450297915c7348e..04e7f4cd77a81b49cf19d820406f35a42eff6c25 100644 (file)
@@ -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;
             }
         }
         
index 65f59e83e1187337d22c237e6bda43a8b9bf2c88..41bea0c950ea5e1303ceb8a2a47e155037224dc3 100644 (file)
@@ -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();
index 67f73b360dcc4d3553b277c72105c64eef7e9bb6..12e7e54eda9e92f5932ff9ad70b0be63fa4405b2 100644 (file)
@@ -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();
index 2bc4ba3bcb36d2fa0cbf24ca670b8f773e7aea05..65bea581eee01a54778630ff62971d5eb013b8b5 100644 (file)
@@ -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) {
index 302e532570aa1d2d4b75af6029b7048387cd4cc0..2017abf125d3ab90e92cbead22dc2755740016d5 100644 (file)
@@ -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 = "?";
 
index da0a877cf4a63578cd948efb328996fde8e61e58..709e3f10cc517c9cd29666bad825a68ba12a44a2 100644 (file)
@@ -127,7 +127,7 @@ public class Units {
         points /= MASTER_DPI;
         return points;
     }
-    
+
     public static int pointsToMaster(double points) {
         points *= MASTER_DPI;
         points /= POINT_DPI;
index 54fa790eca51def01cd73ecf34946c287e3985ec..c8e1a277a4be74bad20ec85da21af4bb79360ff2 100644 (file)
@@ -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.");
index 999abd46eeafbfa22139a519fe2036b744d42245..c3d429b3c79f3bc273ad05918e0ccf5ea64b4e4a 100644 (file)
@@ -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");
+            }
+        }
+    }
 }
index ab58e35833bca1fbb0e9e5e888cc5ab1ff639fcb..c6d7935fdaa22fe50f6b414803dbd2f85bb39814 100644 (file)
@@ -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";
 }
index 094e89c6d776e9dac295f3589f75e39b46edc8c0..0169909c9ba94dafd8883650087f409a7e5e9054 100644 (file)
@@ -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.
index 048b34e2517bd86f683e91b5e3c8a4598544f925..0a56966d4faca3f8e81affed41cb7e94c648f9b4 100644 (file)
@@ -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.
         */
index 0a00e29f1a520f3073b3c34b9615e0623ae54315..0ba11fbd34ea613da10f5f926361ddca0a571a48 100644 (file)
@@ -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);
     }
 
index 321626d71fb5b7a93ff9988953bd0f3b96066624..42678983091da9d22c4d36d5f1cdc226c5e8f8bb 100644 (file)
@@ -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);
         }
index 687ddc5f5b36b0ecbf6368d6a4f665ea2f0e3b02..b0cbc59dd1678407c830114f61acc34486843d2f 100644 (file)
@@ -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);
     }
 
     /**
index 8e6612f875994c0feff6fed166cc4279557543f8..5e8d73cd069a2c5d07619ef133cf32cac3aad993 100644 (file)
 
 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;
+    }
 }
index f4cd0d8e1c03a5ef9e0e91236509571dfd431c3e..ba93988d0b5e30deee65d80b70114472da19918a 100644 (file)
@@ -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));
index 54acd2b7bacc757497f6278c0a5b8625d57929b0..8c41fe1b93ff8de0f409bbf07ccf63f3c9aa0849 100644 (file)
@@ -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() {
index b67264ba0f1fd62fc5d849531b7aaeb8a8e9eea2..2bcf063990b6df4fab286c91721bbdada0a84492 100644 (file)
@@ -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);
+    }
+
 }
index 4e54712a778bd861adf6c8882c4b88086b82a1f3..89f312327bda8724366c76160c27462847bccd13 100644 (file)
@@ -716,7 +716,6 @@ public abstract class XSLFSimpleShape extends XSLFShape
     }
 
     /**
-     *
      * @return definition of the shape geometry
      */
     @Override
index ed52e0e16bd52b9b254db32d666a0e88c8d28bdc..16d7903a37266119e55cd0ccad6f007d2eacc273 100644 (file)
@@ -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()) {
index 44820a58710c2bbf822b83bb289256d80ce1bc6b..495cde1bf924cff831a795ea55d297cbd9008db3 100644 (file)
@@ -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;
index e3cc314a4a6bdef2fe7e9e424c56d68f354eeb6e..8e7e383d45b536407c7c4d839e620d55a731b299 100644 (file)
@@ -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);
     }
 
     /**
index d91b8191eb6cf47852511ad88b63f4a8e13ef027..1ad2a633f9ce492d93ab893c3d04eafbfca082d8 100644 (file)
@@ -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();
index dd2bc1705fccc88bc56cdf0a14eaa43cbd9c6e9c..4b9cff9b3c75ba06dc2352fee1f203878ba913b2 100644 (file)
@@ -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();
index 74ec1bb6cf441d6a61638562b4b47337152af326..6cbf24ab6f36559476b1d795df59a338bf39a0b4 100644 (file)
@@ -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);
index 6a3369ed900e268090a9bd101c3fbe9a08d27182..c261e2c91b5d3cea50c9ed72ca87d879ca5bf10a 100644 (file)
@@ -42,7 +42,7 @@ public class TestXDGFVisioExtractor {
     }
     
     @After
-    public void closeResoures() throws IOException {
+    public void closeResources() throws IOException {
         if(xml != null) {
             xml.close();
         }
index 94205da144006ad6e8dc7009034f3eb5a94c0f96..9a206a48caf2886047523353dfb2c5a1807e77da 100644 (file)
@@ -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";
 
         
     
index fbf45897658e6b607ba7cebc10829a4e2e3527cd..b9cda3fd21ec2c64cfbc8e6dca6a1bd910086de3 100644 (file)
@@ -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();
-    }    
-}
\ No newline at end of file
+    }
+
+    @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();
+    }
+}
index 0f03af7453c03b194bd9a36d5feeaef5f3f75385..b981b9994e9beb11b3ba2e8d650347e0b4a8b6b0 100644 (file)
@@ -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();
-        }
     }
 
     /**
index 0fcccd1838bacdeb287c3ea945878f0fa394806e..30d943051f028c0242356596397d46e5553abe89 100644 (file)
@@ -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");
+    }
 }
index cedfbb0470845a97c4eaf4e137fbabe13db8db0a..26ba59d2c62c3e009fb3c8ff3394c5b4deee8aeb 100644 (file)
@@ -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);
index 910c8a0adc192e3310daf457a77667b5b7fe4e5a..3a3fa7afb36771e0afcec44f43f2607f7d85c62e 100644 (file)
 
 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;
+    }
 }
index ee0a2d07316a9ee2ef7b09056ae13752b6376c23..63885af3f3777c4392b579364f01244e8d9df6c7 100644 (file)
@@ -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(){
index 0b2d322b6319fa0b8f2d0248bdd08081fa72aad0..10eeb7b19c2f1ebca7b8a886a82e48390199f841 100644 (file)
@@ -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);
-//    }
+
+
 }
index 085d617eb85fe6108468cd8ccba052724884e2df..f1f2c224060164fb8c1052b2eadba56f6d393673 100644 (file)
@@ -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);
index f9cf74c2632ff0c6f128823e7a2616b8abc41fe6..acabc68715ca10d9a00c54e65285675eb42e3451 100644 (file)
@@ -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;
     }
 
index ecc360e135f5a6ad301f44a32ea53c22f790df63..2f0a116d6836fd53edfd491323473f97342919f0 100644 (file)
@@ -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
index 6f00755a3d9210506df6edf35a10b9c470640c0c..420ae474840b6d4e94d6a85c5bb7454e607c770e 100644 (file)
@@ -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);
index 14301af2ba448c93e2db28b0d2f1b08f58d1df6d..26b30ea53ca65062936dd15524252136d3b16a5d 100644 (file)
@@ -25,7 +25,6 @@ import org.junit.runners.Suite;
  */
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-    TestBackground.class,
     TestFreeform.class,
     TestHeadersFooters.class,
     TestHyperlink.class,
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java
deleted file mode 100644 (file)
index faf61fb..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/* ====================================================================
-   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.hslf.model;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.awt.Color;
-import java.io.IOException;
-import java.util.List;
-
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.ddf.AbstractEscherOptRecord;
-import org.apache.poi.ddf.EscherBSERecord;
-import org.apache.poi.ddf.EscherContainerRecord;
-import org.apache.poi.ddf.EscherProperties;
-import org.apache.poi.ddf.EscherRecord;
-import org.apache.poi.ddf.EscherSimpleProperty;
-import org.apache.poi.hslf.HSLFTestDataSamples;
-import org.apache.poi.hslf.record.Document;
-import org.apache.poi.hslf.usermodel.HSLFAutoShape;
-import org.apache.poi.hslf.usermodel.HSLFFill;
-import org.apache.poi.hslf.usermodel.HSLFPictureData;
-import org.apache.poi.hslf.usermodel.HSLFShape;
-import org.apache.poi.hslf.usermodel.HSLFSheet;
-import org.apache.poi.hslf.usermodel.HSLFSlide;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.sl.usermodel.PictureData.PictureType;
-import org.apache.poi.sl.usermodel.ShapeType;
-import org.junit.Test;
-
-
-/**
- * Test <code>Fill</code> object.
- *
- * @author Yegor Kozlov
- */
-public final class TestBackground {
-    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
-
-    /**
-     * Default background for slide, shape and slide master.
-     */
-    @Test
-    public void defaults() throws IOException {
-        HSLFSlideShow ppt = new HSLFSlideShow();
-
-        assertEquals(HSLFFill.FILL_SOLID, ppt.getSlideMasters().get(0).getBackground().getFill().getFillType());
-
-        HSLFSlide slide = ppt.createSlide();
-        assertTrue(slide.getFollowMasterBackground());
-        assertEquals(HSLFFill.FILL_SOLID, slide.getBackground().getFill().getFillType());
-
-        HSLFShape shape = new HSLFAutoShape(ShapeType.RECT);
-        assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
-        ppt.close();
-    }
-
-    /**
-     * Read fill information from an reference ppt file
-     */
-    @Test
-    public void readBackground() throws IOException {
-        HSLFSlideShow ppt = HSLFTestDataSamples.getSlideShow("backgrounds.ppt");
-        HSLFFill fill;
-        HSLFShape shape;
-
-        List<HSLFSlide> slide = ppt.getSlides();
-
-        fill = slide.get(0).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType());
-        shape = slide.get(0).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
-
-        fill = slide.get(1).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType());
-        shape = slide.get(1).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType());
-
-        fill = slide.get(2).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType());
-        shape = slide.get(2).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType());
-
-        fill = slide.get(3).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType());
-        shape = slide.get(3).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType());
-        ppt.close();
-    }
-
-    /**
-     * Create a ppt with various fill effects
-     */
-    @Test
-    public void backgroundPicture() throws IOException {
-        HSLFSlideShow ppt1 = new HSLFSlideShow();
-        HSLFSlide slide;
-        HSLFFill fill;
-        HSLFShape shape;
-        HSLFPictureData data;
-
-        //slide 1
-        slide = ppt1.createSlide();
-        slide.setFollowMasterBackground(false);
-        fill = slide.getBackground().getFill();
-        data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
-        fill.setFillType(HSLFFill.FILL_PICTURE);
-        fill.setPictureData(data);
-
-        shape = new HSLFAutoShape(ShapeType.RECT);
-        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
-        fill = shape.getFill();
-        fill.setFillType(HSLFFill.FILL_SOLID);
-        slide.addShape(shape);
-
-        //slide 2
-        slide = ppt1.createSlide();
-        slide.setFollowMasterBackground(false);
-        fill = slide.getBackground().getFill();
-        data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
-        fill.setFillType(HSLFFill.FILL_PATTERN);
-        fill.setPictureData(data);
-        fill.setBackgroundColor(Color.green);
-        fill.setForegroundColor(Color.red);
-
-        shape = new HSLFAutoShape(ShapeType.RECT);
-        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
-        fill = shape.getFill();
-        fill.setFillType(HSLFFill.FILL_BACKGROUND);
-        slide.addShape(shape);
-
-        //slide 3
-        slide = ppt1.createSlide();
-        slide.setFollowMasterBackground(false);
-        fill = slide.getBackground().getFill();
-        data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
-        fill.setFillType(HSLFFill.FILL_TEXTURE);
-        fill.setPictureData(data);
-
-        shape = new HSLFAutoShape(ShapeType.RECT);
-        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
-        fill = shape.getFill();
-        fill.setFillType(HSLFFill.FILL_PICTURE);
-        data = ppt1.addPicture(_slTests.readFile("clock.jpg"), PictureType.JPEG);
-        fill.setPictureData(data);
-        slide.addShape(shape);
-
-        // slide 4
-        slide = ppt1.createSlide();
-        slide.setFollowMasterBackground(false);
-        fill = slide.getBackground().getFill();
-        fill.setFillType(HSLFFill.FILL_SHADE_CENTER);
-        fill.setBackgroundColor(Color.white);
-        fill.setForegroundColor(Color.darkGray);
-
-        shape = new HSLFAutoShape(ShapeType.RECT);
-        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
-        fill = shape.getFill();
-        fill.setFillType(HSLFFill.FILL_SHADE);
-        fill.setBackgroundColor(Color.red);
-        fill.setForegroundColor(Color.green);
-        slide.addShape(shape);
-
-        //serialize and read again
-        HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1);
-        List<HSLFSlide> slides = ppt2.getSlides();
-
-        fill = slides.get(0).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType());
-        assertEquals(3, getFillPictureRefCount(slides.get(0).getBackground(), fill));
-        shape = slides.get(0).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
-
-        fill = slides.get(1).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType());
-        shape = slides.get(1).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType());
-
-        fill = slides.get(2).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType());
-        assertEquals(3, getFillPictureRefCount(slides.get(2).getBackground(), fill));
-        shape = slides.get(2).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType());
-        assertEquals(1, getFillPictureRefCount(shape, fill));
-
-        fill = slides.get(3).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType());
-        shape = slides.get(3).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType());
-        ppt2.close();
-        ppt1.close();
-    }
-
-    private int getFillPictureRefCount(HSLFShape shape, HSLFFill fill) {
-        AbstractEscherOptRecord opt = shape.getEscherOptRecord();
-        EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
-        if(p != null) {
-            int idx = p.getPropertyValue();
-
-            HSLFSheet sheet = shape.getSheet();
-            HSLFSlideShow ppt = sheet.getSlideShow();
-            Document doc = ppt.getDocumentRecord();
-            EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
-            EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
-            List<EscherRecord> lst = bstore.getChildRecords();
-            return ((EscherBSERecord)lst.get(idx-1)).getRef();
-        }
-        return 0;
-    }
-
-}
index 91d23664d828c80ab72c61dbdc25d4ebef48e662..1e3c52ddeeefab94ca61c7ed54e0888397960763 100644 (file)
@@ -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());
     }
index 0354d9b46cc75131a90873d5d6b7e216e4b166d5..cf8dc7658d1115132c966b9aa2a932120fc30cd8 100644 (file)
@@ -26,6 +26,7 @@ import org.junit.runners.Suite;
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
     TestAddingSlides.class,
+    TestBackground.class,
     TestBugs.class,
     TestCounts.class,
     TestMostRecentRecords.class,
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBackground.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBackground.java
new file mode 100644 (file)
index 0000000..2732d16
--- /dev/null
@@ -0,0 +1,227 @@
+/* ====================================================================
+   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.hslf.usermodel;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.ddf.AbstractEscherOptRecord;
+import org.apache.poi.ddf.EscherBSERecord;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherProperties;
+import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherSimpleProperty;
+import org.apache.poi.hslf.HSLFTestDataSamples;
+import org.apache.poi.hslf.record.Document;
+import org.apache.poi.hslf.usermodel.HSLFAutoShape;
+import org.apache.poi.hslf.usermodel.HSLFFill;
+import org.apache.poi.hslf.usermodel.HSLFPictureData;
+import org.apache.poi.hslf.usermodel.HSLFShape;
+import org.apache.poi.hslf.usermodel.HSLFSheet;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.sl.usermodel.PictureData.PictureType;
+import org.apache.poi.sl.usermodel.ShapeType;
+import org.junit.Test;
+
+
+/**
+ * Test <code>Fill</code> object.
+ *
+ * @author Yegor Kozlov
+ */
+public final class TestBackground {
+    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
+
+    /**
+     * Default background for slide, shape and slide master.
+     */
+    @Test
+    public void defaults() throws IOException {
+        HSLFSlideShow ppt = new HSLFSlideShow();
+
+        assertEquals(HSLFFill.FILL_SOLID, ppt.getSlideMasters().get(0).getBackground().getFill().getFillType());
+
+        HSLFSlide slide = ppt.createSlide();
+        assertTrue(slide.getFollowMasterBackground());
+        assertEquals(HSLFFill.FILL_SOLID, slide.getBackground().getFill().getFillType());
+
+        HSLFShape shape = new HSLFAutoShape(ShapeType.RECT);
+        assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
+        ppt.close();
+    }
+
+    /**
+     * Read fill information from an reference ppt file
+     */
+    @Test
+    public void readBackground() throws IOException {
+        HSLFSlideShow ppt = HSLFTestDataSamples.getSlideShow("backgrounds.ppt");
+        HSLFFill fill;
+        HSLFShape shape;
+
+        List<HSLFSlide> slide = ppt.getSlides();
+
+        fill = slide.get(0).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType());
+        shape = slide.get(0).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
+
+        fill = slide.get(1).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType());
+        shape = slide.get(1).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType());
+
+        fill = slide.get(2).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType());
+        shape = slide.get(2).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType());
+
+        fill = slide.get(3).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType());
+        shape = slide.get(3).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType());
+        ppt.close();
+    }
+
+    /**
+     * Create a ppt with various fill effects
+     */
+    @Test
+    public void backgroundPicture() throws IOException {
+        HSLFSlideShow ppt1 = new HSLFSlideShow();
+        HSLFSlide slide;
+        HSLFFill fill;
+        HSLFShape shape;
+        HSLFPictureData data;
+
+        //slide 1
+        slide = ppt1.createSlide();
+        slide.setFollowMasterBackground(false);
+        fill = slide.getBackground().getFill();
+        data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
+        fill.setFillType(HSLFFill.FILL_PICTURE);
+        fill.setPictureData(data);
+
+        shape = new HSLFAutoShape(ShapeType.RECT);
+        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
+        fill = shape.getFill();
+        fill.setFillType(HSLFFill.FILL_SOLID);
+        slide.addShape(shape);
+
+        //slide 2
+        slide = ppt1.createSlide();
+        slide.setFollowMasterBackground(false);
+        fill = slide.getBackground().getFill();
+        data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
+        fill.setFillType(HSLFFill.FILL_PATTERN);
+        fill.setPictureData(data);
+        fill.setBackgroundColor(Color.green);
+        fill.setForegroundColor(Color.red);
+
+        shape = new HSLFAutoShape(ShapeType.RECT);
+        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
+        fill = shape.getFill();
+        fill.setFillType(HSLFFill.FILL_BACKGROUND);
+        slide.addShape(shape);
+
+        //slide 3
+        slide = ppt1.createSlide();
+        slide.setFollowMasterBackground(false);
+        fill = slide.getBackground().getFill();
+        data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
+        fill.setFillType(HSLFFill.FILL_TEXTURE);
+        fill.setPictureData(data);
+
+        shape = new HSLFAutoShape(ShapeType.RECT);
+        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
+        fill = shape.getFill();
+        fill.setFillType(HSLFFill.FILL_PICTURE);
+        data = ppt1.addPicture(_slTests.readFile("clock.jpg"), PictureType.JPEG);
+        fill.setPictureData(data);
+        slide.addShape(shape);
+
+        // slide 4
+        slide = ppt1.createSlide();
+        slide.setFollowMasterBackground(false);
+        fill = slide.getBackground().getFill();
+        fill.setFillType(HSLFFill.FILL_SHADE_CENTER);
+        fill.setBackgroundColor(Color.white);
+        fill.setForegroundColor(Color.darkGray);
+
+        shape = new HSLFAutoShape(ShapeType.RECT);
+        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
+        fill = shape.getFill();
+        fill.setFillType(HSLFFill.FILL_SHADE);
+        fill.setBackgroundColor(Color.red);
+        fill.setForegroundColor(Color.green);
+        slide.addShape(shape);
+
+        //serialize and read again
+        HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1);
+        List<HSLFSlide> slides = ppt2.getSlides();
+
+        fill = slides.get(0).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType());
+        assertEquals(3, getFillPictureRefCount(slides.get(0).getBackground(), fill));
+        shape = slides.get(0).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
+
+        fill = slides.get(1).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType());
+        shape = slides.get(1).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType());
+
+        fill = slides.get(2).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType());
+        assertEquals(3, getFillPictureRefCount(slides.get(2).getBackground(), fill));
+        shape = slides.get(2).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType());
+        assertEquals(1, getFillPictureRefCount(shape, fill));
+
+        fill = slides.get(3).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType());
+        shape = slides.get(3).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType());
+        ppt2.close();
+        ppt1.close();
+    }
+
+    private int getFillPictureRefCount(HSLFShape shape, HSLFFill fill) {
+        AbstractEscherOptRecord opt = shape.getEscherOptRecord();
+        EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
+        if(p != null) {
+            int idx = p.getPropertyValue();
+
+            HSLFSheet sheet = shape.getSheet();
+            HSLFSlideShow ppt = sheet.getSlideShow();
+            Document doc = ppt.getDocumentRecord();
+            EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
+            EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
+            List<EscherRecord> lst = bstore.getChildRecords();
+            return ((EscherBSERecord)lst.get(idx-1)).getRef();
+        }
+        return 0;
+    }
+
+}
diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestFileMagic.java b/src/testcases/org/apache/poi/poifs/filesystem/TestFileMagic.java
new file mode 100644 (file)
index 0000000..4dba721
--- /dev/null
@@ -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));
+        }
+    }
+}
index 83b085bfd3eb02fb11055caae32e4dae9e63dc1c..1fffceafeb7840aea7df05e40e74fd48e053e0d3 100644 (file)
@@ -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)));
+       }
 }
diff --git a/src/testcases/org/apache/poi/ss/formula/SheetRangeAndWorkbookIndexFormatterTest.java b/src/testcases/org/apache/poi/ss/formula/SheetRangeAndWorkbookIndexFormatterTest.java
new file mode 100644 (file)
index 0000000..43dd236
--- /dev/null
@@ -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);
+    }
+}
index b7fd43e36723305987d85fd914bef038876cded1..742fb2228fa7235d5cdaf7b3480933d1530123e0 100644 (file)
@@ -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;
     }
 
diff --git a/test-data/document/60316.docx b/test-data/document/60316.docx
new file mode 100644 (file)
index 0000000..78b2b1d
Binary files /dev/null and b/test-data/document/60316.docx differ
diff --git a/test-data/document/60316b.dotx b/test-data/document/60316b.dotx
new file mode 100644 (file)
index 0000000..e0e0d58
Binary files /dev/null and b/test-data/document/60316b.dotx differ
diff --git a/test-data/slideshow/customGeo.ppt b/test-data/slideshow/customGeo.ppt
new file mode 100644 (file)
index 0000000..fdb80ed
Binary files /dev/null and b/test-data/slideshow/customGeo.ppt differ
diff --git a/test-data/slideshow/customGeo.pptx b/test-data/slideshow/customGeo.pptx
new file mode 100644 (file)
index 0000000..c30e331
Binary files /dev/null and b/test-data/slideshow/customGeo.pptx differ
diff --git a/test-data/slideshow/keyframes.pptx b/test-data/slideshow/keyframes.pptx
new file mode 100644 (file)
index 0000000..e653d64
Binary files /dev/null and b/test-data/slideshow/keyframes.pptx differ
diff --git a/test-data/slideshow/pp40only.ppt b/test-data/slideshow/pp40only.ppt
new file mode 100644 (file)
index 0000000..bd53490
Binary files /dev/null and b/test-data/slideshow/pp40only.ppt differ