Просмотр исходного кода

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
tags/REL_3_13_FINAL
Andreas Beeker 8 лет назад
Родитель
Сommit
89ab6304a4
100 измененных файлов: 6981 добавлений и 3952 удалений
  1. 2
    0
      .settings/org.eclipse.core.resources.prefs
  2. 4
    0
      .settings/org.eclipse.jdt.core.prefs
  3. 69
    0
      .settings/org.eclipse.jdt.ui.prefs
  4. 4
    0
      .settings/org.moreunit.prefs
  5. 345
    0
      KEYS
  6. 71
    28
      build.xml
  7. 34
    0
      doap_POI.rdf
  8. 1
    1
      legal/NOTICE
  9. 229
    0
      osgi/pom.xml
  10. 28
    0
      osgi/src/main/java/org/apache/poi/osgi/Activator.java
  11. 84
    0
      osgi/src/test/java/org/apache/poi/osgi/TestOSGiBundle.java
  12. 34
    0
      osgi/test-bundles.xml
  13. 3
    3
      src/examples/src/org/apache/poi/hpsf/examples/ReadCustomPropertySets.java
  14. 2
    0
      src/examples/src/org/apache/poi/hssf/usermodel/examples/CreateCells.java
  15. 134
    4
      src/examples/src/org/apache/poi/ss/examples/ConditionalFormats.java
  16. 7
    3
      src/examples/src/org/apache/poi/ss/examples/html/ToHtml.java
  17. 3
    2
      src/examples/src/org/apache/poi/xssf/usermodel/examples/AligningCells.java
  18. 24
    19
      src/examples/src/org/apache/poi/xssf/usermodel/examples/BigGridDemo.java
  19. 145
    0
      src/integrationtest/build.xml
  20. 224
    174
      src/integrationtest/org/apache/poi/TestAllFiles.java
  21. 143
    0
      src/integrationtest/org/apache/poi/stress/AbstractFileHandler.java
  22. 7
    0
      src/integrationtest/org/apache/poi/stress/FileHandler.java
  23. 19
    1
      src/integrationtest/org/apache/poi/stress/HDGFFileHandler.java
  24. 1
    1
      src/integrationtest/org/apache/poi/stress/HMEFFileHandler.java
  25. 20
    1
      src/integrationtest/org/apache/poi/stress/HPBFFileHandler.java
  26. 8
    1
      src/integrationtest/org/apache/poi/stress/HPSFFileHandler.java
  27. 15
    0
      src/integrationtest/org/apache/poi/stress/HSMFFileHandler.java
  28. 7
    0
      src/integrationtest/org/apache/poi/stress/HSSFFileHandler.java
  29. 52
    2
      src/integrationtest/org/apache/poi/stress/HWPFFileHandler.java
  30. 1
    1
      src/integrationtest/org/apache/poi/stress/POIFSFileHandler.java
  31. 31
    1
      src/integrationtest/org/apache/poi/stress/POIXMLDocumentHandler.java
  32. 1
    1
      src/integrationtest/org/apache/poi/stress/SpreadsheetHandler.java
  33. 67
    5
      src/integrationtest/org/apache/poi/stress/XSLFFileHandler.java
  34. 7
    0
      src/integrationtest/org/apache/poi/stress/XSSFFileHandler.java
  35. 8
    2
      src/integrationtest/org/apache/poi/stress/XWPFFileHandler.java
  36. 28
    0
      src/java/org/apache/poi/EmptyFileException.java
  37. 2
    1
      src/java/org/apache/poi/EncryptedDocumentException.java
  38. 43
    77
      src/java/org/apache/poi/POIDocument.java
  39. 13
    15
      src/java/org/apache/poi/POIOLE2TextExtractor.java
  40. 0
    18
      src/java/org/apache/poi/POITextExtractor.java
  41. 7
    0
      src/java/org/apache/poi/ddf/EscherPropertyFactory.java
  42. 5
    1
      src/java/org/apache/poi/hpsf/HPSFPropertiesOnlyDocument.java
  43. 1
    1
      src/java/org/apache/poi/hpsf/Section.java
  44. 11
    2
      src/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java
  45. 2
    2
      src/java/org/apache/poi/hssf/dev/BiffDrawingToXml.java
  46. 368
    318
      src/java/org/apache/poi/hssf/dev/BiffViewer.java
  47. 19
    5
      src/java/org/apache/poi/hssf/eventusermodel/HSSFEventFactory.java
  48. 2
    11
      src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java
  49. 6
    5
      src/java/org/apache/poi/hssf/model/InternalWorkbook.java
  50. 88
    0
      src/java/org/apache/poi/hssf/record/CFHeader12Record.java
  51. 153
    0
      src/java/org/apache/poi/hssf/record/CFHeaderBase.java
  52. 31
    136
      src/java/org/apache/poi/hssf/record/CFHeaderRecord.java
  53. 365
    0
      src/java/org/apache/poi/hssf/record/CFRule12Record.java
  54. 455
    0
      src/java/org/apache/poi/hssf/record/CFRuleBase.java
  55. 102
    485
      src/java/org/apache/poi/hssf/record/CFRuleRecord.java
  56. 5
    2
      src/java/org/apache/poi/hssf/record/FeatRecord.java
  57. 26
    10
      src/java/org/apache/poi/hssf/record/NameCommentRecord.java
  58. 3
    2
      src/java/org/apache/poi/hssf/record/NameRecord.java
  59. 411
    416
      src/java/org/apache/poi/hssf/record/RecordFactory.java
  60. 10
    1
      src/java/org/apache/poi/hssf/record/RecordInputStream.java
  61. 6
    0
      src/java/org/apache/poi/hssf/record/RowRecord.java
  62. 11
    8
      src/java/org/apache/poi/hssf/record/UnknownRecord.java
  63. 236
    204
      src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java
  64. 4
    4
      src/java/org/apache/poi/hssf/record/aggregates/ConditionalFormattingTable.java
  65. 3
    3
      src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java
  66. 173
    182
      src/java/org/apache/poi/hssf/record/cf/CellRangeUtil.java
  67. 518
    520
      src/java/org/apache/poi/hssf/record/cf/FontFormatting.java
  68. 139
    0
      src/java/org/apache/poi/hssf/record/cf/IconMultiStateFormatting.java
  69. 4
    2
      src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java
  70. 146
    0
      src/java/org/apache/poi/hssf/record/cf/Threshold.java
  71. 58
    50
      src/java/org/apache/poi/hssf/record/common/FtrHeader.java
  72. 30
    0
      src/java/org/apache/poi/hssf/record/common/FutureRecord.java
  73. 2
    2
      src/java/org/apache/poi/hssf/record/crypto/Biff8DecryptingStream.java
  74. 236
    186
      src/java/org/apache/poi/hssf/usermodel/HSSFBorderFormatting.java
  75. 4
    4
      src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
  76. 5
    2
      src/java/org/apache/poi/hssf/usermodel/HSSFComment.java
  77. 66
    73
      src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormatting.java
  78. 225
    175
      src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java
  79. 63
    0
      src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingThreshold.java
  80. 379
    373
      src/java/org/apache/poi/hssf/usermodel/HSSFFontFormatting.java
  81. 81
    0
      src/java/org/apache/poi/hssf/usermodel/HSSFIconMultiStateFormatting.java
  82. 0
    1
      src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
  83. 107
    79
      src/java/org/apache/poi/hssf/usermodel/HSSFPatternFormatting.java
  84. 9
    12
      src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java
  85. 11
    0
      src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
  86. 173
    168
      src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java
  87. 18
    4
      src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
  88. 7
    0
      src/java/org/apache/poi/hssf/util/HSSFColor.java
  89. 4
    2
      src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java
  90. 1
    1
      src/java/org/apache/poi/poifs/crypt/DataSpaceMapUtils.java
  91. 5
    1
      src/java/org/apache/poi/poifs/crypt/Decryptor.java
  92. 27
    8
      src/java/org/apache/poi/poifs/crypt/EncryptionInfo.java
  93. 5
    1
      src/java/org/apache/poi/poifs/crypt/Encryptor.java
  94. 2
    2
      src/java/org/apache/poi/poifs/crypt/binaryrc4/BinaryRC4Decryptor.java
  95. 3
    2
      src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIDecryptor.java
  96. 1
    1
      src/java/org/apache/poi/poifs/crypt/standard/StandardDecryptor.java
  97. 1
    1
      src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptor.java
  98. 84
    15
      src/java/org/apache/poi/poifs/dev/POIFSDump.java
  99. 144
    108
      src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java
  100. 0
    0
      src/java/org/apache/poi/poifs/dev/POIFSViewer.java

+ 2
- 0
.settings/org.eclipse.core.resources.prefs Просмотреть файл

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

+ 4
- 0
.settings/org.eclipse.jdt.core.prefs Просмотреть файл

@@ -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

+ 69
- 0
.settings/org.eclipse.jdt.ui.prefs
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


+ 4
- 0
.settings/org.moreunit.prefs Просмотреть файл

@@ -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
- 0
KEYS Просмотреть файл

@@ -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-----

+ 71
- 28
build.xml Просмотреть файл

@@ -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 -->
@@ -56,7 +56,7 @@ under the License.

<property name="main.lib" location="lib"/>
<property name="ooxml.lib" location="ooxml-lib"/>
<property name="compile.lib" location="compile-lib"/>
<property name="compile.lib" location="compile-lib"/>
<property name="forrest.home" value="${env.FORREST_HOME}"/>

<!-- compiler options options -->
@@ -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"/>
@@ -194,14 +198,14 @@ under the License.
<property name="ooxml.xsds.src.jar" location="${ooxml.lib}/ooxml-schemas-1.1-sources.jar"/>
<property name="ooxml.xsds.jar" location="${ooxml.lib}/ooxml-schemas-1.1.jar"/>

<!-- additional schemas are packed into the poi schemas jar, -->
<!-- so we don't have to care about a seperate versioning of the original ooxml schemas -->
<property name="ooxml.xsds.dc.1" value="http://dublincore.org/schemas/xmls/qdc/2003/04/02/dc.xsd"/>
<property name="ooxml.xsds.dc.2" value="http://dublincore.org/schemas/xmls/qdc/2003/04/02/dcterms.xsd"/>
<property name="ooxml.xsds.dc.3" value="http://dublincore.org/schemas/xmls/qdc/2003/04/02/dcmitype.xsd"/>
<property name="ooxml.xsds.dsig.1" value="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd"/>
<property name="ooxml.xsds.dsig.2" value="http://uri.etsi.org/01903/v1.3.2/XAdES.xsd"/>
<property name="ooxml.xsds.dsig.3" value="http://uri.etsi.org/01903/v1.4.1/XAdESv141.xsd"/>
<!-- additional schemas are packed into the poi schemas jar, -->
<!-- so we don't have to care about a seperate versioning of the original ooxml schemas -->
<property name="ooxml.xsds.dc.1" value="http://dublincore.org/schemas/xmls/qdc/2003/04/02/dc.xsd"/>
<property name="ooxml.xsds.dc.2" value="http://dublincore.org/schemas/xmls/qdc/2003/04/02/dcterms.xsd"/>
<property name="ooxml.xsds.dc.3" value="http://dublincore.org/schemas/xmls/qdc/2003/04/02/dcmitype.xsd"/>
<property name="ooxml.xsds.dsig.1" value="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd"/>
<property name="ooxml.xsds.dsig.2" value="http://uri.etsi.org/01903/v1.3.2/XAdES.xsd"/>
<property name="ooxml.xsds.dsig.3" value="http://uri.etsi.org/01903/v1.4.1/XAdESv141.xsd"/>
<property name="ooxml.xsds.ozip.2" value="OfficeOpenXML-Part2.zip"/>
<property name="ooxml.xsds.izip.2" value="OpenPackagingConventions-XMLSchema.zip"/>
<property name="ooxml.xsds.url.2"
@@ -263,17 +267,18 @@ 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 -->
<!-- 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">
<path refid="main.classpath"/>
<pathelement location="${main.output.dir}"/>
<pathelement location="${main.output.test.dir}"/>
<pathelement location="${additionaljar}"/>
<pathelement location="${additionaljar}"/>
</path>

<path id="test.scratchpad.classpath">
@@ -281,7 +286,7 @@ under the License.
<pathelement location="${main.output.test.dir}"/>
<pathelement location="${scratchpad.output.dir}"/>
<pathelement location="${scratchpad.output.test.dir}"/>
<pathelement location="${additionaljar}"/>
<pathelement location="${additionaljar}"/>
</path>

<path id="test.ooxml.classpath">
@@ -289,14 +294,14 @@ under the License.
<pathelement location="${ooxml.output.dir}"/>
<pathelement location="${ooxml.output.test.dir}"/>
<pathelement location="${main.output.test.dir}"/>
<pathelement location="${additionaljar}"/>
<pathelement location="${additionaljar}"/>
</path>

<path id="test.integration.classpath">
<path refid="scratchpad.classpath"/>
<path refid="ooxml.classpath"/>
<pathelement location="${main.output.test.dir}"/>
<pathelement location="${ooxml.output.dir}"/>
<pathelement location="${ooxml.output.dir}"/>
<pathelement location="${integration.output.test.dir}"/>
</path>

@@ -331,7 +336,7 @@ under the License.
<pathelement location="${excelant.output.dir}"/>
<pathelement location="${excelant.output.test.dir}"/>
<pathelement location="${main.output.test.dir}"/>
<pathelement location="${additionaljar}"/>
<pathelement location="${additionaljar}"/>
</path>

<path id="javadoc.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>
@@ -1744,7 +1764,30 @@ under the License.
<sourcePath path="src/java" />
<sourcePath path="src/ooxml/java" />
<sourcePath path="src/scratchpad/src" />
</findbugs>
</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">

+ 34
- 0
doap_POI.rdf Просмотреть файл

@@ -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>

+ 1
- 1
legal/NOTICE Просмотреть файл

@@ -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
- 0
osgi/pom.xml Просмотреть файл

@@ -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>

+ 28
- 0
osgi/src/main/java/org/apache/poi/osgi/Activator.java Просмотреть файл

@@ -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 {
}
}

+ 84
- 0
osgi/src/test/java/org/apache/poi/osgi/TestOSGiBundle.java Просмотреть файл

@@ -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
- 0
osgi/test-bundles.xml Просмотреть файл

@@ -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>

+ 3
- 3
src/examples/src/org/apache/poi/hpsf/examples/ReadCustomPropertySets.java Просмотреть файл

@@ -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);

+ 2
- 0
src/examples/src/org/apache/poi/hssf/usermodel/examples/CreateCells.java Просмотреть файл

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

wb.close();
}
}

+ 134
- 4
src/examples/src/org/apache/poi/ss/examples/ConditionalFormats.java Просмотреть файл

@@ -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);
}
/**
@@ -139,6 +144,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,
@@ -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);
}
}

+ 7
- 3
src/examples/src/org/apache/poi/ss/examples/html/ToHtml.java Просмотреть файл

@@ -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);
fmt.format("style_%02x", style.getIndex());
return fmt.toString();
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) {

+ 3
- 2
src/examples/src/org/apache/poi/xssf/usermodel/examples/AligningCells.java Просмотреть файл

@@ -114,16 +114,17 @@ 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
ctRow.setSpans(spanList);
}
}
}

+ 24
- 19
src/examples/src/org/apache/poi/xssf/usermodel/examples/BigGridDemo.java Просмотреть файл

@@ -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,27 +166,31 @@ 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);

ZipOutputStream zos = new ZipOutputStream(out);

@SuppressWarnings("unchecked")
Enumeration<ZipEntry> en = (Enumeration<ZipEntry>) zip.entries();
while (en.hasMoreElements()) {
ZipEntry ze = en.nextElement();
if(!ze.getName().equals(entry)){
zos.putNextEntry(new ZipEntry(ze.getName()));
InputStream is = zip.getInputStream(ze);
copyStream(is, zos);
is.close();
ZipFile zip = ZipHelper.openZipFile(zipfile);

try {
ZipOutputStream zos = new ZipOutputStream(out);

@SuppressWarnings("unchecked")
Enumeration<ZipEntry> en = (Enumeration<ZipEntry>) zip.entries();
while (en.hasMoreElements()) {
ZipEntry ze = en.nextElement();
if(!ze.getName().equals(entry)){
zos.putNextEntry(new ZipEntry(ze.getName()));
InputStream is = zip.getInputStream(ze);
copyStream(is, zos);
is.close();
}
}
zos.putNextEntry(new ZipEntry(entry));
InputStream is = new FileInputStream(tmpfile);
copyStream(is, zos);
is.close();
zos.close();
} finally {
zip.close();
}
zos.putNextEntry(new ZipEntry(entry));
InputStream is = new FileInputStream(tmpfile);
copyStream(is, zos);
is.close();

zos.close();
}

private static void copyStream(InputStream in, OutputStream out) throws IOException {

+ 145
- 0
src/integrationtest/build.xml Просмотреть файл

@@ -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>

+ 224
- 174
src/integrationtest/org/apache/poi/TestAllFiles.java Просмотреть файл

@@ -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;
@@ -65,83 +66,91 @@ import org.junit.runners.Parameterized.Parameters;
*/
@RunWith(Parameterized.class)
public class TestAllFiles {
private static final File ROOT_DIR = new File("test-data");
private static final File ROOT_DIR = new File("test-data");

// map file extensions to the actual mappers
private static final Map<String, FileHandler> HANDLERS = new HashMap<String, FileHandler>();
static {
// Excel
HANDLERS.put(".xls", new HSSFFileHandler());
HANDLERS.put(".xlsx", new XSSFFileHandler());
HANDLERS.put(".xlsm", new XSSFFileHandler());
HANDLERS.put(".xltx", new XSSFFileHandler());
HANDLERS.put(".xlsb", new XSSFFileHandler());
// Word
HANDLERS.put(".doc", new HWPFFileHandler());
HANDLERS.put(".docx", new XWPFFileHandler());
HANDLERS.put(".dotx", new XWPFFileHandler());
HANDLERS.put(".docm", new XWPFFileHandler());
HANDLERS.put(".ooxml", new XWPFFileHandler()); // OPCPackage

// Powerpoint
HANDLERS.put(".ppt", new HSLFFileHandler());
HANDLERS.put(".pptx", new XSLFFileHandler());
HANDLERS.put(".pptm", new XSLFFileHandler());
HANDLERS.put(".ppsm", new XSLFFileHandler());
HANDLERS.put(".ppsx", new XSLFFileHandler());
HANDLERS.put(".thmx", new XSLFFileHandler());

// Outlook
HANDLERS.put(".msg", new HSMFFileHandler());
// Publisher
HANDLERS.put(".pub", new HPBFFileHandler());

// Visio
HANDLERS.put(".vsd", new HDGFFileHandler());
// POIFS
HANDLERS.put(".ole2", new POIFSFileHandler());

// Microsoft Admin Template?
HANDLERS.put(".adm", new HPSFFileHandler());

// Microsoft TNEF
HANDLERS.put(".dat", new HMEFFileHandler());
// TODO: are these readable by some of the formats?
HANDLERS.put(".shw", new NullFileHandler());
HANDLERS.put(".zvi", new NullFileHandler());
HANDLERS.put(".mpp", new NullFileHandler());
HANDLERS.put(".qwp", new NullFileHandler());
HANDLERS.put(".wps", new NullFileHandler());
HANDLERS.put(".bin", new NullFileHandler());
HANDLERS.put(".xps", new NullFileHandler());
HANDLERS.put(".sldprt", new NullFileHandler());
HANDLERS.put(".mdb", new NullFileHandler());
HANDLERS.put(".vml", new NullFileHandler());

// ignore some file types, images, other formats, ...
HANDLERS.put(".txt", new NullFileHandler());
HANDLERS.put(".pdf", new NullFileHandler());
HANDLERS.put(".rtf", new NullFileHandler());
HANDLERS.put(".gif", new NullFileHandler());
HANDLERS.put(".html", new NullFileHandler());
HANDLERS.put(".png", new NullFileHandler());
HANDLERS.put(".wmf", new NullFileHandler());
HANDLERS.put(".emf", new NullFileHandler());
HANDLERS.put(".dib", new NullFileHandler());
HANDLERS.put(".svg", new NullFileHandler());
HANDLERS.put(".pict", new NullFileHandler());
HANDLERS.put(".jpg", new NullFileHandler());
HANDLERS.put(".wav", new NullFileHandler());
HANDLERS.put(".pfx", new NullFileHandler());
HANDLERS.put(".xml", new NullFileHandler());
HANDLERS.put(".csv", new NullFileHandler());
// map some files without extension
HANDLERS.put("spreadsheet/BigSSTRecord", new NullFileHandler());
private static final Map<String, FileHandler> HANDLERS = new HashMap<String, FileHandler>();
static {
// Excel
HANDLERS.put(".xls", new HSSFFileHandler());
HANDLERS.put(".xlsx", new XSSFFileHandler());
HANDLERS.put(".xlsm", new XSSFFileHandler());
HANDLERS.put(".xltx", new XSSFFileHandler());
HANDLERS.put(".xlsb", new XSSFFileHandler());

// Word
HANDLERS.put(".doc", new HWPFFileHandler());
HANDLERS.put(".docx", new XWPFFileHandler());
HANDLERS.put(".dotx", new XWPFFileHandler());
HANDLERS.put(".docm", new XWPFFileHandler());
HANDLERS.put(".ooxml", new XWPFFileHandler()); // OPCPackage

// Powerpoint
HANDLERS.put(".ppt", new HSLFFileHandler());
HANDLERS.put(".pptx", new XSLFFileHandler());
HANDLERS.put(".pptm", new XSLFFileHandler());
HANDLERS.put(".ppsm", new XSLFFileHandler());
HANDLERS.put(".ppsx", new XSLFFileHandler());
HANDLERS.put(".thmx", new XSLFFileHandler());

// Outlook
HANDLERS.put(".msg", new HSMFFileHandler());

// Publisher
HANDLERS.put(".pub", new HPBFFileHandler());

// 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());

// Microsoft Admin Template?
HANDLERS.put(".adm", new HPSFFileHandler());

// Microsoft TNEF
HANDLERS.put(".dat", new HMEFFileHandler());

// TODO: are these readable by some of the formats?
HANDLERS.put(".shw", new NullFileHandler());
HANDLERS.put(".zvi", new NullFileHandler());
HANDLERS.put(".mpp", new NullFileHandler());
HANDLERS.put(".qwp", new NullFileHandler());
HANDLERS.put(".wps", new NullFileHandler());
HANDLERS.put(".bin", new NullFileHandler());
HANDLERS.put(".xps", new NullFileHandler());
HANDLERS.put(".sldprt", new NullFileHandler());
HANDLERS.put(".mdb", new NullFileHandler());
HANDLERS.put(".vml", new NullFileHandler());

// ignore some file types, images, other formats, ...
HANDLERS.put(".txt", new NullFileHandler());
HANDLERS.put(".pdf", new NullFileHandler());
HANDLERS.put(".rtf", new NullFileHandler());
HANDLERS.put(".gif", new NullFileHandler());
HANDLERS.put(".html", new NullFileHandler());
HANDLERS.put(".png", new NullFileHandler());
HANDLERS.put(".wmf", new NullFileHandler());
HANDLERS.put(".emf", new NullFileHandler());
HANDLERS.put(".dib", new NullFileHandler());
HANDLERS.put(".svg", new NullFileHandler());
HANDLERS.put(".pict", new NullFileHandler());
HANDLERS.put(".jpg", new NullFileHandler());
HANDLERS.put(".wav", new NullFileHandler());
HANDLERS.put(".pfx", new NullFileHandler());
HANDLERS.put(".xml", new NullFileHandler());
HANDLERS.put(".csv", new NullFileHandler());

// map some files without extension
HANDLERS.put("spreadsheet/BigSSTRecord", new NullFileHandler());
HANDLERS.put("spreadsheet/BigSSTRecord2", new NullFileHandler());
HANDLERS.put("spreadsheet/BigSSTRecord2CR1", new NullFileHandler());
HANDLERS.put("spreadsheet/BigSSTRecord2CR2", new NullFileHandler());
@@ -151,88 +160,104 @@ public class TestAllFiles {
HANDLERS.put("spreadsheet/BigSSTRecord2CR6", new NullFileHandler());
HANDLERS.put("spreadsheet/BigSSTRecord2CR7", new NullFileHandler());
HANDLERS.put("spreadsheet/BigSSTRecordCR", new NullFileHandler());
HANDLERS.put("spreadsheet/test_properties1", new NullFileHandler());
}

private static final Set<String> EXPECTED_FAILURES = new HashSet<String>();
static {
// password protected files
EXPECTED_FAILURES.add("spreadsheet/password.xls");
EXPECTED_FAILURES.add("spreadsheet/51832.xls");
EXPECTED_FAILURES.add("document/PasswordProtected.doc");
EXPECTED_FAILURES.add("slideshow/Password_Protected-hello.ppt");
EXPECTED_FAILURES.add("slideshow/Password_Protected-56-hello.ppt");
EXPECTED_FAILURES.add("slideshow/Password_Protected-np-hello.ppt");
EXPECTED_FAILURES.add("slideshow/cryptoapi-proc2356.ppt");
//EXPECTED_FAILURES.add("document/bug53475-password-is-pass.docx");
//EXPECTED_FAILURES.add("document/bug53475-password-is-solrcell.docx");
EXPECTED_FAILURES.add("spreadsheet/xor-encryption-abc.xls");
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");
EXPECTED_FAILURES.add("slideshow/Password_Protected-56-hello.ppt");
EXPECTED_FAILURES.add("slideshow/Password_Protected-np-hello.ppt");
EXPECTED_FAILURES.add("slideshow/cryptoapi-proc2356.ppt");
//EXPECTED_FAILURES.add("document/bug53475-password-is-pass.docx");
//EXPECTED_FAILURES.add("document/bug53475-password-is-solrcell.docx");
EXPECTED_FAILURES.add("spreadsheet/xor-encryption-abc.xls");
EXPECTED_FAILURES.add("spreadsheet/35897-type4.xls");
//EXPECTED_FAILURES.add("poifs/protect.xlsx");
//EXPECTED_FAILURES.add("poifs/protected_sha512.xlsx");
//EXPECTED_FAILURES.add("poifs/extenxls_pwd123.xlsx");
//EXPECTED_FAILURES.add("poifs/protected_agile.docx");
// TODO: fails XMLExportTest, is this ok?
EXPECTED_FAILURES.add("spreadsheet/CustomXMLMapping-singleattributenamespace.xlsx");
EXPECTED_FAILURES.add("spreadsheet/55864.xlsx");
// TODO: these fail now with some NPE/file read error because we now try to compute every value via Cell.toString()!
EXPECTED_FAILURES.add("spreadsheet/44958.xls");
EXPECTED_FAILURES.add("spreadsheet/44958_1.xls");
EXPECTED_FAILURES.add("spreadsheet/testArraysAndTables.xls");

// TODO: good to ignore?
EXPECTED_FAILURES.add("spreadsheet/sample-beta.xlsx");
EXPECTED_FAILURES.add("spreadsheet/49931.xls");
EXPECTED_FAILURES.add("openxml4j/ContentTypeHasParameters.ooxml");

// This is actually a spreadsheet!
EXPECTED_FAILURES.add("hpsf/TestRobert_Flaherty.doc");
// some files that are broken, Excel 5.0/95, 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");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_CoreProperties_LimitedXSITypeAttribute_NotPresentFAIL.docx");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_CoreProperties_LimitedXSITypeAttribute_PresentWithUnauthorizedValueFAIL.docx");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_CoreProperties_OnlyOneCorePropertiesPartFAIL.docx");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_CoreProperties_UnauthorizedXMLLangAttributeFAIL.docx");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_DerivedPartNameFAIL.docx");
EXPECTED_FAILURES.add("spreadsheet/54764-2.xlsx"); // see TestXSSFBugs.bug54764()
EXPECTED_FAILURES.add("spreadsheet/54764.xlsx"); // see TestXSSFBugs.bug54764()

// TODO: fails XMLExportTest, is this ok?
EXPECTED_FAILURES.add("spreadsheet/CustomXMLMapping-singleattributenamespace.xlsx");
EXPECTED_FAILURES.add("spreadsheet/55864.xlsx");

// TODO: these fail now with some NPE/file read error because we now try to compute every value via Cell.toString()!
EXPECTED_FAILURES.add("spreadsheet/44958.xls");
EXPECTED_FAILURES.add("spreadsheet/44958_1.xls");
EXPECTED_FAILURES.add("spreadsheet/testArraysAndTables.xls");

// TODO: good to ignore?
EXPECTED_FAILURES.add("spreadsheet/sample-beta.xlsx");
EXPECTED_FAILURES.add("spreadsheet/49931.xls");
EXPECTED_FAILURES.add("openxml4j/ContentTypeHasParameters.ooxml");

// This is actually a spreadsheet!
EXPECTED_FAILURES.add("hpsf/TestRobert_Flaherty.doc");

// 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/Bug50955.doc");
EXPECTED_FAILURES.add("slideshow/PPT95.ppt");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_CoreProperties_DCTermsNamespaceLimitedUseFAIL.docx");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_CoreProperties_DoNotUseCompatibilityMarkupFAIL.docx");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_CoreProperties_LimitedXSITypeAttribute_NotPresentFAIL.docx");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_CoreProperties_LimitedXSITypeAttribute_PresentWithUnauthorizedValueFAIL.docx");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_CoreProperties_OnlyOneCorePropertiesPartFAIL.docx");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_CoreProperties_UnauthorizedXMLLangAttributeFAIL.docx");
EXPECTED_FAILURES.add("openxml4j/OPCCompliance_DerivedPartNameFAIL.docx");
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");
}

