merged with trunk r653489
git-svn-id: https://svn.apache.org/repos/asf/poi/tags/REL_3_1_BETA2@653490 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2389d26eb0
commit
28b6f4e2a3
180
build.xml
180
build.xml
|
@ -74,7 +74,6 @@ under the License.
|
||||||
<property name="main.output.dir" location="build/classes"/>
|
<property name="main.output.dir" location="build/classes"/>
|
||||||
<property name="main.output.test.dir" location="build/test-classes"/>
|
<property name="main.output.test.dir" location="build/test-classes"/>
|
||||||
<property name="main.lib" location="lib"/>
|
<property name="main.lib" location="lib"/>
|
||||||
<property name="ooxml.lib" location="ooxml-lib"/>
|
|
||||||
<property name="main.reports.test" location="build/test-results"/>
|
<property name="main.reports.test" location="build/test-results"/>
|
||||||
<property name="main.jar1.dir" location="${main.lib}/commons-logging-1.1.jar"/>
|
<property name="main.jar1.dir" location="${main.lib}/commons-logging-1.1.jar"/>
|
||||||
<property name="main.jar1.url" value="${repository}/commons-logging/jars/commons-logging-1.1.jar"/>
|
<property name="main.jar1.url" value="${repository}/commons-logging/jars/commons-logging-1.1.jar"/>
|
||||||
|
@ -124,33 +123,6 @@ under the License.
|
||||||
<property name="examples.jar3.url" value="${repository}/commons-lang/jars/commons-lang-2.1.jar"/>
|
<property name="examples.jar3.url" value="${repository}/commons-lang/jars/commons-lang-2.1.jar"/>
|
||||||
<property name="examples.testokfile" location="build/examples-testokfile.txt"/>
|
<property name="examples.testokfile" location="build/examples-testokfile.txt"/>
|
||||||
|
|
||||||
<!-- Experimental OOXML support: -->
|
|
||||||
<property name="ooxml.src" location="src/scratchpad/ooxml-src"/>
|
|
||||||
<property name="ooxml.src.test" location="src/scratchpad/ooxml-testcases"/>
|
|
||||||
<property name="ooxml.reports.test" location="build/ooxml-test-results"/>
|
|
||||||
<property name="ooxml.output.dir" location="build/ooxml-classes"/>
|
|
||||||
<property name="ooxml.output.test.dir" location="build/ooxml-test-classes"/>
|
|
||||||
<property name="ooxml.testokfile" location="build/ooxml-testokfile.txt"/>
|
|
||||||
|
|
||||||
<property name="ooxml.jar1.dir" location="${ooxml.lib}/dom4j-1.6.1.jar"/>
|
|
||||||
<property name="ooxml.jar1.url" value="${repository}/dom4j/jars/dom4j-1.6.1.jar"/>
|
|
||||||
<property name="ooxml.jar2.dir" location="${ooxml.lib}/jaxen-1.1.jar"/>
|
|
||||||
<property name="ooxml.jar2.url" value="${repository}/jaxen/jars/jaxen-1.1.jar"/>
|
|
||||||
<property name="ooxml.jar3.dir" location="${ooxml.lib}/xmlbeans-2.3.0.jar"/>
|
|
||||||
<property name="ooxml.jar3.url" value="${repository}/org.apache.xmlbeans/jars/xmlbeans-2.3.0.jar"/>
|
|
||||||
<property name="ooxml.jar4.dir" location="${ooxml.lib}/jsr173_1.0_api.jar"/>
|
|
||||||
<property name="ooxml.jar4.url" value="${repository}/xmlbeans/jars/jsr173_1.0_api.jar"/>
|
|
||||||
<!-- No official release of openxml4j yet -->
|
|
||||||
<property name="ooxml.jar5.dir" location="${ooxml.lib}/openxml4j-bin-alpha-080124.jar"/>
|
|
||||||
<property name="ooxml.jar5.url" value="http://people.apache.org/~nick/openxml4j-bin-prealpha-071224.jar"/>
|
|
||||||
|
|
||||||
<!-- See http://www.ecma-international.org/publications/standards/Ecma-376.htm -->
|
|
||||||
<!-- "Copy these file(s), free of charge" -->
|
|
||||||
<property name="ooxml.xsds.ozip" location="${ooxml.lib}/OfficeOpenXML-Part4.zip"/>
|
|
||||||
<property name="ooxml.xsds.izip" location="${ooxml.lib}/OfficeOpenXML-XMLSchema.zip"/>
|
|
||||||
<property name="ooxml.xsds.url" value="http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%20Part%204%20(DOCX).zip" />
|
|
||||||
<property name="ooxml.xsds.jar" location="${ooxml.lib}/ooxml-schemas.jar"/>
|
|
||||||
|
|
||||||
<property name="build.site" location="build/tmp/site/build/site"/>
|
<property name="build.site" location="build/tmp/site/build/site"/>
|
||||||
<property name="build.site.src" location="build/tmp/site"/>
|
<property name="build.site.src" location="build/tmp/site"/>
|
||||||
<property name="junit.report.dir" location="${build.site}/junit"/>
|
<property name="junit.report.dir" location="${build.site}/junit"/>
|
||||||
|
@ -163,7 +135,7 @@ under the License.
|
||||||
<property name="mavendist.poi.dir" location="build/maven-dist/poi"/>
|
<property name="mavendist.poi.dir" location="build/maven-dist/poi"/>
|
||||||
<property name="mavendist.oap.dir" location="build/maven-dist/org.apache.poi"/>
|
<property name="mavendist.oap.dir" location="build/maven-dist/org.apache.poi"/>
|
||||||
<property name="jar.name" value="poi"/>
|
<property name="jar.name" value="poi"/>
|
||||||
<property name="version.id" value="3.1-beta1"/>
|
<property name="version.id" value="3.1-beta2"/>
|
||||||
<property name="halt.on.test.failure" value="true"/>
|
<property name="halt.on.test.failure" value="true"/>
|
||||||
<property name="jdk.version.source" value="1.3"
|
<property name="jdk.version.source" value="1.3"
|
||||||
description="JDK version of source code"/>
|
description="JDK version of source code"/>
|
||||||
|
@ -195,15 +167,6 @@ under the License.
|
||||||
<pathelement location="${contrib.output.test.dir}"/>
|
<pathelement location="${contrib.output.test.dir}"/>
|
||||||
</path>
|
</path>
|
||||||
|
|
||||||
<path id="ooxml.classpath">
|
|
||||||
<path refid="main.classpath"/>
|
|
||||||
<path refid="scratchpad.classpath"/>
|
|
||||||
<fileset dir="${ooxml.lib}">
|
|
||||||
<include name="*.jar" />
|
|
||||||
</fileset>
|
|
||||||
</path>
|
|
||||||
|
|
||||||
|
|
||||||
<path id="examples.classpath">
|
<path id="examples.classpath">
|
||||||
<path refid="main.classpath"/>
|
<path refid="main.classpath"/>
|
||||||
<pathelement location="${main.output.dir}"/>
|
<pathelement location="${main.output.dir}"/>
|
||||||
|
@ -268,15 +231,12 @@ under the License.
|
||||||
<mkdir dir="${scratchpad.output.dir}"/>
|
<mkdir dir="${scratchpad.output.dir}"/>
|
||||||
<mkdir dir="${contrib.output.dir}"/>
|
<mkdir dir="${contrib.output.dir}"/>
|
||||||
<mkdir dir="${examples.output.dir}"/>
|
<mkdir dir="${examples.output.dir}"/>
|
||||||
<mkdir dir="${ooxml.output.dir}"/>
|
|
||||||
<mkdir dir="${main.output.test.dir}"/>
|
<mkdir dir="${main.output.test.dir}"/>
|
||||||
<mkdir dir="${contrib.output.test.dir}"/>
|
<mkdir dir="${contrib.output.test.dir}"/>
|
||||||
<mkdir dir="${scratchpad.output.test.dir}"/>
|
<mkdir dir="${scratchpad.output.test.dir}"/>
|
||||||
<mkdir dir="${ooxml.output.test.dir}"/>
|
|
||||||
<mkdir dir="${main.reports.test}"/>
|
<mkdir dir="${main.reports.test}"/>
|
||||||
<mkdir dir="${scratchpad.reports.test}"/>
|
<mkdir dir="${scratchpad.reports.test}"/>
|
||||||
<mkdir dir="${contrib.reports.test}"/>
|
<mkdir dir="${contrib.reports.test}"/>
|
||||||
<mkdir dir="${ooxml.reports.test}"/>
|
|
||||||
<mkdir dir="${junit.report.dir}"/>
|
<mkdir dir="${junit.report.dir}"/>
|
||||||
<mkdir dir="${jdepend.report.dir}"/>
|
<mkdir dir="${jdepend.report.dir}"/>
|
||||||
<mkdir dir="${jdepend.report.out.dir}"/>
|
<mkdir dir="${jdepend.report.out.dir}"/>
|
||||||
|
@ -311,11 +271,6 @@ under the License.
|
||||||
<available file="${contrib.jar2.dir}"/>
|
<available file="${contrib.jar2.dir}"/>
|
||||||
<available file="${contrib.jar3.dir}"/>
|
<available file="${contrib.jar3.dir}"/>
|
||||||
<available file="${junit.jar1.dir}"/>
|
<available file="${junit.jar1.dir}"/>
|
||||||
<available file="${ooxml.jar1.dir}"/>
|
|
||||||
<available file="${ooxml.jar2.dir}"/>
|
|
||||||
<available file="${ooxml.jar3.dir}"/>
|
|
||||||
<available file="${ooxml.jar4.dir}"/>
|
|
||||||
<available file="${ooxml.jar5.dir}"/>
|
|
||||||
</and>
|
</and>
|
||||||
<isset property="disconnected"/>
|
<isset property="disconnected"/>
|
||||||
</or>
|
</or>
|
||||||
|
@ -330,65 +285,6 @@ under the License.
|
||||||
<get src="${contrib.jar2.url}" dest="${contrib.jar2.dir}"/>
|
<get src="${contrib.jar2.url}" dest="${contrib.jar2.dir}"/>
|
||||||
<get src="${contrib.jar3.url}" dest="${contrib.jar3.dir}"/>
|
<get src="${contrib.jar3.url}" dest="${contrib.jar3.dir}"/>
|
||||||
<get src="${junit.jar1.url}" dest="${junit.jar1.dir}"/>
|
<get src="${junit.jar1.url}" dest="${junit.jar1.dir}"/>
|
||||||
|
|
||||||
<get src="${ooxml.jar1.url}" dest="${ooxml.jar1.dir}"/>
|
|
||||||
<get src="${ooxml.jar2.url}" dest="${ooxml.jar2.dir}"/>
|
|
||||||
<get src="${ooxml.jar3.url}" dest="${ooxml.jar3.dir}"/>
|
|
||||||
<get src="${ooxml.jar4.url}" dest="${ooxml.jar4.dir}"/>
|
|
||||||
<get src="${ooxml.jar5.url}" dest="${ooxml.jar5.dir}"/>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="check-ooxml-xsds">
|
|
||||||
<condition property="ooxml-xsds.present">
|
|
||||||
<or>
|
|
||||||
<and>
|
|
||||||
<available file="${ooxml.xsds.izip}"/>
|
|
||||||
</and>
|
|
||||||
<isset property="disconnected"/>
|
|
||||||
</or>
|
|
||||||
</condition>
|
|
||||||
</target>
|
|
||||||
<target name="fetch-ooxml-xsds" unless="ooxml-xsds.present"
|
|
||||||
description="Fetches needed OOXML xsd files from the Internet">
|
|
||||||
<get src="${ooxml.xsds.url}" dest="${ooxml.xsds.ozip}"/>
|
|
||||||
<unzip src="${ooxml.xsds.ozip}" dest="${ooxml.lib}">
|
|
||||||
<patternset>
|
|
||||||
<include name="OfficeOpenXML-XMLSchema.zip" />
|
|
||||||
</patternset>
|
|
||||||
</unzip>
|
|
||||||
</target>
|
|
||||||
<target name="check-compiled-ooxml-xsds">
|
|
||||||
<condition property="ooxml-compiled-xsds.present">
|
|
||||||
<or>
|
|
||||||
<and>
|
|
||||||
<available file="${ooxml.xsds.jar}"/>
|
|
||||||
</and>
|
|
||||||
<isset property="disconnected"/>
|
|
||||||
</or>
|
|
||||||
</condition>
|
|
||||||
</target>
|
|
||||||
<target name="compile-ooxml-xsds" unless="ooxml-compiled-xsds.present"
|
|
||||||
depends="check-jars,fetch-jars,check-ooxml-xsds,fetch-ooxml-xsds,check-compiled-ooxml-xsds"
|
|
||||||
description="Unpacks the OOXML xsd files, and compiles them into XmlBeans">
|
|
||||||
<taskdef name="xmlbean"
|
|
||||||
classname="org.apache.xmlbeans.impl.tool.XMLBean"
|
|
||||||
classpath="${ooxml.jar3.dir}:${ooxml.jar4.dir}" />
|
|
||||||
|
|
||||||
<unzip src="${ooxml.xsds.izip}" dest="build/ooxml-xsds/" />
|
|
||||||
<!--
|
|
||||||
schema="build/ooxml-xsds/"
|
|
||||||
schema="build/ooxml-xsds/sml-workbook.xsd"
|
|
||||||
-->
|
|
||||||
<xmlbean
|
|
||||||
schema="build/ooxml-xsds/"
|
|
||||||
destfile="${ooxml.xsds.jar}"
|
|
||||||
javasource="1.4"
|
|
||||||
failonerror="false"
|
|
||||||
fork="true"
|
|
||||||
memoryMaximumSize="512m"
|
|
||||||
>
|
|
||||||
<classpath refid="ooxml.classpath"/>
|
|
||||||
</xmlbean>
|
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="compile" depends="init, compile-main, compile-scratchpad,
|
<target name="compile" depends="init, compile-main, compile-scratchpad,
|
||||||
|
@ -473,24 +369,6 @@ under the License.
|
||||||
</javac>
|
</javac>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="compile-ooxml" depends="init, check-ooxml-xsds, fetch-ooxml-xsds, compile-ooxml-xsds, compile-main">
|
|
||||||
<!-- openxml4j requires java 1.5, so so must we, for now -->
|
|
||||||
<javac target="1.5" source="1.5"
|
|
||||||
destdir="${ooxml.output.dir}" debug="on" srcdir="${ooxml.src}">
|
|
||||||
<classpath refid="ooxml.classpath"/>
|
|
||||||
</javac>
|
|
||||||
|
|
||||||
<javac target="1.5" source="1.5"
|
|
||||||
failonerror="true" destdir="${ooxml.output.test.dir}" debug="on"
|
|
||||||
fork="yes" srcdir="${ooxml.src.test}">
|
|
||||||
<classpath>
|
|
||||||
<path refid="ooxml.classpath"/>
|
|
||||||
<pathelement location="${ooxml.output.dir}"/>
|
|
||||||
<pathelement location="${junit.jar1.dir}"/>
|
|
||||||
</classpath>
|
|
||||||
</javac>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="test" depends="test-main,test-scratchpad,test-contrib"
|
<target name="test" depends="test-main,test-scratchpad,test-contrib"
|
||||||
description="Tests main, contrib and scratchpad"/>
|
description="Tests main, contrib and scratchpad"/>
|
||||||
|
|
||||||
|
@ -523,6 +401,8 @@ under the License.
|
||||||
file="${main.src.test}/org/apache/poi/hpsf/data"/>
|
file="${main.src.test}/org/apache/poi/hpsf/data"/>
|
||||||
<sysproperty key="POIFS.testdata.path"
|
<sysproperty key="POIFS.testdata.path"
|
||||||
file="${main.src.test}/org/apache/poi/poifs/data"/>
|
file="${main.src.test}/org/apache/poi/poifs/data"/>
|
||||||
|
<sysproperty key="DDF.testdata.path"
|
||||||
|
file="${main.src.test}/org/apache/poi/ddf/data"/>
|
||||||
<sysproperty key="java.awt.headless" value="true"/>
|
<sysproperty key="java.awt.headless" value="true"/>
|
||||||
<formatter type="plain"/>
|
<formatter type="plain"/>
|
||||||
<formatter type="xml"/>
|
<formatter type="xml"/>
|
||||||
|
@ -725,43 +605,6 @@ under the License.
|
||||||
<echo file="${contrib.testokfile}" append="false" message="testok"/>
|
<echo file="${contrib.testokfile}" append="false" message="testok"/>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="-test-ooxml-check">
|
|
||||||
<uptodate property="ooxml.test.notRequired" targetfile="${ooxml.testokfile}">
|
|
||||||
<srcfiles dir="${ooxml.src}"/>
|
|
||||||
<srcfiles dir="${ooxml.src.test}"/>
|
|
||||||
</uptodate>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="test-ooxml" depends="compile-main,compile-ooxml,-test-ooxml-check" unless="ooxml.test.notRequired">
|
|
||||||
<junit printsummary="yes" fork="no" haltonfailure="${halt.on.test.failure}" failureproperty="ooxml.test.failed">
|
|
||||||
<classpath>
|
|
||||||
<path refid="ooxml.classpath"/>
|
|
||||||
<pathelement location="${main.output.dir}"/>
|
|
||||||
<pathelement location="${ooxml.output.dir}"/>
|
|
||||||
<pathelement location="${ooxml.output.test.dir}"/>
|
|
||||||
<pathelement location="${junit.jar1.dir}"/>
|
|
||||||
</classpath>
|
|
||||||
<sysproperty key="HSSF.testdata.path" file="${main.src.test}/org/apache/poi/hssf/data"/>
|
|
||||||
<sysproperty key="HWPF.testdata.path" file="${scratchpad.src.test}/org/apache/poi/hwpf/data"/>
|
|
||||||
<sysproperty key="HSLF.testdata.path" file="${scratchpad.src.test}/org/apache/poi/hslf/data"/>
|
|
||||||
<sysproperty key="java.awt.headless" value="true"/>
|
|
||||||
<formatter type="plain"/>
|
|
||||||
<formatter type="xml"/>
|
|
||||||
<batchtest todir="${ooxml.reports.test}">
|
|
||||||
<fileset dir="${ooxml.src.test}">
|
|
||||||
<include name="**/Test*.java"/>
|
|
||||||
<exclude name="**/AllTests.java"/>
|
|
||||||
</fileset>
|
|
||||||
</batchtest>
|
|
||||||
</junit>
|
|
||||||
<delete file="${ooxml.testokfile}"/>
|
|
||||||
<antcall target="-test-ooxml-write-testfile"/>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="-test-ooxml-write-testfile" unless="ooxml.test.failed">
|
|
||||||
<echo file="${ooxml.testokfile}" append="false" message="testok"/>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="-check-docs">
|
<target name="-check-docs">
|
||||||
<uptodate property="main.docs.notRequired" targetfile="${build.site}/index.html">
|
<uptodate property="main.docs.notRequired" targetfile="${build.site}/index.html">
|
||||||
<srcfiles dir="${build.site.src}"/>
|
<srcfiles dir="${build.site.src}"/>
|
||||||
|
@ -1148,21 +991,6 @@ FORREST_HOME environment variable!</echo>
|
||||||
</manifest>
|
</manifest>
|
||||||
</jar>
|
</jar>
|
||||||
</target>
|
</target>
|
||||||
<target name="jar-ooxml" depends="compile-ooxml" description="Creates the ooxml jar files for distribution">
|
|
||||||
<jar destfile="${dist.dir}/${jar.name}-ooxml-${version.id}-${DSTAMP}.jar">
|
|
||||||
<fileset dir="${ooxml.output.dir}" />
|
|
||||||
<fileset dir="legal/" />
|
|
||||||
<manifest>
|
|
||||||
<attribute name="Built-By" value="${user.name}"/>
|
|
||||||
<attribute name="Specification-Title" value="Apache POI"/>
|
|
||||||
<attribute name="Specification-Version" value="${version.id}-${DSTAMP}"/>
|
|
||||||
<attribute name="Specification-Vendor" value="Apache"/>
|
|
||||||
<attribute name="Implementation-Title" value="Apache POI"/>
|
|
||||||
<attribute name="Implementation-Version" value="${version.id}-${DSTAMP}"/>
|
|
||||||
<attribute name="Implementation-Vendor" value="Apache"/>
|
|
||||||
</manifest>
|
|
||||||
</jar>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="dist" depends="clean, fail-unless-tools-are-available, compile, site, jar"
|
<target name="dist" depends="clean, fail-unless-tools-are-available, compile, site, jar"
|
||||||
description="Creates the entire distribution into build/dist, from scratch">
|
description="Creates the entire distribution into build/dist, from scratch">
|
||||||
|
@ -1171,6 +999,7 @@ FORREST_HOME environment variable!</echo>
|
||||||
|
|
||||||
<zip destfile="${dist.dir}/${jar.name}-bin-${version.id}-${DSTAMP}.zip">
|
<zip destfile="${dist.dir}/${jar.name}-bin-${version.id}-${DSTAMP}.zip">
|
||||||
<zipfileset dir="legal/" prefix="${zipdir}" />
|
<zipfileset dir="legal/" prefix="${zipdir}" />
|
||||||
|
<zipfileset dir="lib/" prefix="${zipdir}/lib" />
|
||||||
<zipfileset dir="${build.site}" prefix="${zipdir}/docs"/>
|
<zipfileset dir="${build.site}" prefix="${zipdir}/docs"/>
|
||||||
<zipfileset file="${dist.dir}/${jar.name}-${version.id}-${DSTAMP}.jar" prefix="${zipdir}" />
|
<zipfileset file="${dist.dir}/${jar.name}-${version.id}-${DSTAMP}.jar" prefix="${zipdir}" />
|
||||||
<zipfileset file="${dist.dir}/${jar.name}-contrib-${version.id}-${DSTAMP}.jar" prefix="${zipdir}" />
|
<zipfileset file="${dist.dir}/${jar.name}-contrib-${version.id}-${DSTAMP}.jar" prefix="${zipdir}" />
|
||||||
|
@ -1193,6 +1022,7 @@ FORREST_HOME environment variable!</echo>
|
||||||
<tar destfile="${dist.dir}/${jar.name}-bin-${version.id}-${DSTAMP}.tar.gz"
|
<tar destfile="${dist.dir}/${jar.name}-bin-${version.id}-${DSTAMP}.tar.gz"
|
||||||
compression="gzip">
|
compression="gzip">
|
||||||
<tarfileset dir="legal/" prefix="${zipdir}" />
|
<tarfileset dir="legal/" prefix="${zipdir}" />
|
||||||
|
<tarfileset dir="lib/" prefix="${zipdir}/lib" />
|
||||||
<tarfileset dir="${build.site}" prefix="${zipdir}/docs"/>
|
<tarfileset dir="${build.site}" prefix="${zipdir}/docs"/>
|
||||||
<tarfileset file="${dist.dir}/${jar.name}-${version.id}-${DSTAMP}.jar" prefix="${zipdir}" />
|
<tarfileset file="${dist.dir}/${jar.name}-${version.id}-${DSTAMP}.jar" prefix="${zipdir}" />
|
||||||
<tarfileset file="${dist.dir}/${jar.name}-contrib-${version.id}-${DSTAMP}.jar" prefix="${zipdir}" />
|
<tarfileset file="${dist.dir}/${jar.name}-contrib-${version.id}-${DSTAMP}.jar" prefix="${zipdir}" />
|
||||||
|
|
|
@ -36,7 +36,17 @@
|
||||||
</devs>
|
</devs>
|
||||||
|
|
||||||
<!-- Don't forget to update status.xml too! -->
|
<!-- Don't forget to update status.xml too! -->
|
||||||
<release version="3.1-beta1" date="2008-04-??">
|
<release version="3.1-beta2" date="2008-05-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44929 - Improved error handling in HSSFWorkbook when attempting to read a BIFF5 file</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44675 - Parameter operand classes (function metadata) required to encode SUM() etc properly. Added parse validation for number of parameters</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44921 - allow Ptg.writeBytes() to be called on relative ref Ptgs (RefN* and AreaN*)</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44914 - Fix/suppress warning message "WARN. Unread n bytes of record 0xNN"</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44892 - made HSSFWorkbook.getSheet(String) case insensitive</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44886] - Correctly process PICT metafile in EscherMetafileBlip</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44893 - Take into account indentation in HSSFSheet.autoSizeColumn</action>
|
||||||
|
</release>
|
||||||
|
<release version="3.1-beta1" date="2008-04-28">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44857 - Avoid OOM on unknown escher records when EscherMetafileBlip is incorrect</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting embedded sounds from slide show </action>
|
<action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting embedded sounds from slide show </action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Initial support for rendering slides into images</action>
|
<action dev="POI-DEVELOPERS" type="add">HSLF: Initial support for rendering slides into images</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting OLE object data from slide show </action>
|
<action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting OLE object data from slide show </action>
|
||||||
|
|
|
@ -31,6 +31,23 @@
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<section><title>POI 3.1-BETA1 Released (2008-04028)</title>
|
||||||
|
<p>
|
||||||
|
The POI team is pleased to announce the release of 3.1 BETA1 which is one of the final steps before 3.1 FINAL.
|
||||||
|
The status of this release is a beta, meaning that we encourage users to try it out.
|
||||||
|
If you find any bugs, please report them to the POI <link href="https://issues.apache.org/bugzilla/buglist.cgi?product=POI">bug database</link> or to
|
||||||
|
the <link href="./mailinglists.html">POI Developer List</link>.
|
||||||
|
</p><p> A full list of changes is available in
|
||||||
|
<link href="./changes.html">the changelog</link>, and
|
||||||
|
<link href="http://www.apache.org/dyn/closer.cgi/poi/dev/">download</link>
|
||||||
|
the source and binaries from your
|
||||||
|
<link href="http://www.apache.org/dyn/closer.cgi/poi/dev/">local mirror</link>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The release is also available from the central Maven repository
|
||||||
|
under Group ID "org.apache.poi" and Version "3.1-beta1".
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
<section><title>POI 3.0.2 Released</title>
|
<section><title>POI 3.0.2 Released</title>
|
||||||
<p>The POI team is pleased to announce POI 3.0.2, the latest release of Apache POI.
|
<p>The POI team is pleased to announce POI 3.0.2, the latest release of Apache POI.
|
||||||
There have been many important bug fixes since the 3.0.1 release and a lot of new features. A full list of changes is available in
|
There have been many important bug fixes since the 3.0.1 release and a lot of new features. A full list of changes is available in
|
||||||
|
|
|
@ -33,7 +33,17 @@
|
||||||
|
|
||||||
<!-- Don't forget to update changes.xml too! -->
|
<!-- Don't forget to update changes.xml too! -->
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.1-beta1" date="2008-04-??">
|
<release version="3.1-beta2" date="2008-05-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44929 - Improved error handling in HSSFWorkbook when attempting to read a BIFF5 file</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44675 - Parameter operand classes (function metadata) required to encode SUM() etc properly. Added parse validation for number of parameters</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44921 - allow Ptg.writeBytes() to be called on relative ref Ptgs (RefN* and AreaN*)</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44914 - Fix/suppress warning message "WARN. Unread n bytes of record 0xNN"</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44892 - made HSSFWorkbook.getSheet(String) case insensitive</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44886] - Correctly process PICT metafile in EscherMetafileBlip</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44893 - Take into account indentation in HSSFSheet.autoSizeColumn</action>
|
||||||
|
</release>
|
||||||
|
<release version="3.1-beta1" date="2008-04-28">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44857 - Avoid OOM on unknown escher records when EscherMetafileBlip is incorrect</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting embedded sounds from slide show </action>
|
<action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting embedded sounds from slide show </action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Initial support for rendering slides into images</action>
|
<action dev="POI-DEVELOPERS" type="add">HSLF: Initial support for rendering slides into images</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting OLE object data from slide show </action>
|
<action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting OLE object data from slide show </action>
|
||||||
|
|
|
@ -19,7 +19,11 @@ POI Release Guide
|
||||||
POI 3.0.2 and 3.1 were built using Ant 1.6.2 and Forrest 0.5
|
POI 3.0.2 and 3.1 were built using Ant 1.6.2 and Forrest 0.5
|
||||||
|
|
||||||
(II) Making release artefacts
|
(II) Making release artefacts
|
||||||
1. Update version id in build.xml.
|
1. Update version id in build.xml
|
||||||
|
{code:xml}
|
||||||
|
<property name="version.id" value="3.1-beta1"/>
|
||||||
|
{code}
|
||||||
|
|
||||||
2. Tag current version. Include the current revision number in the comment
|
2. Tag current version. Include the current revision number in the comment
|
||||||
|
|
||||||
{code}
|
{code}
|
||||||
|
@ -46,7 +50,7 @@ https://svn.apache.org/repos/asf/poi/trunk
|
||||||
|
|
||||||
5. Start a new section in sites.xml and status.xml.
|
5. Start a new section in sites.xml and status.xml.
|
||||||
|
|
||||||
6. Build as if the vote had passed. The buid date must be +7 days from current.
|
6. Build as if the vote had passed. The build date must be +7 days from current.
|
||||||
{code}
|
{code}
|
||||||
ant build
|
ant build
|
||||||
{code}
|
{code}
|
||||||
|
@ -109,27 +113,68 @@ Log-in on people.apache.org
|
||||||
|
|
||||||
1. Go to ~/POI-3.1-BETA1
|
1. Go to ~/POI-3.1-BETA1
|
||||||
|
|
||||||
|
zap previous version first.
|
||||||
|
|
||||||
|
{code}
|
||||||
cd ~/POI-3.1-BETA1/main
|
cd ~/POI-3.1-BETA1/main
|
||||||
|
{code}
|
||||||
|
|
||||||
BETA and ALPHA releases:
|
BETA and ALPHA releases:
|
||||||
|
|
||||||
|
{code}
|
||||||
cp *-src-* /www/www.apache.org/dist/poi/dev/src
|
cp *-src-* /www/www.apache.org/dist/poi/dev/src
|
||||||
cp *-bin-* /www/www.apache.org/dist/poi/dev/bin
|
cp *-bin-* /www/www.apache.org/dist/poi/dev/bin
|
||||||
|
{code}
|
||||||
|
|
||||||
FINAL release:
|
FINAL release:
|
||||||
|
{code}
|
||||||
cp *-src-* /www/www.apache.org/dist/poi/release/src
|
cp *-src-* /www/www.apache.org/dist/poi/release/src
|
||||||
cp *-bin-* /www/www.apache.org/dist/poi/release/bin
|
cp *-bin-* /www/www.apache.org/dist/poi/release/bin
|
||||||
|
{code}
|
||||||
|
|
||||||
|
{code}
|
||||||
cd ~/POI-3.1-BETA1/maven
|
cd ~/POI-3.1-BETA1/maven
|
||||||
|
|
||||||
cp -r org.apache.poi /www/people.apache.org/repo/m1-ibiblio-rsync-repository/
|
cp -r org.apache.poi /www/people.apache.org/repo/m1-ibiblio-rsync-repository/
|
||||||
cp -r poi/poms /www/people.apache.org/repo/m1-ibiblio-rsync-repository/poi
|
cp -r poi/poms /www/people.apache.org/repo/m1-ibiblio-rsync-repository/poi
|
||||||
|
{code}
|
||||||
|
|
||||||
2. Make sure that the files are owned by the unix group apcvs and that they are writable by this group.
|
2. Make sure that the files are owned by the unix group apcvs and that they are writable by this group.
|
||||||
|
|
||||||
3. Wait for the distributions to appear on your favourite mirror
|
3. Wait for the distributions to appear on your favourite mirror
|
||||||
|
|
||||||
4. Send announcements:
|
4. test maven
|
||||||
- to poi-user and poi-dev lists
|
create a simple project and make sure the release artifacts are accessible by maven:
|
||||||
- send announcements to announcement@apache.org, announcements@jakarta.apache.org
|
|
||||||
|
{code}
|
||||||
|
$ mvn archetype:create -DgroupId=org.apache.poi.scratchpad -DartifactId=maven-test
|
||||||
|
cd maven-test
|
||||||
|
{code}
|
||||||
|
edit pom.xml and add the release artefacts to the project dependencies:
|
||||||
|
|
||||||
|
{code:xml}
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi</artifactId>
|
||||||
|
<version>3.1-beta1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi-scratchpad</artifactId>
|
||||||
|
<version>3.1-beta1</version>
|
||||||
|
</dependency>
|
||||||
|
{code}
|
||||||
|
|
||||||
|
{code}
|
||||||
|
mvn compile
|
||||||
|
{code}
|
||||||
|
|
||||||
|
You should see [INFO] BUILD SUCCESSFUL in the end.
|
||||||
|
|
||||||
|
5. Don't forget to upload the latest version of the site and javadocs
|
||||||
|
|
||||||
|
6. Send announcements:
|
||||||
|
- to poi-user and poi-dev lists
|
||||||
|
- to announcement@apache.org, announcements@jakarta.apache.org
|
||||||
|
|
||||||
|
Note, announcements should be sent from your @apache.org e-mail address.
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ public class EscherDggRecord
|
||||||
private int field_3_numShapesSaved;
|
private int field_3_numShapesSaved;
|
||||||
private int field_4_drawingsSaved;
|
private int field_4_drawingsSaved;
|
||||||
private FileIdCluster[] field_5_fileIdClusters;
|
private FileIdCluster[] field_5_fileIdClusters;
|
||||||
|
private int maxDgId;
|
||||||
|
|
||||||
public static class FileIdCluster
|
public static class FileIdCluster
|
||||||
{
|
{
|
||||||
|
@ -87,6 +88,7 @@ public class EscherDggRecord
|
||||||
for (int i = 0; i < field_5_fileIdClusters.length; i++)
|
for (int i = 0; i < field_5_fileIdClusters.length; i++)
|
||||||
{
|
{
|
||||||
field_5_fileIdClusters[i] = new FileIdCluster(LittleEndian.getInt( data, pos + size ), LittleEndian.getInt( data, pos + size + 4 ));
|
field_5_fileIdClusters[i] = new FileIdCluster(LittleEndian.getInt( data, pos + size ), LittleEndian.getInt( data, pos + size + 4 ));
|
||||||
|
maxDgId = Math.max(maxDgId, field_5_fileIdClusters[i].getDrawingGroupId());
|
||||||
size += 8;
|
size += 8;
|
||||||
}
|
}
|
||||||
bytesRemaining -= size;
|
bytesRemaining -= size;
|
||||||
|
@ -229,6 +231,13 @@ public class EscherDggRecord
|
||||||
this.field_4_drawingsSaved = field_4_drawingsSaved;
|
this.field_4_drawingsSaved = field_4_drawingsSaved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The maximum drawing group ID
|
||||||
|
*/
|
||||||
|
public int getMaxDrawingGroupId(){
|
||||||
|
return maxDgId;
|
||||||
|
}
|
||||||
|
|
||||||
public FileIdCluster[] getFileIdClusters()
|
public FileIdCluster[] getFileIdClusters()
|
||||||
{
|
{
|
||||||
return field_5_fileIdClusters;
|
return field_5_fileIdClusters;
|
||||||
|
@ -240,10 +249,23 @@ public class EscherDggRecord
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCluster( int dgId, int numShapedUsed )
|
public void addCluster( int dgId, int numShapedUsed )
|
||||||
|
{
|
||||||
|
addCluster(dgId, numShapedUsed, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new cluster
|
||||||
|
*
|
||||||
|
* @param dgId id of the drawing group (stored in the record options)
|
||||||
|
* @param numShapedUsed initial value of the numShapedUsed field
|
||||||
|
* @param sort if true then sort clusters by drawing group id.(
|
||||||
|
* In Excel the clusters are sorted but in PPT they are not)
|
||||||
|
*/
|
||||||
|
public void addCluster( int dgId, int numShapedUsed, boolean sort )
|
||||||
{
|
{
|
||||||
List clusters = new ArrayList(Arrays.asList(field_5_fileIdClusters));
|
List clusters = new ArrayList(Arrays.asList(field_5_fileIdClusters));
|
||||||
clusters.add(new FileIdCluster(dgId, numShapedUsed));
|
clusters.add(new FileIdCluster(dgId, numShapedUsed));
|
||||||
Collections.sort(clusters, new Comparator()
|
if(sort) Collections.sort(clusters, new Comparator()
|
||||||
{
|
{
|
||||||
public int compare( Object o1, Object o2 )
|
public int compare( Object o1, Object o2 )
|
||||||
{
|
{
|
||||||
|
@ -257,6 +279,7 @@ public class EscherDggRecord
|
||||||
return +1;
|
return +1;
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
maxDgId = Math.min(maxDgId, dgId);
|
||||||
field_5_fileIdClusters = (FileIdCluster[]) clusters.toArray( new FileIdCluster[clusters.size()] );
|
field_5_fileIdClusters = (FileIdCluster[]) clusters.toArray( new FileIdCluster[clusters.size()] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,9 +41,20 @@ public class EscherMetafileBlip
|
||||||
public static final short RECORD_ID_WMF = (short) 0xF018 + 3;
|
public static final short RECORD_ID_WMF = (short) 0xF018 + 3;
|
||||||
public static final short RECORD_ID_PICT = (short) 0xF018 + 4;
|
public static final short RECORD_ID_PICT = (short) 0xF018 + 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BLIP signatures as defined in the escher spec
|
||||||
|
*/
|
||||||
|
public static final short SIGNATURE_EMF = 0x3D40;
|
||||||
|
public static final short SIGNATURE_WMF = 0x2160;
|
||||||
|
public static final short SIGNATURE_PICT = 0x5420;
|
||||||
|
|
||||||
private static final int HEADER_SIZE = 8;
|
private static final int HEADER_SIZE = 8;
|
||||||
|
|
||||||
private byte[] field_1_UID;
|
private byte[] field_1_UID;
|
||||||
|
/**
|
||||||
|
* The primary UID is only saved to disk if (blip_instance ^ blip_signature == 1)
|
||||||
|
*/
|
||||||
|
private byte[] field_2_UID;
|
||||||
private int field_2_cb;
|
private int field_2_cb;
|
||||||
private int field_3_rcBounds_x1;
|
private int field_3_rcBounds_x1;
|
||||||
private int field_3_rcBounds_y1;
|
private int field_3_rcBounds_y1;
|
||||||
|
@ -72,6 +83,12 @@ public class EscherMetafileBlip
|
||||||
|
|
||||||
field_1_UID = new byte[16];
|
field_1_UID = new byte[16];
|
||||||
System.arraycopy( data, pos, field_1_UID, 0, 16 ); pos += 16;
|
System.arraycopy( data, pos, field_1_UID, 0, 16 ); pos += 16;
|
||||||
|
|
||||||
|
if((getOptions() ^ getSignature()) == 0x10){
|
||||||
|
field_2_UID = new byte[16];
|
||||||
|
System.arraycopy( data, pos, field_2_UID, 0, 16 ); pos += 16;
|
||||||
|
}
|
||||||
|
|
||||||
field_2_cb = LittleEndian.getInt( data, pos ); pos += 4;
|
field_2_cb = LittleEndian.getInt( data, pos ); pos += 4;
|
||||||
field_3_rcBounds_x1 = LittleEndian.getInt( data, pos ); pos += 4;
|
field_3_rcBounds_x1 = LittleEndian.getInt( data, pos ); pos += 4;
|
||||||
field_3_rcBounds_y1 = LittleEndian.getInt( data, pos ); pos += 4;
|
field_3_rcBounds_y1 = LittleEndian.getInt( data, pos ); pos += 4;
|
||||||
|
@ -118,9 +135,12 @@ public class EscherMetafileBlip
|
||||||
int pos = offset;
|
int pos = offset;
|
||||||
LittleEndian.putShort( data, pos, getOptions() ); pos += 2;
|
LittleEndian.putShort( data, pos, getOptions() ); pos += 2;
|
||||||
LittleEndian.putShort( data, pos, getRecordId() ); pos += 2;
|
LittleEndian.putShort( data, pos, getRecordId() ); pos += 2;
|
||||||
LittleEndian.putInt( data, getRecordSize() - HEADER_SIZE ); pos += 4;
|
LittleEndian.putInt( data, pos, getRecordSize() - HEADER_SIZE ); pos += 4;
|
||||||
|
|
||||||
System.arraycopy( field_1_UID, 0, data, pos, 16 ); pos += 16;
|
System.arraycopy( field_1_UID, 0, data, pos, field_1_UID.length ); pos += field_1_UID.length;
|
||||||
|
if((getOptions() ^ getSignature()) == 0x10){
|
||||||
|
System.arraycopy( field_2_UID, 0, data, pos, field_2_UID.length ); pos += field_2_UID.length;
|
||||||
|
}
|
||||||
LittleEndian.putInt( data, pos, field_2_cb ); pos += 4;
|
LittleEndian.putInt( data, pos, field_2_cb ); pos += 4;
|
||||||
LittleEndian.putInt( data, pos, field_3_rcBounds_x1 ); pos += 4;
|
LittleEndian.putInt( data, pos, field_3_rcBounds_x1 ); pos += 4;
|
||||||
LittleEndian.putInt( data, pos, field_3_rcBounds_y1 ); pos += 4;
|
LittleEndian.putInt( data, pos, field_3_rcBounds_y1 ); pos += 4;
|
||||||
|
@ -135,7 +155,7 @@ public class EscherMetafileBlip
|
||||||
System.arraycopy( raw_pictureData, 0, data, pos, raw_pictureData.length );
|
System.arraycopy( raw_pictureData, 0, data, pos, raw_pictureData.length );
|
||||||
|
|
||||||
listener.afterRecordSerialize(offset + getRecordSize(), getRecordId(), getRecordSize(), this);
|
listener.afterRecordSerialize(offset + getRecordSize(), getRecordId(), getRecordSize(), this);
|
||||||
return HEADER_SIZE + 16 + 1 + raw_pictureData.length;
|
return getRecordSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -161,7 +181,7 @@ public class EscherMetafileBlip
|
||||||
}
|
}
|
||||||
catch ( IOException e )
|
catch ( IOException e )
|
||||||
{
|
{
|
||||||
log.log(POILogger.INFO, "Possibly corrupt compression or non-compressed data", e);
|
log.log(POILogger.WARN, "Possibly corrupt compression or non-compressed data", e);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,7 +193,11 @@ public class EscherMetafileBlip
|
||||||
*/
|
*/
|
||||||
public int getRecordSize()
|
public int getRecordSize()
|
||||||
{
|
{
|
||||||
return 8 + 50 + raw_pictureData.length;
|
int size = 8 + 50 + raw_pictureData.length;
|
||||||
|
if((getOptions() ^ getSignature()) == 0x10){
|
||||||
|
size += field_2_UID.length;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getUID()
|
public byte[] getUID()
|
||||||
|
@ -186,6 +210,16 @@ public class EscherMetafileBlip
|
||||||
this.field_1_UID = field_1_UID;
|
this.field_1_UID = field_1_UID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getPrimaryUID()
|
||||||
|
{
|
||||||
|
return field_2_UID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrimaryUID( byte[] field_2_UID )
|
||||||
|
{
|
||||||
|
this.field_2_UID = field_2_UID;
|
||||||
|
}
|
||||||
|
|
||||||
public int getUncompressedSize()
|
public int getUncompressedSize()
|
||||||
{
|
{
|
||||||
return field_2_cb;
|
return field_2_cb;
|
||||||
|
@ -264,6 +298,7 @@ public class EscherMetafileBlip
|
||||||
" RecordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
" RecordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
||||||
" Options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
" Options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||||
" UID: 0x" + HexDump.toHex( field_1_UID ) + nl +
|
" UID: 0x" + HexDump.toHex( field_1_UID ) + nl +
|
||||||
|
(field_2_UID == null ? "" : (" UID2: 0x" + HexDump.toHex( field_2_UID ) + nl)) +
|
||||||
" Uncompressed Size: " + HexDump.toHex( field_2_cb ) + nl +
|
" Uncompressed Size: " + HexDump.toHex( field_2_cb ) + nl +
|
||||||
" Bounds: " + getBounds() + nl +
|
" Bounds: " + getBounds() + nl +
|
||||||
" Size in EMU: " + getSizeEMU() + nl +
|
" Size in EMU: " + getSizeEMU() + nl +
|
||||||
|
@ -273,4 +308,19 @@ public class EscherMetafileBlip
|
||||||
" Extra Data:" + nl + extraData;
|
" Extra Data:" + nl + extraData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the blip signature
|
||||||
|
*
|
||||||
|
* @return the blip signature
|
||||||
|
*/
|
||||||
|
public short getSignature(){
|
||||||
|
short sig = 0;
|
||||||
|
switch(getRecordId()){
|
||||||
|
case RECORD_ID_EMF: sig = SIGNATURE_EMF; break;
|
||||||
|
case RECORD_ID_WMF: sig = SIGNATURE_WMF; break;
|
||||||
|
case RECORD_ID_PICT: sig = SIGNATURE_PICT; break;
|
||||||
|
default: log.log(POILogger.WARN, "Unknown metafile: " + getRecordId()); break;
|
||||||
|
}
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -380,12 +380,13 @@ public final class FormulaParser {
|
||||||
} else {
|
} else {
|
||||||
isVarArgs = !fm.hasFixedArgsLength();
|
isVarArgs = !fm.hasFixedArgsLength();
|
||||||
funcIx = fm.getIndex();
|
funcIx = fm.getIndex();
|
||||||
|
validateNumArgs(numArgs, fm);
|
||||||
}
|
}
|
||||||
AbstractFunctionPtg retval;
|
AbstractFunctionPtg retval;
|
||||||
if(isVarArgs) {
|
if(isVarArgs) {
|
||||||
retval = new FuncVarPtg(name, (byte)numArgs);
|
retval = new FuncVarPtg(name, (byte)numArgs);
|
||||||
} else {
|
} else {
|
||||||
retval = new FuncPtg(funcIx, (byte)numArgs);
|
retval = new FuncPtg(funcIx);
|
||||||
}
|
}
|
||||||
if (!name.equals(AbstractFunctionPtg.FUNCTION_NAME_IF)) {
|
if (!name.equals(AbstractFunctionPtg.FUNCTION_NAME_IF)) {
|
||||||
// early return for everything else besides IF()
|
// early return for everything else besides IF()
|
||||||
|
@ -447,6 +448,29 @@ public final class FormulaParser {
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateNumArgs(int numArgs, FunctionMetadata fm) {
|
||||||
|
if(numArgs < fm.getMinParams()) {
|
||||||
|
String msg = "Too few arguments to function '" + fm.getName() + "'. ";
|
||||||
|
if(fm.hasFixedArgsLength()) {
|
||||||
|
msg += "Expected " + fm.getMinParams();
|
||||||
|
} else {
|
||||||
|
msg += "At least " + fm.getMinParams() + " were expected";
|
||||||
|
}
|
||||||
|
msg += " but got " + numArgs + ".";
|
||||||
|
throw new FormulaParseException(msg);
|
||||||
|
}
|
||||||
|
if(numArgs > fm.getMaxParams()) {
|
||||||
|
String msg = "Too many arguments to function '" + fm.getName() + "'. ";
|
||||||
|
if(fm.hasFixedArgsLength()) {
|
||||||
|
msg += "Expected " + fm.getMaxParams();
|
||||||
|
} else {
|
||||||
|
msg += "At most " + fm.getMaxParams() + " were expected";
|
||||||
|
}
|
||||||
|
msg += " but got " + numArgs + ".";
|
||||||
|
throw new FormulaParseException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isArgumentDelimiter(char ch) {
|
private static boolean isArgumentDelimiter(char ch) {
|
||||||
return ch == ',' || ch == ')';
|
return ch == ',' || ch == ')';
|
||||||
}
|
}
|
||||||
|
|
|
@ -476,9 +476,9 @@ public class Workbook implements Model
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether a workbook contains the privided sheet name.
|
* Determines whether a workbook contains the provided sheet name.
|
||||||
*
|
*
|
||||||
* @param name the name to test
|
* @param name the name to test (case insensitive match)
|
||||||
* @param excludeSheetIdx the sheet to exclude from the check or -1 to include all sheets in the check.
|
* @param excludeSheetIdx the sheet to exclude from the check or -1 to include all sheets in the check.
|
||||||
* @return true if the sheet contains the name, false otherwise.
|
* @return true if the sheet contains the name, false otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -487,7 +487,7 @@ public class Workbook implements Model
|
||||||
for ( int i = 0; i < boundsheets.size(); i++ )
|
for ( int i = 0; i < boundsheets.size(); i++ )
|
||||||
{
|
{
|
||||||
BoundSheetRecord boundSheetRecord = (BoundSheetRecord) boundsheets.get( i );
|
BoundSheetRecord boundSheetRecord = (BoundSheetRecord) boundsheets.get( i );
|
||||||
if (excludeSheetIdx != i && name.equals(boundSheetRecord.getSheetname()))
|
if (excludeSheetIdx != i && name.equalsIgnoreCase(boundSheetRecord.getSheetname()))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
@ -16,12 +15,6 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ColumnInfoRecord.java
|
|
||||||
*
|
|
||||||
* Created on December 8, 2001, 8:44 AM
|
|
||||||
*/
|
|
||||||
package org.apache.poi.hssf.record;
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
@ -29,29 +22,28 @@ import org.apache.poi.util.BitField;
|
||||||
import org.apache.poi.util.BitFieldFactory;
|
import org.apache.poi.util.BitFieldFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title: ColumnInfo Record<P>
|
* Title: COLINFO Record<p/>
|
||||||
* Description: Defines with width and formatting for a range of columns<P>
|
* Description: Defines with width and formatting for a range of columns<p/>
|
||||||
* REFERENCE: PG 293 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
|
* REFERENCE: PG 293 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<p/>
|
||||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||||
* @version 2.0-pre
|
* @version 2.0-pre
|
||||||
*/
|
*/
|
||||||
|
public final class ColumnInfoRecord extends Record {
|
||||||
public class ColumnInfoRecord
|
|
||||||
extends Record
|
|
||||||
{
|
|
||||||
public static final short sid = 0x7d;
|
public static final short sid = 0x7d;
|
||||||
private short field_1_first_col;
|
private short field_1_first_col;
|
||||||
private short field_2_last_col;
|
private short field_2_last_col;
|
||||||
private short field_3_col_width;
|
private short field_3_col_width;
|
||||||
private short field_4_xf_index;
|
private short field_4_xf_index;
|
||||||
private short field_5_options;
|
private short field_5_options;
|
||||||
static final private BitField hidden = BitFieldFactory.getInstance(0x01);
|
private static final BitField hidden = BitFieldFactory.getInstance(0x01);
|
||||||
static final private BitField outlevel = BitFieldFactory.getInstance(0x0700);
|
private static final BitField outlevel = BitFieldFactory.getInstance(0x0700);
|
||||||
static final private BitField collapsed = BitFieldFactory.getInstance(0x1000);
|
private static final BitField collapsed = BitFieldFactory.getInstance(0x1000);
|
||||||
|
// Excel seems write values 2, 10, and 260, even though spec says "must be zero"
|
||||||
private short field_6_reserved;
|
private short field_6_reserved;
|
||||||
|
|
||||||
public ColumnInfoRecord()
|
public ColumnInfoRecord()
|
||||||
{
|
{
|
||||||
|
field_6_reserved = 2; // seems to be the most common value
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,7 +63,18 @@ public class ColumnInfoRecord
|
||||||
field_3_col_width = in.readShort();
|
field_3_col_width = in.readShort();
|
||||||
field_4_xf_index = in.readShort();
|
field_4_xf_index = in.readShort();
|
||||||
field_5_options = in.readShort();
|
field_5_options = in.readShort();
|
||||||
|
switch(in.remaining()) {
|
||||||
|
case 2: // usual case
|
||||||
field_6_reserved = in.readShort();
|
field_6_reserved = in.readShort();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// often COLINFO gets encoded 1 byte short
|
||||||
|
// shouldn't matter because this field is unused
|
||||||
|
field_6_reserved = in.readByte();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Unusual record size remaining=(" + in.remaining() + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void validateSid(short id)
|
protected void validateSid(short id)
|
||||||
|
|
|
@ -15,30 +15,25 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.hssf.record;
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.POILogFactory;
|
|
||||||
import org.apache.poi.util.POILogger;
|
|
||||||
import org.apache.poi.util.StringUtil;
|
import org.apache.poi.util.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title: FileSharing<P>
|
* Title: FILESHARING<P>
|
||||||
* Description: stores the encrypted readonly for a workbook (write protect)
|
* Description: stores the encrypted readonly for a workbook (write protect)
|
||||||
* REFERENCE: PG 314 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
|
* This functionality is accessed from the options dialog box available when performing 'Save As'.<p/>
|
||||||
|
* REFERENCE: PG 314 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<p/>
|
||||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||||
*/
|
*/
|
||||||
|
public final class FileSharingRecord extends Record {
|
||||||
public class FileSharingRecord extends Record {
|
|
||||||
private static POILogger logger = POILogFactory.getLogger(FileSharingRecord.class);
|
|
||||||
|
|
||||||
public final static short sid = 0x5b;
|
public final static short sid = 0x5b;
|
||||||
private short field_1_readonly;
|
private short field_1_readonly;
|
||||||
private short field_2_password;
|
private short field_2_password;
|
||||||
private byte field_3_username_length;
|
private byte field_3_username_unicode_options;
|
||||||
private short field_4_unknown; // not documented
|
private String field_3_username_value;
|
||||||
private String field_5_username;
|
|
||||||
|
|
||||||
public FileSharingRecord() {}
|
public FileSharingRecord() {}
|
||||||
|
|
||||||
|
@ -61,23 +56,15 @@ public class FileSharingRecord extends Record {
|
||||||
protected void fillFields(RecordInputStream in) {
|
protected void fillFields(RecordInputStream in) {
|
||||||
field_1_readonly = in.readShort();
|
field_1_readonly = in.readShort();
|
||||||
field_2_password = in.readShort();
|
field_2_password = in.readShort();
|
||||||
field_3_username_length = in.readByte();
|
|
||||||
|
|
||||||
// Is this really correct? The latest docs
|
int nameLen = in.readShort();
|
||||||
// seem to hint there's nothing between the
|
|
||||||
// username length and the username string
|
|
||||||
field_4_unknown = in.readShort();
|
|
||||||
|
|
||||||
// Ensure we don't try to read more data than
|
if(nameLen > 0) {
|
||||||
// there actually is
|
// TODO - Current examples(3) from junits only have zero length username.
|
||||||
if(field_3_username_length > in.remaining()) {
|
field_3_username_unicode_options = in.readByte();
|
||||||
logger.log(POILogger.WARN, "FileSharingRecord defined a username of length " + field_3_username_length + ", but only " + in.remaining() + " bytes were left, truncating");
|
field_3_username_value = in.readCompressedUnicode(nameLen);
|
||||||
field_3_username_length = (byte)in.remaining();
|
|
||||||
}
|
|
||||||
if(field_3_username_length > 0) {
|
|
||||||
field_5_username = in.readCompressedUnicode(field_3_username_length);
|
|
||||||
} else {
|
} else {
|
||||||
field_5_username = "";
|
field_3_username_value = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,45 +122,24 @@ public class FileSharingRecord extends Record {
|
||||||
/**
|
/**
|
||||||
* @returns byte representing the length of the username field
|
* @returns byte representing the length of the username field
|
||||||
*/
|
*/
|
||||||
public byte getUsernameLength() {
|
public short getUsernameLength() {
|
||||||
return field_3_username_length ;
|
return (short) field_3_username_value.length();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param byte representing the length of the username field
|
|
||||||
*/
|
|
||||||
public void setUsernameLength(byte length) {
|
|
||||||
this.field_3_username_length = length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns username of the user that created the file
|
* @returns username of the user that created the file
|
||||||
*/
|
*/
|
||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
return this.field_5_username;
|
return field_3_username_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param username of the user that created the file
|
* @param username of the user that created the file
|
||||||
*/
|
*/
|
||||||
public void setUsername(String username) {
|
public void setUsername(String username) {
|
||||||
this.field_5_username = username;
|
field_3_username_value = username;
|
||||||
this.field_3_username_length = (byte)username.length();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return short value of a "bonus field" in Excel that was not doc'd
|
|
||||||
*/
|
|
||||||
public short getUnknown() {
|
|
||||||
return field_4_unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param unknown field value to set (bonus field that is not doc'd)
|
|
||||||
*/
|
|
||||||
public void setUnknown(short unk) {
|
|
||||||
field_4_unknown = unk;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
@ -183,10 +149,6 @@ public class FileSharingRecord extends Record {
|
||||||
.append(getReadOnly() == 1 ? "true" : "false").append("\n");
|
.append(getReadOnly() == 1 ? "true" : "false").append("\n");
|
||||||
buffer.append(" .password = ")
|
buffer.append(" .password = ")
|
||||||
.append(Integer.toHexString(getPassword())).append("\n");
|
.append(Integer.toHexString(getPassword())).append("\n");
|
||||||
buffer.append(" .userlen = ")
|
|
||||||
.append(Integer.toHexString(getUsernameLength())).append("\n");
|
|
||||||
buffer.append(" .unknown = ")
|
|
||||||
.append(Integer.toHexString(getUnknown())).append("\n");
|
|
||||||
buffer.append(" .username = ")
|
buffer.append(" .username = ")
|
||||||
.append(getUsername()).append("\n");
|
.append(getUsername()).append("\n");
|
||||||
buffer.append("[/FILESHARING]\n");
|
buffer.append("[/FILESHARING]\n");
|
||||||
|
@ -194,18 +156,25 @@ public class FileSharingRecord extends Record {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int serialize(int offset, byte [] data) {
|
public int serialize(int offset, byte [] data) {
|
||||||
|
// TODO - junit
|
||||||
LittleEndian.putShort(data, 0 + offset, sid);
|
LittleEndian.putShort(data, 0 + offset, sid);
|
||||||
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize()-4));
|
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize()-4));
|
||||||
LittleEndian.putShort(data, 4 + offset, getReadOnly());
|
LittleEndian.putShort(data, 4 + offset, getReadOnly());
|
||||||
LittleEndian.putShort(data, 6 + offset, getPassword());
|
LittleEndian.putShort(data, 6 + offset, getPassword());
|
||||||
data[ 8 + offset ] = getUsernameLength();
|
LittleEndian.putShort(data, 8 + offset, getUsernameLength());
|
||||||
LittleEndian.putShort(data, 9 + offset, getUnknown());
|
if(getUsernameLength() > 0) {
|
||||||
|
LittleEndian.putByte(data, 10 + offset, field_3_username_unicode_options);
|
||||||
StringUtil.putCompressedUnicode( getUsername(), data, 11 + offset );
|
StringUtil.putCompressedUnicode( getUsername(), data, 11 + offset );
|
||||||
|
}
|
||||||
return getRecordSize();
|
return getRecordSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRecordSize() {
|
public int getRecordSize() {
|
||||||
return 11+getUsernameLength();
|
short nameLen = getUsernameLength();
|
||||||
|
if (nameLen < 1) {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
return 11+nameLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getSid() {
|
public short getSid() {
|
||||||
|
@ -219,10 +188,7 @@ public class FileSharingRecord extends Record {
|
||||||
FileSharingRecord clone = new FileSharingRecord();
|
FileSharingRecord clone = new FileSharingRecord();
|
||||||
clone.setReadOnly(field_1_readonly);
|
clone.setReadOnly(field_1_readonly);
|
||||||
clone.setPassword(field_2_password);
|
clone.setPassword(field_2_password);
|
||||||
clone.setUsernameLength(field_3_username_length);
|
clone.setUsername(field_3_username_value);
|
||||||
clone.setUnknown(field_4_unknown);
|
|
||||||
clone.setUsername(field_5_username);
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ import org.apache.poi.util.LittleEndian;
|
||||||
* @version 2.0-pre
|
* @version 2.0-pre
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class FormulaRecord
|
public final class FormulaRecord
|
||||||
extends Record
|
extends Record
|
||||||
implements CellValueRecordInterface, Comparable
|
implements CellValueRecordInterface, Comparable
|
||||||
{
|
{
|
||||||
|
@ -108,6 +108,11 @@ public class FormulaRecord
|
||||||
} catch (java.lang.UnsupportedOperationException uoe) {
|
} catch (java.lang.UnsupportedOperationException uoe) {
|
||||||
throw new RecordFormatException(uoe);
|
throw new RecordFormatException(uoe);
|
||||||
}
|
}
|
||||||
|
if (in.remaining() == 10) {
|
||||||
|
// TODO - this seems to occur when IntersectionPtg is present
|
||||||
|
// 10 extra bytes are just 0x01 and 0x00
|
||||||
|
// This causes POI stderr: "WARN. Unread 10 bytes of record 0x6"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//public void setRow(short row)
|
//public void setRow(short row)
|
||||||
|
|
|
@ -186,6 +186,16 @@ public final class SharedFormulaRecord extends Record {
|
||||||
* counter part
|
* counter part
|
||||||
*/
|
*/
|
||||||
protected static Stack convertSharedFormulas(Stack ptgs, int formulaRow, int formulaColumn) {
|
protected static Stack convertSharedFormulas(Stack ptgs, int formulaRow, int formulaColumn) {
|
||||||
|
if(false) {
|
||||||
|
/*
|
||||||
|
* TODO - (May-2008) Stop converting relative ref Ptgs in shared formula records.
|
||||||
|
* If/when POI writes out the workbook, this conversion makes an unnecessary diff in the BIFF records.
|
||||||
|
* Disabling this code breaks one existing junit.
|
||||||
|
* Some fix-up will be required to make Ptg.toFormulaString(HSSFWorkbook) work properly.
|
||||||
|
* That method will need 2 extra params: rowIx and colIx.
|
||||||
|
*/
|
||||||
|
return ptgs;
|
||||||
|
}
|
||||||
Stack newPtgStack = new Stack();
|
Stack newPtgStack = new Stack();
|
||||||
|
|
||||||
if (ptgs != null)
|
if (ptgs != null)
|
||||||
|
|
|
@ -147,10 +147,12 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getParameterClass(int index) {
|
public byte getParameterClass(int index) {
|
||||||
try {
|
if (index >= paramClass.length) {
|
||||||
return paramClass[index];
|
// For var-arg (and other?) functions, the metadata does not list all the parameter
|
||||||
} catch (ArrayIndexOutOfBoundsException aioobe) {
|
// operand classes. In these cases, all extra parameters are assumed to have the
|
||||||
|
// same operand class as the last one specified.
|
||||||
return paramClass[paramClass.length - 1];
|
return paramClass[paramClass.length - 1];
|
||||||
}
|
}
|
||||||
|
return paramClass[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
@ -16,19 +15,9 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
/*
|
|
||||||
* AreaPtg.java
|
|
||||||
*
|
|
||||||
* Created on November 17, 2001, 9:30 PM
|
|
||||||
*/
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
|
||||||
import org.apache.poi.util.BitField;
|
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.hssf.record.RecordInputStream;
|
||||||
import org.apache.poi.hssf.util.AreaReference;
|
|
||||||
import org.apache.poi.hssf.util.CellReference;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,8 +25,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class AreaNAPtg
|
public final class AreaNAPtg extends AreaPtg
|
||||||
extends AreaPtg
|
|
||||||
{
|
{
|
||||||
public final static short sid = 0x6D;
|
public final static short sid = 0x6D;
|
||||||
|
|
||||||
|
@ -50,20 +38,16 @@ public class AreaNAPtg
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset) {
|
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAreaPtgName() {
|
public String getAreaPtgName() {
|
||||||
return "AreaNAPtg";
|
return "AreaNAPtg";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString(HSSFWorkbook book)
|
public String toFormulaString(HSSFWorkbook book)
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
throw notImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
throw notImplemented();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class AreaNPtg
|
public final class AreaNPtg extends AreaPtg
|
||||||
extends AreaPtg
|
|
||||||
{
|
{
|
||||||
public final static short sid = 0x2D;
|
public final static short sid = 0x2D;
|
||||||
|
|
||||||
|
@ -50,23 +49,16 @@ public class AreaNPtg
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset) {
|
|
||||||
super.writeBytes(array,offset);
|
|
||||||
//this should be a warning...there doesn't seem to be any rationale to throwing an exception here...
|
|
||||||
//this excpeiton appears to break user defined named ranges...
|
|
||||||
//throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAreaPtgName() {
|
public String getAreaPtgName() {
|
||||||
return "AreaNPtg";
|
return "AreaNPtg";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString(HSSFWorkbook book)
|
public String toFormulaString(HSSFWorkbook book)
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
throw notImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
throw notImplemented();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
@ -16,19 +15,9 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
/*
|
|
||||||
* AreaPtg.java
|
|
||||||
*
|
|
||||||
* Created on November 17, 2001, 9:30 PM
|
|
||||||
*/
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
|
||||||
import org.apache.poi.util.BitField;
|
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.hssf.record.RecordInputStream;
|
||||||
import org.apache.poi.hssf.util.AreaReference;
|
|
||||||
import org.apache.poi.hssf.util.CellReference;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,10 +25,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
* @author andy
|
* @author andy
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
|
public final class AreaNVPtg extends AreaPtg {
|
||||||
public class AreaNVPtg
|
|
||||||
extends AreaPtg
|
|
||||||
{
|
|
||||||
public final static short sid = 0x4D;
|
public final static short sid = 0x4D;
|
||||||
|
|
||||||
protected AreaNVPtg() {
|
protected AreaNVPtg() {
|
||||||
|
@ -51,20 +37,16 @@ public class AreaNVPtg
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset) {
|
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAreaPtgName() {
|
public String getAreaPtgName() {
|
||||||
return "AreaNVPtg";
|
return "AreaNVPtg";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString(HSSFWorkbook book)
|
public String toFormulaString(HSSFWorkbook book)
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
throw notImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
throw notImplemented();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
@ -32,10 +31,15 @@ import org.apache.poi.hssf.record.RecordInputStream;
|
||||||
* @author andy
|
* @author andy
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
|
public class AreaPtg extends Ptg implements AreaI {
|
||||||
|
/**
|
||||||
|
* TODO - (May-2008) fix subclasses of AreaPtg 'AreaN~' which are used in shared formulas.
|
||||||
|
* see similar comment in ReferencePtg
|
||||||
|
*/
|
||||||
|
protected final RuntimeException notImplemented() {
|
||||||
|
return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
||||||
|
}
|
||||||
|
|
||||||
public class AreaPtg
|
|
||||||
extends Ptg implements AreaI
|
|
||||||
{
|
|
||||||
public final static short sid = 0x25;
|
public final static short sid = 0x25;
|
||||||
private final static int SIZE = 9;
|
private final static int SIZE = 9;
|
||||||
/** zero based, unsigned 16 bit */
|
/** zero based, unsigned 16 bit */
|
||||||
|
|
|
@ -57,10 +57,12 @@ public final class FuncPtg extends AbstractFunctionPtg {
|
||||||
}
|
}
|
||||||
numParams = fm.getMinParams();
|
numParams = fm.getMinParams();
|
||||||
}
|
}
|
||||||
public FuncPtg(int functionIndex, int numberOfParameters) {
|
public FuncPtg(int functionIndex) {
|
||||||
field_2_fnc_index = (short) functionIndex;
|
field_2_fnc_index = (short) functionIndex;
|
||||||
numParams = numberOfParameters;
|
FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByIndex(functionIndex);
|
||||||
paramClass = new byte[] { Ptg.CLASS_VALUE, }; // TODO
|
numParams = fm.getMinParams(); // same as max since these are not var-arg funcs
|
||||||
|
returnClass = fm.getReturnClassCode();
|
||||||
|
paramClass = fm.getParameterClassCodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte[] array, int offset) {
|
public void writeBytes(byte[] array, int offset) {
|
||||||
|
|
|
@ -54,8 +54,8 @@ public final class FuncVarPtg extends AbstractFunctionPtg{
|
||||||
returnClass = Ptg.CLASS_VALUE;
|
returnClass = Ptg.CLASS_VALUE;
|
||||||
paramClass = new byte[] {Ptg.CLASS_VALUE};
|
paramClass = new byte[] {Ptg.CLASS_VALUE};
|
||||||
} else {
|
} else {
|
||||||
returnClass = Ptg.CLASS_VALUE;
|
returnClass = fm.getReturnClassCode();
|
||||||
paramClass = new byte[] {Ptg.CLASS_VALUE};
|
paramClass = fm.getParameterClassCodes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@ import org.apache.poi.hssf.record.RecordInputStream;
|
||||||
* @author avik
|
* @author avik
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public abstract class Ptg
|
public abstract class Ptg
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -88,6 +87,10 @@ public abstract class Ptg
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads <tt>size</tt> bytes of the input stream, to create an array of <tt>Ptg</tt>s.
|
||||||
|
* Extra data (beyond <tt>size</tt>) may be read if and <tt>ArrayPtg</tt>s are present.
|
||||||
|
*/
|
||||||
public static Stack createParsedExpressionTokens(short size, RecordInputStream in )
|
public static Stack createParsedExpressionTokens(short size, RecordInputStream in )
|
||||||
{
|
{
|
||||||
Stack stack = new Stack();
|
Stack stack = new Stack();
|
||||||
|
@ -104,6 +107,9 @@ public abstract class Ptg
|
||||||
} else pos += ptg.getSize();
|
} else pos += ptg.getSize();
|
||||||
stack.push( ptg );
|
stack.push( ptg );
|
||||||
}
|
}
|
||||||
|
if(pos != size) {
|
||||||
|
throw new RuntimeException("Ptg array size mismatch");
|
||||||
|
}
|
||||||
if (arrayPtgs != null) {
|
if (arrayPtgs != null) {
|
||||||
for (int i=0;i<arrayPtgs.size();i++) {
|
for (int i=0;i<arrayPtgs.size();i++) {
|
||||||
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
|
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
@ -16,26 +15,16 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
/*
|
|
||||||
* ValueReferencePtg.java
|
|
||||||
*
|
|
||||||
* Created on November 21, 2001, 5:27 PM
|
|
||||||
*/
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
|
||||||
import org.apache.poi.util.BitField;
|
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.hssf.record.RecordInputStream;
|
||||||
import org.apache.poi.hssf.util.CellReference;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RefNAPtg
|
* RefNAPtg
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
|
public final class RefNAPtg extends ReferencePtg
|
||||||
public class RefNAPtg extends ReferencePtg
|
|
||||||
{
|
{
|
||||||
public final static byte sid = 0x6C;
|
public final static byte sid = 0x6C;
|
||||||
|
|
||||||
|
@ -48,21 +37,16 @@ public class RefNAPtg extends ReferencePtg
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset)
|
|
||||||
{
|
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRefPtgName() {
|
public String getRefPtgName() {
|
||||||
return "RefNAPtg";
|
return "RefNAPtg";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString(HSSFWorkbook book)
|
public String toFormulaString(HSSFWorkbook book)
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
throw notImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
throw notImplemented();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
@ -16,25 +15,16 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
/*
|
|
||||||
* RefNPtg.java
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
|
||||||
import org.apache.poi.util.BitField;
|
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.hssf.record.RecordInputStream;
|
||||||
import org.apache.poi.hssf.util.CellReference;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RefNPtg
|
* RefNPtg
|
||||||
* @author Jason Height (jheight at apache dot com)
|
* @author Jason Height (jheight at apache dot com)
|
||||||
*/
|
*/
|
||||||
|
public final class RefNPtg extends ReferencePtg
|
||||||
public class RefNPtg extends ReferencePtg
|
|
||||||
{
|
{
|
||||||
public final static byte sid = 0x2C;
|
public final static byte sid = 0x2C;
|
||||||
|
|
||||||
|
@ -49,21 +39,16 @@ public class RefNPtg extends ReferencePtg
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset)
|
|
||||||
{
|
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRefPtgName() {
|
public String getRefPtgName() {
|
||||||
return "RefNPtg";
|
return "RefNPtg";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString(HSSFWorkbook book)
|
public String toFormulaString(HSSFWorkbook book)
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
throw notImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
throw notImplemented();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
@ -18,11 +17,7 @@
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
|
||||||
import org.apache.poi.util.BitField;
|
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.hssf.record.RecordInputStream;
|
||||||
import org.apache.poi.hssf.util.CellReference;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,8 +25,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class RefNVPtg extends ReferencePtg
|
public final class RefNVPtg extends ReferencePtg {
|
||||||
{
|
|
||||||
public final static byte sid = 0x4C;
|
public final static byte sid = 0x4C;
|
||||||
|
|
||||||
protected RefNVPtg() {
|
protected RefNVPtg() {
|
||||||
|
@ -45,21 +39,16 @@ public class RefNVPtg extends ReferencePtg
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset)
|
|
||||||
{
|
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRefPtgName() {
|
public String getRefPtgName() {
|
||||||
return "RefNVPtg";
|
return "RefNVPtg";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString(HSSFWorkbook book)
|
public String toFormulaString(HSSFWorkbook book)
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
throw notImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
throw new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
throw notImplemented();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,20 @@ import org.apache.poi.hssf.record.RecordInputStream;
|
||||||
* @author Andrew C. Oliver (acoliver@apache.org)
|
* @author Andrew C. Oliver (acoliver@apache.org)
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ReferencePtg extends Ptg {
|
public class ReferencePtg extends Ptg {
|
||||||
|
/**
|
||||||
|
* TODO - (May-2008) fix subclasses of ReferencePtg 'RefN~' which are used in shared formulas.
|
||||||
|
* (See bugzilla 44921)
|
||||||
|
* The 'RefN~' instances do not work properly, and are expected to be converted by
|
||||||
|
* SharedFormulaRecord.convertSharedFormulas().
|
||||||
|
* This conversion currently does not take place for formulas of named ranges, conditional
|
||||||
|
* format rules and data validation rules.
|
||||||
|
* Furthermore, conversion is probably not appropriate in those instances.
|
||||||
|
*/
|
||||||
|
protected final RuntimeException notImplemented() {
|
||||||
|
return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
||||||
|
}
|
||||||
|
|
||||||
private final static int SIZE = 5;
|
private final static int SIZE = 5;
|
||||||
public final static byte sid = 0x24;
|
public final static byte sid = 0x24;
|
||||||
private final static int MAX_ROW_NUMBER = 65536;
|
private final static int MAX_ROW_NUMBER = 65536;
|
||||||
|
|
|
@ -42,8 +42,10 @@ final class FunctionDataBuilder {
|
||||||
_mutatingFunctionIndexes = new HashSet();
|
_mutatingFunctionIndexes = new HashSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(int functionIndex, String functionName, int minParams, int maxParams, boolean hasFootnote) {
|
public void add(int functionIndex, String functionName, int minParams, int maxParams,
|
||||||
FunctionMetadata fm = new FunctionMetadata(functionIndex, functionName, minParams, maxParams);
|
byte returnClassCode, byte[] parameterClassCodes, boolean hasFootnote) {
|
||||||
|
FunctionMetadata fm = new FunctionMetadata(functionIndex, functionName, minParams, maxParams,
|
||||||
|
returnClassCode, parameterClassCodes);
|
||||||
|
|
||||||
Integer indexKey = new Integer(functionIndex);
|
Integer indexKey = new Integer(functionIndex);
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,17 @@ public final class FunctionMetadata {
|
||||||
private final String _name;
|
private final String _name;
|
||||||
private final int _minParams;
|
private final int _minParams;
|
||||||
private final int _maxParams;
|
private final int _maxParams;
|
||||||
|
private final byte _returnClassCode;
|
||||||
|
private final byte[] _parameterClassCodes;
|
||||||
|
|
||||||
/* package */ FunctionMetadata(int index, String name, int minParams, int maxParams) {
|
/* package */ FunctionMetadata(int index, String name, int minParams, int maxParams,
|
||||||
|
byte returnClassCode, byte[] parameterClassCodes) {
|
||||||
_index = index;
|
_index = index;
|
||||||
_name = name;
|
_name = name;
|
||||||
_minParams = minParams;
|
_minParams = minParams;
|
||||||
_maxParams = maxParams;
|
_maxParams = maxParams;
|
||||||
|
_returnClassCode = returnClassCode;
|
||||||
|
_parameterClassCodes = parameterClassCodes;
|
||||||
}
|
}
|
||||||
public int getIndex() {
|
public int getIndex() {
|
||||||
return _index;
|
return _index;
|
||||||
|
@ -49,6 +54,12 @@ public final class FunctionMetadata {
|
||||||
public boolean hasFixedArgsLength() {
|
public boolean hasFixedArgsLength() {
|
||||||
return _minParams == _maxParams;
|
return _minParams == _maxParams;
|
||||||
}
|
}
|
||||||
|
public byte getReturnClassCode() {
|
||||||
|
return _returnClassCode;
|
||||||
|
}
|
||||||
|
public byte[] getParameterClassCodes() {
|
||||||
|
return (byte[]) _parameterClassCodes.clone();
|
||||||
|
}
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuffer sb = new StringBuffer(64);
|
StringBuffer sb = new StringBuffer(64);
|
||||||
sb.append(getClass().getName()).append(" [");
|
sb.append(getClass().getName()).append(" [");
|
||||||
|
|
|
@ -26,6 +26,8 @@ import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.record.formula.Ptg;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the text meta-data file into a <tt>FunctionMetadataRegistry</tt>
|
* Converts the text meta-data file into a <tt>FunctionMetadataRegistry</tt>
|
||||||
*
|
*
|
||||||
|
@ -36,6 +38,12 @@ final class FunctionMetadataReader {
|
||||||
private static final String METADATA_FILE_NAME = "functionMetadata.txt";
|
private static final String METADATA_FILE_NAME = "functionMetadata.txt";
|
||||||
|
|
||||||
private static final Pattern TAB_DELIM_PATTERN = Pattern.compile("\t");
|
private static final Pattern TAB_DELIM_PATTERN = Pattern.compile("\t");
|
||||||
|
private static final Pattern SPACE_DELIM_PATTERN = Pattern.compile(" ");
|
||||||
|
private static final byte[] EMPTY_BYTE_ARRAY = { };
|
||||||
|
|
||||||
|
// special characters from the ooo document
|
||||||
|
private static final int CHAR_ELLIPSIS_8230 = 8230;
|
||||||
|
private static final int CHAR_NDASH_8211 = 8211;
|
||||||
|
|
||||||
private static final String[] DIGIT_ENDING_FUNCTION_NAMES = {
|
private static final String[] DIGIT_ENDING_FUNCTION_NAMES = {
|
||||||
// Digits at the end of a function might be due to a left-over footnote marker.
|
// Digits at the end of a function might be due to a left-over footnote marker.
|
||||||
|
@ -86,14 +94,66 @@ final class FunctionMetadataReader {
|
||||||
String functionName = parts[1];
|
String functionName = parts[1];
|
||||||
int minParams = parseInt(parts[2]);
|
int minParams = parseInt(parts[2]);
|
||||||
int maxParams = parseInt(parts[3]);
|
int maxParams = parseInt(parts[3]);
|
||||||
// 4 returnClass
|
byte returnClassCode = parseReturnTypeCode(parts[4]);
|
||||||
// 5 parameterClasses
|
byte[] parameterClassCodes = parseOperandTypeCodes(parts[5]);
|
||||||
// 6 isVolatile
|
// 6 isVolatile
|
||||||
boolean hasNote = parts[7].length() > 0;
|
boolean hasNote = parts[7].length() > 0;
|
||||||
|
|
||||||
validateFunctionName(functionName);
|
validateFunctionName(functionName);
|
||||||
// TODO - make POI use returnClass, parameterClasses, isVolatile
|
// TODO - make POI use isVolatile
|
||||||
fdb.add(functionIndex, functionName, minParams, maxParams, hasNote);
|
fdb.add(functionIndex, functionName, minParams, maxParams,
|
||||||
|
returnClassCode, parameterClassCodes, hasNote);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static byte parseReturnTypeCode(String code) {
|
||||||
|
if(code.length() == 0) {
|
||||||
|
return Ptg.CLASS_REF; // happens for GETPIVOTDATA
|
||||||
|
}
|
||||||
|
return parseOperandTypeCode(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] parseOperandTypeCodes(String codes) {
|
||||||
|
if(codes.length() < 1) {
|
||||||
|
return EMPTY_BYTE_ARRAY; // happens for GETPIVOTDATA
|
||||||
|
}
|
||||||
|
if(isDash(codes)) {
|
||||||
|
// '-' means empty:
|
||||||
|
return EMPTY_BYTE_ARRAY;
|
||||||
|
}
|
||||||
|
String[] array = SPACE_DELIM_PATTERN.split(codes);
|
||||||
|
int nItems = array.length;
|
||||||
|
if(array[nItems-1].charAt(0) == CHAR_ELLIPSIS_8230) {
|
||||||
|
nItems --;
|
||||||
|
}
|
||||||
|
byte[] result = new byte[nItems];
|
||||||
|
for (int i = 0; i < nItems; i++) {
|
||||||
|
result[i] = parseOperandTypeCode(array[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isDash(String codes) {
|
||||||
|
if(codes.length() == 1) {
|
||||||
|
switch (codes.charAt(0)) {
|
||||||
|
case '-':
|
||||||
|
case CHAR_NDASH_8211: // this is what the ooo doc has
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte parseOperandTypeCode(String code) {
|
||||||
|
if(code.length() != 1) {
|
||||||
|
throw new RuntimeException("Bad operand type code format '" + code + "' expected single char");
|
||||||
|
}
|
||||||
|
switch(code.charAt(0)) {
|
||||||
|
case 'V': return Ptg.CLASS_VALUE;
|
||||||
|
case 'R': return Ptg.CLASS_REF;
|
||||||
|
case 'A': return Ptg.CLASS_ARRAY;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Unexpected operand type code '" + code + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
import org.apache.poi.ddf.EscherBitmapBlip;
|
import org.apache.poi.ddf.EscherBitmapBlip;
|
||||||
import org.apache.poi.ddf.EscherBlipRecord;
|
import org.apache.poi.ddf.EscherBlipRecord;
|
||||||
|
import org.apache.poi.ddf.EscherMetafileBlip;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents binary data stored in the file. Eg. A GIF, JPEG etc...
|
* Represents binary data stored in the file. Eg. A GIF, JPEG etc...
|
||||||
|
@ -69,19 +70,19 @@ public class HSSFPictureData
|
||||||
*/
|
*/
|
||||||
public String suggestFileExtension()
|
public String suggestFileExtension()
|
||||||
{
|
{
|
||||||
switch (blip.getOptions() & FORMAT_MASK)
|
switch (blip.getRecordId())
|
||||||
{
|
{
|
||||||
case MSOBI_WMF:
|
case EscherMetafileBlip.RECORD_ID_WMF:
|
||||||
return "wmf";
|
return "wmf";
|
||||||
case MSOBI_EMF:
|
case EscherMetafileBlip.RECORD_ID_EMF:
|
||||||
return "emf";
|
return "emf";
|
||||||
case MSOBI_PICT:
|
case EscherMetafileBlip.RECORD_ID_PICT:
|
||||||
return "pict";
|
return "pict";
|
||||||
case MSOBI_PNG:
|
case EscherBitmapBlip.RECORD_ID_PNG:
|
||||||
return "png";
|
return "png";
|
||||||
case MSOBI_JPEG:
|
case EscherBitmapBlip.RECORD_ID_JPEG:
|
||||||
return "jpeg";
|
return "jpeg";
|
||||||
case MSOBI_DIB:
|
case EscherBitmapBlip.RECORD_ID_DIB:
|
||||||
return "dib";
|
return "dib";
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
|
|
|
@ -1710,6 +1710,8 @@ public final class HSSFSheet {
|
||||||
|
|
||||||
HSSFCellStyle style = cell.getCellStyle();
|
HSSFCellStyle style = cell.getCellStyle();
|
||||||
HSSFFont font = wb.getFontAt(style.getFontIndex());
|
HSSFFont font = wb.getFontAt(style.getFontIndex());
|
||||||
|
//the number of spaces to indent the text in the cell
|
||||||
|
int indention = style.getIndention();
|
||||||
|
|
||||||
if (cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
|
if (cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
|
||||||
HSSFRichTextString rt = cell.getRichStringCellValue();
|
HSSFRichTextString rt = cell.getRichStringCellValue();
|
||||||
|
@ -1742,9 +1744,9 @@ public final class HSSFSheet {
|
||||||
trans.concatenate(
|
trans.concatenate(
|
||||||
AffineTransform.getScaleInstance(1, fontHeightMultiple)
|
AffineTransform.getScaleInstance(1, fontHeightMultiple)
|
||||||
);
|
);
|
||||||
width = Math.max(width, layout.getOutline(trans).getBounds().getWidth() / defaultCharWidth);
|
width = Math.max(width, layout.getOutline(trans).getBounds().getWidth() / defaultCharWidth + indention);
|
||||||
} else {
|
} else {
|
||||||
width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth);
|
width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth + indention);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1787,15 +1789,15 @@ public final class HSSFSheet {
|
||||||
trans.concatenate(
|
trans.concatenate(
|
||||||
AffineTransform.getScaleInstance(1, fontHeightMultiple)
|
AffineTransform.getScaleInstance(1, fontHeightMultiple)
|
||||||
);
|
);
|
||||||
width = Math.max(width, layout.getOutline(trans).getBounds().getWidth() / defaultCharWidth);
|
width = Math.max(width, layout.getOutline(trans).getBounds().getWidth() / defaultCharWidth + indention);
|
||||||
} else {
|
} else {
|
||||||
width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth);
|
width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth + indention);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (width != -1) {
|
if (width != -1) {
|
||||||
if (width > Short.MAX_VALUE) { //width can be bigger that Short.MAX_VALUE!
|
if (width > Short.MAX_VALUE) { //calculated width can be greater that Short.MAX_VALUE!
|
||||||
width = Short.MAX_VALUE;
|
width = Short.MAX_VALUE;
|
||||||
}
|
}
|
||||||
sheet.setColumnWidth(column, (short) (width * 256));
|
sheet.setColumnWidth(column, (short) (width * 256));
|
||||||
|
|
|
@ -168,6 +168,42 @@ public class HSSFWorkbook extends POIDocument
|
||||||
this(fs.getRoot(), fs, preserveNodes);
|
this(fs.getRoot(), fs, preserveNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normally, the Workbook will be in a POIFS Stream
|
||||||
|
* called "Workbook". However, some weird XLS generators use "WORKBOOK"
|
||||||
|
*/
|
||||||
|
private static final String[] WORKBOOK_DIR_ENTRY_NAMES = {
|
||||||
|
"Workbook", // as per BIFF8 spec
|
||||||
|
"WORKBOOK",
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private static String getWorkbookDirEntryName(DirectoryNode directory) {
|
||||||
|
|
||||||
|
String[] potentialNames = WORKBOOK_DIR_ENTRY_NAMES;
|
||||||
|
for (int i = 0; i < potentialNames.length; i++) {
|
||||||
|
String wbName = potentialNames[i];
|
||||||
|
try {
|
||||||
|
directory.getEntry(wbName);
|
||||||
|
return wbName;
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
// continue - to try other options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for previous version of file format
|
||||||
|
try {
|
||||||
|
directory.getEntry("Book");
|
||||||
|
throw new IllegalArgumentException("The supplied spreadsheet seems to be Excel 5.0/7.0 (BIFF5) format. "
|
||||||
|
+ "POI only supports BIFF8 format (from Excel versions 97/2000/XP/2003)");
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("The supplied POIFSFileSystem does not contain a BIFF8 'Workbook' entry. "
|
||||||
|
+ "Is it really an excel file?");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* given a POI POIFSFileSystem object, and a specific directory
|
* given a POI POIFSFileSystem object, and a specific directory
|
||||||
* within it, read in its Workbook and populate the high and
|
* within it, read in its Workbook and populate the high and
|
||||||
|
@ -186,6 +222,8 @@ public class HSSFWorkbook extends POIDocument
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
super(directory, fs);
|
super(directory, fs);
|
||||||
|
String workbookName = getWorkbookDirEntryName(directory);
|
||||||
|
|
||||||
this.preserveNodes = preserveNodes;
|
this.preserveNodes = preserveNodes;
|
||||||
|
|
||||||
// If we're not preserving nodes, don't track the
|
// If we're not preserving nodes, don't track the
|
||||||
|
@ -198,27 +236,8 @@ public class HSSFWorkbook extends POIDocument
|
||||||
sheets = new ArrayList(INITIAL_CAPACITY);
|
sheets = new ArrayList(INITIAL_CAPACITY);
|
||||||
names = new ArrayList(INITIAL_CAPACITY);
|
names = new ArrayList(INITIAL_CAPACITY);
|
||||||
|
|
||||||
// Normally, the Workbook will be in a POIFS Stream
|
|
||||||
// called "Workbook". However, some wierd XLS generators
|
|
||||||
// put theirs in one called "WORKBOOK"
|
|
||||||
String workbookName = "Workbook";
|
|
||||||
try {
|
|
||||||
directory.getEntry(workbookName);
|
|
||||||
// Is the default name
|
|
||||||
} catch(FileNotFoundException fe) {
|
|
||||||
// Try the upper case form
|
|
||||||
try {
|
|
||||||
workbookName = "WORKBOOK";
|
|
||||||
directory.getEntry(workbookName);
|
|
||||||
} catch(FileNotFoundException wfe) {
|
|
||||||
// Doesn't contain it in either form
|
|
||||||
throw new IllegalArgumentException("The supplied POIFSFileSystem contained neither a 'Workbook' entry, nor a 'WORKBOOK' entry. Is it really an excel file?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Grab the data from the workbook stream, however
|
// Grab the data from the workbook stream, however
|
||||||
// it happens to be spelt.
|
// it happens to be spelled.
|
||||||
InputStream stream = directory.createDocumentInputStream(workbookName);
|
InputStream stream = directory.createDocumentInputStream(workbookName);
|
||||||
|
|
||||||
EventRecordFactory factory = new EventRecordFactory();
|
EventRecordFactory factory = new EventRecordFactory();
|
||||||
|
@ -600,6 +619,8 @@ public class HSSFWorkbook extends POIDocument
|
||||||
*
|
*
|
||||||
* @param sheetname sheetname to set for the sheet.
|
* @param sheetname sheetname to set for the sheet.
|
||||||
* @return HSSFSheet representing the new sheet.
|
* @return HSSFSheet representing the new sheet.
|
||||||
|
* @throws IllegalArgumentException if there is already a sheet present with a case-insensitive
|
||||||
|
* match for the specified name.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public HSSFSheet createSheet(String sheetname)
|
public HSSFSheet createSheet(String sheetname)
|
||||||
|
@ -639,9 +660,9 @@ public class HSSFWorkbook extends POIDocument
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get sheet with the given name
|
* Get sheet with the given name (case insensitive match)
|
||||||
* @param name of the sheet
|
* @param name of the sheet
|
||||||
* @return HSSFSheet with the name provided or null if it does not exist
|
* @return HSSFSheet with the name provided or <code>null</code> if it does not exist
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public HSSFSheet getSheet(String name)
|
public HSSFSheet getSheet(String name)
|
||||||
|
@ -652,7 +673,7 @@ public class HSSFWorkbook extends POIDocument
|
||||||
{
|
{
|
||||||
String sheetname = workbook.getSheetName(k);
|
String sheetname = workbook.getSheetName(k);
|
||||||
|
|
||||||
if (sheetname.equals(name))
|
if (sheetname.equalsIgnoreCase(name))
|
||||||
{
|
{
|
||||||
retval = (HSSFSheet) sheets.get(k);
|
retval = (HSSFSheet) sheets.get(k);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +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;
|
|
||||||
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parent class of all UserModel POI XML (ooxml)
|
|
||||||
* implementations.
|
|
||||||
* Provides a similar function to {@link POIDocument},
|
|
||||||
* for the XML based classes.
|
|
||||||
*/
|
|
||||||
public abstract class POIXMLDocument {
|
|
||||||
private HXFDocument document;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new POI XML Document, wrapping up
|
|
||||||
* the underlying raw HXFDocument
|
|
||||||
*/
|
|
||||||
protected POIXMLDocument(HXFDocument document) {
|
|
||||||
this.document = document;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the underlying HXFDocument, typically
|
|
||||||
* used for unit testing
|
|
||||||
*/
|
|
||||||
public HXFDocument _getHXFDocument() {
|
|
||||||
return document;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +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;
|
|
||||||
|
|
||||||
public abstract class POIXMLTextExtractor extends POITextExtractor {
|
|
||||||
/** The POIXMLDocument that's open */
|
|
||||||
protected POIXMLDocument document;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new text extractor for the given document
|
|
||||||
*/
|
|
||||||
public POIXMLTextExtractor(POIXMLDocument document) {
|
|
||||||
super(null);
|
|
||||||
|
|
||||||
this.document = document;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,148 +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;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
import org.apache.xmlbeans.XmlException;
|
|
||||||
import org.openxml4j.exceptions.InvalidFormatException;
|
|
||||||
import org.openxml4j.exceptions.OpenXML4JException;
|
|
||||||
import org.openxml4j.opc.Package;
|
|
||||||
import org.openxml4j.opc.PackagePart;
|
|
||||||
import org.openxml4j.opc.PackageRelationshipCollection;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesSlide;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPresentation;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdList;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdListEntry;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMaster;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterIdList;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterIdListEntry;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.NotesDocument;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.PresentationDocument;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.SldDocument;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.SldMasterDocument;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Experimental class to do low level processing
|
|
||||||
* of pptx files.
|
|
||||||
*
|
|
||||||
* If you are using these low level classes, then you
|
|
||||||
* will almost certainly need to refer to the OOXML
|
|
||||||
* specifications from
|
|
||||||
* http://www.ecma-international.org/publications/standards/Ecma-376.htm
|
|
||||||
*
|
|
||||||
* WARNING - APIs expected to change rapidly
|
|
||||||
*/
|
|
||||||
public class HSLFXML extends HXFDocument {
|
|
||||||
public static final String MAIN_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml";
|
|
||||||
public static final String NOTES_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml";
|
|
||||||
public static final String SLIDE_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml";
|
|
||||||
public static final String SLIDE_LAYOUT_RELATION_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
|
|
||||||
public static final String NOTES_RELATION_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide";
|
|
||||||
|
|
||||||
private PresentationDocument presentationDoc;
|
|
||||||
|
|
||||||
public HSLFXML(Package container) throws OpenXML4JException, IOException, XmlException {
|
|
||||||
super(container, MAIN_CONTENT_TYPE);
|
|
||||||
|
|
||||||
presentationDoc =
|
|
||||||
PresentationDocument.Factory.parse(basePart.getInputStream());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the low level presentation base object
|
|
||||||
*/
|
|
||||||
public CTPresentation getPresentation() {
|
|
||||||
return presentationDoc.getPresentation();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the references from the presentation to its
|
|
||||||
* slides.
|
|
||||||
* You'll need these to figure out the slide ordering,
|
|
||||||
* and to get at the actual slides themselves
|
|
||||||
*/
|
|
||||||
public CTSlideIdList getSlideReferences() {
|
|
||||||
return getPresentation().getSldIdLst();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Returns the references from the presentation to its
|
|
||||||
* slide masters.
|
|
||||||
* You'll need these to get at the actual slide
|
|
||||||
* masters themselves
|
|
||||||
*/
|
|
||||||
public CTSlideMasterIdList getSlideMasterReferences() {
|
|
||||||
return getPresentation().getSldMasterIdLst();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the low level slide master object from
|
|
||||||
* the supplied slide master reference
|
|
||||||
*/
|
|
||||||
public CTSlideMaster getSlideMaster(CTSlideMasterIdListEntry master) throws IOException, XmlException {
|
|
||||||
PackagePart masterPart =
|
|
||||||
getRelatedPackagePart(master.getId2());
|
|
||||||
SldMasterDocument masterDoc =
|
|
||||||
SldMasterDocument.Factory.parse(masterPart.getInputStream());
|
|
||||||
return masterDoc.getSldMaster();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the low level slide object from
|
|
||||||
* the supplied slide reference
|
|
||||||
*/
|
|
||||||
public CTSlide getSlide(CTSlideIdListEntry slide) throws IOException, XmlException {
|
|
||||||
PackagePart slidePart =
|
|
||||||
getRelatedPackagePart(slide.getId2());
|
|
||||||
SldDocument slideDoc =
|
|
||||||
SldDocument.Factory.parse(slidePart.getInputStream());
|
|
||||||
return slideDoc.getSld();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the low level notes object for the given
|
|
||||||
* slide, as found from the supplied slide reference
|
|
||||||
*/
|
|
||||||
public CTNotesSlide getNotes(CTSlideIdListEntry slide) throws IOException, XmlException {
|
|
||||||
PackagePart slidePart =
|
|
||||||
getRelatedPackagePart(slide.getId2());
|
|
||||||
|
|
||||||
PackageRelationshipCollection notes;
|
|
||||||
try {
|
|
||||||
notes = slidePart.getRelationshipsByType(NOTES_RELATION_TYPE);
|
|
||||||
} catch(InvalidFormatException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(notes.size() == 0) {
|
|
||||||
// No notes for this slide
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if(notes.size() > 1) {
|
|
||||||
throw new IllegalStateException("Expecting 0 or 1 notes for a slide, but found " + notes.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
PackagePart notesPart =
|
|
||||||
getPackagePart(notes.getRelationship(0));
|
|
||||||
NotesDocument notesDoc =
|
|
||||||
NotesDocument.Factory.parse(notesPart.getInputStream());
|
|
||||||
|
|
||||||
return notesDoc.getNotes();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,139 +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.extractor;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.poi.POIXMLTextExtractor;
|
|
||||||
import org.apache.poi.hslf.HSLFXML;
|
|
||||||
import org.apache.poi.hslf.usermodel.HSLFXMLSlideShow;
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
import org.apache.xmlbeans.XmlException;
|
|
||||||
import org.openxml4j.exceptions.OpenXML4JException;
|
|
||||||
import org.openxml4j.opc.Package;
|
|
||||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
|
|
||||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
|
|
||||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesSlide;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdListEntry;
|
|
||||||
|
|
||||||
public class HXFPowerPointExtractor extends POIXMLTextExtractor {
|
|
||||||
private HSLFXMLSlideShow slideshow;
|
|
||||||
private boolean slidesByDefault = true;
|
|
||||||
private boolean notesByDefault = false;
|
|
||||||
|
|
||||||
public HXFPowerPointExtractor(Package container) throws XmlException, OpenXML4JException, IOException {
|
|
||||||
this(new HSLFXMLSlideShow(
|
|
||||||
new HSLFXML(container)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
public HXFPowerPointExtractor(HSLFXMLSlideShow slideshow) {
|
|
||||||
super(slideshow);
|
|
||||||
this.slideshow = slideshow;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
if(args.length < 1) {
|
|
||||||
System.err.println("Use:");
|
|
||||||
System.err.println(" HXFPowerPointExtractor <filename.pptx>");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
POIXMLTextExtractor extractor =
|
|
||||||
new HXFPowerPointExtractor(HXFDocument.openPackage(
|
|
||||||
new File(args[0])
|
|
||||||
));
|
|
||||||
System.out.println(extractor.getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should a call to getText() return slide text?
|
|
||||||
* Default is yes
|
|
||||||
*/
|
|
||||||
public void setSlidesByDefault(boolean slidesByDefault) {
|
|
||||||
this.slidesByDefault = slidesByDefault;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Should a call to getText() return notes text?
|
|
||||||
* Default is no
|
|
||||||
*/
|
|
||||||
public void setNotesByDefault(boolean notesByDefault) {
|
|
||||||
this.notesByDefault = notesByDefault;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the slide text, but not the notes text
|
|
||||||
*/
|
|
||||||
public String getText() {
|
|
||||||
return getText(slidesByDefault, notesByDefault);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the requested text from the file
|
|
||||||
* @param slideText Should we retrieve text from slides?
|
|
||||||
* @param notesText Should we retrieve text from notes?
|
|
||||||
*/
|
|
||||||
public String getText(boolean slideText, boolean notesText) {
|
|
||||||
StringBuffer text = new StringBuffer();
|
|
||||||
|
|
||||||
CTSlideIdListEntry[] slideRefs =
|
|
||||||
slideshow._getHSLFXML().getSlideReferences().getSldIdArray();
|
|
||||||
for (int i = 0; i < slideRefs.length; i++) {
|
|
||||||
try {
|
|
||||||
CTSlide slide =
|
|
||||||
slideshow._getHSLFXML().getSlide(slideRefs[i]);
|
|
||||||
CTNotesSlide notes =
|
|
||||||
slideshow._getHSLFXML().getNotes(slideRefs[i]);
|
|
||||||
|
|
||||||
if(slideText) {
|
|
||||||
extractText(slide.getCSld().getSpTree(), text);
|
|
||||||
}
|
|
||||||
if(notesText && notes != null) {
|
|
||||||
extractText(notes.getCSld().getSpTree(), text);
|
|
||||||
}
|
|
||||||
} catch(Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return text.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void extractText(CTGroupShape gs, StringBuffer text) {
|
|
||||||
CTShape[] shapes = gs.getSpArray();
|
|
||||||
for (int i = 0; i < shapes.length; i++) {
|
|
||||||
CTTextBody textBody =
|
|
||||||
shapes[i].getTxBody();
|
|
||||||
if(textBody != null) {
|
|
||||||
CTTextParagraph[] paras =
|
|
||||||
textBody.getPArray();
|
|
||||||
for (int j = 0; j < paras.length; j++) {
|
|
||||||
CTRegularTextRun[] textRuns =
|
|
||||||
paras[j].getRArray();
|
|
||||||
for (int k = 0; k < textRuns.length; k++) {
|
|
||||||
text.append( textRuns[k].getT() );
|
|
||||||
}
|
|
||||||
// End each paragraph with a new line
|
|
||||||
text.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +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.usermodel;
|
|
||||||
|
|
||||||
import org.apache.poi.POIXMLDocument;
|
|
||||||
import org.apache.poi.hslf.HSLFXML;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* High level representation of a ooxml slideshow.
|
|
||||||
* This is the first object most users will construct whether
|
|
||||||
* they are reading or writing a slideshow. It is also the
|
|
||||||
* top level object for creating new slides/etc.
|
|
||||||
*/
|
|
||||||
public class HSLFXMLSlideShow extends POIXMLDocument {
|
|
||||||
private org.apache.poi.hslf.HSLFXML hslfXML;
|
|
||||||
|
|
||||||
public HSLFXMLSlideShow(HSLFXML xml) {
|
|
||||||
super(xml);
|
|
||||||
this.hslfXML = xml;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HSLFXML _getHSLFXML() {
|
|
||||||
return hslfXML;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,104 +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.hssf;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.poi.hssf.model.SharedStringsTable;
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
import org.apache.xmlbeans.XmlException;
|
|
||||||
import org.openxml4j.exceptions.OpenXML4JException;
|
|
||||||
import org.openxml4j.opc.Package;
|
|
||||||
import org.openxml4j.opc.PackagePart;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheets;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Experimental class to do low level processing
|
|
||||||
* of xlsx files.
|
|
||||||
*
|
|
||||||
* If you are using these low level classes, then you
|
|
||||||
* will almost certainly need to refer to the OOXML
|
|
||||||
* specifications from
|
|
||||||
* http://www.ecma-international.org/publications/standards/Ecma-376.htm
|
|
||||||
*
|
|
||||||
* WARNING - APIs expected to change rapidly
|
|
||||||
*/
|
|
||||||
public class HSSFXML extends HXFDocument {
|
|
||||||
public static final String MAIN_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
|
|
||||||
public static final String SHEET_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
|
|
||||||
public static final String SHARED_STRINGS_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml";
|
|
||||||
public static final String SHARED_STRINGS_RELATION_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
|
|
||||||
|
|
||||||
private WorkbookDocument workbookDoc;
|
|
||||||
private SharedStringsTable sharedStrings;
|
|
||||||
|
|
||||||
public HSSFXML(Package container) throws OpenXML4JException, IOException, XmlException {
|
|
||||||
super(container, MAIN_CONTENT_TYPE);
|
|
||||||
|
|
||||||
workbookDoc =
|
|
||||||
WorkbookDocument.Factory.parse(basePart.getInputStream());
|
|
||||||
|
|
||||||
PackagePart ssPart = getSinglePartByRelationType(SHARED_STRINGS_RELATION_TYPE, basePart);
|
|
||||||
if (ssPart != null) {
|
|
||||||
sharedStrings = new SharedStringsTable(ssPart);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the low level workbook base object
|
|
||||||
*/
|
|
||||||
public CTWorkbook getWorkbook() {
|
|
||||||
return workbookDoc.getWorkbook();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Returns the references from the workbook to its
|
|
||||||
* sheets.
|
|
||||||
* You'll need these to figure out the sheet ordering,
|
|
||||||
* and to get at the actual sheets themselves
|
|
||||||
*/
|
|
||||||
public CTSheets getSheetReferences() {
|
|
||||||
return getWorkbook().getSheets();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Returns the low level (work)sheet object from
|
|
||||||
* the supplied sheet reference
|
|
||||||
*/
|
|
||||||
public CTWorksheet getSheet(CTSheet sheet) throws IOException, XmlException {
|
|
||||||
PackagePart sheetPart =
|
|
||||||
getRelatedPackagePart(sheet.getId());
|
|
||||||
WorksheetDocument sheetDoc =
|
|
||||||
WorksheetDocument.Factory.parse(sheetPart.getInputStream());
|
|
||||||
return sheetDoc.getWorksheet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the shared string at the given index
|
|
||||||
*/
|
|
||||||
public String getSharedString(int index) {
|
|
||||||
return this.sharedStrings.get(index);
|
|
||||||
}
|
|
||||||
protected SharedStringsTable _getSharedStringsTable() {
|
|
||||||
return sharedStrings;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,133 +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.hssf.extractor;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.poi.POIXMLTextExtractor;
|
|
||||||
import org.apache.poi.hssf.HSSFXML;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFXMLCell;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFXMLWorkbook;
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
import org.apache.xmlbeans.XmlException;
|
|
||||||
import org.openxml4j.exceptions.OpenXML4JException;
|
|
||||||
import org.openxml4j.opc.Package;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class to extract text from an OOXML Excel file
|
|
||||||
*/
|
|
||||||
public class HXFExcelExtractor extends POIXMLTextExtractor {
|
|
||||||
private HSSFXMLWorkbook workbook;
|
|
||||||
private boolean includeSheetNames = true;
|
|
||||||
private boolean formulasNotResults = false;
|
|
||||||
|
|
||||||
public HXFExcelExtractor(Package container) throws XmlException, OpenXML4JException, IOException {
|
|
||||||
this(new HSSFXMLWorkbook(
|
|
||||||
new HSSFXML(container)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
public HXFExcelExtractor(HSSFXMLWorkbook workbook) {
|
|
||||||
super(workbook);
|
|
||||||
this.workbook = workbook;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
if(args.length < 1) {
|
|
||||||
System.err.println("Use:");
|
|
||||||
System.err.println(" HXFExcelExtractor <filename.xlsx>");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
POIXMLTextExtractor extractor =
|
|
||||||
new HXFExcelExtractor(HXFDocument.openPackage(
|
|
||||||
new File(args[0])
|
|
||||||
));
|
|
||||||
System.out.println(extractor.getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should sheet names be included? Default is true
|
|
||||||
*/
|
|
||||||
public void setIncludeSheetNames(boolean includeSheetNames) {
|
|
||||||
this.includeSheetNames = includeSheetNames;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Should we return the formula itself, and not
|
|
||||||
* the result it produces? Default is false
|
|
||||||
*/
|
|
||||||
public void setFormulasNotResults(boolean formulasNotResults) {
|
|
||||||
this.formulasNotResults = formulasNotResults;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retreives the text contents of the file
|
|
||||||
*/
|
|
||||||
public String getText() {
|
|
||||||
StringBuffer text = new StringBuffer();
|
|
||||||
|
|
||||||
CTSheet[] sheetRefs =
|
|
||||||
workbook._getHSSFXML().getSheetReferences().getSheetArray();
|
|
||||||
for(int i=0; i<sheetRefs.length; i++) {
|
|
||||||
try {
|
|
||||||
CTWorksheet sheet =
|
|
||||||
workbook._getHSSFXML().getSheet(sheetRefs[i]);
|
|
||||||
CTRow[] rows =
|
|
||||||
sheet.getSheetData().getRowArray();
|
|
||||||
|
|
||||||
if(i > 0) {
|
|
||||||
text.append("\n");
|
|
||||||
}
|
|
||||||
if(includeSheetNames) {
|
|
||||||
text.append(sheetRefs[i].getName() + "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int j=0; j<rows.length; j++) {
|
|
||||||
CTCell[] cells = rows[j].getCArray();
|
|
||||||
for(int k=0; k<cells.length; k++) {
|
|
||||||
CTCell cell = cells[k];
|
|
||||||
if(k > 0) {
|
|
||||||
text.append("\t");
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean done = false;
|
|
||||||
|
|
||||||
// Is it a formula one?
|
|
||||||
if(cell.getF() != null) {
|
|
||||||
if(formulasNotResults) {
|
|
||||||
text.append(cell.getF().getStringValue());
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!done) {
|
|
||||||
HSSFXMLCell uCell = new HSSFXMLCell(cell, workbook);
|
|
||||||
text.append(uCell.getStringValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
text.append("\n");
|
|
||||||
}
|
|
||||||
} catch(Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return text.toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,78 +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.hssf.model;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
import org.apache.xmlbeans.XmlException;
|
|
||||||
import org.openxml4j.opc.PackagePart;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRst;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSst;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.SstDocument;
|
|
||||||
|
|
||||||
|
|
||||||
public class SharedStringsTable extends LinkedList<String> {
|
|
||||||
public static final String MAIN_SML_NS_URI = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
|
||||||
|
|
||||||
private SstDocument doc;
|
|
||||||
private PackagePart part;
|
|
||||||
|
|
||||||
public SharedStringsTable(PackagePart part) throws IOException, XmlException {
|
|
||||||
this.part = part;
|
|
||||||
doc = SstDocument.Factory.parse(
|
|
||||||
part.getInputStream()
|
|
||||||
);
|
|
||||||
read();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void read() {
|
|
||||||
CTRst[] sts = doc.getSst().getSiArray();
|
|
||||||
for (int i = 0; i < sts.length; i++) {
|
|
||||||
add(sts[i].getT());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the current shared strings table into
|
|
||||||
* the associated OOXML PackagePart
|
|
||||||
*/
|
|
||||||
public void write() throws IOException {
|
|
||||||
CTSst sst = doc.getSst();
|
|
||||||
|
|
||||||
// Remove the old list
|
|
||||||
for(int i=sst.sizeOfSiArray() - 1; i>=0; i--) {
|
|
||||||
sst.removeSi(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the new one
|
|
||||||
for(String s : this) {
|
|
||||||
sst.addNewSi().setT(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the counts
|
|
||||||
sst.setCount(this.size());
|
|
||||||
sst.setUniqueCount(this.size());
|
|
||||||
|
|
||||||
// Write out
|
|
||||||
OutputStream out = part.getOutputStream();
|
|
||||||
doc.save(out);
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +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.hssf.usermodel;
|
|
||||||
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User facing wrapper around an underlying cell object
|
|
||||||
*/
|
|
||||||
public class HSSFXMLCell {
|
|
||||||
private CTCell cell;
|
|
||||||
|
|
||||||
/** The workbook to which this cell belongs */
|
|
||||||
private final HSSFXMLWorkbook workbook;
|
|
||||||
|
|
||||||
public HSSFXMLCell(CTCell rawCell, HSSFXMLWorkbook workbook) {
|
|
||||||
this.cell = rawCell;
|
|
||||||
this.workbook = workbook;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats the cell's contents, based on its type,
|
|
||||||
* and returns it as a string.
|
|
||||||
*/
|
|
||||||
public String getStringValue() {
|
|
||||||
|
|
||||||
switch (cell.getT().intValue()) {
|
|
||||||
case STCellType.INT_S:
|
|
||||||
return this.workbook.getSharedString(Integer.valueOf(cell.getV()));
|
|
||||||
case STCellType.INT_INLINE_STR:
|
|
||||||
return cell.getV();
|
|
||||||
case STCellType.INT_N:
|
|
||||||
return cell.getV();
|
|
||||||
// TODO: support other types
|
|
||||||
default:
|
|
||||||
return "UNSUPPORTED CELL TYPE: '" + cell.getT() + "'";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return cell.getR() + " - " + getStringValue();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +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.hssf.usermodel;
|
|
||||||
|
|
||||||
import org.apache.poi.POIXMLDocument;
|
|
||||||
import org.apache.poi.hssf.HSSFXML;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* High level representation of a ooxml workbook.
|
|
||||||
* This is the first object most users will construct whether
|
|
||||||
* they are reading or writing a workbook. It is also the
|
|
||||||
* top level object for creating new sheets/etc.
|
|
||||||
*/
|
|
||||||
public class HSSFXMLWorkbook extends POIXMLDocument {
|
|
||||||
private HSSFXML hssfXML;
|
|
||||||
|
|
||||||
public HSSFXMLWorkbook(HSSFXML xml) {
|
|
||||||
super(xml);
|
|
||||||
this.hssfXML = xml;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HSSFXML _getHSSFXML() {
|
|
||||||
return hssfXML;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSharedString(int index) {
|
|
||||||
return hssfXML.getSharedString(index);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,92 +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.hwpf;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
import org.apache.xmlbeans.XmlException;
|
|
||||||
import org.openxml4j.exceptions.InvalidFormatException;
|
|
||||||
import org.openxml4j.exceptions.OpenXML4JException;
|
|
||||||
import org.openxml4j.opc.Package;
|
|
||||||
import org.openxml4j.opc.PackagePart;
|
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
|
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1;
|
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles;
|
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.DocumentDocument;
|
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.StylesDocument;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Experimental class to do low level processing
|
|
||||||
* of docx files.
|
|
||||||
*
|
|
||||||
* If you are using these low level classes, then you
|
|
||||||
* will almost certainly need to refer to the OOXML
|
|
||||||
* specifications from
|
|
||||||
* http://www.ecma-international.org/publications/standards/Ecma-376.htm
|
|
||||||
*
|
|
||||||
* WARNING - APIs expected to change rapidly
|
|
||||||
*/
|
|
||||||
public class HWPFXML extends HXFDocument {
|
|
||||||
public static final String MAIN_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml";
|
|
||||||
public static final String FOOTER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml";
|
|
||||||
public static final String HEADER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml";
|
|
||||||
public static final String STYLES_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml";
|
|
||||||
public static final String STYLES_RELATION_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
|
|
||||||
|
|
||||||
private DocumentDocument wordDoc;
|
|
||||||
|
|
||||||
public HWPFXML(Package container) throws OpenXML4JException, IOException, XmlException {
|
|
||||||
super(container, MAIN_CONTENT_TYPE);
|
|
||||||
|
|
||||||
wordDoc =
|
|
||||||
DocumentDocument.Factory.parse(basePart.getInputStream());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the low level document base object
|
|
||||||
*/
|
|
||||||
public CTDocument1 getDocument() {
|
|
||||||
return wordDoc.getDocument();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the low level body of the document
|
|
||||||
*/
|
|
||||||
public CTBody getDocumentBody() {
|
|
||||||
return getDocument().getBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the styles object used
|
|
||||||
*/
|
|
||||||
public CTStyles getStyle() throws XmlException, IOException {
|
|
||||||
PackagePart[] parts;
|
|
||||||
try {
|
|
||||||
parts = getRelatedByType(STYLES_RELATION_TYPE);
|
|
||||||
} catch(InvalidFormatException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
if(parts.length != 1) {
|
|
||||||
throw new IllegalStateException("Expecting one Styles document part, but found " + parts.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
StylesDocument sd =
|
|
||||||
StylesDocument.Factory.parse(parts[0].getInputStream());
|
|
||||||
return sd.getStyles();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,87 +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.hwpf.extractor;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.poi.POIXMLTextExtractor;
|
|
||||||
import org.apache.poi.hwpf.HWPFXML;
|
|
||||||
import org.apache.poi.hwpf.usermodel.HWPFXMLDocument;
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
import org.apache.xmlbeans.XmlException;
|
|
||||||
import org.openxml4j.exceptions.OpenXML4JException;
|
|
||||||
import org.openxml4j.opc.Package;
|
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
|
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
|
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
|
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class to extract text from an OOXML Word file
|
|
||||||
*/
|
|
||||||
public class HXFWordExtractor extends POIXMLTextExtractor {
|
|
||||||
private HWPFXMLDocument document;
|
|
||||||
|
|
||||||
public HXFWordExtractor(Package container) throws XmlException, OpenXML4JException, IOException {
|
|
||||||
this(new HWPFXMLDocument(
|
|
||||||
new HWPFXML(container)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
public HXFWordExtractor(HWPFXMLDocument document) {
|
|
||||||
super(document);
|
|
||||||
this.document = document;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
if(args.length < 1) {
|
|
||||||
System.err.println("Use:");
|
|
||||||
System.err.println(" HXFWordExtractor <filename.xlsx>");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
POIXMLTextExtractor extractor =
|
|
||||||
new HXFWordExtractor(HXFDocument.openPackage(
|
|
||||||
new File(args[0])
|
|
||||||
));
|
|
||||||
System.out.println(extractor.getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getText() {
|
|
||||||
CTBody body = document._getHWPFXML().getDocumentBody();
|
|
||||||
StringBuffer text = new StringBuffer();
|
|
||||||
|
|
||||||
// Loop over paragraphs
|
|
||||||
CTP[] ps = body.getPArray();
|
|
||||||
for (int i = 0; i < ps.length; i++) {
|
|
||||||
// Loop over ranges
|
|
||||||
CTR[] rs = ps[i].getRArray();
|
|
||||||
for (int j = 0; j < rs.length; j++) {
|
|
||||||
// Loop over text runs
|
|
||||||
CTText[] texts = rs[j].getTArray();
|
|
||||||
for (int k = 0; k < texts.length; k++) {
|
|
||||||
text.append(
|
|
||||||
texts[k].getStringValue()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// New line after each paragraph.
|
|
||||||
text.append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return text.toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +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.hwpf.usermodel;
|
|
||||||
|
|
||||||
import org.apache.poi.POIXMLDocument;
|
|
||||||
import org.apache.poi.hwpf.HWPFXML;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* High level representation of a ooxml text document.
|
|
||||||
*/
|
|
||||||
public class HWPFXMLDocument extends POIXMLDocument {
|
|
||||||
private HWPFXML hwpfXML;
|
|
||||||
|
|
||||||
public HWPFXMLDocument(HWPFXML xml) {
|
|
||||||
super(xml);
|
|
||||||
this.hwpfXML = xml;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HWPFXML _getHWPFXML() {
|
|
||||||
return hwpfXML;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,272 +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.hxf;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.PushbackInputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.apache.poi.POIXMLDocument;
|
|
||||||
import org.apache.poi.poifs.common.POIFSConstants;
|
|
||||||
import org.apache.poi.poifs.storage.HeaderBlockConstants;
|
|
||||||
import org.apache.poi.util.IOUtils;
|
|
||||||
import org.apache.poi.util.LongField;
|
|
||||||
import org.apache.xmlbeans.XmlException;
|
|
||||||
import org.dom4j.Document;
|
|
||||||
import org.dom4j.DocumentException;
|
|
||||||
import org.dom4j.io.SAXReader;
|
|
||||||
import org.openxml4j.exceptions.InvalidFormatException;
|
|
||||||
import org.openxml4j.exceptions.OpenXML4JException;
|
|
||||||
import org.openxml4j.opc.Package;
|
|
||||||
import org.openxml4j.opc.PackageAccess;
|
|
||||||
import org.openxml4j.opc.PackagePart;
|
|
||||||
import org.openxml4j.opc.PackagePartName;
|
|
||||||
import org.openxml4j.opc.PackageRelationship;
|
|
||||||
import org.openxml4j.opc.PackageRelationshipCollection;
|
|
||||||
import org.openxml4j.opc.PackagingURIHelper;
|
|
||||||
import org.openxml4j.opc.internal.PackagePropertiesPart;
|
|
||||||
import org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.CTProperties;
|
|
||||||
import org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parent class of the low level interface to
|
|
||||||
* all POI XML (OOXML) implementations.
|
|
||||||
* Normal users should probably deal with things that
|
|
||||||
* extends {@link POIXMLDocument}, unless they really
|
|
||||||
* do need to get low level access to the files.
|
|
||||||
*
|
|
||||||
* If you are using these low level classes, then you
|
|
||||||
* will almost certainly need to refer to the OOXML
|
|
||||||
* specifications from
|
|
||||||
* http://www.ecma-international.org/publications/standards/Ecma-376.htm
|
|
||||||
*
|
|
||||||
* WARNING - APIs expected to change rapidly
|
|
||||||
*/
|
|
||||||
public abstract class HXFDocument {
|
|
||||||
public static final String CORE_PROPERTIES_REL_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
|
|
||||||
public static final String EXTENDED_PROPERTIES_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File package/container.
|
|
||||||
*/
|
|
||||||
protected Package container;
|
|
||||||
/**
|
|
||||||
* The Package Part for our base document
|
|
||||||
*/
|
|
||||||
protected PackagePart basePart;
|
|
||||||
/**
|
|
||||||
* The base document of this instance, eg Workbook for
|
|
||||||
* xslsx
|
|
||||||
*/
|
|
||||||
protected Document baseDocument;
|
|
||||||
|
|
||||||
protected HXFDocument(Package container, String baseContentType) throws OpenXML4JException {
|
|
||||||
this.container = container;
|
|
||||||
|
|
||||||
// Find the base document
|
|
||||||
basePart = getSinglePartByType(baseContentType);
|
|
||||||
|
|
||||||
// And load it up
|
|
||||||
try {
|
|
||||||
SAXReader reader = new SAXReader();
|
|
||||||
baseDocument = reader.read(basePart.getInputStream());
|
|
||||||
} catch (DocumentException e) {
|
|
||||||
throw new OpenXML4JException(e.getMessage());
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
throw new OpenXML4JException(ioe.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks that the supplied InputStream (which MUST
|
|
||||||
* support mark and reset, or be a PushbackInputStream)
|
|
||||||
* has a OOXML (zip) header at the start of it.
|
|
||||||
* If your InputStream does not support mark / reset,
|
|
||||||
* then wrap it in a PushBackInputStream, then be
|
|
||||||
* sure to always use that, and not the original!
|
|
||||||
* @param inp An InputStream which supports either mark/reset, or is a PushbackInputStream
|
|
||||||
*/
|
|
||||||
public static boolean hasOOXMLHeader(InputStream inp) throws IOException {
|
|
||||||
// We want to peek at the first 4 bytes
|
|
||||||
inp.mark(4);
|
|
||||||
|
|
||||||
byte[] header = new byte[4];
|
|
||||||
IOUtils.readFully(inp, header);
|
|
||||||
|
|
||||||
// Wind back those 4 bytes
|
|
||||||
if(inp instanceof PushbackInputStream) {
|
|
||||||
PushbackInputStream pin = (PushbackInputStream)inp;
|
|
||||||
pin.unread(header);
|
|
||||||
} else {
|
|
||||||
inp.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Did it match the ooxml zip signature?
|
|
||||||
return (
|
|
||||||
header[0] == POIFSConstants.OOXML_FILE_HEADER[0] &&
|
|
||||||
header[1] == POIFSConstants.OOXML_FILE_HEADER[1] &&
|
|
||||||
header[2] == POIFSConstants.OOXML_FILE_HEADER[2] &&
|
|
||||||
header[3] == POIFSConstants.OOXML_FILE_HEADER[3]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the (single) PackagePart with the supplied
|
|
||||||
* content type.
|
|
||||||
* @param contentType The content type to search for
|
|
||||||
* @throws IllegalArgumentException If we don't find a single part of that type
|
|
||||||
*/
|
|
||||||
private PackagePart getSinglePartByType(String contentType) throws IllegalArgumentException {
|
|
||||||
ArrayList<PackagePart> parts =
|
|
||||||
container.getPartsByContentType(contentType);
|
|
||||||
if(parts.size() != 1) {
|
|
||||||
throw new IllegalArgumentException("Expecting one entry with content type of " + contentType + ", but found " + parts.size());
|
|
||||||
}
|
|
||||||
return parts.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the (single) PackagePart which is defined as
|
|
||||||
* the supplied relation content type of the specified part,
|
|
||||||
* or null if none found.
|
|
||||||
* @param relationType The relation content type to search for
|
|
||||||
* @throws IllegalArgumentException If we find more than one part of that type
|
|
||||||
* TODO: this sucks! Make Package and PackagePart implement common intf that defines getRelationshipsByType & friends
|
|
||||||
*/
|
|
||||||
protected PackagePart getSinglePartByRelationType(String relationType, PackagePart part) throws IllegalArgumentException, OpenXML4JException {
|
|
||||||
PackageRelationshipCollection rels =
|
|
||||||
part.getRelationshipsByType(relationType);
|
|
||||||
if(rels.size() == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if(rels.size() > 1) {
|
|
||||||
throw new IllegalArgumentException("Found " + rels.size() + " relations for the type " + relationType + ", should only ever be one!");
|
|
||||||
}
|
|
||||||
PackageRelationship rel = rels.getRelationship(0);
|
|
||||||
return getPackagePart(rel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the (single) PackagePart which is defined as
|
|
||||||
* the supplied relation content type of the base
|
|
||||||
* container, or null if none found.
|
|
||||||
* @param relationType The relation content type to search for
|
|
||||||
* @throws IllegalArgumentException If we find more than one part of that type
|
|
||||||
*/
|
|
||||||
protected PackagePart getSinglePartByRelationType(String relationType) throws IllegalArgumentException, OpenXML4JException {
|
|
||||||
PackageRelationshipCollection rels =
|
|
||||||
container.getRelationshipsByType(relationType);
|
|
||||||
if(rels.size() == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if(rels.size() > 1) {
|
|
||||||
throw new IllegalArgumentException("Found " + rels.size() + " relations for the type " + relationType + ", should only ever be one!");
|
|
||||||
}
|
|
||||||
PackageRelationship rel = rels.getRelationship(0);
|
|
||||||
return getPackagePart(rel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the PackagePart for the given relation
|
|
||||||
* id. This will normally come from a r:id attribute
|
|
||||||
* on part of the base document.
|
|
||||||
* @param partId The r:id pointing to the other PackagePart
|
|
||||||
*/
|
|
||||||
protected PackagePart getRelatedPackagePart(String partId) {
|
|
||||||
PackageRelationship rel =
|
|
||||||
basePart.getRelationship(partId);
|
|
||||||
return getPackagePart(rel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the PackagePart for the given Relationship
|
|
||||||
* object. Normally you'll want to go via a content type
|
|
||||||
* or r:id to get one of those.
|
|
||||||
*/
|
|
||||||
protected PackagePart getPackagePart(PackageRelationship rel) {
|
|
||||||
PackagePartName relName;
|
|
||||||
try {
|
|
||||||
relName = PackagingURIHelper.createPartName(rel.getTargetURI());
|
|
||||||
} catch(InvalidFormatException e) {
|
|
||||||
throw new InternalError(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
PackagePart part = container.getPart(relName);
|
|
||||||
if(part == null) {
|
|
||||||
throw new IllegalArgumentException("No part found for rel " + rel);
|
|
||||||
}
|
|
||||||
return part;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves all the PackageParts which are defined as
|
|
||||||
* relationships of the base document with the
|
|
||||||
* specified content type.
|
|
||||||
*/
|
|
||||||
protected PackagePart[] getRelatedByType(String contentType) throws InvalidFormatException {
|
|
||||||
PackageRelationshipCollection partsC =
|
|
||||||
basePart.getRelationshipsByType(contentType);
|
|
||||||
|
|
||||||
PackagePart[] parts = new PackagePart[partsC.size()];
|
|
||||||
int count = 0;
|
|
||||||
for (PackageRelationship rel : partsC) {
|
|
||||||
parts[count] = getPackagePart(rel);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
return parts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the package container.
|
|
||||||
* @return The package associated to this document.
|
|
||||||
*/
|
|
||||||
public Package getPackage() {
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the core document properties (core ooxml properties).
|
|
||||||
*/
|
|
||||||
public PackagePropertiesPart getCoreProperties() throws OpenXML4JException, XmlException, IOException {
|
|
||||||
PackagePart propsPart = getSinglePartByRelationType(CORE_PROPERTIES_REL_TYPE);
|
|
||||||
if(propsPart == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (PackagePropertiesPart)propsPart;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the extended document properties (extended ooxml properties)
|
|
||||||
*/
|
|
||||||
public CTProperties getExtendedProperties() throws OpenXML4JException, XmlException, IOException {
|
|
||||||
PackagePart propsPart = getSinglePartByRelationType(EXTENDED_PROPERTIES_REL_TYPE);
|
|
||||||
|
|
||||||
PropertiesDocument props = PropertiesDocument.Factory.parse(
|
|
||||||
propsPart.getInputStream());
|
|
||||||
return props.getProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an opened OOXML Package for the supplied File
|
|
||||||
* @param f File to open
|
|
||||||
*/
|
|
||||||
public static Package openPackage(File f) throws InvalidFormatException {
|
|
||||||
return Package.open(f.toString(), PackageAccess.READ_WRITE);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,133 +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.hxf.dev;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.openxml4j.opc.Package;
|
|
||||||
import org.openxml4j.opc.PackageAccess;
|
|
||||||
import org.openxml4j.opc.PackagePart;
|
|
||||||
import org.openxml4j.opc.PackageRelationship;
|
|
||||||
import org.openxml4j.opc.PackageRelationshipCollection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints out the contents of a HXF (ooxml) container.
|
|
||||||
* Useful for seeing what parts are defined, and how
|
|
||||||
* they're all related to each other.
|
|
||||||
*/
|
|
||||||
public class HXFLister {
|
|
||||||
private Package container;
|
|
||||||
private PrintStream disp;
|
|
||||||
|
|
||||||
public HXFLister(Package container) {
|
|
||||||
this(container, System.out);
|
|
||||||
}
|
|
||||||
public HXFLister(Package container, PrintStream disp) {
|
|
||||||
this.container = container;
|
|
||||||
this.disp = disp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Figures out how big a given PackagePart is.
|
|
||||||
*/
|
|
||||||
public static long getSize(PackagePart part) throws IOException {
|
|
||||||
InputStream in = part.getInputStream();
|
|
||||||
byte[] b = new byte[8192];
|
|
||||||
long size = 0;
|
|
||||||
int read = 0;
|
|
||||||
|
|
||||||
while(read > -1) {
|
|
||||||
read = in.read(b);
|
|
||||||
if(read > 0) {
|
|
||||||
size += read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays information on all the different
|
|
||||||
* parts of the OOXML file container.
|
|
||||||
*/
|
|
||||||
public void displayParts() throws Exception {
|
|
||||||
ArrayList<PackagePart> parts = container.getParts();
|
|
||||||
for (PackagePart part : parts) {
|
|
||||||
disp.println(part.getPartName());
|
|
||||||
disp.println("\t" + part.getContentType());
|
|
||||||
|
|
||||||
if(! part.getPartName().toString().equals("/docProps/core.xml")) {
|
|
||||||
disp.println("\t" + getSize(part) + " bytes");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(! part.isRelationshipPart()) {
|
|
||||||
disp.println("\t" + part.getRelationships().size() + " relations");
|
|
||||||
for(PackageRelationship rel : part.getRelationships()) {
|
|
||||||
displayRelation(rel, "\t ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Displays information on all the different
|
|
||||||
* relationships between different parts
|
|
||||||
* of the OOXML file container.
|
|
||||||
*/
|
|
||||||
public void displayRelations() throws Exception {
|
|
||||||
PackageRelationshipCollection rels =
|
|
||||||
container.getRelationships();
|
|
||||||
for (PackageRelationship rel : rels) {
|
|
||||||
displayRelation(rel, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void displayRelation(PackageRelationship rel, String indent) {
|
|
||||||
disp.println(indent+"Relationship:");
|
|
||||||
disp.println(indent+"\tFrom: "+ rel.getSourceURI());
|
|
||||||
disp.println(indent+"\tTo: " + rel.getTargetURI());
|
|
||||||
disp.println(indent+"\tID: " + rel.getId());
|
|
||||||
disp.println(indent+"\tMode: " + rel.getTargetMode());
|
|
||||||
disp.println(indent+"\tType: " + rel.getRelationshipType());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
if(args.length == 0) {
|
|
||||||
System.err.println("Use:");
|
|
||||||
System.err.println("\tjava HXFLister <filename>");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
File f = new File(args[0]);
|
|
||||||
if(! f.exists()) {
|
|
||||||
System.err.println("Error, file not found!");
|
|
||||||
System.err.println("\t" + f.toString());
|
|
||||||
System.exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
HXFLister lister = new HXFLister(
|
|
||||||
Package.open(f.toString(), PackageAccess.READ)
|
|
||||||
);
|
|
||||||
|
|
||||||
lister.disp.println(f.toString() + "\n");
|
|
||||||
lister.displayParts();
|
|
||||||
lister.disp.println();
|
|
||||||
lister.displayRelations();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,127 +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;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
import org.openxml4j.opc.Package;
|
|
||||||
import org.openxml4j.opc.PackagePart;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdListEntry;
|
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterIdListEntry;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
public class TestHSLFXML extends TestCase {
|
|
||||||
private File sampleFile;
|
|
||||||
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
sampleFile = new File(
|
|
||||||
System.getProperty("HSLF.testdata.path") +
|
|
||||||
File.separator + "sample.pptx"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testContainsMainContentType() throws Exception {
|
|
||||||
Package pack = HXFDocument.openPackage(sampleFile);
|
|
||||||
|
|
||||||
boolean found = false;
|
|
||||||
for(PackagePart part : pack.getParts()) {
|
|
||||||
if(part.getContentType().equals(HSLFXML.MAIN_CONTENT_TYPE)) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
System.out.println(part);
|
|
||||||
}
|
|
||||||
assertTrue(found);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testOpen() throws Exception {
|
|
||||||
HXFDocument.openPackage(sampleFile);
|
|
||||||
|
|
||||||
HSLFXML xml;
|
|
||||||
|
|
||||||
// With the finalised uri, should be fine
|
|
||||||
xml = new HSLFXML(
|
|
||||||
HXFDocument.openPackage(sampleFile)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check the core
|
|
||||||
assertNotNull(xml.getPresentation());
|
|
||||||
|
|
||||||
// Check it has some slides
|
|
||||||
assertTrue(
|
|
||||||
xml.getSlideReferences().sizeOfSldIdArray() > 0
|
|
||||||
);
|
|
||||||
assertTrue(
|
|
||||||
xml.getSlideMasterReferences().sizeOfSldMasterIdArray() > 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testSlideBasics() throws Exception {
|
|
||||||
HSLFXML xml = new HSLFXML(
|
|
||||||
HXFDocument.openPackage(sampleFile)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Should have 1 master
|
|
||||||
assertEquals(1, xml.getSlideMasterReferences().sizeOfSldMasterIdArray());
|
|
||||||
assertEquals(1, xml.getSlideMasterReferences().getSldMasterIdArray().length);
|
|
||||||
|
|
||||||
// Should have three sheets
|
|
||||||
assertEquals(2, xml.getSlideReferences().sizeOfSldIdArray());
|
|
||||||
assertEquals(2, xml.getSlideReferences().getSldIdArray().length);
|
|
||||||
|
|
||||||
// Check they're as expected
|
|
||||||
CTSlideIdListEntry[] slides = xml.getSlideReferences().getSldIdArray();
|
|
||||||
assertEquals(256, slides[0].getId());
|
|
||||||
assertEquals(257, slides[1].getId());
|
|
||||||
assertEquals("rId2", slides[0].getId2());
|
|
||||||
assertEquals("rId3", slides[1].getId2());
|
|
||||||
|
|
||||||
// Now get those objects
|
|
||||||
assertNotNull(xml.getSlide(slides[0]));
|
|
||||||
assertNotNull(xml.getSlide(slides[1]));
|
|
||||||
|
|
||||||
// And check they have notes as expected
|
|
||||||
assertNotNull(xml.getNotes(slides[0]));
|
|
||||||
assertNotNull(xml.getNotes(slides[1]));
|
|
||||||
|
|
||||||
// And again for the master
|
|
||||||
CTSlideMasterIdListEntry[] masters =
|
|
||||||
xml.getSlideMasterReferences().getSldMasterIdArray();
|
|
||||||
assertEquals(2147483648l, masters[0].getId());
|
|
||||||
assertEquals("rId1", masters[0].getId2());
|
|
||||||
assertNotNull(xml.getSlideMaster(masters[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testMetadataBasics() throws Exception {
|
|
||||||
HSLFXML xml = new HSLFXML(
|
|
||||||
HXFDocument.openPackage(sampleFile)
|
|
||||||
);
|
|
||||||
|
|
||||||
assertNotNull(xml.getCoreProperties());
|
|
||||||
assertNotNull(xml.getExtendedProperties());
|
|
||||||
|
|
||||||
assertEquals("Microsoft Office PowerPoint", xml.getExtendedProperties().getApplication());
|
|
||||||
assertEquals(0, xml.getExtendedProperties().getCharacters());
|
|
||||||
assertEquals(0, xml.getExtendedProperties().getLines());
|
|
||||||
|
|
||||||
assertEquals(null, xml.getCoreProperties().getTitleProperty().getValue());
|
|
||||||
assertEquals(null, xml.getCoreProperties().getSubjectProperty().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,109 +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.extractor;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.apache.poi.hslf.HSLFXML;
|
|
||||||
import org.apache.poi.hslf.usermodel.HSLFXMLSlideShow;
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for HXFPowerPointExtractor
|
|
||||||
*/
|
|
||||||
public class TestHXFPowerPointExtractor extends TestCase {
|
|
||||||
/**
|
|
||||||
* A simple file
|
|
||||||
*/
|
|
||||||
private HSLFXML xmlA;
|
|
||||||
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
File fileA = new File(
|
|
||||||
System.getProperty("HSLF.testdata.path") +
|
|
||||||
File.separator + "sample.pptx"
|
|
||||||
);
|
|
||||||
|
|
||||||
xmlA = new HSLFXML(HXFDocument.openPackage(fileA));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get text out of the simple file
|
|
||||||
*/
|
|
||||||
public void testGetSimpleText() throws Exception {
|
|
||||||
new HXFPowerPointExtractor(xmlA.getPackage());
|
|
||||||
new HXFPowerPointExtractor(new HSLFXMLSlideShow(xmlA));
|
|
||||||
|
|
||||||
HXFPowerPointExtractor extractor =
|
|
||||||
new HXFPowerPointExtractor(xmlA.getPackage());
|
|
||||||
extractor.getText();
|
|
||||||
|
|
||||||
String text = extractor.getText();
|
|
||||||
assertTrue(text.length() > 0);
|
|
||||||
|
|
||||||
// Check Basics
|
|
||||||
assertTrue(text.startsWith("Lorem ipsum dolor sit amet\n"));
|
|
||||||
assertTrue(text.endsWith("amet\n\n"));
|
|
||||||
|
|
||||||
// Just slides, no notes
|
|
||||||
text = extractor.getText(true, false);
|
|
||||||
assertEquals(
|
|
||||||
"Lorem ipsum dolor sit amet\n" +
|
|
||||||
"Nunc at risus vel erat tempus posuere. Aenean non ante.\n" +
|
|
||||||
"\n" +
|
|
||||||
"Lorem ipsum dolor sit amet\n" +
|
|
||||||
"Lorem\n" +
|
|
||||||
"ipsum\n" +
|
|
||||||
"dolor\n" +
|
|
||||||
"sit\n" +
|
|
||||||
"amet\n" +
|
|
||||||
"\n", text
|
|
||||||
);
|
|
||||||
|
|
||||||
// Just notes, no slides
|
|
||||||
text = extractor.getText(false, true);
|
|
||||||
assertEquals(
|
|
||||||
"\n\n\n\n", text
|
|
||||||
);
|
|
||||||
|
|
||||||
// Both
|
|
||||||
text = extractor.getText(true, true);
|
|
||||||
assertEquals(
|
|
||||||
"Lorem ipsum dolor sit amet\n" +
|
|
||||||
"Nunc at risus vel erat tempus posuere. Aenean non ante.\n" +
|
|
||||||
"\n\n\n" +
|
|
||||||
"Lorem ipsum dolor sit amet\n" +
|
|
||||||
"Lorem\n" +
|
|
||||||
"ipsum\n" +
|
|
||||||
"dolor\n" +
|
|
||||||
"sit\n" +
|
|
||||||
"amet\n" +
|
|
||||||
"\n\n\n", text
|
|
||||||
);
|
|
||||||
|
|
||||||
// Via set defaults
|
|
||||||
extractor.setSlidesByDefault(false);
|
|
||||||
extractor.setNotesByDefault(true);
|
|
||||||
text = extractor.getText();
|
|
||||||
assertEquals(
|
|
||||||
"\n\n\n\n", text
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,160 +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.hssf;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.apache.poi.hssf.model.SharedStringsTable;
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
import org.openxml4j.opc.Package;
|
|
||||||
import org.openxml4j.opc.PackagePart;
|
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
public class TestHSSFXML extends TestCase {
|
|
||||||
/**
|
|
||||||
* Uses the old style schemas.microsoft.com schema uri
|
|
||||||
*/
|
|
||||||
private File sampleFileBeta;
|
|
||||||
/**
|
|
||||||
* Uses the new style schemas.openxmlformats.org schema uri
|
|
||||||
*/
|
|
||||||
private File sampleFile;
|
|
||||||
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
sampleFile = new File(
|
|
||||||
System.getProperty("HSSF.testdata.path") +
|
|
||||||
File.separator + "sample.xlsx"
|
|
||||||
);
|
|
||||||
sampleFileBeta = new File(
|
|
||||||
System.getProperty("HSSF.testdata.path") +
|
|
||||||
File.separator + "sample-beta.xlsx"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testContainsMainContentType() throws Exception {
|
|
||||||
Package pack = HXFDocument.openPackage(sampleFile);
|
|
||||||
|
|
||||||
boolean found = false;
|
|
||||||
for(PackagePart part : pack.getParts()) {
|
|
||||||
if(part.getContentType().equals(HSSFXML.MAIN_CONTENT_TYPE)) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
System.out.println(part);
|
|
||||||
}
|
|
||||||
assertTrue(found);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testOpen() throws Exception {
|
|
||||||
HXFDocument.openPackage(sampleFile);
|
|
||||||
HXFDocument.openPackage(sampleFileBeta);
|
|
||||||
|
|
||||||
HSSFXML xml;
|
|
||||||
|
|
||||||
// With an old-style uri, as found in a file produced
|
|
||||||
// with the office 2007 beta, will fail, as we don't
|
|
||||||
// translate things
|
|
||||||
try {
|
|
||||||
xml = new HSSFXML(
|
|
||||||
HXFDocument.openPackage(sampleFileBeta)
|
|
||||||
);
|
|
||||||
fail();
|
|
||||||
} catch(Exception e) {}
|
|
||||||
|
|
||||||
// With the finalised uri, should be fine
|
|
||||||
xml = new HSSFXML(
|
|
||||||
HXFDocument.openPackage(sampleFile)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check it has a workbook
|
|
||||||
assertNotNull(xml.getWorkbook());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testSheetBasics() throws Exception {
|
|
||||||
HSSFXML xml = new HSSFXML(
|
|
||||||
HXFDocument.openPackage(sampleFile)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Should have three sheets
|
|
||||||
assertEquals(3, xml.getSheetReferences().sizeOfSheetArray());
|
|
||||||
assertEquals(3, xml.getSheetReferences().getSheetArray().length);
|
|
||||||
|
|
||||||
// Check they're as expected
|
|
||||||
CTSheet[] sheets = xml.getSheetReferences().getSheetArray();
|
|
||||||
assertEquals("Sheet1", sheets[0].getName());
|
|
||||||
assertEquals("Sheet2", sheets[1].getName());
|
|
||||||
assertEquals("Sheet3", sheets[2].getName());
|
|
||||||
assertEquals("rId1", sheets[0].getId());
|
|
||||||
assertEquals("rId2", sheets[1].getId());
|
|
||||||
assertEquals("rId3", sheets[2].getId());
|
|
||||||
|
|
||||||
// Now get those objects
|
|
||||||
assertNotNull(xml.getSheet(sheets[0]));
|
|
||||||
assertNotNull(xml.getSheet(sheets[1]));
|
|
||||||
assertNotNull(xml.getSheet(sheets[2]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testMetadataBasics() throws Exception {
|
|
||||||
HSSFXML xml = new HSSFXML(
|
|
||||||
HXFDocument.openPackage(sampleFile)
|
|
||||||
);
|
|
||||||
assertNotNull(xml.getCoreProperties());
|
|
||||||
assertNotNull(xml.getExtendedProperties());
|
|
||||||
|
|
||||||
assertEquals("Microsoft Excel", xml.getExtendedProperties().getApplication());
|
|
||||||
assertEquals(0, xml.getExtendedProperties().getCharacters());
|
|
||||||
assertEquals(0, xml.getExtendedProperties().getLines());
|
|
||||||
|
|
||||||
assertEquals(null, xml.getCoreProperties().getTitleProperty().getValue());
|
|
||||||
assertEquals(null, xml.getCoreProperties().getSubjectProperty().getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testSharedStringBasics() throws Exception {
|
|
||||||
HSSFXML xml = new HSSFXML(
|
|
||||||
HXFDocument.openPackage(sampleFile)
|
|
||||||
);
|
|
||||||
assertNotNull(xml._getSharedStringsTable());
|
|
||||||
|
|
||||||
SharedStringsTable sst = xml._getSharedStringsTable();
|
|
||||||
assertEquals(10, sst.size());
|
|
||||||
|
|
||||||
assertEquals("Lorem", sst.get(0));
|
|
||||||
for(int i=0; i<sst.size(); i++) {
|
|
||||||
assertEquals(sst.get(i), xml.getSharedString(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a few more, then save and reload, checking
|
|
||||||
// changes have been kept
|
|
||||||
sst.add("Foo");
|
|
||||||
sst.add("Bar");
|
|
||||||
sst.set(0, "LoremLorem");
|
|
||||||
|
|
||||||
sst.write();
|
|
||||||
|
|
||||||
xml = new HSSFXML(xml.getPackage());
|
|
||||||
sst = xml._getSharedStringsTable();
|
|
||||||
assertEquals(12, sst.size());
|
|
||||||
|
|
||||||
assertEquals("LoremLorem", sst.get(0));
|
|
||||||
for(int i=0; i<sst.size(); i++) {
|
|
||||||
assertEquals(sst.get(i), xml.getSharedString(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,196 +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.hssf.extractor;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
import org.apache.poi.POITextExtractor;
|
|
||||||
import org.apache.poi.hssf.HSSFXML;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFXMLWorkbook;
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for HXFExcelExtractor
|
|
||||||
*/
|
|
||||||
public class TestHXFExcelExtractor extends TestCase {
|
|
||||||
/**
|
|
||||||
* A very simple file
|
|
||||||
*/
|
|
||||||
private HSSFXML xmlA;
|
|
||||||
/**
|
|
||||||
* A fairly complex file
|
|
||||||
*/
|
|
||||||
private HSSFXML xmlB;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A fairly simple file - ooxml
|
|
||||||
*/
|
|
||||||
private HSSFXML simpleXLSX;
|
|
||||||
/**
|
|
||||||
* A fairly simple file - ole2
|
|
||||||
*/
|
|
||||||
private HSSFWorkbook simpleXLS;
|
|
||||||
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
File fileA = new File(
|
|
||||||
System.getProperty("HSSF.testdata.path") +
|
|
||||||
File.separator + "sample.xlsx"
|
|
||||||
);
|
|
||||||
File fileB = new File(
|
|
||||||
System.getProperty("HSSF.testdata.path") +
|
|
||||||
File.separator + "AverageTaxRates.xlsx"
|
|
||||||
);
|
|
||||||
|
|
||||||
File fileSOOXML = new File(
|
|
||||||
System.getProperty("HSSF.testdata.path") +
|
|
||||||
File.separator + "SampleSS.xlsx"
|
|
||||||
);
|
|
||||||
File fileSOLE2 = new File(
|
|
||||||
System.getProperty("HSSF.testdata.path") +
|
|
||||||
File.separator + "SampleSS.xls"
|
|
||||||
);
|
|
||||||
|
|
||||||
xmlA = new HSSFXML(HXFDocument.openPackage(fileA));
|
|
||||||
xmlB = new HSSFXML(HXFDocument.openPackage(fileB));
|
|
||||||
|
|
||||||
simpleXLSX = new HSSFXML(HXFDocument.openPackage(fileSOOXML));
|
|
||||||
simpleXLS = new HSSFWorkbook(new FileInputStream(fileSOLE2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get text out of the simple file
|
|
||||||
*/
|
|
||||||
public void testGetSimpleText() throws Exception {
|
|
||||||
new HXFExcelExtractor(xmlA.getPackage());
|
|
||||||
new HXFExcelExtractor(new HSSFXMLWorkbook(xmlA));
|
|
||||||
|
|
||||||
HXFExcelExtractor extractor =
|
|
||||||
new HXFExcelExtractor(xmlA.getPackage());
|
|
||||||
extractor.getText();
|
|
||||||
|
|
||||||
String text = extractor.getText();
|
|
||||||
assertTrue(text.length() > 0);
|
|
||||||
|
|
||||||
// Check sheet names
|
|
||||||
assertTrue(text.startsWith("Sheet1"));
|
|
||||||
assertTrue(text.endsWith("Sheet3\n"));
|
|
||||||
|
|
||||||
// Now without, will have text
|
|
||||||
extractor.setIncludeSheetNames(false);
|
|
||||||
text = extractor.getText();
|
|
||||||
assertEquals(
|
|
||||||
"Lorem\t111\n" +
|
|
||||||
"ipsum\t222\n" +
|
|
||||||
"dolor\t333\n" +
|
|
||||||
"sit\t444\n" +
|
|
||||||
"amet\t555\n" +
|
|
||||||
"consectetuer\t666\n" +
|
|
||||||
"adipiscing\t777\n" +
|
|
||||||
"elit\t888\n" +
|
|
||||||
"Nunc\t999\n" +
|
|
||||||
"at\t4995\n" +
|
|
||||||
"\n\n", text);
|
|
||||||
|
|
||||||
// Now get formulas not their values
|
|
||||||
extractor.setFormulasNotResults(true);
|
|
||||||
text = extractor.getText();
|
|
||||||
assertEquals(
|
|
||||||
"Lorem\t111\n" +
|
|
||||||
"ipsum\t222\n" +
|
|
||||||
"dolor\t333\n" +
|
|
||||||
"sit\t444\n" +
|
|
||||||
"amet\t555\n" +
|
|
||||||
"consectetuer\t666\n" +
|
|
||||||
"adipiscing\t777\n" +
|
|
||||||
"elit\t888\n" +
|
|
||||||
"Nunc\t999\n" +
|
|
||||||
"at\tSUM(B1:B9)\n" +
|
|
||||||
"\n\n", text);
|
|
||||||
|
|
||||||
// With sheet names too
|
|
||||||
extractor.setIncludeSheetNames(true);
|
|
||||||
text = extractor.getText();
|
|
||||||
assertEquals(
|
|
||||||
"Sheet1\n" +
|
|
||||||
"Lorem\t111\n" +
|
|
||||||
"ipsum\t222\n" +
|
|
||||||
"dolor\t333\n" +
|
|
||||||
"sit\t444\n" +
|
|
||||||
"amet\t555\n" +
|
|
||||||
"consectetuer\t666\n" +
|
|
||||||
"adipiscing\t777\n" +
|
|
||||||
"elit\t888\n" +
|
|
||||||
"Nunc\t999\n" +
|
|
||||||
"at\tSUM(B1:B9)\n\n" +
|
|
||||||
"Sheet2\n\n" +
|
|
||||||
"Sheet3\n"
|
|
||||||
, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetComplexText() throws Exception {
|
|
||||||
new HXFExcelExtractor(xmlB.getPackage());
|
|
||||||
new HXFExcelExtractor(new HSSFXMLWorkbook(xmlB));
|
|
||||||
|
|
||||||
HXFExcelExtractor extractor =
|
|
||||||
new HXFExcelExtractor(xmlB.getPackage());
|
|
||||||
extractor.getText();
|
|
||||||
|
|
||||||
String text = extractor.getText();
|
|
||||||
assertTrue(text.length() > 0);
|
|
||||||
|
|
||||||
// Might not have all formatting it should do!
|
|
||||||
// TODO decide if we should really have the "null" in there
|
|
||||||
assertTrue(text.startsWith(
|
|
||||||
"Avgtxfull\n" +
|
|
||||||
"null\t(iii) AVERAGE TAX RATES ON ANNUAL"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that we return pretty much the same as
|
|
||||||
* ExcelExtractor does, when we're both passed
|
|
||||||
* the same file, just saved as xls and xlsx
|
|
||||||
*/
|
|
||||||
public void testComparedToOLE2() throws Exception {
|
|
||||||
HXFExcelExtractor ooxmlExtractor =
|
|
||||||
new HXFExcelExtractor(simpleXLSX.getPackage());
|
|
||||||
ExcelExtractor ole2Extractor =
|
|
||||||
new ExcelExtractor(simpleXLS);
|
|
||||||
|
|
||||||
POITextExtractor[] extractors =
|
|
||||||
new POITextExtractor[] { ooxmlExtractor, ole2Extractor };
|
|
||||||
for (int i = 0; i < extractors.length; i++) {
|
|
||||||
POITextExtractor extractor = extractors[i];
|
|
||||||
|
|
||||||
String text = extractor.getText().replaceAll("[\r\t]", "");
|
|
||||||
//System.out.println(text.length());
|
|
||||||
//System.out.println(text);
|
|
||||||
assertTrue(text.startsWith("First Sheet\nTest spreadsheet\n2nd row2nd row 2nd column\n"));
|
|
||||||
Pattern pattern = Pattern.compile(".*13(\\.0+)?\\s+Sheet3.*", Pattern.DOTALL);
|
|
||||||
Matcher m = pattern.matcher(text);
|
|
||||||
assertTrue(m.matches());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,110 +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.hwpf;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
import org.openxml4j.opc.Package;
|
|
||||||
import org.openxml4j.opc.PackagePart;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
public class TestHWPFXML extends TestCase {
|
|
||||||
private File sampleFile;
|
|
||||||
private File complexFile;
|
|
||||||
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
sampleFile = new File(
|
|
||||||
System.getProperty("HWPF.testdata.path") +
|
|
||||||
File.separator + "sample.docx"
|
|
||||||
);
|
|
||||||
complexFile = new File(
|
|
||||||
System.getProperty("HWPF.testdata.path") +
|
|
||||||
File.separator + "IllustrativeCases.docx"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testContainsMainContentType() throws Exception {
|
|
||||||
Package pack = HXFDocument.openPackage(sampleFile);
|
|
||||||
|
|
||||||
boolean found = false;
|
|
||||||
for(PackagePart part : pack.getParts()) {
|
|
||||||
if(part.getContentType().equals(HWPFXML.MAIN_CONTENT_TYPE)) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
System.out.println(part);
|
|
||||||
}
|
|
||||||
assertTrue(found);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testOpen() throws Exception {
|
|
||||||
HXFDocument.openPackage(sampleFile);
|
|
||||||
HXFDocument.openPackage(complexFile);
|
|
||||||
|
|
||||||
HWPFXML xml;
|
|
||||||
|
|
||||||
// Simple file
|
|
||||||
xml = new HWPFXML(
|
|
||||||
HXFDocument.openPackage(sampleFile)
|
|
||||||
);
|
|
||||||
// Check it has key parts
|
|
||||||
assertNotNull(xml.getDocument());
|
|
||||||
assertNotNull(xml.getDocumentBody());
|
|
||||||
assertNotNull(xml.getStyle());
|
|
||||||
|
|
||||||
// Complex file
|
|
||||||
xml = new HWPFXML(
|
|
||||||
HXFDocument.openPackage(complexFile)
|
|
||||||
);
|
|
||||||
assertNotNull(xml.getDocument());
|
|
||||||
assertNotNull(xml.getDocumentBody());
|
|
||||||
assertNotNull(xml.getStyle());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testMetadataBasics() throws Exception {
|
|
||||||
HWPFXML xml = new HWPFXML(
|
|
||||||
HXFDocument.openPackage(sampleFile)
|
|
||||||
);
|
|
||||||
assertNotNull(xml.getCoreProperties());
|
|
||||||
assertNotNull(xml.getExtendedProperties());
|
|
||||||
|
|
||||||
assertEquals("Microsoft Office Word", xml.getExtendedProperties().getApplication());
|
|
||||||
assertEquals(1315, xml.getExtendedProperties().getCharacters());
|
|
||||||
assertEquals(10, xml.getExtendedProperties().getLines());
|
|
||||||
|
|
||||||
assertEquals(null, xml.getCoreProperties().getTitleProperty().getValue());
|
|
||||||
assertEquals(null, xml.getCoreProperties().getSubjectProperty().getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testMetadataComplex() throws Exception {
|
|
||||||
HWPFXML xml = new HWPFXML(
|
|
||||||
HXFDocument.openPackage(complexFile)
|
|
||||||
);
|
|
||||||
assertNotNull(xml.getCoreProperties());
|
|
||||||
assertNotNull(xml.getExtendedProperties());
|
|
||||||
|
|
||||||
assertEquals("Microsoft Office Outlook", xml.getExtendedProperties().getApplication());
|
|
||||||
assertEquals(5184, xml.getExtendedProperties().getCharacters());
|
|
||||||
assertEquals(0, xml.getExtendedProperties().getLines());
|
|
||||||
|
|
||||||
assertEquals(" ", xml.getCoreProperties().getTitleProperty().getValue());
|
|
||||||
assertEquals(" ", xml.getCoreProperties().getSubjectProperty().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,117 +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.hwpf.extractor;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.apache.poi.hwpf.HWPFXML;
|
|
||||||
import org.apache.poi.hwpf.usermodel.HWPFXMLDocument;
|
|
||||||
import org.apache.poi.hxf.HXFDocument;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for HXFWordExtractor
|
|
||||||
*/
|
|
||||||
public class TestHXFWordExtractor extends TestCase {
|
|
||||||
/**
|
|
||||||
* A very simple file
|
|
||||||
*/
|
|
||||||
private HWPFXML xmlA;
|
|
||||||
/**
|
|
||||||
* A fairly complex file
|
|
||||||
*/
|
|
||||||
private HWPFXML xmlB;
|
|
||||||
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
File fileA = new File(
|
|
||||||
System.getProperty("HWPF.testdata.path") +
|
|
||||||
File.separator + "sample.docx"
|
|
||||||
);
|
|
||||||
File fileB = new File(
|
|
||||||
System.getProperty("HWPF.testdata.path") +
|
|
||||||
File.separator + "IllustrativeCases.docx"
|
|
||||||
);
|
|
||||||
|
|
||||||
xmlA = new HWPFXML(HXFDocument.openPackage(fileA));
|
|
||||||
xmlB = new HWPFXML(HXFDocument.openPackage(fileB));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get text out of the simple file
|
|
||||||
*/
|
|
||||||
public void testGetSimpleText() throws Exception {
|
|
||||||
new HXFWordExtractor(xmlA.getPackage());
|
|
||||||
new HXFWordExtractor(new HWPFXMLDocument(xmlA));
|
|
||||||
|
|
||||||
HXFWordExtractor extractor =
|
|
||||||
new HXFWordExtractor(xmlA.getPackage());
|
|
||||||
extractor.getText();
|
|
||||||
|
|
||||||
String text = extractor.getText();
|
|
||||||
assertTrue(text.length() > 0);
|
|
||||||
|
|
||||||
// Check contents
|
|
||||||
assertTrue(text.startsWith(
|
|
||||||
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc at risus vel erat tempus posuere. Aenean non ante. Suspendisse vehicula dolor sit amet odio."
|
|
||||||
));
|
|
||||||
assertTrue(text.endsWith(
|
|
||||||
"Phasellus ultricies mi nec leo. Sed tempus. In sit amet lorem at velit faucibus vestibulum.\n"
|
|
||||||
));
|
|
||||||
|
|
||||||
// Check number of paragraphs
|
|
||||||
int ps = 0;
|
|
||||||
char[] t = text.toCharArray();
|
|
||||||
for (int i = 0; i < t.length; i++) {
|
|
||||||
if(t[i] == '\n') { ps++; }
|
|
||||||
}
|
|
||||||
assertEquals(3, ps);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests getting the text out of a complex file
|
|
||||||
*/
|
|
||||||
public void testGetComplexText() throws Exception {
|
|
||||||
HXFWordExtractor extractor =
|
|
||||||
new HXFWordExtractor(xmlB.getPackage());
|
|
||||||
extractor.getText();
|
|
||||||
|
|
||||||
String text = extractor.getText();
|
|
||||||
assertTrue(text.length() > 0);
|
|
||||||
|
|
||||||
char euro = '\u20ac';
|
|
||||||
System.err.println("'"+text.substring(text.length() - 20) + "'");
|
|
||||||
|
|
||||||
// Check contents
|
|
||||||
assertTrue(text.startsWith(
|
|
||||||
" \n(V) ILLUSTRATIVE CASES\n\n"
|
|
||||||
));
|
|
||||||
assertTrue(text.endsWith(
|
|
||||||
"As well as gaining "+euro+"90 from child benefit increases, he will also receive the early childhood supplement of "+euro+"250 per quarter for Vincent for the full four quarters of the year.\n\n\n\n \n\n\n"
|
|
||||||
));
|
|
||||||
|
|
||||||
// Check number of paragraphs
|
|
||||||
int ps = 0;
|
|
||||||
char[] t = text.toCharArray();
|
|
||||||
for (int i = 0; i < t.length; i++) {
|
|
||||||
if(t[i] == '\n') { ps++; }
|
|
||||||
}
|
|
||||||
assertEquals(79, ps);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +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.hxf;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to test that HXF correctly detects OOXML
|
|
||||||
* documents
|
|
||||||
*/
|
|
||||||
public class TestDetectAsOOXML extends TestCase
|
|
||||||
{
|
|
||||||
public String dirname;
|
|
||||||
|
|
||||||
public void setUp() {
|
|
||||||
dirname = System.getProperty("HSSF.testdata.path");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testOpensProperly() throws Exception
|
|
||||||
{
|
|
||||||
File f = new File(dirname + "/sample.xlsx");
|
|
||||||
|
|
||||||
HXFDocument.openPackage(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testDetectAsPOIFS() throws Exception {
|
|
||||||
InputStream in;
|
|
||||||
|
|
||||||
// ooxml file is
|
|
||||||
in = new PushbackInputStream(
|
|
||||||
new FileInputStream(dirname + "/SampleSS.xlsx"), 10
|
|
||||||
);
|
|
||||||
assertTrue(HXFDocument.hasOOXMLHeader(in));
|
|
||||||
|
|
||||||
// xls file isn't
|
|
||||||
in = new PushbackInputStream(
|
|
||||||
new FileInputStream(dirname + "/SampleSS.xls"), 10
|
|
||||||
);
|
|
||||||
assertFalse(HXFDocument.hasOOXMLHeader(in));
|
|
||||||
|
|
||||||
// text file isn't
|
|
||||||
in = new PushbackInputStream(
|
|
||||||
new FileInputStream(dirname + "/SampleSS.txt"), 10
|
|
||||||
);
|
|
||||||
assertFalse(HXFDocument.hasOOXMLHeader(in));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -369,5 +369,12 @@ public class AutoShapes {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
shapes[ShapeTypes.StraightConnector1] = new ShapeOutline(){
|
||||||
|
public java.awt.Shape getOutline(Shape shape){
|
||||||
|
return new Line2D.Float(0, 0, 21600, 21600);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.poi.hslf.model;
|
||||||
import org.apache.poi.ddf.*;
|
import org.apache.poi.ddf.*;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
import java.awt.geom.*;
|
import java.awt.geom.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -185,10 +186,6 @@ public class Freeform extends AutoShape {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle2D bounds = getAnchor2D();
|
|
||||||
float right = (float)bounds.getX();
|
|
||||||
float bottom = (float)bounds.getY();
|
|
||||||
|
|
||||||
GeneralPath path = new GeneralPath();
|
GeneralPath path = new GeneralPath();
|
||||||
int numPoints = verticesProp.getNumberOfElementsInArray();
|
int numPoints = verticesProp.getNumberOfElementsInArray();
|
||||||
int numSegments = segmentsProp.getNumberOfElementsInArray();
|
int numSegments = segmentsProp.getNumberOfElementsInArray();
|
||||||
|
@ -199,8 +196,8 @@ public class Freeform extends AutoShape {
|
||||||
short x = LittleEndian.getShort(p, 0);
|
short x = LittleEndian.getShort(p, 0);
|
||||||
short y = LittleEndian.getShort(p, 2);
|
short y = LittleEndian.getShort(p, 2);
|
||||||
path.moveTo(
|
path.moveTo(
|
||||||
((float)x*POINT_DPI/MASTER_DPI + right),
|
((float)x*POINT_DPI/MASTER_DPI),
|
||||||
((float)y*POINT_DPI/MASTER_DPI + bottom));
|
((float)y*POINT_DPI/MASTER_DPI));
|
||||||
} else if (Arrays.equals(elem, SEGMENTINFO_CUBICTO) || Arrays.equals(elem, SEGMENTINFO_CUBICTO2)){
|
} else if (Arrays.equals(elem, SEGMENTINFO_CUBICTO) || Arrays.equals(elem, SEGMENTINFO_CUBICTO2)){
|
||||||
i++;
|
i++;
|
||||||
byte[] p1 = verticesProp.getElement(j++);
|
byte[] p1 = verticesProp.getElement(j++);
|
||||||
|
@ -213,9 +210,9 @@ public class Freeform extends AutoShape {
|
||||||
short x3 = LittleEndian.getShort(p3, 0);
|
short x3 = LittleEndian.getShort(p3, 0);
|
||||||
short y3 = LittleEndian.getShort(p3, 2);
|
short y3 = LittleEndian.getShort(p3, 2);
|
||||||
path.curveTo(
|
path.curveTo(
|
||||||
((float)x1*POINT_DPI/MASTER_DPI + right), ((float)y1*POINT_DPI/MASTER_DPI + bottom),
|
((float)x1*POINT_DPI/MASTER_DPI), ((float)y1*POINT_DPI/MASTER_DPI),
|
||||||
((float)x2*POINT_DPI/MASTER_DPI + right), ((float)y2*POINT_DPI/MASTER_DPI + bottom),
|
((float)x2*POINT_DPI/MASTER_DPI), ((float)y2*POINT_DPI/MASTER_DPI),
|
||||||
((float)x3*POINT_DPI/MASTER_DPI + right), ((float)y3*POINT_DPI/MASTER_DPI + bottom));
|
((float)x3*POINT_DPI/MASTER_DPI), ((float)y3*POINT_DPI/MASTER_DPI));
|
||||||
|
|
||||||
} else if (Arrays.equals(elem, SEGMENTINFO_LINETO)){
|
} else if (Arrays.equals(elem, SEGMENTINFO_LINETO)){
|
||||||
i++;
|
i++;
|
||||||
|
@ -226,18 +223,26 @@ public class Freeform extends AutoShape {
|
||||||
short x = LittleEndian.getShort(p, 0);
|
short x = LittleEndian.getShort(p, 0);
|
||||||
short y = LittleEndian.getShort(p, 2);
|
short y = LittleEndian.getShort(p, 2);
|
||||||
path.lineTo(
|
path.lineTo(
|
||||||
((float)x*POINT_DPI/MASTER_DPI + right), ((float)y*POINT_DPI/MASTER_DPI + bottom));
|
((float)x*POINT_DPI/MASTER_DPI), ((float)y*POINT_DPI/MASTER_DPI));
|
||||||
}
|
}
|
||||||
} else if (Arrays.equals(pnext, SEGMENTINFO_CLOSE)){
|
} else if (Arrays.equals(pnext, SEGMENTINFO_CLOSE)){
|
||||||
path.closePath();
|
path.closePath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public java.awt.Shape getOutline(){
|
public java.awt.Shape getOutline(){
|
||||||
return getPath();
|
GeneralPath path = getPath();
|
||||||
|
Rectangle2D anchor = getAnchor2D();
|
||||||
|
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 at.createTransformedShape(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,4 +67,21 @@ public abstract class MasterSheet extends Sheet {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return placeholder by text type
|
||||||
|
*/
|
||||||
|
public TextShape getPlaceholder(int type){
|
||||||
|
Shape[] shape = getShapes();
|
||||||
|
for (int i = 0; i < shape.length; i++) {
|
||||||
|
if(shape[i] instanceof TextShape){
|
||||||
|
TextShape tx = (TextShape)shape[i];
|
||||||
|
TextRun run = tx.getTextRun();
|
||||||
|
if(run != null && run.getRunType() == type){
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import javax.imageio.ImageIO;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
@ -244,6 +245,9 @@ public class Picture extends SimpleShape {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void draw(Graphics2D graphics){
|
public void draw(Graphics2D graphics){
|
||||||
|
AffineTransform at = graphics.getTransform();
|
||||||
|
ShapePainter.paint(this, graphics);
|
||||||
|
|
||||||
PictureData data = getPictureData();
|
PictureData data = getPictureData();
|
||||||
if (data instanceof Bitmap){
|
if (data instanceof Bitmap){
|
||||||
BufferedImage img = null;
|
BufferedImage img = null;
|
||||||
|
@ -260,5 +264,6 @@ public class Picture extends SimpleShape {
|
||||||
} else {
|
} else {
|
||||||
logger.log(POILogger.WARN, "Rendering of metafiles is not yet supported. image.type: " + (data == null ? "NA" : data.getClass().getName()));
|
logger.log(POILogger.WARN, "Rendering of metafiles is not yet supported. image.type: " + (data == null ? "NA" : data.getClass().getName()));
|
||||||
}
|
}
|
||||||
|
graphics.setTransform(at);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -341,58 +341,7 @@ public abstract class Shape {
|
||||||
* @param sh - owning shape
|
* @param sh - owning shape
|
||||||
*/
|
*/
|
||||||
protected void afterInsert(Sheet sh){
|
protected void afterInsert(Sheet sh){
|
||||||
PPDrawing ppdrawing = sh.getPPDrawing();
|
|
||||||
|
|
||||||
EscherContainerRecord dgContainer = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
|
|
||||||
|
|
||||||
EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
|
|
||||||
|
|
||||||
int id = allocateShapeId(dg);
|
|
||||||
setShapeId(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocates new shape id for the new drawing group id.
|
|
||||||
*
|
|
||||||
* @param dg EscherDgRecord of the sheet that owns the shape being created
|
|
||||||
*
|
|
||||||
* @return a new shape id.
|
|
||||||
*/
|
|
||||||
protected int allocateShapeId(EscherDgRecord dg)
|
|
||||||
{
|
|
||||||
EscherDggRecord dgg = _sheet.getSlideShow().getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
|
|
||||||
if(dgg == null){
|
|
||||||
logger.log(POILogger.ERROR, "EscherDggRecord not found");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 );
|
|
||||||
|
|
||||||
// Add to existing cluster if space available
|
|
||||||
for (int i = 0; i < dgg.getFileIdClusters().length; i++)
|
|
||||||
{
|
|
||||||
EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i];
|
|
||||||
if (c.getDrawingGroupId() == dg.getDrawingGroupId() && c.getNumShapeIdsUsed() != 1024)
|
|
||||||
{
|
|
||||||
int result = c.getNumShapeIdsUsed() + (1024 * (i+1));
|
|
||||||
c.incrementShapeId();
|
|
||||||
dg.setNumShapes( dg.getNumShapes() + 1 );
|
|
||||||
dg.setLastMSOSPID( result );
|
|
||||||
if (result >= dgg.getShapeIdMax())
|
|
||||||
dgg.setShapeIdMax( result + 1 );
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create new cluster
|
|
||||||
dgg.addCluster( dg.getDrawingGroupId(), 0 );
|
|
||||||
dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId();
|
|
||||||
dg.setNumShapes( dg.getNumShapes() + 1 );
|
|
||||||
int result = (1024 * dgg.getFileIdClusters().length);
|
|
||||||
dg.setLastMSOSPID( result );
|
|
||||||
if (result >= dgg.getShapeIdMax())
|
|
||||||
dgg.setShapeIdMax( result + 1 );
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -196,13 +196,8 @@ public class ShapeGroup extends Shape{
|
||||||
|
|
||||||
Sheet sheet = getSheet();
|
Sheet sheet = getSheet();
|
||||||
shape.setSheet(sheet);
|
shape.setSheet(sheet);
|
||||||
|
shape.setShapeId(sheet.allocateShapeId());
|
||||||
shape.afterInsert(sheet);
|
shape.afterInsert(sheet);
|
||||||
|
|
||||||
if (shape instanceof TextShape) {
|
|
||||||
TextShape tbox = (TextShape) shape;
|
|
||||||
EscherTextboxWrapper txWrapper = tbox.getEscherTextboxWrapper();
|
|
||||||
if(txWrapper != null) getSheet().getPPDrawing().addTextboxWrapper(txWrapper);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -277,20 +272,9 @@ public class ShapeGroup extends Shape{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void draw(Graphics2D graphics){
|
public void draw(Graphics2D graphics){
|
||||||
Rectangle2D anchor = getAnchor2D();
|
|
||||||
Rectangle2D coords = getCoordinates();
|
|
||||||
|
|
||||||
//transform coordinates
|
|
||||||
AffineTransform at = graphics.getTransform();
|
AffineTransform at = graphics.getTransform();
|
||||||
/*
|
|
||||||
if(!anchor.equals(coords)){
|
|
||||||
graphics.scale(anchor.getWidth()/coords.getWidth(), anchor.getHeight()/coords.getHeight());
|
|
||||||
|
|
||||||
graphics.translate(
|
|
||||||
anchor.getX()*coords.getWidth()/anchor.getWidth() - coords.getX(),
|
|
||||||
anchor.getY()*coords.getHeight()/anchor.getHeight() - coords.getY());
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
Shape[] sh = getShapes();
|
Shape[] sh = getShapes();
|
||||||
for (int i = 0; i < sh.length; i++) {
|
for (int i = 0; i < sh.length; i++) {
|
||||||
sh[i].draw(graphics);
|
sh[i].draw(graphics);
|
||||||
|
|
|
@ -18,12 +18,10 @@
|
||||||
|
|
||||||
package org.apache.poi.hslf.model;
|
package org.apache.poi.hslf.model;
|
||||||
|
|
||||||
import org.apache.poi.ddf.EscherContainerRecord;
|
import org.apache.poi.ddf.*;
|
||||||
import org.apache.poi.ddf.EscherDgRecord;
|
|
||||||
import org.apache.poi.ddf.EscherRecord;
|
|
||||||
import org.apache.poi.ddf.EscherSpRecord;
|
|
||||||
import org.apache.poi.hslf.record.*;
|
import org.apache.poi.hslf.record.*;
|
||||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||||
|
import org.apache.poi.util.POILogger;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -248,15 +246,47 @@ public abstract class Sheet {
|
||||||
spgr.addChildRecord(shape.getSpContainer());
|
spgr.addChildRecord(shape.getSpContainer());
|
||||||
|
|
||||||
shape.setSheet(this);
|
shape.setSheet(this);
|
||||||
|
shape.setShapeId(allocateShapeId());
|
||||||
shape.afterInsert(this);
|
shape.afterInsert(this);
|
||||||
|
|
||||||
// If it's a TextShape, we need to tell the PPDrawing, as it has to
|
|
||||||
// track TextboxWrappers specially
|
|
||||||
if (shape instanceof TextShape) {
|
|
||||||
TextShape tbox = (TextShape) shape;
|
|
||||||
EscherTextboxWrapper txWrapper = tbox.getEscherTextboxWrapper();
|
|
||||||
if(txWrapper != null) ppdrawing.addTextboxWrapper(txWrapper);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates new shape id for the new drawing group id.
|
||||||
|
*
|
||||||
|
* @return a new shape id.
|
||||||
|
*/
|
||||||
|
public int allocateShapeId()
|
||||||
|
{
|
||||||
|
EscherDggRecord dgg = _slideShow.getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
|
||||||
|
EscherDgRecord dg = _container.getPPDrawing().getEscherDgRecord();
|
||||||
|
|
||||||
|
dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 );
|
||||||
|
|
||||||
|
// Add to existing cluster if space available
|
||||||
|
for (int i = 0; i < dgg.getFileIdClusters().length; i++)
|
||||||
|
{
|
||||||
|
EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i];
|
||||||
|
if (c.getDrawingGroupId() == dg.getDrawingGroupId() && c.getNumShapeIdsUsed() != 1024)
|
||||||
|
{
|
||||||
|
int result = c.getNumShapeIdsUsed() + (1024 * (i+1));
|
||||||
|
c.incrementShapeId();
|
||||||
|
dg.setNumShapes( dg.getNumShapes() + 1 );
|
||||||
|
dg.setLastMSOSPID( result );
|
||||||
|
if (result >= dgg.getShapeIdMax())
|
||||||
|
dgg.setShapeIdMax( result + 1 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new cluster
|
||||||
|
dgg.addCluster( dg.getDrawingGroupId(), 0, false );
|
||||||
|
dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId();
|
||||||
|
dg.setNumShapes( dg.getNumShapes() + 1 );
|
||||||
|
int result = (1024 * dgg.getFileIdClusters().length);
|
||||||
|
dg.setLastMSOSPID( result );
|
||||||
|
if (result >= dgg.getShapeIdMax())
|
||||||
|
dgg.setShapeIdMax( result + 1 );
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -284,6 +314,13 @@ public abstract class Sheet {
|
||||||
return lst.remove(shape.getSpContainer());
|
return lst.remove(shape.getSpContainer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by SlideShow ater a new sheet is created
|
||||||
|
*/
|
||||||
|
public void onCreate(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the master sheet .
|
* Return the master sheet .
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -126,8 +126,8 @@ public class SimpleShape extends Shape {
|
||||||
EscherSimpleProperty p2 = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH);
|
EscherSimpleProperty p2 = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH);
|
||||||
int p2val = p2 == null ? 0 : p2.getPropertyValue();
|
int p2val = p2 == null ? 0 : p2.getPropertyValue();
|
||||||
Color clr = null;
|
Color clr = null;
|
||||||
if (p1 != null && (p2val & 0x8) != 0){
|
if ((p2val & 0x8) != 0 || (p2val & 0x10) != 0){
|
||||||
int rgb = p1.getPropertyValue();
|
int rgb = p1 == null ? 0 : p1.getPropertyValue();
|
||||||
if (rgb >= 0x8000000) {
|
if (rgb >= 0x8000000) {
|
||||||
int idx = rgb % 0x8000000;
|
int idx = rgb % 0x8000000;
|
||||||
if(getSheet() != null) {
|
if(getSheet() != null) {
|
||||||
|
|
|
@ -21,12 +21,17 @@
|
||||||
package org.apache.poi.hslf.model;
|
package org.apache.poi.hslf.model;
|
||||||
|
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
import org.apache.poi.hslf.record.SlideAtom;
|
import org.apache.poi.hslf.record.SlideAtom;
|
||||||
import org.apache.poi.hslf.record.TextHeaderAtom;
|
import org.apache.poi.hslf.record.TextHeaderAtom;
|
||||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||||
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
|
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
|
||||||
|
import org.apache.poi.ddf.EscherDggRecord;
|
||||||
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
|
import org.apache.poi.ddf.EscherDgRecord;
|
||||||
|
import org.apache.poi.ddf.EscherSpRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a slide in a PowerPoint Document. It allows
|
* This class represents a slide in a PowerPoint Document. It allows
|
||||||
|
@ -126,6 +131,42 @@ public class Slide extends Sheet
|
||||||
_slideNo = newSlideNumber;
|
_slideNo = newSlideNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by SlideShow ater a new slide is created.
|
||||||
|
* <p>
|
||||||
|
* For Slide we need to do the following:
|
||||||
|
* <li> set id of the drawing group.
|
||||||
|
* <li> set shapeId for the container descriptor and background
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public void onCreate(){
|
||||||
|
//initialize drawing group id
|
||||||
|
EscherDggRecord dgg = getSlideShow().getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
|
||||||
|
EscherContainerRecord dgContainer = (EscherContainerRecord)getSheetContainer().getPPDrawing().getEscherRecords()[0];
|
||||||
|
EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
|
||||||
|
int dgId = dgg.getMaxDrawingGroupId() + 1;
|
||||||
|
dg.setOptions((short)(dgId << 4));
|
||||||
|
dgg.setDrawingsSaved(dgg.getDrawingsSaved() + 1);
|
||||||
|
|
||||||
|
for (Iterator it = dgContainer.getChildContainers().iterator(); it.hasNext(); ) {
|
||||||
|
EscherContainerRecord c = (EscherContainerRecord)it.next();
|
||||||
|
EscherSpRecord spr = null;
|
||||||
|
switch(c.getRecordId()){
|
||||||
|
case EscherContainerRecord.SPGR_CONTAINER:
|
||||||
|
EscherContainerRecord dc = (EscherContainerRecord)c.getChildRecords().get(0);
|
||||||
|
spr = dc.getChildById(EscherSpRecord.RECORD_ID);
|
||||||
|
break;
|
||||||
|
case EscherContainerRecord.SP_CONTAINER:
|
||||||
|
spr = c.getChildById(EscherSpRecord.RECORD_ID);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(spr != null) spr.setShapeId(allocateShapeId());
|
||||||
|
}
|
||||||
|
|
||||||
|
//PPT doen't increment the number of saved shapes for group descriptor and background
|
||||||
|
dg.setNumShapes(1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a <code>TextBox</code> object that represents the slide's title.
|
* Create a <code>TextBox</code> object that represents the slide's title.
|
||||||
*
|
*
|
||||||
|
|
|
@ -92,6 +92,7 @@ public class SlideMaster extends MasterSheet {
|
||||||
} else {
|
} else {
|
||||||
switch (txtype) {
|
switch (txtype) {
|
||||||
case TextHeaderAtom.CENTRE_BODY_TYPE:
|
case TextHeaderAtom.CENTRE_BODY_TYPE:
|
||||||
|
case TextHeaderAtom.HALF_BODY_TYPE:
|
||||||
case TextHeaderAtom.QUARTER_BODY_TYPE:
|
case TextHeaderAtom.QUARTER_BODY_TYPE:
|
||||||
txtype = TextHeaderAtom.BODY_TYPE;
|
txtype = TextHeaderAtom.BODY_TYPE;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.apache.poi.hslf.model;
|
package org.apache.poi.hslf.model;
|
||||||
|
|
||||||
import org.apache.poi.hslf.usermodel.RichTextRun;
|
import org.apache.poi.hslf.usermodel.RichTextRun;
|
||||||
|
import org.apache.poi.hslf.record.TextRulerAtom;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
|
|
||||||
|
@ -38,6 +39,13 @@ import java.util.ArrayList;
|
||||||
public class TextPainter {
|
public class TextPainter {
|
||||||
protected POILogger logger = POILogFactory.getLogger(this.getClass());
|
protected POILogger logger = POILogFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display unicode square if a bullet char can't be displayed,
|
||||||
|
* for example, if Wingdings font is used.
|
||||||
|
* TODO: map Wingdngs and Symbol to unicode Arial
|
||||||
|
*/
|
||||||
|
protected static final char DEFAULT_BULLET_CHAR = '\u25a0';
|
||||||
|
|
||||||
protected TextShape _shape;
|
protected TextShape _shape;
|
||||||
|
|
||||||
public TextPainter(TextShape shape){
|
public TextPainter(TextShape shape){
|
||||||
|
@ -49,6 +57,10 @@ public class TextPainter {
|
||||||
*/
|
*/
|
||||||
public AttributedString getAttributedString(TextRun txrun){
|
public AttributedString getAttributedString(TextRun txrun){
|
||||||
String text = txrun.getText();
|
String text = txrun.getText();
|
||||||
|
//TODO: properly process tabs
|
||||||
|
text = text.replace('\t', ' ');
|
||||||
|
text = text.replace((char)160, ' ');
|
||||||
|
|
||||||
AttributedString at = new AttributedString(text);
|
AttributedString at = new AttributedString(text);
|
||||||
RichTextRun[] rt = txrun.getRichTextRuns();
|
RichTextRun[] rt = txrun.getRichTextRuns();
|
||||||
for (int i = 0; i < rt.length; i++) {
|
for (int i = 0; i < rt.length; i++) {
|
||||||
|
@ -109,7 +121,24 @@ public class TextPainter {
|
||||||
}
|
}
|
||||||
|
|
||||||
float wrappingWidth = (float)anchor.getWidth() - _shape.getMarginLeft() - _shape.getMarginRight();
|
float wrappingWidth = (float)anchor.getWidth() - _shape.getMarginLeft() - _shape.getMarginRight();
|
||||||
wrappingWidth -= rt.getTextOffset();
|
int bulletOffset = rt.getBulletOffset();
|
||||||
|
int textOffset = rt.getTextOffset();
|
||||||
|
int indent = rt.getIndentLevel();
|
||||||
|
|
||||||
|
TextRulerAtom ruler = run.getTextRuler();
|
||||||
|
if(ruler != null) {
|
||||||
|
int bullet_val = ruler.getBulletOffsets()[indent]*Shape.POINT_DPI/Shape.MASTER_DPI;
|
||||||
|
int text_val = ruler.getTextOffsets()[indent]*Shape.POINT_DPI/Shape.MASTER_DPI;
|
||||||
|
if(bullet_val > text_val){
|
||||||
|
int a = bullet_val;
|
||||||
|
bullet_val = text_val;
|
||||||
|
text_val = a;
|
||||||
|
}
|
||||||
|
if(bullet_val != 0 ) bulletOffset = bullet_val;
|
||||||
|
if(text_val != 0) textOffset = text_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
wrappingWidth -= textOffset;
|
||||||
|
|
||||||
if (_shape.getWordWrap() == TextShape.WrapNone) {
|
if (_shape.getWordWrap() == TextShape.WrapNone) {
|
||||||
wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width;
|
wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width;
|
||||||
|
@ -141,8 +170,9 @@ public class TextPainter {
|
||||||
}
|
}
|
||||||
|
|
||||||
el._align = rt.getAlignment();
|
el._align = rt.getAlignment();
|
||||||
el._text = textLayout;
|
el.advance = textLayout.getAdvance();
|
||||||
el._textOffset = rt.getTextOffset();
|
el._textOffset = textOffset;
|
||||||
|
el._text = new AttributedString(it, startIndex, endIndex);
|
||||||
|
|
||||||
if (prStart){
|
if (prStart){
|
||||||
int sp = rt.getSpaceBefore();
|
int sp = rt.getSpaceBefore();
|
||||||
|
@ -182,13 +212,25 @@ public class TextPainter {
|
||||||
Color clr = rt.getBulletColor();
|
Color clr = rt.getBulletColor();
|
||||||
if (clr != null) bat.addAttribute(TextAttribute.FOREGROUND, clr);
|
if (clr != null) bat.addAttribute(TextAttribute.FOREGROUND, clr);
|
||||||
else bat.addAttribute(TextAttribute.FOREGROUND, it.getAttribute(TextAttribute.FOREGROUND));
|
else bat.addAttribute(TextAttribute.FOREGROUND, it.getAttribute(TextAttribute.FOREGROUND));
|
||||||
bat.addAttribute(TextAttribute.FAMILY, it.getAttribute(TextAttribute.FAMILY));
|
|
||||||
bat.addAttribute(TextAttribute.SIZE, it.getAttribute(TextAttribute.SIZE));
|
|
||||||
|
|
||||||
TextLayout bulletLayout = new TextLayout(bat.getIterator(), graphics.getFontRenderContext());
|
int fontIdx = rt.getBulletFont();
|
||||||
|
if(fontIdx == -1) fontIdx = rt.getFontIndex();
|
||||||
|
PPFont bulletFont = _shape.getSheet().getSlideShow().getFont(fontIdx);
|
||||||
|
bat.addAttribute(TextAttribute.FAMILY, bulletFont.getFontName());
|
||||||
|
|
||||||
|
int bulletSize = rt.getBulletSize();
|
||||||
|
int fontSize = rt.getFontSize();
|
||||||
|
if(bulletSize != -1) fontSize = Math.round(fontSize*bulletSize*0.01f);
|
||||||
|
bat.addAttribute(TextAttribute.SIZE, new Float(fontSize));
|
||||||
|
|
||||||
|
if(!new Font(bulletFont.getFontName(), Font.PLAIN, 1).canDisplay(rt.getBulletChar())){
|
||||||
|
bat.addAttribute(TextAttribute.FAMILY, "Arial");
|
||||||
|
bat = new AttributedString("" + DEFAULT_BULLET_CHAR, bat.getIterator().getAttributes());
|
||||||
|
}
|
||||||
|
|
||||||
if(text.substring(startIndex, endIndex).length() > 1){
|
if(text.substring(startIndex, endIndex).length() > 1){
|
||||||
el._bullet = bulletLayout;
|
el._bullet = bat;
|
||||||
el._bulletOffset = rt.getBulletOffset();
|
el._bulletOffset = bulletOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lines.add(el);
|
lines.add(el);
|
||||||
|
@ -225,29 +267,32 @@ public class TextPainter {
|
||||||
break;
|
break;
|
||||||
case TextShape.AlignCenter:
|
case TextShape.AlignCenter:
|
||||||
pen.x = anchor.getX() + _shape.getMarginLeft() +
|
pen.x = anchor.getX() + _shape.getMarginLeft() +
|
||||||
(anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;
|
(anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;
|
||||||
break;
|
break;
|
||||||
case TextShape.AlignRight:
|
case TextShape.AlignRight:
|
||||||
pen.x = anchor.getX() + _shape.getMarginLeft() +
|
pen.x = anchor.getX() + _shape.getMarginLeft() +
|
||||||
(anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight());
|
(anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(elem._bullet != null){
|
if(elem._bullet != null){
|
||||||
elem._bullet.draw(graphics, (float)(pen.x + elem._bulletOffset), (float)pen.y);
|
graphics.drawString(elem._bullet.getIterator(), (float)(pen.x + elem._bulletOffset), (float)pen.y);
|
||||||
|
}
|
||||||
|
AttributedCharacterIterator chIt = elem._text.getIterator();
|
||||||
|
if(chIt.getEndIndex() > chIt.getBeginIndex()) {
|
||||||
|
graphics.drawString(chIt, (float)(pen.x + elem._textOffset), (float)pen.y);
|
||||||
}
|
}
|
||||||
elem._text.draw(graphics, (float)(pen.x + elem._textOffset), (float)pen.y);
|
|
||||||
|
|
||||||
y0 += elem.descent;
|
y0 += elem.descent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static class TextElement {
|
public static class TextElement {
|
||||||
public TextLayout _text;
|
public AttributedString _text;
|
||||||
public int _textOffset;
|
public int _textOffset;
|
||||||
public TextLayout _bullet;
|
public AttributedString _bullet;
|
||||||
public int _bulletOffset;
|
public int _bulletOffset;
|
||||||
public int _align;
|
public int _align;
|
||||||
public float ascent, descent;
|
public float ascent, descent;
|
||||||
|
public float advance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -535,9 +535,13 @@ public class TextRun
|
||||||
// them to \n
|
// them to \n
|
||||||
String text = rawText.replace('\r','\n');
|
String text = rawText.replace('\r','\n');
|
||||||
|
|
||||||
//0xB acts like cariage return in page titles
|
int type = _headerAtom == null ? 0 : _headerAtom.getTextType();
|
||||||
|
if(type == TextHeaderAtom.TITLE_TYPE || type == TextHeaderAtom.CENTER_TITLE_TYPE){
|
||||||
|
//0xB acts like cariage return in page titles and like blank in the others
|
||||||
text = text.replace((char) 0x0B, '\n');
|
text = text.replace((char) 0x0B, '\n');
|
||||||
|
} else {
|
||||||
|
text = text.replace((char) 0x0B, ' ');
|
||||||
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,4 +659,11 @@ public class TextRun
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TextRulerAtom getTextRuler(){
|
||||||
|
for (int i = 0; i < _records.length; i++) {
|
||||||
|
if(_records[i] instanceof TextRulerAtom) return (TextRulerAtom)_records[i];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,9 +261,19 @@ public abstract class TextShape extends SimpleShape {
|
||||||
public int getVerticalAlignment(){
|
public int getVerticalAlignment(){
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||||
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
|
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
|
||||||
int valign;
|
int valign = TextShape.AnchorTop;
|
||||||
if (prop == null){
|
if (prop == null){
|
||||||
|
/**
|
||||||
|
* If vertical alignment was not found in the shape properties then try to
|
||||||
|
* fetch the master shape and search for the align property there.
|
||||||
|
*/
|
||||||
int type = getTextRun().getRunType();
|
int type = getTextRun().getRunType();
|
||||||
|
MasterSheet master = getSheet().getMasterSheet();
|
||||||
|
if(master != null){
|
||||||
|
TextShape masterShape = master.getPlaceholder(type);
|
||||||
|
if(masterShape != null) valign = masterShape.getVerticalAlignment();
|
||||||
|
} else {
|
||||||
|
//not found in the master sheet. Use the hardcoded defaults.
|
||||||
switch (type){
|
switch (type){
|
||||||
case TextHeaderAtom.TITLE_TYPE:
|
case TextHeaderAtom.TITLE_TYPE:
|
||||||
case TextHeaderAtom.CENTER_TITLE_TYPE:
|
case TextHeaderAtom.CENTER_TITLE_TYPE:
|
||||||
|
@ -273,6 +283,7 @@ public abstract class TextShape extends SimpleShape {
|
||||||
valign = TextShape.AnchorTop;
|
valign = TextShape.AnchorTop;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
valign = prop.getPropertyValue();
|
valign = prop.getPropertyValue();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,11 +24,13 @@ import org.apache.poi.util.POILogger;
|
||||||
|
|
||||||
import org.apache.poi.ddf.*;
|
import org.apache.poi.ddf.*;
|
||||||
import org.apache.poi.hslf.model.ShapeTypes;
|
import org.apache.poi.hslf.model.ShapeTypes;
|
||||||
|
import org.apache.poi.hslf.model.Shape;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These are actually wrappers onto Escher drawings. Make use of
|
* These are actually wrappers onto Escher drawings. Make use of
|
||||||
|
@ -52,6 +54,8 @@ public class PPDrawing extends RecordAtom
|
||||||
private EscherRecord[] childRecords;
|
private EscherRecord[] childRecords;
|
||||||
private EscherTextboxWrapper[] textboxWrappers;
|
private EscherTextboxWrapper[] textboxWrappers;
|
||||||
|
|
||||||
|
//cached EscherDgRecord
|
||||||
|
private EscherDgRecord dg;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get access to the underlying Escher Records
|
* Get access to the underlying Escher Records
|
||||||
|
@ -296,4 +300,24 @@ public class PPDrawing extends RecordAtom
|
||||||
tw[textboxWrappers.length] = txtbox;
|
tw[textboxWrappers.length] = txtbox;
|
||||||
textboxWrappers = tw;
|
textboxWrappers = tw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return EscherDgRecord which keeps track of the number of shapes and shapeId in this drawing group
|
||||||
|
*
|
||||||
|
* @return EscherDgRecord
|
||||||
|
*/
|
||||||
|
public EscherDgRecord getEscherDgRecord(){
|
||||||
|
if(dg == null){
|
||||||
|
EscherContainerRecord dgContainer = (EscherContainerRecord)childRecords[0];
|
||||||
|
for(Iterator it = dgContainer.getChildRecords().iterator(); it.hasNext();){
|
||||||
|
EscherRecord r = (EscherRecord) it.next();
|
||||||
|
if(r instanceof EscherDgRecord){
|
||||||
|
dg = (EscherDgRecord)r;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dg;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class RecordTypes {
|
||||||
public static final Type TxMasterStyleAtom = new Type(4003,TxMasterStyleAtom.class);
|
public static final Type TxMasterStyleAtom = new Type(4003,TxMasterStyleAtom.class);
|
||||||
public static final Type TxCFStyleAtom = new Type(4004,null);
|
public static final Type TxCFStyleAtom = new Type(4004,null);
|
||||||
public static final Type TxPFStyleAtom = new Type(4005,null);
|
public static final Type TxPFStyleAtom = new Type(4005,null);
|
||||||
public static final Type TextRulerAtom = new Type(4006,null);
|
public static final Type TextRulerAtom = new Type(4006,TextRulerAtom.class);
|
||||||
public static final Type TextBookmarkAtom = new Type(4007,null);
|
public static final Type TextBookmarkAtom = new Type(4007,null);
|
||||||
public static final Type TextBytesAtom = new Type(4008,TextBytesAtom.class);
|
public static final Type TextBytesAtom = new Type(4008,TextBytesAtom.class);
|
||||||
public static final Type TxSIStyleAtom = new Type(4009,null);
|
public static final Type TxSIStyleAtom = new Type(4009,null);
|
||||||
|
|
|
@ -127,8 +127,8 @@ public class StyleTextPropAtom extends RecordAtom
|
||||||
new ParagraphFlagsTextProp(),
|
new ParagraphFlagsTextProp(),
|
||||||
new TextProp(2, 0x80, "bullet.char"),
|
new TextProp(2, 0x80, "bullet.char"),
|
||||||
new TextProp(2, 0x10, "bullet.font"),
|
new TextProp(2, 0x10, "bullet.font"),
|
||||||
new TextProp(4, 0x20, "bullet.color"),
|
|
||||||
new TextProp(2, 0x40, "bullet.size"),
|
new TextProp(2, 0x40, "bullet.size"),
|
||||||
|
new TextProp(4, 0x20, "bullet.color"),
|
||||||
new AlignmentTextProp(),
|
new AlignmentTextProp(),
|
||||||
new TextProp(2, 0x100, "text.offset"),
|
new TextProp(2, 0x100, "text.offset"),
|
||||||
new TextProp(2, 0x200, "para_unknown_2"),
|
new TextProp(2, 0x200, "para_unknown_2"),
|
||||||
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.hslf.record;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.zip.InflaterInputStream;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.POILogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ruler of a text as it differs from the style's ruler settings.
|
||||||
|
*
|
||||||
|
* @author Yegor Kozlov
|
||||||
|
*/
|
||||||
|
public class TextRulerAtom extends RecordAtom {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record header.
|
||||||
|
*/
|
||||||
|
private byte[] _header;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record data.
|
||||||
|
*/
|
||||||
|
private byte[] _data;
|
||||||
|
|
||||||
|
//ruler internals
|
||||||
|
private int defaultTabSize;
|
||||||
|
private int numLevels;
|
||||||
|
private int[] tabStops;
|
||||||
|
private int[] bulletOffsets = new int[5];
|
||||||
|
private int[] textOffsets = new int[5];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new empty ruler atom.
|
||||||
|
*/
|
||||||
|
protected TextRulerAtom() {
|
||||||
|
_header = new byte[8];
|
||||||
|
_data = new byte[0];
|
||||||
|
|
||||||
|
LittleEndian.putShort(_header, 2, (short)getRecordType());
|
||||||
|
LittleEndian.putInt(_header, 4, _data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the ruler atom record from its
|
||||||
|
* source data.
|
||||||
|
*
|
||||||
|
* @param source the source data as a byte array.
|
||||||
|
* @param start the start offset into the byte array.
|
||||||
|
* @param len the length of the slice in the byte array.
|
||||||
|
*/
|
||||||
|
protected TextRulerAtom(byte[] source, int start, int len) {
|
||||||
|
// Get the header.
|
||||||
|
_header = new byte[8];
|
||||||
|
System.arraycopy(source,start,_header,0,8);
|
||||||
|
|
||||||
|
// Get the record data.
|
||||||
|
_data = new byte[len-8];
|
||||||
|
System.arraycopy(source,start+8,_data,0,len-8);
|
||||||
|
|
||||||
|
try {
|
||||||
|
read();
|
||||||
|
} catch (Exception e){
|
||||||
|
logger.log(POILogger.ERROR, "Failed to parse TextRulerAtom: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the record type.
|
||||||
|
*
|
||||||
|
* @return the record type.
|
||||||
|
*/
|
||||||
|
public long getRecordType() {
|
||||||
|
return RecordTypes.TextRulerAtom.typeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the contents of the record back, so it can be written
|
||||||
|
* to disk.
|
||||||
|
*
|
||||||
|
* @param out the output stream to write to.
|
||||||
|
* @throws java.io.IOException if an error occurs.
|
||||||
|
*/
|
||||||
|
public void writeOut(OutputStream out) throws IOException {
|
||||||
|
out.write(_header);
|
||||||
|
out.write(_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the record bytes and initialize the internal variables
|
||||||
|
*/
|
||||||
|
private void read(){
|
||||||
|
int pos = 0;
|
||||||
|
short mask = LittleEndian.getShort(_data); pos += 4;
|
||||||
|
short val;
|
||||||
|
int[] bits = {1, 0, 2, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12};
|
||||||
|
for (int i = 0; i < bits.length; i++) {
|
||||||
|
if((mask & 1 << bits[i]) != 0){
|
||||||
|
switch (bits[i]){
|
||||||
|
case 0:
|
||||||
|
//defaultTabSize
|
||||||
|
defaultTabSize = LittleEndian.getShort(_data, pos); pos += 2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
//numLevels
|
||||||
|
numLevels = LittleEndian.getShort(_data, pos); pos += 2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
//tabStops
|
||||||
|
val = LittleEndian.getShort(_data, pos); pos += 2;
|
||||||
|
tabStops = new int[val*2];
|
||||||
|
for (int j = 0; j < tabStops.length; j++) {
|
||||||
|
tabStops[j] = LittleEndian.getUShort(_data, pos); pos += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
//bullet.offset
|
||||||
|
val = LittleEndian.getShort(_data, pos); pos += 2;
|
||||||
|
bulletOffsets[bits[i]-3] = val;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
case 9:
|
||||||
|
case 10:
|
||||||
|
case 11:
|
||||||
|
case 12:
|
||||||
|
//text.offset
|
||||||
|
val = LittleEndian.getShort(_data, pos); pos += 2;
|
||||||
|
textOffsets[bits[i]-8] = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default distance between tab stops, in master coordinates (576 dpi).
|
||||||
|
*/
|
||||||
|
public int getDefaultTabSize(){
|
||||||
|
return defaultTabSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of indent levels (maximum 5).
|
||||||
|
*/
|
||||||
|
public int getNumberOfLevels(){
|
||||||
|
return numLevels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default distance between tab stops, in master coordinates (576 dpi).
|
||||||
|
*/
|
||||||
|
public int[] getTabStops(){
|
||||||
|
return tabStops;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paragraph's distance from shape's left margin, in master coordinates (576 dpi).
|
||||||
|
*/
|
||||||
|
public int[] getTextOffsets(){
|
||||||
|
return textOffsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First line of paragraph's distance from shape's left margin, in master coordinates (576 dpi).
|
||||||
|
*/
|
||||||
|
public int[] getBulletOffsets(){
|
||||||
|
return bulletOffsets;
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,8 @@ import org.apache.poi.hslf.model.textproperties.ParagraphFlagsTextProp;
|
||||||
import org.apache.poi.hslf.model.textproperties.TextProp;
|
import org.apache.poi.hslf.model.textproperties.TextProp;
|
||||||
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
||||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||||
|
import org.apache.poi.util.POILogger;
|
||||||
|
import org.apache.poi.util.POILogFactory;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,6 +41,8 @@ import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class RichTextRun {
|
public class RichTextRun {
|
||||||
|
protected POILogger logger = POILogFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
/** The TextRun we belong to */
|
/** The TextRun we belong to */
|
||||||
private TextRun parentRun;
|
private TextRun parentRun;
|
||||||
/** The SlideShow we belong to */
|
/** The SlideShow we belong to */
|
||||||
|
@ -199,11 +203,16 @@ public class RichTextRun {
|
||||||
}
|
}
|
||||||
if (prop == null){
|
if (prop == null){
|
||||||
Sheet sheet = parentRun.getSheet();
|
Sheet sheet = parentRun.getSheet();
|
||||||
|
if(sheet != null){
|
||||||
int txtype = parentRun.getRunType();
|
int txtype = parentRun.getRunType();
|
||||||
MasterSheet master = sheet.getMasterSheet();
|
MasterSheet master = sheet.getMasterSheet();
|
||||||
if (master != null)
|
if (master != null){
|
||||||
prop = (BitMaskTextProp)master.getStyleAttribute(txtype, getIndentLevel(), propname, isCharacter);
|
prop = (BitMaskTextProp)master.getStyleAttribute(txtype, getIndentLevel(), propname, isCharacter);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logger.log(POILogger.WARN, "MasterSheet is not available");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return prop == null ? false : prop.getSubValue(index);
|
return prop == null ? false : prop.getSubValue(index);
|
||||||
}
|
}
|
||||||
|
@ -213,7 +222,7 @@ public class RichTextRun {
|
||||||
* it if required.
|
* it if required.
|
||||||
*/
|
*/
|
||||||
private void setCharFlagsTextPropVal(int index, boolean value) {
|
private void setCharFlagsTextPropVal(int index, boolean value) {
|
||||||
setFlag(true, index, value);
|
if(getFlag(true, index) != value) setFlag(true, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFlag(boolean isCharacter, int index, boolean value) {
|
public void setFlag(boolean isCharacter, int index, boolean value) {
|
||||||
|
@ -281,10 +290,14 @@ public class RichTextRun {
|
||||||
*/
|
*/
|
||||||
private int getParaTextPropVal(String propName) {
|
private int getParaTextPropVal(String propName) {
|
||||||
TextProp prop = null;
|
TextProp prop = null;
|
||||||
|
boolean hardAttribute = false;
|
||||||
if (paragraphStyle != null){
|
if (paragraphStyle != null){
|
||||||
prop = paragraphStyle.findByName(propName);
|
prop = paragraphStyle.findByName(propName);
|
||||||
|
|
||||||
|
BitMaskTextProp maskProp = (BitMaskTextProp)paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);
|
||||||
|
hardAttribute = maskProp != null && maskProp.getValue() == 0;
|
||||||
}
|
}
|
||||||
if (prop == null){
|
if (prop == null && !hardAttribute){
|
||||||
Sheet sheet = parentRun.getSheet();
|
Sheet sheet = parentRun.getSheet();
|
||||||
int txtype = parentRun.getRunType();
|
int txtype = parentRun.getRunType();
|
||||||
MasterSheet master = sheet.getMasterSheet();
|
MasterSheet master = sheet.getMasterSheet();
|
||||||
|
@ -574,6 +587,13 @@ public class RichTextRun {
|
||||||
return getFlag(false, ParagraphFlagsTextProp.BULLET_IDX);
|
return getFlag(false, ParagraphFlagsTextProp.BULLET_IDX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this rich text run has bullets
|
||||||
|
*/
|
||||||
|
public boolean isBulletHard() {
|
||||||
|
return getFlag(false, ParagraphFlagsTextProp.BULLET_IDX);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the bullet character
|
* Sets the bullet character
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -24,10 +24,7 @@ import java.util.*;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
import org.apache.poi.ddf.EscherBSERecord;
|
import org.apache.poi.ddf.*;
|
||||||
import org.apache.poi.ddf.EscherContainerRecord;
|
|
||||||
import org.apache.poi.ddf.EscherOptRecord;
|
|
||||||
import org.apache.poi.ddf.EscherRecord;
|
|
||||||
import org.apache.poi.hslf.*;
|
import org.apache.poi.hslf.*;
|
||||||
import org.apache.poi.hslf.model.*;
|
import org.apache.poi.hslf.model.*;
|
||||||
import org.apache.poi.hslf.model.Notes;
|
import org.apache.poi.hslf.model.Notes;
|
||||||
|
@ -66,8 +63,6 @@ public class SlideShow
|
||||||
// Lookup between the PersitPtr "sheet" IDs, and the position
|
// Lookup between the PersitPtr "sheet" IDs, and the position
|
||||||
// in the mostRecentCoreRecords array
|
// in the mostRecentCoreRecords array
|
||||||
private Hashtable _sheetIdToCoreRecordsLookup;
|
private Hashtable _sheetIdToCoreRecordsLookup;
|
||||||
// Used when adding new core records
|
|
||||||
private int _highestSheetId;
|
|
||||||
|
|
||||||
// Records that are interesting
|
// Records that are interesting
|
||||||
private Document _documentRecord;
|
private Document _documentRecord;
|
||||||
|
@ -203,8 +198,6 @@ public class SlideShow
|
||||||
for(int i=0; i<allIDs.length; i++) {
|
for(int i=0; i<allIDs.length; i++) {
|
||||||
_sheetIdToCoreRecordsLookup.put(new Integer(allIDs[i]), new Integer(i));
|
_sheetIdToCoreRecordsLookup.put(new Integer(allIDs[i]), new Integer(i));
|
||||||
}
|
}
|
||||||
// Capture the ID of the highest sheet
|
|
||||||
_highestSheetId = allIDs[(allIDs.length-1)];
|
|
||||||
|
|
||||||
// Now convert the byte offsets back into record offsets
|
// Now convert the byte offsets back into record offsets
|
||||||
for(int i=0; i<_records.length; i++) {
|
for(int i=0; i<_records.length; i++) {
|
||||||
|
@ -616,12 +609,6 @@ public class SlideShow
|
||||||
// Set up a new SlidePersistAtom for this slide
|
// Set up a new SlidePersistAtom for this slide
|
||||||
SlidePersistAtom sp = new SlidePersistAtom();
|
SlidePersistAtom sp = new SlidePersistAtom();
|
||||||
|
|
||||||
// Reference is the 1-based index of the slide container in
|
|
||||||
// the PersistPtr root.
|
|
||||||
// It always starts with 3 (1 is Document, 2 is MainMaster, 3 is
|
|
||||||
// the first slide), but quicksaves etc can leave gaps
|
|
||||||
_highestSheetId++;
|
|
||||||
sp.setRefID(_highestSheetId);
|
|
||||||
// First slideId is always 256
|
// First slideId is always 256
|
||||||
sp.setSlideIdentifier(prev == null ? 256 : (prev.getSlideIdentifier() + 1));
|
sp.setSlideIdentifier(prev == null ? 256 : (prev.getSlideIdentifier() + 1));
|
||||||
|
|
||||||
|
@ -631,6 +618,9 @@ public class SlideShow
|
||||||
|
|
||||||
// Create a new Slide
|
// Create a new Slide
|
||||||
Slide slide = new Slide(sp.getSlideIdentifier(), sp.getRefID(), _slides.length+1);
|
Slide slide = new Slide(sp.getSlideIdentifier(), sp.getRefID(), _slides.length+1);
|
||||||
|
slide.setSlideShow(this);
|
||||||
|
slide.onCreate();
|
||||||
|
|
||||||
// Add in to the list of Slides
|
// Add in to the list of Slides
|
||||||
Slide[] s = new Slide[_slides.length+1];
|
Slide[] s = new Slide[_slides.length+1];
|
||||||
System.arraycopy(_slides, 0, s, 0, _slides.length);
|
System.arraycopy(_slides, 0, s, 0, _slides.length);
|
||||||
|
@ -640,10 +630,10 @@ public class SlideShow
|
||||||
|
|
||||||
// Add the core records for this new Slide to the record tree
|
// Add the core records for this new Slide to the record tree
|
||||||
org.apache.poi.hslf.record.Slide slideRecord = slide.getSlideRecord();
|
org.apache.poi.hslf.record.Slide slideRecord = slide.getSlideRecord();
|
||||||
slideRecord.setSheetId(sp.getRefID());
|
|
||||||
int slideRecordPos = _hslfSlideShow.appendRootLevelRecord(slideRecord);
|
int slideRecordPos = _hslfSlideShow.appendRootLevelRecord(slideRecord);
|
||||||
_records = _hslfSlideShow.getRecords();
|
_records = _hslfSlideShow.getRecords();
|
||||||
|
|
||||||
|
|
||||||
// Add the new Slide into the PersistPtr stuff
|
// Add the new Slide into the PersistPtr stuff
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int slideOffset = 0;
|
int slideOffset = 0;
|
||||||
|
@ -668,18 +658,22 @@ public class SlideShow
|
||||||
offset += out.size();
|
offset += out.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// persist ID is UserEditAtom.maxPersistWritten + 1
|
||||||
|
int psrId = usr.getMaxPersistWritten() + 1;
|
||||||
|
sp.setRefID(psrId);
|
||||||
|
slideRecord.setSheetId(psrId);
|
||||||
|
|
||||||
|
// Last view is now of the slide
|
||||||
|
usr.setLastViewType((short)UserEditAtom.LAST_VIEW_SLIDE_VIEW);
|
||||||
|
usr.setMaxPersistWritten(psrId); //increment the number of persit objects
|
||||||
|
|
||||||
// Add the new slide into the last PersistPtr
|
// Add the new slide into the last PersistPtr
|
||||||
// (Also need to tell it where it is)
|
// (Also need to tell it where it is)
|
||||||
slideRecord.setLastOnDiskOffset(slideOffset);
|
slideRecord.setLastOnDiskOffset(slideOffset);
|
||||||
ptr.addSlideLookup(sp.getRefID(), slideOffset);
|
ptr.addSlideLookup(sp.getRefID(), slideOffset);
|
||||||
logger.log(POILogger.INFO, "New slide ended up at " + slideOffset);
|
logger.log(POILogger.INFO, "New slide ended up at " + slideOffset);
|
||||||
|
|
||||||
// Last view is now of the slide
|
|
||||||
usr.setLastViewType((short)UserEditAtom.LAST_VIEW_SLIDE_VIEW);
|
|
||||||
usr.setMaxPersistWritten(_highestSheetId);
|
|
||||||
|
|
||||||
// All done and added
|
// All done and added
|
||||||
slide.setSlideShow(this);
|
|
||||||
return slide;
|
return slide;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class TestFreeform extends TestCase {
|
||||||
Freeform p = new Freeform();
|
Freeform p = new Freeform();
|
||||||
p.setPath(path1);
|
p.setPath(path1);
|
||||||
|
|
||||||
GeneralPath path2 = p.getPath();
|
java.awt.Shape path2 = p.getOutline();
|
||||||
assertTrue(new Area(path1).equals(new Area(path2)));
|
assertTrue(new Area(path1).equals(new Area(path2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ public class TestFreeform extends TestCase {
|
||||||
Freeform p = new Freeform();
|
Freeform p = new Freeform();
|
||||||
p.setPath(path1);
|
p.setPath(path1);
|
||||||
|
|
||||||
GeneralPath path2 = p.getPath();
|
java.awt.Shape path2 = p.getOutline();
|
||||||
assertTrue(new Area(path1).equals(new Area(path2)));
|
assertTrue(new Area(path1).equals(new Area(path2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ public class TestFreeform extends TestCase {
|
||||||
Freeform p = new Freeform();
|
Freeform p = new Freeform();
|
||||||
p.setPath(path1);
|
p.setPath(path1);
|
||||||
|
|
||||||
GeneralPath path2 = p.getPath();
|
java.awt.Shape path2 = p.getOutline();
|
||||||
assertTrue(new Area(path1).equals(new Area(path2)));
|
assertTrue(new Area(path1).equals(new Area(path2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ import junit.framework.TestCase;
|
||||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||||
import org.apache.poi.hslf.usermodel.RichTextRun;
|
import org.apache.poi.hslf.usermodel.RichTextRun;
|
||||||
import org.apache.poi.hslf.HSLFSlideShow;
|
import org.apache.poi.hslf.HSLFSlideShow;
|
||||||
|
import org.apache.poi.ddf.EscherDggRecord;
|
||||||
|
import org.apache.poi.ddf.EscherDgRecord;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
|
@ -311,18 +313,49 @@ public class TestShapes extends TestCase {
|
||||||
public void testShapeId() throws IOException {
|
public void testShapeId() throws IOException {
|
||||||
SlideShow ppt = new SlideShow();
|
SlideShow ppt = new SlideShow();
|
||||||
Slide slide = ppt.createSlide();
|
Slide slide = ppt.createSlide();
|
||||||
Shape shape;
|
Shape shape = null;
|
||||||
|
|
||||||
|
//EscherDgg is a document-level record which keeps track of the drawing groups
|
||||||
|
EscherDggRecord dgg = ppt.getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
|
||||||
|
EscherDgRecord dg = slide.getSheetContainer().getPPDrawing().getEscherDgRecord();
|
||||||
|
|
||||||
|
int dggShapesUsed = dgg.getNumShapesSaved(); //total number of shapes in the ppt
|
||||||
|
int dggMaxId = dgg.getShapeIdMax(); //max number of shapeId
|
||||||
|
|
||||||
|
int dgMaxId = dg.getLastMSOSPID(); //max shapeId in the slide
|
||||||
|
int dgShapesUsed = dg.getNumShapes(); // number of shapes in the slide
|
||||||
|
//insert 3 shapes and make sure the Ids are properly incremented
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
shape = new Line();
|
shape = new Line();
|
||||||
assertEquals(0, shape.getShapeId());
|
assertEquals(0, shape.getShapeId());
|
||||||
slide.addShape(shape);
|
slide.addShape(shape);
|
||||||
assertTrue(shape.getShapeId() > 0);
|
assertTrue(shape.getShapeId() > 0);
|
||||||
|
|
||||||
int shapeId = shape.getShapeId();
|
//check that EscherDgRecord is updated
|
||||||
|
assertEquals(shape.getShapeId(), dg.getLastMSOSPID());
|
||||||
|
assertEquals(dgMaxId + 1, dg.getLastMSOSPID());
|
||||||
|
assertEquals(dgShapesUsed + 1, dg.getNumShapes());
|
||||||
|
|
||||||
|
//check that EscherDggRecord is updated
|
||||||
|
assertEquals(shape.getShapeId() + 1, dgg.getShapeIdMax());
|
||||||
|
assertEquals(dggMaxId + 1, dgg.getShapeIdMax());
|
||||||
|
assertEquals(dggShapesUsed + 1, dgg.getNumShapesSaved());
|
||||||
|
|
||||||
|
dggShapesUsed = dgg.getNumShapesSaved();
|
||||||
|
dggMaxId = dgg.getShapeIdMax();
|
||||||
|
dgMaxId = dg.getLastMSOSPID();
|
||||||
|
dgShapesUsed = dg.getNumShapes();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//For each drawing group PPT allocates clusters with size=1024
|
||||||
|
//if the number of shapes is greater that 1024 a new cluster is allocated
|
||||||
|
//make sure it is so
|
||||||
|
int numClusters = dgg.getNumIdClusters();
|
||||||
|
for (int i = 0; i < 1025; i++) {
|
||||||
shape = new Line();
|
shape = new Line();
|
||||||
assertEquals(0, shape.getShapeId());
|
|
||||||
slide.addShape(shape);
|
slide.addShape(shape);
|
||||||
assertEquals(shapeId + 1, shape.getShapeId());
|
}
|
||||||
|
assertEquals(numClusters + 1, dgg.getNumIdClusters());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
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.record;
|
||||||
|
|
||||||
|
import org.apache.poi.hslf.HSLFSlideShow;
|
||||||
|
import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;
|
||||||
|
import org.apache.poi.hslf.model.textproperties.TextProp;
|
||||||
|
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
||||||
|
import org.apache.poi.hslf.record.StyleTextPropAtom.*;
|
||||||
|
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests TextRulerAtom
|
||||||
|
*
|
||||||
|
* @author Yegor Kozlov
|
||||||
|
*/
|
||||||
|
public class TestTextRulerAtom extends TestCase {
|
||||||
|
|
||||||
|
//from a real file
|
||||||
|
private byte[] data_1 = new byte[] {
|
||||||
|
0x00, 0x00, (byte)0xA6, 0x0F, 0x18, 0x00, 0x00, 0x00,
|
||||||
|
(byte)0xF8, 0x1F, 0x00, 0x00, 0x75, 0x00, (byte)0xE2, 0x00, 0x59,
|
||||||
|
0x01, (byte)0xC3, 0x01, 0x1A, 0x03, (byte)0x87, 0x03, (byte)0xF8,
|
||||||
|
0x03, 0x69, 0x04, (byte)0xF6, 0x05, (byte)0xF6, 0x05
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public void testReadRuler() throws Exception {
|
||||||
|
TextRulerAtom ruler = new TextRulerAtom(data_1, 0, data_1.length);
|
||||||
|
assertEquals(ruler.getNumberOfLevels(), 0);
|
||||||
|
assertEquals(ruler.getDefaultTabSize(), 0);
|
||||||
|
|
||||||
|
int[] tabStops = ruler.getTabStops();
|
||||||
|
assertNull(tabStops);
|
||||||
|
|
||||||
|
int[] textOffsets = ruler.getTextOffsets();
|
||||||
|
assertTrue(Arrays.equals(new int[]{226, 451, 903, 1129, 1526}, textOffsets));
|
||||||
|
|
||||||
|
int[] bulletOffsets = ruler.getBulletOffsets();
|
||||||
|
assertTrue(Arrays.equals(new int[]{117, 345, 794, 1016, 1526}, bulletOffsets));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWriteRuler() throws Exception {
|
||||||
|
TextRulerAtom ruler = new TextRulerAtom(data_1, 0, data_1.length);
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
ruler.writeOut(out);
|
||||||
|
|
||||||
|
byte[] result = out.toByteArray();
|
||||||
|
assertTrue(Arrays.equals(result, data_1));
|
||||||
|
}
|
||||||
|
}
|
|
@ -90,8 +90,10 @@ public class TestRichTextRun extends TestCase {
|
||||||
|
|
||||||
// Now set it to not bold
|
// Now set it to not bold
|
||||||
rtr.setBold(false);
|
rtr.setBold(false);
|
||||||
assertNotNull(rtr._getRawCharacterStyle());
|
//setting bold=false doesn't change the internal state
|
||||||
assertNotNull(rtr._getRawParagraphStyle());
|
assertNull(rtr._getRawCharacterStyle());
|
||||||
|
assertNull(rtr._getRawParagraphStyle());
|
||||||
|
|
||||||
assertFalse(rtr.isBold());
|
assertFalse(rtr.isBold());
|
||||||
|
|
||||||
// And now make it bold
|
// And now make it bold
|
||||||
|
|
|
@ -42,6 +42,7 @@ public final class AllPOIDDFTests {
|
||||||
result.addTestSuite(TestEscherSplitMenuColorsRecord.class);
|
result.addTestSuite(TestEscherSplitMenuColorsRecord.class);
|
||||||
result.addTestSuite(TestEscherSpRecord.class);
|
result.addTestSuite(TestEscherSpRecord.class);
|
||||||
result.addTestSuite(TestUnknownEscherRecord.class);
|
result.addTestSuite(TestUnknownEscherRecord.class);
|
||||||
|
result.addTestSuite(TestEscherBlipRecord.class);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
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.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test read/serialize of escher blip records
|
||||||
|
*
|
||||||
|
* @author Yegor Kozlov
|
||||||
|
*/
|
||||||
|
public class TestEscherBlipRecord extends TestCase
|
||||||
|
{
|
||||||
|
protected String cwd = System.getProperty("DDF.testdata.path");
|
||||||
|
|
||||||
|
//test reading/serializing of a PNG blip
|
||||||
|
public void testReadPNG() throws IOException {
|
||||||
|
//provided in bug-44886
|
||||||
|
byte[] data = read(new File(cwd, "Container.dat"));
|
||||||
|
|
||||||
|
EscherContainerRecord record = new EscherContainerRecord();
|
||||||
|
record.fillFields(data, 0, new DefaultEscherRecordFactory());
|
||||||
|
EscherContainerRecord bstore = (EscherContainerRecord)record.getChildRecords().get(1);
|
||||||
|
EscherBSERecord bse1 = (EscherBSERecord)bstore.getChildRecords().get(0);
|
||||||
|
assertEquals(EscherBSERecord.BT_PNG, bse1.getBlipTypeWin32());
|
||||||
|
assertEquals(EscherBSERecord.BT_PNG, bse1.getBlipTypeMacOS());
|
||||||
|
assertTrue(Arrays.equals(new byte[]{
|
||||||
|
0x65, 0x07, 0x4A, (byte)0x8D, 0x3E, 0x42, (byte)0x8B, (byte)0xAC,
|
||||||
|
0x1D, (byte)0x89, 0x35, 0x4F, 0x48, (byte)0xFA, 0x37, (byte)0xC2
|
||||||
|
}, bse1.getUid()));
|
||||||
|
assertEquals(255, bse1.getTag());
|
||||||
|
assertEquals(32308, bse1.getSize());
|
||||||
|
|
||||||
|
EscherBitmapBlip blip1 = (EscherBitmapBlip)bse1.getBlipRecord();
|
||||||
|
assertEquals(0x6E00, blip1.getOptions());
|
||||||
|
assertEquals(EscherBitmapBlip.RECORD_ID_PNG, blip1.getRecordId());
|
||||||
|
assertTrue(Arrays.equals(new byte[]{
|
||||||
|
0x65, 0x07, 0x4A, (byte)0x8D, 0x3E, 0x42, (byte)0x8B, (byte)0xAC,
|
||||||
|
0x1D, (byte)0x89, 0x35, 0x4F, 0x48, (byte)0xFA, 0x37, (byte)0xC2
|
||||||
|
}, blip1.getUID()));
|
||||||
|
|
||||||
|
//serialize and read again
|
||||||
|
byte[] ser = bse1.serialize();
|
||||||
|
EscherBSERecord bse2 = new EscherBSERecord();
|
||||||
|
bse2.fillFields(ser, 0, new DefaultEscherRecordFactory());
|
||||||
|
assertEquals(bse1.getRecordId(), bse2.getRecordId());
|
||||||
|
assertEquals(bse1.getBlipTypeWin32(), bse2.getBlipTypeWin32());
|
||||||
|
assertEquals(bse1.getBlipTypeMacOS(), bse2.getBlipTypeMacOS());
|
||||||
|
assertTrue(Arrays.equals(bse1.getUid(), bse2.getUid()));
|
||||||
|
assertEquals(bse1.getTag(), bse2.getTag());
|
||||||
|
assertEquals(bse1.getSize(), bse2.getSize());
|
||||||
|
|
||||||
|
EscherBitmapBlip blip2 = (EscherBitmapBlip)bse1.getBlipRecord();
|
||||||
|
assertEquals(blip1.getOptions(), blip2.getOptions());
|
||||||
|
assertEquals(blip1.getRecordId(), blip2.getRecordId());
|
||||||
|
assertEquals(blip1.getUID(), blip2.getUID());
|
||||||
|
|
||||||
|
assertTrue(Arrays.equals(blip1.getPicturedata(), blip1.getPicturedata()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//test reading/serializing of a PICT metafile
|
||||||
|
public void testReadPICT() throws IOException {
|
||||||
|
//provided in bug-44886
|
||||||
|
byte[] data = read(new File(cwd, "Container.dat"));
|
||||||
|
|
||||||
|
EscherContainerRecord record = new EscherContainerRecord();
|
||||||
|
record.fillFields(data, 0, new DefaultEscherRecordFactory());
|
||||||
|
EscherContainerRecord bstore = (EscherContainerRecord)record.getChildRecords().get(1);
|
||||||
|
EscherBSERecord bse1 = (EscherBSERecord)bstore.getChildRecords().get(1);
|
||||||
|
//System.out.println(bse1);
|
||||||
|
assertEquals(EscherBSERecord.BT_WMF, bse1.getBlipTypeWin32());
|
||||||
|
assertEquals(EscherBSERecord.BT_PICT, bse1.getBlipTypeMacOS());
|
||||||
|
assertTrue(Arrays.equals(new byte[]{
|
||||||
|
(byte)0xC7, 0x15, 0x69, 0x2D, (byte)0xE5, (byte)0x89, (byte)0xA3, 0x6F,
|
||||||
|
0x66, 0x03, (byte)0xD6, 0x24, (byte)0xF7, (byte)0xDB, 0x1D, 0x13
|
||||||
|
}, bse1.getUid()));
|
||||||
|
assertEquals(255, bse1.getTag());
|
||||||
|
assertEquals(1133, bse1.getSize());
|
||||||
|
|
||||||
|
EscherMetafileBlip blip1 = (EscherMetafileBlip)bse1.getBlipRecord();
|
||||||
|
assertEquals(0x5430, blip1.getOptions());
|
||||||
|
assertEquals(EscherMetafileBlip.RECORD_ID_PICT, blip1.getRecordId());
|
||||||
|
assertTrue(Arrays.equals(new byte[]{
|
||||||
|
0x57, 0x32, 0x7B, (byte)0x91, 0x23, 0x5D, (byte)0xDB, 0x36,
|
||||||
|
0x7A, (byte)0xDB, (byte)0xFF, 0x17, (byte)0xFE, (byte)0xF3, (byte)0xA7, 0x05
|
||||||
|
}, blip1.getUID()));
|
||||||
|
assertTrue(Arrays.equals(new byte[]{
|
||||||
|
(byte)0xC7, 0x15, 0x69, 0x2D, (byte)0xE5, (byte)0x89, (byte)0xA3, 0x6F,
|
||||||
|
0x66, 0x03, (byte)0xD6, 0x24, (byte)0xF7, (byte)0xDB, 0x1D, 0x13
|
||||||
|
}, blip1.getPrimaryUID()));
|
||||||
|
|
||||||
|
//serialize and read again
|
||||||
|
byte[] ser = bse1.serialize();
|
||||||
|
EscherBSERecord bse2 = new EscherBSERecord();
|
||||||
|
bse2.fillFields(ser, 0, new DefaultEscherRecordFactory());
|
||||||
|
assertEquals(bse1.getRecordId(), bse2.getRecordId());
|
||||||
|
assertEquals(bse1.getOptions(), bse2.getOptions());
|
||||||
|
assertEquals(bse1.getBlipTypeWin32(), bse2.getBlipTypeWin32());
|
||||||
|
assertEquals(bse1.getBlipTypeMacOS(), bse2.getBlipTypeMacOS());
|
||||||
|
assertTrue(Arrays.equals(bse1.getUid(), bse2.getUid()));
|
||||||
|
assertEquals(bse1.getTag(), bse2.getTag());
|
||||||
|
assertEquals(bse1.getSize(), bse2.getSize());
|
||||||
|
|
||||||
|
EscherMetafileBlip blip2 = (EscherMetafileBlip)bse1.getBlipRecord();
|
||||||
|
assertEquals(blip1.getOptions(), blip2.getOptions());
|
||||||
|
assertEquals(blip1.getRecordId(), blip2.getRecordId());
|
||||||
|
assertEquals(blip1.getUID(), blip2.getUID());
|
||||||
|
assertEquals(blip1.getPrimaryUID(), blip2.getPrimaryUID());
|
||||||
|
|
||||||
|
assertTrue(Arrays.equals(blip1.getPicturedata(), blip1.getPicturedata()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//integral test: check that the read-write-read round trip is consistent
|
||||||
|
public void testContainer() throws IOException {
|
||||||
|
byte[] data = read(new File(cwd, "Container.dat"));
|
||||||
|
|
||||||
|
EscherContainerRecord record = new EscherContainerRecord();
|
||||||
|
record.fillFields(data, 0, new DefaultEscherRecordFactory());
|
||||||
|
|
||||||
|
byte[] ser = record.serialize();
|
||||||
|
assertTrue(Arrays.equals(data, ser));
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] read(File file) throws IOException {
|
||||||
|
byte[] data = new byte[(int)file.length()];
|
||||||
|
FileInputStream is = new FileInputStream(file);
|
||||||
|
is.read(data);
|
||||||
|
is.close();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,12 +18,23 @@
|
||||||
|
|
||||||
package org.apache.poi.ddf;
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import org.apache.poi.util.HexRead;
|
import org.apache.poi.util.HexRead;
|
||||||
import org.apache.poi.util.HexDump;
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.IOUtils;
|
||||||
|
|
||||||
public class TestEscherContainerRecord extends TestCase
|
public class TestEscherContainerRecord extends TestCase
|
||||||
{
|
{
|
||||||
|
private String ESCHER_DATA_PATH;
|
||||||
|
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
ESCHER_DATA_PATH = System.getProperty("DDF.testdata.path");
|
||||||
|
}
|
||||||
|
|
||||||
public void testFillFields() throws Exception
|
public void testFillFields() throws Exception
|
||||||
{
|
{
|
||||||
EscherRecordFactory f = new DefaultEscherRecordFactory();
|
EscherRecordFactory f = new DefaultEscherRecordFactory();
|
||||||
|
@ -137,4 +148,19 @@ public class TestEscherContainerRecord extends TestCase
|
||||||
assertEquals(18, r.getRecordSize());
|
assertEquals(18, r.getRecordSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We were having problems with reading too much data on an UnknownEscherRecord,
|
||||||
|
* but hopefully we now read the correct size.
|
||||||
|
*/
|
||||||
|
public void testBug44857() throws Exception {
|
||||||
|
File f = new File(ESCHER_DATA_PATH, "Container.dat");
|
||||||
|
assertTrue(f.exists());
|
||||||
|
|
||||||
|
FileInputStream finp = new FileInputStream(f);
|
||||||
|
byte[] data = IOUtils.toByteArray(finp);
|
||||||
|
|
||||||
|
// This used to fail with an OutOfMemory
|
||||||
|
EscherContainerRecord record = new EscherContainerRecord();
|
||||||
|
record.fillFields(data, 0, new DefaultEscherRecordFactory());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -172,4 +172,28 @@ public final class HSSFTestDataSamples {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return byte array of sample file content from file found in standard hssf test data dir
|
||||||
|
*/
|
||||||
|
public static byte[] getTestDataFileContent(String fileName) {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
try {
|
||||||
|
InputStream fis = HSSFTestDataSamples.openSampleFileStream(fileName);
|
||||||
|
|
||||||
|
byte[] buf = new byte[512];
|
||||||
|
while (true) {
|
||||||
|
int bytesRead = fis.read(buf);
|
||||||
|
if (bytesRead < 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bos.write(buf, 0, bytesRead);
|
||||||
|
}
|
||||||
|
fis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return bos.toByteArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -592,7 +592,7 @@ public final class TestFormulaParser extends TestCase {
|
||||||
HSSFWorkbook book = new HSSFWorkbook();
|
HSSFWorkbook book = new HSSFWorkbook();
|
||||||
|
|
||||||
Ptg[] ptgs = {
|
Ptg[] ptgs = {
|
||||||
new FuncPtg(10, 0),
|
new FuncPtg(10),
|
||||||
};
|
};
|
||||||
assertEquals("NA()", FormulaParser.toFormulaString(book, ptgs));
|
assertEquals("NA()", FormulaParser.toFormulaString(book, ptgs));
|
||||||
}
|
}
|
||||||
|
@ -900,4 +900,21 @@ public final class TestFormulaParser extends TestCase {
|
||||||
assertEquals(2, ptgs.length);
|
assertEquals(2, ptgs.length);
|
||||||
assertEquals(FuncPtg.class, ptgs[1].getClass());
|
assertEquals(FuncPtg.class, ptgs[1].getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testWrongNumberOfFunctionArgs() {
|
||||||
|
confirmArgCountMsg("sin()", "Too few arguments to function 'SIN'. Expected 1 but got 0.");
|
||||||
|
confirmArgCountMsg("countif(1, 2, 3, 4)", "Too many arguments to function 'COUNTIF'. Expected 2 but got 4.");
|
||||||
|
confirmArgCountMsg("index(1, 2, 3, 4, 5, 6)", "Too many arguments to function 'INDEX'. At most 4 were expected but got 6.");
|
||||||
|
confirmArgCountMsg("vlookup(1, 2)", "Too few arguments to function 'VLOOKUP'. At least 3 were expected but got 2.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void confirmArgCountMsg(String formula, String expectedMessage) {
|
||||||
|
HSSFWorkbook book = new HSSFWorkbook();
|
||||||
|
try {
|
||||||
|
FormulaParser.parse(formula, book);
|
||||||
|
throw new AssertionFailedError("Didn't get parse exception as expected");
|
||||||
|
} catch (FormulaParseException e) {
|
||||||
|
assertEquals(expectedMessage, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ public final class AllFormulaTests {
|
||||||
result.addTestSuite(TestErrPtg.class);
|
result.addTestSuite(TestErrPtg.class);
|
||||||
result.addTestSuite(TestExternalFunctionFormulas.class);
|
result.addTestSuite(TestExternalFunctionFormulas.class);
|
||||||
result.addTestSuite(TestFuncPtg.class);
|
result.addTestSuite(TestFuncPtg.class);
|
||||||
|
result.addTestSuite(TestFuncVarPtg.class);
|
||||||
result.addTestSuite(TestIntersectionPtg.class);
|
result.addTestSuite(TestIntersectionPtg.class);
|
||||||
result.addTestSuite(TestPercentPtg.class);
|
result.addTestSuite(TestPercentPtg.class);
|
||||||
result.addTestSuite(TestRangePtg.class);
|
result.addTestSuite(TestRangePtg.class);
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.hssf.record.formula;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.model.FormulaParser;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
/**
|
||||||
|
* @author Josh Micich
|
||||||
|
*/
|
||||||
|
public final class TestFuncVarPtg extends TestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first fix for bugzilla 44675 broke the encoding of SUM formulas (and probably others).
|
||||||
|
* The operand classes of the parameters to SUM() should be coerced to 'reference' not 'value'.
|
||||||
|
* In the case of SUM, Excel evaluates the formula to '#VALUE!' if a parameter operand class is
|
||||||
|
* wrong. In other cases Excel seems to tolerate bad operand classes.</p>
|
||||||
|
* This functionality is related to the setParameterRVA() methods of <tt>FormulaParser</tt>
|
||||||
|
*/
|
||||||
|
public void testOperandClass() {
|
||||||
|
HSSFWorkbook book = new HSSFWorkbook();
|
||||||
|
Ptg[] ptgs = FormulaParser.parse("sum(A1:A2)", book);
|
||||||
|
assertEquals(2, ptgs.length);
|
||||||
|
assertEquals(AreaPtg.class, ptgs[0].getClass());
|
||||||
|
|
||||||
|
switch(ptgs[0].getPtgClass()) {
|
||||||
|
case Ptg.CLASS_REF:
|
||||||
|
// correct behaviour
|
||||||
|
break;
|
||||||
|
case Ptg.CLASS_VALUE:
|
||||||
|
throw new AssertionFailedError("Identified bug 44675b");
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Unexpected operand class");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
@ -18,20 +17,22 @@
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link ReferencePtg}.
|
* Tests for {@link ReferencePtg}.
|
||||||
*/
|
*/
|
||||||
public class TestReferencePtg extends AbstractPtgTestCase
|
public final class TestReferencePtg extends TestCase {
|
||||||
{
|
|
||||||
/**
|
/**
|
||||||
* Tests reading a file containing this ptg.
|
* Tests reading a file containing this ptg.
|
||||||
*/
|
*/
|
||||||
public void testReading() throws Exception
|
public void testReading() {
|
||||||
{
|
HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook("ReferencePtg.xls");
|
||||||
HSSFWorkbook workbook = loadWorkbook("ReferencePtg.xls");
|
|
||||||
HSSFSheet sheet = workbook.getSheetAt(0);
|
HSSFSheet sheet = workbook.getSheetAt(0);
|
||||||
|
|
||||||
// First row
|
// First row
|
||||||
|
@ -72,6 +73,18 @@ public class TestReferencePtg extends AbstractPtgTestCase
|
||||||
assertEquals("Wrong formula string for reference", "A32770",
|
assertEquals("Wrong formula string for reference", "A32770",
|
||||||
sheet.getRow(32769).getCell((short) 1).getCellFormula());
|
sheet.getRow(32769).getCell((short) 1).getCellFormula());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testBug44921() {
|
||||||
|
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ex44921-21902.xls");
|
||||||
|
|
||||||
|
try {
|
||||||
|
HSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
if(e.getMessage().equals("Coding Error: This method should never be called. This ptg should be converted")) {
|
||||||
|
throw new AssertionFailedError("Identified bug 44921");
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ public class AllUserModelTests {
|
||||||
result.addTestSuite(TestHSSFHeaderFooter.class);
|
result.addTestSuite(TestHSSFHeaderFooter.class);
|
||||||
result.addTestSuite(TestHSSFHyperlink.class);
|
result.addTestSuite(TestHSSFHyperlink.class);
|
||||||
result.addTestSuite(TestHSSFPalette.class);
|
result.addTestSuite(TestHSSFPalette.class);
|
||||||
|
result.addTestSuite(TestHSSFPatriarch.class);
|
||||||
result.addTestSuite(TestHSSFPicture.class);
|
result.addTestSuite(TestHSSFPicture.class);
|
||||||
result.addTestSuite(TestHSSFPictureData.class);
|
result.addTestSuite(TestHSSFPictureData.class);
|
||||||
result.addTestSuite(TestHSSFRichTextString.class);
|
result.addTestSuite(TestHSSFRichTextString.class);
|
||||||
|
|
|
@ -882,10 +882,20 @@ public final class TestBugs extends TestCase {
|
||||||
* Bug 28774: Excel will crash when opening xls-files with images.
|
* Bug 28774: Excel will crash when opening xls-files with images.
|
||||||
*/
|
*/
|
||||||
public void test28774() {
|
public void test28774() {
|
||||||
|
|
||||||
HSSFWorkbook wb = openSample("28774.xls");
|
HSSFWorkbook wb = openSample("28774.xls");
|
||||||
assertTrue("no errors reading sample xls", true);
|
assertTrue("no errors reading sample xls", true);
|
||||||
writeOutAndReadBack(wb);
|
writeOutAndReadBack(wb);
|
||||||
assertTrue("no errors writing sample xls", true);
|
assertTrue("no errors writing sample xls", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Had a problem apparently, not sure what as it
|
||||||
|
* works just fine...
|
||||||
|
*/
|
||||||
|
public void test44891() throws Exception {
|
||||||
|
HSSFWorkbook wb = openSample("44891.xls");
|
||||||
|
assertTrue("no errors reading sample xls", true);
|
||||||
|
writeOutAndReadBack(wb);
|
||||||
|
assertTrue("no errors writing sample xls", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
@ -252,4 +253,29 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
|
||||||
}
|
}
|
||||||
assertEquals(true, cell.getBooleanCellValue());
|
assertEquals(true, cell.getBooleanCellValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testClassCast_bug44861() throws Exception {
|
||||||
|
HSSFWorkbook wb = HSSFTestDataSamples.
|
||||||
|
openSampleWorkbook("44861.xls");
|
||||||
|
|
||||||
|
// Check direct
|
||||||
|
HSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||||
|
|
||||||
|
// And via calls
|
||||||
|
int numSheets = wb.getNumberOfSheets();
|
||||||
|
for(int i=0; i<numSheets; i++) {
|
||||||
|
HSSFSheet s = wb.getSheetAt(i);
|
||||||
|
HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(s,wb);
|
||||||
|
|
||||||
|
for(Iterator rows = s.rowIterator(); rows.hasNext();) {
|
||||||
|
HSSFRow r = (HSSFRow)rows.next();
|
||||||
|
eval.setCurrentRow(r);
|
||||||
|
|
||||||
|
for(Iterator cells = r.cellIterator(); cells.hasNext();) {
|
||||||
|
HSSFCell c = (HSSFCell)cells.next();
|
||||||
|
eval.evaluateFormulaCell(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.hssf.usermodel;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Josh Micich
|
||||||
|
*/
|
||||||
|
public final class TestHSSFPatriarch extends TestCase {
|
||||||
|
|
||||||
|
public void testBasic() {
|
||||||
|
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
HSSFSheet sheet = wb.createSheet();
|
||||||
|
|
||||||
|
HSSFPatriarch patr = sheet.createDrawingPatriarch();
|
||||||
|
|
||||||
|
assertNotNull(patr);
|
||||||
|
|
||||||
|
// assert something more interesting
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - fix bug 44916 (1-May-2008)
|
||||||
|
public void DISABLED_test44916() {
|
||||||
|
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
HSSFSheet sheet = wb.createSheet();
|
||||||
|
|
||||||
|
// 1. Create drawing patriarch
|
||||||
|
HSSFPatriarch patr = sheet.createDrawingPatriarch();
|
||||||
|
|
||||||
|
// 2. Try to re-get the patriarch
|
||||||
|
HSSFPatriarch existingPatr;
|
||||||
|
try {
|
||||||
|
existingPatr = sheet.getDrawingPatriarch();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
throw new AssertionFailedError("Identified bug 44916");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Use patriarch
|
||||||
|
HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 600, 245, (short) 1, 1, (short) 1, 2);
|
||||||
|
anchor.setAnchorType(3);
|
||||||
|
byte[] pictureData = HSSFTestDataSamples.getTestDataFileContent("logoKarmokar4.png");
|
||||||
|
int idx1 = wb.addPicture(pictureData, HSSFWorkbook.PICTURE_TYPE_PNG);
|
||||||
|
patr.createPicture(anchor, idx1);
|
||||||
|
|
||||||
|
// 4. Try to re-use patriarch later
|
||||||
|
existingPatr = sheet.getDrawingPatriarch();
|
||||||
|
assertNotNull(existingPatr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,10 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
|
@ -36,7 +32,7 @@ public final class TestHSSFPicture extends TestCase{
|
||||||
HSSFSheet sh1 = wb.createSheet();
|
HSSFSheet sh1 = wb.createSheet();
|
||||||
HSSFPatriarch p1 = sh1.createDrawingPatriarch();
|
HSSFPatriarch p1 = sh1.createDrawingPatriarch();
|
||||||
|
|
||||||
byte[] pictureData = getTestDataFileContent("logoKarmokar4.png");
|
byte[] pictureData = HSSFTestDataSamples.getTestDataFileContent("logoKarmokar4.png");
|
||||||
int idx1 = wb.addPicture( pictureData, HSSFWorkbook.PICTURE_TYPE_PNG );
|
int idx1 = wb.addPicture( pictureData, HSSFWorkbook.PICTURE_TYPE_PNG );
|
||||||
HSSFPicture picture1 = p1.createPicture(new HSSFClientAnchor(), idx1);
|
HSSFPicture picture1 = p1.createPicture(new HSSFClientAnchor(), idx1);
|
||||||
HSSFClientAnchor anchor1 = picture1.getPreferredSize();
|
HSSFClientAnchor anchor1 = picture1.getPreferredSize();
|
||||||
|
@ -51,28 +47,4 @@ public final class TestHSSFPicture extends TestCase{
|
||||||
assertEquals(848, anchor1.getDx2());
|
assertEquals(848, anchor1.getDx2());
|
||||||
assertEquals(240, anchor1.getDy2());
|
assertEquals(240, anchor1.getDy2());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Copied from org.apache.poi.hssf.usermodel.examples.OfficeDrawing
|
|
||||||
*/
|
|
||||||
private static byte[] getTestDataFileContent(String fileName) {
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
try {
|
|
||||||
InputStream fis = HSSFTestDataSamples.openSampleFileStream(fileName);
|
|
||||||
|
|
||||||
byte[] buf = new byte[512];
|
|
||||||
while(true) {
|
|
||||||
int bytesRead = fis.read(buf);
|
|
||||||
if(bytesRead < 1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bos.write(buf, 0, bytesRead);
|
|
||||||
}
|
|
||||||
fis.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
return bos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
|
@ -40,6 +41,23 @@ public final class TestHSSFWorkbook extends TestCase {
|
||||||
assertEquals( 3, nameRecord.getIndexToSheet() );
|
assertEquals( 3, nameRecord.getIndexToSheet() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testCaseInsensitiveNames() {
|
||||||
|
HSSFWorkbook b = new HSSFWorkbook( );
|
||||||
|
HSSFSheet originalSheet = b.createSheet("Sheet1");
|
||||||
|
HSSFSheet fetchedSheet = b.getSheet("sheet1");
|
||||||
|
if(fetchedSheet == null) {
|
||||||
|
throw new AssertionFailedError("Identified bug 44892");
|
||||||
|
}
|
||||||
|
assertEquals(originalSheet, fetchedSheet);
|
||||||
|
try {
|
||||||
|
b.createSheet("sHeeT1");
|
||||||
|
fail("should have thrown exceptiuon due to duplicate sheet name");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// expected during successful test
|
||||||
|
assertEquals("The workbook already contains a sheet of this name", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void testDuplicateNames() {
|
public void testDuplicateNames() {
|
||||||
HSSFWorkbook b = new HSSFWorkbook( );
|
HSSFWorkbook b = new HSSFWorkbook( );
|
||||||
b.createSheet("Sheet1");
|
b.createSheet("Sheet1");
|
||||||
|
|
Loading…
Reference in New Issue