merge trunk to common sl branch

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/common_sl@1691843 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2015-07-19 19:00:32 +00:00
commit d439f080d6
639 changed files with 27028 additions and 17686 deletions

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -152,6 +152,7 @@ org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
@ -197,6 +198,7 @@ org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
@ -244,6 +246,7 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=inser
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
@ -321,6 +324,7 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do n
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.moreunit.preferences.version=2
org.moreunit.unitsourcefolder=ApachePOI\:src/java\:ApachePOI\:src/testcases\#ApachePOI\:src/java\:ApachePOI\:src/ooxml/testcases\#ApachePOI\:src/java\:ApachePOI\:src/scratchpad/testcases\#ApachePOI\:src/java\:ApachePOI\:src/excelant/testcases\#ApachePOI\:src/java\:ApachePOI\:src/integrationtest
org.moreunit.useprojectsettings=true

345
KEYS
View File

@ -1796,3 +1796,348 @@ qoiVaXWfFHwg8u4bSHunrzNja17GyaZHdCEmM9vFzlaqBkoLWCMwIcaKnX9stQJp
FZwpzgut7DanaPcCDk7LMBbntaJwRC72M0qcj16SUAdAuGt1yQ==
=0DjT
-----END PGP PUBLIC KEY BLOCK-----
pub 4096R/B4812553 2014-02-26 [expires: 2019-02-25]
uid David North <david@dnorth.net>
uid David North (Oxford CompSoc) <north@ox.compsoc.net>
uid David North (ASF Committer ID) <dnorth@apache.org>
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
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
=keWk
-----END PGP PUBLIC KEY BLOCK-----
pub 4096R/27B9F635 2015-06-22
uid Dominik Stadler <centic@apache.org>
sub 4096R/EF9D5EA6 2015-06-22
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
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
kg==
=rPGm
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -47,8 +47,8 @@ under the License.
<description>The Apache POI project Ant build.</description>
<property name="version.id" value="3.12-beta1"/>
<property name="version.rel" value="REL_3_12_BETA1"/>
<property name="version.id" value="3.13-beta1"/>
<property name="version.rel" value="REL_3_13_BETA1"/>
<property environment="env"/>
<!-- the repository to download jars from -->
@ -82,7 +82,11 @@ under the License.
<property name="POI.testdata.path" value="test-data"/>
<property name="java.awt.headless" value="true"/>
<property name="additionaljar" value=""/>
<property name="http_proxy" value="${env.http_proxy}"/>
<condition property="http_proxy"
value="${env.http_proxy}"
else="">
<isset property="env.http_proxy"/>
</condition>
<!-- Main: -->
<property name="main.resource1.dir" value="src/resources/main"/>
@ -175,8 +179,8 @@ under the License.
value="${repository.m2}/maven2/org/apache/xmlbeans/xmlbeans/2.6.0/xmlbeans-2.6.0.jar"/>
<!-- coverage libs -->
<property name="jacoco.zip" location="${main.lib}/jacoco-0.7.2.201409121644.zip"/>
<property name="jacoco.url" value="${repository.m2}/maven2/org/jacoco/jacoco/0.7.2.201409121644/jacoco-0.7.2.201409121644.zip"/>
<property name="jacoco.zip" location="${main.lib}/jacoco-0.7.4.201502262128.zip"/>
<property name="jacoco.url" value="${repository.m2}/maven2/org/jacoco/jacoco/0.7.4.201502262128/jacoco-0.7.4.201502262128.zip"/>
<property name="asm.jar" location="${main.lib}/asm-all-5.0.3.jar"/>
<property name="asm.url" value="${repository.m2}/maven2/org/ow2/asm/asm-all/5.0.3/asm-all-5.0.3.jar"/>
@ -263,10 +267,11 @@ under the License.
<pathelement location="${ooxml.xsds.jar}"/>
<path refid="main.classpath"/>
<pathelement location="${main.output.dir}"/>
<pathelement location="${scratchpad.output.dir}"/>
<pathelement location="${ooxml.security.jar}"/>
<!-- classes are omitted on test cases outside the xml-dsign area to avoid classpath poisioning -->
<!--path refid="ooxml.xmlsec.classpath"/-->
<!-- Used only for ExtractorFactory, see #57963 -->
<pathelement location="${scratchpad.output.dir}"/>
</path>
<path id="test.classpath">
@ -360,6 +365,8 @@ under the License.
- compile Compile all files from main, ooxml and scratchpad
- test Run all unit tests from main, ooxml and scratchpad
- jar Produce jar files
- jar-src Produce source-jar files
- assemble Produce the zipped distribution files
- site Generate all documentation (Requires Apache Forrest)
- dist Create a distribution (Requires Apache Forrest)
</echo>
@ -409,6 +416,7 @@ under the License.
<!-- remove previous versions of third-party jars to prevent them from lingering around,
we often had hard-to-find build/CI-problems because of these! -->
<mkdir dir="${main.lib}"/>
<mkdir dir="${compile.lib}"/>
<delete verbose="true">
<fileset dir="${main.lib}">
<include name="ant-1.8*"/>
@ -417,9 +425,13 @@ under the License.
<include name="commons-logging-1.1.jar"/>
<include name="jacoco-0.6*"/>
<include name="jacoco-0.7.1*"/>
<include name="jacoco-0.7.2*"/>
<include name="jacoco-0.7.3*"/>
<include name="log4j-1.2.13*"/>
<include name="org.jacoco.*-0.6.*"/>
<include name="org.jacoco.*-0.7.1*"/>
<include name="org.jacoco.*-0.7.2*"/>
<include name="org.jacoco.*-0.7.3*"/>
<include name="dom4j*"/>
<include name="apache-rat-0.10*"/>
<include name="xercesImpl-*.jar"/>
@ -721,7 +733,7 @@ under the License.
<headfilter lines="16"/>
</filterchain>
</copy>
<copy todir="${scratchpad.src}">
<copy todir="${main.src}">
<fileset dir="${geometry.output.tmpdir}" includes="**/*.java"/>
<filterchain>
<concatfilter prepend="${geometry.output.tmpdir}/apache-license.txt"/>
@ -976,7 +988,7 @@ under the License.
<xml destfile="${coverage.dir}/coverage.xml"/>
</jacoco:report>
<echo message="Coverage results are available at coverage\index.html, coverage/coverage.xml" />
<echo message="Coverage results are available at ${coverage.dir}/index.html, ${coverage.dir}/coverage.xml" />
</target>
<target name="-test-main-check">
@ -1280,7 +1292,7 @@ under the License.
description="Generates the API documentation">
<javadoc verbose="false" author="true" destdir="${apidocs.report.dir}"
windowtitle="POI API Documentation" use="true" version="true"
maxmemory="384M" additionalparam="-notimestamp"
maxmemory="384M" additionalparam="-notimestamp" locale="en_US"
classpathref="javadoc.classpath">
<packageset dir="${main.src}" defaultexcludes="yes">
<include name="org/apache/poi/**"/>
@ -1440,7 +1452,7 @@ under the License.
</jar>
</target>
<target name="jar-src" description="Sources for Maven">
<target name="jar-src" depends="compile-all, compile-version, -manifest" description="Sources for Maven">
<jar destfile="${dist.dir}/${jar.name}-${version.id}-sources-${DSTAMP}.jar"
manifest="build/poi-manifest.mf">
<fileset dir="${main.src}"/>
@ -1508,12 +1520,12 @@ under the License.
<mkdir dir="${build.maven.javadocs}"/>
<javadoc verbose="false" author="false" destdir="${build.maven.javadocs}"
windowtitle="POI API Documentation" use="false" version="false"
maxmemory="384M" additionalparam="-notimestamp -quiet"
maxmemory="384M" additionalparam="-notimestamp -quiet" locale="en_US"
classpathref="javadoc.classpath">
<packageset dir="${srcfolder}" defaultexcludes="yes">
<include name="org/apache/poi/**"/>
</packageset>
<link href="https://poi.apache.org/apidocs" packagelistLoc="build/tmp/site/build/site/apidocs"/>
<link offline="true" href="https://poi.apache.org/apidocs" packagelistLoc="build/tmp/site/build/site/apidocs"/>
</javadoc>
<jar destfile="${dist.dir}/${jarname}-${version.id}-javadocs-${DSTAMP}.jar"
manifest="build/poi-manifest.mf">
@ -1628,6 +1640,14 @@ under the License.
<echo>Use ${dist.dir}/multisign.sh to create md5 checksums and GPG signatures</echo>
</target>
<target name="osgi" depends="mvn-install">
<echo message="Building OSGi bundle via Maven" />
<mvn:mvn pom="osgi/pom.xml">
<arg value="-Dpoi.version=${version.id}" />
<arg value="install" />
</mvn:mvn>
</target>
<target name="dist" depends="clean, compile-all, test-all, site, jar, release-notes, assemble"
description="Creates the entire distribution into build/dist, from scratch">
</target>
@ -1745,6 +1765,29 @@ under the License.
<sourcePath path="src/ooxml/java" />
<sourcePath path="src/scratchpad/src" />
</findbugs>
<findbugs home="${findbugs.home}" output="xml" outputFile="build/findbugs.xml"
excludeFilter="src/resources/devtools/findbugs-filters.xml">
<fileset dir="${dist.dir}">
<include name="poi-${version.id}-*.jar"/>
<include name="poi-scratchpad-${version.id}-*.jar"/>
<include name="poi-ooxml-${version.id}-*.jar"/>
<exclude name="poi-*${version.id}-sources-*.jar"/>
<exclude name="poi-*${version.id}-javadocs-*.jar"/>
</fileset>
<auxClasspath path="${compile.lib}/bcpkix-jdk15on-1.51.jar" />
<auxClasspath path="${compile.lib}/bcprov-ext-jdk15on-1.51.jar" />
<auxClasspath path="${compile.lib}/slf4j-api-1.7.7.jar" />
<auxClasspath path="${compile.lib}/xmlsec-2.0.1.jar" />
<auxClasspath path="ooxml-lib/ooxml-schemas-1.1.jar" />
<auxClasspath path="ooxml-lib/ooxml-security-1.0.jar" />
<auxClasspath path="ooxml-lib/xmlbeans-2.6.0.jar" />
<auxClasspath path="lib/commons-codec-1.9.jar" />
<auxClasspath path="lib/commons-logging-1.1.3.jar" />
<auxClasspath path="lib/junit-4.12.jar" />
<sourcePath path="src/java" />
<sourcePath path="src/ooxml/java" />
<sourcePath path="src/scratchpad/src" />
</findbugs>
</target>
<target name="test-scratchpad-download-resources">

View File

@ -19,22 +19,56 @@
<programming-language>Java</programming-language>
<category rdf:resource="http://projects.apache.org/category/content" />
<category rdf:resource="http://projects.apache.org/category/library" />
<release>
<Version>
<name>Apache POI 3.12</name>
<created>2015-05-11</created>
<revision>3.12</revision>
</Version>
</release>
<release>
<Version>
<name>Apache POI 3.11</name>
<created>2014-12-21</created>
<revision>3.11</revision>
</Version>
</release>
<release>
<Version>
<name>Apache POI 3.10.1</name>
<created>2014-08-18</created>
<revision>3.10.1</revision>
</Version>
</release>
<release>
<Version>
<name>Apache POI 3.10</name>
<created>2014-02-08</created>
<revision>3.10</revision>
</Version>
</release>
<release>
<Version>
<name>Apache POI 3.9</name>
<created>2012-12-03</created>
<revision>3.9</revision>
</Version>
</release>
<release>
<Version>
<name>Apache POI 3.8</name>
<created>2012-03-26</created>
<revision>3.8</revision>
</Version>
</release>
<release>
<Version>
<name>Apache POI 3.7</name>
<created>2010-10-29</created>
<revision>3.7</revision>
</Version>
</release>
<release>
<Version>
<name>Apache POI 3.6</name>
<created>2009-12-14</created>

View File

@ -1,5 +1,5 @@
Apache POI
Copyright 2003-2014 The Apache Software Foundation
Copyright 2003-2015 The Apache Software Foundation
This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).

229
osgi/pom.xml Normal file
View File