// non-TNEF files
EXPECTED_FAILURES.add("ddf/Container.dat");
EXPECTED_FAILURES.add("ddf/47143.dat");
}
@Parameters(name="{index}: {0} using {1}")
public static Iterable<Object[]> files() {
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir(ROOT_DIR);
scanner.setExcludes(new String[] { "**/.svn/**" });
scanner.scan();
System.out.println("Handling " + scanner.getIncludedFiles().length + " files");

List<Object[]> files = new ArrayList<Object[]>();
@@ -240,47 +265,72 @@ public class TestAllFiles {
file = file.replace('\\', '/'); // ... failures/handlers lookup doesn't work on windows otherwise
files.add(new Object[] { file, HANDLERS.get(getExtension(file)) });
}
return files;
}
}
@Parameter(value=0)
public String file;
@Parameter(value=1)
public FileHandler handler;
@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);
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);
}
} finally {
stream.close();
}
}

private static String getExtension(String file) {
int pos = file.lastIndexOf('.');
if(pos == -1 || pos == file.length()-1) {
return file;
}
return file.substring(pos);
}

private static class NullFileHandler implements FileHandler {
@Override
assertNotNull("Unknown file extension for file: " + file + ": " + getExtension(file), handler);
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!",
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) {
int pos = file.lastIndexOf('.');
if(pos == -1 || pos == file.length()-1) {
return file;
}

return file.substring(pos);
}

private static class NullFileHandler implements FileHandler {
@Override
public void handleFile(InputStream stream) throws Exception {
}
}
}

@Override
public void handleExtracting(File file) throws Exception {
}
}
}

+ 143
- 0
src/integrationtest/org/apache/poi/stress/AbstractFileHandler.java Просмотреть файл

@@ -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();
}
}
}

+ 7
- 0
src/integrationtest/org/apache/poi/stress/FileHandler.java Просмотреть файл

@@ -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;
}

+ 19
- 1
src/integrationtest/org/apache/poi/stress/HDGFFileHandler.java Просмотреть файл

@@ -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();
}
}
}

+ 1
- 1
src/integrationtest/org/apache/poi/stress/HMEFFileHandler.java Просмотреть файл

@@ -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 {

+ 20
- 1
src/integrationtest/org/apache/poi/stress/HPBFFileHandler.java Просмотреть файл

@@ -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();
}
}
}

+ 8
- 1
src/integrationtest/org/apache/poi/stress/HPSFFileHandler.java Просмотреть файл

@@ -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"));
}
}

+ 15
- 0
src/integrationtest/org/apache/poi/stress/HSMFFileHandler.java Просмотреть файл

@@ -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");

+ 7
- 0
src/integrationtest/org/apache/poi/stress/HSSFFileHandler.java Просмотреть файл

@@ -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"));
}
}

+ 52
- 2
src/integrationtest/org/apache/poi/stress/HWPFFileHandler.java Просмотреть файл

@@ -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);
}
}
}

+ 1
- 1
src/integrationtest/org/apache/poi/stress/POIFSFileHandler.java Просмотреть файл

@@ -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 {

+ 31
- 1
src/integrationtest/org/apache/poi/stress/POIXMLDocumentHandler.java Просмотреть файл

@@ -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;
}
}
}

+ 1
- 1
src/integrationtest/org/apache/poi/stress/SpreadsheetHandler.java Просмотреть файл

@@ -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);

+ 67
- 5
src/integrationtest/org/apache/poi/stress/XSLFFileHandler.java Просмотреть файл

@@ -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"));
}
}

+ 7
- 0
src/integrationtest/org/apache/poi/stress/XSSFFileHandler.java Просмотреть файл

@@ -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"));
}
}

+ 8
- 2
src/integrationtest/org/apache/poi/stress/XWPFFileHandler.java Просмотреть файл

@@ -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);
}
}

+ 28
- 0
src/java/org/apache/poi/EmptyFileException.java Просмотреть файл

@@ -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)");
}
}

+ 2
- 1
src/java/org/apache/poi/EncryptedDocumentException.java Просмотреть файл

@@ -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);
}

+ 43
- 77
src/java/org/apache/poi/POIDocument.java Просмотреть файл

@@ -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
@@ -218,26 +222,39 @@ public abstract class POIDocument {
}
return null;
}
/**
* 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 Documment Information Properties (HPSF)
* 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 );
}
}

+ 13
- 15
src/java/org/apache/poi/POIOLE2TextExtractor.java Просмотреть файл

@@ -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,15 +33,27 @@ 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;
}
/**
* Returns the document information metadata for the 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();
}
}

+ 0
- 18
src/java/org/apache/poi/POITextExtractor.java Просмотреть файл

@@ -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

+ 7
- 0
src/java/org/apache/poi/ddf/EscherPropertyFactory.java Просмотреть файл

@@ -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;
}

+ 5
- 1
src/java/org/apache/poi/hpsf/HPSFPropertiesOnlyDocument.java Просмотреть файл

@@ -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);

+ 1
- 1
src/java/org/apache/poi/hpsf/Section.java Просмотреть файл

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



+ 11
- 2
src/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java Просмотреть файл

@@ -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

+ 2
- 2
src/java/org/apache/poi/hssf/dev/BiffDrawingToXml.java Просмотреть файл

@@ -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);

+ 368
- 318
src/java/org/apache/poi/hssf/dev/BiffViewer.java Просмотреть файл

@@ -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,330 +82,330 @@ 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();
static final char[] NEW_LINE_CHARS = System.getProperty("line.separator").toCharArray();

private BiffViewer() {
// no instances of this class
}

/**
* Create an array of records from an input stream
*
*@param is the InputStream from which the records will be obtained
*@return an array of Records created from the InputStream
*@exception RecordFormatException on error processing the InputStream
*/
public static Record[] createRecords(InputStream is, PrintStream ps, BiffRecordListener recListener, boolean dumpInterpretedRecords)
throws RecordFormatException {
List<Record> temp = new ArrayList<Record>();

RecordInputStream recStream = new RecordInputStream(is);
while (true) {
boolean hasNext;
try {
hasNext = recStream.hasNextRecord();
} catch (LeftoverDataException e) {
e.printStackTrace();
System.err.println("Discarding " + recStream.remaining() + " bytes and continuing");
recStream.readRemainder();
hasNext = recStream.hasNextRecord();
}
if (!hasNext) {
break;
}
recStream.nextRecord();
if (recStream.getSid() == 0) {
continue;
}
Record record;
if (dumpInterpretedRecords) {
record = createRecord (recStream);
if (record.getSid() == ContinueRecord.sid) {
continue;
}
temp.add(record);

if (dumpInterpretedRecords) {
for (String header : recListener.getRecentHeaders()) {
ps.println(header);
}
ps.print(record.toString());
}
} else {
recStream.readRemainder();
}
ps.println();
}
Record[] result = new Record[temp.size()];
temp.toArray(result);
return result;
}


/**
* Essentially a duplicate of RecordFactory. Kept separate as not to screw
* up non-debug operations.
*
*/
private static Record createRecord(RecordInputStream in) {
switch (in.getSid()) {
case AreaFormatRecord.sid: return new AreaFormatRecord(in);
case AreaRecord.sid: return new AreaRecord(in);
case ArrayRecord.sid: return new ArrayRecord(in);
case AxisLineFormatRecord.sid: return new AxisLineFormatRecord(in);
case AxisOptionsRecord.sid: return new AxisOptionsRecord(in);
case AxisParentRecord.sid: return new AxisParentRecord(in);
case AxisRecord.sid: return new AxisRecord(in);
case AxisUsedRecord.sid: return new AxisUsedRecord(in);
case AutoFilterInfoRecord.sid: return new AutoFilterInfoRecord(in);
case BOFRecord.sid: return new BOFRecord(in);
case BackupRecord.sid: return new BackupRecord(in);
case BarRecord.sid: return new BarRecord(in);
case BeginRecord.sid: return new BeginRecord(in);
case BlankRecord.sid: return new BlankRecord(in);
case BookBoolRecord.sid: return new BookBoolRecord(in);
case BoolErrRecord.sid: return new BoolErrRecord(in);
case BottomMarginRecord.sid: return new BottomMarginRecord(in);
case BoundSheetRecord.sid: return new BoundSheetRecord(in);
case CFHeaderRecord.sid: return new CFHeaderRecord(in);
case CFRuleRecord.sid: return new CFRuleRecord(in);
case CalcCountRecord.sid: return new CalcCountRecord(in);
case CalcModeRecord.sid: return new CalcModeRecord(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);
case ColumnInfoRecord.sid: return new ColumnInfoRecord(in);
case ContinueRecord.sid: return new ContinueRecord(in);
case CountryRecord.sid: return new CountryRecord(in);
case DBCellRecord.sid: return new DBCellRecord(in);
case DSFRecord.sid: return new DSFRecord(in);
case DatRecord.sid: return new DatRecord(in);
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 DefaultDataLabelTextPropertiesRecord.sid: return new DefaultDataLabelTextPropertiesRecord(in);
case DefaultRowHeightRecord.sid: return new DefaultRowHeightRecord(in);
case DeltaRecord.sid: return new DeltaRecord(in);
case DimensionsRecord.sid: return new DimensionsRecord(in);
case DrawingGroupRecord.sid: return new DrawingGroupRecord(in);
case DrawingRecordForBiffViewer.sid: return new DrawingRecordForBiffViewer(in);
case DrawingSelectionRecord.sid: return new DrawingSelectionRecord(in);
case DVRecord.sid: return new DVRecord(in);
case DVALRecord.sid: return new DVALRecord(in);
case EOFRecord.sid: return new EOFRecord(in);
case EndRecord.sid: return new EndRecord(in);
case ExtSSTRecord.sid: return new ExtSSTRecord(in);
case ExtendedFormatRecord.sid: return new ExtendedFormatRecord(in);
case ExternSheetRecord.sid: return new ExternSheetRecord(in);
case ExternalNameRecord.sid: return new ExternalNameRecord(in);
case FeatRecord.sid: return new FeatRecord(in);
case FeatHdrRecord.sid: return new FeatHdrRecord(in);
case FilePassRecord.sid: return new FilePassRecord(in);
case FileSharingRecord.sid: return new FileSharingRecord(in);
case FnGroupCountRecord.sid: return new FnGroupCountRecord(in);
case FontBasisRecord.sid: return new FontBasisRecord(in);
case FontIndexRecord.sid: return new FontIndexRecord(in);
case FontRecord.sid: return new FontRecord(in);
case FooterRecord.sid: return new FooterRecord(in);
case FormatRecord.sid: return new FormatRecord(in);
case FormulaRecord.sid: return new FormulaRecord(in);
case FrameRecord.sid: return new FrameRecord(in);
case GridsetRecord.sid: return new GridsetRecord(in);
case GutsRecord.sid: return new GutsRecord(in);
case HCenterRecord.sid: return new HCenterRecord(in);
case HeaderRecord.sid: return new HeaderRecord(in);
case HideObjRecord.sid: return new HideObjRecord(in);
case HorizontalPageBreakRecord.sid: return new HorizontalPageBreakRecord(in);
case HyperlinkRecord.sid: return new HyperlinkRecord(in);
case IndexRecord.sid: return new IndexRecord(in);
case InterfaceEndRecord.sid: return InterfaceEndRecord.create(in);
case InterfaceHdrRecord.sid: return new InterfaceHdrRecord(in);
case IterationRecord.sid: return new IterationRecord(in);
case LabelRecord.sid: return new LabelRecord(in);
case LabelSSTRecord.sid: return new LabelSSTRecord(in);
case LeftMarginRecord.sid: return new LeftMarginRecord(in);
case LegendRecord.sid: return new LegendRecord(in);
case LineFormatRecord.sid: return new LineFormatRecord(in);
case LinkedDataRecord.sid: return new LinkedDataRecord(in);
case MMSRecord.sid: return new MMSRecord(in);
case MergeCellsRecord.sid: return new MergeCellsRecord(in);
case MulBlankRecord.sid: return new MulBlankRecord(in);
case MulRKRecord.sid: return new MulRKRecord(in);
case NameRecord.sid: return new NameRecord(in);
case NameCommentRecord.sid: return new NameCommentRecord(in);
case NoteRecord.sid: return new NoteRecord(in);
case NumberRecord.sid: return new NumberRecord(in);
case ObjRecord.sid: return new ObjRecord(in);
case ObjectLinkRecord.sid: return new ObjectLinkRecord(in);
case PaletteRecord.sid: return new PaletteRecord(in);
case PaneRecord.sid: return new PaneRecord(in);
case PasswordRecord.sid: return new PasswordRecord(in);
case PasswordRev4Record.sid: return new PasswordRev4Record(in);
case PlotAreaRecord.sid: return new PlotAreaRecord(in);
case PlotGrowthRecord.sid: return new PlotGrowthRecord(in);
case PrecisionRecord.sid: return new PrecisionRecord(in);
case PrintGridlinesRecord.sid: return new PrintGridlinesRecord(in);
case PrintHeadersRecord.sid: return new PrintHeadersRecord(in);
case PrintSetupRecord.sid: return new PrintSetupRecord(in);
case ProtectRecord.sid: return new ProtectRecord(in);
case ProtectionRev4Record.sid: return new ProtectionRev4Record(in);
case RKRecord.sid: return new RKRecord(in);
case RecalcIdRecord.sid: return new RecalcIdRecord(in);
case RefModeRecord.sid: return new RefModeRecord(in);
case RefreshAllRecord.sid: return new RefreshAllRecord(in);
case RightMarginRecord.sid: return new RightMarginRecord(in);
case RowRecord.sid: return new RowRecord(in);
case SCLRecord.sid: return new SCLRecord(in);
case SSTRecord.sid: return new SSTRecord(in);
case SaveRecalcRecord.sid: return new SaveRecalcRecord(in);
case SelectionRecord.sid: return new SelectionRecord(in);
case SeriesIndexRecord.sid: return new SeriesIndexRecord(in);
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 SharedFormulaRecord.sid: return new SharedFormulaRecord(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);
case TabIdRecord.sid: return new TabIdRecord(in);
case TableStylesRecord.sid: return new TableStylesRecord(in);
case TableRecord.sid: return new TableRecord(in);
case TextObjectRecord.sid: return new TextObjectRecord(in);
case TextRecord.sid: return new TextRecord(in);
case TickRecord.sid: return new TickRecord(in);
case TopMarginRecord.sid: return new TopMarginRecord(in);
case UncalcedRecord.sid: return new UncalcedRecord(in);
case UnitsRecord.sid: return new UnitsRecord(in);
case UseSelFSRecord.sid: return new UseSelFSRecord(in);
case VCenterRecord.sid: return new VCenterRecord(in);
case ValueRangeRecord.sid: return new ValueRangeRecord(in);
case VerticalPageBreakRecord.sid: return new VerticalPageBreakRecord(in);
case WSBoolRecord.sid: return new WSBoolRecord(in);
case WindowOneRecord.sid: return new WindowOneRecord(in);
case WindowProtectRecord.sid: return new WindowProtectRecord(in);
case WindowTwoRecord.sid: return new WindowTwoRecord(in);
case WriteAccessRecord.sid: return new WriteAccessRecord(in);
case WriteProtectRecord.sid: return new WriteProtectRecord(in);

// chart
case CatLabRecord.sid: return new CatLabRecord(in);
case ChartEndBlockRecord.sid: return new ChartEndBlockRecord(in);
case ChartEndObjectRecord.sid: return new ChartEndObjectRecord(in);
case ChartFRTInfoRecord.sid: return new ChartFRTInfoRecord(in);
case ChartStartBlockRecord.sid: return new ChartStartBlockRecord(in);
case ChartStartObjectRecord.sid: return new ChartStartObjectRecord(in);

// pivot table
case StreamIDRecord.sid: return new StreamIDRecord(in);
case ViewSourceRecord.sid: return new ViewSourceRecord(in);
case PageItemRecord.sid: return new PageItemRecord(in);
case ViewDefinitionRecord.sid: return new ViewDefinitionRecord(in);
case ViewFieldsRecord.sid: return new ViewFieldsRecord(in);
case DataItemRecord.sid: return new DataItemRecord(in);
case ExtendedPivotTableViewFieldsRecord.sid: return new ExtendedPivotTableViewFieldsRecord(in);
}
return new UnknownRecord(in);
}

