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.test.dir" location="build/test-classes"/>
|
||||
<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.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"/>
|
||||
|
@ -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.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.src" location="build/tmp/site"/>
|
||||
<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.oap.dir" location="build/maven-dist/org.apache.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="jdk.version.source" value="1.3"
|
||||
description="JDK version of source code"/>
|
||||
|
@ -195,15 +167,6 @@ under the License.
|
|||
<pathelement location="${contrib.output.test.dir}"/>
|
||||
</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 refid="main.classpath"/>
|
||||
<pathelement location="${main.output.dir}"/>
|
||||
|
@ -268,15 +231,12 @@ under the License.
|
|||
<mkdir dir="${scratchpad.output.dir}"/>
|
||||
<mkdir dir="${contrib.output.dir}"/>
|
||||
<mkdir dir="${examples.output.dir}"/>
|
||||
<mkdir dir="${ooxml.output.dir}"/>
|
||||
<mkdir dir="${main.output.test.dir}"/>
|
||||
<mkdir dir="${contrib.output.test.dir}"/>
|
||||
<mkdir dir="${scratchpad.output.test.dir}"/>
|
||||
<mkdir dir="${ooxml.output.test.dir}"/>
|
||||
<mkdir dir="${main.reports.test}"/>
|
||||
<mkdir dir="${scratchpad.reports.test}"/>
|
||||
<mkdir dir="${contrib.reports.test}"/>
|
||||
<mkdir dir="${ooxml.reports.test}"/>
|
||||
<mkdir dir="${junit.report.dir}"/>
|
||||
<mkdir dir="${jdepend.report.dir}"/>
|
||||
<mkdir dir="${jdepend.report.out.dir}"/>
|
||||
|
@ -311,11 +271,6 @@ under the License.
|
|||
<available file="${contrib.jar2.dir}"/>
|
||||
<available file="${contrib.jar3.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>
|
||||
<isset property="disconnected"/>
|
||||
</or>
|
||||
|
@ -330,67 +285,8 @@ under the License.
|
|||
<get src="${contrib.jar2.url}" dest="${contrib.jar2.dir}"/>
|
||||
<get src="${contrib.jar3.url}" dest="${contrib.jar3.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 name="compile" depends="init, compile-main, compile-scratchpad,
|
||||
compile-contrib, compile-examples"
|
||||
description="Compiles the POI main classes, scratchpad, contrib, and examples"/>
|
||||
|
@ -473,24 +369,6 @@ under the License.
|
|||
</javac>
|
||||
</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"
|
||||
description="Tests main, contrib and scratchpad"/>
|
||||
|
||||
|
@ -523,6 +401,8 @@ under the License.
|
|||
file="${main.src.test}/org/apache/poi/hpsf/data"/>
|
||||
<sysproperty key="POIFS.testdata.path"
|
||||
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"/>
|
||||
<formatter type="plain"/>
|
||||
<formatter type="xml"/>
|
||||
|
@ -725,43 +605,6 @@ under the License.
|
|||
<echo file="${contrib.testokfile}" append="false" message="testok"/>
|
||||
</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">
|
||||
<uptodate property="main.docs.notRequired" targetfile="${build.site}/index.html">
|
||||
<srcfiles dir="${build.site.src}"/>
|
||||
|
@ -1148,21 +991,6 @@ FORREST_HOME environment variable!</echo>
|
|||
</manifest>
|
||||
</jar>
|
||||
</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"
|
||||
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">
|
||||
<zipfileset dir="legal/" prefix="${zipdir}" />
|
||||
<zipfileset dir="lib/" prefix="${zipdir}/lib" />
|
||||
<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}-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"
|
||||
compression="gzip">
|
||||
<tarfileset dir="legal/" prefix="${zipdir}" />
|
||||
<tarfileset dir="lib/" prefix="${zipdir}/lib" />
|
||||
<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}-contrib-${version.id}-${DSTAMP}.jar" prefix="${zipdir}" />
|
||||
|
|
|
@ -36,7 +36,17 @@
|
|||
</devs>
|
||||
|
||||
<!-- 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: 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>
|
||||
|
|
|
@ -31,6 +31,23 @@
|
|||
</header>
|
||||
|
||||
<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>
|
||||
<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
|
||||
|
|
|
@ -33,7 +33,17 @@
|
|||
|
||||
<!-- Don't forget to update changes.xml too! -->
|
||||
<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: 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>
|
||||
|
|
|
@ -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
|
||||
|
||||
(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
|
||||
|
||||
{code}
|
||||
|
@ -46,7 +50,7 @@ https://svn.apache.org/repos/asf/poi/trunk
|
|||
|
||||
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}
|
||||
ant build
|
||||
{code}
|
||||
|
@ -109,27 +113,68 @@ Log-in on people.apache.org
|
|||
|
||||
1. Go to ~/POI-3.1-BETA1
|
||||
|
||||
zap previous version first.
|
||||
|
||||
{code}
|
||||
cd ~/POI-3.1-BETA1/main
|
||||
{code}
|
||||
|
||||
BETA and ALPHA releases:
|
||||
|
||||
{code}
|
||||
cp *-src-* /www/www.apache.org/dist/poi/dev/src
|
||||
cp *-bin-* /www/www.apache.org/dist/poi/dev/bin
|
||||
{code}
|
||||
|
||||
FINAL release:
|
||||
{code}
|
||||
cp *-src-* /www/www.apache.org/dist/poi/release/src
|
||||
cp *-bin-* /www/www.apache.org/dist/poi/release/bin
|
||||
{code}
|
||||
|
||||
{code}
|
||||
cd ~/POI-3.1-BETA1/maven
|
||||
|
||||
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
|
||||
|
||||
{code}
|
||||
|
||||
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
|
||||
|
||||
4. Send announcements:
|
||||
- to poi-user and poi-dev lists
|
||||
- send announcements to announcement@apache.org, announcements@jakarta.apache.org
|
||||
4. test maven
|
||||
create a simple project and make sure the release artifacts are accessible by maven:
|
||||
|
||||
{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_4_drawingsSaved;
|
||||
private FileIdCluster[] field_5_fileIdClusters;
|
||||
private int maxDgId;
|
||||
|
||||
public static class FileIdCluster
|
||||
{
|
||||
|
@ -87,6 +88,7 @@ public class EscherDggRecord
|
|||
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 ));
|
||||
maxDgId = Math.max(maxDgId, field_5_fileIdClusters[i].getDrawingGroupId());
|
||||
size += 8;
|
||||
}
|
||||
bytesRemaining -= size;
|
||||
|
@ -229,7 +231,14 @@ public class EscherDggRecord
|
|||
this.field_4_drawingsSaved = field_4_drawingsSaved;
|
||||
}
|
||||
|
||||
public FileIdCluster[] getFileIdClusters()
|
||||
/**
|
||||
* @return The maximum drawing group ID
|
||||
*/
|
||||
public int getMaxDrawingGroupId(){
|
||||
return maxDgId;
|
||||
}
|
||||
|
||||
public FileIdCluster[] getFileIdClusters()
|
||||
{
|
||||
return field_5_fileIdClusters;
|
||||
}
|
||||
|
@ -240,10 +249,23 @@ public class EscherDggRecord
|
|||
}
|
||||
|
||||
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));
|
||||
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 )
|
||||
{
|
||||
|
@ -257,6 +279,7 @@ public class EscherDggRecord
|
|||
return +1;
|
||||
}
|
||||
} );
|
||||
maxDgId = Math.min(maxDgId, dgId);
|
||||
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_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 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_3_rcBounds_x1;
|
||||
private int field_3_rcBounds_y1;
|
||||
|
@ -72,6 +83,12 @@ public class EscherMetafileBlip
|
|||
|
||||
field_1_UID = new byte[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_3_rcBounds_x1 = 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;
|
||||
LittleEndian.putShort( data, pos, getOptions() ); 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_3_rcBounds_x1 ); 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 );
|
||||
|
||||
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 )
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +193,11 @@ public class EscherMetafileBlip
|
|||
*/
|
||||
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()
|
||||
|
@ -186,6 +210,16 @@ public class EscherMetafileBlip
|
|||
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()
|
||||
{
|
||||
return field_2_cb;
|
||||
|
@ -264,6 +298,7 @@ public class EscherMetafileBlip
|
|||
" RecordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
||||
" Options: 0x" + HexDump.toHex( getOptions() ) + 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 +
|
||||
" Bounds: " + getBounds() + nl +
|
||||
" Size in EMU: " + getSizeEMU() + nl +
|
||||
|
@ -273,4 +308,19 @@ public class EscherMetafileBlip
|
|||
" 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 {
|
||||
isVarArgs = !fm.hasFixedArgsLength();
|
||||
funcIx = fm.getIndex();
|
||||
validateNumArgs(numArgs, fm);
|
||||
}
|
||||
AbstractFunctionPtg retval;
|
||||
if(isVarArgs) {
|
||||
retval = new FuncVarPtg(name, (byte)numArgs);
|
||||
} else {
|
||||
retval = new FuncPtg(funcIx, (byte)numArgs);
|
||||
retval = new FuncPtg(funcIx);
|
||||
}
|
||||
if (!name.equals(AbstractFunctionPtg.FUNCTION_NAME_IF)) {
|
||||
// early return for everything else besides IF()
|
||||
|
@ -447,6 +448,29 @@ public final class FormulaParser {
|
|||
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) {
|
||||
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.
|
||||
* @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++ )
|
||||
{
|
||||
BoundSheetRecord boundSheetRecord = (BoundSheetRecord) boundsheets.get( i );
|
||||
if (excludeSheetIdx != i && name.equals(boundSheetRecord.getSheetname()))
|
||||
if (excludeSheetIdx != i && name.equalsIgnoreCase(boundSheetRecord.getSheetname()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -15,13 +14,7 @@
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
/*
|
||||
* ColumnInfoRecord.java
|
||||
*
|
||||
* Created on December 8, 2001, 8:44 AM
|
||||
*/
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
@ -29,29 +22,28 @@ import org.apache.poi.util.BitField;
|
|||
import org.apache.poi.util.BitFieldFactory;
|
||||
|
||||
/**
|
||||
* Title: ColumnInfo Record<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>
|
||||
* Title: COLINFO Record<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/>
|
||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||
* @version 2.0-pre
|
||||
*/
|
||||
|
||||
public class ColumnInfoRecord
|
||||
extends Record
|
||||
{
|
||||
public final class ColumnInfoRecord extends Record {
|
||||
public static final short sid = 0x7d;
|
||||
private short field_1_first_col;
|
||||
private short field_2_last_col;
|
||||
private short field_3_col_width;
|
||||
private short field_4_xf_index;
|
||||
private short field_5_options;
|
||||
static final private BitField hidden = BitFieldFactory.getInstance(0x01);
|
||||
static final private BitField outlevel = BitFieldFactory.getInstance(0x0700);
|
||||
static final private BitField collapsed = BitFieldFactory.getInstance(0x1000);
|
||||
private static final BitField hidden = BitFieldFactory.getInstance(0x01);
|
||||
private static final BitField outlevel = BitFieldFactory.getInstance(0x0700);
|
||||
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;
|
||||
|
||||
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_4_xf_index = in.readShort();
|
||||
field_5_options = in.readShort();
|
||||
field_6_reserved = in.readShort();
|
||||
switch(in.remaining()) {
|
||||
case 2: // usual case
|
||||
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)
|
||||
|
|
|
@ -14,31 +14,26 @@
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Title: FileSharing<P>
|
||||
* Title: FILESHARING<P>
|
||||
* 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)
|
||||
*/
|
||||
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;
|
||||
private short field_1_readonly;
|
||||
private short field_2_password;
|
||||
private byte field_3_username_length;
|
||||
private short field_4_unknown; // not documented
|
||||
private String field_5_username;
|
||||
private byte field_3_username_unicode_options;
|
||||
private String field_3_username_value;
|
||||
|
||||
public FileSharingRecord() {}
|
||||
|
||||
|
@ -61,23 +56,15 @@ public class FileSharingRecord extends Record {
|
|||
protected void fillFields(RecordInputStream in) {
|
||||
field_1_readonly = in.readShort();
|
||||
field_2_password = in.readShort();
|
||||
field_3_username_length = in.readByte();
|
||||
|
||||
// Is this really correct? The latest docs
|
||||
// seem to hint there's nothing between the
|
||||
// username length and the username string
|
||||
field_4_unknown = in.readShort();
|
||||
int nameLen = in.readShort();
|
||||
|
||||
// Ensure we don't try to read more data than
|
||||
// there actually is
|
||||
if(field_3_username_length > in.remaining()) {
|
||||
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_length = (byte)in.remaining();
|
||||
}
|
||||
if(field_3_username_length > 0) {
|
||||
field_5_username = in.readCompressedUnicode(field_3_username_length);
|
||||
if(nameLen > 0) {
|
||||
// TODO - Current examples(3) from junits only have zero length username.
|
||||
field_3_username_unicode_options = in.readByte();
|
||||
field_3_username_value = in.readCompressedUnicode(nameLen);
|
||||
} 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
|
||||
*/
|
||||
public byte getUsernameLength() {
|
||||
return field_3_username_length ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param byte representing the length of the username field
|
||||
*/
|
||||
public void setUsernameLength(byte length) {
|
||||
this.field_3_username_length = length;
|
||||
public short getUsernameLength() {
|
||||
return (short) field_3_username_value.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns username of the user that created the file
|
||||
*/
|
||||
public String getUsername() {
|
||||
return this.field_5_username;
|
||||
return field_3_username_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param username of the user that created the file
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.field_5_username = username;
|
||||
this.field_3_username_length = (byte)username.length();
|
||||
field_3_username_value = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
@ -183,10 +149,6 @@ public class FileSharingRecord extends Record {
|
|||
.append(getReadOnly() == 1 ? "true" : "false").append("\n");
|
||||
buffer.append(" .password = ")
|
||||
.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 = ")
|
||||
.append(getUsername()).append("\n");
|
||||
buffer.append("[/FILESHARING]\n");
|
||||
|
@ -194,18 +156,25 @@ public class FileSharingRecord extends Record {
|
|||
}
|
||||
|
||||
public int serialize(int offset, byte [] data) {
|
||||
// TODO - junit
|
||||
LittleEndian.putShort(data, 0 + offset, sid);
|
||||
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize()-4));
|
||||
LittleEndian.putShort(data, 4 + offset, getReadOnly());
|
||||
LittleEndian.putShort(data, 6 + offset, getPassword());
|
||||
data[ 8 + offset ] = getUsernameLength();
|
||||
LittleEndian.putShort(data, 9 + offset, getUnknown());
|
||||
StringUtil.putCompressedUnicode( getUsername(), data, 11 + offset );
|
||||
LittleEndian.putShort(data, 8 + offset, getUsernameLength());
|
||||
if(getUsernameLength() > 0) {
|
||||
LittleEndian.putByte(data, 10 + offset, field_3_username_unicode_options);
|
||||
StringUtil.putCompressedUnicode( getUsername(), data, 11 + offset );
|
||||
}
|
||||
return getRecordSize();
|
||||
}
|
||||
|
||||
public int getRecordSize() {
|
||||
return 11+getUsernameLength();
|
||||
short nameLen = getUsernameLength();
|
||||
if (nameLen < 1) {
|
||||
return 10;
|
||||
}
|
||||
return 11+nameLen;
|
||||
}
|
||||
|
||||
public short getSid() {
|
||||
|
@ -219,10 +188,7 @@ public class FileSharingRecord extends Record {
|
|||
FileSharingRecord clone = new FileSharingRecord();
|
||||
clone.setReadOnly(field_1_readonly);
|
||||
clone.setPassword(field_2_password);
|
||||
clone.setUsernameLength(field_3_username_length);
|
||||
clone.setUnknown(field_4_unknown);
|
||||
clone.setUsername(field_5_username);
|
||||
clone.setUsername(field_3_username_value);
|
||||
return clone;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ import org.apache.poi.util.LittleEndian;
|
|||
* @version 2.0-pre
|
||||
*/
|
||||
|
||||
public class FormulaRecord
|
||||
public final class FormulaRecord
|
||||
extends Record
|
||||
implements CellValueRecordInterface, Comparable
|
||||
{
|
||||
|
@ -108,6 +108,11 @@ public class FormulaRecord
|
|||
} catch (java.lang.UnsupportedOperationException 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)
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.apache.poi.hssf.record.formula.*;
|
|||
* @author Danny Mui at apache dot org
|
||||
*/
|
||||
public final class SharedFormulaRecord extends Record {
|
||||
public final static short sid = 0x4BC;
|
||||
public final static short sid = 0x4BC;
|
||||
|
||||
private int field_1_first_row;
|
||||
private int field_2_last_row;
|
||||
|
@ -186,6 +186,16 @@ public final class SharedFormulaRecord extends Record {
|
|||
* counter part
|
||||
*/
|
||||
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();
|
||||
|
||||
if (ptgs != null)
|
||||
|
@ -265,7 +275,7 @@ public final class SharedFormulaRecord extends Record {
|
|||
throw new RuntimeException("Shared Formula Conversion: Coding Error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static int fixupRelativeColumn(int currentcolumn, int column, boolean relative) {
|
||||
if(relative) {
|
||||
// mask out upper bits to produce 'wrapping' at column 256 ("IV")
|
||||
|
|
|
@ -147,10 +147,12 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
|
|||
}
|
||||
|
||||
public byte getParameterClass(int index) {
|
||||
try {
|
||||
return paramClass[index];
|
||||
} catch (ArrayIndexOutOfBoundsException aioobe) {
|
||||
if (index >= paramClass.length) {
|
||||
// For var-arg (and other?) functions, the metadata does not list all the parameter
|
||||
// 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[index];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -16,19 +15,9 @@
|
|||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
/*
|
||||
* AreaPtg.java
|
||||
*
|
||||
* Created on November 17, 2001, 9:30 PM
|
||||
*/
|
||||
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.util.AreaReference;
|
||||
import org.apache.poi.hssf.util.CellReference;
|
||||
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)
|
||||
*/
|
||||
|
||||
public class AreaNAPtg
|
||||
extends AreaPtg
|
||||
public final class AreaNAPtg extends AreaPtg
|
||||
{
|
||||
public final static short sid = 0x6D;
|
||||
|
||||
|
@ -50,20 +38,16 @@ public class AreaNAPtg
|
|||
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() {
|
||||
return "AreaNAPtg";
|
||||
}
|
||||
|
||||
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() {
|
||||
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)
|
||||
*/
|
||||
|
||||
public class AreaNPtg
|
||||
extends AreaPtg
|
||||
public final class AreaNPtg extends AreaPtg
|
||||
{
|
||||
public final static short sid = 0x2D;
|
||||
|
||||
|
@ -50,23 +49,16 @@ public class AreaNPtg
|
|||
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() {
|
||||
return "AreaNPtg";
|
||||
}
|
||||
|
||||
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() {
|
||||
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
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -16,19 +15,9 @@
|
|||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
/*
|
||||
* AreaPtg.java
|
||||
*
|
||||
* Created on November 17, 2001, 9:30 PM
|
||||
*/
|
||||
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.util.AreaReference;
|
||||
import org.apache.poi.hssf.util.CellReference;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
|
||||
/**
|
||||
|
@ -36,10 +25,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|||
* @author andy
|
||||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
*/
|
||||
|
||||
public class AreaNVPtg
|
||||
extends AreaPtg
|
||||
{
|
||||
public final class AreaNVPtg extends AreaPtg {
|
||||
public final static short sid = 0x4D;
|
||||
|
||||
protected AreaNVPtg() {
|
||||
|
@ -51,20 +37,16 @@ public class AreaNVPtg
|
|||
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() {
|
||||
return "AreaNVPtg";
|
||||
}
|
||||
|
||||
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() {
|
||||
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.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.record.formula;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
@ -32,10 +31,15 @@ import org.apache.poi.hssf.record.RecordInputStream;
|
|||
* @author andy
|
||||
* @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;
|
||||
private final static int SIZE = 9;
|
||||
/** zero based, unsigned 16 bit */
|
||||
|
|
|
@ -57,10 +57,12 @@ public final class FuncPtg extends AbstractFunctionPtg {
|
|||
}
|
||||
numParams = fm.getMinParams();
|
||||
}
|
||||
public FuncPtg(int functionIndex, int numberOfParameters) {
|
||||
public FuncPtg(int functionIndex) {
|
||||
field_2_fnc_index = (short) functionIndex;
|
||||
numParams = numberOfParameters;
|
||||
paramClass = new byte[] { Ptg.CLASS_VALUE, }; // TODO
|
||||
FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByIndex(functionIndex);
|
||||
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) {
|
||||
|
|
|
@ -54,8 +54,8 @@ public final class FuncVarPtg extends AbstractFunctionPtg{
|
|||
returnClass = Ptg.CLASS_VALUE;
|
||||
paramClass = new byte[] {Ptg.CLASS_VALUE};
|
||||
} else {
|
||||
returnClass = Ptg.CLASS_VALUE;
|
||||
paramClass = new byte[] {Ptg.CLASS_VALUE};
|
||||
returnClass = fm.getReturnClassCode();
|
||||
paramClass = fm.getParameterClassCodes();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,24 +30,23 @@ import org.apache.poi.hssf.record.RecordInputStream;
|
|||
* @author avik
|
||||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
*/
|
||||
|
||||
public abstract class Ptg
|
||||
{
|
||||
|
||||
|
||||
|
||||
/* convert infix order ptg list to rpn order ptg list
|
||||
* @return List ptgs in RPN order
|
||||
* @param infixPtgs List of ptgs in infix order
|
||||
*/
|
||||
|
||||
|
||||
/* DO NOT REMOVE
|
||||
*we keep this method in case we wish to change the way we parse
|
||||
*It needs a getPrecedence in OperationsPtg
|
||||
|
||||
|
||||
public static List ptgsToRpn(List infixPtgs) {
|
||||
java.util.Stack operands = new java.util.Stack();
|
||||
java.util.List retval = new java.util.Stack();
|
||||
|
||||
|
||||
java.util.ListIterator i = infixPtgs.listIterator();
|
||||
Object p;
|
||||
OperationPtg o ;
|
||||
|
@ -61,13 +60,13 @@ public abstract class Ptg
|
|||
weHaveABracket = true;
|
||||
} else {
|
||||
o = (OperationPtg) operands.pop();
|
||||
while (!(o instanceof ParenthesisPtg)) {
|
||||
while (!(o instanceof ParenthesisPtg)) {
|
||||
retval.add(o);
|
||||
}
|
||||
weHaveABracket = false;
|
||||
}
|
||||
} else {
|
||||
|
||||
|
||||
while (!operands.isEmpty() && ((OperationPtg) operands.peek()).getPrecedence() >= ((OperationPtg) p).getPrecedence() ) { //TODO handle ^ since it is right associative
|
||||
retval.add(operands.pop());
|
||||
}
|
||||
|
@ -82,12 +81,16 @@ public abstract class Ptg
|
|||
//throw some error
|
||||
} else {
|
||||
retval.add(operands.pop());
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
Stack stack = new Stack();
|
||||
|
@ -97,22 +100,25 @@ public abstract class Ptg
|
|||
{
|
||||
Ptg ptg = Ptg.createPtg( in );
|
||||
if (ptg instanceof ArrayPtg) {
|
||||
if (arrayPtgs == null)
|
||||
arrayPtgs = new ArrayList(5);
|
||||
arrayPtgs.add(ptg);
|
||||
pos += 8;
|
||||
if (arrayPtgs == null)
|
||||
arrayPtgs = new ArrayList(5);
|
||||
arrayPtgs.add(ptg);
|
||||
pos += 8;
|
||||
} else pos += ptg.getSize();
|
||||
stack.push( ptg );
|
||||
}
|
||||
if(pos != size) {
|
||||
throw new RuntimeException("Ptg array size mismatch");
|
||||
}
|
||||
if (arrayPtgs != null) {
|
||||
for (int i=0;i<arrayPtgs.size();i++) {
|
||||
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
|
||||
p.readTokenValues(in);
|
||||
}
|
||||
for (int i=0;i<arrayPtgs.size();i++) {
|
||||
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
|
||||
p.readTokenValues(in);
|
||||
}
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
|
||||
public static Ptg createPtg(RecordInputStream in)
|
||||
{
|
||||
byte id = in.readByte();
|
||||
|
@ -123,142 +129,142 @@ public abstract class Ptg
|
|||
case ExpPtg.sid : // 0x01
|
||||
retval = new ExpPtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case AddPtg.sid : // 0x03
|
||||
retval = new AddPtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case SubtractPtg.sid : // 0x04
|
||||
retval = new SubtractPtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case MultiplyPtg.sid : // 0x05
|
||||
retval = new MultiplyPtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case DividePtg.sid : // 0x06
|
||||
retval = new DividePtg(in);
|
||||
break;
|
||||
|
||||
retval = new DividePtg(in);
|
||||
break;
|
||||
|
||||
case PowerPtg.sid : // 0x07
|
||||
retval = new PowerPtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case ConcatPtg.sid : // 0x08
|
||||
retval = new ConcatPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case LessThanPtg.sid: // 0x09
|
||||
retval = new LessThanPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case LessEqualPtg.sid : // 0x0a
|
||||
retval = new LessEqualPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case EqualPtg.sid : // 0x0b
|
||||
retval = new EqualPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case GreaterEqualPtg.sid : // 0x0c
|
||||
retval = new GreaterEqualPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case GreaterThanPtg.sid : // 0x0d
|
||||
retval = new GreaterThanPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case NotEqualPtg.sid : // 0x0e
|
||||
retval = new NotEqualPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case IntersectionPtg.sid : // 0x0f
|
||||
retval = new IntersectionPtg(in);
|
||||
break;
|
||||
break;
|
||||
case UnionPtg.sid : // 0x10
|
||||
retval = new UnionPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case RangePtg.sid : // 0x11
|
||||
retval = new RangePtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case UnaryPlusPtg.sid : // 0x12
|
||||
retval = new UnaryPlusPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case UnaryMinusPtg.sid : // 0x13
|
||||
retval = new UnaryMinusPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case PercentPtg.sid : // 0x14
|
||||
retval = new PercentPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case ParenthesisPtg.sid : // 0x15
|
||||
retval = new ParenthesisPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case MissingArgPtg.sid : // 0x16
|
||||
retval = new MissingArgPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case StringPtg.sid : // 0x17
|
||||
retval = new StringPtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case AttrPtg.sid : // 0x19
|
||||
case 0x1a :
|
||||
retval = new AttrPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case ErrPtg.sid : // 0x1c
|
||||
retval = new ErrPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case BoolPtg.sid : // 0x1d
|
||||
retval = new BoolPtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case IntPtg.sid : // 0x1e
|
||||
retval = new IntPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case NumberPtg.sid : // 0x1f
|
||||
retval = new NumberPtg(in);
|
||||
break;
|
||||
|
||||
retval = new NumberPtg(in);
|
||||
break;
|
||||
|
||||
case ArrayPtg.sid : // 0x20
|
||||
retval = new ArrayPtg(in);
|
||||
break;
|
||||
retval = new ArrayPtg(in);
|
||||
break;
|
||||
case ArrayPtgV.sid : // 0x40
|
||||
retval = new ArrayPtgV(in);
|
||||
break;
|
||||
retval = new ArrayPtgV(in);
|
||||
break;
|
||||
case ArrayPtgA.sid : // 0x60
|
||||
retval = new ArrayPtgA(in);
|
||||
break;
|
||||
|
||||
retval = new ArrayPtgA(in);
|
||||
break;
|
||||
|
||||
case FuncPtg.sid : // 0x21
|
||||
case FuncPtg.sid + 0x20 : // 0x41
|
||||
case FuncPtg.sid + 0x40 : // 0x61
|
||||
retval = new FuncPtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case FuncVarPtg.sid : // 0x22
|
||||
case FuncVarPtg.sid + 0x20 : // 0x42
|
||||
case FuncVarPtg.sid + 0x40 : // 0x62
|
||||
retval = new FuncVarPtg(in);
|
||||
break;
|
||||
|
||||
case ReferencePtg.sid : // 0x24
|
||||
break;
|
||||
|
||||
case ReferencePtg.sid : // 0x24
|
||||
retval = new ReferencePtg(in);
|
||||
break;
|
||||
break;
|
||||
case RefAPtg.sid : // 0x64
|
||||
retval = new RefAPtg(in);
|
||||
break;
|
||||
break;
|
||||
case RefVPtg.sid : // 0x44
|
||||
retval = new RefVPtg(in);
|
||||
break;
|
||||
break;
|
||||
case RefNAPtg.sid : // 0x6C
|
||||
retval = new RefNAPtg(in);
|
||||
break;
|
||||
|
@ -267,11 +273,11 @@ public abstract class Ptg
|
|||
break;
|
||||
case RefNVPtg.sid : // 0x4C
|
||||
retval = new RefNVPtg(in);
|
||||
break;
|
||||
|
||||
case AreaPtg.sid : // 0x25
|
||||
break;
|
||||
|
||||
case AreaPtg.sid : // 0x25
|
||||
retval = new AreaPtg(in);
|
||||
break;
|
||||
break;
|
||||
case AreaVPtg.sid: // 0x45
|
||||
retval = new AreaVPtg(in);
|
||||
break;
|
||||
|
@ -287,81 +293,81 @@ public abstract class Ptg
|
|||
case AreaNVPtg.sid : // 0x4D
|
||||
retval = new AreaNVPtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case MemAreaPtg.sid : // 0x26
|
||||
case MemAreaPtg.sid + 0x40 : // 0x46
|
||||
case MemAreaPtg.sid + 0x20 : // 0x66
|
||||
retval = new MemAreaPtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case MemErrPtg.sid : // 0x27
|
||||
case MemErrPtg.sid + 0x20 : // 0x47
|
||||
case MemErrPtg.sid + 0x40 : // 0x67
|
||||
retval = new MemErrPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case MemFuncPtg.sid : // 0x29
|
||||
retval = new MemFuncPtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case RefErrorPtg.sid : // 0x2a
|
||||
case RefErrorPtg.sid + 0x20 : // 0x4a
|
||||
case RefErrorPtg.sid + 0x40 : // 0x6a
|
||||
retval = new RefErrorPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case AreaErrPtg.sid : // 0x2b
|
||||
case AreaErrPtg.sid + 0x20 : // 0x4b
|
||||
case AreaErrPtg.sid + 0x40 : // 0x6b
|
||||
retval = new AreaErrPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case NamePtg.sid : // 0x23
|
||||
case NamePtg.sid + 0x20 : // 0x43
|
||||
case NamePtg.sid + 0x40 : // 0x63
|
||||
retval = new NamePtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case NameXPtg.sid : // 0x39
|
||||
case NameXPtg.sid + 0x20 : // 0x45
|
||||
case NameXPtg.sid + 0x40 : // 0x79
|
||||
retval = new NameXPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case Area3DPtg.sid : // 0x3b
|
||||
case Area3DPtg.sid + 0x20 : // 0x5b
|
||||
case Area3DPtg.sid + 0x40 : // 0x7b
|
||||
retval = new Area3DPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case Ref3DPtg.sid : // 0x3a
|
||||
case Ref3DPtg.sid + 0x20: // 0x5a
|
||||
case Ref3DPtg.sid + 0x40: // 0x7a
|
||||
retval = new Ref3DPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case DeletedRef3DPtg.sid: // 0x3c
|
||||
case DeletedRef3DPtg.sid + 0x20: // 0x5c
|
||||
case DeletedRef3DPtg.sid + 0x40: // 0x7c
|
||||
retval = new DeletedRef3DPtg(in);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case DeletedArea3DPtg.sid : // 0x3d
|
||||
case DeletedArea3DPtg.sid + 0x20 : // 0x5d
|
||||
case DeletedArea3DPtg.sid + 0x40 : // 0x7d
|
||||
retval = new DeletedArea3DPtg(in);
|
||||
break;
|
||||
|
||||
|
||||
case 0x00:
|
||||
retval = new UnknownPtg();
|
||||
break;
|
||||
|
||||
retval = new UnknownPtg();
|
||||
break;
|
||||
|
||||
default :
|
||||
//retval = new UnknownPtg();
|
||||
throw new java.lang.UnsupportedOperationException(" Unknown Ptg in Formula: 0x"+
|
||||
Integer.toHexString(( int ) id) + " (" + ( int ) id + ")");
|
||||
}
|
||||
|
||||
|
||||
if (id > 0x60) {
|
||||
retval.setClass(CLASS_ARRAY);
|
||||
} else if (id > 0x40) {
|
||||
|
@ -371,35 +377,35 @@ public abstract class Ptg
|
|||
}
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
public static int serializePtgStack(Stack expression, byte[] array, int offset) {
|
||||
int pos = 0;
|
||||
int size = 0;
|
||||
if (expression != null)
|
||||
size = expression.size();
|
||||
|
||||
List arrayPtgs = null;
|
||||
|
||||
for (int k = 0; k < size; k++) {
|
||||
Ptg ptg = ( Ptg ) expression.get(k);
|
||||
|
||||
ptg.writeBytes(array, pos + offset);
|
||||
if (ptg instanceof ArrayPtg) {
|
||||
if (arrayPtgs == null)
|
||||
arrayPtgs = new ArrayList(5);
|
||||
arrayPtgs.add(ptg);
|
||||
pos += 8;
|
||||
} else pos += ptg.getSize();
|
||||
}
|
||||
if (arrayPtgs != null) {
|
||||
for (int i=0;i<arrayPtgs.size();i++) {
|
||||
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
|
||||
pos += p.writeTokenValueBytes(array, pos + offset);
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
public static int serializePtgStack(Stack expression, byte[] array, int offset) {
|
||||
int pos = 0;
|
||||
int size = 0;
|
||||
if (expression != null)
|
||||
size = expression.size();
|
||||
|
||||
List arrayPtgs = null;
|
||||
|
||||
for (int k = 0; k < size; k++) {
|
||||
Ptg ptg = ( Ptg ) expression.get(k);
|
||||
|
||||
ptg.writeBytes(array, pos + offset);
|
||||
if (ptg instanceof ArrayPtg) {
|
||||
if (arrayPtgs == null)
|
||||
arrayPtgs = new ArrayList(5);
|
||||
arrayPtgs.add(ptg);
|
||||
pos += 8;
|
||||
} else pos += ptg.getSize();
|
||||
}
|
||||
if (arrayPtgs != null) {
|
||||
for (int i=0;i<arrayPtgs.size();i++) {
|
||||
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
|
||||
pos += p.writeTokenValueBytes(array, pos + offset);
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
public abstract int getSize();
|
||||
|
@ -414,7 +420,7 @@ public abstract class Ptg
|
|||
}
|
||||
/** write this Ptg to a byte array*/
|
||||
public abstract void writeBytes(byte [] array, int offset);
|
||||
|
||||
|
||||
/**
|
||||
* return a string representation of this token alone
|
||||
*/
|
||||
|
@ -425,7 +431,7 @@ public abstract class Ptg
|
|||
public String toDebugString() {
|
||||
byte[] ba = new byte[getSize()];
|
||||
String retval=null;
|
||||
writeBytes(ba,0);
|
||||
writeBytes(ba,0);
|
||||
try {
|
||||
retval = org.apache.poi.util.HexDump.dump(ba,0,0);
|
||||
} catch (Exception e) {
|
||||
|
@ -433,7 +439,7 @@ public abstract class Ptg
|
|||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/** Overridden toString method to ensure object hash is not printed.
|
||||
* This helps get rid of gratuitous diffs when comparing two dumps
|
||||
* Subclasses may output more relevant information by overriding this method
|
||||
|
@ -441,26 +447,26 @@ public abstract class Ptg
|
|||
public String toString(){
|
||||
return this.getClass().toString();
|
||||
}
|
||||
|
||||
|
||||
public static final byte CLASS_REF = 0x00;
|
||||
public static final byte CLASS_VALUE = 0x20;
|
||||
public static final byte CLASS_ARRAY = 0x40;
|
||||
|
||||
|
||||
protected byte ptgClass = CLASS_REF; //base ptg
|
||||
|
||||
|
||||
public void setClass(byte thePtgClass) {
|
||||
ptgClass = thePtgClass;
|
||||
}
|
||||
|
||||
|
||||
/** returns the class (REF/VALUE/ARRAY) for this Ptg */
|
||||
public byte getPtgClass() {
|
||||
return ptgClass;
|
||||
}
|
||||
|
||||
|
||||
public abstract byte getDefaultOperandClass();
|
||||
|
||||
public abstract Object clone();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -16,26 +15,16 @@
|
|||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
/*
|
||||
* ValueReferencePtg.java
|
||||
*
|
||||
* Created on November 21, 2001, 5:27 PM
|
||||
*/
|
||||
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.util.CellReference;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
|
||||
/**
|
||||
* RefNAPtg
|
||||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
*/
|
||||
|
||||
public class RefNAPtg extends ReferencePtg
|
||||
public final class RefNAPtg extends ReferencePtg
|
||||
{
|
||||
public final static byte sid = 0x6C;
|
||||
|
||||
|
@ -48,21 +37,16 @@ public class RefNAPtg extends ReferencePtg
|
|||
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() {
|
||||
return "RefNAPtg";
|
||||
}
|
||||
|
||||
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() {
|
||||
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
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -16,25 +15,16 @@
|
|||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
/*
|
||||
* RefNPtg.java
|
||||
*
|
||||
*/
|
||||
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.util.CellReference;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
|
||||
/**
|
||||
* RefNPtg
|
||||
* @author Jason Height (jheight at apache dot com)
|
||||
*/
|
||||
|
||||
public class RefNPtg extends ReferencePtg
|
||||
public final class RefNPtg extends ReferencePtg
|
||||
{
|
||||
public final static byte sid = 0x2C;
|
||||
|
||||
|
@ -49,21 +39,16 @@ public class RefNPtg extends ReferencePtg
|
|||
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() {
|
||||
return "RefNPtg";
|
||||
}
|
||||
|
||||
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() {
|
||||
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
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -18,11 +17,7 @@
|
|||
|
||||
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.util.CellReference;
|
||||
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)
|
||||
*/
|
||||
|
||||
public class RefNVPtg extends ReferencePtg
|
||||
{
|
||||
public final class RefNVPtg extends ReferencePtg {
|
||||
public final static byte sid = 0x4C;
|
||||
|
||||
protected RefNVPtg() {
|
||||
|
@ -45,21 +39,16 @@ public class RefNVPtg extends ReferencePtg
|
|||
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() {
|
||||
return "RefNVPtg";
|
||||
}
|
||||
|
||||
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() {
|
||||
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 Jason Height (jheight at chariot dot net dot au)
|
||||
*/
|
||||
|
||||
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;
|
||||
public final static byte sid = 0x24;
|
||||
private final static int MAX_ROW_NUMBER = 65536;
|
||||
|
|
|
@ -42,8 +42,10 @@ final class FunctionDataBuilder {
|
|||
_mutatingFunctionIndexes = new HashSet();
|
||||
}
|
||||
|
||||
public void add(int functionIndex, String functionName, int minParams, int maxParams, boolean hasFootnote) {
|
||||
FunctionMetadata fm = new FunctionMetadata(functionIndex, functionName, minParams, maxParams);
|
||||
public void add(int functionIndex, String functionName, int minParams, int maxParams,
|
||||
byte returnClassCode, byte[] parameterClassCodes, boolean hasFootnote) {
|
||||
FunctionMetadata fm = new FunctionMetadata(functionIndex, functionName, minParams, maxParams,
|
||||
returnClassCode, parameterClassCodes);
|
||||
|
||||
Integer indexKey = new Integer(functionIndex);
|
||||
|
||||
|
|
|
@ -27,12 +27,17 @@ public final class FunctionMetadata {
|
|||
private final String _name;
|
||||
private final int _minParams;
|
||||
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;
|
||||
_name = name;
|
||||
_minParams = minParams;
|
||||
_maxParams = maxParams;
|
||||
_returnClassCode = returnClassCode;
|
||||
_parameterClassCodes = parameterClassCodes;
|
||||
}
|
||||
public int getIndex() {
|
||||
return _index;
|
||||
|
@ -49,6 +54,12 @@ public final class FunctionMetadata {
|
|||
public boolean hasFixedArgsLength() {
|
||||
return _minParams == _maxParams;
|
||||
}
|
||||
public byte getReturnClassCode() {
|
||||
return _returnClassCode;
|
||||
}
|
||||
public byte[] getParameterClassCodes() {
|
||||
return (byte[]) _parameterClassCodes.clone();
|
||||
}
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(64);
|
||||
sb.append(getClass().getName()).append(" [");
|
||||
|
|
|
@ -26,6 +26,8 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
|
||||
/**
|
||||
* 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 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 = {
|
||||
// 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];
|
||||
int minParams = parseInt(parts[2]);
|
||||
int maxParams = parseInt(parts[3]);
|
||||
// 4 returnClass
|
||||
// 5 parameterClasses
|
||||
byte returnClassCode = parseReturnTypeCode(parts[4]);
|
||||
byte[] parameterClassCodes = parseOperandTypeCodes(parts[5]);
|
||||
// 6 isVolatile
|
||||
boolean hasNote = parts[7].length() > 0;
|
||||
|
||||
validateFunctionName(functionName);
|
||||
// TODO - make POI use returnClass, parameterClasses, isVolatile
|
||||
fdb.add(functionIndex, functionName, minParams, maxParams, hasNote);
|
||||
// TODO - make POI use isVolatile
|
||||
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.EscherBlipRecord;
|
||||
import org.apache.poi.ddf.EscherMetafileBlip;
|
||||
|
||||
/**
|
||||
* Represents binary data stored in the file. Eg. A GIF, JPEG etc...
|
||||
|
@ -69,19 +70,19 @@ public class HSSFPictureData
|
|||
*/
|
||||
public String suggestFileExtension()
|
||||
{
|
||||
switch (blip.getOptions() & FORMAT_MASK)
|
||||
switch (blip.getRecordId())
|
||||
{
|
||||
case MSOBI_WMF:
|
||||
case EscherMetafileBlip.RECORD_ID_WMF:
|
||||
return "wmf";
|
||||
case MSOBI_EMF:
|
||||
case EscherMetafileBlip.RECORD_ID_EMF:
|
||||
return "emf";
|
||||
case MSOBI_PICT:
|
||||
case EscherMetafileBlip.RECORD_ID_PICT:
|
||||
return "pict";
|
||||
case MSOBI_PNG:
|
||||
case EscherBitmapBlip.RECORD_ID_PNG:
|
||||
return "png";
|
||||
case MSOBI_JPEG:
|
||||
case EscherBitmapBlip.RECORD_ID_JPEG:
|
||||
return "jpeg";
|
||||
case MSOBI_DIB:
|
||||
case EscherBitmapBlip.RECORD_ID_DIB:
|
||||
return "dib";
|
||||
default:
|
||||
return "";
|
||||
|
|
|
@ -1710,6 +1710,8 @@ public final class HSSFSheet {
|
|||
|
||||
HSSFCellStyle style = cell.getCellStyle();
|
||||
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) {
|
||||
HSSFRichTextString rt = cell.getRichStringCellValue();
|
||||
|
@ -1742,9 +1744,9 @@ public final class HSSFSheet {
|
|||
trans.concatenate(
|
||||
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 {
|
||||
width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth);
|
||||
width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth + indention);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1787,15 +1789,15 @@ public final class HSSFSheet {
|
|||
trans.concatenate(
|
||||
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 {
|
||||
width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth);
|
||||
width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth + indention);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
sheet.setColumnWidth(column, (short) (width * 256));
|
||||
|
|
|
@ -165,9 +165,45 @@ public class HSSFWorkbook extends POIDocument
|
|||
public HSSFWorkbook(POIFSFileSystem fs, boolean preserveNodes)
|
||||
throws IOException
|
||||
{
|
||||
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
|
||||
* within it, read in its Workbook and populate the high and
|
||||
|
@ -185,9 +221,11 @@ public class HSSFWorkbook extends POIDocument
|
|||
public HSSFWorkbook(DirectoryNode directory, POIFSFileSystem fs, boolean preserveNodes)
|
||||
throws IOException
|
||||
{
|
||||
super(directory, fs);
|
||||
super(directory, fs);
|
||||
String workbookName = getWorkbookDirEntryName(directory);
|
||||
|
||||
this.preserveNodes = preserveNodes;
|
||||
|
||||
|
||||
// If we're not preserving nodes, don't track the
|
||||
// POIFS any more
|
||||
if(! preserveNodes) {
|
||||
|
@ -197,28 +235,9 @@ public class HSSFWorkbook extends POIDocument
|
|||
|
||||
sheets = 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
|
||||
// it happens to be spelt.
|
||||
// it happens to be spelled.
|
||||
InputStream stream = directory.createDocumentInputStream(workbookName);
|
||||
|
||||
EventRecordFactory factory = new EventRecordFactory();
|
||||
|
@ -231,7 +250,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
int sheetNum = 0;
|
||||
|
||||
// convert all LabelRecord records to LabelSSTRecord
|
||||
convertLabelRecords(records, recOffset);
|
||||
convertLabelRecords(records, recOffset);
|
||||
while (recOffset < records.size())
|
||||
{
|
||||
Sheet sheet = Sheet.createSheet(records, sheetNum++, recOffset );
|
||||
|
@ -288,7 +307,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
|
||||
// none currently
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is basically a kludge to deal with the now obsolete Label records. If
|
||||
* you have to read in a sheet that contains Label records, be aware that the rest
|
||||
|
@ -304,7 +323,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
* @see org.apache.poi.hssf.record.LabelSSTRecord
|
||||
* @see org.apache.poi.hssf.record.SSTRecord
|
||||
*/
|
||||
|
||||
|
||||
private void convertLabelRecords(List records, int offset)
|
||||
{
|
||||
if (log.check( POILogger.DEBUG ))
|
||||
|
@ -332,7 +351,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
if (log.check( POILogger.DEBUG ))
|
||||
log.log(POILogger.DEBUG, "convertLabelRecords exit");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* sets the order of appearance for a given sheet.
|
||||
|
@ -345,7 +364,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
sheets.add(pos,sheets.remove(getSheetIndex(sheetname)));
|
||||
workbook.setSheetOrder(sheetname, pos);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sets the tab whose data is actually seen when the sheet is opened.
|
||||
* This may be different from the "selected sheet" since excel seems to
|
||||
|
@ -357,7 +376,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
public void setSelectedTab(short index) {
|
||||
workbook.getWindowOne().setSelectedTab(index);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gets the tab whose data is actually seen when the sheet is opened.
|
||||
* This may be different from the "selected sheet" since excel seems to
|
||||
|
@ -368,7 +387,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
public short getSelectedTab() {
|
||||
return workbook.getWindowOne().getSelectedTab();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sets the first tab that is displayed in the list of tabs
|
||||
* in excel.
|
||||
|
@ -377,7 +396,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
public void setDisplayedTab(short index) {
|
||||
workbook.getWindowOne().setDisplayedTab(index);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sets the first tab that is displayed in the list of tabs
|
||||
* in excel.
|
||||
|
@ -399,7 +418,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
|
||||
|
||||
/**
|
||||
* set the sheet name.
|
||||
* set the sheet name.
|
||||
* Will throw IllegalArgumentException if the name is greater than 31 chars
|
||||
* or contains /\?*[]
|
||||
* @param sheet number (0 based)
|
||||
|
@ -413,19 +432,19 @@ public class HSSFWorkbook extends POIDocument
|
|||
{
|
||||
throw new RuntimeException("Sheet out of bounds");
|
||||
}
|
||||
|
||||
|
||||
workbook.setSheetName( sheet, name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* set the sheet name forcing the encoding. Forcing the encoding IS A BAD IDEA!!!
|
||||
* @deprecated 3-Jan-2006 POI now automatically detects unicode and sets the encoding
|
||||
* appropriately. Simply use setSheetName(int sheet, String encoding)
|
||||
* appropriately. Simply use setSheetName(int sheet, String encoding)
|
||||
* @throws IllegalArgumentException if the name is greater than 31 chars
|
||||
* or contains /\?*[]
|
||||
* @param sheet number (0 based)
|
||||
*/
|
||||
*/
|
||||
public void setSheetName( int sheet, String name, short encoding )
|
||||
{
|
||||
if (workbook.doesContainsSheetName( name, sheet ))
|
||||
|
@ -480,7 +499,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
|
||||
/**
|
||||
* Hide or unhide a sheet
|
||||
*
|
||||
*
|
||||
* @param sheetnum The sheet number
|
||||
* @param hidden True to mark the sheet as hidden, false otherwise
|
||||
*/
|
||||
|
@ -492,7 +511,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
}
|
||||
workbook.setSheetHidden(sheet,hidden);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get the sheet's index
|
||||
* @param name sheet name
|
||||
|
@ -516,23 +535,23 @@ public class HSSFWorkbook extends POIDocument
|
|||
*/
|
||||
public int getSheetIndex(HSSFSheet sheet)
|
||||
{
|
||||
for(int i=0; i<sheets.size(); i++) {
|
||||
if(sheets.get(i) == sheet) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
for(int i=0; i<sheets.size(); i++) {
|
||||
if(sheets.get(i) == sheet) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the external sheet index of the sheet
|
||||
* with the given internal index, creating one
|
||||
* if needed.
|
||||
* Used by some of the more obscure formula and
|
||||
* Used by some of the more obscure formula and
|
||||
* named range things.
|
||||
*/
|
||||
public short getExternalSheetIndex(int internalSheetIndex) {
|
||||
return workbook.checkExternSheet(internalSheetIndex);
|
||||
return workbook.checkExternSheet(internalSheetIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -576,18 +595,18 @@ public class HSSFWorkbook extends POIDocument
|
|||
sheets.add(clonedSheet);
|
||||
int i=1;
|
||||
while (true) {
|
||||
//Try and find the next sheet name that is unique
|
||||
String name = srcName;
|
||||
String index = Integer.toString(i++);
|
||||
if (name.length()+index.length()+2<31)
|
||||
name = name + "("+index+")";
|
||||
else name = name.substring(0, 31-index.length()-2)+"("+index+")";
|
||||
|
||||
//If the sheet name is unique, then set it otherwise move on to the next number.
|
||||
if (workbook.getSheetIndex(name) == -1) {
|
||||
//Try and find the next sheet name that is unique
|
||||
String name = srcName;
|
||||
String index = Integer.toString(i++);
|
||||
if (name.length()+index.length()+2<31)
|
||||
name = name + "("+index+")";
|
||||
else name = name.substring(0, 31-index.length()-2)+"("+index+")";
|
||||
|
||||
//If the sheet name is unique, then set it otherwise move on to the next number.
|
||||
if (workbook.getSheetIndex(name) == -1) {
|
||||
workbook.setSheetName(sheets.size()-1, name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return clonedSheet;
|
||||
}
|
||||
|
@ -600,6 +619,8 @@ public class HSSFWorkbook extends POIDocument
|
|||
*
|
||||
* @param sheetname sheetname to set for the 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)
|
||||
|
@ -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
|
||||
* @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)
|
||||
|
@ -652,16 +673,16 @@ public class HSSFWorkbook extends POIDocument
|
|||
{
|
||||
String sheetname = workbook.getSheetName(k);
|
||||
|
||||
if (sheetname.equals(name))
|
||||
if (sheetname.equalsIgnoreCase(name))
|
||||
{
|
||||
retval = (HSSFSheet) sheets.get(k);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
public SheetReferences getSheetReferences() {
|
||||
return workbook.getSheetReferences();
|
||||
return workbook.getSheetReferences();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -839,7 +860,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
|
@ -989,21 +1010,21 @@ public class HSSFWorkbook extends POIDocument
|
|||
// For tracking what we've written out, used if we're
|
||||
// going to be preserving nodes
|
||||
List excepts = new ArrayList(1);
|
||||
|
||||
|
||||
// Write out the Workbook stream
|
||||
fs.createDocument(new ByteArrayInputStream(bytes), "Workbook");
|
||||
|
||||
|
||||
// Write out our HPFS properties, if we have them
|
||||
writeProperties(fs, excepts);
|
||||
|
||||
if (preserveNodes) {
|
||||
// Don't write out the old Workbook, we'll be doing our new one
|
||||
// Don't write out the old Workbook, we'll be doing our new one
|
||||
excepts.add("Workbook");
|
||||
// If the file had WORKBOOK instead of Workbook, we'll write it
|
||||
// out correctly shortly, so don't include the old one
|
||||
// If the file had WORKBOOK instead of Workbook, we'll write it
|
||||
// out correctly shortly, so don't include the old one
|
||||
excepts.add("WORKBOOK");
|
||||
|
||||
// Copy over all the other nodes to our new poifs
|
||||
// Copy over all the other nodes to our new poifs
|
||||
copyNodes(this.filesystem,fs,excepts);
|
||||
}
|
||||
fs.writeFilesystem(stream);
|
||||
|
@ -1117,7 +1138,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO - make this less cryptic / move elsewhere
|
||||
* @param refIndex Index to REF entry in EXTERNSHEET record in the Link Table
|
||||
|
@ -1125,76 +1146,76 @@ public class HSSFWorkbook extends POIDocument
|
|||
* @return the string representation of the defined or external name
|
||||
*/
|
||||
public String resolveNameXText(int refIndex, int definedNameIndex) {
|
||||
return workbook.resolveNameXText(refIndex, definedNameIndex);
|
||||
return workbook.resolveNameXText(refIndex, definedNameIndex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the printarea for the sheet provided
|
||||
* <p>
|
||||
* i.e. Reference = $A$1:$B$2
|
||||
* @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
|
||||
* @param reference Valid name Reference for the Print Area
|
||||
*/
|
||||
public void setPrintArea(int sheetIndex, String reference)
|
||||
{
|
||||
NameRecord name = workbook.getSpecificBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
|
||||
/**
|
||||
* Sets the printarea for the sheet provided
|
||||
* <p>
|
||||
* i.e. Reference = $A$1:$B$2
|
||||
* @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
|
||||
* @param reference Valid name Reference for the Print Area
|
||||
*/
|
||||
public void setPrintArea(int sheetIndex, String reference)
|
||||
{
|
||||
NameRecord name = workbook.getSpecificBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
|
||||
|
||||
|
||||
if (name == null)
|
||||
name = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
|
||||
if (name == null)
|
||||
name = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
|
||||
//adding one here because 0 indicates a global named region; doesnt make sense for print areas
|
||||
|
||||
short externSheetIndex = getWorkbook().checkExternSheet(sheetIndex);
|
||||
name.setExternSheetNumber(externSheetIndex);
|
||||
name.setAreaReference(reference);
|
||||
short externSheetIndex = getWorkbook().checkExternSheet(sheetIndex);
|
||||
name.setExternSheetNumber(externSheetIndex);
|
||||
name.setAreaReference(reference);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For the Convenience of Java Programmers maintaining pointers.
|
||||
* @see #setPrintArea(int, String)
|
||||
* @param sheetIndex Zero-based sheet index (0 = First Sheet)
|
||||
* @param startColumn Column to begin printarea
|
||||
* @param endColumn Column to end the printarea
|
||||
* @param startRow Row to begin the printarea
|
||||
* @param endRow Row to end the printarea
|
||||
*/
|
||||
public void setPrintArea(int sheetIndex, int startColumn, int endColumn,
|
||||
int startRow, int endRow) {
|
||||
/**
|
||||
* For the Convenience of Java Programmers maintaining pointers.
|
||||
* @see #setPrintArea(int, String)
|
||||
* @param sheetIndex Zero-based sheet index (0 = First Sheet)
|
||||
* @param startColumn Column to begin printarea
|
||||
* @param endColumn Column to end the printarea
|
||||
* @param startRow Row to begin the printarea
|
||||
* @param endRow Row to end the printarea
|
||||
*/
|
||||
public void setPrintArea(int sheetIndex, int startColumn, int endColumn,
|
||||
int startRow, int endRow) {
|
||||
|
||||
//using absolute references because they don't get copied and pasted anyway
|
||||
CellReference cell = new CellReference(startRow, startColumn, true, true);
|
||||
String reference = cell.formatAsString();
|
||||
//using absolute references because they don't get copied and pasted anyway
|
||||
CellReference cell = new CellReference(startRow, startColumn, true, true);
|
||||
String reference = cell.formatAsString();
|
||||
|
||||
cell = new CellReference(endRow, endColumn, true, true);
|
||||
reference = reference+":"+cell.formatAsString();
|
||||
cell = new CellReference(endRow, endColumn, true, true);
|
||||
reference = reference+":"+cell.formatAsString();
|
||||
|
||||
setPrintArea(sheetIndex, reference);
|
||||
}
|
||||
setPrintArea(sheetIndex, reference);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the reference for the printarea of the specified sheet, the sheet name is appended to the reference even if it was not specified.
|
||||
* @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
|
||||
* @return String Null if no print area has been defined
|
||||
*/
|
||||
public String getPrintArea(int sheetIndex)
|
||||
{
|
||||
NameRecord name = workbook.getSpecificBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
|
||||
if (name == null) return null;
|
||||
//adding one here because 0 indicates a global named region; doesnt make sense for print areas
|
||||
/**
|
||||
* Retrieves the reference for the printarea of the specified sheet, the sheet name is appended to the reference even if it was not specified.
|
||||
* @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
|
||||
* @return String Null if no print area has been defined
|
||||
*/
|
||||
public String getPrintArea(int sheetIndex)
|
||||
{
|
||||
NameRecord name = workbook.getSpecificBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
|
||||
if (name == null) return null;
|
||||
//adding one here because 0 indicates a global named region; doesnt make sense for print areas
|
||||
|
||||
return name.getAreaReference(this);
|
||||
}
|
||||
return name.getAreaReference(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the printarea for the sheet specified
|
||||
* @param sheetIndex Zero-based sheet index (0 = First Sheet)
|
||||
*/
|
||||
public void removePrintArea(int sheetIndex) {
|
||||
getWorkbook().removeBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
|
||||
getWorkbook().removeBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
|
||||
}
|
||||
|
||||
/** creates a new named range and add it to the model
|
||||
|
@ -1213,7 +1234,7 @@ public class HSSFWorkbook extends POIDocument
|
|||
/** gets the named range index by his name
|
||||
* <i>Note:</i>Excel named ranges are case-insensitive and
|
||||
* this method performs a case-insensitive search.
|
||||
*
|
||||
*
|
||||
* @param name named range name
|
||||
* @return named range index
|
||||
*/
|
||||
|
@ -1250,9 +1271,9 @@ public class HSSFWorkbook extends POIDocument
|
|||
* @see org.apache.poi.hssf.record.Record
|
||||
*/
|
||||
public HSSFDataFormat createDataFormat() {
|
||||
if (formatter == null)
|
||||
formatter = new HSSFDataFormat(workbook);
|
||||
return formatter;
|
||||
if (formatter == null)
|
||||
formatter = new HSSFDataFormat(workbook);
|
||||
return formatter;
|
||||
}
|
||||
|
||||
/** remove the named range by his name
|
||||
|
@ -1431,9 +1452,9 @@ public class HSSFWorkbook extends POIDocument
|
|||
* Is the workbook protected with a password (not encrypted)?
|
||||
*/
|
||||
public boolean isWriteProtected() {
|
||||
return this.workbook.isWriteProtected();
|
||||
return this.workbook.isWriteProtected();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* protect a workbook with a password (not encypted, just sets writeprotect
|
||||
* flags and the password.
|
||||
|
|
|
@ -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.util.LittleEndian;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.util.HexDump;
|
||||
|
||||
import java.awt.geom.*;
|
||||
import java.util.ArrayList;
|
||||
|
@ -185,10 +186,6 @@ public class Freeform extends AutoShape {
|
|||
return null;
|
||||
}
|
||||
|
||||
Rectangle2D bounds = getAnchor2D();
|
||||
float right = (float)bounds.getX();
|
||||
float bottom = (float)bounds.getY();
|
||||
|
||||
GeneralPath path = new GeneralPath();
|
||||
int numPoints = verticesProp.getNumberOfElementsInArray();
|
||||
int numSegments = segmentsProp.getNumberOfElementsInArray();
|
||||
|
@ -199,8 +196,8 @@ public class Freeform extends AutoShape {
|
|||
short x = LittleEndian.getShort(p, 0);
|
||||
short y = LittleEndian.getShort(p, 2);
|
||||
path.moveTo(
|
||||
((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(elem, SEGMENTINFO_CUBICTO) || Arrays.equals(elem, SEGMENTINFO_CUBICTO2)){
|
||||
i++;
|
||||
byte[] p1 = verticesProp.getElement(j++);
|
||||
|
@ -213,9 +210,9 @@ public class Freeform extends AutoShape {
|
|||
short x3 = LittleEndian.getShort(p3, 0);
|
||||
short y3 = LittleEndian.getShort(p3, 2);
|
||||
path.curveTo(
|
||||
((float)x1*POINT_DPI/MASTER_DPI + right), ((float)y1*POINT_DPI/MASTER_DPI + bottom),
|
||||
((float)x2*POINT_DPI/MASTER_DPI + right), ((float)y2*POINT_DPI/MASTER_DPI + bottom),
|
||||
((float)x3*POINT_DPI/MASTER_DPI + right), ((float)y3*POINT_DPI/MASTER_DPI + bottom));
|
||||
((float)x1*POINT_DPI/MASTER_DPI), ((float)y1*POINT_DPI/MASTER_DPI),
|
||||
((float)x2*POINT_DPI/MASTER_DPI), ((float)y2*POINT_DPI/MASTER_DPI),
|
||||
((float)x3*POINT_DPI/MASTER_DPI), ((float)y3*POINT_DPI/MASTER_DPI));
|
||||
|
||||
} else if (Arrays.equals(elem, SEGMENTINFO_LINETO)){
|
||||
i++;
|
||||
|
@ -226,18 +223,26 @@ public class Freeform extends AutoShape {
|
|||
short x = LittleEndian.getShort(p, 0);
|
||||
short y = LittleEndian.getShort(p, 2);
|
||||
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)){
|
||||
path.closePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
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 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.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
@ -244,6 +245,9 @@ public class Picture extends SimpleShape {
|
|||
}
|
||||
|
||||
public void draw(Graphics2D graphics){
|
||||
AffineTransform at = graphics.getTransform();
|
||||
ShapePainter.paint(this, graphics);
|
||||
|
||||
PictureData data = getPictureData();
|
||||
if (data instanceof Bitmap){
|
||||
BufferedImage img = null;
|
||||
|
@ -260,5 +264,6 @@ public class Picture extends SimpleShape {
|
|||
} else {
|
||||
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
|
||||
*/
|
||||
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();
|
||||
shape.setSheet(sheet);
|
||||
shape.setShapeId(sheet.allocateShapeId());
|
||||
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){
|
||||
Rectangle2D anchor = getAnchor2D();
|
||||
Rectangle2D coords = getCoordinates();
|
||||
|
||||
//transform coordinates
|
||||
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();
|
||||
for (int i = 0; i < sh.length; i++) {
|
||||
sh[i].draw(graphics);
|
||||
|
|
|
@ -18,12 +18,10 @@
|
|||
|
||||
package org.apache.poi.hslf.model;
|
||||
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherDgRecord;
|
||||
import org.apache.poi.ddf.EscherRecord;
|
||||
import org.apache.poi.ddf.EscherSpRecord;
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
@ -248,15 +246,47 @@ public abstract class Sheet {
|
|||
spgr.addChildRecord(shape.getSpContainer());
|
||||
|
||||
shape.setSheet(this);
|
||||
shape.setShapeId(allocateShapeId());
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by SlideShow ater a new sheet is created
|
||||
*/
|
||||
public void onCreate(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the master sheet .
|
||||
*/
|
||||
|
|
|
@ -126,8 +126,8 @@ public class SimpleShape extends Shape {
|
|||
EscherSimpleProperty p2 = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH);
|
||||
int p2val = p2 == null ? 0 : p2.getPropertyValue();
|
||||
Color clr = null;
|
||||
if (p1 != null && (p2val & 0x8) != 0){
|
||||
int rgb = p1.getPropertyValue();
|
||||
if ((p2val & 0x8) != 0 || (p2val & 0x10) != 0){
|
||||
int rgb = p1 == null ? 0 : p1.getPropertyValue();
|
||||
if (rgb >= 0x8000000) {
|
||||
int idx = rgb % 0x8000000;
|
||||
if(getSheet() != null) {
|
||||
|
|
|
@ -21,12 +21,17 @@
|
|||
package org.apache.poi.hslf.model;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.Iterator;
|
||||
import java.awt.*;
|
||||
|
||||
import org.apache.poi.hslf.record.SlideAtom;
|
||||
import org.apache.poi.hslf.record.TextHeaderAtom;
|
||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||
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
|
||||
|
@ -126,6 +131,42 @@ public class Slide extends Sheet
|
|||
_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.
|
||||
*
|
||||
|
|
|
@ -92,6 +92,7 @@ public class SlideMaster extends MasterSheet {
|
|||
} else {
|
||||
switch (txtype) {
|
||||
case TextHeaderAtom.CENTRE_BODY_TYPE:
|
||||
case TextHeaderAtom.HALF_BODY_TYPE:
|
||||
case TextHeaderAtom.QUARTER_BODY_TYPE:
|
||||
txtype = TextHeaderAtom.BODY_TYPE;
|
||||
break;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.apache.poi.hslf.model;
|
||||
|
||||
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.POILogFactory;
|
||||
|
||||
|
@ -38,6 +39,13 @@ import java.util.ArrayList;
|
|||
public class TextPainter {
|
||||
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;
|
||||
|
||||
public TextPainter(TextShape shape){
|
||||
|
@ -49,6 +57,10 @@ public class TextPainter {
|
|||
*/
|
||||
public AttributedString getAttributedString(TextRun txrun){
|
||||
String text = txrun.getText();
|
||||
//TODO: properly process tabs
|
||||
text = text.replace('\t', ' ');
|
||||
text = text.replace((char)160, ' ');
|
||||
|
||||
AttributedString at = new AttributedString(text);
|
||||
RichTextRun[] rt = txrun.getRichTextRuns();
|
||||
for (int i = 0; i < rt.length; i++) {
|
||||
|
@ -109,7 +121,24 @@ public class TextPainter {
|
|||
}
|
||||
|
||||
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) {
|
||||
wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width;
|
||||
|
@ -141,8 +170,9 @@ public class TextPainter {
|
|||
}
|
||||
|
||||
el._align = rt.getAlignment();
|
||||
el._text = textLayout;
|
||||
el._textOffset = rt.getTextOffset();
|
||||
el.advance = textLayout.getAdvance();
|
||||
el._textOffset = textOffset;
|
||||
el._text = new AttributedString(it, startIndex, endIndex);
|
||||
|
||||
if (prStart){
|
||||
int sp = rt.getSpaceBefore();
|
||||
|
@ -182,13 +212,25 @@ public class TextPainter {
|
|||
Color clr = rt.getBulletColor();
|
||||
if (clr != null) bat.addAttribute(TextAttribute.FOREGROUND, clr);
|
||||
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){
|
||||
el._bullet = bulletLayout;
|
||||
el._bulletOffset = rt.getBulletOffset();
|
||||
el._bullet = bat;
|
||||
el._bulletOffset = bulletOffset;
|
||||
}
|
||||
}
|
||||
lines.add(el);
|
||||
|
@ -225,29 +267,32 @@ public class TextPainter {
|
|||
break;
|
||||
case TextShape.AlignCenter:
|
||||
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;
|
||||
case TextShape.AlignRight:
|
||||
pen.x = anchor.getX() + _shape.getMarginLeft() +
|
||||
(anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight());
|
||||
(anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight());
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class TextElement {
|
||||
public TextLayout _text;
|
||||
public static class TextElement {
|
||||
public AttributedString _text;
|
||||
public int _textOffset;
|
||||
public TextLayout _bullet;
|
||||
public AttributedString _bullet;
|
||||
public int _bulletOffset;
|
||||
public int _align;
|
||||
public float ascent, descent;
|
||||
public float advance;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -535,9 +535,13 @@ public class TextRun
|
|||
// them to \n
|
||||
String text = rawText.replace('\r','\n');
|
||||
|
||||
//0xB acts like cariage return in page titles
|
||||
text = text.replace((char) 0x0B, '\n');
|
||||
|
||||
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');
|
||||
} else {
|
||||
text = text.replace((char) 0x0B, ' ');
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
|
@ -655,4 +659,11 @@ public class TextRun
|
|||
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,17 +261,28 @@ public abstract class TextShape extends SimpleShape {
|
|||
public int getVerticalAlignment(){
|
||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
|
||||
int valign;
|
||||
int valign = TextShape.AnchorTop;
|
||||
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();
|
||||
switch (type){
|
||||
case TextHeaderAtom.TITLE_TYPE:
|
||||
case TextHeaderAtom.CENTER_TITLE_TYPE:
|
||||
valign = TextShape.AnchorMiddle;
|
||||
break;
|
||||
default:
|
||||
valign = TextShape.AnchorTop;
|
||||
break;
|
||||
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){
|
||||
case TextHeaderAtom.TITLE_TYPE:
|
||||
case TextHeaderAtom.CENTER_TITLE_TYPE:
|
||||
valign = TextShape.AnchorMiddle;
|
||||
break;
|
||||
default:
|
||||
valign = TextShape.AnchorTop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
valign = prop.getPropertyValue();
|
||||
|
|
|
@ -24,11 +24,13 @@ import org.apache.poi.util.POILogger;
|
|||
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.hslf.model.ShapeTypes;
|
||||
import org.apache.poi.hslf.model.Shape;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* These are actually wrappers onto Escher drawings. Make use of
|
||||
|
@ -52,6 +54,8 @@ public class PPDrawing extends RecordAtom
|
|||
private EscherRecord[] childRecords;
|
||||
private EscherTextboxWrapper[] textboxWrappers;
|
||||
|
||||
//cached EscherDgRecord
|
||||
private EscherDgRecord dg;
|
||||
|
||||
/**
|
||||
* Get access to the underlying Escher Records
|
||||
|
@ -296,4 +300,24 @@ public class PPDrawing extends RecordAtom
|
|||
tw[textboxWrappers.length] = txtbox;
|
||||
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 TxCFStyleAtom = new Type(4004,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 TextBytesAtom = new Type(4008,TextBytesAtom.class);
|
||||
public static final Type TxSIStyleAtom = new Type(4009,null);
|
||||
|
|
|
@ -127,8 +127,8 @@ public class StyleTextPropAtom extends RecordAtom
|
|||
new ParagraphFlagsTextProp(),
|
||||
new TextProp(2, 0x80, "bullet.char"),
|
||||
new TextProp(2, 0x10, "bullet.font"),
|
||||
new TextProp(2, 0x40, "bullet.size"),
|
||||
new TextProp(4, 0x20, "bullet.color"),
|
||||
new TextProp(2, 0x40, "bullet.size"),
|
||||
new AlignmentTextProp(),
|
||||
new TextProp(2, 0x100, "text.offset"),
|
||||
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.TextPropCollection;
|
||||
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 {
|
||||
protected POILogger logger = POILogFactory.getLogger(this.getClass());
|
||||
|
||||
/** The TextRun we belong to */
|
||||
private TextRun parentRun;
|
||||
/** The SlideShow we belong to */
|
||||
|
@ -199,10 +203,15 @@ public class RichTextRun {
|
|||
}
|
||||
if (prop == null){
|
||||
Sheet sheet = parentRun.getSheet();
|
||||
int txtype = parentRun.getRunType();
|
||||
MasterSheet master = sheet.getMasterSheet();
|
||||
if (master != null)
|
||||
prop = (BitMaskTextProp)master.getStyleAttribute(txtype, getIndentLevel(), propname, isCharacter);
|
||||
if(sheet != null){
|
||||
int txtype = parentRun.getRunType();
|
||||
MasterSheet master = sheet.getMasterSheet();
|
||||
if (master != null){
|
||||
prop = (BitMaskTextProp)master.getStyleAttribute(txtype, getIndentLevel(), propname, isCharacter);
|
||||
}
|
||||
} else {
|
||||
logger.log(POILogger.WARN, "MasterSheet is not available");
|
||||
}
|
||||
}
|
||||
|
||||
return prop == null ? false : prop.getSubValue(index);
|
||||
|
@ -213,7 +222,7 @@ public class RichTextRun {
|
|||
* it if required.
|
||||
*/
|
||||
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) {
|
||||
|
@ -281,10 +290,14 @@ public class RichTextRun {
|
|||
*/
|
||||
private int getParaTextPropVal(String propName) {
|
||||
TextProp prop = null;
|
||||
boolean hardAttribute = false;
|
||||
if (paragraphStyle != null){
|
||||
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();
|
||||
int txtype = parentRun.getRunType();
|
||||
MasterSheet master = sheet.getMasterSheet();
|
||||
|
@ -574,6 +587,13 @@ public class RichTextRun {
|
|||
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
|
||||
*/
|
||||
|
|
|
@ -24,10 +24,7 @@ import java.util.*;
|
|||
import java.awt.Dimension;
|
||||
import java.io.*;
|
||||
|
||||
import org.apache.poi.ddf.EscherBSERecord;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherOptRecord;
|
||||
import org.apache.poi.ddf.EscherRecord;
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
import org.apache.poi.hslf.model.Notes;
|
||||
|
@ -66,9 +63,7 @@ public class SlideShow
|
|||
// Lookup between the PersitPtr "sheet" IDs, and the position
|
||||
// in the mostRecentCoreRecords array
|
||||
private Hashtable _sheetIdToCoreRecordsLookup;
|
||||
// Used when adding new core records
|
||||
private int _highestSheetId;
|
||||
|
||||
|
||||
// Records that are interesting
|
||||
private Document _documentRecord;
|
||||
|
||||
|
@ -203,8 +198,6 @@ public class SlideShow
|
|||
for(int i=0; i<allIDs.length; 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
|
||||
for(int i=0; i<_records.length; i++) {
|
||||
|
@ -612,38 +605,35 @@ public class SlideShow
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set up a new SlidePersistAtom for this slide
|
||||
|
||||
// Set up a new SlidePersistAtom for this slide
|
||||
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
|
||||
sp.setSlideIdentifier(prev == null ? 256 : (prev.getSlideIdentifier() + 1));
|
||||
|
||||
|
||||
// Add this new SlidePersistAtom to the SlideListWithText
|
||||
slist.addSlidePersistAtom(sp);
|
||||
|
||||
|
||||
|
||||
|
||||
// Create a new Slide
|
||||
Slide slide = new Slide(sp.getSlideIdentifier(), sp.getRefID(), _slides.length+1);
|
||||
slide.setSlideShow(this);
|
||||
slide.onCreate();
|
||||
|
||||
// Add in to the list of Slides
|
||||
Slide[] s = new Slide[_slides.length+1];
|
||||
System.arraycopy(_slides, 0, s, 0, _slides.length);
|
||||
s[_slides.length] = slide;
|
||||
_slides = s;
|
||||
logger.log(POILogger.INFO, "Added slide " + _slides.length + " with ref " + sp.getRefID() + " and identifier " + sp.getSlideIdentifier());
|
||||
|
||||
|
||||
// Add the core records for this new Slide to the record tree
|
||||
org.apache.poi.hslf.record.Slide slideRecord = slide.getSlideRecord();
|
||||
slideRecord.setSheetId(sp.getRefID());
|
||||
int slideRecordPos = _hslfSlideShow.appendRootLevelRecord(slideRecord);
|
||||
_records = _hslfSlideShow.getRecords();
|
||||
|
||||
|
||||
// Add the new Slide into the PersistPtr stuff
|
||||
int offset = 0;
|
||||
int slideOffset = 0;
|
||||
|
@ -653,7 +643,7 @@ public class SlideShow
|
|||
Record record = _records[i];
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
record.writeOut(out);
|
||||
|
||||
|
||||
// Grab interesting records as they come past
|
||||
if(_records[i].getRecordType() == RecordTypes.PersistPtrIncrementalBlock.typeID){
|
||||
ptr = (PersistPtrHolder)_records[i];
|
||||
|
@ -661,25 +651,29 @@ public class SlideShow
|
|||
if(_records[i].getRecordType() == RecordTypes.UserEditAtom.typeID) {
|
||||
usr = (UserEditAtom)_records[i];
|
||||
}
|
||||
|
||||
|
||||
if(i == slideRecordPos) {
|
||||
slideOffset = offset;
|
||||
}
|
||||
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
|
||||
// (Also need to tell it where it is)
|
||||
slideRecord.setLastOnDiskOffset(slideOffset);
|
||||
ptr.addSlideLookup(sp.getRefID(), 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
|
||||
slide.setSlideShow(this);
|
||||
return slide;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public class TestFreeform extends TestCase {
|
|||
Freeform p = new Freeform();
|
||||
p.setPath(path1);
|
||||
|
||||
GeneralPath path2 = p.getPath();
|
||||
java.awt.Shape path2 = p.getOutline();
|
||||
assertTrue(new Area(path1).equals(new Area(path2)));
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ public class TestFreeform extends TestCase {
|
|||
Freeform p = new Freeform();
|
||||
p.setPath(path1);
|
||||
|
||||
GeneralPath path2 = p.getPath();
|
||||
java.awt.Shape path2 = p.getOutline();
|
||||
assertTrue(new Area(path1).equals(new Area(path2)));
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ public class TestFreeform extends TestCase {
|
|||
Freeform p = new Freeform();
|
||||
p.setPath(path1);
|
||||
|
||||
GeneralPath path2 = p.getPath();
|
||||
java.awt.Shape path2 = p.getOutline();
|
||||
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.RichTextRun;
|
||||
import org.apache.poi.hslf.HSLFSlideShow;
|
||||
import org.apache.poi.ddf.EscherDggRecord;
|
||||
import org.apache.poi.ddf.EscherDgRecord;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Rectangle;
|
||||
|
@ -311,18 +313,49 @@ public class TestShapes extends TestCase {
|
|||
public void testShapeId() throws IOException {
|
||||
SlideShow ppt = new SlideShow();
|
||||
Slide slide = ppt.createSlide();
|
||||
Shape shape;
|
||||
Shape shape = null;
|
||||
|
||||
shape = new Line();
|
||||
assertEquals(0, shape.getShapeId());
|
||||
slide.addShape(shape);
|
||||
assertTrue(shape.getShapeId() > 0);
|
||||
//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 shapeId = shape.getShapeId();
|
||||
int dggShapesUsed = dgg.getNumShapesSaved(); //total number of shapes in the ppt
|
||||
int dggMaxId = dgg.getShapeIdMax(); //max number of shapeId
|
||||
|
||||
shape = new Line();
|
||||
assertEquals(0, shape.getShapeId());
|
||||
slide.addShape(shape);
|
||||
assertEquals(shapeId + 1, shape.getShapeId());
|
||||
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();
|
||||
assertEquals(0, shape.getShapeId());
|
||||
slide.addShape(shape);
|
||||
assertTrue(shape.getShapeId() > 0);
|
||||
|
||||
//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();
|
||||
slide.addShape(shape);
|
||||
}
|
||||
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,9 +90,11 @@ public class TestRichTextRun extends TestCase {
|
|||
|
||||
// Now set it to not bold
|
||||
rtr.setBold(false);
|
||||
assertNotNull(rtr._getRawCharacterStyle());
|
||||
assertNotNull(rtr._getRawParagraphStyle());
|
||||
assertFalse(rtr.isBold());
|
||||
//setting bold=false doesn't change the internal state
|
||||
assertNull(rtr._getRawCharacterStyle());
|
||||
assertNull(rtr._getRawParagraphStyle());
|
||||
|
||||
assertFalse(rtr.isBold());
|
||||
|
||||
// And now make it bold
|
||||
rtr.setBold(true);
|
||||
|
|
|
@ -42,6 +42,7 @@ public final class AllPOIDDFTests {
|
|||
result.addTestSuite(TestEscherSplitMenuColorsRecord.class);
|
||||
result.addTestSuite(TestEscherSpRecord.class);
|
||||
result.addTestSuite(TestUnknownEscherRecord.class);
|
||||
result.addTestSuite(TestEscherBlipRecord.class);
|
||||
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,13 +18,24 @@
|
|||
|
||||
package org.apache.poi.ddf;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.poi.util.HexRead;
|
||||
import org.apache.poi.util.HexDump;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
|
||||
public class TestEscherContainerRecord extends TestCase
|
||||
{
|
||||
public void testFillFields() throws Exception
|
||||
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
|
||||
{
|
||||
EscherRecordFactory f = new DefaultEscherRecordFactory();
|
||||
byte[] data = HexRead.readFromString( "0F 02 11 F1 00 00 00 00" );
|
||||
|
@ -137,4 +148,19 @@ public class TestEscherContainerRecord extends TestCase
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
|
||||
Ptg[] ptgs = {
|
||||
new FuncPtg(10, 0),
|
||||
new FuncPtg(10),
|
||||
};
|
||||
assertEquals("NA()", FormulaParser.toFormulaString(book, ptgs));
|
||||
}
|
||||
|
@ -900,4 +900,21 @@ public final class TestFormulaParser extends TestCase {
|
|||
assertEquals(2, ptgs.length);
|
||||
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(TestExternalFunctionFormulas.class);
|
||||
result.addTestSuite(TestFuncPtg.class);
|
||||
result.addTestSuite(TestFuncVarPtg.class);
|
||||
result.addTestSuite(TestIntersectionPtg.class);
|
||||
result.addTestSuite(TestPercentPtg.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
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -18,20 +17,22 @@
|
|||
|
||||
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.HSSFWorkbook;
|
||||
|
||||
/**
|
||||
* Tests for {@link ReferencePtg}.
|
||||
*/
|
||||
public class TestReferencePtg extends AbstractPtgTestCase
|
||||
{
|
||||
public final class TestReferencePtg extends TestCase {
|
||||
/**
|
||||
* Tests reading a file containing this ptg.
|
||||
*/
|
||||
public void testReading() throws Exception
|
||||
{
|
||||
HSSFWorkbook workbook = loadWorkbook("ReferencePtg.xls");
|
||||
public void testReading() {
|
||||
HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook("ReferencePtg.xls");
|
||||
HSSFSheet sheet = workbook.getSheetAt(0);
|
||||
|
||||
// First row
|
||||
|
@ -72,6 +73,18 @@ public class TestReferencePtg extends AbstractPtgTestCase
|
|||
assertEquals("Wrong formula string for reference", "A32770",
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.usermodel;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
@ -46,6 +46,7 @@ public class AllUserModelTests {
|
|||
result.addTestSuite(TestHSSFHeaderFooter.class);
|
||||
result.addTestSuite(TestHSSFHyperlink.class);
|
||||
result.addTestSuite(TestHSSFPalette.class);
|
||||
result.addTestSuite(TestHSSFPatriarch.class);
|
||||
result.addTestSuite(TestHSSFPicture.class);
|
||||
result.addTestSuite(TestHSSFPictureData.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.
|
||||
*/
|
||||
public void test28774() {
|
||||
|
||||
HSSFWorkbook wb = openSample("28774.xls");
|
||||
assertTrue("no errors reading sample xls", true);
|
||||
writeOutAndReadBack(wb);
|
||||
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.FileOutputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
@ -252,4 +253,29 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
|
|||
}
|
||||
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;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
|
@ -36,7 +32,7 @@ public final class TestHSSFPicture extends TestCase{
|
|||
HSSFSheet sh1 = wb.createSheet();
|
||||
HSSFPatriarch p1 = sh1.createDrawingPatriarch();
|
||||
|
||||
byte[] pictureData = getTestDataFileContent("logoKarmokar4.png");
|
||||
byte[] pictureData = HSSFTestDataSamples.getTestDataFileContent("logoKarmokar4.png");
|
||||
int idx1 = wb.addPicture( pictureData, HSSFWorkbook.PICTURE_TYPE_PNG );
|
||||
HSSFPicture picture1 = p1.createPicture(new HSSFClientAnchor(), idx1);
|
||||
HSSFClientAnchor anchor1 = picture1.getPreferredSize();
|
||||
|
@ -51,28 +47,4 @@ public final class TestHSSFPicture extends TestCase{
|
|||
assertEquals(848, anchor1.getDx2());
|
||||
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;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
|
@ -39,7 +40,24 @@ public final class TestHSSFWorkbook extends TestCase {
|
|||
NameRecord nameRecord = b.getWorkbook().getNameRecord( 0 );
|
||||
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() {
|
||||
HSSFWorkbook b = new HSSFWorkbook( );
|
||||
b.createSheet("Sheet1");
|
||||
|
|
Loading…
Reference in New Issue