@ -0,0 +1,229 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache</groupId>
<artifactId>apache</artifactId>
<version>10</version>
<relativePath />
</parent>
<groupId>org.apache.poi</groupId>
<artifactId>poi-bundle</artifactId>
<packaging>bundle</packaging>
<name>Apache POI OSGi bundle</name>
<description>
OSGi bundle that contains Apache POI, and the dependencies.
</description>
<url>http://poi.apache.org/</url>
<version>${poi.version}</version>
<!--
<version>3.12-beta2</version>
<version>@VERSION@</version>
-->
<properties>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<pax.exam.version>4.4.0</pax.exam.version>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId>
<version>${pax.exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-native</artifactId>
<version>${pax.exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.framework</artifactId>
<version>4.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-link-assembly</artifactId>
<version>${pax.exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.url</groupId>
<artifactId>pax-url-aether</artifactId>
<version>2.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-Activator>
org.apache.poi.osgi.Activator
</Bundle-Activator>
<Embed-Dependency>
poi;inline=true,
poi-scratchpad;inline=true,
poi-ooxml;inline=true,
poi-ooxml-schemas,
xmlbeans
</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
<Bundle-DocURL>${project.url}</Bundle-DocURL>
<Export-Package>
org.apache.poi.*
</Export-Package>
<Import-Package>
!org.junit,
*,
org.apache.xmlbeans.impl.xpath.saxon;resolution:=optional,
org.apache.xmlbeans.impl.xquery.saxon;resolution:=optional,
org.bouncycastle.cert;resolution:=optional,
org.bouncycastle.cert.ocsp;resolution:=optional,
org.bouncycastle.cms.bc;resolution:=optional,
org.bouncycastle.cert.jcajce;resolution:=optional,
org.bouncycastle.operator;resolution:=optional,
org.bouncycastle.operator.bc;resolution:=optional,
org.bouncycastle.tsp;resolution:=optional,
org.openxmlformats.schemas.officeDocument.x2006.math;resolution:=optional,
org.openxmlformats.schemas.schemaLibrary.x2006.main;resolution:=optional,
schemasMicrosoftComOfficePowerpoint;resolution:=optional,
schemasMicrosoftComOfficeWord;resolution:=optional,
</Import-Package>
</instructions>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>java6</id>
<activation>
<jdk>[1.6,)</jdk>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>pre-integration-test</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptor>test-bundles.xml</descriptor>
<finalName>test</finalName>
<attach>false</attach>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<org.ops4j.pax.logging.DefaultServiceLog.level>
WARN
</org.ops4j.pax.logging.DefaultServiceLog.level>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<organization>
<name>The Apache Software Founation</name>
<url>http://www.apache.org</url>
</organization>
<scm>
<url>http://svn.apache.org/viewvc/poi/trunk/osgi</url>
<connection>scm:svn:http://svn.apache.org/repos/asf/poi/trunk/osgi</connection>
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/poi/trunk/osgi</developerConnection>
</scm>
</project>

View File

@ -0,0 +1,28 @@
/* ====================================================================
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.osgi;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class Activator implements BundleActivator {
public void start(BundleContext context) throws Exception {
}
public void stop(BundleContext context) throws Exception {
}
}

View File

@ -0,0 +1,84 @@
/* ====================================================================
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.osgi;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.ops4j.pax.exam.CoreOptions.bundle;
import static org.ops4j.pax.exam.CoreOptions.junitBundles;
import static org.ops4j.pax.exam.CoreOptions.options;
import javax.inject.Inject;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerMethod;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
/**
* Test to ensure that all our main formats can create, write
* and read back in, when running under OSGi
*/
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerMethod.class)
public class TestOSGiBundle {
private final File TARGET = new File("target");
@Inject
private BundleContext bc;
@Configuration
public Option[] configuration() throws IOException, URISyntaxException {
File base = new File(TARGET, "test-bundles");
return options(
junitBundles(),
bundle(new File(base, "poi-bundle.jar").toURI().toURL().toString()));
}
@Test
public void testHSSF() throws Exception {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet("OSGi");
s.createRow(0).createCell(0).setCellValue("With OSGi");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
wb.write(baos);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
wb = new HSSFWorkbook(bais);
assertEquals(1, wb.getNumberOfSheets());
s = wb.getSheet("OSGi");
assertEquals("With OSGi", s.getRow(0).getCell(0).toString());
}
}

34
osgi/test-bundles.xml Normal file
View File

@ -0,0 +1,34 @@
<!--
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.
-->
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>bundles</id>
<formats>
<format>dir</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory/>
<outputFileNameMapping>${artifact.artifactId}.jar</outputFileNameMapping>
<includes>
<include>org.apache.poi:poi-bundle</include>
</includes>
</dependencySet>
</dependencySets>
</assembly>

View File

@ -93,12 +93,12 @@ public class ReadCustomPropertySets
out(" No. of sections: " + sectionCount);
/* Print the list of sections: */
List sections = ps.getSections();
List<Section> sections = ps.getSections();
int nr = 0;
for (Iterator i = sections.iterator(); i.hasNext();)
for (Iterator<Section> i = sections.iterator(); i.hasNext();)
{
/* Print a single section: */
Section sec = (Section) i.next();
Section sec = i.next();
out(" Section " + nr++ + ":");
String s = hex(sec.getFormatID().getBytes());
s = s.substring(0, s.length() - 1);

View File

@ -50,5 +50,7 @@ public class CreateCells {
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
fileOut.close();
wb.close();
}
}

View File

@ -21,6 +21,8 @@ package org.apache.poi.ss.examples;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.ConditionalFormattingThreshold.RangeType;
import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
@ -31,10 +33,9 @@ import java.io.IOException;
* Excel Conditional Formatting -- Examples
*
* <p>
* Based on the code snippets from http://www.contextures.com/xlcondformat03.html
* Partly based on the code snippets from
* http://www.contextures.com/xlcondformat03.html
* </p>
*
* @author Yegor Kozlov
*/
public class ConditionalFormats {
@ -46,6 +47,7 @@ public class ConditionalFormats {
sameCell(wb.createSheet("Same Cell"));
multiCell(wb.createSheet("MultiCell"));
overlapping(wb.createSheet("Overlapping"));
errors(wb.createSheet("Errors"));
hideDupplicates(wb.createSheet("Hide Dups"));
formatDuplicates(wb.createSheet("Duplicates"));
@ -53,6 +55,9 @@ public class ConditionalFormats {
expiry(wb.createSheet("Expiry"));
shadeAlt(wb.createSheet("Shade Alt"));
shadeBands(wb.createSheet("Shade Bands"));
iconSets(wb.createSheet("Icon Sets"));
// TODO Add colour scales, data bars etc, see bug #58130
// Write the output to a file
String file = "cf-poi.xls";
@ -60,7 +65,7 @@ public class ConditionalFormats {
FileOutputStream out = new FileOutputStream(file);
wb.write(out);
out.close();
System.out.println("Generated: " + file);
}
/**
@ -140,6 +145,71 @@ public class ConditionalFormats {
sheet.getRow(2).createCell(4).setCellValue("<== Condition 1: Formula Is =$B2>75 (Blue Fill)");
}
/**
* Multiple conditional formatting rules can apply to
* one cell, some combining, some beating others.
* Done in order of the rules added to the
* SheetConditionalFormatting object
*/
static void overlapping(Sheet sheet) {
for (int i=0; i<40; i++) {
int rn = i+1;
Row r = sheet.createRow(i);
r.createCell(0).setCellValue("This is row " + rn + " (" + i + ")");
String str = "";
if (rn%2 == 0) str = str + "even ";
if (rn%3 == 0) str = str + "x3 ";
if (rn%5 == 0) str = str + "x5 ";
if (rn%10 == 0) str = str + "x10 ";
if (str.length() == 0) str = "nothing special...";
r.createCell(1).setCellValue("It is " + str);
}
sheet.autoSizeColumn(0);
sheet.autoSizeColumn(1);
sheet.getRow(1).createCell(3).setCellValue("Even rows are blue");
sheet.getRow(2).createCell(3).setCellValue("Multiples of 3 have a grey background");
sheet.getRow(4).createCell(3).setCellValue("Multiples of 5 are bold");
sheet.getRow(9).createCell(3).setCellValue("Multiples of 10 are red (beats even)");
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
// Condition 1: Row divides by 10, red (will beat #1)
ConditionalFormattingRule rule1 =
sheetCF.createConditionalFormattingRule("MOD(ROW(),10)=0");
FontFormatting font1 = rule1.createFontFormatting();
font1.setFontColorIndex(IndexedColors.RED.index);
// Condition 2: Row is even, blue
ConditionalFormattingRule rule2 =
sheetCF.createConditionalFormattingRule("MOD(ROW(),2)=0");
FontFormatting font2 = rule2.createFontFormatting();
font2.setFontColorIndex(IndexedColors.BLUE.index);
// Condition 3: Row divides by 5, bold
ConditionalFormattingRule rule3 =
sheetCF.createConditionalFormattingRule("MOD(ROW(),5)=0");
FontFormatting font3 = rule3.createFontFormatting();
font3.setFontStyle(false, true);
// Condition 4: Row divides by 3, grey background
ConditionalFormattingRule rule4 =
sheetCF.createConditionalFormattingRule("MOD(ROW(),3)=0");
PatternFormatting fill4 = rule4.createPatternFormatting();
fill4.setFillBackgroundColor(IndexedColors.GREY_25_PERCENT.index);
fill4.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
// Apply
CellRangeAddress[] regions = {
CellRangeAddress.valueOf("A1:F41")
};
sheetCF.addConditionalFormatting(regions, rule1);
sheetCF.addConditionalFormatting(regions, rule2);
sheetCF.addConditionalFormatting(regions, rule3);
sheetCF.addConditionalFormatting(regions, rule4);
}
/**
* Use Excel conditional formatting to check for errors,
* and change the font colour to match the cell colour.
@ -346,4 +416,64 @@ public class ConditionalFormats {
sheet.createRow(0).createCell(1).setCellValue("Shade Bands of Rows");
sheet.createRow(1).createCell(1).setCellValue("Condition: Formula Is =MOD(ROW(),6)<2 (Light Grey Fill)");
}
/**
* Icon Sets / Multi-States allow you to have icons shown which vary
* based on the values, eg Red traffic light / Yellow traffic light /
* Green traffic light
*/
static void iconSets(Sheet sheet) {
sheet.createRow(0).createCell(0).setCellValue("Icon Sets");
Row r = sheet.createRow(1);
r.createCell(0).setCellValue("Reds");
r.createCell(1).setCellValue(0);
r.createCell(2).setCellValue(0);
r.createCell(3).setCellValue(0);
r = sheet.createRow(2);
r.createCell(0).setCellValue("Yellows");
r.createCell(1).setCellValue(5);
r.createCell(2).setCellValue(5);
r.createCell(3).setCellValue(5);
r = sheet.createRow(3);
r.createCell(0).setCellValue("Greens");
r.createCell(1).setCellValue(10);
r.createCell(2).setCellValue(10);
r.createCell(3).setCellValue(10);
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
CellRangeAddress[] regions = { CellRangeAddress.valueOf("B1:B4") };
ConditionalFormattingRule rule1 =
sheetCF.createConditionalFormattingRule(IconSet.GYR_3_TRAFFIC_LIGHTS);
IconMultiStateFormatting im1 = rule1.getMultiStateFormatting();
im1.getThresholds()[0].setRangeType(RangeType.MIN);
im1.getThresholds()[1].setRangeType(RangeType.PERCENT);
im1.getThresholds()[1].setValue(33d);
im1.getThresholds()[2].setRangeType(RangeType.MAX);
sheetCF.addConditionalFormatting(regions, rule1);
regions = new CellRangeAddress[] { CellRangeAddress.valueOf("C1:C4") };
ConditionalFormattingRule rule2 =
sheetCF.createConditionalFormattingRule(IconSet.GYR_3_FLAGS);
IconMultiStateFormatting im2 = rule1.getMultiStateFormatting();
im2.getThresholds()[0].setRangeType(RangeType.PERCENT);
im2.getThresholds()[0].setValue(0d);
im2.getThresholds()[1].setRangeType(RangeType.PERCENT);
im2.getThresholds()[1].setValue(33d);
im2.getThresholds()[2].setRangeType(RangeType.PERCENT);
im2.getThresholds()[2].setValue(67d);
sheetCF.addConditionalFormatting(regions, rule2);
regions = new CellRangeAddress[] { CellRangeAddress.valueOf("D1:D4") };
ConditionalFormattingRule rule3 =
sheetCF.createConditionalFormattingRule(IconSet.GYR_3_SYMBOLS_CIRCLE);
IconMultiStateFormatting im3 = rule1.getMultiStateFormatting();
im3.setIconOnly(true);
im3.getThresholds()[0].setRangeType(RangeType.MIN);
im3.getThresholds()[1].setRangeType(RangeType.NUMBER);
im3.getThresholds()[1].setValue(3d);
im3.getThresholds()[2].setRangeType(RangeType.NUMBER);
im3.getThresholds()[2].setValue(7d);
sheetCF.addConditionalFormatting(regions, rule3);
}
}

View File

@ -289,7 +289,7 @@ public class ToHtml {
private void fontStyle(CellStyle style) {
Font font = wb.getFontAt(style.getFontIndex());
if (font.getBoldweight() >= HSSFFont.BOLDWEIGHT_NORMAL)
if (font.getBoldweight() >= HSSFFont.BOLDWEIGHT_BOLD)
out.format(" font-weight: bold;%n");
if (font.getItalic())
out.format(" font-style: italic;%n");
@ -309,8 +309,12 @@ public class ToHtml {
style = wb.getCellStyleAt((short) 0);
StringBuilder sb = new StringBuilder();
Formatter fmt = new Formatter(sb);
try {
fmt.format("style_%02x", style.getIndex());
return fmt.toString();
} finally {
fmt.close();
}
}
private <K> void styleOut(String attr, K key, Map<K, String> mapping) {

View File

@ -114,13 +114,14 @@ public class AligningCells {
// Make the selection
CTRowImpl ctRow = (CTRowImpl) row.getCTRow();
List spanList = new ArrayList();
// Add object with format start_coll:end_coll. For example 1:3 will span from
// cell 1 to cell 3, where the column index starts with 0
//
// You can add multiple spans for one row
Object span = start_column + ":" + end_column;
List<Object> spanList = new ArrayList<Object>();
spanList.add(span);
//add spns to the row

View File

@ -23,6 +23,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import org.apache.poi.openxml4j.opc.internal.ZipHelper;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellReference;
@ -165,8 +166,9 @@ public class BigGridDemo {
* @param out the stream to write the result to
*/
private static void substitute(File zipfile, File tmpfile, String entry, OutputStream out) throws IOException {
ZipFile zip = new ZipFile(zipfile);
ZipFile zip = ZipHelper.openZipFile(zipfile);
try {
ZipOutputStream zos = new ZipOutputStream(out);
@SuppressWarnings("unchecked")
@ -186,6 +188,9 @@ public class BigGridDemo {
is.close();
zos.close();
} finally {
zip.close();
}
}
private static void copyStream(InputStream in, OutputStream out) throws IOException {

View File

@ -0,0 +1,145 @@
<?xml version="1.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.
-->
<project name="POI Testbuild" default="run" basedir=".">
<description>Test-Ant file which verifies that the Apache POI distribution build sources can be compiled successfully.
Before running this, you should execute the "assemble" target in the main build.xml to have the packaged files
created correctly.
</description>
<property name="dist" value="../../build/dist"/>
<property name="build" value="../../build/distsourcebuild"/>
<target name="init" depends="">
</target>
<target name="run" depends="init,runSourceBuild,runCompileTest"/>
<target name="runSourceBuild" depends="init">
<!-- clean out old stuff in build-dir -->
<delete dir="${build}"/>
<mkdir dir="${build}"/>
<!-- select latest built source zip -->
<pathconvert property="srcpackage">
<last>
<sort>
<date xmlns="antlib:org.apache.tools.ant.types.resources.comparators"/>
<resources>
<fileset dir="${dist}">
<include name="poi-src-*.zip" />
</fileset>
</resources>
</sort>
</last>
</pathconvert>
<echo message="Found source package at ${srcpackage}"/>
<unzip src="${srcpackage}" dest="${build}" failOnEmptyArchive="true"/>
<!-- look for name of sub-dir, do this dynamically as it changes with every (beta|rc)-release -->
<pathconvert property="dirversion">
<dirset dir="${build}">
<include name="*" />
</dirset>
</pathconvert>
<!-- finally call Ant on the extracted source to check if we can build the packages -->
<echo message="Building in temporary dir ${dirversion}/"/>
<ant dir="${dirversion}" target="jar" inheritAll="false" inheritRefs="false" useNativeBasedir="true"/>
</target>
<target name="runCompileTest" depends="init" description="Verify that we can compile most examples without including excelant or scratchpad jars">
<!-- clean out old stuff in build-dir -->
<delete dir="${build}"/>
<mkdir dir="${build}"/>
<!-- select latest built jar files without scratchpad.jar -->
<pathconvert property="jarpackage">
<sort>
<resources>
<fileset dir="${dist}">
<include name="poi-3.*.jar" />
<include name="poi-ooxml-3.*.jar" />
<include name="poi-ooxml-schemas-3.*.jar" />
<exclude name="*-javadocs-*" />
<exclude name="*-sources-*" />
</fileset>
</resources>
</sort>
</pathconvert>
<echo message="Found jar packages at ${jarpackage}"/>
<path id="libs">
<fileset dir="../../lib">
<include name="junit*.jar" />
</fileset>
<fileset dir="../../ooxml-lib">
<include name="ooxml-schemas-*.jar" />
<include name="xmlbeans-*.jar" />
<exclude name="xmlbeans-2.3.*.jar" />
</fileset>
</path>
<echo message="Compiling examples without linking to scratchpad.jar to ensure that only some specific ones require this jar" />
<javac srcdir="../examples/src" destdir="${build}"
target="1.6"
source="1.6"
debug="trye"
encoding="ASCII"
fork="yes"
includeantruntime="false"
excludes="org/apache/poi/hslf/**,org/apache/poi/hsmf/**,**/EmbeddedObjects.java,**/EmeddedObjects.java,**/Word2Forrest.java"
classpath="${jarpackage}"
classpathref="libs">
</javac>
<!-- select latest built jar files with additionally scratchpad.jar -->
<pathconvert property="jarpackagescratchpad">
<sort>
<resources>
<fileset dir="${dist}">
<include name="poi-3.*.jar" />
<include name="poi-ooxml-3.*.jar" />
<include name="poi-ooxml-schemas-3.*.jar" />
<include name="poi-scratchpad-3.*.jar" />
<exclude name="*-javadocs-*" />
<exclude name="*-sources-*" />
</fileset>
</resources>
</sort>
</pathconvert>
<echo message="Compiling all examples with the additinal scratchpad.jar" />
<javac srcdir="../examples/src" destdir="${build}"
target="1.6"
source="1.6"
debug="trye"
encoding="ASCII"
fork="yes"
includeantruntime="false"
classpath="${jarpackagescratchpad}"
classpathref="libs">
</javac>
</target>
</project>

View File

@ -31,6 +31,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.poi.hwpf.OldWordFileFormatException;
import org.apache.poi.stress.*;
import org.apache.tools.ant.DirectoryScanner;
import org.junit.Test;
@ -98,9 +99,17 @@ public class TestAllFiles {
// Publisher
HANDLERS.put(".pub", new HPBFFileHandler());
// Visio
// Visio - binary
HANDLERS.put(".vsd", new HDGFFileHandler());
// Visio - ooxml (currently unsupported)
HANDLERS.put(".vsdm", new NullFileHandler());
HANDLERS.put(".vsdx", new NullFileHandler());
HANDLERS.put(".vssm", new NullFileHandler());
HANDLERS.put(".vssx", new NullFileHandler());
HANDLERS.put(".vstm", new NullFileHandler());
HANDLERS.put(".vstx", new NullFileHandler());
// POIFS
HANDLERS.put(".ole2", new POIFSFileHandler());
@ -154,10 +163,25 @@ public class TestAllFiles {
HANDLERS.put("spreadsheet/test_properties1", new NullFileHandler());
}
// Old Word Documents where we can at least extract some text
private static final Set<String> OLD_FILES = new HashSet<String>();
static {
OLD_FILES.add("document/Bug49933.doc");
OLD_FILES.add("document/Bug51944.doc");
OLD_FILES.add("document/Word6.doc");
OLD_FILES.add("document/Word6_sections.doc");
OLD_FILES.add("document/Word6_sections2.doc");
OLD_FILES.add("document/Word95.doc");
OLD_FILES.add("document/word95err.doc");
OLD_FILES.add("hpsf/TestMickey.doc");
OLD_FILES.add("document/52117.doc");
}
private static final Set<String> EXPECTED_FAILURES = new HashSet<String>();
static {
// password protected files
EXPECTED_FAILURES.add("spreadsheet/password.xls");
EXPECTED_FAILURES.add("spreadsheet/protected_passtika.xlsx");
EXPECTED_FAILURES.add("spreadsheet/51832.xls");
EXPECTED_FAILURES.add("document/PasswordProtected.doc");
EXPECTED_FAILURES.add("slideshow/Password_Protected-hello.ppt");
@ -190,19 +214,11 @@ public class TestAllFiles {
// This is actually a spreadsheet!
EXPECTED_FAILURES.add("hpsf/TestRobert_Flaherty.doc");
// some files that are broken, Excel 5.0/95, Word 95, ...
// some files that are broken, eg Word 95, ...
EXPECTED_FAILURES.add("spreadsheet/43493.xls");
EXPECTED_FAILURES.add("spreadsheet/46904.xls");
EXPECTED_FAILURES.add("document/56880.doc");
EXPECTED_FAILURES.add("document/Bug49933.doc");
EXPECTED_FAILURES.add("document/Bug50955.doc");
EXPECTED_FAILURES.add("document/Bug51944.doc");
EXPECTED_FAILURES.add("document/Word6.doc");
EXPECTED_FAILURES.add("document/Word6_sections.doc");
EXPECTED_FAILURES.add("document/Word6_sections2.doc");
EXPECTED_FAILURES.add("document/Word95.doc");
EXPECTED_FAILURES.add("document/word95err.doc");
EXPECTED_FAILURES.add("hpsf/TestMickey.doc");
EXPECTED_FAILURES.add("slideshow/PPT95.ppt");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_CoreProperties_DCTermsNamespaceLimitedUseFAIL.docx");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_CoreProperties_DoNotUseCompatibilityMarkupFAIL.docx");
@ -214,12 +230,21 @@ public class TestAllFiles {
EXPECTED_FAILURES.add("spreadsheet/54764-2.xlsx"); // see TestXSSFBugs.bug54764()
EXPECTED_FAILURES.add("spreadsheet/54764.xlsx"); // see TestXSSFBugs.bug54764()
EXPECTED_FAILURES.add("spreadsheet/Simple.xlsb");
EXPECTED_FAILURES.add("poifs/unknown_properties.msg"); // POIFS properties corrupted
EXPECTED_FAILURES.add("poifs/only-zero-byte-streams.ole2"); // No actual contents
// old Excel files, which we only support simple text extraction of
EXPECTED_FAILURES.add("spreadsheet/testEXCEL_2.xls");
EXPECTED_FAILURES.add("spreadsheet/testEXCEL_3.xls");
EXPECTED_FAILURES.add("spreadsheet/testEXCEL_4.xls");
EXPECTED_FAILURES.add("spreadsheet/testEXCEL_5.xls");
EXPECTED_FAILURES.add("spreadsheet/testEXCEL_95.xls");
// OOXML Strict is not yet supported, see bug #57699
EXPECTED_FAILURES.add("spreadsheet/SampleSS.strict.xlsx");
EXPECTED_FAILURES.add("spreadsheet/SimpleStrict.xlsx");
EXPECTED_FAILURES.add("spreadsheet/sample.strict.xlsx");
// non-TNEF files
EXPECTED_FAILURES.add("ddf/Container.dat");
EXPECTED_FAILURES.add("ddf/47143.dat");
@ -253,20 +278,41 @@ public class TestAllFiles {
@Test
public void testAllFiles() throws Exception {
assertNotNull("Unknown file extension for file: " + file + ": " + getExtension(file), handler);
InputStream stream = new BufferedInputStream(new FileInputStream(new File(ROOT_DIR, file)),100);
File inputFile = new File(ROOT_DIR, file);
try {
InputStream stream = new BufferedInputStream(new FileInputStream(inputFile), 64*1024);
try {
handler.handleFile(stream);
assertFalse("Expected to fail for file " + file + " and handler " + handler + ", but did not fail!",
EXPECTED_FAILURES.contains(file));
} catch (Exception e) {
// check if we expect failure for this file
if(!EXPECTED_FAILURES.contains(file)) {
throw new Exception("While handling " + file, e);
}
OLD_FILES.contains(file));
} finally {
stream.close();
}
handler.handleExtracting(inputFile);
assertFalse("Expected to fail for file " + file + " and handler " + handler + ", but did not fail!",
EXPECTED_FAILURES.contains(file));
} catch (OldWordFileFormatException e) {
// for old word files we should still support extracting text
if(OLD_FILES.contains(file)) {
handler.handleExtracting(inputFile);
} else {
// check if we expect failure for this file
if(!EXPECTED_FAILURES.contains(file) && !AbstractFileHandler.EXPECTED_EXTRACTOR_FAILURES.contains(file)) {
System.out.println("Failed: " + file);
throw new Exception("While handling " + file, e);
}
}
} catch (Exception e) {
// check if we expect failure for this file
if(!EXPECTED_FAILURES.contains(file) && !AbstractFileHandler.EXPECTED_EXTRACTOR_FAILURES.contains(file)) {
System.out.println("Failed: " + file);
throw new Exception("While handling " + file, e);
}
}
}
private static String getExtension(String file) {
@ -282,5 +328,9 @@ public class TestAllFiles {
@Override
public void handleFile(InputStream stream) throws Exception {
}
@Override
public void handleExtracting(File file) throws Exception {
}
}
}

View File

@ -0,0 +1,143 @@
/* ====================================================================
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.stress;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.ZipException;
import org.apache.poi.POIOLE2TextExtractor;
import org.apache.poi.POITextExtractor;
import org.apache.poi.dev.OOXMLPrettyPrint;
import org.apache.poi.extractor.ExtractorFactory;
import org.apache.poi.hpsf.extractor.HPSFPropertiesExtractor;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.xmlbeans.XmlException;
public abstract class AbstractFileHandler implements FileHandler {
public static final Set<String> EXPECTED_EXTRACTOR_FAILURES = new HashSet<String>();
static {
// password protected files
EXPECTED_EXTRACTOR_FAILURES.add("document/bug53475-password-is-pass.docx");
EXPECTED_EXTRACTOR_FAILURES.add("poifs/extenxls_pwd123.xlsx");
EXPECTED_EXTRACTOR_FAILURES.add("poifs/protect.xlsx");
EXPECTED_EXTRACTOR_FAILURES.add("poifs/protected_agile.docx");
EXPECTED_EXTRACTOR_FAILURES.add("poifs/protected_sha512.xlsx");
// unsupported file-types, no supported OLE2 parts
EXPECTED_EXTRACTOR_FAILURES.add("hmef/quick-winmail.dat");
EXPECTED_EXTRACTOR_FAILURES.add("hmef/winmail-sample1.dat");
EXPECTED_EXTRACTOR_FAILURES.add("hmef/bug52400-winmail-simple.dat");
EXPECTED_EXTRACTOR_FAILURES.add("hmef/bug52400-winmail-with-attachments.dat");
EXPECTED_EXTRACTOR_FAILURES.add("hpsf/Test0313rur.adm");
EXPECTED_EXTRACTOR_FAILURES.add("hsmf/attachment_msg_pdf.msg");
EXPECTED_EXTRACTOR_FAILURES.add("poifs/Notes.ole2");
EXPECTED_EXTRACTOR_FAILURES.add("slideshow/testPPT.thmx");
}
public void handleExtracting(File file) throws Exception {
boolean before = ExtractorFactory.getThreadPrefersEventExtractors();
try {
ExtractorFactory.setThreadPrefersEventExtractors(true);
handleExtractingInternal(file);
ExtractorFactory.setThreadPrefersEventExtractors(false);
handleExtractingInternal(file);
} finally {
ExtractorFactory.setThreadPrefersEventExtractors(before);
}
/* Did fail for some documents with special XML contents...
try {
OOXMLPrettyPrint.main(new String[] { file.getAbsolutePath(),
"/tmp/pretty-" + file.getName() });
} catch (ZipException e) {
// ignore, not a Zip/OOXML file
}*/
}
private void handleExtractingInternal(File file) throws Exception {
long length = file.length();
long modified = file.lastModified();
POITextExtractor extractor = ExtractorFactory.createExtractor(file);
try {
assertNotNull(extractor);
assertNotNull(extractor.getText());
// also try metadata
POITextExtractor metadataExtractor = extractor.getMetadataTextExtractor();
assertNotNull(metadataExtractor.getText());
assertFalse("Expected Extraction to fail for file " + file + " and handler " + this + ", but did not fail!",
EXPECTED_EXTRACTOR_FAILURES.contains(file));
assertEquals("File should not be modified by extractor", length, file.length());
assertEquals("File should not be modified by extractor", modified, file.lastModified());
handleExtractingAsStream(file);
if(extractor instanceof POIOLE2TextExtractor) {
HPSFPropertiesExtractor hpsfExtractor = new HPSFPropertiesExtractor((POIOLE2TextExtractor)extractor);
try {
assertNotNull(hpsfExtractor.getDocumentSummaryInformationText());
assertNotNull(hpsfExtractor.getSummaryInformationText());
String text = hpsfExtractor.getText();
//System.out.println(text);
assertNotNull(text);
} finally {
hpsfExtractor.close();
}
}
} catch (IllegalArgumentException e) {
if(!EXPECTED_EXTRACTOR_FAILURES.contains(file)) {
throw new Exception("While handling " + file, e);
}
} finally {
extractor.close();
}
}
private void handleExtractingAsStream(File file) throws FileNotFoundException,
IOException, InvalidFormatException, OpenXML4JException,
XmlException {
InputStream stream = new FileInputStream(file);
try {
POITextExtractor streamExtractor = ExtractorFactory.createExtractor(stream);
try {
assertNotNull(streamExtractor);
assertNotNull(streamExtractor.getText());
} finally {
streamExtractor.close();
}
} finally {
stream.close();
}
}
}

View File

@ -16,6 +16,7 @@
==================================================================== */
package org.apache.poi.stress;
import java.io.File;
import java.io.InputStream;
/**
@ -34,4 +35,10 @@ public interface FileHandler {
* @throws Exception
*/
void handleFile(InputStream stream) throws Exception;
/**
* Ensures that extracting text from the given file
* is returning some text.
*/
void handleExtracting(File file) throws Exception;
}

View File

@ -19,10 +19,12 @@ package org.apache.poi.stress;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.poi.hdgf.HDGFDiagram;
import org.apache.poi.hdgf.extractor.VisioTextExtractor;
import org.apache.poi.hdgf.streams.Stream;
import org.apache.poi.hdgf.streams.TrailerStream;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
@ -48,11 +50,27 @@ public class HDGFFileHandler extends POIFSFileHandler {
// a test-case to test this locally without executing the full TestAllFiles
@Test
public void test() throws Exception {
InputStream stream = new FileInputStream("test-data/diagram/44501.vsd");
File file = new File("test-data/diagram/44501.vsd");
InputStream stream = new FileInputStream(file);
try {
handleFile(stream);
} finally {
stream.close();
}
handleExtracting(file);
stream = new FileInputStream(file);
try {
VisioTextExtractor extractor = new VisioTextExtractor(stream);
try {
assertNotNull(extractor.getText());
} finally {
extractor.close();
}
} finally {
stream.close();
}
}
}

View File

@ -26,7 +26,7 @@ import org.apache.poi.hmef.attribute.MAPIAttribute;
import org.apache.poi.hmef.attribute.MAPIStringAttribute;
import org.junit.Test;
public class HMEFFileHandler implements FileHandler {
public class HMEFFileHandler extends AbstractFileHandler {
@Override
public void handleFile(InputStream stream) throws Exception {

View File

@ -18,10 +18,12 @@ package org.apache.poi.stress;
import static org.junit.Assert.assertNotNull;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.poi.hpbf.HPBFDocument;
import org.apache.poi.hpbf.extractor.PublisherTextExtractor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.junit.Test;
@ -39,11 +41,28 @@ public class HPBFFileHandler extends POIFSFileHandler {
// a test-case to test this locally without executing the full TestAllFiles
@Test
public void test() throws Exception {
InputStream stream = new FileInputStream("test-data/publisher/SampleBrochure.pub");
File file = new File("test-data/publisher/SampleBrochure.pub");
InputStream stream = new FileInputStream(file);
try {
handleFile(stream);
} finally {
stream.close();
}
handleExtracting(file);
stream = new FileInputStream(file);
try {
PublisherTextExtractor extractor = new PublisherTextExtractor(stream);
try {
assertNotNull(extractor.getText());
} finally {
extractor.close();
}
} finally {
stream.close();
}
}
}

View File

@ -18,6 +18,7 @@ package org.apache.poi.stress;
import static org.junit.Assert.assertNotNull;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
@ -25,7 +26,7 @@ import org.apache.poi.hpsf.HPSFPropertiesOnlyDocument;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.junit.Test;
public class HPSFFileHandler implements FileHandler {
public class HPSFFileHandler extends AbstractFileHandler {
@Override
public void handleFile(InputStream stream) throws Exception {
HPSFPropertiesOnlyDocument hpsf = new HPSFPropertiesOnlyDocument(new POIFSFileSystem(stream));
@ -43,4 +44,10 @@ public class HPSFFileHandler implements FileHandler {
stream.close();
}
}
// a test-case to test this locally without executing the full TestAllFiles
@Test
public void testExtractor() throws Exception {
handleExtracting(new File("test-data/hpsf/TestBug44375.xls"));
}
}

View File

@ -22,6 +22,8 @@ import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.poi.hsmf.MAPIMessage;
import org.apache.poi.hsmf.datatypes.AttachmentChunks;
import org.apache.poi.hsmf.datatypes.DirectoryChunk;
import org.junit.Test;
public class HSMFFileHandler extends POIFSFileHandler {
@ -32,6 +34,19 @@ public class HSMFFileHandler extends POIFSFileHandler {
assertNotNull(mapi.getDisplayBCC());
assertNotNull(mapi.getMessageDate());
AttachmentChunks[] attachments = mapi.getAttachmentFiles();
for(AttachmentChunks attachment : attachments) {
DirectoryChunk chunkDirectory = attachment.attachmentDirectory;
if(chunkDirectory != null) {
MAPIMessage attachmentMSG = chunkDirectory.getAsEmbededMessage();
assertNotNull(attachmentMSG);
String body = attachmentMSG.getTextBody();
assertNotNull(body);
}
}
/* => Writing isn't yet supported...
// write out the file
File file = TempFile.createTempFile("StressTest", ".msg");

View File

@ -16,6 +16,7 @@
==================================================================== */
package org.apache.poi.stress;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
@ -49,4 +50,10 @@ public class HSSFFileHandler extends SpreadsheetHandler {
stream.close();
}
}
// a test-case to test this locally without executing the full TestAllFiles
@Test
public void testExtractor() throws Exception {
handleExtracting(new File("test-data/spreadsheet/BOOK_in_capitals.xls"));
}
}

View File

@ -18,12 +18,21 @@ package org.apache.poi.stress;
import static org.junit.Assert.assertNotNull;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.apache.poi.hdf.extractor.WordDocument;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.junit.Test;
@SuppressWarnings("deprecation")
public class HWPFFileHandler extends POIFSFileHandler {
@Override
public void handleFile(InputStream stream) throws Exception {
@ -33,16 +42,57 @@ public class HWPFFileHandler extends POIFSFileHandler {
assertNotNull(doc.getEndnotes());
handlePOIDocument(doc);
// fails for many documents, but is deprecated anyway...
// handleWordDocument(doc);
}
protected void handleWordDocument(HWPFDocument doc) throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
doc.write(outStream);
WordDocument wordDoc = new WordDocument(new ByteArrayInputStream(outStream.toByteArray()));
StringWriter docTextWriter = new StringWriter();
PrintWriter out = new PrintWriter(docTextWriter);
try {
wordDoc.writeAllText(out);
} finally {
out.close();
}
docTextWriter.close();
}
// a test-case to test this locally without executing the full TestAllFiles
@Test
public void test() throws Exception {
InputStream stream = new FileInputStream("test-data/document/HeaderFooterUnicode.doc");
File file = new File("test-data/document/52117.doc");
InputStream stream = new FileInputStream(file);
try {
handleFile(stream);
} finally {
stream.close();
}
handleExtracting(file);
stream = new FileInputStream(file);
try {
WordExtractor extractor = new WordExtractor(stream);
try {
assertNotNull(extractor.getText());
} finally {
extractor.close();
}
} finally {
stream.close();
}
}
@Test
public void testExtractingOld() throws Exception {
File file = new File("test-data/document/52117.doc");
handleExtracting(file);
}
}

View File

@ -25,7 +25,7 @@ import java.io.InputStream;
import org.apache.poi.POIDocument;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public class POIFSFileHandler implements FileHandler {
public class POIFSFileHandler extends AbstractFileHandler {
@Override
public void handleFile(InputStream stream) throws Exception {

View File

@ -20,9 +20,17 @@ import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.poifs.crypt.Decryptor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.junit.Ignore;
import org.junit.Test;
public final class POIXMLDocumentHandler {
protected void handlePOIXMLDocument(POIXMLDocument doc) throws Exception {
@ -36,11 +44,33 @@ public final class POIXMLDocumentHandler {
protected static boolean isEncrypted(InputStream stream) throws IOException {
if (POIFSFileSystem.hasPOIFSHeader(stream)) {
POIFSFileSystem poifs = new POIFSFileSystem(stream);
if (poifs.getRoot().hasEntry("EncryptedPackage")) {
if (poifs.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
return true;
}
throw new IOException("wrong file format or file extension for OO XML file");
}
return false;
}
// a test-case to test this locally without executing the full TestAllFiles
@Ignore("POIXMLDocument cannot handle this Visio file currently...")
@Test
public void test() throws Exception {
OPCPackage pkg = OPCPackage.open("test-data/diagram/test.vsdx", PackageAccess.READ);
try {
handlePOIXMLDocument(new TestPOIXMLDocument(pkg));
} finally {
pkg.close();
}
}
private final static class TestPOIXMLDocument extends POIXMLDocument {
public TestPOIXMLDocument(OPCPackage pkg) {
super(pkg);
}
public List<PackagePart> getAllEmbedds() throws OpenXML4JException {
return null;
}
}
}

View File

@ -30,7 +30,7 @@ import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
public abstract class SpreadsheetHandler implements FileHandler {
public abstract class SpreadsheetHandler extends AbstractFileHandler {
public void handleWorkbook(Workbook wb, String extension) throws IOException {
// try to access some of the content
readContent(wb);

View File

@ -18,35 +18,97 @@ package org.apache.poi.stress;
import static org.junit.Assert.assertNotNull;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.xslf.XSLFSlideShow;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFNotes;
import org.apache.poi.xslf.usermodel.XSLFShape;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
import org.apache.poi.xslf.usermodel.XSLFTextShape;
import org.junit.Test;
public class XSLFFileHandler implements FileHandler {
public class XSLFFileHandler extends AbstractFileHandler {
@Override
public void handleFile(InputStream stream) throws Exception {
// ignore password protected files
if (POIXMLDocumentHandler.isEncrypted(stream)) return;
XSLFSlideShow slide = new XSLFSlideShow(OPCPackage.open(stream));
assertNotNull(slide.getPresentation());
assertNotNull(slide.getSlideMasterReferences());
assertNotNull(slide.getSlideReferences());
new POIXMLDocumentHandler().handlePOIXMLDocument(slide);
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
slide.write(out);
} finally {
out.close();
}
createBitmaps(out);
}
private void createBitmaps(ByteArrayOutputStream out) throws IOException {
XMLSlideShow ppt = new XMLSlideShow(new ByteArrayInputStream(out.toByteArray()));
Dimension pgsize = ppt.getPageSize();
for (XSLFSlide xmlSlide : ppt.getSlides()) {
// System.out.println("slide-" + (i + 1));
// System.out.println("" + xmlSlide[i].getTitle());
BufferedImage img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
// draw stuff
xmlSlide.draw(graphics);
// Also try to read notes
XSLFNotes notes = xmlSlide.getNotes();
if(notes != null) {
for (XSLFShape note : notes) {
DrawFactory df = DrawFactory.getInstance(graphics);
Drawable d = df.getDrawable(note);
d.draw(graphics);
if (note instanceof XSLFTextShape) {
XSLFTextShape txShape = (XSLFTextShape) note;
for (XSLFTextParagraph xslfParagraph : txShape.getTextParagraphs()) {
xslfParagraph.getText();
}
}
}
}
}
ppt.close();
}
// a test-case to test this locally without executing the full TestAllFiles
@Test
public void test() throws Exception {
InputStream stream = new FileInputStream("test-data/slideshow/testPPT.pptx");
InputStream stream = new FileInputStream("test-data/slideshow/SampleShow.pptx");
try {
handleFile(stream);
} finally {
stream.close();
}
}
// a test-case to test this locally without executing the full TestAllFiles
@Test
public void testExtractor() throws Exception {
handleExtracting(new File("test-data/slideshow/testPPT.thmx"));
}
}

View File

@ -17,6 +17,7 @@
package org.apache.poi.stress;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
@ -71,4 +72,10 @@ public class XSSFFileHandler extends SpreadsheetHandler {
stream.close();
}
}
// a test-case to test this locally without executing the full TestAllFiles
@Test
public void testExtractor() throws Exception {
handleExtracting(new File("test-data/spreadsheet/56278.xlsx"));
}
}

View File

@ -16,13 +16,15 @@
==================================================================== */
package org.apache.poi.stress;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.PushbackInputStream;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.junit.Test;
public class XWPFFileHandler implements FileHandler {
public class XWPFFileHandler extends AbstractFileHandler {
@Override
public void handleFile(InputStream stream) throws Exception {
// ignore password protected files
@ -36,12 +38,16 @@ public class XWPFFileHandler implements FileHandler {
// a test-case to test this locally without executing the full TestAllFiles
@Test
public void test() throws Exception {
InputStream stream = new FileInputStream("test-data/document/footnotes.docx");
File file = new File("test-data/document/51921-Word-Crash067.docx");
InputStream stream = new PushbackInputStream(new FileInputStream(file), 100000);
try {
handleFile(stream);
} finally {
stream.close();
}
handleExtracting(file);
}
}

View File

@ -0,0 +1,28 @@
/* ====================================================================
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;
/**
* Exception thrown if an Empty (zero byte) file is supplied
*/
public class EmptyFileException extends IllegalArgumentException {
private static final long serialVersionUID = 1536449292174360166L;
public EmptyFileException() {
super("The supplied file was empty (zero bytes long)");
}
}

View File

@ -16,9 +16,10 @@
==================================================================== */
package org.apache.poi;
@SuppressWarnings("serial")
public class EncryptedDocumentException extends IllegalStateException
{
private static final long serialVersionUID = 7276950444540469193L;
public EncryptedDocumentException(String s) {
super(s);
}

View File

@ -30,14 +30,11 @@ import org.apache.poi.hpsf.PropertySet;
import org.apache.poi.hpsf.PropertySetFactory;
import org.apache.poi.hpsf.SummaryInformation;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.poifs.filesystem.EntryUtils;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -45,8 +42,6 @@ import org.apache.poi.util.POILogger;
* This holds the common functionality for all POI
* Document classes.
* Currently, this relates to Document Information Properties
*
* @author Nick Burch
*/
public abstract class POIDocument {
/** Holds metadata on our document */
@ -72,20 +67,23 @@ public abstract class POIDocument {
}
/**
* @deprecated use {@link POIDocument#POIDocument(DirectoryNode)} instead
* Constructs from an old-style OPOIFS
*/
@Deprecated
protected POIDocument(DirectoryNode dir, POIFSFileSystem fs) {
this.directory = dir;
}
protected POIDocument(POIFSFileSystem fs) {
protected POIDocument(OPOIFSFileSystem fs) {
this(fs.getRoot());
}
/**
* Constructs from an old-style OPOIFS
*/
protected POIDocument(NPOIFSFileSystem fs) {
this(fs.getRoot());
}
/**
* Constructs from the default POIFS
*/
protected POIDocument(POIFSFileSystem fs) {
this(fs.getRoot());
}
/**
* Fetch the Document Summary Information of the document
@ -179,12 +177,13 @@ public abstract class POIDocument {
protected PropertySet getPropertySet(String setName, EncryptionInfo encryptionInfo) {
DirectoryNode dirNode = directory;
NPOIFSFileSystem encPoifs = null;
if (encryptionInfo != null) {
try {
InputStream is = encryptionInfo.getDecryptor().getDataStream(directory);
POIFSFileSystem poifs = new POIFSFileSystem(is);
encPoifs = new NPOIFSFileSystem(is);
is.close();
dirNode = poifs.getRoot();
dirNode = encPoifs.getRoot();
} catch (Exception e) {
logger.log(POILogger.ERROR, "Error getting encrypted property set with name " + setName, e);
return null;
@ -208,6 +207,11 @@ public abstract class POIDocument {
try {
// Create the Property Set
PropertySet set = PropertySetFactory.create(dis);
// Tidy up if needed
if (encPoifs != null) {
encPoifs.close();
}
// Return the properties
return set;
} catch(IOException ie) {
// Must be corrupt or something like that
@ -220,24 +224,37 @@ public abstract class POIDocument {
}
/**
* Writes out the standard Documment Information Properties (HPSF)
* Writes out the updated standard Document Information Properties (HPSF)
* into the currently open NPOIFSFileSystem
* TODO Implement in-place update
*
* @throws IOException if an error when writing to the open
* {@link NPOIFSFileSystem} occurs
* TODO throws exception if open from stream not file
*/
protected void writeProperties() throws IOException {
throw new IllegalStateException("In-place write is not yet supported");
}
/**
* Writes out the standard Document Information Properties (HPSF)
* @param outFS the POIFSFileSystem to write the properties into
*
* @throws IOException if an error when writing to the
* {@link POIFSFileSystem} occurs
* {@link NPOIFSFileSystem} occurs
*/
protected void writeProperties(POIFSFileSystem outFS) throws IOException {
protected void writeProperties(NPOIFSFileSystem outFS) throws IOException {
writeProperties(outFS, null);
}
/**
* Writes out the standard Documment Information Properties (HPSF)
* @param outFS the POIFSFileSystem to write the properties into
* Writes out the standard Document Information Properties (HPSF)
* @param outFS the NPOIFSFileSystem to write the properties into
* @param writtenEntries a list of POIFS entries to add the property names too
*
* @throws IOException if an error when writing to the
* {@link POIFSFileSystem} occurs
* {@link NPOIFSFileSystem} occurs
*/
protected void writeProperties(POIFSFileSystem outFS, List<String> writtenEntries) throws IOException {
protected void writeProperties(NPOIFSFileSystem outFS, List<String> writtenEntries) throws IOException {
SummaryInformation si = getSummaryInformation();
if (si != null) {
writePropertySet(SummaryInformation.DEFAULT_STREAM_NAME, si, outFS);
@ -258,12 +275,12 @@ public abstract class POIDocument {
* Writes out a given ProperySet
* @param name the (POIFS Level) name of the property to write
* @param set the PropertySet to write out
* @param outFS the POIFSFileSystem to write the property into
* @param outFS the NPOIFSFileSystem to write the property into
*
* @throws IOException if an error when writing to the
* {@link POIFSFileSystem} occurs
* {@link NPOIFSFileSystem} occurs
*/
protected void writePropertySet(String name, PropertySet set, POIFSFileSystem outFS) throws IOException {
protected void writePropertySet(String name, PropertySet set, NPOIFSFileSystem outFS) throws IOException {
try {
MutablePropertySet mSet = new MutablePropertySet(set);
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
@ -288,55 +305,4 @@ public abstract class POIDocument {
* @throws IOException thrown on errors writing to the stream
*/
public abstract void write(OutputStream out) throws IOException;
/**
* Copies nodes from one POIFS to the other minus the excepts
* @param source is the source POIFS to copy from
* @param target is the target POIFS to copy to
* @param excepts is a list of Strings specifying what nodes NOT to copy
*
* @throws IOException thrown on errors writing to the target file system.
*
* @deprecated Use {@link EntryUtils#copyNodes(DirectoryEntry, DirectoryEntry, List)} instead
*/
@Deprecated
protected void copyNodes( POIFSFileSystem source, POIFSFileSystem target,
List<String> excepts ) throws IOException {
EntryUtils.copyNodes( source, target, excepts );
}
/**
* Copies nodes from one POIFS to the other minus the excepts
* @param sourceRoot is the source POIFS to copy from
* @param targetRoot is the target POIFS to copy to
* @param excepts is a list of Strings specifying what nodes NOT to copy
*
* @throws IOException thrown on errors writing to the target directory node.
*
* @deprecated Use {@link EntryUtils#copyNodes(DirectoryEntry, DirectoryEntry, List)} instead
*/
@Deprecated
protected void copyNodes( DirectoryNode sourceRoot,
DirectoryNode targetRoot, List<String> excepts ) throws IOException
{
EntryUtils.copyNodes( sourceRoot, targetRoot, excepts );
}
/**
* Copies an Entry into a target POIFS directory, recursively
*
* @param entry the entry to copy from
* @param target the entry to write to
*
* @throws IOException thrown on errors writing to the target directory entry.
*
* @deprecated Use {@link EntryUtils#copyNodeRecursively(Entry, DirectoryEntry)} instead
*/
@Internal
@Deprecated
protected void copyNodeRecursively( Entry entry, DirectoryEntry target )
throws IOException
{
EntryUtils.copyNodeRecursively( entry, target );
}
}

View File

@ -20,7 +20,6 @@ import org.apache.poi.hpsf.DocumentSummaryInformation;
import org.apache.poi.hpsf.SummaryInformation;
import org.apache.poi.hpsf.extractor.HPSFPropertiesExtractor;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/**
* Common Parent for OLE2 based Text Extractors
@ -34,13 +33,25 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
* @see org.apache.poi.hwpf.extractor.WordExtractor
*/
public abstract class POIOLE2TextExtractor extends POITextExtractor {
/** The POIDocument that's open */
protected POIDocument document;
/**
* Creates a new text extractor for the given document
*
* @param document The POIDocument to use in this extractor.
*/
public POIOLE2TextExtractor(POIDocument document) {
super(document);
this.document = document;
}
/**
* Creates a new text extractor, using the same
* document as another text extractor. Normally
* only used by properties extractors.
*/
protected POIOLE2TextExtractor(POIOLE2TextExtractor otherExtractor) {
this.document = otherExtractor.document;
}
/**
@ -81,17 +92,4 @@ public abstract class POIOLE2TextExtractor extends POITextExtractor {
{
return document.directory;
}
/**
* Return the underlying POIFS FileSystem of this document.
*
* @return the POIFSFileSystem that is associated with the POIDocument of this extractor.
*
* @deprecated Use {@link #getRoot()} instead
*/
@Deprecated
public POIFSFileSystem getFileSystem()
{
return document.directory.getFileSystem();
}
}

View File

@ -31,24 +31,6 @@ import java.io.IOException;
* @see org.apache.poi.hwpf.extractor.WordExtractor
*/
public abstract class POITextExtractor implements Closeable {
/** The POIDocument that's open */
protected POIDocument document;
/**
* Creates a new text extractor for the given document
*/
public POITextExtractor(POIDocument document) {
this.document = document;
}
/**
* Creates a new text extractor, using the same
* document as another text extractor. Normally
* only used by properties extractors.
*/
protected POITextExtractor(POITextExtractor otherExtractor) {
this.document = otherExtractor.document;
}
/**
* Retrieves all the text from the document.
* How cells, paragraphs etc are separated in the text

View File

@ -82,6 +82,13 @@ public final class EscherPropertyFactory {
pos += ((EscherArrayProperty)p).setArrayData(data, pos);
} else {
byte[] complexData = ((EscherComplexProperty)p).getComplexData();
int leftover = data.length-pos;
if(leftover < complexData.length){
throw new IllegalStateException("Could not read complex escher property, lenght was " + complexData.length + ", but had only " +
leftover + " bytes left");
}
System.arraycopy(data, pos, complexData, 0, complexData.length);
pos += complexData.length;
}

View File

@ -24,6 +24,7 @@ import java.util.List;
import org.apache.poi.POIDocument;
import org.apache.poi.poifs.filesystem.EntryUtils;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/**
@ -36,6 +37,9 @@ public class HPSFPropertiesOnlyDocument extends POIDocument {
public HPSFPropertiesOnlyDocument(NPOIFSFileSystem fs) {
super(fs.getRoot());
}
public HPSFPropertiesOnlyDocument(OPOIFSFileSystem fs) {
super(fs);
}
public HPSFPropertiesOnlyDocument(POIFSFileSystem fs) {
super(fs);
}
@ -44,7 +48,7 @@ public class HPSFPropertiesOnlyDocument extends POIDocument {
* Write out, with any properties changes, but nothing else
*/
public void write(OutputStream out) throws IOException {
POIFSFileSystem fs = new POIFSFileSystem();
NPOIFSFileSystem fs = new NPOIFSFileSystem();
// For tracking what we've written out, so far
List<String> excepts = new ArrayList<String>(1);

View File

@ -285,7 +285,7 @@ public class Section
/*
* Extract the dictionary (if available).
*/
dictionary = (Map) getProperty(0);
dictionary = (Map<Long,String>) getProperty(0);
}

View File

@ -23,6 +23,7 @@ import java.io.IOException;
import java.util.Iterator;
import org.apache.poi.POIDocument;
import org.apache.poi.POIOLE2TextExtractor;
import org.apache.poi.POITextExtractor;
import org.apache.poi.hpsf.CustomProperties;
import org.apache.poi.hpsf.DocumentSummaryInformation;
@ -39,10 +40,10 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
* build in and custom, returning them in
* textual form.
*/
public class HPSFPropertiesExtractor extends POITextExtractor {
public class HPSFPropertiesExtractor extends POIOLE2TextExtractor {
private Closeable toClose;
public HPSFPropertiesExtractor(POITextExtractor mainExtractor) {
public HPSFPropertiesExtractor(POIOLE2TextExtractor mainExtractor) {
super(mainExtractor);
}
public HPSFPropertiesExtractor(POIDocument doc) {
@ -57,6 +58,10 @@ public class HPSFPropertiesExtractor extends POITextExtractor {
}
public String getDocumentSummaryInformationText() {
if(document == null) { // event based extractor does not have a document
return "";
}
DocumentSummaryInformation dsi = document.getDocumentSummaryInformation();
StringBuffer text = new StringBuffer();
@ -78,6 +83,10 @@ public class HPSFPropertiesExtractor extends POITextExtractor {
return text.toString();
}
public String getSummaryInformationText() {
if(document == null) { // event based extractor does not have a document
return "";
}
SummaryInformation si = document.getSummaryInformation();
// Just normal properties

View File

@ -34,7 +34,7 @@ import org.apache.poi.hssf.record.DrawingGroupRecord;
import org.apache.poi.hssf.record.EscherAggregate;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
/**
* Utility for representing drawings contained in a binary Excel file as a XML tree
@ -138,7 +138,7 @@ public class BiffDrawingToXml {
}
public static void writeToFile(OutputStream fos, InputStream xlsWorkbook, boolean excludeWorkbookRecords, String[] params) throws IOException {
POIFSFileSystem fs = new POIFSFileSystem(xlsWorkbook);
NPOIFSFileSystem fs = new NPOIFSFileSystem(xlsWorkbook);
HSSFWorkbook workbook = new HSSFWorkbook(fs);
InternalWorkbook internalWorkbook = getInternalWorkbook(workbook);
DrawingGroupRecord r = (DrawingGroupRecord) internalWorkbook.findFirstRecordBySid(DrawingGroupRecord.sid);

View File

@ -17,13 +17,63 @@
package org.apache.poi.hssf.dev;
import java.io.*;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.RecordInputStream.LeftoverDataException;
import org.apache.poi.hssf.record.chart.*;
import org.apache.poi.hssf.record.chart.AreaFormatRecord;
import org.apache.poi.hssf.record.chart.AreaRecord;
import org.apache.poi.hssf.record.chart.AxisLineFormatRecord;
import org.apache.poi.hssf.record.chart.AxisOptionsRecord;
import org.apache.poi.hssf.record.chart.AxisParentRecord;
import org.apache.poi.hssf.record.chart.AxisRecord;
import org.apache.poi.hssf.record.chart.AxisUsedRecord;
import org.apache.poi.hssf.record.chart.BarRecord;
import org.apache.poi.hssf.record.chart.BeginRecord;
import org.apache.poi.hssf.record.chart.CatLabRecord;
import org.apache.poi.hssf.record.chart.CategorySeriesAxisRecord;
import org.apache.poi.hssf.record.chart.ChartEndBlockRecord;
import org.apache.poi.hssf.record.chart.ChartEndObjectRecord;
import org.apache.poi.hssf.record.chart.ChartFRTInfoRecord;
import org.apache.poi.hssf.record.chart.ChartFormatRecord;
import org.apache.poi.hssf.record.chart.ChartRecord;
import org.apache.poi.hssf.record.chart.ChartStartBlockRecord;
import org.apache.poi.hssf.record.chart.ChartStartObjectRecord;
import org.apache.poi.hssf.record.chart.DatRecord;
import org.apache.poi.hssf.record.chart.DataFormatRecord;
import org.apache.poi.hssf.record.chart.DefaultDataLabelTextPropertiesRecord;
import org.apache.poi.hssf.record.chart.EndRecord;
import org.apache.poi.hssf.record.chart.FontBasisRecord;
import org.apache.poi.hssf.record.chart.FontIndexRecord;
import org.apache.poi.hssf.record.chart.FrameRecord;
import org.apache.poi.hssf.record.chart.LegendRecord;
import org.apache.poi.hssf.record.chart.LineFormatRecord;
import org.apache.poi.hssf.record.chart.LinkedDataRecord;
import org.apache.poi.hssf.record.chart.ObjectLinkRecord;
import org.apache.poi.hssf.record.chart.PlotAreaRecord;
import org.apache.poi.hssf.record.chart.PlotGrowthRecord;
import org.apache.poi.hssf.record.chart.SeriesIndexRecord;
import org.apache.poi.hssf.record.chart.SeriesListRecord;
import org.apache.poi.hssf.record.chart.SeriesRecord;
import org.apache.poi.hssf.record.chart.SeriesTextRecord;
import org.apache.poi.hssf.record.chart.SeriesToChartGroupRecord;
import org.apache.poi.hssf.record.chart.SheetPropertiesRecord;
import org.apache.poi.hssf.record.chart.TextRecord;
import org.apache.poi.hssf.record.chart.TickRecord;
import org.apache.poi.hssf.record.chart.UnitsRecord;
import org.apache.poi.hssf.record.chart.ValueRangeRecord;
import org.apache.poi.hssf.record.pivottable.DataItemRecord;
import org.apache.poi.hssf.record.pivottable.ExtendedPivotTableViewFieldsRecord;
import org.apache.poi.hssf.record.pivottable.PageItemRecord;
@ -32,16 +82,13 @@ import org.apache.poi.hssf.record.pivottable.ViewDefinitionRecord;
import org.apache.poi.hssf.record.pivottable.ViewFieldsRecord;
import org.apache.poi.hssf.record.pivottable.ViewSourceRecord;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
/**
* Utillity for reading in BIFF8 records and displaying data from them.
*
*@author Andrew C. Oliver (acoliver at apache dot org)
*@author Glen Stampoultzis (glens at apache.org)
*@see #main
* @see #main
*/
public final class BiffViewer {
static final char[] NEW_LINE_CHARS = System.getProperty("line.separator").toCharArray();
@ -130,10 +177,13 @@ public final class BiffViewer {
case BottomMarginRecord.sid: return new BottomMarginRecord(in);
case BoundSheetRecord.sid: return new BoundSheetRecord(in);
case CFHeaderRecord.sid: return new CFHeaderRecord(in);
case CFHeader12Record.sid: return new CFHeader12Record(in);
case CFRuleRecord.sid: return new CFRuleRecord(in);
case CFRule12Record.sid: return new CFRule12Record(in);
// TODO Add CF Ex, and remove from UnknownRecord
case CalcCountRecord.sid: return new CalcCountRecord(in);
case CalcModeRecord.sid: return new CalcModeRecord(in);
case CategorySeriesAxisRecord.sid: return new CategorySeriesAxisRecord(in);
case CategorySeriesAxisRecord.sid:return new CategorySeriesAxisRecord(in);
case ChartFormatRecord.sid: return new ChartFormatRecord(in);
case ChartRecord.sid: return new ChartRecord(in);
case CodepageRecord.sid: return new CodepageRecord(in);
@ -146,7 +196,7 @@ public final class BiffViewer {
case DataFormatRecord.sid: return new DataFormatRecord(in);
case DateWindow1904Record.sid: return new DateWindow1904Record(in);
case DConRefRecord.sid: return new DConRefRecord(in);
case DefaultColWidthRecord.sid:return new DefaultColWidthRecord(in);
case DefaultColWidthRecord.sid: return new DefaultColWidthRecord(in);
case DefaultDataLabelTextPropertiesRecord.sid: return new DefaultDataLabelTextPropertiesRecord(in);
case DefaultRowHeightRecord.sid: return new DefaultRowHeightRecord(in);
case DeltaRecord.sid: return new DeltaRecord(in);
@ -227,9 +277,9 @@ public final class BiffViewer {
case SeriesListRecord.sid: return new SeriesListRecord(in);
case SeriesRecord.sid: return new SeriesRecord(in);
case SeriesTextRecord.sid: return new SeriesTextRecord(in);
case SeriesToChartGroupRecord.sid: return new SeriesToChartGroupRecord(in);
case SeriesToChartGroupRecord.sid:return new SeriesToChartGroupRecord(in);
case SharedFormulaRecord.sid: return new SharedFormulaRecord(in);
case SheetPropertiesRecord.sid:return new SheetPropertiesRecord(in);
case SheetPropertiesRecord.sid: return new SheetPropertiesRecord(in);
case StringRecord.sid: return new StringRecord(in);
case StyleRecord.sid: return new StyleRecord(in);
case SupBookRecord.sid: return new SupBookRecord(in);
@ -420,7 +470,7 @@ public final class BiffViewer {
protected static InputStream getPOIFSInputStream(File file)
throws IOException, FileNotFoundException {
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(file));
NPOIFSFileSystem fs = new NPOIFSFileSystem(new FileInputStream(file));
String workbookName = HSSFWorkbook.getWorkbookDirEntryName(fs.getRoot());
return fs.createDocumentInputStream(workbookName);
}

View File

@ -19,6 +19,7 @@ package org.apache.poi.hssf.eventusermodel;
import java.io.InputStream;
import java.io.IOException;
import java.util.Set;
import org.apache.poi.hssf.eventusermodel.HSSFUserException;
import org.apache.poi.hssf.record.*;
@ -57,7 +58,20 @@ public class HSSFEventFactory {
* @param dir a DirectoryNode containing your workbook
*/
public void processWorkbookEvents(HSSFRequest req, DirectoryNode dir) throws IOException {
InputStream in = dir.createDocumentInputStream("Workbook");
// some old documents have "WORKBOOK" or "BOOK"
final String name;
Set<String> entryNames = dir.getEntryNames();
if (entryNames.contains("Workbook")) {
name = "Workbook";
} else if (entryNames.contains("WORKBOOK")) {
name = "WORKBOOK";
} else if (entryNames.contains("BOOK")) {
name = "BOOK";
} else {
name = "Workbook";
}
InputStream in = dir.createDocumentInputStream(name);
processEvents(req, in);
}

View File

@ -21,6 +21,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.POIDocument;
import org.apache.poi.POIOLE2TextExtractor;
import org.apache.poi.hpsf.DocumentSummaryInformation;
import org.apache.poi.hpsf.SummaryInformation;
@ -75,7 +76,7 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor implements or
public EventBasedExcelExtractor( DirectoryNode dir )
{
super( null );
super( (POIDocument)null );
_dir = dir;
}
@ -83,16 +84,6 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor implements or
this(fs.getRoot());
}
/**
* Return the underlying POIFS FileSystem of
* this document.
*
* @deprecated Use {@link #getRoot()} instead
*/
public POIFSFileSystem getFileSystem() {
return _dir.getFileSystem();
}
/**
* Would return the document information metadata for the document,
* if we supported it

View File

@ -774,13 +774,14 @@ public final class InternalWorkbook {
}
}
if (linkTable != null) {
// also tell the LinkTable about the removed sheet
// +1 because we already removed it from the count of sheets!
for(int i = sheetIndex+1;i < getNumSheets()+1;i++) {
// also update the link-table as otherwise references might point at invalid sheets
linkTable.removeSheet(i);
}
}
}
/**
* make the tabid record look like the current situation.

View File

@ -0,0 +1,88 @@
/* ====================================================================
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;
import org.apache.poi.hssf.record.common.FtrHeader;
import org.apache.poi.hssf.record.common.FutureRecord;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.LittleEndianOutput;
/**
* Conditional Formatting Header v12 record CFHEADER12 (0x0879),
* for conditional formattings introduced in Excel 2007 and newer.
*/
public final class CFHeader12Record extends CFHeaderBase implements FutureRecord {
public static final short sid = 0x0879;
private FtrHeader futureHeader;
/** Creates new CFHeaderRecord */
public CFHeader12Record() {
createEmpty();
futureHeader = new FtrHeader();
futureHeader.setRecordType(sid);
}
public CFHeader12Record(CellRangeAddress[] regions, int nRules) {
super(regions, nRules);
futureHeader = new FtrHeader();
futureHeader.setRecordType(sid);
}
public CFHeader12Record(RecordInputStream in) {
futureHeader = new FtrHeader(in);
read(in);
}
@Override
protected String getRecordName() {
return "CFHEADER12";
}
protected int getDataSize() {
return FtrHeader.getDataSize() + super.getDataSize();
}
public void serialize(LittleEndianOutput out) {
// Sync the associated range
futureHeader.setAssociatedRange(getEnclosingCellRange());
// Write the future header first
futureHeader.serialize(out);
// Then the rest of the CF Header details
super.serialize(out);
}
public short getSid() {
return sid;
}
public short getFutureRecordType() {
return futureHeader.getRecordType();
}
public FtrHeader getFutureHeader() {
return futureHeader;
}
public CellRangeAddress getAssociatedRange() {
return futureHeader.getAssociatedRange();
}
public Object clone() {
CFHeader12Record result = new CFHeader12Record();
result.futureHeader = (FtrHeader)futureHeader.clone();
super.copyTo(result);
return result;
}
}

View File

@ -0,0 +1,153 @@
/* ====================================================================
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;
import org.apache.poi.hssf.record.cf.CellRangeUtil;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.util.LittleEndianOutput;
/**
* Parent of Conditional Formatting Header records,
* {@link CFHeaderRecord} and {@link CFHeader12Record}.
*/
public abstract class CFHeaderBase extends StandardRecord {
private int field_1_numcf;
private int field_2_need_recalculation_and_id;
private CellRangeAddress field_3_enclosing_cell_range;
private CellRangeAddressList field_4_cell_ranges;
/** Creates new CFHeaderBase */
protected CFHeaderBase() {
}
protected CFHeaderBase(CellRangeAddress[] regions, int nRules) {
CellRangeAddress[] unmergedRanges = regions;
CellRangeAddress[] mergeCellRanges = CellRangeUtil.mergeCellRanges(unmergedRanges);
setCellRanges(mergeCellRanges);
field_1_numcf = nRules;
}
protected void createEmpty() {
field_3_enclosing_cell_range = new CellRangeAddress(0, 0, 0, 0);
field_4_cell_ranges = new CellRangeAddressList();
}
protected void read(RecordInputStream in) {
field_1_numcf = in.readShort();
field_2_need_recalculation_and_id = in.readShort();
field_3_enclosing_cell_range = new CellRangeAddress(in);
field_4_cell_ranges = new CellRangeAddressList(in);
}
public int getNumberOfConditionalFormats() {
return field_1_numcf;
}
public void setNumberOfConditionalFormats(int n) {
field_1_numcf=n;
}
public boolean getNeedRecalculation() {
// Held on the 1st bit
return field_2_need_recalculation_and_id % 2 == 1;
}
public void setNeedRecalculation(boolean b) {
// held on the first bit
if (b == getNeedRecalculation()) return;
if (b) field_2_need_recalculation_and_id++;
else field_2_need_recalculation_and_id--;
}
public int getID() {
// Remaining 15 bits of field 2
return field_2_need_recalculation_and_id>>1;
}
public void setID(int id) {
// Remaining 15 bits of field 2
boolean needsRecalc = getNeedRecalculation();
field_2_need_recalculation_and_id = (id<<1);
if (needsRecalc) field_2_need_recalculation_and_id++;
}
public CellRangeAddress getEnclosingCellRange() {
return field_3_enclosing_cell_range;
}
public void setEnclosingCellRange(CellRangeAddress cr) {
field_3_enclosing_cell_range = cr;
}
/**
* Set cell ranges list to a single cell range and
* modify the enclosing cell range accordingly.
* @param cellRanges - list of CellRange objects
*/
public void setCellRanges(CellRangeAddress[] cellRanges) {
if(cellRanges == null) {
throw new IllegalArgumentException("cellRanges must not be null");
}
CellRangeAddressList cral = new CellRangeAddressList();
CellRangeAddress enclosingRange = null;
for (int i = 0; i < cellRanges.length; i++) {
CellRangeAddress cr = cellRanges[i];
enclosingRange = CellRangeUtil.createEnclosingCellRange(cr, enclosingRange);
cral.addCellRangeAddress(cr);
}
field_3_enclosing_cell_range = enclosingRange;
field_4_cell_ranges = cral;
}
public CellRangeAddress[] getCellRanges() {
return field_4_cell_ranges.getCellRangeAddresses();
}
protected abstract String getRecordName();
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("[").append(getRecordName()).append("]\n");
buffer.append("\t.numCF = ").append(getNumberOfConditionalFormats()).append("\n");
buffer.append("\t.needRecalc = ").append(getNeedRecalculation()).append("\n");
buffer.append("\t.id = ").append(getID()).append("\n");
buffer.append("\t.enclosingCellRange= ").append(getEnclosingCellRange()).append("\n");
buffer.append("\t.cfranges=[");
for( int i=0; i<field_4_cell_ranges.countRanges(); i++) {
buffer.append(i==0?"":",").append(field_4_cell_ranges.getCellRangeAddress(i).toString());
}
buffer.append("]\n");
buffer.append("[/").append(getRecordName()).append("]\n");
return buffer.toString();
}
protected int getDataSize() {
return 4 // 2 short fields
+ CellRangeAddress.ENCODED_SIZE
+ field_4_cell_ranges.getSize();
}
public void serialize(LittleEndianOutput out) {
out.writeShort(field_1_numcf);
out.writeShort(field_2_need_recalculation_and_id);
field_3_enclosing_cell_range.serialize(out);
field_4_cell_ranges.serialize(out);
}
protected void copyTo(CFHeaderBase result) {
result.field_1_numcf = field_1_numcf;
result.field_2_need_recalculation_and_id = field_2_need_recalculation_and_id;
result.field_3_enclosing_cell_range = field_3_enclosing_cell_range.copy();
result.field_4_cell_ranges = field_4_cell_ranges.copy();
}
}

View File

@ -17,144 +17,39 @@
package org.apache.poi.hssf.record;
import org.apache.poi.hssf.record.cf.CellRangeUtil;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.util.LittleEndianOutput;
/**
* Conditional Formatting Header record CFHEADER (0x01B0)
*
* @author Dmitriy Kumshayev
* Conditional Formatting Header record CFHEADER (0x01B0).
* Used to describe a {@link CFRuleRecord}.
* @see CFHeader12Record
*/
public final class CFHeaderRecord extends StandardRecord {
public final class CFHeaderRecord extends CFHeaderBase {
public static final short sid = 0x01B0;
private int field_1_numcf;
private int field_2_need_recalculation;
private CellRangeAddress field_3_enclosing_cell_range;
private CellRangeAddressList field_4_cell_ranges;
/** Creates new CFHeaderRecord */
public CFHeaderRecord()
{
field_4_cell_ranges = new CellRangeAddressList();
public CFHeaderRecord() {
createEmpty();
}
public CFHeaderRecord(CellRangeAddress[] regions, int nRules) {
CellRangeAddress[] unmergedRanges = regions;
CellRangeAddress[] mergeCellRanges = CellRangeUtil.mergeCellRanges(unmergedRanges);
setCellRanges(mergeCellRanges);
field_1_numcf = nRules;
super(regions, nRules);
}
public CFHeaderRecord(RecordInputStream in)
{
field_1_numcf = in.readShort();
field_2_need_recalculation = in.readShort();
field_3_enclosing_cell_range = new CellRangeAddress(in);
field_4_cell_ranges = new CellRangeAddressList(in);
public CFHeaderRecord(RecordInputStream in) {
read(in);
}
public int getNumberOfConditionalFormats()
{
return field_1_numcf;
}
public void setNumberOfConditionalFormats(int n)
{
field_1_numcf=n;
}
public boolean getNeedRecalculation()
{
return field_2_need_recalculation==1?true:false;
}
public void setNeedRecalculation(boolean b)
{
field_2_need_recalculation=b?1:0;
}
public CellRangeAddress getEnclosingCellRange()
{
return field_3_enclosing_cell_range;
}
public void setEnclosingCellRange(CellRangeAddress cr)
{
field_3_enclosing_cell_range = cr;
}
/**
* Set cell ranges list to a single cell range and
* modify the enclosing cell range accordingly.
* @param cellRanges - list of CellRange objects
*/
public void setCellRanges(CellRangeAddress[] cellRanges)
{
if(cellRanges == null)
{
throw new IllegalArgumentException("cellRanges must not be null");
}
CellRangeAddressList cral = new CellRangeAddressList();
CellRangeAddress enclosingRange = null;
for (int i = 0; i < cellRanges.length; i++)
{
CellRangeAddress cr = cellRanges[i];
enclosingRange = CellRangeUtil.createEnclosingCellRange(cr, enclosingRange);
cral.addCellRangeAddress(cr);
}
field_3_enclosing_cell_range = enclosingRange;
field_4_cell_ranges = cral;
}
public CellRangeAddress[] getCellRanges() {
return field_4_cell_ranges.getCellRangeAddresses();
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append("[CFHEADER]\n");
buffer.append(" .id = ").append(Integer.toHexString(sid)).append("\n");
buffer.append(" .numCF = ").append(getNumberOfConditionalFormats()).append("\n");
buffer.append(" .needRecalc = ").append(getNeedRecalculation()).append("\n");
buffer.append(" .enclosingCellRange= ").append(getEnclosingCellRange()).append("\n");
buffer.append(" .cfranges=[");
for( int i=0; i<field_4_cell_ranges.countRanges(); i++)
{
buffer.append(i==0?"":",").append(field_4_cell_ranges.getCellRangeAddress(i).toString());
}
buffer.append("]\n");
buffer.append("[/CFHEADER]\n");
return buffer.toString();
}
protected int getDataSize() {
return 4 // 2 short fields
+ CellRangeAddress.ENCODED_SIZE
+ field_4_cell_ranges.getSize();
}
public void serialize(LittleEndianOutput out) {
out.writeShort(field_1_numcf);
out.writeShort(field_2_need_recalculation);
field_3_enclosing_cell_range.serialize(out);
field_4_cell_ranges.serialize(out);
protected String getRecordName() {
return "CFHEADER";
}
public short getSid() {
return sid;
}
public Object clone()
{
public Object clone() {
CFHeaderRecord result = new CFHeaderRecord();
result.field_1_numcf = field_1_numcf;
result.field_2_need_recalculation = field_2_need_recalculation;
result.field_3_enclosing_cell_range = field_3_enclosing_cell_range;
result.field_4_cell_ranges = field_4_cell_ranges.copy();
super.copyTo(result);
return result;
}
}

View File

@ -0,0 +1,365 @@
/* ====================================================================
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;
import java.util.Arrays;
import org.apache.poi.hssf.record.cf.IconMultiStateFormatting;
import org.apache.poi.hssf.record.cf.Threshold;
import org.apache.poi.hssf.record.common.FtrHeader;
import org.apache.poi.hssf.record.common.FutureRecord;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.formula.Formula;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogger;
/**
* Conditional Formatting v12 Rule Record (0x087A).
*
* <p>This is for newer-style Excel conditional formattings,
* from Excel 2007 onwards.
*
* <p>{@link CFRuleRecord} is used where the condition type is
* {@link #CONDITION_TYPE_CELL_VALUE_IS} or {@link #CONDITION_TYPE_FORMULA},
* this is only used for the other types
*/
public final class CFRule12Record extends CFRuleBase implements FutureRecord {
public static final short sid = 0x087A;
private FtrHeader futureHeader;
private int ext_formatting_length;
private byte[] ext_formatting_data;
private Formula formula_scale;
private byte ext_opts;
private int priority;
private int template_type;
private byte template_param_length;
private byte[] template_params;
private IconMultiStateFormatting multistate;
// TODO Parse these
private byte[] gradient_data;
private byte[] databar_data;
private byte[] filter_data;
/** Creates new CFRuleRecord */
private CFRule12Record(byte conditionType, byte comparisonOperation) {
super(conditionType, comparisonOperation);
setDefaults();
}
private CFRule12Record(byte conditionType, byte comparisonOperation, Ptg[] formula1, Ptg[] formula2, Ptg[] formulaScale) {
super(conditionType, comparisonOperation, formula1, formula2);
setDefaults();
this.formula_scale = Formula.create(formulaScale);
}
private void setDefaults() {
futureHeader = new FtrHeader();
futureHeader.setRecordType(sid);
ext_formatting_length = 0;
ext_formatting_data = new byte[4];
formula_scale = Formula.create(Ptg.EMPTY_PTG_ARRAY);
ext_opts = 0;
priority = 0;
template_type = getConditionType();
template_param_length = 16;
template_params = new byte[template_param_length];
}
/**
* Creates a new comparison operation rule
*/
public static CFRule12Record create(HSSFSheet sheet, String formulaText) {
Ptg[] formula1 = parseFormula(formulaText, sheet);
return new CFRule12Record(CONDITION_TYPE_FORMULA, ComparisonOperator.NO_COMPARISON,
formula1, null, null);
}
/**
* Creates a new comparison operation rule
*/
public static CFRule12Record create(HSSFSheet sheet, byte comparisonOperation,
String formulaText1, String formulaText2) {
Ptg[] formula1 = parseFormula(formulaText1, sheet);
Ptg[] formula2 = parseFormula(formulaText2, sheet);
return new CFRule12Record(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation,
formula1, formula2, null);
}
/**
* Creates a new comparison operation rule
*/
public static CFRule12Record create(HSSFSheet sheet, byte comparisonOperation,
String formulaText1, String formulaText2, String formulaTextScale) {
Ptg[] formula1 = parseFormula(formulaText1, sheet);
Ptg[] formula2 = parseFormula(formulaText2, sheet);
Ptg[] formula3 = parseFormula(formulaTextScale, sheet);
return new CFRule12Record(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation,
formula1, formula2, formula3);
}
/**
* Creates a new Icon Set / Multi-State formatting
*/
public static CFRule12Record create(HSSFSheet sheet, IconSet iconSet) {
Threshold[] ts = new Threshold[iconSet.num];
for (int i=0; i<ts.length; i++) {
ts[i] = new Threshold();
}
CFRule12Record r = new CFRule12Record(CONDITION_TYPE_COLOR_SCALE,
ComparisonOperator.NO_COMPARISON);
IconMultiStateFormatting imf = r.createMultiStateFormatting();
imf.setIconSet(iconSet);
imf.setThresholds(ts);
return r;
}
// TODO Static creators for the other record types
public CFRule12Record(RecordInputStream in) {
futureHeader = new FtrHeader(in);
setConditionType(in.readByte());
setComparisonOperation(in.readByte());
int field_3_formula1_len = in.readUShort();
int field_4_formula2_len = in.readUShort();
ext_formatting_length = in.readInt();
ext_formatting_data = new byte[0];
if (ext_formatting_length == 0) {
// 2 bytes reserved
in.readUShort();
} else {
int len = readFormatOptions(in);
if (len < ext_formatting_length) {
ext_formatting_data = new byte[ext_formatting_length-len];
in.readFully(ext_formatting_data);
}
}
setFormula1(Formula.read(field_3_formula1_len, in));
setFormula2(Formula.read(field_4_formula2_len, in));
int formula_scale_len = in.readUShort();
formula_scale = Formula.read(formula_scale_len, in);
ext_opts = in.readByte();
priority = in.readUShort();
template_type = in.readUShort();
template_param_length = in.readByte();
if (template_param_length == 0 || template_param_length == 16) {
template_params = new byte[template_param_length];
in.readFully(template_params);
} else {
logger.log(POILogger.WARN, "CF Rule v12 template params length should be 0 or 16, found " + template_param_length);
in.readRemainder();
}
byte type = getConditionType();
if (type == CONDITION_TYPE_COLOR_SCALE) {
gradient_data = in.readRemainder();
} else if (type == CONDITION_TYPE_DATA_BAR) {
databar_data = in.readRemainder();
} else if (type == CONDITION_TYPE_FILTER) {
filter_data = in.readRemainder();
} else if (type == CONDITION_TYPE_ICON_SET) {
multistate = new IconMultiStateFormatting(in);
}
}
public boolean containsMultiStateBlock() {
return (multistate != null);
}
public IconMultiStateFormatting getMultiStateFormatting() {
return multistate;
}
public IconMultiStateFormatting createMultiStateFormatting() {
if (multistate != null) return multistate;
// Convert, setup and return
setConditionType(CONDITION_TYPE_ICON_SET);
multistate = new IconMultiStateFormatting();
return multistate;
}
/**
* get the stack of the scale expression as a list
*
* @return list of tokens (casts stack to a list and returns it!)
* this method can return null is we are unable to create Ptgs from
* existing excel file
* callers should check for null!
*/
public Ptg[] getParsedExpressionScale() {
return formula_scale.getTokens();
}
public void setParsedExpressionScale(Ptg[] ptgs) {
formula_scale = Formula.create(ptgs);
}
public short getSid() {
return sid;
}
/**
* called by the class that is responsible for writing this sucker.
* Subclasses should implement this so that their data is passed back in a
* byte array.
*
* @param out the stream to write to
*/
public void serialize(LittleEndianOutput out) {
futureHeader.serialize(out);
int formula1Len=getFormulaSize(getFormula1());
int formula2Len=getFormulaSize(getFormula2());
out.writeByte(getConditionType());
out.writeByte(getComparisonOperation());
out.writeShort(formula1Len);
out.writeShort(formula2Len);
// TODO Update ext_formatting_length
if (ext_formatting_length == 0) {
out.writeInt(0);
out.writeShort(0);
} else {
out.writeInt(ext_formatting_length);
serializeFormattingBlock(out);
out.write(ext_formatting_data);
}
getFormula1().serializeTokens(out);
getFormula2().serializeTokens(out);
out.writeShort(getFormulaSize(formula_scale));
formula_scale.serializeTokens(out);
out.writeByte(ext_opts);
out.writeShort(priority);
out.writeShort(template_type);
out.writeByte(template_param_length);
out.write(template_params);
byte type = getConditionType();
if (type == CONDITION_TYPE_COLOR_SCALE) {
out.write(gradient_data);
} else if (type == CONDITION_TYPE_DATA_BAR) {
out.write(databar_data);
} else if (type == CONDITION_TYPE_FILTER) {
out.write(filter_data);
} else if (type == CONDITION_TYPE_ICON_SET) {
multistate.serialize(out);
}
}
protected int getDataSize() {
int len = FtrHeader.getDataSize() + 6;
if (ext_formatting_length == 0) {
len += 6;
} else {
len += 4 + getFormattingBlockSize() + ext_formatting_data.length;
}
len += getFormulaSize(getFormula1());
len += getFormulaSize(getFormula2());
len += 2 + getFormulaSize(formula_scale);
len += 6 + template_params.length;
byte type = getConditionType();
if (type == CONDITION_TYPE_COLOR_SCALE) {
len += gradient_data.length;
} else if (type == CONDITION_TYPE_DATA_BAR) {
len += databar_data.length;
} else if (type == CONDITION_TYPE_FILTER) {
len += filter_data.length;
} else if (type == CONDITION_TYPE_ICON_SET) {
len += multistate.getDataLength();
}
return len;
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("[CFRULE12]\n");
buffer.append(" .condition_type=").append(getConditionType()).append("\n");
buffer.append(" .dxfn12_length =0x").append(Integer.toHexString(ext_formatting_length)).append("\n");
buffer.append(" .option_flags =0x").append(Integer.toHexString(getOptions())).append("\n");
if (containsFontFormattingBlock()) {
buffer.append(_fontFormatting.toString()).append("\n");
}
if (containsBorderFormattingBlock()) {
buffer.append(_borderFormatting.toString()).append("\n");
}
if (containsPatternFormattingBlock()) {
buffer.append(_patternFormatting.toString()).append("\n");
}
buffer.append(" .dxfn12_ext=").append(HexDump.toHex(ext_formatting_data)).append("\n");
buffer.append(" .formula_1 =").append(Arrays.toString(getFormula1().getTokens())).append("\n");
buffer.append(" .formula_2 =").append(Arrays.toString(getFormula2().getTokens())).append("\n");
buffer.append(" .formula_S =").append(Arrays.toString(formula_scale.getTokens())).append("\n");
buffer.append(" .ext_opts =").append(ext_opts).append("\n");
buffer.append(" .priority =").append(priority).append("\n");
buffer.append(" .template_type =").append(template_type).append("\n");
buffer.append(" .template_params=").append(HexDump.toHex(template_params)).append("\n");
buffer.append(" .gradient_data =").append(HexDump.toHex(gradient_data)).append("\n");
buffer.append(" .databar_data =").append(HexDump.toHex(databar_data)).append("\n");
buffer.append(" .filter_data =").append(HexDump.toHex(filter_data)).append("\n");
if (multistate != null) {
buffer.append(multistate);
}
buffer.append("[/CFRULE12]\n");
return buffer.toString();
}
public Object clone() {
CFRule12Record rec = new CFRule12Record(getConditionType(), getComparisonOperation());
rec.futureHeader.setAssociatedRange(futureHeader.getAssociatedRange().copy());
super.copyTo(rec);
rec.ext_formatting_length = ext_formatting_length;
rec.ext_formatting_data = new byte[ext_formatting_length];
System.arraycopy(ext_formatting_data, 0, rec.ext_formatting_data, 0, ext_formatting_length);
rec.formula_scale = formula_scale.copy();
rec.ext_opts = ext_opts;
rec.priority = priority;
rec.template_type = template_type;
rec.template_param_length = template_param_length;
rec.template_params = new byte[template_param_length];
System.arraycopy(template_params, 0, rec.template_params, 0, template_param_length);
// TODO Clone the rgbCT data like Gradients, Databars etc
return rec;
}
public short getFutureRecordType() {
return futureHeader.getRecordType();
}
public FtrHeader getFutureHeader() {
return futureHeader;
}
public CellRangeAddress getAssociatedRange() {
return futureHeader.getAssociatedRange();
}
}

View File

@ -0,0 +1,455 @@
/* ====================================================================
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;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.cf.BorderFormatting;
import org.apache.poi.hssf.record.cf.FontFormatting;
import org.apache.poi.hssf.record.cf.PatternFormatting;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.formula.Formula;
import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
/**
* Conditional Formatting Rules. This can hold old-style rules
*
*
* <p>This is for the older-style Excel conditional formattings,
* new-style (Excel 2007+) also make use of {@link CFRule12Record}
* and {@link CFExRuleRecord} for their rules.
*/
public abstract class CFRuleBase extends StandardRecord {
public static final class ComparisonOperator {
public static final byte NO_COMPARISON = 0;
public static final byte BETWEEN = 1;
public static final byte NOT_BETWEEN = 2;
public static final byte EQUAL = 3;
public static final byte NOT_EQUAL = 4;
public static final byte GT = 5;
public static final byte LT = 6;
public static final byte GE = 7;
public static final byte LE = 8;
private static final byte max_operator = 8;
}
protected static final POILogger logger = POILogFactory.getLogger(CFRuleBase.class);
private byte condition_type;
// The only kinds that CFRuleRecord handles
public static final byte CONDITION_TYPE_CELL_VALUE_IS = 1;
public static final byte CONDITION_TYPE_FORMULA = 2;
// These are CFRule12Rule only
public static final byte CONDITION_TYPE_COLOR_SCALE = 3;
public static final byte CONDITION_TYPE_DATA_BAR = 4;
public static final byte CONDITION_TYPE_FILTER = 5;
public static final byte CONDITION_TYPE_ICON_SET = 6;
private byte comparison_operator;
public static final int TEMPLATE_CELL_VALUE = 0x0000;
public static final int TEMPLATE_FORMULA = 0x0001;
public static final int TEMPLATE_COLOR_SCALE_FORMATTING = 0x0002;
public static final int TEMPLATE_DATA_BAR_FORMATTING = 0x0003;
public static final int TEMPLATE_ICON_SET_FORMATTING = 0x0004;
public static final int TEMPLATE_FILTER = 0x0005;
public static final int TEMPLATE_UNIQUE_VALUES = 0x0007;
public static final int TEMPLATE_CONTAINS_TEXT = 0x0008;
public static final int TEMPLATE_CONTAINS_BLANKS = 0x0009;
public static final int TEMPLATE_CONTAINS_NO_BLANKS = 0x000A;
public static final int TEMPLATE_CONTAINS_ERRORS = 0x000B;
public static final int TEMPLATE_CONTAINS_NO_ERRORS = 0x000C;
public static final int TEMPLATE_TODAY = 0x000F;
public static final int TEMPLATE_TOMORROW = 0x0010;
public static final int TEMPLATE_YESTERDAY = 0x0011;
public static final int TEMPLATE_LAST_7_DAYS = 0x0012;
public static final int TEMPLATE_LAST_MONTH = 0x0013;
public static final int TEMPLATE_NEXT_MONTH = 0x0014;
public static final int TEMPLATE_THIS_WEEK = 0x0015;
public static final int TEMPLATE_NEXT_WEEK = 0x0016;
public static final int TEMPLATE_LAST_WEEK = 0x0017;
public static final int TEMPLATE_THIS_MONTH = 0x0018;
public static final int TEMPLATE_ABOVE_AVERAGE = 0x0019;
public static final int TEMPLATE_BELOW_AVERAGE = 0x001A;
public static final int TEMPLATE_DUPLICATE_VALUES = 0x001B;
public static final int TEMPLATE_ABOVE_OR_EQUAL_TO_AVERAGE = 0x001D;
public static final int TEMPLATE_BELOW_OR_EQUAL_TO_AVERAGE = 0x001E;
static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot
static final BitField alignHor = bf(0x00000001); // 0 = Horizontal alignment modified
static final BitField alignVer = bf(0x00000002); // 0 = Vertical alignment modified
static final BitField alignWrap = bf(0x00000004); // 0 = Text wrapped flag modified
static final BitField alignRot = bf(0x00000008); // 0 = Text rotation modified
static final BitField alignJustLast = bf(0x00000010); // 0 = Justify last line flag modified
static final BitField alignIndent = bf(0x00000020); // 0 = Indentation modified
static final BitField alignShrin = bf(0x00000040); // 0 = Shrink to fit flag modified
static final BitField mergeCell = bf(0x00000080); // Normally 1, 0 = Merge Cell flag modified
static final BitField protLocked = bf(0x00000100); // 0 = Cell locked flag modified
static final BitField protHidden = bf(0x00000200); // 0 = Cell hidden flag modified
static final BitField bordLeft = bf(0x00000400); // 0 = Left border style and colour modified
static final BitField bordRight = bf(0x00000800); // 0 = Right border style and colour modified
static final BitField bordTop = bf(0x00001000); // 0 = Top border style and colour modified
static final BitField bordBot = bf(0x00002000); // 0 = Bottom border style and colour modified
static final BitField bordTlBr = bf(0x00004000); // 0 = Top-left to bottom-right border flag modified
static final BitField bordBlTr = bf(0x00008000); // 0 = Bottom-left to top-right border flag modified
static final BitField pattStyle = bf(0x00010000); // 0 = Pattern style modified
static final BitField pattCol = bf(0x00020000); // 0 = Pattern colour modified
static final BitField pattBgCol = bf(0x00040000); // 0 = Pattern background colour modified
static final BitField notUsed2 = bf(0x00380000); // Always 111 (ifmt / ifnt / 1)
static final BitField undocumented = bf(0x03C00000); // Undocumented bits
static final BitField fmtBlockBits = bf(0x7C000000); // Bits: font,align,bord,patt,prot
static final BitField font = bf(0x04000000); // 1 = Record contains font formatting block
static final BitField align = bf(0x08000000); // 1 = Record contains alignment formatting block
static final BitField bord = bf(0x10000000); // 1 = Record contains border formatting block
static final BitField patt = bf(0x20000000); // 1 = Record contains pattern formatting block
static final BitField prot = bf(0x40000000); // 1 = Record contains protection formatting block
static final BitField alignTextDir = bf(0x80000000); // 0 = Text direction modified
private static BitField bf(int i) {
return BitFieldFactory.getInstance(i);
}
protected int formatting_options;
protected short formatting_not_used; // TODO Decode this properly
protected FontFormatting _fontFormatting;
protected BorderFormatting _borderFormatting;
protected PatternFormatting _patternFormatting;
private Formula formula1;
private Formula formula2;
/** Creates new CFRuleRecord */
protected CFRuleBase(byte conditionType, byte comparisonOperation) {
setConditionType(conditionType);
setComparisonOperation(comparisonOperation);
formula1 = Formula.create(Ptg.EMPTY_PTG_ARRAY);
formula2 = Formula.create(Ptg.EMPTY_PTG_ARRAY);
}
protected CFRuleBase(byte conditionType, byte comparisonOperation, Ptg[] formula1, Ptg[] formula2) {
this(conditionType, comparisonOperation);
this.formula1 = Formula.create(formula1);
this.formula2 = Formula.create(formula2);
}
protected CFRuleBase() {}
protected int readFormatOptions(RecordInputStream in) {
formatting_options = in.readInt();
formatting_not_used = in.readShort();
int len = 6;
if (containsFontFormattingBlock()) {
_fontFormatting = new FontFormatting(in);
len += _fontFormatting.getDataLength();
}
if (containsBorderFormattingBlock()) {
_borderFormatting = new BorderFormatting(in);
len += _borderFormatting.getDataLength();
}
if (containsPatternFormattingBlock()) {
_patternFormatting = new PatternFormatting(in);
len += _patternFormatting.getDataLength();
}
return len;
}
public byte getConditionType() {
return condition_type;
}
protected void setConditionType(byte condition_type) {
if ((this instanceof CFRuleRecord)) {
if (condition_type == CONDITION_TYPE_CELL_VALUE_IS ||
condition_type == CONDITION_TYPE_FORMULA) {
// Good, valid combination
} else {
throw new IllegalArgumentException("CFRuleRecord only accepts Value-Is and Formula types");
}
}
this.condition_type = condition_type;
}
public void setComparisonOperation(byte operation) {
if (operation < 0 || operation > ComparisonOperator.max_operator)
throw new IllegalArgumentException(
"Valid operators are only in the range 0 to " +ComparisonOperator.max_operator);
this.comparison_operator = operation;
}
public byte getComparisonOperation() {
return comparison_operator;
}
public boolean containsFontFormattingBlock() {
return getOptionFlag(font);
}
public void setFontFormatting(FontFormatting fontFormatting) {
_fontFormatting = fontFormatting;
setOptionFlag(fontFormatting != null, font);
}
public FontFormatting getFontFormatting() {
if( containsFontFormattingBlock()) {
return _fontFormatting;
}
return null;
}
public boolean containsAlignFormattingBlock() {
return getOptionFlag(align);
}
public void setAlignFormattingUnchanged() {
setOptionFlag(false,align);
}
public boolean containsBorderFormattingBlock() {
return getOptionFlag(bord);
}
public void setBorderFormatting(BorderFormatting borderFormatting) {
_borderFormatting = borderFormatting;
setOptionFlag(borderFormatting != null, bord);
}
public BorderFormatting getBorderFormatting() {
if( containsBorderFormattingBlock()) {
return _borderFormatting;
}
return null;
}
public boolean containsPatternFormattingBlock() {
return getOptionFlag(patt);
}
public void setPatternFormatting(PatternFormatting patternFormatting) {
_patternFormatting = patternFormatting;
setOptionFlag(patternFormatting!=null, patt);
}
public PatternFormatting getPatternFormatting() {
if( containsPatternFormattingBlock())
{
return _patternFormatting;
}
return null;
}
public boolean containsProtectionFormattingBlock() {
return getOptionFlag(prot);
}
public void setProtectionFormattingUnchanged() {
setOptionFlag(false,prot);
}
/**
* get the option flags
*
* @return bit mask
*/
public int getOptions() {
return formatting_options;
}
private boolean isModified(BitField field) {
return !field.isSet(formatting_options);
}
private void setModified(boolean modified, BitField field) {
formatting_options = field.setBoolean(formatting_options, !modified);
}
public boolean isLeftBorderModified() {
return isModified(bordLeft);
}
public void setLeftBorderModified(boolean modified) {
setModified(modified,bordLeft);
}
public boolean isRightBorderModified() {
return isModified(bordRight);
}
public void setRightBorderModified(boolean modified)
{
setModified(modified,bordRight);
}
public boolean isTopBorderModified() {
return isModified(bordTop);
}
public void setTopBorderModified(boolean modified) {
setModified(modified,bordTop);
}
public boolean isBottomBorderModified() {
return isModified(bordBot);
}
public void setBottomBorderModified(boolean modified) {
setModified(modified,bordBot);
}
public boolean isTopLeftBottomRightBorderModified() {
return isModified(bordTlBr);
}
public void setTopLeftBottomRightBorderModified(boolean modified) {
setModified(modified,bordTlBr);
}
public boolean isBottomLeftTopRightBorderModified() {
return isModified(bordBlTr);
}
public void setBottomLeftTopRightBorderModified(boolean modified) {
setModified(modified,bordBlTr);
}
public boolean isPatternStyleModified() {
return isModified(pattStyle);
}
public void setPatternStyleModified(boolean modified) {
setModified(modified,pattStyle);
}
public boolean isPatternColorModified() {
return isModified(pattCol);
}
public void setPatternColorModified(boolean modified) {
setModified(modified,pattCol);
}
public boolean isPatternBackgroundColorModified() {
return isModified(pattBgCol);
}
public void setPatternBackgroundColorModified(boolean modified) {
setModified(modified,pattBgCol);
}
private boolean getOptionFlag(BitField field) {
return field.isSet(formatting_options);
}
private void setOptionFlag(boolean flag, BitField field) {
formatting_options = field.setBoolean(formatting_options, flag);
}
protected int getFormattingBlockSize() {
return 6 +
(containsFontFormattingBlock()?_fontFormatting.getRawRecord().length:0)+
(containsBorderFormattingBlock()?8:0)+
(containsPatternFormattingBlock()?4:0);
}
protected void serializeFormattingBlock(LittleEndianOutput out) {
out.writeInt(formatting_options);
out.writeShort(formatting_not_used);
if (containsFontFormattingBlock()) {
byte[] fontFormattingRawRecord = _fontFormatting.getRawRecord();
out.write(fontFormattingRawRecord);
}
if (containsBorderFormattingBlock()) {
_borderFormatting.serialize(out);
}
if (containsPatternFormattingBlock()) {
_patternFormatting.serialize(out);
}
}
/**
* get the stack of the 1st expression as a list
*
* @return list of tokens (casts stack to a list and returns it!)
* this method can return null is we are unable to create Ptgs from
* existing excel file
* callers should check for null!
*/
public Ptg[] getParsedExpression1() {
return formula1.getTokens();
}
public void setParsedExpression1(Ptg[] ptgs) {
formula1 = Formula.create(ptgs);
}
protected Formula getFormula1() {
return formula1;
}
protected void setFormula1(Formula formula1) {
this.formula1 = formula1;
}
/**
* get the stack of the 2nd expression as a list
*
* @return array of {@link Ptg}s, possibly <code>null</code>
*/
public Ptg[] getParsedExpression2() {
return Formula.getTokens(formula2);
}
public void setParsedExpression2(Ptg[] ptgs) {
formula2 = Formula.create(ptgs);
}
protected Formula getFormula2() {
return formula2;
}
protected void setFormula2(Formula formula2) {
this.formula2 = formula2;
}
/**
* @param formula must not be <code>null</code>
* @return encoded size of the formula tokens (does not include 2 bytes for ushort length)
*/
protected static int getFormulaSize(Formula formula) {
return formula.getEncodedTokenSize();
}
/**
* TODO - parse conditional format formulas properly i.e. produce tRefN and tAreaN instead of tRef and tArea
* this call will produce the wrong results if the formula contains any cell references
* One approach might be to apply the inverse of SharedFormulaRecord.convertSharedFormulas(Stack, int, int)
* Note - two extra parameters (rowIx & colIx) will be required. They probably come from one of the Region objects.
*
* @return <code>null</code> if <tt>formula</tt> was null.
*/
public static Ptg[] parseFormula(String formula, HSSFSheet sheet) {
if(formula == null) {
return null;
}
int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);
return HSSFFormulaParser.parse(formula, sheet.getWorkbook(), FormulaType.CELL, sheetIndex);
}
protected void copyTo(CFRuleBase rec) {
rec.condition_type = condition_type;
rec.comparison_operator = comparison_operator;
rec.formatting_options = formatting_options;
rec.formatting_not_used = formatting_not_used;
if (containsFontFormattingBlock()) {
rec._fontFormatting = (FontFormatting) _fontFormatting.clone();
}
if (containsBorderFormattingBlock()) {
rec._borderFormatting = (BorderFormatting) _borderFormatting.clone();
}
if (containsPatternFormattingBlock()) {
rec._patternFormatting = (PatternFormatting) _patternFormatting.clone();
}
rec.setFormula1(getFormula1().copy());
rec.setFormula2(getFormula2().copy());
}
}

View File

@ -19,117 +19,42 @@ package org.apache.poi.hssf.record;
import java.util.Arrays;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.cf.BorderFormatting;
import org.apache.poi.hssf.record.cf.FontFormatting;
import org.apache.poi.hssf.record.cf.PatternFormatting;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.formula.Formula;
import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndianOutput;
/**
* Conditional Formatting Rule Record (0x01B1).<br/>
* Conditional Formatting Rule Record (0x01B1).
*
* @author Dmitriy Kumshayev
* <p>This is for the older-style Excel conditional formattings,
* new-style (Excel 2007+) also make use of {@link CFRule12Record}
* and {@link CFExRuleRecord} for their rules.
*/
public final class CFRuleRecord extends StandardRecord {
public final class CFRuleRecord extends CFRuleBase {
public static final short sid = 0x01B1;
public static final class ComparisonOperator {
public static final byte NO_COMPARISON = 0;
public static final byte BETWEEN = 1;
public static final byte NOT_BETWEEN = 2;
public static final byte EQUAL = 3;
public static final byte NOT_EQUAL = 4;
public static final byte GT = 5;
public static final byte LT = 6;
public static final byte GE = 7;
public static final byte LE = 8;
}
private byte field_1_condition_type;
public static final byte CONDITION_TYPE_CELL_VALUE_IS = 1;
public static final byte CONDITION_TYPE_FORMULA = 2;
private byte field_2_comparison_operator;
private int field_5_options;
private static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot
private static final BitField alignHor = bf(0x00000001); // 0 = Horizontal alignment modified
private static final BitField alignVer = bf(0x00000002); // 0 = Vertical alignment modified
private static final BitField alignWrap = bf(0x00000004); // 0 = Text wrapped flag modified
private static final BitField alignRot = bf(0x00000008); // 0 = Text rotation modified
private static final BitField alignJustLast = bf(0x00000010); // 0 = Justify last line flag modified
private static final BitField alignIndent = bf(0x00000020); // 0 = Indentation modified
private static final BitField alignShrin = bf(0x00000040); // 0 = Shrink to fit flag modified
private static final BitField notUsed1 = bf(0x00000080); // Always 1
private static final BitField protLocked = bf(0x00000100); // 0 = Cell locked flag modified
private static final BitField protHidden = bf(0x00000200); // 0 = Cell hidden flag modified
private static final BitField bordLeft = bf(0x00000400); // 0 = Left border style and colour modified
private static final BitField bordRight = bf(0x00000800); // 0 = Right border style and colour modified
private static final BitField bordTop = bf(0x00001000); // 0 = Top border style and colour modified
private static final BitField bordBot = bf(0x00002000); // 0 = Bottom border style and colour modified
private static final BitField bordTlBr = bf(0x00004000); // 0 = Top-left to bottom-right border flag modified
private static final BitField bordBlTr = bf(0x00008000); // 0 = Bottom-left to top-right border flag modified
private static final BitField pattStyle = bf(0x00010000); // 0 = Pattern style modified
private static final BitField pattCol = bf(0x00020000); // 0 = Pattern colour modified
private static final BitField pattBgCol = bf(0x00040000); // 0 = Pattern background colour modified
private static final BitField notUsed2 = bf(0x00380000); // Always 111
private static final BitField undocumented = bf(0x03C00000); // Undocumented bits
private static final BitField fmtBlockBits = bf(0x7C000000); // Bits: font,align,bord,patt,prot
private static final BitField font = bf(0x04000000); // 1 = Record contains font formatting block
private static final BitField align = bf(0x08000000); // 1 = Record contains alignment formatting block
private static final BitField bord = bf(0x10000000); // 1 = Record contains border formatting block
private static final BitField patt = bf(0x20000000); // 1 = Record contains pattern formatting block
private static final BitField prot = bf(0x40000000); // 1 = Record contains protection formatting block
private static final BitField alignTextDir = bf(0x80000000); // 0 = Text direction modified
private static BitField bf(int i) {
return BitFieldFactory.getInstance(i);
}
private short field_6_not_used;
private FontFormatting _fontFormatting;
private BorderFormatting _borderFormatting;
private PatternFormatting _patternFormatting;
private Formula field_17_formula1;
private Formula field_18_formula2;
/** Creates new CFRuleRecord */
private CFRuleRecord(byte conditionType, byte comparisonOperation)
{
field_1_condition_type=conditionType;
field_2_comparison_operator=comparisonOperation;
// Set modification flags to 1: by default options are not modified
field_5_options = modificationBits.setValue(field_5_options, -1);
// Set formatting block flags to 0 (no formatting blocks)
field_5_options = fmtBlockBits.setValue(field_5_options, 0);
field_5_options = undocumented.clear(field_5_options);
field_6_not_used = (short)0x8002; // Excel seems to write this value, but it doesn't seem to care what it reads
_fontFormatting=null;
_borderFormatting=null;
_patternFormatting=null;
field_17_formula1=Formula.create(Ptg.EMPTY_PTG_ARRAY);
field_18_formula2=Formula.create(Ptg.EMPTY_PTG_ARRAY);
private CFRuleRecord(byte conditionType, byte comparisonOperation) {
super(conditionType, comparisonOperation);
setDefaults();
}
private CFRuleRecord(byte conditionType, byte comparisonOperation, Ptg[] formula1, Ptg[] formula2) {
this(conditionType, comparisonOperation);
field_17_formula1 = Formula.create(formula1);
field_18_formula2 = Formula.create(formula2);
super(conditionType, comparisonOperation, formula1, formula2);
setDefaults();
}
private void setDefaults() {
// Set modification flags to 1: by default options are not modified
formatting_options = modificationBits.setValue(formatting_options, -1);
// Set formatting block flags to 0 (no formatting blocks)
formatting_options = fmtBlockBits.setValue(formatting_options, 0);
formatting_options = undocumented.clear(formatting_options);
formatting_not_used = (short)0x8002; // Excel seems to write this value, but it doesn't seem to care what it reads
_fontFormatting = null;
_borderFormatting = null;
_patternFormatting = null;
}
/**
@ -151,280 +76,21 @@ public final class CFRuleRecord extends StandardRecord {
}
public CFRuleRecord(RecordInputStream in) {
field_1_condition_type = in.readByte();
field_2_comparison_operator = in.readByte();
setConditionType(in.readByte());
setComparisonOperation(in.readByte());
int field_3_formula1_len = in.readUShort();
int field_4_formula2_len = in.readUShort();
field_5_options = in.readInt();
field_6_not_used = in.readShort();
if (containsFontFormattingBlock()) {
_fontFormatting = new FontFormatting(in);
}
if (containsBorderFormattingBlock()) {
_borderFormatting = new BorderFormatting(in);
}
if (containsPatternFormattingBlock()) {
_patternFormatting = new PatternFormatting(in);
}
readFormatOptions(in);
// "You may not use unions, intersections or array constants in Conditional Formatting criteria"
field_17_formula1 = Formula.read(field_3_formula1_len, in);
field_18_formula2 = Formula.read(field_4_formula2_len, in);
setFormula1(Formula.read(field_3_formula1_len, in));
setFormula2(Formula.read(field_4_formula2_len, in));
}
public byte getConditionType()
{
return field_1_condition_type;
}
public boolean containsFontFormattingBlock()
{
return getOptionFlag(font);
}
public void setFontFormatting(FontFormatting fontFormatting)
{
_fontFormatting = fontFormatting;
setOptionFlag(fontFormatting != null, font);
}
public FontFormatting getFontFormatting()
{
if( containsFontFormattingBlock())
{
return _fontFormatting;
}
return null;
}
public boolean containsAlignFormattingBlock()
{
return getOptionFlag(align);
}
public void setAlignFormattingUnchanged()
{
setOptionFlag(false,align);
}
public boolean containsBorderFormattingBlock()
{
return getOptionFlag(bord);
}
public void setBorderFormatting(BorderFormatting borderFormatting)
{
_borderFormatting = borderFormatting;
setOptionFlag(borderFormatting != null, bord);
}
public BorderFormatting getBorderFormatting()
{
if( containsBorderFormattingBlock())
{
return _borderFormatting;
}
return null;
}
public boolean containsPatternFormattingBlock()
{
return getOptionFlag(patt);
}
public void setPatternFormatting(PatternFormatting patternFormatting)
{
_patternFormatting = patternFormatting;
setOptionFlag(patternFormatting!=null, patt);
}
public PatternFormatting getPatternFormatting()
{
if( containsPatternFormattingBlock())
{
return _patternFormatting;
}
return null;
}
public boolean containsProtectionFormattingBlock()
{
return getOptionFlag(prot);
}
public void setProtectionFormattingUnchanged()
{
setOptionFlag(false,prot);
}
public void setComparisonOperation(byte operation)
{
field_2_comparison_operator = operation;
}
public byte getComparisonOperation()
{
return field_2_comparison_operator;
}
/**
* get the option flags
*
* @return bit mask
*/
public int getOptions()
{
return field_5_options;
}
private boolean isModified(BitField field)
{
return !field.isSet(field_5_options);
}
private void setModified(boolean modified, BitField field)
{
field_5_options = field.setBoolean(field_5_options, !modified);
}
public boolean isLeftBorderModified()
{
return isModified(bordLeft);
}
public void setLeftBorderModified(boolean modified)
{
setModified(modified,bordLeft);
}
public boolean isRightBorderModified()
{
return isModified(bordRight);
}
public void setRightBorderModified(boolean modified)
{
setModified(modified,bordRight);
}
public boolean isTopBorderModified()
{
return isModified(bordTop);
}
public void setTopBorderModified(boolean modified)
{
setModified(modified,bordTop);
}
public boolean isBottomBorderModified()
{
return isModified(bordBot);
}
public void setBottomBorderModified(boolean modified)
{
setModified(modified,bordBot);
}
public boolean isTopLeftBottomRightBorderModified()
{
return isModified(bordTlBr);
}
public void setTopLeftBottomRightBorderModified(boolean modified)
{
setModified(modified,bordTlBr);
}
public boolean isBottomLeftTopRightBorderModified()
{
return isModified(bordBlTr);
}
public void setBottomLeftTopRightBorderModified(boolean modified)
{
setModified(modified,bordBlTr);
}
public boolean isPatternStyleModified()
{
return isModified(pattStyle);
}
public void setPatternStyleModified(boolean modified)
{
setModified(modified,pattStyle);
}
public boolean isPatternColorModified()
{
return isModified(pattCol);
}
public void setPatternColorModified(boolean modified)
{
setModified(modified,pattCol);
}
public boolean isPatternBackgroundColorModified()
{
return isModified(pattBgCol);
}
public void setPatternBackgroundColorModified(boolean modified)
{
setModified(modified,pattBgCol);
}
private boolean getOptionFlag(BitField field)
{
return field.isSet(field_5_options);
}
private void setOptionFlag(boolean flag, BitField field)
{
field_5_options = field.setBoolean(field_5_options, flag);
}
/**
* get the stack of the 1st expression as a list
*
* @return list of tokens (casts stack to a list and returns it!)
* this method can return null is we are unable to create Ptgs from
* existing excel file
* callers should check for null!
*/
public Ptg[] getParsedExpression1()
{
return field_17_formula1.getTokens();
}
public void setParsedExpression1(Ptg[] ptgs) {
field_17_formula1 = Formula.create(ptgs);
}
/**
* get the stack of the 2nd expression as a list
*
* @return array of {@link Ptg}s, possibly <code>null</code>
*/
public Ptg[] getParsedExpression2() {
return Formula.getTokens(field_18_formula2);
}
public void setParsedExpression2(Ptg[] ptgs) {
field_18_formula2 = Formula.create(ptgs);
}
public short getSid()
{
public short getSid() {
return sid;
}
/**
* @param ptgs must not be <code>null</code>
* @return encoded size of the formula tokens (does not include 2 bytes for ushort length)
*/
private static int getFormulaSize(Formula formula) {
return formula.getEncodedTokenSize();
}
/**
* called by the class that is responsible for writing this sucker.
* Subclasses should implement this so that their data is passed back in a
@ -433,50 +99,30 @@ public final class CFRuleRecord extends StandardRecord {
* @param out the stream to write to
*/
public void serialize(LittleEndianOutput out) {
int formula1Len=getFormulaSize(getFormula1());
int formula2Len=getFormulaSize(getFormula2());
int formula1Len=getFormulaSize(field_17_formula1);
int formula2Len=getFormulaSize(field_18_formula2);
out.writeByte(field_1_condition_type);
out.writeByte(field_2_comparison_operator);
out.writeByte(getConditionType());
out.writeByte(getComparisonOperation());
out.writeShort(formula1Len);
out.writeShort(formula2Len);
out.writeInt(field_5_options);
out.writeShort(field_6_not_used);
if (containsFontFormattingBlock()) {
byte[] fontFormattingRawRecord = _fontFormatting.getRawRecord();
out.write(fontFormattingRawRecord);
}
serializeFormattingBlock(out);
if (containsBorderFormattingBlock()) {
_borderFormatting.serialize(out);
}
if (containsPatternFormattingBlock()) {
_patternFormatting.serialize(out);
}
field_17_formula1.serializeTokens(out);
field_18_formula2.serializeTokens(out);
getFormula1().serializeTokens(out);
getFormula2().serializeTokens(out);
}
protected int getDataSize() {
int i = 12 +
(containsFontFormattingBlock()?_fontFormatting.getRawRecord().length:0)+
(containsBorderFormattingBlock()?8:0)+
(containsPatternFormattingBlock()?4:0)+
getFormulaSize(field_17_formula1)+
getFormulaSize(field_18_formula2);
return i
;
return 6 + getFormattingBlockSize() +
getFormulaSize(getFormula1())+
getFormulaSize(getFormula2());
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("[CFRULE]\n");
buffer.append(" .condition_type =").append(field_1_condition_type).append("\n");
buffer.append(" .condition_type =").append(getConditionType()).append("\n");
buffer.append(" OPTION FLAGS=0x").append(Integer.toHexString(getOptions())).append("\n");
if (containsFontFormattingBlock()) {
buffer.append(_fontFormatting.toString()).append("\n");
@ -487,44 +133,15 @@ public final class CFRuleRecord extends StandardRecord {
if (containsPatternFormattingBlock()) {
buffer.append(_patternFormatting.toString()).append("\n");
}
buffer.append(" Formula 1 =").append(Arrays.toString(field_17_formula1.getTokens())).append("\n");
buffer.append(" Formula 2 =").append(Arrays.toString(field_18_formula2.getTokens())).append("\n");
buffer.append(" Formula 1 =").append(Arrays.toString(getFormula1().getTokens())).append("\n");
buffer.append(" Formula 2 =").append(Arrays.toString(getFormula2().getTokens())).append("\n");
buffer.append("[/CFRULE]\n");
return buffer.toString();
}
public Object clone() {
CFRuleRecord rec = new CFRuleRecord(field_1_condition_type, field_2_comparison_operator);
rec.field_5_options = field_5_options;
rec.field_6_not_used = field_6_not_used;
if (containsFontFormattingBlock()) {
rec._fontFormatting = (FontFormatting) _fontFormatting.clone();
}
if (containsBorderFormattingBlock()) {
rec._borderFormatting = (BorderFormatting) _borderFormatting.clone();
}
if (containsPatternFormattingBlock()) {
rec._patternFormatting = (PatternFormatting) _patternFormatting.clone();
}
rec.field_17_formula1 = field_17_formula1.copy();
rec.field_18_formula2 = field_18_formula2.copy();
CFRuleRecord rec = new CFRuleRecord(getConditionType(), getComparisonOperation());
super.copyTo(rec);
return rec;
}
/**
* TODO - parse conditional format formulas properly i.e. produce tRefN and tAreaN instead of tRef and tArea
* this call will produce the wrong results if the formula contains any cell references
* One approach might be to apply the inverse of SharedFormulaRecord.convertSharedFormulas(Stack, int, int)
* Note - two extra parameters (rowIx & colIx) will be required. They probably come from one of the Region objects.
*
* @return <code>null</code> if <tt>formula</tt> was null.
*/
private static Ptg[] parseFormula(String formula, HSSFSheet sheet) {
if(formula == null) {
return null;
}
int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);
return HSSFFormulaParser.parse(formula, sheet.getWorkbook(), FormulaType.CELL, sheetIndex);
}
}

View File

@ -36,6 +36,9 @@ import org.apache.poi.util.POILogger;
public final class FeatRecord extends StandardRecord {
private static POILogger logger = POILogFactory.getLogger(FeatRecord.class);
public final static short sid = 0x0868;
// SIDs from newer versions
public final static short v11_sid = 0x0872;
public final static short v12_sid = 0x0878;
private FtrHeader futureHeader;

View File

@ -62,17 +62,27 @@ public final class NameCommentRecord extends StandardRecord {
out.writeShort(field_4_name_length);
out.writeShort(field_5_comment_length);
out.writeByte(0);
boolean isNameMultiByte = StringUtil.hasMultibyte(field_6_name_text);
out.writeByte(isNameMultiByte ? 1 : 0);
if (isNameMultiByte) {
StringUtil.putUnicodeLE(field_6_name_text, out);
} else {
StringUtil.putCompressedUnicode(field_6_name_text, out);
out.writeByte(0);
}
boolean isCommentMultiByte = StringUtil.hasMultibyte(field_7_comment_text);
out.writeByte(isCommentMultiByte ? 1 : 0);
if (isCommentMultiByte) {
StringUtil.putUnicodeLE(field_7_comment_text, out);
} else {
StringUtil.putCompressedUnicode(field_7_comment_text, out);
}
}
@Override
protected int getDataSize() {
return 18 // 4 shorts + 1 long + 2 spurious 'nul's
+ field_6_name_text.length()
+ field_7_comment_text.length();
+ (StringUtil.hasMultibyte(field_6_name_text) ? field_6_name_text.length()*2 : field_6_name_text.length())
+ (StringUtil.hasMultibyte(field_7_comment_text) ? field_7_comment_text.length()*2 : field_7_comment_text.length());
}
/**
@ -86,10 +96,16 @@ public final class NameCommentRecord extends StandardRecord {
final int field_4_name_length = in.readShort();
final int field_5_comment_length = in.readShort();
in.readByte(); //spurious NUL
if (in.readByte() == 0) {
field_6_name_text = StringUtil.readCompressedUnicode(in, field_4_name_length);
in.readByte(); //spurious NUL
} else {
field_6_name_text = StringUtil.readUnicodeLE(in, field_4_name_length);
}
if (in.readByte() == 0) {
field_7_comment_text = StringUtil.readCompressedUnicode(in, field_5_comment_length);
} else {
field_7_comment_text = StringUtil.readUnicodeLE(in, field_5_comment_length);
}
}
/**

View File

@ -411,11 +411,12 @@ public final class NameRecord extends ContinuableRecord {
* @return extern sheet index
*/
public int getExternSheetNumber(){
if (field_13_name_definition.getEncodedSize() < 1) {
Ptg[] tokens = field_13_name_definition.getTokens();
if (tokens.length == 0) {
return 0;
}
Ptg ptg = field_13_name_definition.getTokens()[0];
Ptg ptg = tokens[0];
if (ptg.getClass() == Area3DPtg.class){
return ((Area3DPtg) ptg).getExternSheetIndex();

View File

@ -62,10 +62,6 @@ import org.apache.poi.hssf.record.pivottable.ViewSourceRecord;
* Description: Takes a stream and outputs an array of Record objects.<P>
*
* @see org.apache.poi.hssf.eventmodel.EventRecordFactory
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Marc Johnson (mjohnson at apache dot org)
* @author Glen Stampoultzis (glens at apache.org)
* @author Csaba Nagy (ncsaba at yahoo dot com)
*/
public final class RecordFactory {
private static final int NUM_RECORDS = 512;
@ -111,7 +107,6 @@ public final class RecordFactory {
* be of a different class to the declaring class.
*/
private static final class ReflectionMethodRecordCreator implements I_RecordCreator {
private final Method _m;
public ReflectionMethodRecordCreator(Method m) {
_m = m;
@ -134,7 +129,6 @@ public final class RecordFactory {
}
}
private static final Class<?>[] CONSTRUCTOR_ARGS = { RecordInputStream.class, };
/**
@ -155,7 +149,9 @@ public final class RecordFactory {
CalcCountRecord.class,
CalcModeRecord.class,
CFHeaderRecord.class,
CFHeader12Record.class,
CFRuleRecord.class,
CFRule12Record.class,
ChartRecord.class,
ChartTitleFormatRecord.class,
CodepageRecord.class,
@ -267,7 +263,7 @@ public final class RecordFactory {
ChartFRTInfoRecord.class,
ChartStartBlockRecord.class,
ChartEndBlockRecord.class,
// TODO ChartFormatRecord.class,
// TODO ChartFormatRecord.class,
ChartStartObjectRecord.class,
ChartEndObjectRecord.class,
CatLabRecord.class,
@ -313,7 +309,6 @@ public final class RecordFactory {
* are returned digested into the non-mul form.
*/
public static Record [] createRecord(RecordInputStream in) {
Record record = createSingleRecord(in);
if (record instanceof DBCellRecord) {
// Not needed by POI. Regenerated from scratch by POI when spreadsheet is written
@ -442,7 +437,7 @@ public final class RecordFactory {
}
result.put(key, getRecordCreator(recClass));
}
// result.put(Integer.valueOf(0x0406), result.get(Integer.valueOf(0x06)));
// result.put(Integer.valueOf(0x0406), result.get(Integer.valueOf(0x06)));
return result;
}

View File

@ -52,7 +52,16 @@ public final class RecordInputStream implements LittleEndianInput {
public static final class LeftoverDataException extends RuntimeException {
public LeftoverDataException(int sid, int remainingByteCount) {
super("Initialisation of record 0x" + Integer.toHexString(sid).toUpperCase()
+ " left " + remainingByteCount + " bytes remaining still to be read.");
+ "(" + getRecordName(sid) + ") left " + remainingByteCount
+ " bytes remaining still to be read.");
}
private static String getRecordName(int sid) {
Class<? extends Record> recordClass = RecordFactory.getRecordClass(sid);
if(recordClass == null) {
return null;
}
return recordClass.getSimpleName();
}
}

View File

@ -64,6 +64,9 @@ public final class RowRecord extends StandardRecord {
// bit 15 is unused
public RowRecord(int rowNumber) {
if(rowNumber < 0) {
throw new IllegalArgumentException("Invalid row number (" + rowNumber + ")");
}
field_1_row_number = rowNumber;
field_4_height = (short)0xFF;
field_5_optimize = ( short ) 0;
@ -76,6 +79,9 @@ public final class RowRecord extends StandardRecord {
public RowRecord(RecordInputStream in) {
field_1_row_number = in.readUShort();
if(field_1_row_number < 0) {
throw new IllegalArgumentException("Invalid row number " + field_1_row_number + " found in InputStream");
}
field_2_first_col = in.readShort();
field_3_last_col = in.readShort();
field_4_height = in.readShort();

View File

@ -179,8 +179,10 @@ public final class UnknownRecord extends StandardRecord {
case SHEETPROTECTION_0867: return "SHEETPROTECTION";
case 0x086B: return "DATALABEXTCONTENTS";
case 0x086C: return "CELLWATCH";
case FeatRecord.v11_sid: return "SHARED FEATURE v11";
case 0x0874: return "DROPDOWNOBJIDS";
case 0x0876: return "DCONN";
case FeatRecord.v12_sid: return "SHARED FEATURE v12";
case 0x087B: return "CFEX";
case 0x087C: return "XFCRC";
case 0x087D: return "XFEXT";
@ -194,15 +196,21 @@ public final class UnknownRecord extends StandardRecord {
case 0x089A: return "MTRSETTINGS";
case 0x089B: return "COMPRESSPICTURES";
case HEADER_FOOTER_089C: return "HEADERFOOTER";
case 0x089D: return "CRTLAYOUT12";
case 0x089E: return "CRTMLFRT";
case 0x089F: return "CRTMLFRTCONTINUE";
case 0x08A1: return "SHAPEPROPSSTREAM";
case 0x08A3: return "FORCEFULLCALCULATION";
case 0x08A4: return "SHAPEPROPSSTREAM";
case 0x08A5: return "TEXTPROPSSTREAM";
case 0x08A6: return "RICHTEXTSTREAM";
case 0x08A7: return "CRTLAYOUT12A";
case 0x08C8: return "PLV{Mac Excel}";
case 0x1001: return "UNITS";
case 0x1006: return "CHARTDATAFORMAT";
case 0x1007: return "CHARTLINEFORMAT";
}
if (isObservedButUnknown(sid)) {
return "UNKNOWN-" + Integer.toHexString(sid).toUpperCase();
@ -215,6 +223,7 @@ public final class UnknownRecord extends StandardRecord {
* @return <code>true</code> if the unknown record id has been observed in POI unit tests
*/
private static boolean isObservedButUnknown(int sid) {
// TODO Look up more of these in the latest [MS-XLS] doc and move to getBiffName
switch (sid) {
case 0x0033:
// contains 2 bytes of data: 0x0001 or 0x0003
@ -227,13 +236,7 @@ public final class UnknownRecord extends StandardRecord {
// Written by Excel 2007
// rawData is multiple of 12 bytes long
// appears after last cell value record and before WINDOW2 or drawing records
case 0x089D:
case 0x089E:
case 0x08A7:
case 0x1001:
case 0x1006:
case 0x1007:
case 0x1009:
case 0x100A:
case 0x100B:

View File

@ -21,7 +21,11 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.CFHeader12Record;
import org.apache.poi.hssf.record.CFHeaderBase;
import org.apache.poi.hssf.record.CFHeaderRecord;
import org.apache.poi.hssf.record.CFRule12Record;
import org.apache.poi.hssf.record.CFRuleBase;
import org.apache.poi.hssf.record.CFRuleRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.ss.formula.FormulaShifter;
@ -45,12 +49,12 @@ public final class CFRecordsAggregate extends RecordAggregate {
private static final int MAX_97_2003_CONDTIONAL_FORMAT_RULES = 3;
private static final POILogger logger = POILogFactory.getLogger(CFRecordsAggregate.class);
private final CFHeaderRecord header;
private final CFHeaderBase header;
/** List of CFRuleRecord objects */
private final List<CFRuleRecord> rules;
private final List<CFRuleBase> rules;
private CFRecordsAggregate(CFHeaderRecord pHeader, CFRuleRecord[] pRules) {
private CFRecordsAggregate(CFHeaderBase pHeader, CFRuleBase[] pRules) {
if(pHeader == null) {
throw new IllegalArgumentException("header must not be null");
}
@ -67,14 +71,21 @@ public final class CFRecordsAggregate extends RecordAggregate {
throw new RuntimeException("Mismatch number of rules");
}
header = pHeader;
rules = new ArrayList<CFRuleRecord>(3);
rules = new ArrayList<CFRuleBase>(pRules.length);
for (int i = 0; i < pRules.length; i++) {
checkRuleType(pRules[i]);
rules.add(pRules[i]);
}
}
public CFRecordsAggregate(CellRangeAddress[] regions, CFRuleRecord[] rules) {
this(new CFHeaderRecord(regions, rules.length), rules);
public CFRecordsAggregate(CellRangeAddress[] regions, CFRuleBase[] rules) {
this(createHeader(regions, rules), rules);
}
private static CFHeaderBase createHeader(CellRangeAddress[] regions, CFRuleBase[] rules) {
if (rules.length == 0 || rules[0] instanceof CFRuleRecord) {
return new CFHeaderRecord(regions, rules.length);
}
return new CFHeader12Record(regions, rules.length);
}
/**
@ -84,17 +95,19 @@ public final class CFRecordsAggregate extends RecordAggregate {
*/
public static CFRecordsAggregate createCFAggregate(RecordStream rs) {
Record rec = rs.getNext();
if (rec.getSid() != CFHeaderRecord.sid) {
if (rec.getSid() != CFHeaderRecord.sid &&
rec.getSid() != CFHeader12Record.sid) {
throw new IllegalStateException("next record sid was " + rec.getSid()
+ " instead of " + CFHeaderRecord.sid + " as expected");
+ " instead of " + CFHeaderRecord.sid + " or " +
CFHeader12Record.sid + " as expected");
}
CFHeaderRecord header = (CFHeaderRecord)rec;
CFHeaderBase header = (CFHeaderBase)rec;
int nRules = header.getNumberOfConditionalFormats();
CFRuleRecord[] rules = new CFRuleRecord[nRules];
CFRuleBase[] rules = new CFRuleBase[nRules];
for (int i = 0; i < rules.length; i++) {
rules[i] = (CFRuleRecord) rs.getNext();
rules[i] = (CFRuleBase) rs.getNext();
}
return new CFRecordsAggregate(header, rules);
@ -103,21 +116,18 @@ public final class CFRecordsAggregate extends RecordAggregate {
/**
* Create a deep clone of the record
*/
public CFRecordsAggregate cloneCFAggregate()
{
CFRuleRecord[] newRecs = new CFRuleRecord[rules.size()];
public CFRecordsAggregate cloneCFAggregate() {
CFRuleBase[] newRecs = new CFRuleBase[rules.size()];
for (int i = 0; i < newRecs.length; i++) {
newRecs[i] = (CFRuleRecord) getRule(i).clone();
}
return new CFRecordsAggregate((CFHeaderRecord) header.clone(), newRecs);
return new CFRecordsAggregate((CFHeaderBase)header.clone(), newRecs);
}
/**
* @return the header. Never <code>null</code>.
*/
public CFHeaderRecord getHeader()
{
public CFHeaderBase getHeader() {
return header;
}
@ -127,18 +137,31 @@ public final class CFRecordsAggregate extends RecordAggregate {
+ ") nRules=" + rules.size());
}
}
public CFRuleRecord getRule(int idx) {
private void checkRuleType(CFRuleBase r) {
if (header instanceof CFHeaderRecord &&
r instanceof CFRuleRecord) {
return;
}
if (header instanceof CFHeader12Record &&
r instanceof CFRule12Record) {
return;
}
throw new IllegalArgumentException("Header and Rule must both be CF or both be CF12, can't mix");
}
public CFRuleBase getRule(int idx) {
checkRuleIndex(idx);
return rules.get(idx);
}
public void setRule(int idx, CFRuleRecord r) {
public void setRule(int idx, CFRuleBase r) {
if (r == null) {
throw new IllegalArgumentException("r must not be null");
}
checkRuleIndex(idx);
checkRuleType(r);
rules.set(idx, r);
}
public void addRule(CFRuleRecord r) {
public void addRule(CFRuleBase r) {
if (r == null) {
throw new IllegalArgumentException("r must not be null");
}
@ -147,6 +170,7 @@ public final class CFRecordsAggregate extends RecordAggregate {
+ " any more than " + MAX_97_2003_CONDTIONAL_FORMAT_RULES
+ " - this file will cause problems with old Excel versions");
}
checkRuleType(r);
rules.add(r);
header.setNumberOfConditionalFormats(rules.size());
}
@ -157,28 +181,29 @@ public final class CFRecordsAggregate extends RecordAggregate {
/**
* String representation of CFRecordsAggregate
*/
public String toString()
{
public String toString() {
StringBuffer buffer = new StringBuffer();
String type = "CF";
if (header instanceof CFHeader12Record) {
type = "CF12";
}
buffer.append("[CF]\n");
if( header != null )
{
buffer.append("[").append(type).append("]\n");
if( header != null ) {
buffer.append(header.toString());
}
for(int i=0; i<rules.size(); i++)
{
CFRuleRecord cfRule = rules.get(i);
for(int i=0; i<rules.size(); i++) {
CFRuleBase cfRule = rules.get(i);
buffer.append(cfRule.toString());
}
buffer.append("[/CF]\n");
buffer.append("[/").append(type).append("]\n");
return buffer.toString();
}
public void visitContainedRecords(RecordVisitor rv) {
rv.visitRecord(header);
for(int i=0; i<rules.size(); i++) {
CFRuleRecord rule = rules.get(i);
CFRuleBase rule = rules.get(i);
rv.visitRecord(rule);
}
}
@ -214,7 +239,7 @@ public final class CFRecordsAggregate extends RecordAggregate {
}
for(int i=0; i<rules.size(); i++) {
CFRuleRecord rule = rules.get(i);
CFRuleBase rule = rules.get(i);
Ptg[] ptgs;
ptgs = rule.getParsedExpression1();
if (ptgs != null && shifter.adjustFormula(ptgs, currentExternSheetIx)) {
@ -224,6 +249,13 @@ public final class CFRecordsAggregate extends RecordAggregate {
if (ptgs != null && shifter.adjustFormula(ptgs, currentExternSheetIx)) {
rule.setParsedExpression2(ptgs);
}
if (rule instanceof CFRule12Record) {
CFRule12Record rule12 = (CFRule12Record)rule;
ptgs = rule12.getParsedExpressionScale();
if (ptgs != null && shifter.adjustFormula(ptgs, currentExternSheetIx)) {
rule12.setParsedExpressionScale(ptgs);
}
}
}
return true;
}

View File

@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.CFHeader12Record;
import org.apache.poi.hssf.record.CFHeaderRecord;
import org.apache.poi.ss.formula.FormulaShifter;
@ -28,11 +29,8 @@ import org.apache.poi.ss.formula.FormulaShifter;
* Holds all the conditional formatting for a workbook sheet.<p/>
*
* See OOO exelfileformat.pdf sec 4.12 'Conditional Formatting Table'
*
* @author Josh Micich
*/
public final class ConditionalFormattingTable extends RecordAggregate {
private final List<CFRecordsAggregate> _cfHeaders;
/**
@ -45,7 +43,8 @@ public final class ConditionalFormattingTable extends RecordAggregate {
public ConditionalFormattingTable(RecordStream rs) {
List<CFRecordsAggregate> temp = new ArrayList<CFRecordsAggregate>();
while (rs.peekNextClass() == CFHeaderRecord.class) {
while (rs.peekNextClass() == CFHeaderRecord.class ||
rs.peekNextClass() == CFHeader12Record.class) {
temp.add(CFRecordsAggregate.createCFAggregate(rs));
}
_cfHeaders = temp;
@ -62,6 +61,7 @@ public final class ConditionalFormattingTable extends RecordAggregate {
* @return index of the newly added CF header aggregate
*/
public int add(CFRecordsAggregate cfAggregate) {
cfAggregate.getHeader().setID(_cfHeaders.size());
_cfHeaders.add(cfAggregate);
return _cfHeaders.size() - 1;
}

View File

@ -25,11 +25,8 @@ import org.apache.poi.util.LittleEndianOutput;
/**
* Border Formatting Block of the Conditional Formatting Rule Record.
*
* @author Dmitriy Kumshayev
*/
public final class BorderFormatting {
/** No border */
public final static short BORDER_NONE = 0x0;
/** Thin border */
@ -89,6 +86,9 @@ public final class BorderFormatting {
field_14_border_styles2 = in.readInt();
}
public int getDataLength() {
return 8;
}
/**
* set the type of border to use for the left border of the cell

View File

@ -23,12 +23,9 @@ import java.util.List;
import org.apache.poi.ss.util.CellRangeAddress;
/**
*
* @author Dmitriy Kumshayev
* TODO Should this move to org.apache.poi.ss.util ?
*/
public final class CellRangeUtil
{
public final class CellRangeUtil {
private CellRangeUtil() {
// no instance of this class
}
@ -81,7 +78,6 @@ public final class CellRangeUtil
{
return OVERLAP;
}
}
/**
@ -171,15 +167,12 @@ public final class CellRangeUtil
throw new RuntimeException("unexpected intersection result (" + x + ")");
}
private static CellRangeAddress[] toArray(List<CellRangeAddress> temp) {
CellRangeAddress[] result = new CellRangeAddress[temp.size()];
temp.toArray(result);
return result;
}
/**
* Check if the specified range is located inside of this cell range.
*
@ -234,14 +227,12 @@ public final class CellRangeUtil
return crA.copy();
}
return
new CellRangeAddress(
return new CellRangeAddress(
lt(crB.getFirstRow(), crA.getFirstRow()) ?crB.getFirstRow() :crA.getFirstRow(),
gt(crB.getLastRow(), crA.getLastRow()) ?crB.getLastRow() :crA.getLastRow(),
lt(crB.getFirstColumn(),crA.getFirstColumn())?crB.getFirstColumn():crA.getFirstColumn(),
gt(crB.getLastColumn(), crA.getLastColumn()) ?crB.getLastColumn() :crA.getLastColumn()
);
}
/**

View File

@ -25,11 +25,8 @@ import org.apache.poi.util.LittleEndian;
/**
* Font Formatting Block of the Conditional Formatting Rule Record.
*
* @author Dmitriy Kumshayev
*/
public final class FontFormatting
{
public final class FontFormatting {
private byte[] _rawData;
private static final int OFFSET_FONT_NAME = 0;
@ -150,6 +147,10 @@ public final class FontFormatting
return _rawData;
}
public int getDataLength() {
return RAW_DATA_SIZE;
}
/**
* sets the height of the font in 1/20th point units
*
@ -234,7 +235,6 @@ public final class FontFormatting
*
* @param strike - whether the font is stricken out or not
*/
public void setStrikeout(boolean strike)
{
setFontOption(strike, cancellation);
@ -246,7 +246,6 @@ public final class FontFormatting
* @return strike - whether the font is stricken out or not
* @see #getFontOption(org.apache.poi.util.BitField)
*/
public boolean isStruckout()
{
return getFontOption(cancellation);
@ -337,7 +336,6 @@ public final class FontFormatting
* @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#U_SINGLE_ACCOUNTING
* @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#U_DOUBLE_ACCOUNTING
*/
public short getUnderlineType()
{
return getShort(OFFSET_UNDERLINE_TYPE);
@ -370,8 +368,7 @@ public final class FontFormatting
setInt(OFFSET_FONT_COLOR_INDEX,fci);
}
private boolean getOptionFlag(BitField field)
{
private boolean getOptionFlag(BitField field) {
int optionFlags = getInt(OFFSET_OPTION_FLAGS);
int value = field.getValue(optionFlags);
return value==0? true : false ;
@ -510,7 +507,8 @@ public final class FontFormatting
append(getFontWeight()).
append(
getFontWeight() == FONT_WEIGHT_NORMAL ? "(Normal)"
: getFontWeight() == FONT_WEIGHT_BOLD ? "(Bold)" : "0x"+Integer.toHexString(getFontWeight())).
: getFontWeight() == FONT_WEIGHT_BOLD ? "(Bold)"
: "0x"+Integer.toHexString(getFontWeight())).
append("\n");
}
else

View File

@ -0,0 +1,139 @@
/* ====================================================================
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.cf;
import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
/**
* Icon / Multi-State Conditional Formatting Rule Record.
*/
public final class IconMultiStateFormatting implements Cloneable {
private static POILogger log = POILogFactory.getLogger(IconMultiStateFormatting.class);
private IconSet iconSet;
private byte options;
private Threshold[] thresholds;
private static BitField iconOnly = BitFieldFactory.getInstance(0x01);
private static BitField reversed = BitFieldFactory.getInstance(0x04);
public IconMultiStateFormatting() {
iconSet = IconSet.GYR_3_TRAFFIC_LIGHTS;
options = 0;
thresholds = new Threshold[iconSet.num];
}
public IconMultiStateFormatting(LittleEndianInput in) {
in.readShort(); // Ignored
in.readByte(); // Reserved
int num = in.readByte();
int set = in.readByte();
iconSet = IconSet.byId(set);
if (iconSet.num != num) {
log.log(POILogger.WARN, "Inconsistent Icon Set defintion, found " + iconSet + " but defined as " + num + " entries");
}
options = in.readByte();
thresholds = new Threshold[iconSet.num];
for (int i=0; i<thresholds.length; i++) {
thresholds[i] = new Threshold(in);
}
}
public IconSet getIconSet() {
return iconSet;
}
public void setIconSet(IconSet set) {
this.iconSet = set;
}
public Threshold[] getThresholds() {
return thresholds;
}
public void setThresholds(Threshold[] thresholds) {
this.thresholds = thresholds;
}
public boolean isIconOnly() {
return getOptionFlag(iconOnly);
}
public void setIconOnly(boolean only) {
setOptionFlag(only, iconOnly);
}
public boolean isReversed() {
return getOptionFlag(reversed);
}
public void setReversed(boolean rev) {
setOptionFlag(rev, reversed);
}
private boolean getOptionFlag(BitField field) {
int value = field.getValue(options);
return value==0 ? false : true;
}
private void setOptionFlag(boolean option, BitField field) {
options = field.setByteBoolean(options, option);
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(" [Icon Formatting]\n");
buffer.append(" .icon_set = ").append(iconSet).append("\n");
buffer.append(" .icon_only= ").append(isIconOnly()).append("\n");
buffer.append(" .reversed = ").append(isReversed()).append("\n");
for (Threshold t : thresholds) {
buffer.append(t.toString());
}
buffer.append(" [/Icon Formatting]\n");
return buffer.toString();
}
public Object clone() {
IconMultiStateFormatting rec = new IconMultiStateFormatting();
rec.iconSet = iconSet;
rec.options = options;
rec.thresholds = new Threshold[thresholds.length];
System.arraycopy(thresholds, 0, rec.thresholds, 0, thresholds.length);
return rec;
}
public int getDataLength() {
int len = 6;
for (Threshold t : thresholds) {
len += t.getDataLength();
}
return len;
}
public void serialize(LittleEndianOutput out) {
out.writeShort(0);
out.writeByte(0);
out.writeByte(iconSet.num);
out.writeByte(iconSet.id);
out.writeByte(options);
for (Threshold t : thresholds) {
t.serialize(out);
}
}
}

View File

@ -24,8 +24,6 @@ import org.apache.poi.util.LittleEndianOutput;
/**
* Pattern Formatting Block of the Conditional Formatting Rule Record.
*
* @author Dmitriy Kumshayev
*/
public final class PatternFormatting implements Cloneable {
/** No background */
@ -89,6 +87,10 @@ public final class PatternFormatting implements Cloneable {
field_16_pattern_color_indexes = in.readUShort();
}
public int getDataLength() {
return 4;
}
/**
* setting fill pattern
*

View File

@ -0,0 +1,146 @@
/* ====================================================================
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.cf;
import java.util.Arrays;
import org.apache.poi.ss.formula.Formula;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.ConditionalFormattingThreshold.RangeType;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
/**
* Threshold / value for changes in Conditional Formatting
*/
public final class Threshold {
/**
* Cell values that are equal to the threshold value do not pass the threshold
*/
public static final byte EQUALS_EXCLUDE = 0;
/**
* Cell values that are equal to the threshold value pass the threshold.
*/
public static final byte EQUALS_INCLUDE = 1;
private byte type;
private Formula formula;
private Double value;
private byte equals;
public Threshold() {
type = (byte)RangeType.NUMBER.id;
formula = Formula.create(null);
value = 0d;
}
/** Creates new Threshold */
public Threshold(LittleEndianInput in) {
type = in.readByte();
short formulaLen = in.readShort();
if (formulaLen > 0) {
formula = Formula.read(formulaLen, in);
} else {
formula = Formula.create(null);
}
// Value is only there for non-formula, non min/max thresholds
if (formulaLen == 0 && type != RangeType.MIN.id &&
type != RangeType.MAX.id) {
value = in.readDouble();
}
equals = in.readByte();
// Reserved, 4 bytes, all 0
in.readInt();
}
public byte getType() {
return type;
}
public void setType(byte type) {
this.type = type;
}
public void setType(int type) {
this.type = (byte)type;
}
protected Formula getFormula() {
return formula;
}
public Ptg[] getParsedExpression() {
return formula.getTokens();
}
public void setParsedExpression(Ptg[] ptgs) {
formula = Formula.create(ptgs);
}
public Double getValue() {
return value;
}
public void setValue(Double value) {
this.value = value;
}
public byte getEquals() {
return equals;
}
public void setEquals(byte equals) {
this.equals = equals;
}
public int getDataLength() {
int len = 1 + formula.getEncodedSize();
if (value != null) {
len += 8;
}
len += 5;
return len;
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(" [CF Threshold]\n");
buffer.append(" .type = ").append(Integer.toHexString(type)).append("\n");
buffer.append(" .formula = ").append(Arrays.toString(formula.getTokens())).append("\n");
buffer.append(" .value = ").append(value).append("\n");
buffer.append(" [/CF Threshold]\n");
return buffer.toString();
}
public Object clone() {
Threshold rec = new Threshold();
rec.type = type;
rec.formula = formula;
rec.value = value;
rec.equals = equals;
return rec;
}
public void serialize(LittleEndianOutput out) {
out.writeByte(type);
if (formula.getTokens().length == 0) {
out.writeShort(0);
} else {
formula.serialize(out);
}
if (value != null) {
out.writeDouble(value);
}
out.writeByte(equals);
out.writeInt(0); // Reserved
}
}

View File

@ -18,6 +18,7 @@
package org.apache.poi.hssf.record.common;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.LittleEndianOutput;
/**
@ -32,19 +33,18 @@ public final class FtrHeader {
private short recordType;
/** This is a FrtFlags */
private short grbitFrt;
/** MUST be 8 bytes and all zero */
private byte[] reserved;
/** The range of cells the parent record applies to, or 0 if N/A */
private CellRangeAddress associatedRange;
public FtrHeader() {
reserved = new byte[8];
associatedRange = new CellRangeAddress(0, 0, 0, 0);
}
public FtrHeader(RecordInputStream in) {
recordType = in.readShort();
grbitFrt = in.readShort();
reserved = new byte[8];
in.read(reserved, 0, 8);
associatedRange = new CellRangeAddress(in);
}
public String toString() {
@ -59,7 +59,7 @@ public final class FtrHeader {
public void serialize(LittleEndianOutput out) {
out.writeShort(recordType);
out.writeShort(grbitFrt);
out.write(reserved);
associatedRange.serialize(out);
}
public static int getDataSize() {
@ -80,10 +80,18 @@ public final class FtrHeader {
this.grbitFrt = grbitFrt;
}
public byte[] getReserved() {
return reserved;
public CellRangeAddress getAssociatedRange() {
return associatedRange;
}
public void setReserved(byte[] reserved) {
this.reserved = reserved;
public void setAssociatedRange(CellRangeAddress associatedRange) {
this.associatedRange = associatedRange;
}
public Object clone() {
FtrHeader result = new FtrHeader();
result.recordType = recordType;
result.grbitFrt = grbitFrt;
result.associatedRange = associatedRange.copy();
return result;
}
}

View File

@ -0,0 +1,30 @@
/* ====================================================================
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.common;
import org.apache.poi.ss.util.CellRangeAddress;
/**
* Title: Future Record, a newer (largely Excel 2007+) record
* which contains a Future Record Header ({@link FtrHeader})
*/
public interface FutureRecord {
public short getFutureRecordType();
public FtrHeader getFutureHeader();
public CellRangeAddress getAssociatedRange();
}

View File

@ -95,7 +95,7 @@ public final class Biff8DecryptingStream implements BiffHeaderInput, LittleEndia
public int readUByte() {
return _cipher.xorByte(_le.readUByte());
return readByte() & 0xFF;
}
public byte readByte() {
return (byte) _cipher.xorByte(_le.readUByte());
@ -103,7 +103,7 @@ public final class Biff8DecryptingStream implements BiffHeaderInput, LittleEndia
public int readUShort() {
return _cipher.xorShort(_le.readUShort());
return readShort() & 0xFFFF;
}
public short readShort() {
return (short) _cipher.xorShort(_le.readUShort());

View File

@ -17,196 +17,246 @@
package org.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.record.CFRuleRecord;
import org.apache.poi.hssf.record.CFRuleBase;
import org.apache.poi.hssf.record.cf.BorderFormatting;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Color;
/**
* High level representation for Border Formatting component
* of Conditional Formatting settings
*/
public final class HSSFBorderFormatting implements org.apache.poi.ss.usermodel.BorderFormatting
{
private final CFRuleRecord cfRuleRecord;
public final class HSSFBorderFormatting implements org.apache.poi.ss.usermodel.BorderFormatting {
private final HSSFWorkbook workbook;
private final CFRuleBase cfRuleRecord;
private final BorderFormatting borderFormatting;
protected HSSFBorderFormatting(CFRuleRecord cfRuleRecord)
{
protected HSSFBorderFormatting(CFRuleBase cfRuleRecord, HSSFWorkbook workbook) {
this.workbook = workbook;
this.cfRuleRecord = cfRuleRecord;
this.borderFormatting = cfRuleRecord.getBorderFormatting();
}
protected BorderFormatting getBorderFormattingBlock()
{
protected BorderFormatting getBorderFormattingBlock() {
return borderFormatting;
}
public short getBorderBottom()
{
public short getBorderBottom() {
return (short)borderFormatting.getBorderBottom();
}
public short getBorderDiagonal()
{
public short getBorderDiagonal() {
return (short)borderFormatting.getBorderDiagonal();
}
public short getBorderLeft()
{
public short getBorderLeft() {
return (short)borderFormatting.getBorderLeft();
}
public short getBorderRight()
{
public short getBorderRight() {
return (short)borderFormatting.getBorderRight();
}
public short getBorderTop()
{
public short getBorderTop() {
return (short)borderFormatting.getBorderTop();
}
public short getBottomBorderColor()
{
public short getBottomBorderColor() {
return (short)borderFormatting.getBottomBorderColor();
}
public HSSFColor getBottomBorderColorColor() {
return workbook.getCustomPalette().getColor(
borderFormatting.getBottomBorderColor()
);
}
public short getDiagonalBorderColor()
{
public short getDiagonalBorderColor() {
return (short)borderFormatting.getDiagonalBorderColor();
}
public HSSFColor getDiagonalBorderColorColor() {
return workbook.getCustomPalette().getColor(
borderFormatting.getDiagonalBorderColor()
);
}
public short getLeftBorderColor()
{
public short getLeftBorderColor() {
return (short)borderFormatting.getLeftBorderColor();
}
public HSSFColor getLeftBorderColorColor() {
return workbook.getCustomPalette().getColor(
borderFormatting.getLeftBorderColor()
);
}
public short getRightBorderColor()
{
public short getRightBorderColor() {
return (short)borderFormatting.getRightBorderColor();
}
public HSSFColor getRightBorderColorColor() {
return workbook.getCustomPalette().getColor(
borderFormatting.getRightBorderColor()
);
}
public short getTopBorderColor()
{
public short getTopBorderColor() {
return (short)borderFormatting.getTopBorderColor();
}
public boolean isBackwardDiagonalOn()
{
return borderFormatting.isBackwardDiagonalOn();
public HSSFColor getTopBorderColorColor() {
return workbook.getCustomPalette().getColor(
borderFormatting.getTopBorderColor()
);
}
public boolean isForwardDiagonalOn()
{
public boolean isBackwardDiagonalOn() {
return borderFormatting.isBackwardDiagonalOn();
}
public boolean isForwardDiagonalOn() {
return borderFormatting.isForwardDiagonalOn();
}
public void setBackwardDiagonalOn(boolean on)
{
public void setBackwardDiagonalOn(boolean on) {
borderFormatting.setBackwardDiagonalOn(on);
if( on )
{
if (on) {
cfRuleRecord.setTopLeftBottomRightBorderModified(on);
}
}
public void setBorderBottom(short border)
{
borderFormatting.setBorderBottom(border);
if( border != 0)
{
cfRuleRecord.setBottomBorderModified(true);
}
}
public void setBorderDiagonal(short border)
{
borderFormatting.setBorderDiagonal(border);
if( border != 0)
{
cfRuleRecord.setBottomLeftTopRightBorderModified(true);
cfRuleRecord.setTopLeftBottomRightBorderModified(true);
}
}
public void setBorderLeft(short border)
{
borderFormatting.setBorderLeft(border);
if( border != 0)
{
cfRuleRecord.setLeftBorderModified(true);
}
}
public void setBorderRight(short border)
{
borderFormatting.setBorderRight(border);
if( border != 0)
{
cfRuleRecord.setRightBorderModified(true);
}
}
public void setBorderTop(short border)
{
borderFormatting.setBorderTop(border);
if( border != 0)
{
cfRuleRecord.setTopBorderModified(true);
}
}
public void setBottomBorderColor(short color)
{
borderFormatting.setBottomBorderColor(color);
if( color != 0)
{
cfRuleRecord.setBottomBorderModified(true);
}
}
public void setDiagonalBorderColor(short color)
{
borderFormatting.setDiagonalBorderColor(color);
if( color != 0)
{
cfRuleRecord.setBottomLeftTopRightBorderModified(true);
cfRuleRecord.setTopLeftBottomRightBorderModified(true);
}
}
public void setForwardDiagonalOn(boolean on)
{
public void setForwardDiagonalOn(boolean on) {
borderFormatting.setForwardDiagonalOn(on);
if( on )
{
if (on) {
cfRuleRecord.setBottomLeftTopRightBorderModified(on);
}
}
public void setLeftBorderColor(short color)
{
borderFormatting.setLeftBorderColor(color);
if( color != 0)
{
public void setBorderBottom(short border) {
borderFormatting.setBorderBottom(border);
if (border != 0) {
cfRuleRecord.setBottomBorderModified(true);
} else {
cfRuleRecord.setBottomBorderModified(false);
}
}
public void setBorderDiagonal(short border) {
borderFormatting.setBorderDiagonal(border);
if (border != 0) {
cfRuleRecord.setBottomLeftTopRightBorderModified(true);
cfRuleRecord.setTopLeftBottomRightBorderModified(true);
} else {
cfRuleRecord.setBottomLeftTopRightBorderModified(false);
cfRuleRecord.setTopLeftBottomRightBorderModified(false);
}
}
public void setBorderLeft(short border) {
borderFormatting.setBorderLeft(border);
if (border != 0) {
cfRuleRecord.setLeftBorderModified(true);
} else {
cfRuleRecord.setLeftBorderModified(false);
}
}
public void setRightBorderColor(short color)
{
borderFormatting.setRightBorderColor(color);
if( color != 0)
{
public void setBorderRight(short border) {
borderFormatting.setBorderRight(border);
if (border != 0) {
cfRuleRecord.setRightBorderModified(true);
} else {
cfRuleRecord.setRightBorderModified(false);
}
}
public void setTopBorderColor(short color)
{
borderFormatting.setTopBorderColor(color);
if( color != 0)
{
public void setBorderTop(short border) {
borderFormatting.setBorderTop(border);
if (border != 0) {
cfRuleRecord.setTopBorderModified(true);
} else {
cfRuleRecord.setTopBorderModified(false);
}
}
public void setBottomBorderColor(short color) {
borderFormatting.setBottomBorderColor(color);
if (color != 0) {
cfRuleRecord.setBottomBorderModified(true);
} else {
cfRuleRecord.setBottomBorderModified(false);
}
}
public void setBottomBorderColor(Color color) {
HSSFColor hcolor = HSSFColor.toHSSFColor(color);
if (hcolor == null) {
setBottomBorderColor((short)0);
} else {
setBottomBorderColor(hcolor.getIndex());
}
}
public void setDiagonalBorderColor(short color) {
borderFormatting.setDiagonalBorderColor(color);
if (color != 0) {
cfRuleRecord.setBottomLeftTopRightBorderModified(true);
cfRuleRecord.setTopLeftBottomRightBorderModified(true);
} else {
cfRuleRecord.setBottomLeftTopRightBorderModified(false);
cfRuleRecord.setTopLeftBottomRightBorderModified(false);
}
}
public void setDiagonalBorderColor(Color color) {
HSSFColor hcolor = HSSFColor.toHSSFColor(color);
if (hcolor == null) {
setDiagonalBorderColor((short)0);
} else {
setDiagonalBorderColor(hcolor.getIndex());
}
}
public void setLeftBorderColor(short color) {
borderFormatting.setLeftBorderColor(color);
if (color != 0) {
cfRuleRecord.setLeftBorderModified(true);
} else {
cfRuleRecord.setLeftBorderModified(false);
}
}
public void setLeftBorderColor(Color color) {
HSSFColor hcolor = HSSFColor.toHSSFColor(color);
if (hcolor == null) {
setLeftBorderColor((short)0);
} else {
setLeftBorderColor(hcolor.getIndex());
}
}
public void setRightBorderColor(short color) {
borderFormatting.setRightBorderColor(color);
if (color != 0) {
cfRuleRecord.setRightBorderModified(true);
} else {
cfRuleRecord.setRightBorderModified(false);
}
}
public void setRightBorderColor(Color color) {
HSSFColor hcolor = HSSFColor.toHSSFColor(color);
if (hcolor == null) {
setRightBorderColor((short)0);
} else {
setRightBorderColor(hcolor.getIndex());
}
}
public void setTopBorderColor(short color) {
borderFormatting.setTopBorderColor(color);
if (color != 0) {
cfRuleRecord.setTopBorderModified(true);
} else {
cfRuleRecord.setTopBorderModified(false);
}
}
public void setTopBorderColor(Color color) {
HSSFColor hcolor = HSSFColor.toHSSFColor(color);
if (hcolor == null) {
setTopBorderColor((short)0);
} else {
setTopBorderColor(hcolor.getIndex());
}
}
}

View File

@ -538,18 +538,17 @@ public class HSSFCell implements Cell {
public void setCellValue(RichTextString value)
{
HSSFRichTextString hvalue = (HSSFRichTextString) value;
int row=_record.getRow();
short col=_record.getColumn();
short styleIndex=_record.getXFIndex();
if (hvalue == null)
if (value == null)
{
notifyFormulaChanging();
setCellType(CELL_TYPE_BLANK, false, row, col, styleIndex);
return;
}
if(hvalue.length() > SpreadsheetVersion.EXCEL97.getMaxTextLength()){
if(value.length() > SpreadsheetVersion.EXCEL97.getMaxTextLength()){
throw new IllegalArgumentException("The maximum length of cell contents (text) is 32,767 characters");
}
@ -557,7 +556,7 @@ public class HSSFCell implements Cell {
// Set the 'pre-evaluated result' for the formula
// note - formulas do not preserve text formatting.
FormulaRecordAggregate fr = (FormulaRecordAggregate) _record;
fr.setCachedStringResult(hvalue.getString());
fr.setCachedStringResult(value.getString());
// Update our local cache to the un-formatted version
_stringValue = new HSSFRichTextString(value.getString());
@ -573,6 +572,7 @@ public class HSSFCell implements Cell {
}
int index = 0;
HSSFRichTextString hvalue = (HSSFRichTextString) value;
UnicodeString str = hvalue.getUnicodeString();
index = _book.getWorkbook().addSSTString(str);
(( LabelSSTRecord ) _record).setSSTIndex(index);

View File

@ -129,10 +129,13 @@ public class HSSFComment extends HSSFTextbox implements Comment {
@Override
void setShapeId(int shapeId) {
if(shapeId > 65535) {
throw new IllegalArgumentException("Cannot add more than " + 65535 + " shapes");
}
super.setShapeId(shapeId);
CommonObjectDataSubRecord cod = (CommonObjectDataSubRecord) getObjRecord().getSubRecords().get(0);
cod.setObjectId((short) (shapeId % 1024));
_note.setShapeId(shapeId % 1024);
cod.setObjectId(shapeId);
_note.setShapeId(shapeId);
}
/**

View File

@ -16,7 +16,7 @@
==================================================================== */
package org.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.record.CFRuleRecord;
import org.apache.poi.hssf.record.CFRuleBase;
import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate;
import org.apache.poi.ss.usermodel.ConditionalFormatting;
import org.apache.poi.ss.usermodel.ConditionalFormattingRule;
@ -73,20 +73,18 @@ import org.apache.poi.ss.util.CellRangeAddress;
* sheet.addConditionalFormatting(regions, rule);
* </PRE>
*/
public final class HSSFConditionalFormatting implements ConditionalFormatting
{
private final HSSFWorkbook _workbook;
public final class HSSFConditionalFormatting implements ConditionalFormatting {
private final HSSFSheet sheet;
private final CFRecordsAggregate cfAggregate;
HSSFConditionalFormatting(HSSFWorkbook workbook, CFRecordsAggregate cfAggregate)
{
if(workbook == null) {
throw new IllegalArgumentException("workbook must not be null");
HSSFConditionalFormatting(HSSFSheet sheet, CFRecordsAggregate cfAggregate) {
if(sheet == null) {
throw new IllegalArgumentException("sheet must not be null");
}
if(cfAggregate == null) {
throw new IllegalArgumentException("cfAggregate must not be null");
}
_workbook = workbook;
this.sheet = sheet;
this.cfAggregate = cfAggregate;
}
CFRecordsAggregate getCFRecordsAggregate() {
@ -96,8 +94,7 @@ public final class HSSFConditionalFormatting implements ConditionalFormatting
/**
* @deprecated (Aug-2008) use {@link HSSFConditionalFormatting#getFormattingRanges()}
*/
public org.apache.poi.ss.util.Region[] getFormattingRegions()
{
public org.apache.poi.ss.util.Region[] getFormattingRegions() {
CellRangeAddress[] cellRanges = getFormattingRanges();
return org.apache.poi.ss.util.Region.convertCellRangesToRegions(cellRanges);
}
@ -110,14 +107,14 @@ public final class HSSFConditionalFormatting implements ConditionalFormatting
/**
* Replaces an existing Conditional Formatting rule at position idx.
* Excel allows to create up to 3 Conditional Formatting rules.
* Older versions of Excel only allow up to 3 Conditional Formatting rules,
* and will ignore rules beyond that, while newer versions are fine.
* This method can be useful to modify existing Conditional Formatting rules.
*
* @param idx position of the rule. Should be between 0 and 2.
* @param idx position of the rule. Should be between 0 and 2 for older Excel versions
* @param cfRule - Conditional Formatting rule
*/
public void setRule(int idx, HSSFConditionalFormattingRule cfRule)
{
public void setRule(int idx, HSSFConditionalFormattingRule cfRule) {
cfAggregate.setRule(idx, cfRule.getCfRuleRecord());
}
@ -130,8 +127,7 @@ public final class HSSFConditionalFormatting implements ConditionalFormatting
* Excel allows to create up to 3 Conditional Formatting rules.
* @param cfRule - Conditional Formatting rule
*/
public void addRule(HSSFConditionalFormattingRule cfRule)
{
public void addRule(HSSFConditionalFormattingRule cfRule) {
cfAggregate.addRule(cfRule.getCfRuleRecord());
}
@ -142,22 +138,19 @@ public final class HSSFConditionalFormatting implements ConditionalFormatting
/**
* @return the Conditional Formatting rule at position idx.
*/
public HSSFConditionalFormattingRule getRule(int idx)
{
CFRuleRecord ruleRecord = cfAggregate.getRule(idx);
return new HSSFConditionalFormattingRule(_workbook, ruleRecord);
public HSSFConditionalFormattingRule getRule(int idx) {
CFRuleBase ruleRecord = cfAggregate.getRule(idx);
return new HSSFConditionalFormattingRule(sheet, ruleRecord);
}
/**
* @return number of Conditional Formatting rules.
*/
public int getNumberOfRules()
{
public int getNumberOfRules() {
return cfAggregate.getNumberOfRules();
}
public String toString()
{
public String toString() {
return cfAggregate.toString();
}
}

View File

@ -18,12 +18,16 @@
package org.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.CFRule12Record;
import org.apache.poi.hssf.record.CFRuleBase;
import org.apache.poi.hssf.record.CFRuleBase.ComparisonOperator;
import org.apache.poi.hssf.record.CFRuleRecord;
import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
import org.apache.poi.hssf.record.cf.BorderFormatting;
import org.apache.poi.hssf.record.cf.FontFormatting;
import org.apache.poi.hssf.record.cf.IconMultiStateFormatting;
import org.apache.poi.hssf.record.cf.PatternFormatting;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.ConditionType;
import org.apache.poi.ss.usermodel.ConditionalFormattingRule;
/**
@ -32,25 +36,26 @@ import org.apache.poi.ss.usermodel.ConditionalFormattingRule;
* It allows to specify formula based conditions for the Conditional Formatting
* and the formatting settings such as font, border and pattern.
*/
public final class HSSFConditionalFormattingRule implements ConditionalFormattingRule
{
public final class HSSFConditionalFormattingRule implements ConditionalFormattingRule {
private static final byte CELL_COMPARISON = CFRuleRecord.CONDITION_TYPE_CELL_VALUE_IS;
private final CFRuleRecord cfRuleRecord;
private final CFRuleBase cfRuleRecord;
private final HSSFWorkbook workbook;
private final HSSFSheet sheet;
HSSFConditionalFormattingRule(HSSFWorkbook pWorkbook, CFRuleRecord pRuleRecord) {
if (pWorkbook == null) {
throw new IllegalArgumentException("pWorkbook must not be null");
HSSFConditionalFormattingRule(HSSFSheet pSheet, CFRuleBase pRuleRecord) {
if (pSheet == null) {
throw new IllegalArgumentException("pSheet must not be null");
}
if (pRuleRecord == null) {
throw new IllegalArgumentException("pRuleRecord must not be null");
}
workbook = pWorkbook;
sheet = pSheet;
workbook = pSheet.getWorkbook();
cfRuleRecord = pRuleRecord;
}
CFRuleRecord getCfRuleRecord()
CFRuleBase getCfRuleRecord()
{
return cfRuleRecord;
}
@ -61,13 +66,13 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
if ( fontFormatting != null)
{
cfRuleRecord.setFontFormatting(fontFormatting);
return new HSSFFontFormatting(cfRuleRecord);
return new HSSFFontFormatting(cfRuleRecord, workbook);
}
else if( create )
{
fontFormatting = new FontFormatting();
cfRuleRecord.setFontFormatting(fontFormatting);
return new HSSFFontFormatting(cfRuleRecord);
return new HSSFFontFormatting(cfRuleRecord, workbook);
}
else
{
@ -98,13 +103,13 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
if ( borderFormatting != null)
{
cfRuleRecord.setBorderFormatting(borderFormatting);
return new HSSFBorderFormatting(cfRuleRecord);
return new HSSFBorderFormatting(cfRuleRecord, workbook);
}
else if( create )
{
borderFormatting = new BorderFormatting();
cfRuleRecord.setBorderFormatting(borderFormatting);
return new HSSFBorderFormatting(cfRuleRecord);
return new HSSFBorderFormatting(cfRuleRecord, workbook);
}
else
{
@ -134,13 +139,13 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
if ( patternFormatting != null)
{
cfRuleRecord.setPatternFormatting(patternFormatting);
return new HSSFPatternFormatting(cfRuleRecord);
return new HSSFPatternFormatting(cfRuleRecord, workbook);
}
else if( create )
{
patternFormatting = new PatternFormatting();
cfRuleRecord.setPatternFormatting(patternFormatting);
return new HSSFPatternFormatting(cfRuleRecord);
return new HSSFPatternFormatting(cfRuleRecord, workbook);
}
else
{
@ -165,12 +170,57 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
return getPatternFormatting(true);
}
private HSSFIconMultiStateFormatting getMultiStateFormatting(boolean create) {
if (cfRuleRecord instanceof CFRule12Record) {
// Good
} else {
if (create) throw new IllegalArgumentException("Can't convert a CF into a CF12 record");
return null;
}
CFRule12Record cfRule12Record = (CFRule12Record)cfRuleRecord;
IconMultiStateFormatting iconFormatting = cfRule12Record.getMultiStateFormatting();
if (iconFormatting != null)
{
return new HSSFIconMultiStateFormatting(cfRule12Record, sheet);
}
else if( create )
{
iconFormatting = cfRule12Record.createMultiStateFormatting();
return new HSSFIconMultiStateFormatting(cfRule12Record, sheet);
}
else
{
return null;
}
}
/**
* @return icon / multi-state formatting object if defined, <code>null</code> otherwise
*/
public HSSFIconMultiStateFormatting getMultiStateFormatting() {
return getMultiStateFormatting(false);
}
/**
* create a new icon / multi-state formatting object if it does not exist,
* otherwise just return the existing object.
*/
public HSSFIconMultiStateFormatting createMultiStateFormatting() {
return getMultiStateFormatting(true);
}
/**
* @return - the conditiontype for the cfrule
*/
public byte getConditionType() {
return cfRuleRecord.getConditionType();
}
/**
* @return - the conditiontype for the cfrule
*/
public ConditionType getConditionTypeType() {
return ConditionType.forId(getConditionType());
}
/**
* @return - the comparisionoperatation for the cfrule
@ -184,13 +234,11 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
return toFormulaString(cfRuleRecord.getParsedExpression1());
}
public String getFormula2()
{
public String getFormula2() {
byte conditionType = cfRuleRecord.getConditionType();
if (conditionType == CELL_COMPARISON) {
byte comparisonOperation = cfRuleRecord.getComparisonOperation();
switch(comparisonOperation)
{
switch(comparisonOperation) {
case ComparisonOperator.BETWEEN:
case ComparisonOperator.NOT_BETWEEN:
return toFormulaString(cfRuleRecord.getParsedExpression2());
@ -199,9 +247,11 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
return null;
}
private String toFormulaString(Ptg[] parsedExpression)
{
if(parsedExpression ==null) {
protected String toFormulaString(Ptg[] parsedExpression) {
return toFormulaString(parsedExpression, workbook);
}
protected static String toFormulaString(Ptg[] parsedExpression, HSSFWorkbook workbook) {
if(parsedExpression == null || parsedExpression.length == 0) {
return null;
}
return HSSFFormulaParser.toFormulaString(workbook, parsedExpression);

View File

@ -0,0 +1,63 @@
/* ====================================================================
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 static org.apache.poi.hssf.record.CFRuleBase.parseFormula;
import static org.apache.poi.hssf.usermodel.HSSFConditionalFormattingRule.toFormulaString;
import org.apache.poi.hssf.record.cf.Threshold;
/**
* High level representation for Icon / Multi-State / Databar /
* Colour Scale change thresholds
*/
public final class HSSFConditionalFormattingThreshold implements org.apache.poi.ss.usermodel.ConditionalFormattingThreshold {
private final Threshold threshold;
private final HSSFSheet sheet;
private final HSSFWorkbook workbook;
protected HSSFConditionalFormattingThreshold(Threshold threshold, HSSFSheet sheet) {
this.threshold = threshold;
this.sheet = sheet;
this.workbook = sheet.getWorkbook();
}
protected Threshold getThreshold() {
return threshold;
}
public RangeType getRangeType() {
return RangeType.byId(threshold.getType());
}
public void setRangeType(RangeType type) {
threshold.setType((byte)type.id);
}
public String getFormula() {
return toFormulaString(threshold.getParsedExpression(), workbook);
}
public void setFormula(String formula) {
threshold.setParsedExpression(parseFormula(formula, sheet));
}
public Double getValue() {
return threshold.getValue();
}
public void setValue(Double value) {
threshold.setValue(value);
}
}

View File

@ -17,15 +17,15 @@
package org.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.record.CFRuleRecord;
import org.apache.poi.hssf.record.CFRuleBase;
import org.apache.poi.hssf.record.cf.FontFormatting;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Color;
/**
* High level representation for Font Formatting component
* of Conditional Formatting settings
*/
public final class HSSFFontFormatting implements org.apache.poi.ss.usermodel.FontFormatting
{
public final class HSSFFontFormatting implements org.apache.poi.ss.usermodel.FontFormatting {
/** Underline type - None */
public final static byte U_NONE = FontFormatting.U_NONE;
/** Underline type - Single */
@ -38,14 +38,14 @@ public final class HSSFFontFormatting implements org.apache.poi.ss.usermodel.Fon
public final static byte U_DOUBLE_ACCOUNTING = FontFormatting.U_DOUBLE_ACCOUNTING;
private final FontFormatting fontFormatting;
private final HSSFWorkbook workbook;
protected HSSFFontFormatting(CFRuleRecord cfRuleRecord)
{
protected HSSFFontFormatting(CFRuleBase cfRuleRecord, HSSFWorkbook workbook) {
this.fontFormatting = cfRuleRecord.getFontFormatting();
this.workbook = workbook;
}
protected FontFormatting getFontFormattingBlock()
{
protected FontFormatting getFontFormattingBlock() {
return fontFormatting;
}
@ -70,13 +70,27 @@ public final class HSSFFontFormatting implements org.apache.poi.ss.usermodel.Fon
return fontFormatting.getFontColorIndex();
}
public HSSFColor getFontColor() {
return workbook.getCustomPalette().getColor(
getFontColorIndex()
);
}
public void setFontColor(Color color) {
HSSFColor hcolor = HSSFColor.toHSSFColor(color);
if (hcolor == null) {
fontFormatting.setFontColorIndex((short)0);
} else {
fontFormatting.setFontColorIndex(hcolor.getIndex());
}
}
/**
* gets the height of the font in 1/20th point units
*
* @return fontheight (in points/20); or -1 if not modified
*/
public int getFontHeight()
{
public int getFontHeight() {
return fontFormatting.getFontHeight();
}
@ -86,17 +100,14 @@ public final class HSSFFontFormatting implements org.apache.poi.ss.usermodel.Fon
*
* @return bw - a number between 100-1000 for the fonts "boldness"
*/
public short getFontWeight()
{
public short getFontWeight() {
return fontFormatting.getFontWeight();
}
/**
* @see org.apache.poi.hssf.record.cf.FontFormatting#getRawRecord()
*/
protected byte[] getRawRecord()
{
protected byte[] getRawRecord() {
return fontFormatting.getRawRecord();
}
@ -246,10 +257,8 @@ public final class HSSFFontFormatting implements org.apache.poi.ss.usermodel.Fon
* @see #SS_SUPER
* @see #SS_SUB
*/
public void setEscapementType(short escapementType)
{
switch(escapementType)
{
public void setEscapementType(short escapementType) {
switch(escapementType) {
case HSSFFontFormatting.SS_SUB:
case HSSFFontFormatting.SS_SUPER:
fontFormatting.setEscapementType(escapementType);
@ -267,8 +276,7 @@ public final class HSSFFontFormatting implements org.apache.poi.ss.usermodel.Fon
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setEscapementTypeModified(boolean)
*/
public void setEscapementTypeModified(boolean modified)
{
public void setEscapementTypeModified(boolean modified) {
fontFormatting.setEscapementTypeModified(modified);
}
@ -367,10 +375,8 @@ public final class HSSFFontFormatting implements org.apache.poi.ss.usermodel.Fon
* @see #U_SINGLE_ACCOUNTING
* @see #U_DOUBLE_ACCOUNTING
*/
public void setUnderlineType(short underlineType)
{
switch(underlineType)
{
public void setUnderlineType(short underlineType) {
switch(underlineType) {
case HSSFFontFormatting.U_SINGLE:
case HSSFFontFormatting.U_DOUBLE:
case HSSFFontFormatting.U_SINGLE_ACCOUNTING:

View File

@ -0,0 +1,81 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.record.CFRule12Record;
import org.apache.poi.hssf.record.cf.IconMultiStateFormatting;
import org.apache.poi.hssf.record.cf.Threshold;
import org.apache.poi.ss.usermodel.ConditionalFormattingThreshold;
/**
* High level representation for Icon / Multi-State Formatting
* component of Conditional Formatting settings
*/
public final class HSSFIconMultiStateFormatting implements org.apache.poi.ss.usermodel.IconMultiStateFormatting {
private final HSSFSheet sheet;
private final CFRule12Record cfRule12Record;
private final IconMultiStateFormatting iconFormatting;
protected HSSFIconMultiStateFormatting(CFRule12Record cfRule12Record, HSSFSheet sheet) {
this.sheet = sheet;
this.cfRule12Record = cfRule12Record;
this.iconFormatting = this.cfRule12Record.getMultiStateFormatting();
}
public IconSet getIconSet() {
return iconFormatting.getIconSet();
}
public void setIconSet(IconSet set) {
iconFormatting.setIconSet(set);
}
public boolean isIconOnly() {
return iconFormatting.isIconOnly();
}
public void setIconOnly(boolean only) {
iconFormatting.setIconOnly(only);
}
public boolean isReversed() {
return iconFormatting.isReversed();
}
public void setReversed(boolean reversed) {
iconFormatting.setReversed(reversed);
}
public HSSFConditionalFormattingThreshold[] getThresholds() {
Threshold[] t = iconFormatting.getThresholds();
HSSFConditionalFormattingThreshold[] ht = new HSSFConditionalFormattingThreshold[t.length];
for (int i=0; i<t.length; i++) {
ht[i] = new HSSFConditionalFormattingThreshold(t[i], sheet);
}
return ht;
}
public void setThresholds(ConditionalFormattingThreshold[] thresholds) {
Threshold[] t = new Threshold[thresholds.length];
for (int i=0; i<t.length; i++) {
t[i] = ((HSSFConditionalFormattingThreshold)thresholds[i]).getThreshold();
}
iconFormatting.setThresholds(t);
}
public HSSFConditionalFormattingThreshold createThreshold() {
return new HSSFConditionalFormattingThreshold(new Threshold(), sheet);
}
}

View File

@ -45,7 +45,6 @@ import org.apache.poi.hssf.record.ObjRecord;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Chart;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Drawing;

View File

@ -17,19 +17,21 @@
package org.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.record.CFRuleRecord;
import org.apache.poi.hssf.record.CFRuleBase;
import org.apache.poi.hssf.record.cf.PatternFormatting;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Color;
/**
* High level representation for Conditional Formatting settings
*/
public class HSSFPatternFormatting implements org.apache.poi.ss.usermodel.PatternFormatting
{
private final CFRuleRecord cfRuleRecord;
public class HSSFPatternFormatting implements org.apache.poi.ss.usermodel.PatternFormatting {
private final HSSFWorkbook workbook;
private final CFRuleBase cfRuleRecord;
private final PatternFormatting patternFormatting;
protected HSSFPatternFormatting(CFRuleRecord cfRuleRecord)
{
protected HSSFPatternFormatting(CFRuleBase cfRuleRecord, HSSFWorkbook workbook) {
this.workbook = workbook;
this.cfRuleRecord = cfRuleRecord;
this.patternFormatting = cfRuleRecord.getPatternFormatting();
}
@ -39,6 +41,14 @@ public class HSSFPatternFormatting implements org.apache.poi.ss.usermodel.Patter
return patternFormatting;
}
public HSSFColor getFillBackgroundColorColor() {
return workbook.getCustomPalette().getColor(getFillBackgroundColor());
}
public HSSFColor getFillForegroundColorColor() {
return workbook.getCustomPalette().getColor(getFillForegroundColor());
}
/**
* @see org.apache.poi.hssf.record.cf.PatternFormatting#getFillBackgroundColor()
*/
@ -63,6 +73,24 @@ public class HSSFPatternFormatting implements org.apache.poi.ss.usermodel.Patter
return (short)patternFormatting.getFillPattern();
}
public void setFillBackgroundColor(Color bg) {
HSSFColor hcolor = HSSFColor.toHSSFColor(bg);
if (hcolor == null) {
setFillBackgroundColor((short)0);
} else {
setFillBackgroundColor(hcolor.getIndex());
}
}
public void setFillForegroundColor(Color fg) {
HSSFColor hcolor = HSSFColor.toHSSFColor(fg);
if (hcolor == null) {
setFillForegroundColor((short)0);
} else {
setFillForegroundColor(hcolor.getIndex());
}
}
/**
* @param bg
* @see org.apache.poi.hssf.record.cf.PatternFormatting#setFillBackgroundColor(int)

View File

@ -29,13 +29,6 @@ import java.util.Map;
* Factory class for producing Excel Shapes from Escher records
*/
public class HSSFShapeFactory {
private final static short OBJECT_TYPE_LINE = 1;
private final static short OBJECT_TYPE_RECTANGLE = 2;
private final static short OBJECT_TYPE_OVAL = 3;
private final static short OBJECT_TYPE_ARC = 4;
private final static short OBJECT_TYPE_PICTURE = 8;
/**
* build shape tree from escher container
* @param container root escher container from which escher records must be taken
@ -81,7 +74,7 @@ public class HSSFShapeFactory {
return;
}
CommonObjectDataSubRecord cmo = (CommonObjectDataSubRecord) objRecord.getSubRecords().get(0);
HSSFShape shape;
final HSSFShape shape;
switch (cmo.getObjectType()) {
case CommonObjectDataSubRecord.OBJECT_TYPE_PICTURE:
shape = new HSSFPicture(container, objRecord);
@ -97,12 +90,16 @@ public class HSSFShapeFactory {
break;
case CommonObjectDataSubRecord.OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING:
EscherOptRecord optRecord = container.getChildById(EscherOptRecord.RECORD_ID);
if(optRecord == null) {
shape = new HSSFSimpleShape(container, objRecord, txtRecord);
} else {
EscherProperty property = optRecord.lookup(EscherProperties.GEOMETRY__VERTICES);
if (null != property) {
shape = new HSSFPolygon(container, objRecord, txtRecord);
} else {
shape = new HSSFSimpleShape(container, objRecord, txtRecord);
}
}
break;
case CommonObjectDataSubRecord.OBJECT_TYPE_TEXT:
shape = new HSSFTextbox(container, objRecord, txtRecord);

View File

@ -867,6 +867,17 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
return _sheet.getMergedRegionAt(index);
}
/**
* @return the list of merged regions
*/
public List<CellRangeAddress> getMergedRegions() {
List<CellRangeAddress> addresses = new ArrayList<CellRangeAddress>();
for (int i=0; i < _sheet.getNumMergedRegions(); i++) {
addresses.add(_sheet.getMergedRegionAt(i));
}
return addresses;
}
/**
* @return an iterator of the PHYSICAL rows. Meaning the 3rd element may not
* be the third row if say for instance the second row is undefined.

View File

@ -17,20 +17,22 @@
package org.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.record.CFRule12Record;
import org.apache.poi.hssf.record.CFRuleBase;
import org.apache.poi.hssf.record.CFRuleRecord;
import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.usermodel.ConditionalFormatting;
import org.apache.poi.ss.usermodel.ConditionalFormattingRule;
import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet;
import org.apache.poi.ss.usermodel.SheetConditionalFormatting;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.SpreadsheetVersion;
/**
* The 'Conditional Formatting' facet of <tt>HSSFSheet</tt>
*/
public final class HSSFSheetConditionalFormatting implements SheetConditionalFormatting {
private final HSSFSheet _sheet;
private final ConditionalFormattingTable _conditionalFormattingTable;
@ -66,19 +68,15 @@ public final class HSSFSheetConditionalFormatting implements SheetConditionalFor
byte comparisonOperation,
String formula1,
String formula2) {
HSSFWorkbook wb = _sheet.getWorkbook();
CFRuleRecord rr = CFRuleRecord.create(_sheet, comparisonOperation, formula1, formula2);
return new HSSFConditionalFormattingRule(wb, rr);
return new HSSFConditionalFormattingRule(_sheet, rr);
}
public HSSFConditionalFormattingRule createConditionalFormattingRule(
byte comparisonOperation,
String formula1) {
HSSFWorkbook wb = _sheet.getWorkbook();
CFRuleRecord rr = CFRuleRecord.create(_sheet, comparisonOperation, formula1, null);
return new HSSFConditionalFormattingRule(wb, rr);
return new HSSFConditionalFormattingRule(_sheet, rr);
}
/**
@ -89,11 +87,27 @@ public final class HSSFSheetConditionalFormatting implements SheetConditionalFor
* @param formula - formula for the valued, compared with the cell
*/
public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) {
HSSFWorkbook wb = _sheet.getWorkbook();
CFRuleRecord rr = CFRuleRecord.create(_sheet, formula);
return new HSSFConditionalFormattingRule(wb, rr);
return new HSSFConditionalFormattingRule(_sheet, rr);
}
/**
* A factory method allowing the creation of conditional formatting
* rules using an Icon Set / Multi-State formatting.
* The thresholds for it will be created, but will be empty
* and require configuring with
* {@link HSSFConditionalFormattingRule#getMultiStateFormatting()}
* then
* {@link HSSFIconMultiStateFormatting#getThresholds()}
*/
public HSSFConditionalFormattingRule createConditionalFormattingRule(
IconSet iconSet) {
CFRule12Record rr = CFRule12Record.create(_sheet, iconSet);
return new HSSFConditionalFormattingRule(_sheet, rr);
}
// TODO Support types beyond CELL_VALUE_IS and FORMULA and ICONs
/**
* Adds a copy of HSSFConditionalFormatting object to the sheet
* <p>This method could be used to copy HSSFConditionalFormatting object
@ -146,7 +160,7 @@ public final class HSSFSheetConditionalFormatting implements SheetConditionalFor
throw new IllegalArgumentException("Number of rules must not exceed 3");
}
CFRuleRecord[] rules = new CFRuleRecord[cfRules.length];
CFRuleBase[] rules = new CFRuleBase[cfRules.length];
for (int i = 0; i != cfRules.length; i++) {
rules[i] = cfRules[i].getCfRuleRecord();
}
@ -165,36 +179,27 @@ public final class HSSFSheetConditionalFormatting implements SheetConditionalFor
}
public int addConditionalFormatting(CellRangeAddress[] regions,
HSSFConditionalFormattingRule rule1)
{
return addConditionalFormatting(regions,
rule1 == null ? null : new HSSFConditionalFormattingRule[]
{
rule1
});
HSSFConditionalFormattingRule rule1) {
return addConditionalFormatting(regions, rule1 == null ?
null : new HSSFConditionalFormattingRule[] { rule1 }
);
}
public int addConditionalFormatting(CellRangeAddress[] regions,
ConditionalFormattingRule rule1)
{
ConditionalFormattingRule rule1) {
return addConditionalFormatting(regions, (HSSFConditionalFormattingRule)rule1);
}
public int addConditionalFormatting(CellRangeAddress[] regions,
HSSFConditionalFormattingRule rule1,
HSSFConditionalFormattingRule rule2)
{
HSSFConditionalFormattingRule rule2) {
return addConditionalFormatting(regions,
new HSSFConditionalFormattingRule[]
{
rule1, rule2
});
new HSSFConditionalFormattingRule[] { rule1, rule2 });
}
public int addConditionalFormatting(CellRangeAddress[] regions,
ConditionalFormattingRule rule1,
ConditionalFormattingRule rule2)
{
ConditionalFormattingRule rule2) {
return addConditionalFormatting(regions,
(HSSFConditionalFormattingRule)rule1,
(HSSFConditionalFormattingRule)rule2
@ -213,7 +218,7 @@ public final class HSSFSheetConditionalFormatting implements SheetConditionalFor
if (cf == null) {
return null;
}
return new HSSFConditionalFormatting(_sheet.getWorkbook(), cf);
return new HSSFConditionalFormatting(_sheet, cf);
}
/**

View File

@ -65,6 +65,7 @@ import org.apache.poi.hssf.record.UnknownRecord;
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
import org.apache.poi.hssf.record.common.UnicodeString;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.poifs.crypt.Decryptor;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.EntryUtils;
@ -205,6 +206,19 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
public HSSFWorkbook(POIFSFileSystem fs) throws IOException {
this(fs,true);
}
/**
* Given a POI POIFSFileSystem object, read in its Workbook along
* with all related nodes, and populate the high and low level models.
* <p>This calls {@link #HSSFWorkbook(POIFSFileSystem, boolean)} with
* preserve nodes set to true.
*
* @see #HSSFWorkbook(POIFSFileSystem, boolean)
* @see org.apache.poi.poifs.filesystem.POIFSFileSystem
* @exception IOException if the stream cannot be read
*/
public HSSFWorkbook(NPOIFSFileSystem fs) throws IOException {
this(fs.getRoot(),true);
}
/**
* Given a POI POIFSFileSystem object, read in its Workbook and populate
@ -248,7 +262,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
// check for an encrypted .xlsx file - they get OLE2 wrapped
try {
directory.getEntry("EncryptedPackage");
directory.getEntry(Decryptor.DEFAULT_POIFS_ENTRY);
throw new EncryptedDocumentException("The supplied spreadsheet seems to be an Encrypted .xlsx file. " +
"It must be decrypted before use by XSSF, it cannot be used by HSSF");
} catch (FileNotFoundException e) {
@ -378,7 +392,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
public HSSFWorkbook(InputStream s, boolean preserveNodes)
throws IOException
{
this(new POIFSFileSystem(s), preserveNodes);
this(new NPOIFSFileSystem(s).getRoot(), preserveNodes);
}
/**
@ -1276,7 +1290,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
throws IOException
{
byte[] bytes = getBytes();
POIFSFileSystem fs = new POIFSFileSystem();
NPOIFSFileSystem fs = new NPOIFSFileSystem();
// For tracking what we've written out, used if we're
// going to be preserving nodes
@ -1843,7 +1857,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
throws IOException {
// check if we were created by POIFS otherwise create a new dummy POIFS for storing the package data
if (directory == null) {
directory = new POIFSFileSystem().getRoot();
directory = new NPOIFSFileSystem().getRoot();
preserveNodes = true;
}

View File

@ -205,6 +205,13 @@ public class HSSFColor implements Color {
return BLACK.hexString;
}
public static HSSFColor toHSSFColor(Color color) {
if (color != null && !(color instanceof HSSFColor)) {
throw new IllegalArgumentException("Only HSSFColor objects are supported");
}
return (HSSFColor)color;
}
/**
* Class BLACK
*

View File

@ -16,6 +16,8 @@
==================================================================== */
package org.apache.poi.poifs.crypt;
import static org.apache.poi.poifs.crypt.Decryptor.DEFAULT_POIFS_ENTRY;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -132,8 +134,8 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream {
super.close();
int oleStreamSize = (int)(fileOut.length()+LittleEndianConsts.LONG_SIZE);
calculateChecksum(fileOut, oleStreamSize);
dir.createDocument("EncryptedPackage", oleStreamSize, new EncryptedPackageWriter());
calculateChecksum(fileOut, (int)_pos);
dir.createDocument(DEFAULT_POIFS_ENTRY, oleStreamSize, new EncryptedPackageWriter());
createEncryptionInfoEntry(dir, fileOut);
} catch (GeneralSecurityException e) {
throw new IOException(e);

View File

@ -36,7 +36,7 @@ public class DataSpaceMapUtils {
public static void addDefaultDataSpace(DirectoryEntry dir) throws IOException {
DataSpaceMapEntry dsme = new DataSpaceMapEntry(
new int[]{ 0 }
, new String[]{ "EncryptedPackage" }
, new String[]{ Decryptor.DEFAULT_POIFS_ENTRY }
, "StrongEncryptionDataSpace"
);
DataSpaceMap dsm = new DataSpaceMap(new DataSpaceMapEntry[]{dsme});

View File

@ -25,10 +25,12 @@ import javax.crypto.SecretKey;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public abstract class Decryptor {
public static final String DEFAULT_PASSWORD="VelvetSweatshop";
public static final String DEFAULT_POIFS_ENTRY="EncryptedPackage";
protected final EncryptionInfoBuilder builder;
private SecretKey secretKey;
@ -83,7 +85,9 @@ public abstract class Decryptor {
public InputStream getDataStream(NPOIFSFileSystem fs) throws IOException, GeneralSecurityException {
return getDataStream(fs.getRoot());
}
public InputStream getDataStream(OPOIFSFileSystem fs) throws IOException, GeneralSecurityException {
return getDataStream(fs.getRoot());
}
public InputStream getDataStream(POIFSFileSystem fs) throws IOException, GeneralSecurityException {
return getDataStream(fs.getRoot());
}

View File

@ -26,6 +26,7 @@ import java.io.IOException;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
@ -68,14 +69,27 @@ public class EncryptionInfo {
public static BitField flagAES = BitFieldFactory.getInstance(0x20);
/**
* Opens for decryption
*/
public EncryptionInfo(POIFSFileSystem fs) throws IOException {
this(fs.getRoot());
}
/**
* Opens for decryption
*/
public EncryptionInfo(OPOIFSFileSystem fs) throws IOException {
this(fs.getRoot());
}
/**
* Opens for decryption
*/
public EncryptionInfo(NPOIFSFileSystem fs) throws IOException {
this(fs.getRoot());
}
/**
* Opens for decryption
*/
public EncryptionInfo(DirectoryNode dir) throws IOException {
this(dir.createDocumentInputStream("EncryptionInfo"), false);
}
@ -131,7 +145,7 @@ public class EncryptionInfo {
}
/**
* @deprecated use constructor without fs parameter
* @deprecated Use {@link #EncryptionInfo(EncryptionMode)} (fs parameter no longer required)
*/
@Deprecated
public EncryptionInfo(POIFSFileSystem fs, EncryptionMode encryptionMode) {
@ -139,7 +153,7 @@ public class EncryptionInfo {
}
/**
* @deprecated use constructor without fs parameter
* @deprecated Use {@link #EncryptionInfo(EncryptionMode)} (fs parameter no longer required)
*/
@Deprecated
public EncryptionInfo(NPOIFSFileSystem fs, EncryptionMode encryptionMode) {
@ -147,7 +161,7 @@ public class EncryptionInfo {
}
/**
* @deprecated use constructor without dir parameter
* @deprecated Use {@link #EncryptionInfo(EncryptionMode)} (dir parameter no longer required)
*/
@Deprecated
public EncryptionInfo(DirectoryNode dir, EncryptionMode encryptionMode) {
@ -155,7 +169,7 @@ public class EncryptionInfo {
}
/**
* @deprecated use constructor without fs parameter
* @deprecated use {@link #EncryptionInfo(EncryptionMode, CipherAlgorithm, HashAlgorithm, int, int, ChainingMode)}
*/
@Deprecated
public EncryptionInfo(
@ -171,7 +185,7 @@ public class EncryptionInfo {
}
/**
* @deprecated use constructor without fs parameter
* @deprecated use {@link #EncryptionInfo(EncryptionMode, CipherAlgorithm, HashAlgorithm, int, int, ChainingMode)}
*/
@Deprecated
public EncryptionInfo(
@ -187,7 +201,7 @@ public class EncryptionInfo {
}
/**
* @deprecated use constructor without dir parameter
* @deprecated use {@link #EncryptionInfo(EncryptionMode, CipherAlgorithm, HashAlgorithm, int, int, ChainingMode)}
*/
@Deprecated
public EncryptionInfo(
@ -202,6 +216,11 @@ public class EncryptionInfo {
this(encryptionMode, cipherAlgorithm, hashAlgorithm, keyBits, blockSize, chainingMode);
}
/**
* Prepares for encryption, using the given Encryption Mode, and
* all other parameters as default.
* @see #EncryptionInfo(EncryptionMode, CipherAlgorithm, HashAlgorithm, int, int, ChainingMode)
*/
public EncryptionInfo(EncryptionMode encryptionMode) {
this(encryptionMode, null, null, -1, -1, null);
}

View File

@ -24,9 +24,11 @@ import javax.crypto.SecretKey;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public abstract class Encryptor {
protected static final String DEFAULT_POIFS_ENTRY = Decryptor.DEFAULT_POIFS_ENTRY;
private SecretKey secretKey;
/**
@ -50,7 +52,9 @@ public abstract class Encryptor {
public OutputStream getDataStream(NPOIFSFileSystem fs) throws IOException, GeneralSecurityException {
return getDataStream(fs.getRoot());
}
public OutputStream getDataStream(OPOIFSFileSystem fs) throws IOException, GeneralSecurityException {
return getDataStream(fs.getRoot());
}
public OutputStream getDataStream(POIFSFileSystem fs) throws IOException, GeneralSecurityException {
return getDataStream(fs.getRoot());
}

View File

@ -118,7 +118,7 @@ public class BinaryRC4Decryptor extends Decryptor {
public InputStream getDataStream(DirectoryNode dir) throws IOException,
GeneralSecurityException {
DocumentInputStream dis = dir.createDocumentInputStream("EncryptedPackage");
DocumentInputStream dis = dir.createDocumentInputStream(DEFAULT_POIFS_ENTRY);
_length = dis.readLong();
BinaryRC4CipherInputStream cipherStream = new BinaryRC4CipherInputStream(dis, _length);
return cipherStream;

View File

@ -40,7 +40,7 @@ import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.poifs.filesystem.DocumentNode;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.BoundedInputStream;
@ -200,7 +200,7 @@ public class CryptoAPIDecryptor extends Decryptor {
@SuppressWarnings("unused")
public InputStream getDataStream(DirectoryNode dir)
throws IOException, GeneralSecurityException {
POIFSFileSystem fsOut = new POIFSFileSystem();
NPOIFSFileSystem fsOut = new NPOIFSFileSystem();
DocumentNode es = (DocumentNode) dir.getEntry("EncryptedSummary");
DocumentInputStream dis = dir.createDocumentInputStream(es);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
@ -240,6 +240,7 @@ public class CryptoAPIDecryptor extends Decryptor {
sbis = null;
bos.reset();
fsOut.writeFilesystem(bos);
fsOut.close();
_length = bos.size();
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
return bis;

View File

@ -123,7 +123,7 @@ public class StandardDecryptor extends Decryptor {
}
public InputStream getDataStream(DirectoryNode dir) throws IOException {
DocumentInputStream dis = dir.createDocumentInputStream("EncryptedPackage");
DocumentInputStream dis = dir.createDocumentInputStream(DEFAULT_POIFS_ENTRY);
_length = dis.readLong();

View File

@ -166,7 +166,7 @@ public class StandardEncryptor extends Encryptor {
void writeToPOIFS() throws IOException {
int oleStreamSize = (int)(fileOut.length()+LittleEndianConsts.LONG_SIZE);
dir.createDocument("EncryptedPackage", oleStreamSize, this);
dir.createDocument(DEFAULT_POIFS_ENTRY, oleStreamSize, this);
// TODO: any properties???
}

View File

@ -16,27 +16,54 @@
==================================================================== */
package org.apache.poi.poifs.dev;
import org.apache.poi.poifs.filesystem.*;
import java.io.FileInputStream;
import java.io.File;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.Iterator;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.poifs.filesystem.DocumentNode;
import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.NPOIFSStream;
import org.apache.poi.poifs.property.NPropertyTable;
import org.apache.poi.poifs.storage.HeaderBlock;
/**
*
* Dump internal structure of a OLE2 file into file system
*
* @author Yegor Kozlov
*/
public class POIFSDump {
public static void main(String[] args) throws Exception {
if (args.length == 0) {
System.err.println("Must specify at least one file to dump");
System.exit(1);
}
boolean dumpProps = false, dumpMini = false;
for (int i = 0; i < args.length; i++) {
if (args[i].equalsIgnoreCase("-dumprops") ||
args[i].equalsIgnoreCase("-dump-props") ||
args[i].equalsIgnoreCase("-dump-properties")) {
dumpProps = true;
continue;
}
if (args[i].equalsIgnoreCase("-dumpmini") ||
args[i].equalsIgnoreCase("-dump-mini") ||
args[i].equalsIgnoreCase("-dump-ministream") ||
args[i].equalsIgnoreCase("-dump-mini-stream")) {
dumpMini = true;
continue;
}
System.out.println("Dumping " + args[i]);
FileInputStream is = new FileInputStream(args[i]);
POIFSFileSystem fs = new POIFSFileSystem(is);
NPOIFSFileSystem fs = new NPOIFSFileSystem(is);
is.close();
DirectoryEntry root = fs.getRoot();
@ -44,13 +71,39 @@ public class POIFSDump {
file.mkdir();
dump(root, file);
if (dumpProps) {
HeaderBlock header = getHeaderBlock(fs);
dump(fs, header.getPropertyStart(), "properties", file);
}
if (dumpMini) {
NPropertyTable props = getPropertyTable(fs);
int startBlock = props.getRoot().getStartBlock();
if (startBlock == POIFSConstants.END_OF_CHAIN) {
System.err.println("No Mini Stream in file");
} else {
dump(fs, startBlock, "mini-stream", file);
}
}
}
}
protected static HeaderBlock getHeaderBlock(NPOIFSFileSystem fs) throws Exception {
Field headerF = NPOIFSFileSystem.class.getDeclaredField("_header");
headerF.setAccessible(true);
HeaderBlock header = (HeaderBlock)headerF.get(fs);
return header;
}
protected static NPropertyTable getPropertyTable(NPOIFSFileSystem fs) throws Exception {
Field ptF = NPOIFSFileSystem.class.getDeclaredField("_property_table");
ptF.setAccessible(true);
NPropertyTable table = (NPropertyTable)ptF.get(fs);
return table;
}
public static void dump(DirectoryEntry root, File parent) throws IOException {
for(Iterator it = root.getEntries(); it.hasNext();){
Entry entry = (Entry)it.next();
for(Iterator<Entry> it = root.getEntries(); it.hasNext();){
Entry entry = it.next();
if(entry instanceof DocumentNode){
DocumentNode node = (DocumentNode)entry;
DocumentInputStream is = new DocumentInputStream(node);
@ -58,9 +111,12 @@ public class POIFSDump {
is.read(bytes);
is.close();
FileOutputStream out = new FileOutputStream(new File(parent, node.getName().trim()));
OutputStream out = new FileOutputStream(new File(parent, node.getName().trim()));
try {
out.write(bytes);
} finally {
out.close();
}
} else if (entry instanceof DirectoryEntry){
DirectoryEntry dir = (DirectoryEntry)entry;
File file = new File(parent, entry.getName());
@ -71,4 +127,17 @@ public class POIFSDump {
}
}
}
public static void dump(NPOIFSFileSystem fs, int startBlock, String name, File parent) throws IOException {
File file = new File(parent, name);
FileOutputStream out = new FileOutputStream(file);
NPOIFSStream stream = new NPOIFSStream(fs, startBlock);
byte[] b = new byte[fs.getBigBlockSize()];
for (ByteBuffer bb : stream) {
int len = bb.remaining();
bb.get(b);
out.write(b, 0, len);
}
out.close();
}
}

View File

@ -24,9 +24,10 @@ import java.lang.reflect.Method;
import org.apache.poi.poifs.common.POIFSBigBlockSize;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.property.DirectoryProperty;
import org.apache.poi.poifs.property.Property;
import org.apache.poi.poifs.property.PropertyTable;
import org.apache.poi.poifs.storage.BlockAllocationTableReader;
import org.apache.poi.poifs.storage.BlockList;
import org.apache.poi.poifs.storage.HeaderBlock;
import org.apache.poi.poifs.storage.ListManagedBlock;
import org.apache.poi.poifs.storage.RawDataBlockList;
@ -59,6 +60,7 @@ public class POIFSHeaderDumper {
}
public static void viewFile(final String filename) throws Exception {
System.out.println("Dumping headers from: " + filename);
InputStream inp = new FileInputStream(filename);
// Header
@ -79,18 +81,22 @@ public class POIFSHeaderDumper {
header_block.getXBATCount(),
header_block.getXBATIndex(),
data_blocks);
displayBATReader(batReader);
displayBATReader("Big Blocks", batReader);
// Properties Table
PropertyTable properties =
new PropertyTable(header_block, data_blocks);
// Mini Fat
BlockList sbat =
SmallBlockTableReader.getSmallDocumentBlocks(
BlockAllocationTableReader sbatReader =
SmallBlockTableReader._getSmallDocumentBlockReader(
bigBlockSize, data_blocks, properties.getRoot(),
header_block.getSBATStart()
);
displayBATReader("Small Blocks", sbatReader);
// Summary of the properties
displayPropertiesSummary(properties);
}
public static void displayHeader(HeaderBlock header_block) throws Exception {
@ -98,6 +104,8 @@ public class POIFSHeaderDumper {
System.out.println(" Block size: " + header_block.getBigBlockSize().getBigBlockSize());
System.out.println(" BAT (FAT) header blocks: " + header_block.getBATArray().length);
System.out.println(" BAT (FAT) block count: " + header_block.getBATCount());
if (header_block.getBATCount() > 0)
System.out.println(" BAT (FAT) block 1 at: " + header_block.getBATArray()[0]);
System.out.println(" XBAT (FAT) block count: " + header_block.getXBATCount());
System.out.println(" XBAT (FAT) block 1 at: " + header_block.getXBATIndex());
System.out.println(" SBAT (MiniFAT) block count: " + header_block.getSBATCount());
@ -125,8 +133,8 @@ public class POIFSHeaderDumper {
System.out.println("");
}
public static void displayBATReader(BlockAllocationTableReader batReader) throws Exception {
System.out.println("Sectors, as referenced from the FAT:");
public static void displayBATReader(String type, BlockAllocationTableReader batReader) throws Exception {
System.out.println("Sectors, as referenced from the "+type+" FAT:");
Field entriesF = batReader.getClass().getDeclaredField("_entries");
entriesF.setAccessible(true);
IntList entries = (IntList)entriesF.get(batReader);
@ -149,4 +157,32 @@ public class POIFSHeaderDumper {
System.out.println("");
}
public static void displayPropertiesSummary(PropertyTable properties) {
System.out.println("Mini Stream starts at " + properties.getRoot().getStartBlock());
System.out.println("Mini Stream length is " + properties.getRoot().getSize());
System.out.println();
System.out.println("Properties and their block start:");
displayProperties(properties.getRoot(), "");
System.out.println("");
}
public static void displayProperties(DirectoryProperty prop, String indent) {
String nextIndent = indent + " ";
System.out.println(indent + "-> " + prop.getName());
for (Property cp : prop) {
if (cp instanceof DirectoryProperty) {
displayProperties((DirectoryProperty)cp, nextIndent);
} else {
System.out.println(nextIndent + "=> " + cp.getName());
System.out.print(nextIndent + " " + cp.getSize() + " bytes in ");
if (cp.shouldUseSmallBlocks()) {
System.out.print("mini");
} else {
System.out.print("main");
}
System.out.println(" stream, starts at " + cp.getStartBlock());
}
}
}
}

View File

@ -19,12 +19,12 @@
package org.apache.poi.poifs.dev;
import java.io.FileInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
/**
* A simple viewer for POIFS files
@ -76,7 +76,7 @@ public class POIFSViewer
try
{
POIFSViewable fs =
new POIFSFileSystem(new FileInputStream(filename));
new NPOIFSFileSystem(new File(filename));
List<String> strings = POIFSViewEngine.inspectViewable(fs, true,
0, " ");
Iterator<String> iter = strings.iterator();

Some files were not shown because too many files have changed in this diff Show More