private static final class CommandArgs {

private final boolean _biffhex;
private final boolean _noint;
private final boolean _out;
private final boolean _rawhex;
private final boolean _noHeader;
private final File _file;

private CommandArgs(boolean biffhex, boolean noint, boolean out, boolean rawhex, boolean noHeader, File file) {
_biffhex = biffhex;
_noint = noint;
_out = out;
_rawhex = rawhex;
_file = file;
_noHeader = noHeader;
}

public static CommandArgs parse(String[] args) throws CommandParseException {
int nArgs = args.length;
boolean biffhex = false;
boolean noint = false;
boolean out = false;
boolean rawhex = false;
boolean noheader = false;
File file = null;
for (int i=0; i<nArgs; i++) {
String arg = args[i];
if (arg.startsWith("--")) {
if ("--biffhex".equals(arg)) {
biffhex = true;
} else if ("--noint".equals(arg)) {
noint = true;
} else if ("--out".equals(arg)) {
out = true;
} else if ("--escher".equals(arg)) {
System.setProperty("poi.deserialize.escher", "true");
} else if ("--rawhex".equals(arg)) {
rawhex = true;
} else if ("--noheader".equals(arg)) {
noheader = true;
} else {
throw new CommandParseException("Unexpected option '" + arg + "'");
}
continue;
}
file = new File(arg);
if (!file.exists()) {
throw new CommandParseException("Specified file '" + arg + "' does not exist");
}
if (i+1<nArgs) {
throw new CommandParseException("File name must be the last arg");
}
}
if (file == null) {
throw new CommandParseException("Biff viewer needs a filename");
}
return new CommandArgs(biffhex, noint, out, rawhex, noheader, file);
}
public boolean shouldDumpBiffHex() {
return _biffhex;
}
public boolean shouldDumpRecordInterpretations() {
return !_noint;
}
public boolean shouldOutputToFile() {
return _out;
}
public boolean shouldOutputRawHexOnly() {
return _rawhex;
}
public boolean suppressHeader() {
return _noHeader;
}
public File getFile() {
return _file;
}
}
private static final class CommandParseException extends Exception {
public CommandParseException(String msg) {
super(msg);
}
}
// no instances of this class
}

/**
* Create an array of records from an input stream
*
*@param is the InputStream from which the records will be obtained
*@return an array of Records created from the InputStream
*@exception RecordFormatException on error processing the InputStream
*/
public static Record[] createRecords(InputStream is, PrintStream ps, BiffRecordListener recListener, boolean dumpInterpretedRecords)
throws RecordFormatException {
List<Record> temp = new ArrayList<Record>();

RecordInputStream recStream = new RecordInputStream(is);
while (true) {
boolean hasNext;
try {
hasNext = recStream.hasNextRecord();
} catch (LeftoverDataException e) {
e.printStackTrace();
System.err.println("Discarding " + recStream.remaining() + " bytes and continuing");
recStream.readRemainder();
hasNext = recStream.hasNextRecord();
}
if (!hasNext) {
break;
}
recStream.nextRecord();
if (recStream.getSid() == 0) {
continue;
}
Record record;
if (dumpInterpretedRecords) {
record = createRecord (recStream);
if (record.getSid() == ContinueRecord.sid) {
continue;
}
temp.add(record);

if (dumpInterpretedRecords) {
for (String header : recListener.getRecentHeaders()) {
ps.println(header);
}
ps.print(record.toString());
}
} else {
recStream.readRemainder();
}
ps.println();
}
Record[] result = new Record[temp.size()];
temp.toArray(result);
return result;
}


/**
* Essentially a duplicate of RecordFactory. Kept separate as not to screw
* up non-debug operations.
*
*/
private static Record createRecord(RecordInputStream in) {
switch (in.getSid()) {
case AreaFormatRecord.sid: return new AreaFormatRecord(in);
case AreaRecord.sid: return new AreaRecord(in);
case ArrayRecord.sid: return new ArrayRecord(in);
case AxisLineFormatRecord.sid: return new AxisLineFormatRecord(in);
case AxisOptionsRecord.sid: return new AxisOptionsRecord(in);
case AxisParentRecord.sid: return new AxisParentRecord(in);
case AxisRecord.sid: return new AxisRecord(in);
case AxisUsedRecord.sid: return new AxisUsedRecord(in);
case AutoFilterInfoRecord.sid: return new AutoFilterInfoRecord(in);
case BOFRecord.sid: return new BOFRecord(in);
case BackupRecord.sid: return new BackupRecord(in);
case BarRecord.sid: return new BarRecord(in);
case BeginRecord.sid: return new BeginRecord(in);
case BlankRecord.sid: return new BlankRecord(in);
case BookBoolRecord.sid: return new BookBoolRecord(in);
case BoolErrRecord.sid: return new BoolErrRecord(in);
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 ChartFormatRecord.sid: return new ChartFormatRecord(in);
case ChartRecord.sid: return new ChartRecord(in);
case CodepageRecord.sid: return new CodepageRecord(in);
case ColumnInfoRecord.sid: return new ColumnInfoRecord(in);
case ContinueRecord.sid: return new ContinueRecord(in);
case CountryRecord.sid: return new CountryRecord(in);
case DBCellRecord.sid: return new DBCellRecord(in);
case DSFRecord.sid: return new DSFRecord(in);
case DatRecord.sid: return new DatRecord(in);
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 DefaultDataLabelTextPropertiesRecord.sid: return new DefaultDataLabelTextPropertiesRecord(in);
case DefaultRowHeightRecord.sid: return new DefaultRowHeightRecord(in);
case DeltaRecord.sid: return new DeltaRecord(in);
case DimensionsRecord.sid: return new DimensionsRecord(in);
case DrawingGroupRecord.sid: return new DrawingGroupRecord(in);
case DrawingRecordForBiffViewer.sid: return new DrawingRecordForBiffViewer(in);
case DrawingSelectionRecord.sid: return new DrawingSelectionRecord(in);
case DVRecord.sid: return new DVRecord(in);
case DVALRecord.sid: return new DVALRecord(in);
case EOFRecord.sid: return new EOFRecord(in);
case EndRecord.sid: return new EndRecord(in);
case ExtSSTRecord.sid: return new ExtSSTRecord(in);
case ExtendedFormatRecord.sid: return new ExtendedFormatRecord(in);
case ExternSheetRecord.sid: return new ExternSheetRecord(in);
case ExternalNameRecord.sid: return new ExternalNameRecord(in);
case FeatRecord.sid: return new FeatRecord(in);
case FeatHdrRecord.sid: return new FeatHdrRecord(in);
case FilePassRecord.sid: return new FilePassRecord(in);
case FileSharingRecord.sid: return new FileSharingRecord(in);
case FnGroupCountRecord.sid: return new FnGroupCountRecord(in);
case FontBasisRecord.sid: return new FontBasisRecord(in);
case FontIndexRecord.sid: return new FontIndexRecord(in);
case FontRecord.sid: return new FontRecord(in);
case FooterRecord.sid: return new FooterRecord(in);
case FormatRecord.sid: return new FormatRecord(in);
case FormulaRecord.sid: return new FormulaRecord(in);
case FrameRecord.sid: return new FrameRecord(in);
case GridsetRecord.sid: return new GridsetRecord(in);
case GutsRecord.sid: return new GutsRecord(in);
case HCenterRecord.sid: return new HCenterRecord(in);
case HeaderRecord.sid: return new HeaderRecord(in);
case HideObjRecord.sid: return new HideObjRecord(in);
case HorizontalPageBreakRecord.sid: return new HorizontalPageBreakRecord(in);
case HyperlinkRecord.sid: return new HyperlinkRecord(in);
case IndexRecord.sid: return new IndexRecord(in);
case InterfaceEndRecord.sid: return InterfaceEndRecord.create(in);
case InterfaceHdrRecord.sid: return new InterfaceHdrRecord(in);
case IterationRecord.sid: return new IterationRecord(in);
case LabelRecord.sid: return new LabelRecord(in);
case LabelSSTRecord.sid: return new LabelSSTRecord(in);
case LeftMarginRecord.sid: return new LeftMarginRecord(in);
case LegendRecord.sid: return new LegendRecord(in);
case LineFormatRecord.sid: return new LineFormatRecord(in);
case LinkedDataRecord.sid: return new LinkedDataRecord(in);
case MMSRecord.sid: return new MMSRecord(in);
case MergeCellsRecord.sid: return new MergeCellsRecord(in);
case MulBlankRecord.sid: return new MulBlankRecord(in);
case MulRKRecord.sid: return new MulRKRecord(in);
case NameRecord.sid: return new NameRecord(in);
case NameCommentRecord.sid: return new NameCommentRecord(in);
case NoteRecord.sid: return new NoteRecord(in);
case NumberRecord.sid: return new NumberRecord(in);
case ObjRecord.sid: return new ObjRecord(in);
case ObjectLinkRecord.sid: return new ObjectLinkRecord(in);
case PaletteRecord.sid: return new PaletteRecord(in);
case PaneRecord.sid: return new PaneRecord(in);
case PasswordRecord.sid: return new PasswordRecord(in);
case PasswordRev4Record.sid: return new PasswordRev4Record(in);
case PlotAreaRecord.sid: return new PlotAreaRecord(in);
case PlotGrowthRecord.sid: return new PlotGrowthRecord(in);
case PrecisionRecord.sid: return new PrecisionRecord(in);
case PrintGridlinesRecord.sid: return new PrintGridlinesRecord(in);
case PrintHeadersRecord.sid: return new PrintHeadersRecord(in);
case PrintSetupRecord.sid: return new PrintSetupRecord(in);
case ProtectRecord.sid: return new ProtectRecord(in);
case ProtectionRev4Record.sid: return new ProtectionRev4Record(in);
case RKRecord.sid: return new RKRecord(in);
case RecalcIdRecord.sid: return new RecalcIdRecord(in);
case RefModeRecord.sid: return new RefModeRecord(in);
case RefreshAllRecord.sid: return new RefreshAllRecord(in);
case RightMarginRecord.sid: return new RightMarginRecord(in);
case RowRecord.sid: return new RowRecord(in);
case SCLRecord.sid: return new SCLRecord(in);
case SSTRecord.sid: return new SSTRecord(in);
case SaveRecalcRecord.sid: return new SaveRecalcRecord(in);
case SelectionRecord.sid: return new SelectionRecord(in);
case SeriesIndexRecord.sid: return new SeriesIndexRecord(in);
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 SharedFormulaRecord.sid: return new SharedFormulaRecord(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);
case TabIdRecord.sid: return new TabIdRecord(in);
case TableStylesRecord.sid: return new TableStylesRecord(in);
case TableRecord.sid: return new TableRecord(in);
case TextObjectRecord.sid: return new TextObjectRecord(in);
case TextRecord.sid: return new TextRecord(in);
case TickRecord.sid: return new TickRecord(in);
case TopMarginRecord.sid: return new TopMarginRecord(in);
case UncalcedRecord.sid: return new UncalcedRecord(in);
case UnitsRecord.sid: return new UnitsRecord(in);
case UseSelFSRecord.sid: return new UseSelFSRecord(in);
case VCenterRecord.sid: return new VCenterRecord(in);
case ValueRangeRecord.sid: return new ValueRangeRecord(in);
case VerticalPageBreakRecord.sid: return new VerticalPageBreakRecord(in);
case WSBoolRecord.sid: return new WSBoolRecord(in);
case WindowOneRecord.sid: return new WindowOneRecord(in);
case WindowProtectRecord.sid: return new WindowProtectRecord(in);
case WindowTwoRecord.sid: return new WindowTwoRecord(in);
case WriteAccessRecord.sid: return new WriteAccessRecord(in);
case WriteProtectRecord.sid: return new WriteProtectRecord(in);

// chart
case CatLabRecord.sid: return new CatLabRecord(in);
case ChartEndBlockRecord.sid: return new ChartEndBlockRecord(in);
case ChartEndObjectRecord.sid: return new ChartEndObjectRecord(in);
case ChartFRTInfoRecord.sid: return new ChartFRTInfoRecord(in);
case ChartStartBlockRecord.sid: return new ChartStartBlockRecord(in);
case ChartStartObjectRecord.sid: return new ChartStartObjectRecord(in);

// pivot table
case StreamIDRecord.sid: return new StreamIDRecord(in);
case ViewSourceRecord.sid: return new ViewSourceRecord(in);
case PageItemRecord.sid: return new PageItemRecord(in);
case ViewDefinitionRecord.sid: return new ViewDefinitionRecord(in);
case ViewFieldsRecord.sid: return new ViewFieldsRecord(in);
case DataItemRecord.sid: return new DataItemRecord(in);
case ExtendedPivotTableViewFieldsRecord.sid: return new ExtendedPivotTableViewFieldsRecord(in);
}
return new UnknownRecord(in);
}

private static final class CommandArgs {

private final boolean _biffhex;
private final boolean _noint;
private final boolean _out;
private final boolean _rawhex;
private final boolean _noHeader;
private final File _file;

private CommandArgs(boolean biffhex, boolean noint, boolean out, boolean rawhex, boolean noHeader, File file) {
_biffhex = biffhex;
_noint = noint;
_out = out;
_rawhex = rawhex;
_file = file;
_noHeader = noHeader;
}

public static CommandArgs parse(String[] args) throws CommandParseException {
int nArgs = args.length;
boolean biffhex = false;
boolean noint = false;
boolean out = false;
boolean rawhex = false;
boolean noheader = false;
File file = null;
for (int i=0; i<nArgs; i++) {
String arg = args[i];
if (arg.startsWith("--")) {
if ("--biffhex".equals(arg)) {
biffhex = true;
} else if ("--noint".equals(arg)) {
noint = true;
} else if ("--out".equals(arg)) {
out = true;
} else if ("--escher".equals(arg)) {
System.setProperty("poi.deserialize.escher", "true");
} else if ("--rawhex".equals(arg)) {
rawhex = true;
} else if ("--noheader".equals(arg)) {
noheader = true;
} else {
throw new CommandParseException("Unexpected option '" + arg + "'");
}
continue;
}
file = new File(arg);
if (!file.exists()) {
throw new CommandParseException("Specified file '" + arg + "' does not exist");
}
if (i+1<nArgs) {
throw new CommandParseException("File name must be the last arg");
}
}
if (file == null) {
throw new CommandParseException("Biff viewer needs a filename");
}
return new CommandArgs(biffhex, noint, out, rawhex, noheader, file);
}
public boolean shouldDumpBiffHex() {
return _biffhex;
}
public boolean shouldDumpRecordInterpretations() {
return !_noint;
}
public boolean shouldOutputToFile() {
return _out;
}
public boolean shouldOutputRawHexOnly() {
return _rawhex;
}
public boolean suppressHeader() {
return _noHeader;
}
public File getFile() {
return _file;
}
}
private static final class CommandParseException extends Exception {
public CommandParseException(String msg) {
super(msg);
}
}

/**
* Method main with 1 argument just run straight biffview against given
@@ -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);
}

+ 19
- 5
src/java/org/apache/poi/hssf/eventusermodel/HSSFEventFactory.java Просмотреть файл

@@ -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.*;
@@ -56,11 +57,24 @@ public class HSSFEventFactory {
* @param req an Instance of HSSFRequest which has your registered listeners
* @param dir a DirectoryNode containing your workbook
*/
public void processWorkbookEvents(HSSFRequest req, DirectoryNode dir) throws IOException {
InputStream in = dir.createDocumentInputStream("Workbook");

processEvents(req, in);
}
public void processWorkbookEvents(HSSFRequest req, DirectoryNode dir) throws IOException {
// 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);
}

/**
* Processes a file into essentially record events.

+ 2
- 11
src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java Просмотреть файл

@@ -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

+ 6
- 5
src/java/org/apache/poi/hssf/model/InternalWorkbook.java Просмотреть файл

@@ -774,11 +774,12 @@ public final class InternalWorkbook {
}
}
// 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);
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++) {
linkTable.removeSheet(i);
}
}
}


+ 88
- 0
src/java/org/apache/poi/hssf/record/CFHeader12Record.java Просмотреть файл

@@ -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;
}
}

+ 153
- 0
src/java/org/apache/poi/hssf/record/CFHeaderBase.java Просмотреть файл

@@ -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();
}
}

+ 31
- 136
src/java/org/apache/poi/hssf/record/CFHeaderRecord.java Просмотреть файл

@@ -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 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(CellRangeAddress[] regions, int nRules) {
CellRangeAddress[] unmergedRanges = regions;
CellRangeAddress[] mergeCellRanges = CellRangeUtil.mergeCellRanges(unmergedRanges);
setCellRanges(mergeCellRanges);
field_1_numcf = 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 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);
}

public short getSid() {
return sid;
}

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();
return result;
}
public final class CFHeaderRecord extends CFHeaderBase {
public static final short sid = 0x01B0;

/** Creates new CFHeaderRecord */
public CFHeaderRecord() {
createEmpty();
}
public CFHeaderRecord(CellRangeAddress[] regions, int nRules) {
super(regions, nRules);
}

public CFHeaderRecord(RecordInputStream in) {
read(in);
}

protected String getRecordName() {
return "CFHEADER";
}

public short getSid() {
return sid;
}

public Object clone() {
CFHeaderRecord result = new CFHeaderRecord();
super.copyTo(result);
return result;
}
}

+ 365
- 0
src/java/org/apache/poi/hssf/record/CFRule12Record.java Просмотреть файл

@@ -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();
}
}

+ 455
- 0
src/java/org/apache/poi/hssf/record/CFRuleBase.java Просмотреть файл

@@ -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());
}
}

+ 102
- 485
src/java/org/apache/poi/hssf/record/CFRuleRecord.java Просмотреть файл

@@ -19,512 +19,129 @@ 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/>
*
* @author Dmitriy Kumshayev
* Conditional Formatting Rule Record (0x01B1).
*
* <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 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);
}
/** Creates new CFRuleRecord */
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);
}
private CFRuleRecord(byte conditionType, byte comparisonOperation, Ptg[] formula1, Ptg[] 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;
}

/**
* Creates a new comparison operation rule
*/
/**
* Creates a new comparison operation rule
*/
public static CFRuleRecord create(HSSFSheet sheet, String formulaText) {
Ptg[] formula1 = parseFormula(formulaText, sheet);
return new CFRuleRecord(CONDITION_TYPE_FORMULA, ComparisonOperator.NO_COMPARISON,
formula1, null);
}
/**
* Creates a new comparison operation rule
*/
public static CFRuleRecord create(HSSFSheet sheet, byte comparisonOperation,
String formulaText1, String formulaText2) {
Ptg[] formula1 = parseFormula(formulaText1, sheet);
Ptg[] formula2 = parseFormula(formulaText2, sheet);
return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2);
}

public CFRuleRecord(RecordInputStream in) {
field_1_condition_type = in.readByte();
field_2_comparison_operator = 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);
}

// "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);
}

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()
{
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
* byte array.
*
* @param out the stream to write to
*/
public void serialize(LittleEndianOutput out) {

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.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);
}

if (containsBorderFormattingBlock()) {
_borderFormatting.serialize(out);
}

if (containsPatternFormattingBlock()) {
_patternFormatting.serialize(out);
}

field_17_formula1.serializeTokens(out);
field_18_formula2.serializeTokens(out);
}
/**
* Creates a new comparison operation rule
*/
public static CFRuleRecord create(HSSFSheet sheet, byte comparisonOperation,
String formulaText1, String formulaText2) {
Ptg[] formula1 = parseFormula(formulaText1, sheet);
Ptg[] formula2 = parseFormula(formulaText2, sheet);
return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2);
}

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
;
}
public CFRuleRecord(RecordInputStream in) {
setConditionType(in.readByte());
setComparisonOperation(in.readByte());
int field_3_formula1_len = in.readUShort();
int field_4_formula2_len = in.readUShort();
readFormatOptions(in);

// "You may not use unions, intersections or array constants in Conditional Formatting criteria"
setFormula1(Formula.read(field_3_formula1_len, in));
setFormula2(Formula.read(field_4_formula2_len, in));
}

public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("[CFRULE]\n");
buffer.append(" .condition_type =").append(field_1_condition_type).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(" 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("[/CFRULE]\n");
return buffer.toString();
}
public short getSid() {
return sid;
}

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();
/**
* 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) {
int formula1Len=getFormulaSize(getFormula1());
int formula2Len=getFormulaSize(getFormula2());

out.writeByte(getConditionType());
out.writeByte(getComparisonOperation());
out.writeShort(formula1Len);
out.writeShort(formula2Len);
serializeFormattingBlock(out);

getFormula1().serializeTokens(out);
getFormula2().serializeTokens(out);
}

return rec;
}
protected int getDataSize() {
return 6 + getFormattingBlockSize() +
getFormulaSize(getFormula1())+
getFormulaSize(getFormula2());
}

/**
* 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;
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("[CFRULE]\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");
}
int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);
return HSSFFormulaParser.parse(formula, sheet.getWorkbook(), FormulaType.CELL, sheetIndex);
if (containsBorderFormattingBlock()) {
buffer.append(_borderFormatting.toString()).append("\n");
}
if (containsPatternFormattingBlock()) {
buffer.append(_patternFormatting.toString()).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(getConditionType(), getComparisonOperation());
super.copyTo(rec);
return rec;
}
}

+ 5
- 2
src/java/org/apache/poi/hssf/record/FeatRecord.java Просмотреть файл

@@ -34,8 +34,11 @@ import org.apache.poi.util.POILogger;
* up with a {@link FeatHdrRecord}.
*/
public final class FeatRecord extends StandardRecord {
private static POILogger logger = POILogFactory.getLogger(FeatRecord.class);
public final static short sid = 0x0868;
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;

+ 26
- 10
src/java/org/apache/poi/hssf/record/NameCommentRecord.java Просмотреть файл

@@ -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);
StringUtil.putCompressedUnicode(field_6_name_text, out);
out.writeByte(0);
StringUtil.putCompressedUnicode(field_7_comment_text, out);
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);
}
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
field_6_name_text = StringUtil.readCompressedUnicode(in, field_4_name_length);
in.readByte(); //spurious NUL
field_7_comment_text = StringUtil.readCompressedUnicode(in, field_5_comment_length);
if (in.readByte() == 0) {
field_6_name_text = StringUtil.readCompressedUnicode(in, field_4_name_length);
} 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);
}
}

/**

+ 3
- 2
src/java/org/apache/poi/hssf/record/NameRecord.java Просмотреть файл

@@ -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();


+ 411
- 416
src/java/org/apache/poi/hssf/record/RecordFactory.java Просмотреть файл

@@ -62,425 +62,420 @@ 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;

private interface I_RecordCreator {
Record create(RecordInputStream in);

Class<? extends Record> getRecordClass();
}
private static final class ReflectionConstructorRecordCreator implements I_RecordCreator {

private final Constructor<? extends Record> _c;
public ReflectionConstructorRecordCreator(Constructor<? extends Record> c) {
_c = c;
}
public Record create(RecordInputStream in) {
Object[] args = { in, };
try {
return _c.newInstance(args);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (t instanceof RecordFormatException) {
throw (RecordFormatException)t;
} else if (t instanceof EncryptedDocumentException) {
throw (EncryptedDocumentException)t;
} else {
throw new RecordFormatException("Unable to construct record instance" , t);
}
}
}
public Class<? extends Record> getRecordClass() {
return _c.getDeclaringClass();
}
}
/**
* A "create" method is used instead of the usual constructor if the created record might
* 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;
}
public Record create(RecordInputStream in) {
Object[] args = { in, };
try {
return (Record) _m.invoke(null, args);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RecordFormatException("Unable to construct record instance" , e.getTargetException());
}
}
@SuppressWarnings("unchecked")
public Class<? extends Record> getRecordClass() {
return (Class<? extends Record>) _m.getDeclaringClass();
}
}


private static final Class<?>[] CONSTRUCTOR_ARGS = { RecordInputStream.class, };

/**
* contains the classes for all the records we want to parse.<br/>
* Note - this most but not *every* subclass of Record.
*/
@SuppressWarnings("unchecked")
private static final Class<? extends Record>[] recordClasses = new Class[] {
ArrayRecord.class,
private static final int NUM_RECORDS = 512;

private interface I_RecordCreator {
Record create(RecordInputStream in);

Class<? extends Record> getRecordClass();
}
private static final class ReflectionConstructorRecordCreator implements I_RecordCreator {

private final Constructor<? extends Record> _c;
public ReflectionConstructorRecordCreator(Constructor<? extends Record> c) {
_c = c;
}
public Record create(RecordInputStream in) {
Object[] args = { in, };
try {
return _c.newInstance(args);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (t instanceof RecordFormatException) {
throw (RecordFormatException)t;
} else if (t instanceof EncryptedDocumentException) {
throw (EncryptedDocumentException)t;
} else {
throw new RecordFormatException("Unable to construct record instance" , t);
}
}
}
public Class<? extends Record> getRecordClass() {
return _c.getDeclaringClass();
}
}
/**
* A "create" method is used instead of the usual constructor if the created record might
* 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;
}
public Record create(RecordInputStream in) {
Object[] args = { in, };
try {
return (Record) _m.invoke(null, args);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RecordFormatException("Unable to construct record instance" , e.getTargetException());
}
}
@SuppressWarnings("unchecked")
public Class<? extends Record> getRecordClass() {
return (Class<? extends Record>) _m.getDeclaringClass();
}
}

private static final Class<?>[] CONSTRUCTOR_ARGS = { RecordInputStream.class, };

/**
* contains the classes for all the records we want to parse.<br/>
* Note - this most but not *every* subclass of Record.
*/
@SuppressWarnings("unchecked")
private static final Class<? extends Record>[] recordClasses = new Class[] {
ArrayRecord.class,
AutoFilterInfoRecord.class,
BackupRecord.class,
BlankRecord.class,
BOFRecord.class,
BookBoolRecord.class,
BoolErrRecord.class,
BottomMarginRecord.class,
BoundSheetRecord.class,
CalcCountRecord.class,
CalcModeRecord.class,
CFHeaderRecord.class,
CFRuleRecord.class,
ChartRecord.class,
ChartTitleFormatRecord.class,
CodepageRecord.class,
ColumnInfoRecord.class,
ContinueRecord.class,
CountryRecord.class,
CRNCountRecord.class,
CRNRecord.class,
DateWindow1904Record.class,
DBCellRecord.class,
DConRefRecord.class,
DefaultColWidthRecord.class,
DefaultRowHeightRecord.class,
DeltaRecord.class,
DimensionsRecord.class,
DrawingGroupRecord.class,
DrawingRecord.class,
DrawingSelectionRecord.class,
DSFRecord.class,
DVALRecord.class,
DVRecord.class,
EOFRecord.class,
ExtendedFormatRecord.class,
ExternalNameRecord.class,
ExternSheetRecord.class,
ExtSSTRecord.class,
FeatRecord.class,
FeatHdrRecord.class,
FilePassRecord.class,
FileSharingRecord.class,
FnGroupCountRecord.class,
FontRecord.class,
FooterRecord.class,
FormatRecord.class,
FormulaRecord.class,
GridsetRecord.class,
GutsRecord.class,
HCenterRecord.class,
HeaderRecord.class,
BlankRecord.class,
BOFRecord.class,
BookBoolRecord.class,
BoolErrRecord.class,
BottomMarginRecord.class,
BoundSheetRecord.class,
CalcCountRecord.class,
CalcModeRecord.class,
CFHeaderRecord.class,
CFHeader12Record.class,
CFRuleRecord.class,
CFRule12Record.class,
ChartRecord.class,
ChartTitleFormatRecord.class,
CodepageRecord.class,
ColumnInfoRecord.class,
ContinueRecord.class,
CountryRecord.class,
CRNCountRecord.class,
CRNRecord.class,
DateWindow1904Record.class,
DBCellRecord.class,
DConRefRecord.class,
DefaultColWidthRecord.class,
DefaultRowHeightRecord.class,
DeltaRecord.class,
DimensionsRecord.class,
DrawingGroupRecord.class,
DrawingRecord.class,
DrawingSelectionRecord.class,
DSFRecord.class,
DVALRecord.class,
DVRecord.class,
EOFRecord.class,
ExtendedFormatRecord.class,
ExternalNameRecord.class,
ExternSheetRecord.class,
ExtSSTRecord.class,
FeatRecord.class,
FeatHdrRecord.class,
FilePassRecord.class,
FileSharingRecord.class,
FnGroupCountRecord.class,
FontRecord.class,
FooterRecord.class,
FormatRecord.class,
FormulaRecord.class,
GridsetRecord.class,
GutsRecord.class,
HCenterRecord.class,
HeaderRecord.class,
HeaderFooterRecord.class,
HideObjRecord.class,
HorizontalPageBreakRecord.class,
HyperlinkRecord.class,
IndexRecord.class,
InterfaceEndRecord.class,
InterfaceHdrRecord.class,
IterationRecord.class,
LabelRecord.class,
LabelSSTRecord.class,
LeftMarginRecord.class,
LegendRecord.class,
MergeCellsRecord.class,
MMSRecord.class,
MulBlankRecord.class,
MulRKRecord.class,
NameRecord.class,
NameCommentRecord.class,
NoteRecord.class,
NumberRecord.class,
ObjectProtectRecord.class,
ObjRecord.class,
PaletteRecord.class,
PaneRecord.class,
PasswordRecord.class,
PasswordRev4Record.class,
PrecisionRecord.class,
PrintGridlinesRecord.class,
PrintHeadersRecord.class,
PrintSetupRecord.class,
ProtectionRev4Record.class,
ProtectRecord.class,
RecalcIdRecord.class,
RefModeRecord.class,
RefreshAllRecord.class,
RightMarginRecord.class,
RKRecord.class,
RowRecord.class,
SaveRecalcRecord.class,
ScenarioProtectRecord.class,
SelectionRecord.class,
SeriesRecord.class,
SeriesTextRecord.class,
SharedFormulaRecord.class,
SSTRecord.class,
StringRecord.class,
StyleRecord.class,
SupBookRecord.class,
TabIdRecord.class,
TableRecord.class,
TableStylesRecord.class,
TextObjectRecord.class,
TopMarginRecord.class,
UncalcedRecord.class,
UseSelFSRecord.class,
UserSViewBegin.class,
UserSViewEnd.class,
ValueRangeRecord.class,
VCenterRecord.class,
VerticalPageBreakRecord.class,
WindowOneRecord.class,
WindowProtectRecord.class,
WindowTwoRecord.class,
WriteAccessRecord.class,
WriteProtectRecord.class,
WSBoolRecord.class,

// chart records
BeginRecord.class,
ChartFRTInfoRecord.class,
ChartStartBlockRecord.class,
ChartEndBlockRecord.class,
// TODO ChartFormatRecord.class,
ChartStartObjectRecord.class,
ChartEndObjectRecord.class,
CatLabRecord.class,
DataFormatRecord.class,
EndRecord.class,
LinkedDataRecord.class,
SeriesToChartGroupRecord.class,

// pivot table records
DataItemRecord.class,
ExtendedPivotTableViewFieldsRecord.class,
PageItemRecord.class,
StreamIDRecord.class,
ViewDefinitionRecord.class,
ViewFieldsRecord.class,
ViewSourceRecord.class,
};

/**
* cache of the recordsToMap();
*/
private static final Map<Integer, I_RecordCreator> _recordCreatorsById = recordsToMap(recordClasses);

private static short[] _allKnownRecordSIDs;

/**
* Debug / diagnosis method<br/>
* Gets the POI implementation class for a given <tt>sid</tt>. Only a subset of the any BIFF
* records are actually interpreted by POI. A few others are known but not interpreted
* (see {@link UnknownRecord#getBiffName(int)}).
* @return the POI implementation class for the specified record <tt>sid</tt>.
* <code>null</code> if the specified record is not interpreted by POI.
*/
public static Class<? extends Record> getRecordClass(int sid) {
I_RecordCreator rc = _recordCreatorsById.get(Integer.valueOf(sid));
if (rc == null) {
return null;
}
return rc.getRecordClass();
}
/**
* create a record, if there are MUL records than multiple records
* 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
return new Record[] { null, };
}
if (record instanceof RKRecord) {
return new Record[] { convertToNumberRecord((RKRecord) record), };
}
if (record instanceof MulRKRecord) {
return convertRKRecords((MulRKRecord)record);
}
return new Record[] { record, };
}

public static Record createSingleRecord(RecordInputStream in) {
I_RecordCreator constructor = _recordCreatorsById.get(Integer.valueOf(in.getSid()));

if (constructor == null) {
return new UnknownRecord(in);
}

return constructor.create(in);
}

/**
* RK record is a slightly smaller alternative to NumberRecord
* POI likes NumberRecord better
*/
public static NumberRecord convertToNumberRecord(RKRecord rk) {
NumberRecord num = new NumberRecord();

num.setColumn(rk.getColumn());
num.setRow(rk.getRow());
num.setXFIndex(rk.getXFIndex());
num.setValue(rk.getRKNumber());
return num;
}

/**
* Converts a {@link MulRKRecord} into an equivalent array of {@link NumberRecord}s
*/
public static NumberRecord[] convertRKRecords(MulRKRecord mrk) {
NumberRecord[] mulRecs = new NumberRecord[mrk.getNumColumns()];
for (int k = 0; k < mrk.getNumColumns(); k++) {
NumberRecord nr = new NumberRecord();

nr.setColumn((short) (k + mrk.getFirstColumn()));
nr.setRow(mrk.getRow());
nr.setXFIndex(mrk.getXFAt(k));
nr.setValue(mrk.getRKNumberAt(k));
mulRecs[k] = nr;
}
return mulRecs;
}

/**
* Converts a {@link MulBlankRecord} into an equivalent array of {@link BlankRecord}s
*/
public static BlankRecord[] convertBlankRecords(MulBlankRecord mbk) {
BlankRecord[] mulRecs = new BlankRecord[mbk.getNumColumns()];
for (int k = 0; k < mbk.getNumColumns(); k++) {
BlankRecord br = new BlankRecord();

br.setColumn((short) (k + mbk.getFirstColumn()));
br.setRow(mbk.getRow());
br.setXFIndex(mbk.getXFAt(k));
mulRecs[k] = br;
}
return mulRecs;
}

/**
* @return an array of all the SIDS for all known records
*/
public static short[] getAllKnownRecordSIDs() {
if (_allKnownRecordSIDs == null) {
short[] results = new short[ _recordCreatorsById.size() ];
int i = 0;

for (Iterator<Integer> iterator = _recordCreatorsById.keySet().iterator(); iterator.hasNext(); ) {
Integer sid = iterator.next();

results[i++] = sid.shortValue();
}
Arrays.sort(results);
_allKnownRecordSIDs = results;
}

return _allKnownRecordSIDs.clone();
}

/**
* gets the record constructors and sticks them in the map by SID
* @return map of SIDs to short,short,byte[] constructors for Record classes
* most of org.apache.poi.hssf.record.*
*/
private static Map<Integer, I_RecordCreator> recordsToMap(Class<? extends Record> [] records) {
Map<Integer, I_RecordCreator> result = new HashMap<Integer, I_RecordCreator>();
Set<Class<?>> uniqueRecClasses = new HashSet<Class<?>>(records.length * 3 / 2);

for (int i = 0; i < records.length; i++) {

Class<? extends Record> recClass = records[ i ];
if(!Record.class.isAssignableFrom(recClass)) {
throw new RuntimeException("Invalid record sub-class (" + recClass.getName() + ")");
}
if(Modifier.isAbstract(recClass.getModifiers())) {
throw new RuntimeException("Invalid record class (" + recClass.getName() + ") - must not be abstract");
}
if(!uniqueRecClasses.add(recClass)) {
throw new RuntimeException("duplicate record class (" + recClass.getName() + ")");
}

int sid;
try {
sid = recClass.getField("sid").getShort(null);
} catch (Exception illegalArgumentException) {
throw new RecordFormatException(
"Unable to determine record types");
}
Integer key = Integer.valueOf(sid);
if (result.containsKey(key)) {
Class<?> prevClass = result.get(key).getRecordClass();
throw new RuntimeException("duplicate record sid 0x" + Integer.toHexString(sid).toUpperCase()
+ " for classes (" + recClass.getName() + ") and (" + prevClass.getName() + ")");
}
result.put(key, getRecordCreator(recClass));
}
// result.put(Integer.valueOf(0x0406), result.get(Integer.valueOf(0x06)));
return result;
}

private static I_RecordCreator getRecordCreator(Class<? extends Record> recClass) {
try {
Constructor<? extends Record> constructor;
constructor = recClass.getConstructor(CONSTRUCTOR_ARGS);
return new ReflectionConstructorRecordCreator(constructor);
} catch (NoSuchMethodException e) {
// fall through and look for other construction methods
}
try {
Method m = recClass.getDeclaredMethod("create", CONSTRUCTOR_ARGS);
return new ReflectionMethodRecordCreator(m);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Failed to find constructor or create method for (" + recClass.getName() + ").");
}
}
/**
* Create an array of records from an input stream
*
* @param in the InputStream from which the records will be obtained
*
* @return an array of Records created from the InputStream
*
* @exception RecordFormatException on error processing the InputStream
*/
public static List<Record> createRecords(InputStream in) throws RecordFormatException {

List<Record> records = new ArrayList<Record>(NUM_RECORDS);

RecordFactoryInputStream recStream = new RecordFactoryInputStream(in, true);

Record record;
while ((record = recStream.nextRecord())!=null) {
records.add(record);
}

return records;
}
HideObjRecord.class,
HorizontalPageBreakRecord.class,
HyperlinkRecord.class,
IndexRecord.class,
InterfaceEndRecord.class,
InterfaceHdrRecord.class,
IterationRecord.class,
LabelRecord.class,
LabelSSTRecord.class,
LeftMarginRecord.class,
LegendRecord.class,
MergeCellsRecord.class,
MMSRecord.class,
MulBlankRecord.class,
MulRKRecord.class,
NameRecord.class,
NameCommentRecord.class,
NoteRecord.class,
NumberRecord.class,
ObjectProtectRecord.class,
ObjRecord.class,
PaletteRecord.class,
PaneRecord.class,
PasswordRecord.class,
PasswordRev4Record.class,
PrecisionRecord.class,
PrintGridlinesRecord.class,
PrintHeadersRecord.class,
PrintSetupRecord.class,
ProtectionRev4Record.class,
ProtectRecord.class,
RecalcIdRecord.class,
RefModeRecord.class,
RefreshAllRecord.class,
RightMarginRecord.class,
RKRecord.class,
RowRecord.class,
SaveRecalcRecord.class,
ScenarioProtectRecord.class,
SelectionRecord.class,
SeriesRecord.class,
SeriesTextRecord.class,
SharedFormulaRecord.class,
SSTRecord.class,
StringRecord.class,
StyleRecord.class,
SupBookRecord.class,
TabIdRecord.class,
TableRecord.class,
TableStylesRecord.class,
TextObjectRecord.class,
TopMarginRecord.class,
UncalcedRecord.class,
UseSelFSRecord.class,
UserSViewBegin.class,
UserSViewEnd.class,
ValueRangeRecord.class,
VCenterRecord.class,
VerticalPageBreakRecord.class,
WindowOneRecord.class,
WindowProtectRecord.class,
WindowTwoRecord.class,
WriteAccessRecord.class,
WriteProtectRecord.class,
WSBoolRecord.class,

// chart records
BeginRecord.class,
ChartFRTInfoRecord.class,
ChartStartBlockRecord.class,
ChartEndBlockRecord.class,
// TODO ChartFormatRecord.class,
ChartStartObjectRecord.class,
ChartEndObjectRecord.class,
CatLabRecord.class,
DataFormatRecord.class,
EndRecord.class,
LinkedDataRecord.class,
SeriesToChartGroupRecord.class,

// pivot table records
DataItemRecord.class,
ExtendedPivotTableViewFieldsRecord.class,
PageItemRecord.class,
StreamIDRecord.class,
ViewDefinitionRecord.class,
ViewFieldsRecord.class,
ViewSourceRecord.class,
};

/**
* cache of the recordsToMap();
*/
private static final Map<Integer, I_RecordCreator> _recordCreatorsById = recordsToMap(recordClasses);

private static short[] _allKnownRecordSIDs;

/**
* Debug / diagnosis method<br/>
* Gets the POI implementation class for a given <tt>sid</tt>. Only a subset of the any BIFF
* records are actually interpreted by POI. A few others are known but not interpreted
* (see {@link UnknownRecord#getBiffName(int)}).
* @return the POI implementation class for the specified record <tt>sid</tt>.
* <code>null</code> if the specified record is not interpreted by POI.
*/
public static Class<? extends Record> getRecordClass(int sid) {
I_RecordCreator rc = _recordCreatorsById.get(Integer.valueOf(sid));
if (rc == null) {
return null;
}
return rc.getRecordClass();
}
/**
* create a record, if there are MUL records than multiple records
* 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
return new Record[] { null, };
}
if (record instanceof RKRecord) {
return new Record[] { convertToNumberRecord((RKRecord) record), };
}
if (record instanceof MulRKRecord) {
return convertRKRecords((MulRKRecord)record);
}
return new Record[] { record, };
}

public static Record createSingleRecord(RecordInputStream in) {
I_RecordCreator constructor = _recordCreatorsById.get(Integer.valueOf(in.getSid()));

if (constructor == null) {
return new UnknownRecord(in);
}

return constructor.create(in);
}

/**
* RK record is a slightly smaller alternative to NumberRecord
* POI likes NumberRecord better
*/
public static NumberRecord convertToNumberRecord(RKRecord rk) {
NumberRecord num = new NumberRecord();

num.setColumn(rk.getColumn());
num.setRow(rk.getRow());
num.setXFIndex(rk.getXFIndex());
num.setValue(rk.getRKNumber());
return num;
}

/**
* Converts a {@link MulRKRecord} into an equivalent array of {@link NumberRecord}s
*/
public static NumberRecord[] convertRKRecords(MulRKRecord mrk) {
NumberRecord[] mulRecs = new NumberRecord[mrk.getNumColumns()];
for (int k = 0; k < mrk.getNumColumns(); k++) {
NumberRecord nr = new NumberRecord();

nr.setColumn((short) (k + mrk.getFirstColumn()));
nr.setRow(mrk.getRow());
nr.setXFIndex(mrk.getXFAt(k));
nr.setValue(mrk.getRKNumberAt(k));
mulRecs[k] = nr;
}
return mulRecs;
}

/**
* Converts a {@link MulBlankRecord} into an equivalent array of {@link BlankRecord}s
*/
public static BlankRecord[] convertBlankRecords(MulBlankRecord mbk) {
BlankRecord[] mulRecs = new BlankRecord[mbk.getNumColumns()];
for (int k = 0; k < mbk.getNumColumns(); k++) {
BlankRecord br = new BlankRecord();

br.setColumn((short) (k + mbk.getFirstColumn()));
br.setRow(mbk.getRow());
br.setXFIndex(mbk.getXFAt(k));
mulRecs[k] = br;
}
return mulRecs;
}

/**
* @return an array of all the SIDS for all known records
*/
public static short[] getAllKnownRecordSIDs() {
if (_allKnownRecordSIDs == null) {
short[] results = new short[ _recordCreatorsById.size() ];
int i = 0;

for (Iterator<Integer> iterator = _recordCreatorsById.keySet().iterator(); iterator.hasNext(); ) {
Integer sid = iterator.next();

results[i++] = sid.shortValue();
}
Arrays.sort(results);
_allKnownRecordSIDs = results;
}

return _allKnownRecordSIDs.clone();
}

/**
* gets the record constructors and sticks them in the map by SID
* @return map of SIDs to short,short,byte[] constructors for Record classes
* most of org.apache.poi.hssf.record.*
*/
private static Map<Integer, I_RecordCreator> recordsToMap(Class<? extends Record> [] records) {
Map<Integer, I_RecordCreator> result = new HashMap<Integer, I_RecordCreator>();
Set<Class<?>> uniqueRecClasses = new HashSet<Class<?>>(records.length * 3 / 2);

for (int i = 0; i < records.length; i++) {

Class<? extends Record> recClass = records[ i ];
if(!Record.class.isAssignableFrom(recClass)) {
throw new RuntimeException("Invalid record sub-class (" + recClass.getName() + ")");
}
if(Modifier.isAbstract(recClass.getModifiers())) {
throw new RuntimeException("Invalid record class (" + recClass.getName() + ") - must not be abstract");
}
if(!uniqueRecClasses.add(recClass)) {
throw new RuntimeException("duplicate record class (" + recClass.getName() + ")");
}

int sid;
try {
sid = recClass.getField("sid").getShort(null);
} catch (Exception illegalArgumentException) {
throw new RecordFormatException(
"Unable to determine record types");
}
Integer key = Integer.valueOf(sid);
if (result.containsKey(key)) {
Class<?> prevClass = result.get(key).getRecordClass();
throw new RuntimeException("duplicate record sid 0x" + Integer.toHexString(sid).toUpperCase()
+ " for classes (" + recClass.getName() + ") and (" + prevClass.getName() + ")");
}
result.put(key, getRecordCreator(recClass));
}
// result.put(Integer.valueOf(0x0406), result.get(Integer.valueOf(0x06)));
return result;
}

private static I_RecordCreator getRecordCreator(Class<? extends Record> recClass) {
try {
Constructor<? extends Record> constructor;
constructor = recClass.getConstructor(CONSTRUCTOR_ARGS);
return new ReflectionConstructorRecordCreator(constructor);
} catch (NoSuchMethodException e) {
// fall through and look for other construction methods
}
try {
Method m = recClass.getDeclaredMethod("create", CONSTRUCTOR_ARGS);
return new ReflectionMethodRecordCreator(m);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Failed to find constructor or create method for (" + recClass.getName() + ").");
}
}
/**
* Create an array of records from an input stream
*
* @param in the InputStream from which the records will be obtained
*
* @return an array of Records created from the InputStream
*
* @exception RecordFormatException on error processing the InputStream
*/
public static List<Record> createRecords(InputStream in) throws RecordFormatException {

List<Record> records = new ArrayList<Record>(NUM_RECORDS);

RecordFactoryInputStream recStream = new RecordFactoryInputStream(in, true);

Record record;
while ((record = recStream.nextRecord())!=null) {
records.add(record);
}

return records;
}
}

+ 10
- 1
src/java/org/apache/poi/hssf/record/RecordInputStream.java Просмотреть файл

@@ -52,8 +52,17 @@ 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();
}
}

/** Header {@link LittleEndianInput} facet of the wrapped {@link InputStream} */

+ 6
- 0
src/java/org/apache/poi/hssf/record/RowRecord.java Просмотреть файл

@@ -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();

+ 11
- 8
src/java/org/apache/poi/hssf/record/UnknownRecord.java Просмотреть файл

@@ -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:

+ 236
- 204
src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java Просмотреть файл

@@ -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;
@@ -38,212 +42,240 @@ import org.apache.poi.util.POILogger;
* <p>Note that Excel versions before 2007 can only cope with a maximum of 3
* Conditional Formatting rules per sheet. Excel 2007 or newer can cope with
* unlimited numbers, as can Apache OpenOffice. This is an Excel limitation,
* not a file format one.</p>
* not a file format one.</p>
*/
public final class CFRecordsAggregate extends RecordAggregate {
/** Excel 97-2003 allows up to 3 conditional formating rules */
private static final int MAX_97_2003_CONDTIONAL_FORMAT_RULES = 3;
private static final POILogger logger = POILogFactory.getLogger(CFRecordsAggregate.class);

private final CFHeaderRecord header;

/** List of CFRuleRecord objects */
private final List<CFRuleRecord> rules;

private CFRecordsAggregate(CFHeaderRecord pHeader, CFRuleRecord[] pRules) {
if(pHeader == null) {
throw new IllegalArgumentException("header must not be null");
}
if(pRules == null) {
throw new IllegalArgumentException("rules must not be null");
}
if(pRules.length > MAX_97_2003_CONDTIONAL_FORMAT_RULES) {
logger.log(POILogger.WARN, "Excel versions before 2007 require that "
+ "No more than " + MAX_97_2003_CONDTIONAL_FORMAT_RULES
+ " rules may be specified, " + pRules.length + " were found,"
+ " this file will cause problems with old Excel versions");
}
if (pRules.length != pHeader.getNumberOfConditionalFormats()) {
throw new RuntimeException("Mismatch number of rules");
}
header = pHeader;
rules = new ArrayList<CFRuleRecord>(3);
for (int i = 0; i < pRules.length; i++) {
rules.add(pRules[i]);
}
}

public CFRecordsAggregate(CellRangeAddress[] regions, CFRuleRecord[] rules) {
this(new CFHeaderRecord(regions, rules.length), rules);
}

/**
* Create CFRecordsAggregate from a list of CF Records
* @param rs - the stream to read from
* @return CFRecordsAggregate object
*/
public static CFRecordsAggregate createCFAggregate(RecordStream rs) {
Record rec = rs.getNext();
if (rec.getSid() != CFHeaderRecord.sid) {
throw new IllegalStateException("next record sid was " + rec.getSid()
+ " instead of " + CFHeaderRecord.sid + " as expected");
}

CFHeaderRecord header = (CFHeaderRecord)rec;
int nRules = header.getNumberOfConditionalFormats();

CFRuleRecord[] rules = new CFRuleRecord[nRules];
for (int i = 0; i < rules.length; i++) {
rules[i] = (CFRuleRecord) rs.getNext();
}
return new CFRecordsAggregate(header, rules);
}

/**
* Create a deep clone of the record
*/
public CFRecordsAggregate cloneCFAggregate()
{
CFRuleRecord[] newRecs = new CFRuleRecord[rules.size()];
for (int i = 0; i < newRecs.length; i++) {
newRecs[i] = (CFRuleRecord) getRule(i).clone();
}
return new CFRecordsAggregate((CFHeaderRecord) header.clone(), newRecs);
}

/**
* @return the header. Never <code>null</code>.
*/
public CFHeaderRecord getHeader()
{
return header;
}
private void checkRuleIndex(int idx) {
if(idx < 0 || idx >= rules.size()) {
throw new IllegalArgumentException("Bad rule record index (" + idx
+ ") nRules=" + rules.size());
}
}
public CFRuleRecord getRule(int idx) {
checkRuleIndex(idx);
return rules.get(idx);
}
public void setRule(int idx, CFRuleRecord r) {
if (r == null) {
throw new IllegalArgumentException("r must not be null");
}
checkRuleIndex(idx);
rules.set(idx, r);
}
public void addRule(CFRuleRecord r) {
if (r == null) {
throw new IllegalArgumentException("r must not be null");
}
if(rules.size() >= MAX_97_2003_CONDTIONAL_FORMAT_RULES) {
/** Excel 97-2003 allows up to 3 conditional formating rules */
private static final int MAX_97_2003_CONDTIONAL_FORMAT_RULES = 3;
private static final POILogger logger = POILogFactory.getLogger(CFRecordsAggregate.class);

private final CFHeaderBase header;

/** List of CFRuleRecord objects */
private final List<CFRuleBase> rules;

private CFRecordsAggregate(CFHeaderBase pHeader, CFRuleBase[] pRules) {
if(pHeader == null) {
throw new IllegalArgumentException("header must not be null");
}
if(pRules == null) {
throw new IllegalArgumentException("rules must not be null");
}
if(pRules.length > MAX_97_2003_CONDTIONAL_FORMAT_RULES) {
logger.log(POILogger.WARN, "Excel versions before 2007 require that "
+ "No more than " + MAX_97_2003_CONDTIONAL_FORMAT_RULES
+ " rules may be specified, " + pRules.length + " were found,"
+ " this file will cause problems with old Excel versions");
}
if (pRules.length != pHeader.getNumberOfConditionalFormats()) {
throw new RuntimeException("Mismatch number of rules");
}
header = pHeader;
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, 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);
}

/**
* Create CFRecordsAggregate from a list of CF Records
* @param rs - the stream to read from
* @return CFRecordsAggregate object
*/
public static CFRecordsAggregate createCFAggregate(RecordStream rs) {
Record rec = rs.getNext();
if (rec.getSid() != CFHeaderRecord.sid &&
rec.getSid() != CFHeader12Record.sid) {
throw new IllegalStateException("next record sid was " + rec.getSid()
+ " instead of " + CFHeaderRecord.sid + " or " +
CFHeader12Record.sid + " as expected");
}

CFHeaderBase header = (CFHeaderBase)rec;
int nRules = header.getNumberOfConditionalFormats();

CFRuleBase[] rules = new CFRuleBase[nRules];
for (int i = 0; i < rules.length; i++) {
rules[i] = (CFRuleBase) rs.getNext();
}

return new CFRecordsAggregate(header, rules);
}

/**
* Create a deep clone of the record
*/
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((CFHeaderBase)header.clone(), newRecs);
}

/**
* @return the header. Never <code>null</code>.
*/
public CFHeaderBase getHeader() {
return header;
}

private void checkRuleIndex(int idx) {
if(idx < 0 || idx >= rules.size()) {
throw new IllegalArgumentException("Bad rule record index (" + idx
+ ") nRules=" + rules.size());
}
}
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, CFRuleBase r) {
if (r == null) {
throw new IllegalArgumentException("r must not be null");
}
checkRuleIndex(idx);
checkRuleType(r);
rules.set(idx, r);
}
public void addRule(CFRuleBase r) {
if (r == null) {
throw new IllegalArgumentException("r must not be null");
}
if(rules.size() >= MAX_97_2003_CONDTIONAL_FORMAT_RULES) {
logger.log(POILogger.WARN, "Excel versions before 2007 cannot cope with"
+ " any more than " + MAX_97_2003_CONDTIONAL_FORMAT_RULES
+ " any more than " + MAX_97_2003_CONDTIONAL_FORMAT_RULES
+ " - this file will cause problems with old Excel versions");
}
rules.add(r);
header.setNumberOfConditionalFormats(rules.size());
}
public int getNumberOfRules() {
return rules.size();
}

/**
* String representation of CFRecordsAggregate
*/
public String toString()
{
StringBuffer buffer = new StringBuffer();

buffer.append("[CF]\n");
if( header != null )
{
buffer.append(header.toString());
}
for(int i=0; i<rules.size(); i++)
{
CFRuleRecord cfRule = rules.get(i);
buffer.append(cfRule.toString());
}
buffer.append("[/CF]\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);
rv.visitRecord(rule);
}
}

/**
* @return <code>false</code> if this whole {@link CFHeaderRecord} / {@link CFRuleRecord}s should be deleted
*/
public boolean updateFormulasAfterCellShift(FormulaShifter shifter, int currentExternSheetIx) {
CellRangeAddress[] cellRanges = header.getCellRanges();
boolean changed = false;
List<CellRangeAddress> temp = new ArrayList<CellRangeAddress>();
for (int i = 0; i < cellRanges.length; i++) {
CellRangeAddress craOld = cellRanges[i];
CellRangeAddress craNew = shiftRange(shifter, craOld, currentExternSheetIx);
if (craNew == null) {
changed = true;
continue;
}
temp.add(craNew);
if (craNew != craOld) {
changed = true;
}
}

if (changed) {
int nRanges = temp.size();
if (nRanges == 0) {
return false;
}
CellRangeAddress[] newRanges = new CellRangeAddress[nRanges];
temp.toArray(newRanges);
header.setCellRanges(newRanges);
}
for(int i=0; i<rules.size(); i++) {
CFRuleRecord rule = rules.get(i);
Ptg[] ptgs;
ptgs = rule.getParsedExpression1();
if (ptgs != null && shifter.adjustFormula(ptgs, currentExternSheetIx)) {
rule.setParsedExpression1(ptgs);
}
ptgs = rule.getParsedExpression2();
if (ptgs != null && shifter.adjustFormula(ptgs, currentExternSheetIx)) {
rule.setParsedExpression2(ptgs);
}
}
return true;
}

private static CellRangeAddress shiftRange(FormulaShifter shifter, CellRangeAddress cra, int currentExternSheetIx) {
// FormulaShifter works well in terms of Ptgs - so convert CellRangeAddress to AreaPtg (and back) here
AreaPtg aptg = new AreaPtg(cra.getFirstRow(), cra.getLastRow(), cra.getFirstColumn(), cra.getLastColumn(), false, false, false, false);
Ptg[] ptgs = { aptg, };
if (!shifter.adjustFormula(ptgs, currentExternSheetIx)) {
return cra;
}
Ptg ptg0 = ptgs[0];
if (ptg0 instanceof AreaPtg) {
AreaPtg bptg = (AreaPtg) ptg0;
return new CellRangeAddress(bptg.getFirstRow(), bptg.getLastRow(), bptg.getFirstColumn(), bptg.getLastColumn());
}
if (ptg0 instanceof AreaErrPtg) {
return null;
}
throw new IllegalStateException("Unexpected shifted ptg class (" + ptg0.getClass().getName() + ")");
}
}
checkRuleType(r);
rules.add(r);
header.setNumberOfConditionalFormats(rules.size());
}
public int getNumberOfRules() {
return rules.size();
}

/**
* String representation of CFRecordsAggregate
*/
public String toString() {
StringBuffer buffer = new StringBuffer();
String type = "CF";
if (header instanceof CFHeader12Record) {
type = "CF12";
}

buffer.append("[").append(type).append("]\n");
if( header != null ) {
buffer.append(header.toString());
}
for(int i=0; i<rules.size(); i++) {
CFRuleBase cfRule = rules.get(i);
buffer.append(cfRule.toString());
}
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++) {
CFRuleBase rule = rules.get(i);
rv.visitRecord(rule);
}
}

/**
* @return <code>false</code> if this whole {@link CFHeaderRecord} / {@link CFRuleRecord}s should be deleted
*/
public boolean updateFormulasAfterCellShift(FormulaShifter shifter, int currentExternSheetIx) {
CellRangeAddress[] cellRanges = header.getCellRanges();
boolean changed = false;
List<CellRangeAddress> temp = new ArrayList<CellRangeAddress>();
for (int i = 0; i < cellRanges.length; i++) {
CellRangeAddress craOld = cellRanges[i];
CellRangeAddress craNew = shiftRange(shifter, craOld, currentExternSheetIx);
if (craNew == null) {
changed = true;
continue;
}
temp.add(craNew);
if (craNew != craOld) {
changed = true;
}
}

if (changed) {
int nRanges = temp.size();
if (nRanges == 0) {
return false;
}
CellRangeAddress[] newRanges = new CellRangeAddress[nRanges];
temp.toArray(newRanges);
header.setCellRanges(newRanges);
}

for(int i=0; i<rules.size(); i++) {
CFRuleBase rule = rules.get(i);
Ptg[] ptgs;
ptgs = rule.getParsedExpression1();
if (ptgs != null && shifter.adjustFormula(ptgs, currentExternSheetIx)) {
rule.setParsedExpression1(ptgs);
}
ptgs = rule.getParsedExpression2();
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;
}

private static CellRangeAddress shiftRange(FormulaShifter shifter, CellRangeAddress cra, int currentExternSheetIx) {
// FormulaShifter works well in terms of Ptgs - so convert CellRangeAddress to AreaPtg (and back) here
AreaPtg aptg = new AreaPtg(cra.getFirstRow(), cra.getLastRow(), cra.getFirstColumn(), cra.getLastColumn(), false, false, false, false);
Ptg[] ptgs = { aptg, };

if (!shifter.adjustFormula(ptgs, currentExternSheetIx)) {
return cra;
}
Ptg ptg0 = ptgs[0];
if (ptg0 instanceof AreaPtg) {
AreaPtg bptg = (AreaPtg) ptg0;
return new CellRangeAddress(bptg.getFirstRow(), bptg.getLastRow(), bptg.getFirstColumn(), bptg.getLastColumn());
}
if (ptg0 instanceof AreaErrPtg) {
return null;
}
throw new IllegalStateException("Unexpected shifted ptg class (" + ptg0.getClass().getName() + ")");
}
}

+ 4
- 4
src/java/org/apache/poi/hssf/record/aggregates/ConditionalFormattingTable.java Просмотреть файл

@@ -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;
}

+ 3
- 3
src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java Просмотреть файл

@@ -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

+ 173
- 182
src/java/org/apache/poi/hssf/record/cf/CellRangeUtil.java Просмотреть файл

@@ -23,97 +23,93 @@ 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
{
private CellRangeUtil() {
// no instance of this class
}
public static final int NO_INTERSECTION = 1;
public static final int OVERLAP = 2;
/** first range is within the second range */
public static final int INSIDE = 3;
/** first range encloses or is equal to the second */
public static final int ENCLOSES = 4;
/**
* Intersect this range with the specified range.
*
* @param crB - the specified range
* @return code which reflects how the specified range is related to this range.<br/>
* Possible return codes are:
* NO_INTERSECTION - the specified range is outside of this range;<br/>
* OVERLAP - both ranges partially overlap;<br/>
* INSIDE - the specified range is inside of this one<br/>
* ENCLOSES - the specified range encloses (possibly exactly the same as) this range<br/>
*/
public static int intersect(CellRangeAddress crA, CellRangeAddress crB )
{
int firstRow = crB.getFirstRow();
int lastRow = crB.getLastRow();
int firstCol = crB.getFirstColumn();
int lastCol = crB.getLastColumn();
if
(
public final class CellRangeUtil {
private CellRangeUtil() {
// no instance of this class
}

public static final int NO_INTERSECTION = 1;
public static final int OVERLAP = 2;
/** first range is within the second range */
public static final int INSIDE = 3;
/** first range encloses or is equal to the second */
public static final int ENCLOSES = 4;

/**
* Intersect this range with the specified range.
*
* @param crB - the specified range
* @return code which reflects how the specified range is related to this range.<br/>
* Possible return codes are:
* NO_INTERSECTION - the specified range is outside of this range;<br/>
* OVERLAP - both ranges partially overlap;<br/>
* INSIDE - the specified range is inside of this one<br/>
* ENCLOSES - the specified range encloses (possibly exactly the same as) this range<br/>
*/
public static int intersect(CellRangeAddress crA, CellRangeAddress crB )
{

int firstRow = crB.getFirstRow();
int lastRow = crB.getLastRow();
int firstCol = crB.getFirstColumn();
int lastCol = crB.getLastColumn();

if
(
gt(crA.getFirstRow(),lastRow) ||
lt(crA.getLastRow(),firstRow) ||
gt(crA.getFirstColumn(),lastCol) ||
lt(crA.getLastColumn(),firstCol)
)
{
return NO_INTERSECTION;
}
else if( contains(crA, crB) )
{
return INSIDE;
}
else if( contains(crB, crA))
{
return ENCLOSES;
}
else
{
return OVERLAP;
}
}
/**
* Do all possible cell merges between cells of the list so that:<br>
* <li>if a cell range is completely inside of another cell range, it gets removed from the list
* <li>if two cells have a shared border, merge them into one bigger cell range
* @param cellRanges
* @return updated List of cell ranges
*/
public static CellRangeAddress[] mergeCellRanges(CellRangeAddress[] cellRanges) {
if(cellRanges.length < 1) {
return cellRanges;
}
)
{
return NO_INTERSECTION;
}
else if( contains(crA, crB) )
{
return INSIDE;
}
else if( contains(crB, crA))
{
return ENCLOSES;
}
else
{
return OVERLAP;
}
}

/**
* Do all possible cell merges between cells of the list so that:<br>
* <li>if a cell range is completely inside of another cell range, it gets removed from the list
* <li>if two cells have a shared border, merge them into one bigger cell range
* @param cellRanges
* @return updated List of cell ranges
*/
public static CellRangeAddress[] mergeCellRanges(CellRangeAddress[] cellRanges) {
if(cellRanges.length < 1) {
return cellRanges;
}

List<CellRangeAddress> lst = new ArrayList<CellRangeAddress>();
for(CellRangeAddress cr : cellRanges) {
lst.add(cr);
}
List<CellRangeAddress> temp = mergeCellRanges(lst);
return toArray(temp);
}
return toArray(temp);
}

private static List<CellRangeAddress> mergeCellRanges(List<CellRangeAddress> cellRangeList)
{
// loop until either only one item is left or we did not merge anything any more
private static List<CellRangeAddress> mergeCellRanges(List<CellRangeAddress> cellRangeList)
{
// loop until either only one item is left or we did not merge anything any more
while (cellRangeList.size() > 1) {
boolean somethingGotMerged = false;

// look at all cell-ranges
for (int i = 0; i < cellRangeList.size(); i++) {
CellRangeAddress range1 = cellRangeList.get(i);
// compare each cell range to all other cell-ranges
for (int j = i + 1; j < cellRangeList.size(); j++) {
CellRangeAddress range2 = cellRangeList.get(j);
@@ -139,16 +135,16 @@ public final class CellRangeUtil
}
}

return cellRangeList;
}
/**
* @return the new range(s) to replace the supplied ones. <code>null</code> if no merge is possible
*/
private static CellRangeAddress[] mergeRanges(CellRangeAddress range1, CellRangeAddress range2) {
int x = intersect(range1, range2);
switch(x)
{
return cellRangeList;
}
/**
* @return the new range(s) to replace the supplied ones. <code>null</code> if no merge is possible
*/
private static CellRangeAddress[] mergeRanges(CellRangeAddress range1, CellRangeAddress range2) {
int x = intersect(range1, range2);
switch(x)
{
case CellRangeUtil.NO_INTERSECTION:
// nothing in common: at most they could be adjacent to each other and thus form a single bigger area
if(hasExactSharedBorder(range1, range2)) {
@@ -171,108 +167,103 @@ 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;
}
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.
*
* @param crB
* @return true if this cell range contains the argument range inside if it's area
*/
public static boolean contains(CellRangeAddress crA, CellRangeAddress crB)
{
int firstRow = crB.getFirstRow();
int lastRow = crB.getLastRow();
int firstCol = crB.getFirstColumn();
int lastCol = crB.getLastColumn();
return le(crA.getFirstRow(), firstRow) && ge(crA.getLastRow(), lastRow)
&& le(crA.getFirstColumn(), firstCol) && ge(crA.getLastColumn(), lastCol);
}

/**
* Check if the two cell ranges have a shared border.
*
* @return <code>true</code> if the ranges have a complete shared border (i.e.
* the two ranges together make a simple rectangular region.
*/
public static boolean hasExactSharedBorder(CellRangeAddress crA, CellRangeAddress crB) {
int oFirstRow = crB.getFirstRow();
int oLastRow = crB.getLastRow();
int oFirstCol = crB.getFirstColumn();
int oLastCol = crB.getLastColumn();

/**
* Check if the specified range is located inside of this cell range.
*
* @param crB
* @return true if this cell range contains the argument range inside if it's area
*/
public static boolean contains(CellRangeAddress crA, CellRangeAddress crB)
{
int firstRow = crB.getFirstRow();
int lastRow = crB.getLastRow();
int firstCol = crB.getFirstColumn();
int lastCol = crB.getLastColumn();
return le(crA.getFirstRow(), firstRow) && ge(crA.getLastRow(), lastRow)
&& le(crA.getFirstColumn(), firstCol) && ge(crA.getLastColumn(), lastCol);
}
/**
* Check if the two cell ranges have a shared border.
*
* @return <code>true</code> if the ranges have a complete shared border (i.e.
* the two ranges together make a simple rectangular region.
*/
public static boolean hasExactSharedBorder(CellRangeAddress crA, CellRangeAddress crB) {
int oFirstRow = crB.getFirstRow();
int oLastRow = crB.getLastRow();
int oFirstCol = crB.getFirstColumn();
int oLastCol = crB.getLastColumn();
if (crA.getFirstRow() > 0 && crA.getFirstRow()-1 == oLastRow ||
oFirstRow > 0 && oFirstRow-1 == crA.getLastRow()) {
// ranges have a horizontal border in common
// make sure columns are identical:
return crA.getFirstColumn() == oFirstCol && crA.getLastColumn() == oLastCol;
}
if (crA.getFirstRow() > 0 && crA.getFirstRow()-1 == oLastRow ||
oFirstRow > 0 && oFirstRow-1 == crA.getLastRow()) {
// ranges have a horizontal border in common
// make sure columns are identical:
return crA.getFirstColumn() == oFirstCol && crA.getLastColumn() == oLastCol;
}

if (crA.getFirstColumn()>0 && crA.getFirstColumn() - 1 == oLastCol ||
oFirstCol>0 && crA.getLastColumn() == oFirstCol -1) {
// ranges have a vertical border in common
// make sure rows are identical:
return crA.getFirstRow() == oFirstRow && crA.getLastRow() == oLastRow;
}
return false;
}
/**
* Create an enclosing CellRange for the two cell ranges.
*
* @return enclosing CellRange
*/
public static CellRangeAddress createEnclosingCellRange(CellRangeAddress crA, CellRangeAddress crB) {
if( crB == null) {
return crA.copy();
}
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()
);
}
/**
* @return true if a < b
*/
private static boolean lt(int a, int b)
{
return a == -1 ? false : (b == -1 ? true : a < b);
}
/**
* @return true if a <= b
*/
private static boolean le(int a, int b)
{
return a == b || lt(a,b);
}
/**
* @return true if a > b
*/
private static boolean gt(int a, int b)
{
return lt(b,a);
}
if (crA.getFirstColumn()>0 && crA.getFirstColumn() - 1 == oLastCol ||
oFirstCol>0 && crA.getLastColumn() == oFirstCol -1) {
// ranges have a vertical border in common
// make sure rows are identical:
return crA.getFirstRow() == oFirstRow && crA.getLastRow() == oLastRow;
}
return false;
}

/**
* @return true if a >= b
*/
private static boolean ge(int a, int b)
{
return !lt(a,b);
}
/**
* Create an enclosing CellRange for the two cell ranges.
*
* @return enclosing CellRange
*/
public static CellRangeAddress createEnclosingCellRange(CellRangeAddress crA, CellRangeAddress crB) {
if( crB == null) {
return crA.copy();
}

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()
);
}

/**
* @return true if a < b
*/
private static boolean lt(int a, int b)
{
return a == -1 ? false : (b == -1 ? true : a < b);
}

/**
* @return true if a <= b
*/
private static boolean le(int a, int b)
{
return a == b || lt(a,b);
}

/**
* @return true if a > b
*/
private static boolean gt(int a, int b)
{
return lt(b,a);
}

/**
* @return true if a >= b
*/
private static boolean ge(int a, int b)
{
return !lt(a,b);
}
}

+ 518
- 520
src/java/org/apache/poi/hssf/record/cf/FontFormatting.java
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


+ 139
- 0
src/java/org/apache/poi/hssf/record/cf/IconMultiStateFormatting.java Просмотреть файл

@@ -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);
}
}
}

+ 4
- 2
src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java Просмотреть файл

@@ -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
*

+ 146
- 0
src/java/org/apache/poi/hssf/record/cf/Threshold.java Просмотреть файл

@@ -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
}
}

+ 58
- 50
src/java/org/apache/poi/hssf/record/common/FtrHeader.java Просмотреть файл

@@ -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;

/**
@@ -28,62 +29,69 @@ import org.apache.poi.util.LittleEndianOutput;
* beyond those of a traditional record.
*/
public final class FtrHeader {
/** This MUST match the type on the containing record */
private short recordType;
/** This is a FrtFlags */
private short grbitFrt;
/** MUST be 8 bytes and all zero */
private byte[] reserved;
/** This MUST match the type on the containing record */
private short recordType;
/** This is a FrtFlags */
private short grbitFrt;
/** The range of cells the parent record applies to, or 0 if N/A */
private CellRangeAddress associatedRange;

public FtrHeader() {
reserved = new byte[8];
}
public FtrHeader() {
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);
}
public FtrHeader(RecordInputStream in) {
recordType = in.readShort();
grbitFrt = in.readShort();

public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(" [FUTURE HEADER]\n");
buffer.append(" Type " + recordType);
buffer.append(" Flags " + grbitFrt);
buffer.append(" [/FUTURE HEADER]\n");
return buffer.toString();
}
associatedRange = new CellRangeAddress(in);
}

public void serialize(LittleEndianOutput out) {
out.writeShort(recordType);
out.writeShort(grbitFrt);
out.write(reserved);
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(" [FUTURE HEADER]\n");
buffer.append(" Type " + recordType);
buffer.append(" Flags " + grbitFrt);
buffer.append(" [/FUTURE HEADER]\n");
return buffer.toString();
}

public static int getDataSize() {
return 12;
}
public void serialize(LittleEndianOutput out) {
out.writeShort(recordType);
out.writeShort(grbitFrt);
associatedRange.serialize(out);
}

public short getRecordType() {
return recordType;
}
public void setRecordType(short recordType) {
this.recordType = recordType;
}
public static int getDataSize() {
return 12;
}

public short getGrbitFrt() {
return grbitFrt;
}
public void setGrbitFrt(short grbitFrt) {
this.grbitFrt = grbitFrt;
}
public short getRecordType() {
return recordType;
}
public void setRecordType(short recordType) {
this.recordType = recordType;
}

public byte[] getReserved() {
return reserved;
}
public void setReserved(byte[] reserved) {
this.reserved = reserved;
}
public short getGrbitFrt() {
return grbitFrt;
}
public void setGrbitFrt(short grbitFrt) {
this.grbitFrt = grbitFrt;
}

public CellRangeAddress getAssociatedRange() {
return associatedRange;
}
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;
}
}

+ 30
- 0
src/java/org/apache/poi/hssf/record/common/FutureRecord.java Просмотреть файл

@@ -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();
}

+ 2
- 2
src/java/org/apache/poi/hssf/record/crypto/Biff8DecryptingStream.java Просмотреть файл

@@ -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());

+ 236
- 186
src/java/org/apache/poi/hssf/usermodel/HSSFBorderFormatting.java Просмотреть файл

@@ -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;
private final BorderFormatting borderFormatting;
protected HSSFBorderFormatting(CFRuleRecord cfRuleRecord)
{
this.cfRuleRecord = cfRuleRecord;
this.borderFormatting = cfRuleRecord.getBorderFormatting();
}

protected BorderFormatting getBorderFormattingBlock()
{
return borderFormatting;
}

public short getBorderBottom()
{
return (short)borderFormatting.getBorderBottom();
}

public short getBorderDiagonal()
{
return (short)borderFormatting.getBorderDiagonal();
}

public short getBorderLeft()
{
return (short)borderFormatting.getBorderLeft();
}

public short getBorderRight()
{
return (short)borderFormatting.getBorderRight();
}

public short getBorderTop()
{
return (short)borderFormatting.getBorderTop();
}

public short getBottomBorderColor()
{
return (short)borderFormatting.getBottomBorderColor();
}

public short getDiagonalBorderColor()
{
return (short)borderFormatting.getDiagonalBorderColor();
}

public short getLeftBorderColor()
{
return (short)borderFormatting.getLeftBorderColor();
}

public short getRightBorderColor()
{
return (short)borderFormatting.getRightBorderColor();
}

public short getTopBorderColor()
{
return (short)borderFormatting.getTopBorderColor();
}

public boolean isBackwardDiagonalOn()
{
return borderFormatting.isBackwardDiagonalOn();
}

public boolean isForwardDiagonalOn()
{
return borderFormatting.isForwardDiagonalOn();
}

public void setBackwardDiagonalOn(boolean on)
{
borderFormatting.setBackwardDiagonalOn(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)
{
borderFormatting.setForwardDiagonalOn(on);
if( on )
{
cfRuleRecord.setBottomLeftTopRightBorderModified(on);
}
}

public void setLeftBorderColor(short color)
{
borderFormatting.setLeftBorderColor(color);
if( color != 0)
{
cfRuleRecord.setLeftBorderModified(true);
}
}

public void setRightBorderColor(short color)
{
borderFormatting.setRightBorderColor(color);
if( color != 0)
{
cfRuleRecord.setRightBorderModified(true);
}
}

public void setTopBorderColor(short color)
{
borderFormatting.setTopBorderColor(color);
if( color != 0)
{
cfRuleRecord.setTopBorderModified(true);
}
}
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(CFRuleBase cfRuleRecord, HSSFWorkbook workbook) {
this.workbook = workbook;
this.cfRuleRecord = cfRuleRecord;
this.borderFormatting = cfRuleRecord.getBorderFormatting();
}

protected BorderFormatting getBorderFormattingBlock() {
return borderFormatting;
}

public short getBorderBottom() {
return (short)borderFormatting.getBorderBottom();
}

public short getBorderDiagonal() {
return (short)borderFormatting.getBorderDiagonal();
}

public short getBorderLeft() {
return (short)borderFormatting.getBorderLeft();
}

public short getBorderRight() {
return (short)borderFormatting.getBorderRight();
}

public short getBorderTop() {
return (short)borderFormatting.getBorderTop();
}

public short getBottomBorderColor() {
return (short)borderFormatting.getBottomBorderColor();
}
public HSSFColor getBottomBorderColorColor() {
return workbook.getCustomPalette().getColor(
borderFormatting.getBottomBorderColor()
);
}

public short getDiagonalBorderColor() {
return (short)borderFormatting.getDiagonalBorderColor();
}
public HSSFColor getDiagonalBorderColorColor() {
return workbook.getCustomPalette().getColor(
borderFormatting.getDiagonalBorderColor()
);
}

public short getLeftBorderColor() {
return (short)borderFormatting.getLeftBorderColor();
}
public HSSFColor getLeftBorderColorColor() {
return workbook.getCustomPalette().getColor(
borderFormatting.getLeftBorderColor()
);
}

public short getRightBorderColor() {
return (short)borderFormatting.getRightBorderColor();
}
public HSSFColor getRightBorderColorColor() {
return workbook.getCustomPalette().getColor(
borderFormatting.getRightBorderColor()
);
}

public short getTopBorderColor() {
return (short)borderFormatting.getTopBorderColor();
}
public HSSFColor getTopBorderColorColor() {
return workbook.getCustomPalette().getColor(
borderFormatting.getTopBorderColor()
);
}

public boolean isBackwardDiagonalOn() {
return borderFormatting.isBackwardDiagonalOn();
}
public boolean isForwardDiagonalOn() {
return borderFormatting.isForwardDiagonalOn();
}

public void setBackwardDiagonalOn(boolean on) {
borderFormatting.setBackwardDiagonalOn(on);
if (on) {
cfRuleRecord.setTopLeftBottomRightBorderModified(on);
}
}
public void setForwardDiagonalOn(boolean on) {
borderFormatting.setForwardDiagonalOn(on);
if (on) {
cfRuleRecord.setBottomLeftTopRightBorderModified(on);
}
}

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 setBorderRight(short border) {
borderFormatting.setBorderRight(border);
if (border != 0) {
cfRuleRecord.setRightBorderModified(true);
} else {
cfRuleRecord.setRightBorderModified(false);
}
}

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());
}
}
}

+ 4
- 4
src/java/org/apache/poi/hssf/usermodel/HSSFCell.java Просмотреть файл

@@ -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);

+ 5
- 2
src/java/org/apache/poi/hssf/usermodel/HSSFComment.java Просмотреть файл

@@ -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);
}

/**

+ 66
- 73
src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormatting.java Просмотреть файл

@@ -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,91 +73,84 @@ import org.apache.poi.ss.util.CellRangeAddress;
* sheet.addConditionalFormatting(regions, rule);
* </PRE>
*/
public final class HSSFConditionalFormatting implements ConditionalFormatting
{
private final HSSFWorkbook _workbook;
private final CFRecordsAggregate cfAggregate;
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");
}
if(cfAggregate == null) {
throw new IllegalArgumentException("cfAggregate must not be null");
}
_workbook = workbook;
this.cfAggregate = cfAggregate;
}
CFRecordsAggregate getCFRecordsAggregate() {
return cfAggregate;
}
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");
}
this.sheet = sheet;
this.cfAggregate = cfAggregate;
}
CFRecordsAggregate getCFRecordsAggregate() {
return cfAggregate;
}

/**
* @deprecated (Aug-2008) use {@link HSSFConditionalFormatting#getFormattingRanges()}
*/
public org.apache.poi.ss.util.Region[] getFormattingRegions()
{
CellRangeAddress[] cellRanges = getFormattingRanges();
return org.apache.poi.ss.util.Region.convertCellRangesToRegions(cellRanges);
}
/**
* @return array of <tt>CellRangeAddress</tt>s. never <code>null</code>
*/
public CellRangeAddress[] getFormattingRanges() {
return cfAggregate.getHeader().getCellRanges();
}
/**
* @deprecated (Aug-2008) use {@link HSSFConditionalFormatting#getFormattingRanges()}
*/
public org.apache.poi.ss.util.Region[] getFormattingRegions() {
CellRangeAddress[] cellRanges = getFormattingRanges();
return org.apache.poi.ss.util.Region.convertCellRangesToRegions(cellRanges);
}
/**
* @return array of <tt>CellRangeAddress</tt>s. never <code>null</code>
*/
public CellRangeAddress[] getFormattingRanges() {
return cfAggregate.getHeader().getCellRanges();
}

/**
* Replaces an existing Conditional Formatting rule at position idx.
* Excel allows to create up to 3 Conditional Formatting rules.
* This method can be useful to modify existing Conditional Formatting rules.
*
* @param idx position of the rule. Should be between 0 and 2.
* @param cfRule - Conditional Formatting rule
*/
public void setRule(int idx, HSSFConditionalFormattingRule cfRule)
{
cfAggregate.setRule(idx, cfRule.getCfRuleRecord());
}
/**
* Replaces an existing Conditional Formatting rule at position idx.
* 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 for older Excel versions
* @param cfRule - Conditional Formatting rule
*/
public void setRule(int idx, HSSFConditionalFormattingRule cfRule) {
cfAggregate.setRule(idx, cfRule.getCfRuleRecord());
}

public void setRule(int idx, ConditionalFormattingRule cfRule){
setRule(idx, (HSSFConditionalFormattingRule)cfRule);
}

/**
* add a Conditional Formatting rule.
* Excel allows to create up to 3 Conditional Formatting rules.
* @param cfRule - Conditional Formatting rule
*/
public void addRule(HSSFConditionalFormattingRule cfRule)
{
cfAggregate.addRule(cfRule.getCfRuleRecord());
}
/**
* add a Conditional Formatting rule.
* Excel allows to create up to 3 Conditional Formatting rules.
* @param cfRule - Conditional Formatting rule
*/
public void addRule(HSSFConditionalFormattingRule cfRule) {
cfAggregate.addRule(cfRule.getCfRuleRecord());
}

public void addRule(ConditionalFormattingRule cfRule){
addRule((HSSFConditionalFormattingRule)cfRule);
}

/**
* @return the Conditional Formatting rule at position idx.
*/
public HSSFConditionalFormattingRule getRule(int idx)
{
CFRuleRecord ruleRecord = cfAggregate.getRule(idx);
return new HSSFConditionalFormattingRule(_workbook, ruleRecord);
}
/**
* @return the Conditional Formatting rule at position idx.
*/
public HSSFConditionalFormattingRule getRule(int idx) {
CFRuleBase ruleRecord = cfAggregate.getRule(idx);
return new HSSFConditionalFormattingRule(sheet, ruleRecord);
}

/**
* @return number of Conditional Formatting rules.
*/
public int getNumberOfRules()
{
return cfAggregate.getNumberOfRules();
}
/**
* @return number of Conditional Formatting rules.
*/
public int getNumberOfRules() {
return cfAggregate.getNumberOfRules();
}

public String toString()
{
return cfAggregate.toString();
}
public String toString() {
return cfAggregate.toString();
}
}

+ 225
- 175
src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java Просмотреть файл

@@ -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,178 +36,224 @@ 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
{
private static final byte CELL_COMPARISON = CFRuleRecord.CONDITION_TYPE_CELL_VALUE_IS;

private final CFRuleRecord cfRuleRecord;
private final HSSFWorkbook workbook;

HSSFConditionalFormattingRule(HSSFWorkbook pWorkbook, CFRuleRecord pRuleRecord) {
if (pWorkbook == null) {
throw new IllegalArgumentException("pWorkbook must not be null");
}
if (pRuleRecord == null) {
throw new IllegalArgumentException("pRuleRecord must not be null");
}
workbook = pWorkbook;
cfRuleRecord = pRuleRecord;
}

CFRuleRecord getCfRuleRecord()
{
return cfRuleRecord;
}

private HSSFFontFormatting getFontFormatting(boolean create)
{
FontFormatting fontFormatting = cfRuleRecord.getFontFormatting();
if ( fontFormatting != null)
{
cfRuleRecord.setFontFormatting(fontFormatting);
return new HSSFFontFormatting(cfRuleRecord);
}
else if( create )
{
fontFormatting = new FontFormatting();
cfRuleRecord.setFontFormatting(fontFormatting);
return new HSSFFontFormatting(cfRuleRecord);
}
else
{
return null;
}
}

/**
* @return - font formatting object if defined, <code>null</code> otherwise
*/
public HSSFFontFormatting getFontFormatting()
{
return getFontFormatting(false);
}
/**
* create a new font formatting structure if it does not exist,
* otherwise just return existing object.
* @return - font formatting object, never returns <code>null</code>.
*/
public HSSFFontFormatting createFontFormatting()
{
return getFontFormatting(true);
}

private HSSFBorderFormatting getBorderFormatting(boolean create)
{
BorderFormatting borderFormatting = cfRuleRecord.getBorderFormatting();
if ( borderFormatting != null)
{
cfRuleRecord.setBorderFormatting(borderFormatting);
return new HSSFBorderFormatting(cfRuleRecord);
}
else if( create )
{
borderFormatting = new BorderFormatting();
cfRuleRecord.setBorderFormatting(borderFormatting);
return new HSSFBorderFormatting(cfRuleRecord);
}
else
{
return null;
}
}
/**
* @return - border formatting object if defined, <code>null</code> otherwise
*/
public HSSFBorderFormatting getBorderFormatting()
{
return getBorderFormatting(false);
}
/**
* create a new border formatting structure if it does not exist,
* otherwise just return existing object.
* @return - border formatting object, never returns <code>null</code>.
*/
public HSSFBorderFormatting createBorderFormatting()
{
return getBorderFormatting(true);
}

private HSSFPatternFormatting getPatternFormatting(boolean create)
{
PatternFormatting patternFormatting = cfRuleRecord.getPatternFormatting();
if ( patternFormatting != null)
{
cfRuleRecord.setPatternFormatting(patternFormatting);
return new HSSFPatternFormatting(cfRuleRecord);
}
else if( create )
{
patternFormatting = new PatternFormatting();
cfRuleRecord.setPatternFormatting(patternFormatting);
return new HSSFPatternFormatting(cfRuleRecord);
}
else
{
return null;
}
}

/**
* @return - pattern formatting object if defined, <code>null</code> otherwise
*/
public HSSFPatternFormatting getPatternFormatting()
{
return getPatternFormatting(false);
}
/**
* create a new pattern formatting structure if it does not exist,
* otherwise just return existing object.
* @return - pattern formatting object, never returns <code>null</code>.
*/
public HSSFPatternFormatting createPatternFormatting()
{
return getPatternFormatting(true);
}

/**
* @return - the conditiontype for the cfrule
*/
public byte getConditionType() {
return cfRuleRecord.getConditionType();
}

/**
* @return - the comparisionoperatation for the cfrule
*/
public byte getComparisonOperation() {
return cfRuleRecord.getComparisonOperation();
}

public String getFormula1()
{
return toFormulaString(cfRuleRecord.getParsedExpression1());
}

public String getFormula2()
{
byte conditionType = cfRuleRecord.getConditionType();
if (conditionType == CELL_COMPARISON) {
byte comparisonOperation = cfRuleRecord.getComparisonOperation();
switch(comparisonOperation)
{
case ComparisonOperator.BETWEEN:
case ComparisonOperator.NOT_BETWEEN:
return toFormulaString(cfRuleRecord.getParsedExpression2());
}
}
return null;
}

private String toFormulaString(Ptg[] parsedExpression)
{
if(parsedExpression ==null) {
return null;
}
return HSSFFormulaParser.toFormulaString(workbook, parsedExpression);
}
public final class HSSFConditionalFormattingRule implements ConditionalFormattingRule {
private static final byte CELL_COMPARISON = CFRuleRecord.CONDITION_TYPE_CELL_VALUE_IS;

private final CFRuleBase cfRuleRecord;
private final HSSFWorkbook workbook;
private final HSSFSheet sheet;

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");
}
sheet = pSheet;
workbook = pSheet.getWorkbook();
cfRuleRecord = pRuleRecord;
}

CFRuleBase getCfRuleRecord()
{
return cfRuleRecord;
}

private HSSFFontFormatting getFontFormatting(boolean create)
{
FontFormatting fontFormatting = cfRuleRecord.getFontFormatting();
if ( fontFormatting != null)
{
cfRuleRecord.setFontFormatting(fontFormatting);
return new HSSFFontFormatting(cfRuleRecord, workbook);
}
else if( create )
{
fontFormatting = new FontFormatting();
cfRuleRecord.setFontFormatting(fontFormatting);
return new HSSFFontFormatting(cfRuleRecord, workbook);
}
else
{
return null;
}
}

/**
* @return - font formatting object if defined, <code>null</code> otherwise
*/
public HSSFFontFormatting getFontFormatting()
{
return getFontFormatting(false);
}
/**
* create a new font formatting structure if it does not exist,
* otherwise just return existing object.
* @return - font formatting object, never returns <code>null</code>.
*/
public HSSFFontFormatting createFontFormatting()
{
return getFontFormatting(true);
}

private HSSFBorderFormatting getBorderFormatting(boolean create)
{
BorderFormatting borderFormatting = cfRuleRecord.getBorderFormatting();
if ( borderFormatting != null)
{
cfRuleRecord.setBorderFormatting(borderFormatting);
return new HSSFBorderFormatting(cfRuleRecord, workbook);
}
else if( create )
{
borderFormatting = new BorderFormatting();
cfRuleRecord.setBorderFormatting(borderFormatting);
return new HSSFBorderFormatting(cfRuleRecord, workbook);
}
else
{
return null;
}
}
/**
* @return - border formatting object if defined, <code>null</code> otherwise
*/
public HSSFBorderFormatting getBorderFormatting()
{
return getBorderFormatting(false);
}
/**
* create a new border formatting structure if it does not exist,
* otherwise just return existing object.
* @return - border formatting object, never returns <code>null</code>.
*/
public HSSFBorderFormatting createBorderFormatting()
{
return getBorderFormatting(true);
}

private HSSFPatternFormatting getPatternFormatting(boolean create)
{
PatternFormatting patternFormatting = cfRuleRecord.getPatternFormatting();
if ( patternFormatting != null)
{
cfRuleRecord.setPatternFormatting(patternFormatting);
return new HSSFPatternFormatting(cfRuleRecord, workbook);
}
else if( create )
{
patternFormatting = new PatternFormatting();
cfRuleRecord.setPatternFormatting(patternFormatting);
return new HSSFPatternFormatting(cfRuleRecord, workbook);
}
else
{
return null;
}
}

/**
* @return - pattern formatting object if defined, <code>null</code> otherwise
*/
public HSSFPatternFormatting getPatternFormatting()
{
return getPatternFormatting(false);
}
/**
* create a new pattern formatting structure if it does not exist,
* otherwise just return existing object.
* @return - pattern formatting object, never returns <code>null</code>.
*/
public HSSFPatternFormatting createPatternFormatting()
{
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
*/
public byte getComparisonOperation() {
return cfRuleRecord.getComparisonOperation();
}

public String getFormula1()
{
return toFormulaString(cfRuleRecord.getParsedExpression1());
}

public String getFormula2() {
byte conditionType = cfRuleRecord.getConditionType();
if (conditionType == CELL_COMPARISON) {
byte comparisonOperation = cfRuleRecord.getComparisonOperation();
switch(comparisonOperation) {
case ComparisonOperator.BETWEEN:
case ComparisonOperator.NOT_BETWEEN:
return toFormulaString(cfRuleRecord.getParsedExpression2());
}
}
return 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);
}
}

+ 63
- 0
src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingThreshold.java Просмотреть файл

@@ -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);
}
}

+ 379
- 373
src/java/org/apache/poi/hssf/usermodel/HSSFFontFormatting.java Просмотреть файл

@@ -17,382 +17,388 @@

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
{

/** Underline type - None */
public final static byte U_NONE = FontFormatting.U_NONE;
/** Underline type - Single */
public final static byte U_SINGLE = FontFormatting.U_SINGLE;
/** Underline type - Double */
public final static byte U_DOUBLE = FontFormatting.U_DOUBLE;
/** Underline type - Single Accounting */
public final static byte U_SINGLE_ACCOUNTING = FontFormatting.U_SINGLE_ACCOUNTING;
/** Underline type - Double Accounting */
public final static byte U_DOUBLE_ACCOUNTING = FontFormatting.U_DOUBLE_ACCOUNTING;

private final FontFormatting fontFormatting;
protected HSSFFontFormatting(CFRuleRecord cfRuleRecord)
{
this.fontFormatting = cfRuleRecord.getFontFormatting();
}
protected FontFormatting getFontFormattingBlock()
{
return fontFormatting;
}

/**
* get the type of super or subscript for the font
*
* @return super or subscript option
* @see #SS_NONE
* @see #SS_SUPER
* @see #SS_SUB
*/
public short getEscapementType()
{
return fontFormatting.getEscapementType();
}

/**
* @return font color index
*/
public short getFontColorIndex()
{
return fontFormatting.getFontColorIndex();
}

/**
* gets the height of the font in 1/20th point units
*
* @return fontheight (in points/20); or -1 if not modified
*/
public int getFontHeight()
{
return fontFormatting.getFontHeight();
}

/**
* get the font weight for this font (100-1000dec or 0x64-0x3e8). Default is
* 0x190 for normal and 0x2bc for bold
*
* @return bw - a number between 100-1000 for the fonts "boldness"
*/

public short getFontWeight()
{
return fontFormatting.getFontWeight();
}

/**
* @see org.apache.poi.hssf.record.cf.FontFormatting#getRawRecord()
*/
protected byte[] getRawRecord()
{
return fontFormatting.getRawRecord();
}

/**
* get the type of underlining for the font
*
* @return font underlining type
*
* @see #U_NONE
* @see #U_SINGLE
* @see #U_DOUBLE
* @see #U_SINGLE_ACCOUNTING
* @see #U_DOUBLE_ACCOUNTING
*/
public short getUnderlineType()
{
return fontFormatting.getUnderlineType();
}

/**
* get whether the font weight is set to bold or not
*
* @return bold - whether the font is bold or not
*/
public boolean isBold()
{
return fontFormatting.isFontWeightModified() && fontFormatting.isBold();
}

/**
* @return true if escapement type was modified from default
*/
public boolean isEscapementTypeModified()
{
return fontFormatting.isEscapementTypeModified();
}

/**
* @return true if font cancellation was modified from default
*/
public boolean isFontCancellationModified()
{
return fontFormatting.isFontCancellationModified();
}

/**
* @return true if font outline type was modified from default
*/
public boolean isFontOutlineModified()
{
return fontFormatting.isFontOutlineModified();
}

/**
* @return true if font shadow type was modified from default
*/
public boolean isFontShadowModified()
{
return fontFormatting.isFontShadowModified();
}

/**
* @return true if font style was modified from default
*/
public boolean isFontStyleModified()
{
return fontFormatting.isFontStyleModified();
}

/**
* @return true if font style was set to <i>italic</i>
*/
public boolean isItalic()
{
return fontFormatting.isFontStyleModified() && fontFormatting.isItalic();
}

/**
* @return true if font outline is on
*/
public boolean isOutlineOn()
{
return fontFormatting.isFontOutlineModified() && fontFormatting.isOutlineOn();
}

/**
* @return true if font shadow is on
*/
public boolean isShadowOn()
{
return fontFormatting.isFontOutlineModified() && fontFormatting.isShadowOn();
}

/**
* @return true if font strikeout is on
*/
public boolean isStruckout()
{
return fontFormatting.isFontCancellationModified() && fontFormatting.isStruckout();
}

/**
* @return true if font underline type was modified from default
*/
public boolean isUnderlineTypeModified()
{
return fontFormatting.isUnderlineTypeModified();
}

/**
* @return true if font weight was modified from default
*/
public boolean isFontWeightModified()
{
return fontFormatting.isFontWeightModified();
}

/**
* set font style options.
*
* @param italic - if true, set posture style to italic, otherwise to normal
* @param bold if true, set font weight to bold, otherwise to normal
*/
public void setFontStyle(boolean italic, boolean bold)
{
boolean modified = italic || bold;
fontFormatting.setItalic(italic);
fontFormatting.setBold(bold);
fontFormatting.setFontStyleModified(modified);
fontFormatting.setFontWieghtModified(modified);
}

/**
* set font style options to default values (non-italic, non-bold)
*/
public void resetFontStyle()
{
setFontStyle(false,false);
}

/**
* set the escapement type for the font
*
* @param escapementType super or subscript option
* @see #SS_NONE
* @see #SS_SUPER
* @see #SS_SUB
*/
public void setEscapementType(short escapementType)
{
switch(escapementType)
{
case HSSFFontFormatting.SS_SUB:
case HSSFFontFormatting.SS_SUPER:
fontFormatting.setEscapementType(escapementType);
fontFormatting.setEscapementTypeModified(true);
break;
case HSSFFontFormatting.SS_NONE:
fontFormatting.setEscapementType(escapementType);
fontFormatting.setEscapementTypeModified(false);
break;
default:
}
}

/**
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setEscapementTypeModified(boolean)
*/
public void setEscapementTypeModified(boolean modified)
{
fontFormatting.setEscapementTypeModified(modified);
}

/**
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setFontCancellationModified(boolean)
*/
public void setFontCancellationModified(boolean modified)
{
fontFormatting.setFontCancellationModified(modified);
}

/**
* @param fci
* @see org.apache.poi.hssf.record.cf.FontFormatting#setFontColorIndex(short)
*/
public void setFontColorIndex(short fci)
{
fontFormatting.setFontColorIndex(fci);
}

/**
* @param height
* @see org.apache.poi.hssf.record.cf.FontFormatting#setFontHeight(int)
*/
public void setFontHeight(int height)
{
fontFormatting.setFontHeight(height);
}

/**
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setFontOutlineModified(boolean)
*/
public void setFontOutlineModified(boolean modified)
{
fontFormatting.setFontOutlineModified(modified);
}

/**
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setFontShadowModified(boolean)
*/
public void setFontShadowModified(boolean modified)
{
fontFormatting.setFontShadowModified(modified);
}

/**
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setFontStyleModified(boolean)
*/
public void setFontStyleModified(boolean modified)
{
fontFormatting.setFontStyleModified(modified);
}

/**
* @param on
* @see org.apache.poi.hssf.record.cf.FontFormatting#setOutline(boolean)
*/
public void setOutline(boolean on)
{
fontFormatting.setOutline(on);
fontFormatting.setFontOutlineModified(on);
}

/**
* @param on
* @see org.apache.poi.hssf.record.cf.FontFormatting#setShadow(boolean)
*/
public void setShadow(boolean on)
{
fontFormatting.setShadow(on);
fontFormatting.setFontShadowModified(on);
}

/**
* @param strike
* @see org.apache.poi.hssf.record.cf.FontFormatting#setStrikeout(boolean)
*/
public void setStrikeout(boolean strike)
{
fontFormatting.setStrikeout(strike);
fontFormatting.setFontCancellationModified(strike);
}

/**
* set the type of underlining type for the font
*
* @param underlineType super or subscript option
*
* @see #U_NONE
* @see #U_SINGLE
* @see #U_DOUBLE
* @see #U_SINGLE_ACCOUNTING
* @see #U_DOUBLE_ACCOUNTING
*/
public void setUnderlineType(short underlineType)
{
switch(underlineType)
{
case HSSFFontFormatting.U_SINGLE:
case HSSFFontFormatting.U_DOUBLE:
case HSSFFontFormatting.U_SINGLE_ACCOUNTING:
case HSSFFontFormatting.U_DOUBLE_ACCOUNTING:
fontFormatting.setUnderlineType(underlineType);
setUnderlineTypeModified(true);
break;
case HSSFFontFormatting.U_NONE:
fontFormatting.setUnderlineType(underlineType);
setUnderlineTypeModified(false);
break;
default:
}
}

/**
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setUnderlineTypeModified(boolean)
*/
public void setUnderlineTypeModified(boolean modified)
{
fontFormatting.setUnderlineTypeModified(modified);
}
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 */
public final static byte U_SINGLE = FontFormatting.U_SINGLE;
/** Underline type - Double */
public final static byte U_DOUBLE = FontFormatting.U_DOUBLE;
/** Underline type - Single Accounting */
public final static byte U_SINGLE_ACCOUNTING = FontFormatting.U_SINGLE_ACCOUNTING;
/** Underline type - Double Accounting */
public final static byte U_DOUBLE_ACCOUNTING = FontFormatting.U_DOUBLE_ACCOUNTING;

private final FontFormatting fontFormatting;
private final HSSFWorkbook workbook;

protected HSSFFontFormatting(CFRuleBase cfRuleRecord, HSSFWorkbook workbook) {
this.fontFormatting = cfRuleRecord.getFontFormatting();
this.workbook = workbook;
}

protected FontFormatting getFontFormattingBlock() {
return fontFormatting;
}

/**
* get the type of super or subscript for the font
*
* @return super or subscript option
* @see #SS_NONE
* @see #SS_SUPER
* @see #SS_SUB
*/
public short getEscapementType()
{
return fontFormatting.getEscapementType();
}

/**
* @return font color index
*/
public short getFontColorIndex()
{
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() {
return fontFormatting.getFontHeight();
}

/**
* get the font weight for this font (100-1000dec or 0x64-0x3e8). Default is
* 0x190 for normal and 0x2bc for bold
*
* @return bw - a number between 100-1000 for the fonts "boldness"
*/
public short getFontWeight() {
return fontFormatting.getFontWeight();
}

/**
* @see org.apache.poi.hssf.record.cf.FontFormatting#getRawRecord()
*/
protected byte[] getRawRecord() {
return fontFormatting.getRawRecord();
}

/**
* get the type of underlining for the font
*
* @return font underlining type
*
* @see #U_NONE
* @see #U_SINGLE
* @see #U_DOUBLE
* @see #U_SINGLE_ACCOUNTING
* @see #U_DOUBLE_ACCOUNTING
*/
public short getUnderlineType()
{
return fontFormatting.getUnderlineType();
}

/**
* get whether the font weight is set to bold or not
*
* @return bold - whether the font is bold or not
*/
public boolean isBold()
{
return fontFormatting.isFontWeightModified() && fontFormatting.isBold();
}

/**
* @return true if escapement type was modified from default
*/
public boolean isEscapementTypeModified()
{
return fontFormatting.isEscapementTypeModified();
}

/**
* @return true if font cancellation was modified from default
*/
public boolean isFontCancellationModified()
{
return fontFormatting.isFontCancellationModified();
}

/**
* @return true if font outline type was modified from default
*/
public boolean isFontOutlineModified()
{
return fontFormatting.isFontOutlineModified();
}

/**
* @return true if font shadow type was modified from default
*/
public boolean isFontShadowModified()
{
return fontFormatting.isFontShadowModified();
}

/**
* @return true if font style was modified from default
*/
public boolean isFontStyleModified()
{
return fontFormatting.isFontStyleModified();
}

/**
* @return true if font style was set to <i>italic</i>
*/
public boolean isItalic()
{
return fontFormatting.isFontStyleModified() && fontFormatting.isItalic();
}

/**
* @return true if font outline is on
*/
public boolean isOutlineOn()
{
return fontFormatting.isFontOutlineModified() && fontFormatting.isOutlineOn();
}

/**
* @return true if font shadow is on
*/
public boolean isShadowOn()
{
return fontFormatting.isFontOutlineModified() && fontFormatting.isShadowOn();
}

/**
* @return true if font strikeout is on
*/
public boolean isStruckout()
{
return fontFormatting.isFontCancellationModified() && fontFormatting.isStruckout();
}

/**
* @return true if font underline type was modified from default
*/
public boolean isUnderlineTypeModified()
{
return fontFormatting.isUnderlineTypeModified();
}

/**
* @return true if font weight was modified from default
*/
public boolean isFontWeightModified()
{
return fontFormatting.isFontWeightModified();
}

/**
* set font style options.
*
* @param italic - if true, set posture style to italic, otherwise to normal
* @param bold if true, set font weight to bold, otherwise to normal
*/

public void setFontStyle(boolean italic, boolean bold)
{
boolean modified = italic || bold;
fontFormatting.setItalic(italic);
fontFormatting.setBold(bold);
fontFormatting.setFontStyleModified(modified);
fontFormatting.setFontWieghtModified(modified);
}

/**
* set font style options to default values (non-italic, non-bold)
*/
public void resetFontStyle()
{
setFontStyle(false,false);
}

/**
* set the escapement type for the font
*
* @param escapementType super or subscript option
* @see #SS_NONE
* @see #SS_SUPER
* @see #SS_SUB
*/
public void setEscapementType(short escapementType) {
switch(escapementType) {
case HSSFFontFormatting.SS_SUB:
case HSSFFontFormatting.SS_SUPER:
fontFormatting.setEscapementType(escapementType);
fontFormatting.setEscapementTypeModified(true);
break;
case HSSFFontFormatting.SS_NONE:
fontFormatting.setEscapementType(escapementType);
fontFormatting.setEscapementTypeModified(false);
break;
default:
}
}

/**
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setEscapementTypeModified(boolean)
*/
public void setEscapementTypeModified(boolean modified) {
fontFormatting.setEscapementTypeModified(modified);
}

/**
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setFontCancellationModified(boolean)
*/
public void setFontCancellationModified(boolean modified)
{
fontFormatting.setFontCancellationModified(modified);
}

/**
* @param fci
* @see org.apache.poi.hssf.record.cf.FontFormatting#setFontColorIndex(short)
*/
public void setFontColorIndex(short fci)
{
fontFormatting.setFontColorIndex(fci);
}

/**
* @param height
* @see org.apache.poi.hssf.record.cf.FontFormatting#setFontHeight(int)
*/
public void setFontHeight(int height)
{
fontFormatting.setFontHeight(height);
}

/**
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setFontOutlineModified(boolean)
*/
public void setFontOutlineModified(boolean modified)
{
fontFormatting.setFontOutlineModified(modified);
}

/**
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setFontShadowModified(boolean)
*/
public void setFontShadowModified(boolean modified)
{
fontFormatting.setFontShadowModified(modified);
}

/**
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setFontStyleModified(boolean)
*/
public void setFontStyleModified(boolean modified)
{
fontFormatting.setFontStyleModified(modified);
}

/**
* @param on
* @see org.apache.poi.hssf.record.cf.FontFormatting#setOutline(boolean)
*/
public void setOutline(boolean on)
{
fontFormatting.setOutline(on);
fontFormatting.setFontOutlineModified(on);
}

/**
* @param on
* @see org.apache.poi.hssf.record.cf.FontFormatting#setShadow(boolean)
*/
public void setShadow(boolean on)
{
fontFormatting.setShadow(on);
fontFormatting.setFontShadowModified(on);
}

/**
* @param strike
* @see org.apache.poi.hssf.record.cf.FontFormatting#setStrikeout(boolean)
*/
public void setStrikeout(boolean strike)
{
fontFormatting.setStrikeout(strike);
fontFormatting.setFontCancellationModified(strike);
}

/**
* set the type of underlining type for the font
*
* @param underlineType super or subscript option
*
* @see #U_NONE
* @see #U_SINGLE
* @see #U_DOUBLE
* @see #U_SINGLE_ACCOUNTING
* @see #U_DOUBLE_ACCOUNTING
*/
public void setUnderlineType(short underlineType) {
switch(underlineType) {
case HSSFFontFormatting.U_SINGLE:
case HSSFFontFormatting.U_DOUBLE:
case HSSFFontFormatting.U_SINGLE_ACCOUNTING:
case HSSFFontFormatting.U_DOUBLE_ACCOUNTING:
fontFormatting.setUnderlineType(underlineType);
setUnderlineTypeModified(true);
break;
case HSSFFontFormatting.U_NONE:
fontFormatting.setUnderlineType(underlineType);
setUnderlineTypeModified(false);
break;
default:
}
}

/**
* @param modified
* @see org.apache.poi.hssf.record.cf.FontFormatting#setUnderlineTypeModified(boolean)
*/
public void setUnderlineTypeModified(boolean modified)
{
fontFormatting.setUnderlineTypeModified(modified);
}
}

+ 81
- 0
src/java/org/apache/poi/hssf/usermodel/HSSFIconMultiStateFormatting.java Просмотреть файл

@@ -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);
}
}

+ 0
- 1
src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java Просмотреть файл

@@ -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;

+ 107
- 79
src/java/org/apache/poi/hssf/usermodel/HSSFPatternFormatting.java Просмотреть файл

@@ -17,88 +17,116 @@

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;
private final PatternFormatting patternFormatting;
protected HSSFPatternFormatting(CFRuleRecord cfRuleRecord)
{
this.cfRuleRecord = cfRuleRecord;
this.patternFormatting = cfRuleRecord.getPatternFormatting();
}

protected PatternFormatting getPatternFormattingBlock()
{
return patternFormatting;
}

/**
* @see org.apache.poi.hssf.record.cf.PatternFormatting#getFillBackgroundColor()
*/
public short getFillBackgroundColor()
{
return (short)patternFormatting.getFillBackgroundColor();
}

/**
* @see org.apache.poi.hssf.record.cf.PatternFormatting#getFillForegroundColor()
*/
public short getFillForegroundColor()
{
return (short)patternFormatting.getFillForegroundColor();
}

/**
* @see org.apache.poi.hssf.record.cf.PatternFormatting#getFillPattern()
*/
public short getFillPattern()
{
return (short)patternFormatting.getFillPattern();
}

/**
* @param bg
* @see org.apache.poi.hssf.record.cf.PatternFormatting#setFillBackgroundColor(int)
*/
public void setFillBackgroundColor(short bg)
{
patternFormatting.setFillBackgroundColor(bg);
if( bg != 0)
{
cfRuleRecord.setPatternBackgroundColorModified(true);
}
}

/**
* @param fg
* @see org.apache.poi.hssf.record.cf.PatternFormatting#setFillForegroundColor(int)
*/
public void setFillForegroundColor(short fg)
{
patternFormatting.setFillForegroundColor(fg);
if( fg != 0)
{
cfRuleRecord.setPatternColorModified(true);
}
}

/**
* @param fp
* @see org.apache.poi.hssf.record.cf.PatternFormatting#setFillPattern(int)
*/
public void setFillPattern(short fp)
{
patternFormatting.setFillPattern(fp);
if( fp != 0)
{
cfRuleRecord.setPatternStyleModified(true);
}
}
public class HSSFPatternFormatting implements org.apache.poi.ss.usermodel.PatternFormatting {
private final HSSFWorkbook workbook;
private final CFRuleBase cfRuleRecord;
private final PatternFormatting patternFormatting;

protected HSSFPatternFormatting(CFRuleBase cfRuleRecord, HSSFWorkbook workbook) {
this.workbook = workbook;
this.cfRuleRecord = cfRuleRecord;
this.patternFormatting = cfRuleRecord.getPatternFormatting();
}

protected PatternFormatting getPatternFormattingBlock()
{
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()
*/
public short getFillBackgroundColor()
{
return (short)patternFormatting.getFillBackgroundColor();
}

/**
* @see org.apache.poi.hssf.record.cf.PatternFormatting#getFillForegroundColor()
*/
public short getFillForegroundColor()
{
return (short)patternFormatting.getFillForegroundColor();
}

/**
* @see org.apache.poi.hssf.record.cf.PatternFormatting#getFillPattern()
*/
public short getFillPattern()
{
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)
*/
public void setFillBackgroundColor(short bg)
{
patternFormatting.setFillBackgroundColor(bg);
if( bg != 0)
{
cfRuleRecord.setPatternBackgroundColorModified(true);
}
}

/**
* @param fg
* @see org.apache.poi.hssf.record.cf.PatternFormatting#setFillForegroundColor(int)
*/
public void setFillForegroundColor(short fg)
{
patternFormatting.setFillForegroundColor(fg);
if( fg != 0)
{
cfRuleRecord.setPatternColorModified(true);
}
}

/**
* @param fp
* @see org.apache.poi.hssf.record.cf.PatternFormatting#setFillPattern(int)
*/
public void setFillPattern(short fp)
{
patternFormatting.setFillPattern(fp);
if( fp != 0)
{
cfRuleRecord.setPatternStyleModified(true);
}
}
}

+ 9
- 12
src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java Просмотреть файл

@@ -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,11 +90,15 @@ public class HSSFShapeFactory {
break;
case CommonObjectDataSubRecord.OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING:
EscherOptRecord optRecord = container.getChildById(EscherOptRecord.RECORD_ID);
EscherProperty property = optRecord.lookup(EscherProperties.GEOMETRY__VERTICES);
if (null != property) {
shape = new HSSFPolygon(container, objRecord, txtRecord);
if(optRecord == null) {
shape = new HSSFSimpleShape(container, objRecord, txtRecord);
} else {
shape = new HSSFSimpleShape(container, objRecord, txtRecord);
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:

+ 11
- 0
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java Просмотреть файл

@@ -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.

+ 173
- 168
src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java Просмотреть файл

@@ -17,142 +17,156 @@

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;

private final HSSFSheet _sheet;
private final ConditionalFormattingTable _conditionalFormattingTable;

/* package */ HSSFSheetConditionalFormatting(HSSFSheet sheet) {
_sheet = sheet;
_conditionalFormattingTable = sheet.getSheet().getConditionalFormattingTable();
}

/**
* A factory method allowing to create a conditional formatting rule
* with a cell comparison operator<p/>
* TODO - formulas containing cell references are currently not parsed properly
*
* @param comparisonOperation - a constant value from
* <tt>{@link org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator}</tt>: <p>
* <ul>
* <li>BETWEEN</li>
* <li>NOT_BETWEEN</li>
* <li>EQUAL</li>
* <li>NOT_EQUAL</li>
* <li>GT</li>
* <li>LT</li>
* <li>GE</li>
* <li>LE</li>
* </ul>
* </p>
* @param formula1 - formula for the valued, compared with the cell
* @param formula2 - second formula (only used with
* {@link org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator#BETWEEN}) and
* {@link org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator#NOT_BETWEEN} operations)
*/
public HSSFConditionalFormattingRule createConditionalFormattingRule(
byte comparisonOperation,
String formula1,
String formula2) {

HSSFWorkbook wb = _sheet.getWorkbook();
CFRuleRecord rr = CFRuleRecord.create(_sheet, comparisonOperation, formula1, formula2);
return new HSSFConditionalFormattingRule(wb, rr);
}
/* package */ HSSFSheetConditionalFormatting(HSSFSheet sheet) {
_sheet = sheet;
_conditionalFormattingTable = sheet.getSheet().getConditionalFormattingTable();
}

/**
* A factory method allowing to create a conditional formatting rule
* with a cell comparison operator<p/>
* TODO - formulas containing cell references are currently not parsed properly
*
* @param comparisonOperation - a constant value from
* <tt>{@link org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator}</tt>: <p>
* <ul>
* <li>BETWEEN</li>
* <li>NOT_BETWEEN</li>
* <li>EQUAL</li>
* <li>NOT_EQUAL</li>
* <li>GT</li>
* <li>LT</li>
* <li>GE</li>
* <li>LE</li>
* </ul>
* </p>
* @param formula1 - formula for the valued, compared with the cell
* @param formula2 - second formula (only used with
* {@link org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator#BETWEEN}) and
* {@link org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator#NOT_BETWEEN} operations)
*/
public HSSFConditionalFormattingRule createConditionalFormattingRule(
byte comparisonOperation,
String formula1) {
String formula1,
String formula2) {
CFRuleRecord rr = CFRuleRecord.create(_sheet, comparisonOperation, formula1, formula2);
return new HSSFConditionalFormattingRule(_sheet, rr);
}

HSSFWorkbook wb = _sheet.getWorkbook();
public HSSFConditionalFormattingRule createConditionalFormattingRule(
byte comparisonOperation,
String formula1) {
CFRuleRecord rr = CFRuleRecord.create(_sheet, comparisonOperation, formula1, null);
return new HSSFConditionalFormattingRule(wb, rr);
}

/**
* A factory method allowing to create a conditional formatting rule with a formula.<br>
*
* The formatting rules are applied by Excel when the value of the formula not equal to 0.<p/>
* TODO - formulas containing cell references are currently not parsed properly
* @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);
}

/**
* Adds a copy of HSSFConditionalFormatting object to the sheet
* <p>This method could be used to copy HSSFConditionalFormatting object
* from one sheet to another. For example:
* <pre>
* HSSFConditionalFormatting cf = sheet.getConditionalFormattingAt(index);
* newSheet.addConditionalFormatting(cf);
* </pre>
*
* @param cf HSSFConditionalFormatting object
* @return index of the new Conditional Formatting object
*/
public int addConditionalFormatting( HSSFConditionalFormatting cf ) {
CFRecordsAggregate cfraClone = cf.getCFRecordsAggregate().cloneCFAggregate();

return _conditionalFormattingTable.add(cfraClone);
}
return new HSSFConditionalFormattingRule(_sheet, rr);
}

/**
* A factory method allowing to create a conditional formatting rule with a formula.<br>
*
* The formatting rules are applied by Excel when the value of the formula not equal to 0.<p/>
* TODO - formulas containing cell references are currently not parsed properly
* @param formula - formula for the valued, compared with the cell
*/
public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) {
CFRuleRecord rr = CFRuleRecord.create(_sheet, formula);
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
* from one sheet to another. For example:
* <pre>
* HSSFConditionalFormatting cf = sheet.getConditionalFormattingAt(index);
* newSheet.addConditionalFormatting(cf);
* </pre>
*
* @param cf HSSFConditionalFormatting object
* @return index of the new Conditional Formatting object
*/
public int addConditionalFormatting( HSSFConditionalFormatting cf ) {
CFRecordsAggregate cfraClone = cf.getCFRecordsAggregate().cloneCFAggregate();

return _conditionalFormattingTable.add(cfraClone);
}

public int addConditionalFormatting( ConditionalFormatting cf ) {
return addConditionalFormatting((HSSFConditionalFormatting)cf);
}

/**
* @deprecated use <tt>CellRangeAddress</tt> instead of <tt>Region</tt>
*/
public int addConditionalFormatting(org.apache.poi.ss.util.Region[] regions, HSSFConditionalFormattingRule[] cfRules) {
return addConditionalFormatting(org.apache.poi.ss.util.Region.convertRegionsToCellRanges(regions), cfRules);
}
/**
* Allows to add a new Conditional Formatting set to the sheet.
*
* @param regions - list of rectangular regions to apply conditional formatting rules
* @param cfRules - set of up to three conditional formatting rules
*
* @return index of the newly created Conditional Formatting object
*/
public int addConditionalFormatting(CellRangeAddress[] regions, HSSFConditionalFormattingRule[] cfRules) {
if (regions == null) {
throw new IllegalArgumentException("regions must not be null");
}
for(CellRangeAddress range : regions) range.validate(SpreadsheetVersion.EXCEL97);
if (cfRules == null) {
throw new IllegalArgumentException("cfRules must not be null");
}
if (cfRules.length == 0) {
throw new IllegalArgumentException("cfRules must not be empty");
}
if (cfRules.length > 3) {
throw new IllegalArgumentException("Number of rules must not exceed 3");
}
CFRuleRecord[] rules = new CFRuleRecord[cfRules.length];
for (int i = 0; i != cfRules.length; i++) {
rules[i] = cfRules[i].getCfRuleRecord();
}
CFRecordsAggregate cfra = new CFRecordsAggregate(regions, rules);
return _conditionalFormattingTable.add(cfra);
}
/**
* @deprecated use <tt>CellRangeAddress</tt> instead of <tt>Region</tt>
*/
public int addConditionalFormatting(org.apache.poi.ss.util.Region[] regions, HSSFConditionalFormattingRule[] cfRules) {
return addConditionalFormatting(org.apache.poi.ss.util.Region.convertRegionsToCellRanges(regions), cfRules);
}
/**
* Allows to add a new Conditional Formatting set to the sheet.
*
* @param regions - list of rectangular regions to apply conditional formatting rules
* @param cfRules - set of up to three conditional formatting rules
*
* @return index of the newly created Conditional Formatting object
*/
public int addConditionalFormatting(CellRangeAddress[] regions, HSSFConditionalFormattingRule[] cfRules) {
if (regions == null) {
throw new IllegalArgumentException("regions must not be null");
}
for(CellRangeAddress range : regions) range.validate(SpreadsheetVersion.EXCEL97);
if (cfRules == null) {
throw new IllegalArgumentException("cfRules must not be null");
}
if (cfRules.length == 0) {
throw new IllegalArgumentException("cfRules must not be empty");
}
if (cfRules.length > 3) {
throw new IllegalArgumentException("Number of rules must not exceed 3");
}
CFRuleBase[] rules = new CFRuleBase[cfRules.length];
for (int i = 0; i != cfRules.length; i++) {
rules[i] = cfRules[i].getCfRuleRecord();
}
CFRecordsAggregate cfra = new CFRecordsAggregate(regions, rules);
return _conditionalFormattingTable.add(cfra);
}

public int addConditionalFormatting(CellRangeAddress[] regions, ConditionalFormattingRule[] cfRules) {
HSSFConditionalFormattingRule[] hfRules;
@@ -164,70 +178,61 @@ public final class HSSFSheetConditionalFormatting implements SheetConditionalFor
return addConditionalFormatting(regions, hfRules);
}

public int addConditionalFormatting(CellRangeAddress[] regions,
HSSFConditionalFormattingRule rule1)
{
return addConditionalFormatting(regions,
rule1 == null ? null : new HSSFConditionalFormattingRule[]
{
rule1
});
}
public int addConditionalFormatting(CellRangeAddress[] regions,
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)
{
return addConditionalFormatting(regions,
new HSSFConditionalFormattingRule[]
{
rule1, rule2
});
}
public int addConditionalFormatting(CellRangeAddress[] regions,
HSSFConditionalFormattingRule rule1,
HSSFConditionalFormattingRule rule2) {
return addConditionalFormatting(regions,
new HSSFConditionalFormattingRule[] { rule1, rule2 });
}

public int addConditionalFormatting(CellRangeAddress[] regions,
ConditionalFormattingRule rule1,
ConditionalFormattingRule rule2)
{
ConditionalFormattingRule rule2) {
return addConditionalFormatting(regions,
(HSSFConditionalFormattingRule)rule1,
(HSSFConditionalFormattingRule)rule2
);
}
/**
* gets Conditional Formatting object at a particular index
*
* @param index
* of the Conditional Formatting object to fetch
* @return Conditional Formatting object
*/
public HSSFConditionalFormatting getConditionalFormattingAt(int index) {
CFRecordsAggregate cf = _conditionalFormattingTable.get(index);
if (cf == null) {
return null;
}
return new HSSFConditionalFormatting(_sheet.getWorkbook(), cf);
}
/**
* @return number of Conditional Formatting objects of the sheet
*/
public int getNumConditionalFormattings() {
return _conditionalFormattingTable.size();
}
/**
* removes a Conditional Formatting object by index
* @param index of a Conditional Formatting object to remove
*/
public void removeConditionalFormatting(int index) {
_conditionalFormattingTable.remove(index);
}
);
}
/**
* gets Conditional Formatting object at a particular index
*
* @param index
* of the Conditional Formatting object to fetch
* @return Conditional Formatting object
*/
public HSSFConditionalFormatting getConditionalFormattingAt(int index) {
CFRecordsAggregate cf = _conditionalFormattingTable.get(index);
if (cf == null) {
return null;
}
return new HSSFConditionalFormatting(_sheet, cf);
}
/**
* @return number of Conditional Formatting objects of the sheet
*/
public int getNumConditionalFormattings() {
return _conditionalFormattingTable.size();
}
/**
* removes a Conditional Formatting object by index
* @param index of a Conditional Formatting object to remove
*/
public void removeConditionalFormatting(int index) {
_conditionalFormattingTable.remove(index);
}
}

+ 18
- 4
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java Просмотреть файл

@@ -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;
}

+ 7
- 0
src/java/org/apache/poi/hssf/util/HSSFColor.java Просмотреть файл

@@ -204,6 +204,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

+ 4
- 2
src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java Просмотреть файл

@@ -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);

+ 1
- 1
src/java/org/apache/poi/poifs/crypt/DataSpaceMapUtils.java Просмотреть файл

@@ -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});

+ 5
- 1
src/java/org/apache/poi/poifs/crypt/Decryptor.java Просмотреть файл

@@ -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());
}

+ 27
- 8
src/java/org/apache/poi/poifs/crypt/EncryptionInfo.java Просмотреть файл

@@ -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);
}

+ 5
- 1
src/java/org/apache/poi/poifs/crypt/Encryptor.java Просмотреть файл

@@ -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());
}

+ 2
- 2
src/java/org/apache/poi/poifs/crypt/binaryrc4/BinaryRC4Decryptor.java Просмотреть файл

@@ -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;
@@ -131,4 +131,4 @@ public class BinaryRC4Decryptor extends Decryptor {
return _length;
}
}
}

+ 3
- 2
src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIDecryptor.java Просмотреть файл

@@ -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;

+ 1
- 1
src/java/org/apache/poi/poifs/crypt/standard/StandardDecryptor.java Просмотреть файл

@@ -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();


+ 1
- 1
src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptor.java Просмотреть файл

@@ -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???
}

+ 84
- 15
src/java/org/apache/poi/poifs/dev/POIFSDump.java Просмотреть файл

@@ -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()));
out.write(bytes);
out.close();
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();
}
}

+ 144
- 108
src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java Просмотреть файл

@@ -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;
@@ -42,111 +43,146 @@ import org.apache.poi.util.IntList;
* down the source of corruption in a file.
*/
public class POIFSHeaderDumper {
/**
* Display the entries of multiple POIFS files
*
* @param args the names of the files to be displayed
*/
public static void main(final String args[]) throws Exception {
if (args.length == 0) {
System.err.println("Must specify at least one file to view");
System.exit(1);
}

for (int j = 0; j < args.length; j++) {
viewFile(args[j]);
}
}

public static void viewFile(final String filename) throws Exception {
InputStream inp = new FileInputStream(filename);
// Header
HeaderBlock header_block = new HeaderBlock(inp);
displayHeader(header_block);
// Raw blocks
POIFSBigBlockSize bigBlockSize = header_block.getBigBlockSize();
RawDataBlockList data_blocks = new RawDataBlockList(inp, bigBlockSize);
displayRawBlocksSummary(data_blocks);
// Main FAT Table
BlockAllocationTableReader batReader =
new BlockAllocationTableReader(
header_block.getBigBlockSize(),
header_block.getBATCount(),
header_block.getBATArray(),
header_block.getXBATCount(),
header_block.getXBATIndex(),
data_blocks);
displayBATReader(batReader);

// Properties Table
PropertyTable properties =
new PropertyTable(header_block, data_blocks);
// Mini Fat
BlockList sbat =
SmallBlockTableReader.getSmallDocumentBlocks(
bigBlockSize, data_blocks, properties.getRoot(),
header_block.getSBATStart()
);
}

public static void displayHeader(HeaderBlock header_block) throws Exception {
System.out.println("Header Details:");
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());
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());
System.out.println(" SBAT (MiniFAT) block 1 at: " + header_block.getSBATStart());
System.out.println(" Property table at: " + header_block.getPropertyStart());
System.out.println("");
}

public static void displayRawBlocksSummary(RawDataBlockList data_blocks) throws Exception {
System.out.println("Raw Blocks Details:");
System.out.println(" Number of blocks: " + data_blocks.blockCount());
Method gbm = data_blocks.getClass().getSuperclass().getDeclaredMethod("get", int.class);
gbm.setAccessible(true);
for(int i=0; i<Math.min(16, data_blocks.blockCount()); i++) {
ListManagedBlock block = (ListManagedBlock)gbm.invoke(data_blocks, Integer.valueOf(i));
byte[] data = new byte[Math.min(48, block.getData().length)];
System.arraycopy(block.getData(), 0, data, 0, data.length);
System.out.println(" Block #" + i + ":");
System.out.println(HexDump.dump(data, 0, 0));
}
System.out.println("");
}
public static void displayBATReader(BlockAllocationTableReader batReader) throws Exception {
System.out.println("Sectors, as referenced from the FAT:");
Field entriesF = batReader.getClass().getDeclaredField("_entries");
entriesF.setAccessible(true);
IntList entries = (IntList)entriesF.get(batReader);
for(int i=0; i<entries.size(); i++) {
int bn = entries.get(i);
String bnS = Integer.toString(bn);
if(bn == POIFSConstants.END_OF_CHAIN) {
bnS = "End Of Chain";
} else if(bn == POIFSConstants.DIFAT_SECTOR_BLOCK) {
bnS = "DI Fat Block";
} else if(bn == POIFSConstants.FAT_SECTOR_BLOCK) {
bnS = "Normal Fat Block";
} else if(bn == POIFSConstants.UNUSED_BLOCK) {
bnS = "Block Not Used (Free)";
}
System.out.println(" Block # " + i + " -> " + bnS);
}
System.out.println("");
}
/**
* Display the entries of multiple POIFS files
*
* @param args the names of the files to be displayed
*/
public static void main(final String args[]) throws Exception {
if (args.length == 0) {
System.err.println("Must specify at least one file to view");
System.exit(1);
}

for (int j = 0; j < args.length; j++) {
viewFile(args[j]);
}
}

public static void viewFile(final String filename) throws Exception {
System.out.println("Dumping headers from: " + filename);
InputStream inp = new FileInputStream(filename);

// Header
HeaderBlock header_block = new HeaderBlock(inp);
displayHeader(header_block);

// Raw blocks
POIFSBigBlockSize bigBlockSize = header_block.getBigBlockSize();
RawDataBlockList data_blocks = new RawDataBlockList(inp, bigBlockSize);
displayRawBlocksSummary(data_blocks);

// Main FAT Table
BlockAllocationTableReader batReader =
new BlockAllocationTableReader(
header_block.getBigBlockSize(),
header_block.getBATCount(),
header_block.getBATArray(),
header_block.getXBATCount(),
header_block.getXBATIndex(),
data_blocks);
displayBATReader("Big Blocks", batReader);

// Properties Table
PropertyTable properties =
new PropertyTable(header_block, data_blocks);

// Mini Fat
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 {
System.out.println("Header Details:");
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());
System.out.println(" SBAT (MiniFAT) block 1 at: " + header_block.getSBATStart());
System.out.println(" Property table at: " + header_block.getPropertyStart());
System.out.println("");
}

public static void displayRawBlocksSummary(RawDataBlockList data_blocks) throws Exception {
System.out.println("Raw Blocks Details:");
System.out.println(" Number of blocks: " + data_blocks.blockCount());

Method gbm = data_blocks.getClass().getSuperclass().getDeclaredMethod("get", int.class);
gbm.setAccessible(true);

for(int i=0; i<Math.min(16, data_blocks.blockCount()); i++) {
ListManagedBlock block = (ListManagedBlock)gbm.invoke(data_blocks, Integer.valueOf(i));
byte[] data = new byte[Math.min(48, block.getData().length)];
System.arraycopy(block.getData(), 0, data, 0, data.length);

System.out.println(" Block #" + i + ":");
System.out.println(HexDump.dump(data, 0, 0));
}

System.out.println("");
}

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);

for(int i=0; i<entries.size(); i++) {
int bn = entries.get(i);
String bnS = Integer.toString(bn);
if(bn == POIFSConstants.END_OF_CHAIN) {
bnS = "End Of Chain";
} else if(bn == POIFSConstants.DIFAT_SECTOR_BLOCK) {
bnS = "DI Fat Block";
} else if(bn == POIFSConstants.FAT_SECTOR_BLOCK) {
bnS = "Normal Fat Block";
} else if(bn == POIFSConstants.UNUSED_BLOCK) {
bnS = "Block Not Used (Free)";
}

System.out.println(" Block # " + i + " -> " + bnS);
}

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());
}
}
}
}

+ 0
- 0
src/java/org/apache/poi/poifs/dev/POIFSViewer.java Просмотреть файл


Некоторые файлы не были показаны из-за большого количества измененных файлов

Загрузка…
Отмена
Сохранить