Browse Source

[bug-63046] Use Log4j 2 for logging

This removes the POILogger and POILogFactory mechanism for logging. This mechanism was created at a time when the Java landscape looked very different than it does today.

Log4j 2 is an Apache Foundation project that is well maintained and is widely regarded as having good performance and capabilities. We use only the Log4j API artifact. This lets application developers choose how they want to capture logging events if at all. Integrations with Log4j 2 Core and Logback are available from the Log4j project.

Closes #224

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1886770 13f79535-47bb-0310-9956-ffa450edef68
tags/REL_5_1_0
Marius Volkhart 3 years ago
parent
commit
259c9967ef
100 changed files with 847 additions and 1451 deletions
  1. 1
    2
      .classpath
  2. 0
    1
      .gitignore
  3. 11
    4
      build.gradle
  4. 32
    27
      build.xml
  5. 2
    22
      legal/LICENSE
  6. 3
    8
      maven/poi.pom
  7. 1
    0
      osgi/README.md
  8. 6
    6
      osgi/pom.xml
  9. 3
    0
      sonar/excelant/pom.xml
  10. 3
    0
      sonar/integration-test/pom.xml
  11. 6
    8
      sonar/main/pom.xml
  12. 3
    12
      sonar/ooxml/pom.xml
  13. 6
    1
      sonar/pom.xml
  14. 3
    0
      sonar/scratchpad/pom.xml
  15. 4
    4
      src/examples/src/org/apache/poi/examples/hssf/usermodel/Outlines.java
  16. 0
    16
      src/integrationtest/commons-logging.properties
  17. 0
    39
      src/integrationtest/log4j.properties
  18. 6
    6
      src/integrationtest/org/apache/poi/stress/HSLFFileHandler.java
  19. 13
    10
      src/java/org/apache/poi/POIDocument.java
  20. 4
    4
      src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java
  21. 6
    6
      src/java/org/apache/poi/ddf/EscherContainerRecord.java
  22. 7
    7
      src/java/org/apache/poi/ddf/EscherMetafileBlip.java
  23. 4
    4
      src/java/org/apache/poi/extractor/ExtractorFactory.java
  24. 7
    7
      src/java/org/apache/poi/hpsf/ClipboardData.java
  25. 10
    13
      src/java/org/apache/poi/hpsf/CodePageString.java
  26. 9
    7
      src/java/org/apache/poi/hpsf/CustomProperties.java
  27. 11
    8
      src/java/org/apache/poi/hpsf/Property.java
  28. 10
    12
      src/java/org/apache/poi/hpsf/Section.java
  29. 6
    5
      src/java/org/apache/poi/hpsf/TypedPropertyValue.java
  30. 7
    11
      src/java/org/apache/poi/hpsf/UnicodeString.java
  31. 6
    4
      src/java/org/apache/poi/hpsf/VariantBool.java
  32. 4
    4
      src/java/org/apache/poi/hpsf/VariantSupport.java
  33. 11
    8
      src/java/org/apache/poi/hssf/dev/BiffViewer.java
  34. 10
    9
      src/java/org/apache/poi/hssf/eventusermodel/FormatTrackingHSSFListener.java
  35. 50
    56
      src/java/org/apache/poi/hssf/model/InternalSheet.java
  36. 46
    45
      src/java/org/apache/poi/hssf/model/InternalWorkbook.java
  37. 3
    2
      src/java/org/apache/poi/hssf/record/CFRule12Record.java
  38. 3
    3
      src/java/org/apache/poi/hssf/record/CFRuleBase.java
  39. 4
    4
      src/java/org/apache/poi/hssf/record/DimensionsRecord.java
  40. 6
    4
      src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
  41. 7
    5
      src/java/org/apache/poi/hssf/record/FeatRecord.java
  42. 8
    5
      src/java/org/apache/poi/hssf/record/FormatRecord.java
  43. 8
    9
      src/java/org/apache/poi/hssf/record/HyperlinkRecord.java
  44. 8
    9
      src/java/org/apache/poi/hssf/record/LabelRecord.java
  45. 7
    8
      src/java/org/apache/poi/hssf/record/OldLabelRecord.java
  46. 6
    4
      src/java/org/apache/poi/hssf/record/SSTDeserializer.java
  47. 5
    5
      src/java/org/apache/poi/hssf/record/SupBookRecord.java
  48. 9
    8
      src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java
  49. 6
    4
      src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java
  50. 6
    5
      src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java
  51. 6
    4
      src/java/org/apache/poi/hssf/record/cf/IconMultiStateFormatting.java
  52. 7
    5
      src/java/org/apache/poi/hssf/record/common/ExtRst.java
  53. 6
    4
      src/java/org/apache/poi/hssf/record/common/UnicodeString.java
  54. 19
    22
      src/java/org/apache/poi/hssf/usermodel/EscherGraphics.java
  55. 17
    32
      src/java/org/apache/poi/hssf/usermodel/EscherGraphics2d.java
  56. 0
    1
      src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
  57. 5
    5
      src/java/org/apache/poi/hssf/usermodel/HSSFPolygon.java
  58. 4
    4
      src/java/org/apache/poi/hssf/usermodel/HSSFShape.java
  59. 29
    32
      src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
  60. 40
    39
      src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
  61. 5
    5
      src/java/org/apache/poi/hssf/usermodel/StaticFontMetrics.java
  62. 3
    3
      src/java/org/apache/poi/hssf/usermodel/helpers/HSSFColumnShifter.java
  63. 3
    5
      src/java/org/apache/poi/hssf/usermodel/helpers/HSSFRowShifter.java
  64. 5
    5
      src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java
  65. 4
    4
      src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptor.java
  66. 3
    3
      src/java/org/apache/poi/poifs/filesystem/POIFSDocumentPath.java
  67. 4
    4
      src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
  68. 9
    10
      src/java/org/apache/poi/poifs/macros/VBAMacroReader.java
  69. 5
    5
      src/java/org/apache/poi/poifs/nio/FileBackedDataSource.java
  70. 7
    7
      src/java/org/apache/poi/poifs/property/PropertyTable.java
  71. 4
    4
      src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java
  72. 9
    7
      src/java/org/apache/poi/sl/draw/DrawPaint.java
  73. 6
    6
      src/java/org/apache/poi/sl/draw/DrawPictureShape.java
  74. 16
    11
      src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
  75. 97
    114
      src/java/org/apache/poi/sl/draw/SLGraphics.java
  76. 4
    4
      src/java/org/apache/poi/sl/draw/geom/PresetGeometries.java
  77. 4
    4
      src/java/org/apache/poi/sl/draw/geom/PresetParser.java
  78. 4
    4
      src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java
  79. 5
    5
      src/java/org/apache/poi/sl/image/ImageHeaderBitmap.java
  80. 5
    5
      src/java/org/apache/poi/sl/image/ImageHeaderEMF.java
  81. 5
    5
      src/java/org/apache/poi/sl/image/ImageHeaderWMF.java
  82. 4
    4
      src/java/org/apache/poi/sl/usermodel/ObjectData.java
  83. 4
    4
      src/java/org/apache/poi/ss/extractor/EmbeddedExtractor.java
  84. 5
    5
      src/java/org/apache/poi/ss/format/CellNumberFormatter.java
  85. 13
    13
      src/java/org/apache/poi/ss/formula/FormulaParser.java
  86. 27
    36
      src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
  87. 8
    5
      src/java/org/apache/poi/ss/formula/constant/ErrorConstant.java
  88. 5
    5
      src/java/org/apache/poi/ss/formula/functions/Rate.java
  89. 8
    8
      src/java/org/apache/poi/ss/usermodel/DataFormatter.java
  90. 4
    4
      src/java/org/apache/poi/ss/usermodel/FractionFormat.java
  91. 11
    23
      src/java/org/apache/poi/ss/util/CellUtil.java
  92. 4
    4
      src/java/org/apache/poi/ss/util/DateFormatConverter.java
  93. 8
    8
      src/java/org/apache/poi/ss/util/ImageUtils.java
  94. 0
    177
      src/java/org/apache/poi/util/CommonsLogger.java
  95. 5
    2
      src/java/org/apache/poi/util/Configurator.java
  96. 4
    3
      src/java/org/apache/poi/util/IOUtils.java
  97. 0
    81
      src/java/org/apache/poi/util/NullLogger.java
  98. 0
    122
      src/java/org/apache/poi/util/POILogFactory.java
  99. 0
    128
      src/java/org/apache/poi/util/POILogger.java
  100. 0
    0
      src/java/org/apache/poi/util/SLF4JLogger.java

+ 1
- 2
.classpath View File

<classpathentry kind="lib" path="lib/main-tests/jmh-core-1.26.jar"/> <classpathentry kind="lib" path="lib/main-tests/jmh-core-1.26.jar"/>
<classpathentry kind="lib" path="lib/main-tests/jmh-generator-annprocess-1.26.jar"/> <classpathentry kind="lib" path="lib/main-tests/jmh-generator-annprocess-1.26.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry exported="true" kind="lib" path="compile-lib/slf4j-api-1.7.30.jar"/>
<classpathentry exported="true" kind="lib" path="compile-lib/log4j-api-2.14.0.jar"/>
<classpathentry kind="lib" path="lib/ooxml-provided/bcpkix-jdk15on-1.67.jar"/> <classpathentry kind="lib" path="lib/ooxml-provided/bcpkix-jdk15on-1.67.jar"/>
<classpathentry kind="lib" path="lib/ooxml-provided/bcprov-jdk15on-1.67.jar"/> <classpathentry kind="lib" path="lib/ooxml-provided/bcprov-jdk15on-1.67.jar"/>
<classpathentry kind="lib" path="lib/ooxml-tests/reflections-0.9.12.jar"/> <classpathentry kind="lib" path="lib/ooxml-tests/reflections-0.9.12.jar"/>
<classpathentry kind="lib" path="lib/ooxml-tests/log4j-1.2.17.jar"/> <classpathentry kind="lib" path="lib/ooxml-tests/log4j-1.2.17.jar"/>
<classpathentry exported="true" kind="lib" path="lib/ooxml-provided/xmlsec-2.2.0.jar"/> <classpathentry exported="true" kind="lib" path="lib/ooxml-provided/xmlsec-2.2.0.jar"/>
<classpathentry exported="true" kind="lib" path="lib/commons-codec-1.15.jar"/> <classpathentry exported="true" kind="lib" path="lib/commons-codec-1.15.jar"/>
<classpathentry exported="true" kind="lib" path="lib/commons-logging-1.2.jar"/>
<classpathentry exported="true" kind="lib" path="lib/commons-collections4-4.4.jar"/> <classpathentry exported="true" kind="lib" path="lib/commons-collections4-4.4.jar"/>
<classpathentry kind="lib" path="lib/commons-math3-3.6.1.jar"/> <classpathentry kind="lib" path="lib/commons-math3-3.6.1.jar"/>
<classpathentry kind="lib" path="lib/main-tests/xmlunit-core-2.8.0.jar"/> <classpathentry kind="lib" path="lib/main-tests/xmlunit-core-2.8.0.jar"/>

+ 0
- 1
.gitignore View File

*.el *.el
scripts scripts
untitled1.jpx untitled1.jpx
log*.*
*.log *.log


forrest.properties forrest.properties

+ 11
- 4
build.gradle View File

commonsMathVersion = '3.6.1' commonsMathVersion = '3.6.1'
japicmpversion = '5.0.0' japicmpversion = '5.0.0'
junitVersion = '5.7.0' junitVersion = '5.7.0'
log4jVersion = '2.14.0'
mockitoVersion = '3.6.0' mockitoVersion = '3.6.0'
hamcrestVersion = '2.2' hamcrestVersion = '2.2'
slf4jVersion = '1.7.30'
xmlbeansVersion = '4.0.0' xmlbeansVersion = '4.0.0'
} }


testCompile "org.junit.jupiter:junit-jupiter:${junitVersion}" testCompile "org.junit.jupiter:junit-jupiter:${junitVersion}"
testCompile "org.mockito:mockito-core:${mockitoVersion}" testCompile "org.mockito:mockito-core:${mockitoVersion}"
testCompile "org.hamcrest:hamcrest:${hamcrestVersion}" testCompile "org.hamcrest:hamcrest:${hamcrestVersion}"
testCompile "org.apache.logging.log4j:log4j-core:${log4jVersion}"
} }


jar { jar {
sourceSets.main.java.srcDirs = ['../../src/java'] sourceSets.main.java.srcDirs = ['../../src/java']
sourceSets.main.resources.srcDirs = ['../../src/resources/main'] sourceSets.main.resources.srcDirs = ['../../src/resources/main']
sourceSets.test.java.srcDirs = ['../../src/testcases'] sourceSets.test.java.srcDirs = ['../../src/testcases']
sourceSets.test.resources.srcDirs = ['../../src/resources/test']


dependencies { dependencies {
compile "commons-codec:commons-codec:${commonsCodecVersion}" compile "commons-codec:commons-codec:${commonsCodecVersion}"
compile 'commons-logging:commons-logging:1.2'
compile 'org.apache.commons:commons-collections4:4.4' compile 'org.apache.commons:commons-collections4:4.4'
compile "org.apache.commons:commons-math3:${commonsMathVersion}" compile "org.apache.commons:commons-math3:${commonsMathVersion}"
compile "org.slf4j:slf4j-api:${slf4jVersion}"
compile "org.apache.logging.log4j:log4j-api:${log4jVersion}"
compile 'javax.activation:activation:1.1.1' compile 'javax.activation:activation:1.1.1'
compile 'com.zaxxer:SparseBitSet:1.2' compile 'com.zaxxer:SparseBitSet:1.2'


testCompile 'org.reflections:reflections:0.9.12' testCompile 'org.reflections:reflections:0.9.12'
testRuntime "org.slf4j:slf4j-simple:${slf4jVersion}"
} }


jar { jar {
sourceSets.main.java.srcDirs = ['../../src/ooxml/java'] sourceSets.main.java.srcDirs = ['../../src/ooxml/java']
sourceSets.main.resources.srcDirs = ['../../src/ooxml/resources', '../../src/resources/ooxml'] sourceSets.main.resources.srcDirs = ['../../src/ooxml/resources', '../../src/resources/ooxml']
sourceSets.test.java.srcDirs = ['../../src/ooxml/testcases'] sourceSets.test.java.srcDirs = ['../../src/ooxml/testcases']
sourceSets.test.resources.srcDirs = ['../../src/resources/test']


configurations { configurations {
antdep antdep
compile "org.bouncycastle:bcpkix-jdk15on:${bouncyCastleVersion}" compile "org.bouncycastle:bcpkix-jdk15on:${bouncyCastleVersion}"
compile 'com.github.virtuald:curvesapi:1.06' compile 'com.github.virtuald:curvesapi:1.06'
compile 'com.zaxxer:SparseBitSet:1.2' compile 'com.zaxxer:SparseBitSet:1.2'
compile "org.apache.logging.log4j:log4j-api:${log4jVersion}"


// compile only, don't add it to our dist as it blows up the size // compile only, don't add it to our dist as it blows up the size
compile 'org.apache.xmlgraphics:batik-all:1.14' compile 'org.apache.xmlgraphics:batik-all:1.14'
compile project(':scratchpad') compile project(':scratchpad')


compile "org.apache.xmlbeans:xmlbeans:${xmlbeansVersion}" compile "org.apache.xmlbeans:xmlbeans:${xmlbeansVersion}"
compile "org.apache.logging.log4j:log4j-core:${log4jVersion}"


compile files("../../build/dist/maven/poi-ooxml-full/poi-ooxml-full-${version}.jar") compile files("../../build/dist/maven/poi-ooxml-full/poi-ooxml-full-${version}.jar")
compile "org.apache.commons:commons-compress:${commonsCompressVersion}" compile "org.apache.commons:commons-compress:${commonsCompressVersion}"
sourceSets.main.java.srcDirs = ['../../src/excelant/java'] sourceSets.main.java.srcDirs = ['../../src/excelant/java']
sourceSets.main.resources.srcDirs = ['../../src/excelant/resources'] sourceSets.main.resources.srcDirs = ['../../src/excelant/resources']
sourceSets.test.java.srcDirs = ['../../src/excelant/testcases'] sourceSets.test.java.srcDirs = ['../../src/excelant/testcases']
sourceSets.test.resources.srcDirs = ['../../src/resources/test']


dependencies { dependencies {
compile 'org.apache.ant:ant:1.10.9' compile 'org.apache.ant:ant:1.10.9'


project('integrationtest') { project('integrationtest') {
sourceSets.test.java.srcDirs = ['../../src/integrationtest'] sourceSets.test.java.srcDirs = ['../../src/integrationtest']
sourceSets.test.resources.srcDirs = ['../../src/resources/integrationtest']


dependencies { dependencies {
compile 'org.apache.ant:ant:1.10.9' compile 'org.apache.ant:ant:1.10.9'
sourceSets.main.java.srcDirs = ['../../src/scratchpad/src'] sourceSets.main.java.srcDirs = ['../../src/scratchpad/src']
sourceSets.main.resources.srcDirs = ['../../src/resources/scratchpad'] sourceSets.main.resources.srcDirs = ['../../src/resources/scratchpad']
sourceSets.test.java.srcDirs = ['../../src/scratchpad/testcases'] sourceSets.test.java.srcDirs = ['../../src/scratchpad/testcases']
sourceSets.test.resources.srcDirs = ['../../src/resources/test']


dependencies { dependencies {
compile project(':main') compile project(':main')
compile "commons-codec:commons-codec:${commonsCodecVersion}" compile "commons-codec:commons-codec:${commonsCodecVersion}"
compile "org.apache.commons:commons-math3:${commonsMathVersion}" compile "org.apache.commons:commons-math3:${commonsMathVersion}"
compile "org.apache.logging.log4j:log4j-api:${log4jVersion}"


// cyclic-dependency here: compile project(':ooxml') // cyclic-dependency here: compile project(':ooxml')



+ 32
- 27
build.xml View File

<matches pattern="^10\..*" string="${java.version}"/> <matches pattern="^10\..*" string="${java.version}"/>
</condition> </condition>



<!--
Logging is suppressed by default.
To redirect log output to console, run ant with -Dorg.apache.poi.util.POILogger=org.apache.poi.util.SystemOutLogger
-->
<property name="org.apache.poi.util.POILogger" value="org.apache.poi.util.NullLogger"/>

<!-- issue warnings if source code contains unmappable characters for encoding ASCII --> <!-- issue warnings if source code contains unmappable characters for encoding ASCII -->
<property name="java.source.encoding" value="UTF-8"/> <property name="java.source.encoding" value="UTF-8"/>


<property name="main.resource1.dir" value="src/resources/main"/> <property name="main.resource1.dir" value="src/resources/main"/>
<property name="main.src" location="src/java"/> <property name="main.src" location="src/java"/>
<property name="main.src.test" location="src/testcases"/> <property name="main.src.test" location="src/testcases"/>
<property name="main.resources.test" location="src/resources/test"/>
<property name="main.documentation" value="src/documentation"/> <property name="main.documentation" value="src/documentation"/>
<property name="main.output.dir" location="build/classes"/> <property name="main.output.dir" location="build/classes"/>
<property name="main.output.test.dir" location="build/test-classes"/> <property name="main.output.test.dir" location="build/test-classes"/>
<property name="scratchpad.resource1.dir" value="src/resources/scratchpad"/> <property name="scratchpad.resource1.dir" value="src/resources/scratchpad"/>
<property name="scratchpad.src" location="src/scratchpad/src"/> <property name="scratchpad.src" location="src/scratchpad/src"/>
<property name="scratchpad.src.test" location="src/scratchpad/testcases"/> <property name="scratchpad.src.test" location="src/scratchpad/testcases"/>
<property name="scratchpad.resources.test" location="src/resources/test"/>
<property name="scratchpad.reports.test" location="build/scratchpad-test-results"/> <property name="scratchpad.reports.test" location="build/scratchpad-test-results"/>
<property name="scratchpad.output.dir" location="build/scratchpad-classes"/> <property name="scratchpad.output.dir" location="build/scratchpad-classes"/>
<property name="scratchpad.output.test.dir" location="build/scratchpad-test-classes"/> <property name="scratchpad.output.test.dir" location="build/scratchpad-test-classes"/>
<property name="ooxml.src" location="src/ooxml/java"/> <property name="ooxml.src" location="src/ooxml/java"/>
<property name="ooxml.resource1.dir" value="src/resources/ooxml"/> <property name="ooxml.resource1.dir" value="src/resources/ooxml"/>
<property name="ooxml.src.test" location="src/ooxml/testcases"/> <property name="ooxml.src.test" location="src/ooxml/testcases"/>
<property name="ooxml.resources.test" location="src/resources/test"/>
<property name="ooxml.reports.test" location="build/ooxml-test-results"/> <property name="ooxml.reports.test" location="build/ooxml-test-results"/>
<property name="ooxml.output.dir" location="build/ooxml-classes"/> <property name="ooxml.output.dir" location="build/ooxml-classes"/>
<property name="ooxml.output.test.dir" location="build/ooxml-test-classes"/> <property name="ooxml.output.test.dir" location="build/ooxml-test-classes"/>


<!-- Integration testing: --> <!-- Integration testing: -->
<property name="integration.src.test" location="src/integrationtest"/> <property name="integration.src.test" location="src/integrationtest"/>
<property name="integration.resources.test" location="src/resources/integrationtest"/>
<property name="integration.reports.test" location="build/integration-test-results"/> <property name="integration.reports.test" location="build/integration-test-results"/>
<property name="integration.output.test.dir" location="build/integration-test-classes"/> <property name="integration.output.test.dir" location="build/integration-test-classes"/>
<property name="integration.testokfile" location="build/integration-testokfile.txt"/> <property name="integration.testokfile" location="build/integration-testokfile.txt"/>
<property name="excelant.resource.dir" value="src/excelant/resources"/> <property name="excelant.resource.dir" value="src/excelant/resources"/>
<property name="excelant.src" location="src/excelant/java"/> <property name="excelant.src" location="src/excelant/java"/>
<property name="excelant.src.test" location="src/excelant/testcases"/> <property name="excelant.src.test" location="src/excelant/testcases"/>
<property name="excelant.resources.test" location="src/resources/test"/>
<property name="excelant.reports.test" location="build/excelant-test-results"/> <property name="excelant.reports.test" location="build/excelant-test-results"/>
<property name="excelant.output.dir" location="build/excelant-classes"/> <property name="excelant.output.dir" location="build/excelant-classes"/>
<property name="excelant.output.test.dir" location="build/excelant-test-classes"/> <property name="excelant.output.test.dir" location="build/excelant-test-classes"/>




<!-- jars in the /lib directory, see the fetch-jars target--> <!-- jars in the /lib directory, see the fetch-jars target-->
<dependency prefix="main.commons-logging" artifact="org.slf4j:jcl-over-slf4j:1.7.30" usage="main"/>
<dependency prefix="main.commons-codec" artifact="commons-codec:commons-codec:1.15" usage="main"/> <dependency prefix="main.commons-codec" artifact="commons-codec:commons-codec:1.15" usage="main"/>
<dependency prefix="main.commons-collections4" artifact="org.apache.commons:commons-collections4:4.4" usage="main"/> <dependency prefix="main.commons-collections4" artifact="org.apache.commons:commons-collections4:4.4" usage="main"/>
<dependency prefix="main.commons-math3" artifact="org.apache.commons:commons-math3:3.6.1" usage="main"/> <dependency prefix="main.commons-math3" artifact="org.apache.commons:commons-math3:3.6.1" usage="main"/>
<dependency prefix="main.com.zaxxer" artifact="com.zaxxer:SparseBitSet:1.2" usage="main"/> <dependency prefix="main.com.zaxxer" artifact="com.zaxxer:SparseBitSet:1.2" usage="main"/>
<dependency prefix="main.slf4j-api" artifact="org.slf4j:slf4j-api:1.7.30" usage="main"/>
<dependency prefix="main.log4j-api" artifact="org.apache.logging.log4j:log4j-api:2.14.0" usage="main"/>


<dependency prefix="main.junit-api" artifact="org.junit.jupiter:junit-jupiter-api:5.7.0" usage="main-tests"/> <dependency prefix="main.junit-api" artifact="org.junit.jupiter:junit-jupiter-api:5.7.0" usage="main-tests"/>
<dependency prefix="main.junit-jengine" artifact="org.junit.jupiter:junit-jupiter-engine:5.7.0" usage="main-tests"/> <dependency prefix="main.junit-jengine" artifact="org.junit.jupiter:junit-jupiter-engine:5.7.0" usage="main-tests"/>
<dependency prefix="main.byte-buddy" artifact="net.bytebuddy:byte-buddy:1.10.19" usage="main-tests"/> <dependency prefix="main.byte-buddy" artifact="net.bytebuddy:byte-buddy:1.10.19" usage="main-tests"/>
<dependency prefix="main.byte-buddy-agent" artifact="net.bytebuddy:byte-buddy-agent:1.10.19" usage="main-tests"/> <dependency prefix="main.byte-buddy-agent" artifact="net.bytebuddy:byte-buddy-agent:1.10.19" usage="main-tests"/>
<dependency prefix="main.objenesis" artifact="org.objenesis:objenesis:3.1" usage="main-tests"/> <dependency prefix="main.objenesis" artifact="org.objenesis:objenesis:3.1" usage="main-tests"/>
<dependency prefix="main.slf4j-simple" artifact="org.slf4j:slf4j-simple:1.7.30" usage="main-tests"/>
<dependency prefix="main.log4j-core" artifact="org.apache.logging.log4j:log4j-core:2.14.0" usage="main-tests"/>
<dependency prefix="main.commons-logging" artifact="commons-logging:commons-logging:1.2" usage="main-tests"/>
<dependency prefix="main.slf4j-api" artifact="org.slf4j:slf4j-api:1.7.30" usage="main-tests"/>


<dependency prefix="main.ant" artifact="org.apache.ant:ant:1.10.9" usage="excelant"/> <dependency prefix="main.ant" artifact="org.apache.ant:ant:1.10.9" usage="excelant"/>
<dependency prefix="main.antlauncher" artifact="org.apache.ant:ant-launcher:1.10.9" usage="excelant"/> <dependency prefix="main.antlauncher" artifact="org.apache.ant:ant-launcher:1.10.9" usage="excelant"/>
<!-- Coverage --> <!-- Coverage -->
<property name="coverage.dir" value="build/coverage"/> <property name="coverage.dir" value="build/coverage"/>
<!-- Exclude some uninteresting classes from coverage-instrumentation as we do not want to measure coverage in those packages anyway --> <!-- Exclude some uninteresting classes from coverage-instrumentation as we do not want to measure coverage in those packages anyway -->
<property name="coverage.excludes" value="org.openxmlformats.*:com.*:org.junit.*:junit.*:org.etsi.*:org.w3.*:org.slf4j.*:org.hamcrest.*:org.bouncycastle.*:org.apache.xmlbeans.*:org.apache.tools.*:org.apache.commons.*:org.apache.jcp.*:sun.*:schemaorg_apache_xmlbeans.*"/>
<property name="coverage.excludes" value="org.openxmlformats.*:com.*:org.junit.*:junit.*:org.etsi.*:org.w3.*:org.slf4j.*:org.apache.logging.log4j.*:org.hamcrest.*:org.bouncycastle.*:org.apache.xmlbeans.*:org.apache.tools.*:org.apache.commons.*:org.apache.jcp.*:sun.*:schemaorg_apache_xmlbeans.*"/>


<property name="file.leak.detector" value="-Dthis.is.a.dummy=true"/> <property name="file.leak.detector" value="-Dthis.is.a.dummy=true"/>


<propertyset id="junit.properties"> <propertyset id="junit.properties">
<propertyref name="POI.testdata.path"/> <propertyref name="POI.testdata.path"/>
<propertyref name="java.awt.headless"/> <propertyref name="java.awt.headless"/>
<propertyref name="org.apache.poi.util.POILogger"/>
<propertyref name="http_proxy"/> <propertyref name="http_proxy"/>
<propertyref name="additionaljar"/> <propertyref name="additionaljar"/>
<propertyref name="user.language"/> <propertyref name="user.language"/>
<propertyref name="user.country"/> <propertyref name="user.country"/>
<propertyref name="javax.xml.stream.XMLInputFactory"/> <propertyref name="javax.xml.stream.XMLInputFactory"/>
<propertyref name="org.apache.commons.logging.Log"/>
<!-- required for Java 9 compilation --> <!-- required for Java 9 compilation -->
<propertyref name="java.locale.providers"/> <propertyref name="java.locale.providers"/>
<!-- to detect if we are running on slow Gump VM --> <!-- to detect if we are running on slow Gump VM -->
</propertyset> </propertyset>


<path id="main.classpath"> <path id="main.classpath">
<pathelement location="${main.commons-logging.jar}"/>
<pathelement location="${main.commons-codec.jar}"/> <pathelement location="${main.commons-codec.jar}"/>
<pathelement location="${main.commons-collections4.jar}"/> <pathelement location="${main.commons-collections4.jar}"/>
<pathelement location="${main.commons-math3.jar}"/> <pathelement location="${main.commons-math3.jar}"/>
<pathelement location="${main.com.zaxxer.jar}"/> <pathelement location="${main.com.zaxxer.jar}"/>
<pathelement location="${main.log4j-api.jar}"/>
</path> </path>


<!-- some libraries should only be required for compiling/running tests --> <!-- some libraries should only be required for compiling/running tests -->
<pathelement location="${main.byte-buddy.jar}"/> <pathelement location="${main.byte-buddy.jar}"/>
<pathelement location="${main.byte-buddy-agent.jar}"/> <pathelement location="${main.byte-buddy-agent.jar}"/>
<pathelement location="${main.objenesis.jar}"/> <pathelement location="${main.objenesis.jar}"/>
<pathelement location="${main.slf4j-simple.jar}"/>
<pathelement location="${main.log4j-core.jar}"/>
<pathelement location="${main.commons-logging.jar}"/>
<pathelement location="${main.slf4j-api.jar}"/>
</path> </path>


<path id="scratchpad.classpath"> <path id="scratchpad.classpath">
<path refid="ooxml.classpath"/> <path refid="ooxml.classpath"/>
<path refid="ooxml.xmlsec.classpath"/> <path refid="ooxml.xmlsec.classpath"/>
<path refid="test.jar.classpath"/> <path refid="test.jar.classpath"/>
<pathelement location="${main.slf4j-api.jar}"/>
<pathelement location="${main.log4j-api.jar}"/>
<path path="${env.CLASSPATH}"/> <path path="${env.CLASSPATH}"/>
</path> </path>


<condition property="jars.present"> <condition property="jars.present">
<or> <or>
<and> <and>
<available file="${main.commons-logging.jar}"/>
<available file="${main.commons-codec.jar}"/> <available file="${main.commons-codec.jar}"/>
<available file="${main.junit-api.jar}"/> <available file="${main.junit-api.jar}"/>
<available file="${main.junit-jengine.jar}"/> <available file="${main.junit-jengine.jar}"/>
<available file="${main.ant.jar}"/> <available file="${main.ant.jar}"/>
<available file="${main.antlauncher.jar}"/> <available file="${main.antlauncher.jar}"/>
<available file="${main.slf4j-api.jar}"/> <available file="${main.slf4j-api.jar}"/>
<available file="${main.slf4j-simple.jar}"/>
<available file="${main.log4j-api.jar}"/>
<available file="${main.log4j-core.jar}"/>
<available file="${asm.jar}"/> <available file="${asm.jar}"/>
<available file="${asm-commons.jar}"/> <available file="${asm-commons.jar}"/>
<available file="${asm-tree.jar}"/> <available file="${asm-tree.jar}"/>
<downloadfile src="${main.ant.url}" dest="${main.ant.jar}"/> <downloadfile src="${main.ant.url}" dest="${main.ant.jar}"/>
<downloadfile src="${main.antlauncher.url}" dest="${main.antlauncher.jar}"/> <downloadfile src="${main.antlauncher.url}" dest="${main.antlauncher.jar}"/>
<downloadfile src="${main.slf4j-api.url}" dest="${main.slf4j-api.jar}"/> <downloadfile src="${main.slf4j-api.url}" dest="${main.slf4j-api.jar}"/>
<downloadfile src="${main.slf4j-simple.url}" dest="${main.slf4j-simple.jar}"/>
<downloadfile src="${main.log4j-api.url}" dest="${main.log4j-api.jar}"/>
<downloadfile src="${main.log4j-core.url}" dest="${main.log4j-core.jar}"/>
<downloadfile src="${asm.url}" dest="${asm.jar}"/> <downloadfile src="${asm.url}" dest="${asm.jar}"/>
<downloadfile src="${asm-commons.url}" dest="${asm-commons.jar}"/> <downloadfile src="${asm-commons.url}" dest="${asm-commons.jar}"/>
<downloadfile src="${asm-tree.url}" dest="${asm-tree.jar}"/> <downloadfile src="${asm-tree.url}" dest="${asm-tree.jar}"/>
<resources> <resources>
<fileset dir="${main.resource1.dir}"/> <fileset dir="${main.resource1.dir}"/>
</resources> </resources>
<test-resources>
<fileset dir="${main.resources.test}" />
</test-resources>
</compile-jar> </compile-jar>
</target> </target>


<resources> <resources>
<fileset dir="${scratchpad.resource1.dir}"/> <fileset dir="${scratchpad.resource1.dir}"/>
</resources> </resources>
<test-resources>
<fileset dir="${scratchpad.resources.test}" />
</test-resources>
</compile-jar> </compile-jar>
</target> </target>


<resources> <resources>
<fileset dir="${ooxml.resource1.dir}"/> <fileset dir="${ooxml.resource1.dir}"/>
</resources> </resources>
<test-resources>
<fileset dir="${ooxml.resources.test}" />
</test-resources>
</compile-jar> </compile-jar>


<!-- create ooxml-lite-agent jar --> <!-- create ooxml-lite-agent jar -->
<jvmarg line="--add-modules org.junit.jupiter.params" unless:true="${isJava8}"/> <jvmarg line="--add-modules org.junit.jupiter.params" unless:true="${isJava8}"/>
<jvmarg line="--add-modules org.apache.poi.@{module1}" if:set="use_module1"/> <jvmarg line="--add-modules org.apache.poi.@{module1}" if:set="use_module1"/>
<jvmarg line="--add-modules org.apache.poi.@{module2}" if:set="use_module2"/> <jvmarg line="--add-modules org.apache.poi.@{module2}" if:set="use_module2"/>

<!-- mute some notorious talkative classes -->
<jvmarg line="-Dorg.slf4j.simpleLogger.log.org.apache.poi.hdgf.chunks.Chunk=off"/>
<jvmarg line="-Dorg.slf4j.simpleLogger.log.org.apache.poi=error"/>
</fork> </fork>


<listener classname="Junit5Progress" /> <listener classname="Junit5Progress" />
<pathelement location="${examples.output.dir}"/> <pathelement location="${examples.output.dir}"/>
<pathelement location="${main.ant.jar}"/> <pathelement location="${main.ant.jar}"/>
<pathelement location="${scratchpad.output.dir}"/> <pathelement location="${scratchpad.output.dir}"/>
<pathelement location="${integration.resources.test}"/>
</classpath> </classpath>
<exclude name="**/HeapDump**" if:true="${isIBMVM}"/> <exclude name="**/HeapDump**" if:true="${isIBMVM}"/>
</javac> </javac>


<target name="test-integration" depends="compile-integration,-test-integration-check,jacocotask" <target name="test-integration" depends="compile-integration,-test-integration-check,jacocotask"
unless="integration.test.notRequired"> unless="integration.test.notRequired">
<propertyreset name="org.apache.poi.util.POILogger" value="org.apache.poi.util.SLF4JLogger"/>
<delete dir="build" includes="test-integration.log*"/> <delete dir="build" includes="test-integration.log*"/>


<path id="test-integration.modules"> <path id="test-integration.modules">
<mappedresources cache="true"> <mappedresources cache="true">
<fileset dir="${main.lib}"> <fileset dir="${main.lib}">
<include name="commons-codec-*.jar"/> <include name="commons-codec-*.jar"/>
<include name="commons-logging-*.jar"/>
<include name="commons-collections4-*.jar"/> <include name="commons-collections4-*.jar"/>
<include name="commons-math3-*.jar"/> <include name="commons-math3-*.jar"/>
<include name="log4j-api-*.jar"/>
<include name="SparseBitSet-*.jar"/> <include name="SparseBitSet-*.jar"/>
</fileset> </fileset>
<globmapper from="*" to="${zipdir}/lib/*"/> <globmapper from="*" to="${zipdir}/lib/*"/>
<auxClasspath path="${main.commons-math3.jar}" /> <auxClasspath path="${main.commons-math3.jar}" />
<auxClasspath path="${main.commons-codec.jar}" /> <auxClasspath path="${main.commons-codec.jar}" />
<auxClasspath path="${main.commons-logging.jar}" /> <auxClasspath path="${main.commons-logging.jar}" />
<auxClasspath path="${main.slf4j-api.jar}" />
<auxClasspath path="${main.slf4j-simple.jar}" />
<auxClasspath path="${main.log4j-api.jar}" />
<auxClasspath path="${main.log4j-core.jar}" />
<auxClasspath path="${main.junit-api.jar}" /> <auxClasspath path="${main.junit-api.jar}" />
<auxClasspath path="${main.junit-jengine.jar}" /> <auxClasspath path="${main.junit-jengine.jar}" />
<auxClasspath path="${main.junit-params.jar}" /> <auxClasspath path="${main.junit-params.jar}" />

+ 2
- 22
legal/LICENSE View File

NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


SLF4J library (slf4j-api-*.jar)
Log4j 2 library (log4j-api-*.jar)


Copyright (c) 2004-2017 QOS.ch
All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Apache License Version 2.0




inbot-utils (https://github.com/Inbot/inbot-utils) inbot-utils (https://github.com/Inbot/inbot-utils)

+ 3
- 8
maven/poi.pom View File



<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.30</version>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-codec</groupId> <groupId>commons-codec</groupId>

+ 1
- 0
osgi/README.md View File

- commons-compress - commons-compress
- commons-collections4 - commons-collections4
- commons-codec - commons-codec
- Log4j 2 API


## Optional Dependencies ## Optional Dependencies



+ 6
- 6
osgi/pom.xml View File

!org.apache.commons.compress.*, !org.apache.commons.compress.*,
!com.zaxxer.sparsebits.*, !com.zaxxer.sparsebits.*,
!com.graphbuilder.*, !com.graphbuilder.*,
!org.apache.logging.log4j.*,
org.apache.batik.*;resolution:=optional, org.apache.batik.*;resolution:=optional,
org.apache.pdfbox.*;resolution:=optional, org.apache.pdfbox.*;resolution:=optional,
org.apache.fontbox.*;resolution:=optional, org.apache.fontbox.*;resolution:=optional,
org.apache.xml.resolver.*;resolution:=optional, org.apache.xml.resolver.*;resolution:=optional,
org.apache.xml.security.*;resolution:=optional, org.apache.xml.security.*;resolution:=optional,
org.bouncycastle.*;resolution:=optional, org.bouncycastle.*;resolution:=optional,
org.apache.commons.logging.*;resolution:=optional,
org.slf4j.*;resolution:=optional,
!com.github.luben.zstd.*, !com.github.luben.zstd.*,
!org.tukaani.xz.*, !org.tukaani.xz.*,
!org.brotli.dec.*, !org.brotli.dec.*,
commons-math3, commons-math3,
commons-compress, commons-compress,
commons-collections4, commons-collections4,
commons-codec
commons-codec,
log4j-api
</Embed-Dependency> </Embed-Dependency>
<Embed-Directory>lib</Embed-Directory> <Embed-Directory>lib</Embed-Directory>
<Embed-Transitive>true</Embed-Transitive> <Embed-Transitive>true</Embed-Transitive>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>

+ 3
- 0
sonar/excelant/pom.xml View File

<resource> <resource>
<directory>../../src/excelant/resources</directory> <directory>../../src/excelant/resources</directory>
</resource> </resource>
<resource>
<directory>../../src/resources/test</directory>
</resource>
</resources> </resources>
</configuration> </configuration>
</execution> </execution>

+ 3
- 0
sonar/integration-test/pom.xml View File

<include>org/apache/poi/hssf/HSSFTestDataSamples.java</include> <include>org/apache/poi/hssf/HSSFTestDataSamples.java</include>
</includes> </includes>
</resource> </resource>
<resource>
<directory>../../src/resources/integrationtest</directory>
</resource>
</resources> </resources>
</configuration> </configuration>
</execution> </execution>

+ 6
- 8
sonar/main/pom.xml View File

<resource> <resource>
<directory>../../src/testcases</directory> <directory>../../src/testcases</directory>
</resource> </resource>
<resource>
<directory>../../src/resources/test</directory>
</resource>
</resources> </resources>
</configuration> </configuration>
</execution> </execution>


<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.30</version>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-codec</groupId> <groupId>commons-codec</groupId>

+ 3
- 12
sonar/ooxml/pom.xml View File

<resource> <resource>
<directory>../../src/ooxml/testcases</directory> <directory>../../src/ooxml/testcases</directory>
</resource> </resource>
<resource>
<directory>../../src/resources/test</directory>
</resource>
</resources> </resources>
</configuration> </configuration>
</execution> </execution>
<groupId>org.apache.xmlgraphics</groupId> <groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-all</artifactId> <artifactId>batik-all</artifactId>
<version>1.14</version> <version>1.14</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>de.rototor.pdfbox</groupId> <groupId>de.rototor.pdfbox</groupId>
<artifactId>graphics2d</artifactId> <artifactId>graphics2d</artifactId>
<version>0.30</version> <version>0.30</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>


<dependency> <dependency>

+ 6
- 1
sonar/pom.xml View File

<systemPropertyVariables> <systemPropertyVariables>
<POI.testdata.path>../../test-data</POI.testdata.path> <POI.testdata.path>../../test-data</POI.testdata.path>
<java.awt.headless>true</java.awt.headless> <java.awt.headless>true</java.awt.headless>
<org.apache.poi.util.POILogger>org.apache.poi.util.NullLogger</org.apache.poi.util.POILogger>
</systemPropertyVariables> </systemPropertyVariables>
<!-- use to following to analyze OOM issues: -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp --> <!-- use to following to analyze OOM issues: -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -->
<argLine>@{argLine} -Duser.language=en -Duser.country=US -Xmx1024m -Djava.io.tmpdir=${basedir}/target/tmp -XX:-OmitStackTraceInFastThrow</argLine> <argLine>@{argLine} -Duser.language=en -Duser.country=US -Xmx1024m -Djava.io.tmpdir=${basedir}/target/tmp -XX:-OmitStackTraceInFastThrow</argLine>
<version>2.2</version> <version>2.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.0</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>


<profiles> <profiles>

+ 3
- 0
sonar/scratchpad/pom.xml View File

<resource> <resource>
<directory>../../src/scratchpad/testcases</directory> <directory>../../src/scratchpad/testcases</directory>
</resource> </resource>
<resource>
<directory>../../src/resources/test</directory>
</resource>
</resources> </resources>
</configuration> </configuration>
</execution> </execution>

+ 4
- 4
src/examples/src/org/apache/poi/examples/hssf/usermodel/Outlines.java View File

import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Creates outlines. * Creates outlines.
public class Outlines implements Closeable { public class Outlines implements Closeable {
public static void main(String[] args) public static void main(String[] args)
throws IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { throws IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
POILogger LOGGER = POILogFactory.getLogger(Outlines.class);
Logger LOGGER = LogManager.getLogger(Outlines.class);
for (int i=1; i<=13; i++) { for (int i=1; i<=13; i++) {
try (Outlines o = new Outlines()) { try (Outlines o = new Outlines()) {
String log = (String) Outlines.class.getDeclaredMethod("test" + i).invoke(o); String log = (String) Outlines.class.getDeclaredMethod("test" + i).invoke(o);
String filename = "outline" + i + ".xls"; String filename = "outline" + i + ".xls";
o.writeOut(filename); o.writeOut(filename);
LOGGER.log(POILogger.INFO, filename, " written. ", log);
LOGGER.atInfo().log("{} written. {}", filename, log);
} }
} }
} }

+ 0
- 16
src/integrationtest/commons-logging.properties View File

# 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.
log4j.configuration=log4j.properties

+ 0
- 39
src/integrationtest/log4j.properties View File

# 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.
log4j.rootLogger=info, R
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=build/test-integration.log
log4j.appender.R.MaxFileSize=1000KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=5
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
log4j.logger.org.apache.poi.poifs.nio.FileBackedDataSource=ERROR
log4j.logger.org.apache.poi.hdgf.chunks.Chunk=FATAL
log4j.logger.org.apache.poi.hpsf.CodePageString=ERROR
log4j.logger.org.apache.poi.hdgf.chunks.ChunkFactory=ERROR
log4j.logger.org.apache.poi.hslf.model.textproperties.BitMaskTextProp=ERROR
log4j.logger.org.apache.poi.hslf.usermodel.HSLFTextParagraph=ERROR
log4j.logger.org.apache.poi.openxml4j.opc.ZipPackage=ERROR
log4j.logger.org.apache.poi.POIDocument=WARN
log4j.logger.org.apache.poi.openxml4j.opc.OPCPackage=ERROR
log4j.logger.org.apache.poi.xssf.usermodel.XSSFWorkbook=ERROR
log4j.logger.org.apache.poi.hslf.usermodel.HSLFGroupShape=WARN
log4j.logger.org.apache.poi.hslf.record.Record=ERROR

+ 6
- 6
src/integrationtest/org/apache/poi/stress/HSLFFileHandler.java View File

import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStream; import java.io.InputStream;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.SystemOutLogger;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;


class HSLFFileHandler extends SlideShowHandler { class HSLFFileHandler extends SlideShowHandler {

private static final Logger LOGGER = LogManager.getLogger(HSLFFileHandler.class);

@Override @Override
public void handleFile(InputStream stream, String path) throws Exception { public void handleFile(InputStream stream, String path) throws Exception {
HSLFSlideShowImpl slide = new HSLFSlideShowImpl(stream); HSLFSlideShowImpl slide = new HSLFSlideShowImpl(stream);


System.out.println("Testing " + files.length + " files"); System.out.println("Testing " + files.length + " files");


POILogger logger = new SystemOutLogger();
for(File file : files) { for(File file : files) {
try { try {
testOneFile(file); testOneFile(file);
} catch (Throwable e) { } catch (Throwable e) {
logger.log(POILogger.WARN, "Failed to handle file ", file, e);
LOGGER.atWarn().withThrowable(e).log("Failed to handle file {}", file);
} }
} }
} }
private void testOneFile(File file) throws Exception { private void testOneFile(File file) throws Exception {
System.out.println(file); System.out.println(file);


//System.setProperty("org.apache.poi.util.POILogger", "org.apache.poi.util.SystemOutLogger");
try (InputStream stream = new FileInputStream(file)) { try (InputStream stream = new FileInputStream(file)) {
handleFile(stream, file.getPath()); handleFile(stream, file.getPath());
} }
} }


public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
System.setProperty("org.apache.poi.util.POILogger", "org.apache.poi.util.SystemOutLogger");
try (InputStream stream = new FileInputStream(args[0])) { try (InputStream stream = new FileInputStream(args[0])) {
new HSLFFileHandler().handleFile(stream, args[0]); new HSLFFileHandler().handleFile(stream, args[0]);
} }

+ 13
- 10
src/java/org/apache/poi/POIDocument.java View File



package org.apache.poi; package org.apache.poi;


import static org.apache.logging.log4j.util.Unbox.box;
import static org.apache.poi.hpsf.PropertySetFactory.newDocumentSummaryInformation; import static org.apache.poi.hpsf.PropertySetFactory.newDocumentSummaryInformation;


import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.Closeable; import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.List; import java.util.List;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hpsf.DocumentSummaryInformation; import org.apache.poi.hpsf.DocumentSummaryInformation;
import org.apache.poi.hpsf.PropertySet; import org.apache.poi.hpsf.PropertySet;
import org.apache.poi.hpsf.PropertySetFactory; import org.apache.poi.hpsf.PropertySetFactory;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* This holds the common functionality for all POI * This holds the common functionality for all POI
private DirectoryNode directory; private DirectoryNode directory;


/** For our own logging use */ /** For our own logging use */
private static final POILogger LOG = POILogFactory.getLogger(POIDocument.class);
private static final Logger LOG = LogManager.getLogger(POIDocument.class);


/* Have the property streams been read yet? (Only done on-demand) */ /* Have the property streams been read yet? (Only done on-demand) */
private boolean initialized; private boolean initialized;
if (clazz.isInstance(ps)) { if (clazz.isInstance(ps)) {
return (T)ps; return (T)ps;
} else if (ps != null) { } else if (ps != null) {
LOG.log(POILogger.WARN, localName+" property set came back with wrong class - "+ps.getClass().getName());
LOG.atWarn().log("{} property set came back with wrong class - {}", localName, ps.getClass().getName());
} else { } else {
LOG.log(POILogger.WARN, localName+" property set came back as null");
LOG.atWarn().log("{} property set came back as null {}", localName, box(5));
} }
} catch (IOException e) { } catch (IOException e) {
LOG.log(POILogger.ERROR, "can't retrieve property set", e);
LOG.atError().withThrowable(e).log("can't retrieve property set");
} }
return null; return null;
} }
// Create or Update the Property Set stream in the POIFS // Create or Update the Property Set stream in the POIFS
outFS.createOrUpdateDocument(bIn, name); outFS.createOrUpdateDocument(bIn, name);


LOG.log(POILogger.INFO, "Wrote property set ", name, " of size ", data.length);
LOG.atInfo().log("Wrote property set {} of size {}", name, box(data.length));
} catch(WritingNotSupportedException ignored) { } catch(WritingNotSupportedException ignored) {
LOG.log( POILogger.ERROR, "Couldn't write property set with name ", name, " as not supported by HPSF yet");
LOG.atError().log("Couldn't write property set with name {} as not supported by HPSF yet", name);
} }
} }


* {@link #write()} or to a different File. Overwriting the currently * {@link #write()} or to a different File. Overwriting the currently
* open file via an OutputStream isn't possible. * open file via an OutputStream isn't possible.
* *
* If {@code stream} is a {@link java.io.FileOutputStream} on a networked drive
* If {@code stream} is a {@link FileOutputStream} on a networked drive
* or has a high cost/latency associated with each written byte, * or has a high cost/latency associated with each written byte,
* consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream}
* consider wrapping the OutputStream in a {@link BufferedOutputStream}
* to improve write performance, or use {@link #write()} / {@link #write(File)} * to improve write performance, or use {@link #write()} / {@link #write(File)}
* if possible. * if possible.
* *

+ 4
- 4
src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java View File

import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException; import java.nio.charset.UnsupportedCharsetException;


import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


/** /**
* Charset represents the basic set of characters associated with a font (that it can display), and * Charset represents the basic set of characters associated with a font (that it can display), and
charset = Charset.forName(javaCharsetName); charset = Charset.forName(javaCharsetName);
return; return;
} catch (UnsupportedCharsetException e) { } catch (UnsupportedCharsetException e) {
POILogger logger = POILogFactory.getLogger(FontCharset.class);
logger.log(POILogger.WARN, "Unsupported charset: "+javaCharsetName);
Logger logger = LogManager.getLogger(FontCharset.class);
logger.atWarn().log("Unsupported charset: {}", javaCharsetName);
} }
} }
charset = null; charset = null;

+ 6
- 6
src/java/org/apache/poi/ddf/EscherContainerRecord.java View File

import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.HexDump; import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


/** /**
* Escher container records store other escher records as children. * Escher container records store other escher records as children.
public static final short SP_CONTAINER = EscherRecordTypes.SP_CONTAINER.typeID; public static final short SP_CONTAINER = EscherRecordTypes.SP_CONTAINER.typeID;
public static final short SOLVER_CONTAINER = EscherRecordTypes.SOLVER_CONTAINER.typeID; public static final short SOLVER_CONTAINER = EscherRecordTypes.SOLVER_CONTAINER.typeID;


private static final POILogger log = POILogFactory.getLogger(EscherContainerRecord.class);
private static final Logger LOGGER = LogManager.getLogger(EscherContainerRecord.class);


/** /**
* in case if document contains any charts we have such document structure: * in case if document contains any charts we have such document structure:
addChildRecord(child); addChildRecord(child);
if (offset >= data.length && bytesRemaining > 0) { if (offset >= data.length && bytesRemaining > 0) {
_remainingLength = bytesRemaining; _remainingLength = bytesRemaining;
if (log.check(POILogger.WARN)) {
log.log(POILogger.WARN, "Not enough Escher data: " + bytesRemaining + " bytes remaining but no space left");
}
LOGGER.atWarn().log("Not enough Escher data: {} bytes remaining but no space left", box(bytesRemaining));
} }
} }
return bytesWritten; return bytesWritten;

+ 7
- 7
src/java/org/apache/poi/ddf/EscherMetafileBlip.java View File

import java.util.zip.DeflaterOutputStream; import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream; import java.util.zip.InflaterInputStream;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFPictureData; import org.apache.poi.hssf.usermodel.HSSFPictureData;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


public final class EscherMetafileBlip extends EscherBlipRecord { public final class EscherMetafileBlip extends EscherBlipRecord {
private static final POILogger log = POILogFactory.getLogger(EscherMetafileBlip.class);
private static final Logger LOGGER = LogManager.getLogger(EscherMetafileBlip.class);
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000_000; private static final int MAX_RECORD_LENGTH = 100_000_000;


} }
return out.toByteArray(); return out.toByteArray();
} catch (IOException e) { } catch (IOException e) {
log.log(POILogger.WARN, "Possibly corrupt compression or non-compressed data", e);
LOGGER.atWarn().withThrowable(e).log("Possibly corrupt compression or non-compressed data");
return data; return data;
} }
} }
case BLIP_WMF: return HSSFPictureData.MSOBI_WMF; case BLIP_WMF: return HSSFPictureData.MSOBI_WMF;
case BLIP_PICT: return HSSFPictureData.MSOBI_PICT; case BLIP_PICT: return HSSFPictureData.MSOBI_PICT;
} }
if (log.check(POILogger.WARN)) {
log.log(POILogger.WARN, "Unknown metafile: " + getRecordId());
}
LOGGER.atWarn().log("Unknown metafile: {}", box(getRecordId()));
return 0; return 0;
} }



+ 4
- 4
src/java/org/apache/poi/extractor/ExtractorFactory.java View File

import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.EmptyFileException; import org.apache.poi.EmptyFileException;
import org.apache.poi.hssf.extractor.ExcelExtractor; import org.apache.poi.hssf.extractor.ExcelExtractor;
import org.apache.poi.poifs.crypt.Decryptor; import org.apache.poi.poifs.crypt.Decryptor;
import org.apache.poi.poifs.filesystem.FileMagic; import org.apache.poi.poifs.filesystem.FileMagic;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Figures out the correct POIOLE2TextExtractor for your supplied * Figures out the correct POIOLE2TextExtractor for your supplied
*/ */
public static final String OOXML_PACKAGE = "Package"; public static final String OOXML_PACKAGE = "Package";


private static final POILogger LOGGER = POILogFactory.getLogger(ExtractorFactory.class);
private static final Logger LOGGER = LogManager.getLogger(ExtractorFactory.class);


/** Should this thread prefer event based over usermodel based extractors? */ /** Should this thread prefer event based over usermodel based extractors? */
private static final ThreadLocal<Boolean> threadPreferEventExtractors = ThreadLocal.withInitial(() -> Boolean.FALSE); private static final ThreadLocal<Boolean> threadPreferEventExtractors = ThreadLocal.withInitial(() -> Boolean.FALSE);
textExtractors.add(createExtractor(stream)); textExtractors.add(createExtractor(stream));
} catch (IOException e) { } catch (IOException e) {
// Ignore, just means it didn't contain a format we support as yet // Ignore, just means it didn't contain a format we support as yet
LOGGER.log(POILogger.INFO, "Format not supported yet", e.getLocalizedMessage());
LOGGER.atInfo().log("Format not supported yet ({})", e.getLocalizedMessage());
} }
} }
return textExtractors.toArray(new POITextExtractor[0]); return textExtractors.toArray(new POITextExtractor[0]);

+ 7
- 7
src/java/org/apache/poi/hpsf/ClipboardData.java View File

==================================================================== */ ==================================================================== */
package org.apache.poi.hpsf; package org.apache.poi.hpsf;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayInputStream; import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


@Internal @Internal
public class ClipboardData { public class ClipboardData {
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000_000; private static final int MAX_RECORD_LENGTH = 100_000_000;


private static final POILogger LOG = POILogFactory.getLogger( ClipboardData.class );
private static final Logger LOG = LogManager.getLogger(ClipboardData.class);


private int _format; private int _format;
private byte[] _value; private byte[] _value;
long size = lei.readInt(); long size = lei.readInt();


if ( size < 4 ) { if ( size < 4 ) {
String msg =
"ClipboardData at offset "+offset+" size less than 4 bytes "+
"(doesn't even have format field!). Setting to format == 0 and hope for the best";
LOG.log( POILogger.WARN, msg);
LOG.atWarn().log("ClipboardData at offset {} size less than 4 bytes (doesn't even have format " +
"field!). Setting to format == 0 and hope for the best", box(offset));
_format = 0; _format = 0;
_value = new byte[0]; _value = new byte[0];
return; return;

+ 10
- 13
src/java/org/apache/poi/hpsf/CodePageString.java View File

import java.io.OutputStream; import java.io.OutputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.CodePageUtil; import org.apache.poi.util.CodePageUtil;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayInputStream; import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


@Internal @Internal
public class CodePageString { public class CodePageString {
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;


private static final POILogger LOG = POILogFactory.getLogger( CodePageString.class );
private static final Logger LOG = LogManager.getLogger(CodePageString.class);


private byte[] _value; private byte[] _value;


// TODO Some files, such as TestVisioWithCodepage.vsd, are currently // TODO Some files, such as TestVisioWithCodepage.vsd, are currently
// triggering this for values that don't look like codepages // triggering this for values that don't look like codepages
// See Bug #52258 for details // See Bug #52258 for details
String msg = "CodePageString started at offset #" + offset + " is not NULL-terminated";
LOG.log(POILogger.WARN, msg);
LOG.atWarn().log("CodePageString started at offset #{} is not NULL-terminated", box(offset));
} }


TypedPropertyValue.skipPadding(lei); TypedPropertyValue.skipPadding(lei);


final int terminator = result.indexOf( '\0' ); final int terminator = result.indexOf( '\0' );
if ( terminator == -1 ) { if ( terminator == -1 ) {
String msg =
"String terminator (\\0) for CodePageString property value not found. " +
"Continue without trimming and hope for the best.";
LOG.log(POILogger.WARN, msg);
LOG.atWarn().log("String terminator (\\0) for CodePageString property value not found. " +
"Continue without trimming and hope for the best.");
return result; return result;
} }
if ( terminator != result.length() - 1 ) { if ( terminator != result.length() - 1 ) {
String msg =
"String terminator (\\0) for CodePageString property value occured before the end of string. "+
"Trimming and hope for the best.";
LOG.log(POILogger.WARN, msg );
LOG.atWarn().log("String terminator (\\0) for CodePageString property value occurred before the end of " +
"string. Trimming and hope for the best.");
} }
return result.substring( 0, terminator ); return result.substring( 0, terminator );
} }

+ 9
- 7
src/java/org/apache/poi/hpsf/CustomProperties.java View File

import java.util.Set; import java.util.Set;


import org.apache.commons.collections4.bidimap.TreeBidiMap; import org.apache.commons.collections4.bidimap.TreeBidiMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hpsf.wellknown.PropertyIDMap; import org.apache.poi.hpsf.wellknown.PropertyIDMap;
import org.apache.poi.util.CodePageUtil; import org.apache.poi.util.CodePageUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


/** /**
* Maintains the instances of {@link CustomProperty} that belong to a * Maintains the instances of {@link CustomProperty} that belong to a
* HashMap&lt;String,Object&gt; mapping between Names and Custom Property Values. * HashMap&lt;String,Object&gt; mapping between Names and Custom Property Values.
*/ */
public class CustomProperties implements Map<String,Object> { public class CustomProperties implements Map<String,Object> {
private static final POILogger LOG = POILogFactory.getLogger(CustomProperties.class);
private static final Logger LOG = LogManager.getLogger(CustomProperties.class);
/** /**
* The custom properties * The custom properties
*/ */


@Override @Override
public void putAll(Map<? extends String, ?> m) { public void putAll(Map<? extends String, ?> m) {
for (Map.Entry<? extends String, ?> me : m.entrySet()) {
for (Entry<? extends String, ?> me : m.entrySet()) {
put(me.getKey(), me.getValue()); put(me.getKey(), me.getValue());
} }
} }
try { try {
cps = CodePageUtil.codepageToEncoding(cp, false); cps = CodePageUtil.codepageToEncoding(cp, false);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
LOG.log(POILogger.ERROR, "Codepage '", cp, "' can't be found.");
LOG.atError().log("Codepage '{}' can't be found.", box(cp));
} }
if (!cps.isEmpty() && Charset.forName(cps).newEncoder().canEncode(value)) { if (!cps.isEmpty() && Charset.forName(cps).newEncoder().canEncode(value)) {
return; return;
} }
LOG.log(POILogger.DEBUG, "Charset '"+cps+"' can't encode '"+value+"' - switching to unicode.");
LOG.atDebug().log("Charset '{}' can't encode '{}' - switching to unicode.", cps, value);
setCodepage(CodePageUtil.CP_UNICODE); setCodepage(CodePageUtil.CP_UNICODE);
} }
} }

+ 11
- 8
src/java/org/apache/poi/hpsf/Property.java View File

import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hpsf.wellknown.PropertyIDMap; import org.apache.poi.hpsf.wellknown.PropertyIDMap;
import org.apache.poi.util.CodePageUtil; import org.apache.poi.util.CodePageUtil;
import org.apache.poi.util.HexDump; import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianByteArrayInputStream; import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


/** /**
* A property in a {@link Section} of a {@link PropertySet}.<p> * A property in a {@link Section} of a {@link PropertySet}.<p>
*/ */
public static final int DEFAULT_CODEPAGE = CodePageUtil.CP_WINDOWS_1252; public static final int DEFAULT_CODEPAGE = CodePageUtil.CP_WINDOWS_1252;


private static final POILogger LOG = POILogFactory.getLogger(Property.class);
private static final Logger LOG = LogManager.getLogger(Property.class);


/** The property's ID. */ /** The property's ID. */
private long id; private long id;
* section's dictionary. Another special case are strings: Two properties * section's dictionary. Another special case are strings: Two properties
* may have the different types Variant.VT_LPSTR and Variant.VT_LPWSTR; * may have the different types Variant.VT_LPSTR and Variant.VT_LPWSTR;
* *
* @see Object#equals(java.lang.Object)
* @see Object#equals(Object)
*/ */
@Override @Override
public boolean equals(final Object o) { public boolean equals(final Object o) {
try { try {
write(bos, codepage); write(bos, codepage);
} catch (Exception e) { } catch (Exception e) {
LOG.log(POILogger.WARN, "can't serialize string", e);
LOG.atWarn().withThrowable(e).log("can't serialize string");
} }


// skip length field // skip length field
String hex = HexDump.dump(bytes, 0L, 0); String hex = HexDump.dump(bytes, 0L, 0);
b.append(hex); b.append(hex);
} }
} else if (value instanceof java.util.Date) {
java.util.Date d = (java.util.Date)value;
} else if (value instanceof Date) {
Date d = (Date)value;
long filetime = Filetime.dateToFileTime(d); long filetime = Filetime.dateToFileTime(d);
if (Filetime.isUndefined(d)) { if (Filetime.isUndefined(d)) {
b.append("<undefined>"); b.append("<undefined>");
return LocaleUtil.getLocaleFromLCID(((Number)value).intValue()); return LocaleUtil.getLocaleFromLCID(((Number)value).intValue());
} }
} catch (Exception e) { } catch (Exception e) {
LOG.log(POILogger.WARN, "Can't decode id "+getID());
LOG.atWarn().log("Can't decode id {}", box(getID()));
} }
return null; return null;
} }

+ 10
- 12
src/java/org/apache/poi/hpsf/Section.java View File

import java.util.TreeMap; import java.util.TreeMap;


import org.apache.commons.collections4.bidimap.TreeBidiMap; import org.apache.commons.collections4.bidimap.TreeBidiMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hpsf.wellknown.PropertyIDMap; import org.apache.poi.hpsf.wellknown.PropertyIDMap;
import org.apache.poi.util.CodePageUtil; import org.apache.poi.util.CodePageUtil;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianByteArrayInputStream; import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianOutputStream; import org.apache.poi.util.LittleEndianOutputStream;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Represents a section in a {@link PropertySet}. * Represents a section in a {@link PropertySet}.
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;


private static final POILogger LOG = POILogFactory.getLogger(Section.class);
private static final Logger LOG = LogManager.getLogger(Section.class);


/** /**
* Maps property IDs to section-private PID strings. These * Maps property IDs to section-private PID strings. These
id = Math.max(PropertyIDMap.PID_MAX, offset2Id.inverseBidiMap().lastKey())+1; id = Math.max(PropertyIDMap.PID_MAX, offset2Id.inverseBidiMap().lastKey())+1;
setProperty(new Property(id, leis, pLen, codepage)); setProperty(new Property(id, leis, pLen, codepage));
} catch (RuntimeException e) { } catch (RuntimeException e) {
LOG.log(POILogger.INFO, "Dictionary fallback failed - ignoring property");
LOG.atInfo().log("Dictionary fallback failed - ignoring property");
} }
} }
} else { } else {
* (property 0) the codepage property (property 1) must be set, too. */ * (property 0) the codepage property (property 1) must be set, too. */
int codepage = getCodepage(); int codepage = getCodepage();
if (codepage == -1) { if (codepage == -1) {
String msg =
"The codepage property is not set although a dictionary is present. "+
"Defaulting to ISO-8859-1.";
LOG.log(POILogger.WARN, msg);
LOG.atWarn().log("The codepage property is not set although a dictionary is present. " +
"Defaulting to ISO-8859-1.");
codepage = Property.DEFAULT_CODEPAGE; codepage = Property.DEFAULT_CODEPAGE;
} }


int cp = (codepage == -1) ? Property.DEFAULT_CODEPAGE : codepage; int cp = (codepage == -1) ? Property.DEFAULT_CODEPAGE : codepage;
int nrBytes = Math.toIntExact(((sLength-1) * (cp == CodePageUtil.CP_UNICODE ? 2 : 1))); int nrBytes = Math.toIntExact(((sLength-1) * (cp == CodePageUtil.CP_UNICODE ? 2 : 1)));
if (nrBytes > 0xFFFFFF) { if (nrBytes > 0xFFFFFF) {
LOG.log(POILogger.WARN, errMsg);
LOG.atWarn().log(errMsg);
isCorrupted = true; isCorrupted = true;
break; break;
} }


dic.put(id, str); dic.put(id, str);
} catch (RuntimeException|IOException ex) { } catch (RuntimeException|IOException ex) {
LOG.log(POILogger.WARN, errMsg, ex);
LOG.atWarn().withThrowable(ex).log(errMsg);
isCorrupted = true; isCorrupted = true;
break; break;
} }


/** /**
* Sets the section's dictionary. All keys in the dictionary must be * Sets the section's dictionary. All keys in the dictionary must be
* {@link java.lang.Long} instances, all values must be
* {@link java.lang.String}s. This method overwrites the properties with IDs
* {@link Long} instances, all values must be
* {@link String}s. This method overwrites the properties with IDs
* 0 and 1 since they are reserved for the dictionary and the dictionary's * 0 and 1 since they are reserved for the dictionary and the dictionary's
* codepage. Setting these properties explicitly might have surprising * codepage. Setting these properties explicitly might have surprising
* effects. An application should never do this but always use this * effects. An application should never do this but always use this

+ 6
- 5
src/java/org/apache/poi/hpsf/TypedPropertyValue.java View File



import java.math.BigInteger; import java.math.BigInteger;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianByteArrayInputStream; import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


@Internal @Internal
public class TypedPropertyValue { public class TypedPropertyValue {
private static final POILogger LOG = POILogFactory.getLogger( TypedPropertyValue.class );
private static final Logger LOG = LogManager.getLogger(TypedPropertyValue.class);


private int _type; private int _type;
private Object _value; private Object _value;
_type = lei.readShort(); _type = lei.readShort();
short padding = lei.readShort(); short padding = lei.readShort();
if ( padding != 0 ) { if ( padding != 0 ) {
LOG.log( POILogger.WARN, "TypedPropertyValue padding at offset "
+ lei.getReadIndex() + " MUST be 0, but it's value is " + padding );
LOG.atWarn().log("TypedPropertyValue padding at offset {} MUST be 0, but it's value is {}", box(lei.getReadIndex()),box(padding));
} }
readValue( lei ); readValue( lei );
} }

+ 7
- 11
src/java/org/apache/poi/hpsf/UnicodeString.java View File

import java.io.OutputStream; import java.io.OutputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.CodePageUtil; import org.apache.poi.util.CodePageUtil;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayInputStream; import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;


@Internal @Internal
public class UnicodeString { public class UnicodeString {
private static final POILogger LOG = POILogFactory.getLogger( UnicodeString.class );
private static final Logger LOG = LogManager.getLogger(UnicodeString.class);
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;




final int terminator = result.indexOf( '\0' ); final int terminator = result.indexOf( '\0' );
if ( terminator == -1 ) { if ( terminator == -1 ) {
String msg =
"String terminator (\\0) for UnicodeString property value not found. " +
"Continue without trimming and hope for the best.";
LOG.log(POILogger.WARN, msg);
LOG.atWarn().log("String terminator (\\0) for UnicodeString property value not found. " +
"Continue without trimming and hope for the best.");
return result; return result;
} }
if ( terminator != result.length() - 1 ) { if ( terminator != result.length() - 1 ) {
String msg =
"String terminator (\\0) for UnicodeString property value occured before the end of string. " +
"Trimming and hope for the best.";
LOG.log(POILogger.WARN, msg);
LOG.atWarn().log("String terminator (\\0) for UnicodeString property value occured before the end of " +
"string. Trimming and hope for the best.");
} }
return result.substring( 0, terminator ); return result.substring( 0, terminator );
} }

+ 6
- 4
src/java/org/apache/poi/hpsf/VariantBool.java View File

==================================================================== */ ==================================================================== */
package org.apache.poi.hpsf; package org.apache.poi.hpsf;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianByteArrayInputStream; import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


@Internal @Internal
public class VariantBool { public class VariantBool {
private static final POILogger LOG = POILogFactory.getLogger( VariantBool.class );
private static final Logger LOG = LogManager.getLogger(VariantBool.class);


static final int SIZE = 2; static final int SIZE = 2;


_value = true; _value = true;
break; break;
default: default:
LOG.log( POILogger.WARN, "VARIANT_BOOL value '"+value+"' is incorrect" );
LOG.atWarn().log("VARIANT_BOOL value '{}' is incorrect", box(value));
_value = true; _value = true;
break; break;
} }

+ 4
- 4
src/java/org/apache/poi/hpsf/VariantSupport.java View File

import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayInputStream; import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Supports reading and writing of variant data.<p> * Supports reading and writing of variant data.<p>
Variant.VT_CF, Variant.VT_BOOL }; Variant.VT_CF, Variant.VT_BOOL };




private static final POILogger LOG = POILogFactory.getLogger(VariantSupport.class);
private static final Logger LOG = LogManager.getLogger(VariantSupport.class);
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;


Long vt = Long.valueOf(ex.getVariantType()); Long vt = Long.valueOf(ex.getVariantType());
if (!unsupportedMessage.contains(vt)) if (!unsupportedMessage.contains(vt))
{ {
LOG.log( POILogger.ERROR, ex.getMessage());
LOG.atError().withThrowable(ex).log("Unsupported type");
unsupportedMessage.add(vt); unsupportedMessage.add(vt);
} }
} }

+ 11
- 8
src/java/org/apache/poi/hssf/dev/BiffViewer.java View File

import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.record.*; import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.RecordInputStream.LeftoverDataException; import org.apache.poi.hssf.record.RecordInputStream.LeftoverDataException;
import org.apache.poi.hssf.record.chart.*; import org.apache.poi.hssf.record.chart.*;
import org.apache.poi.util.HexDump; import org.apache.poi.util.HexDump;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;
import org.apache.poi.util.SuppressForbidden; import org.apache.poi.util.SuppressForbidden;


import static org.apache.logging.log4j.util.Unbox.box;

/** /**
* Utility for reading in BIFF8 records and displaying data from them. * Utility for reading in BIFF8 records and displaying data from them.
* @see #main * @see #main
*/ */
public final class BiffViewer { public final class BiffViewer {
private static final char[] NEW_LINE_CHARS = System.getProperty("line.separator").toCharArray(); private static final char[] NEW_LINE_CHARS = System.getProperty("line.separator").toCharArray();
private static final POILogger LOG = POILogFactory.getLogger(BiffViewer.class);
private static final Logger LOG = LogManager.getLogger(BiffViewer.class);


private BiffViewer() { private BiffViewer() {
// no instances of this class // no instances of this class
* @param recListener the record listener to notify about read records * @param recListener the record listener to notify about read records
* @param dumpInterpretedRecords if {@code true}, the read records will be written to the PrintWriter * @param dumpInterpretedRecords if {@code true}, the read records will be written to the PrintWriter
* *
* @exception org.apache.poi.util.RecordFormatException on error processing the InputStream
* @exception RecordFormatException on error processing the InputStream
*/ */
private static void createRecords(InputStream is, PrintWriter ps, BiffRecordListener recListener, boolean dumpInterpretedRecords) private static void createRecords(InputStream is, PrintWriter ps, BiffRecordListener recListener, boolean dumpInterpretedRecords)
throws org.apache.poi.util.RecordFormatException {
throws RecordFormatException {
RecordInputStream recStream = new RecordInputStream(is); RecordInputStream recStream = new RecordInputStream(is);
while (true) { while (true) {
boolean hasNext; boolean hasNext;
try { try {
hasNext = recStream.hasNextRecord(); hasNext = recStream.hasNextRecord();
} catch (LeftoverDataException e) { } catch (LeftoverDataException e) {
LOG.log(POILogger.ERROR, "Discarding ", recStream.remaining(), " bytes and continuing", e);
LOG.atError().withThrowable(e).log("Discarding {} bytes and continuing", box(recStream.remaining()));
recStream.readRemainder(); recStream.readRemainder();
hasNext = recStream.hasNextRecord(); hasNext = recStream.hasNextRecord();
} }
if (recStream.getSid() == 0) { if (recStream.getSid() == 0) {
continue; continue;
} }
org.apache.poi.hssf.record.Record record;
Record record;
if (dumpInterpretedRecords) { if (dumpInterpretedRecords) {
record = createRecord (recStream); record = createRecord (recStream);
if (record.getSid() == ContinueRecord.sid) { if (record.getSid() == ContinueRecord.sid) {
* up non-debug operations. * up non-debug operations.
* *
*/ */
private static org.apache.poi.hssf.record.Record createRecord(RecordInputStream in) {
private static Record createRecord(RecordInputStream in) {
switch (in.getSid()) { switch (in.getSid()) {
case AreaFormatRecord.sid: return new AreaFormatRecord(in); case AreaFormatRecord.sid: return new AreaFormatRecord(in);
case AreaRecord.sid: return new AreaRecord(in); case AreaRecord.sid: return new AreaRecord(in);

+ 10
- 9
src/java/org/apache/poi/hssf/eventusermodel/FormatTrackingHSSFListener.java View File

import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.record.CellValueRecordInterface; import org.apache.poi.hssf.record.CellValueRecordInterface;
import org.apache.poi.hssf.record.ExtendedFormatRecord; import org.apache.poi.hssf.record.ExtendedFormatRecord;
import org.apache.poi.hssf.record.FormatRecord; import org.apache.poi.hssf.record.FormatRecord;
import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.NumberRecord; import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.usermodel.HSSFDataFormat; import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.hssf.usermodel.HSSFDataFormatter; import org.apache.poi.hssf.usermodel.HSSFDataFormatter;
import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


/** /**
* A proxy HSSFListener that keeps track of the document formatting records, and * A proxy HSSFListener that keeps track of the document formatting records, and
* ids. * ids.
*/ */
public class FormatTrackingHSSFListener implements HSSFListener { public class FormatTrackingHSSFListener implements HSSFListener {
private static final POILogger LOG = POILogFactory.getLogger(FormatTrackingHSSFListener.class);
private static final Logger LOG = LogManager.getLogger(FormatTrackingHSSFListener.class);
private final HSSFListener _childListener; private final HSSFListener _childListener;
private final HSSFDataFormatter _formatter; private final HSSFDataFormatter _formatter;
private final NumberFormat _defaultFormat; private final NumberFormat _defaultFormat;
* Process this record ourselves, and then pass it on to our child listener * Process this record ourselves, and then pass it on to our child listener
*/ */
@Override @Override
public void processRecord(org.apache.poi.hssf.record.Record record) {
public void processRecord(Record record) {
// Handle it ourselves // Handle it ourselves
processRecordInternally(record); processRecordInternally(record);


* *
* @param record the record to be processed * @param record the record to be processed
*/ */
public void processRecordInternally(org.apache.poi.hssf.record.Record record) {
public void processRecordInternally(Record record) {
if (record instanceof FormatRecord) { if (record instanceof FormatRecord) {
FormatRecord fr = (FormatRecord) record; FormatRecord fr = (FormatRecord) record;
_customFormatRecords.put(Integer.valueOf(fr.getIndexCode()), fr); _customFormatRecords.put(Integer.valueOf(fr.getIndexCode()), fr);
if (formatIndex >= HSSFDataFormat.getNumberOfBuiltinBuiltinFormats()) { if (formatIndex >= HSSFDataFormat.getNumberOfBuiltinBuiltinFormats()) {
FormatRecord tfr = _customFormatRecords.get(Integer.valueOf(formatIndex)); FormatRecord tfr = _customFormatRecords.get(Integer.valueOf(formatIndex));
if (tfr == null) { if (tfr == null) {
LOG.log( POILogger.ERROR, "Requested format at index ", formatIndex,
", but it wasn't found");
LOG.atError().log("Requested format at index {}, but it wasn't found", box(formatIndex));
} else { } else {
format = tfr.getFormatString(); format = tfr.getFormatString();
} }
public int getFormatIndex(CellValueRecordInterface cell) { public int getFormatIndex(CellValueRecordInterface cell) {
ExtendedFormatRecord xfr = _xfRecords.get(cell.getXFIndex()); ExtendedFormatRecord xfr = _xfRecords.get(cell.getXFIndex());
if (xfr == null) { if (xfr == null) {
LOG.log( POILogger.ERROR, "Cell ", cell.getRow(), ",", cell.getColumn(),
" uses XF with index ", cell.getXFIndex(), ", but we don't have that");
LOG.atError().log("Cell {},{} uses XF with index {}, but we don't have that", box(cell.getRow()),box(cell.getColumn()),box(cell.getXFIndex()));
return -1; return -1;
} }
return xfr.getFormatIndex(); return xfr.getFormatIndex();

+ 50
- 56
src/java/org/apache/poi/hssf/model/InternalSheet.java View File

import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.poi.hssf.record.*; import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.aggregates.ChartSubstreamRecordAggregate; import org.apache.poi.hssf.record.aggregates.ChartSubstreamRecordAggregate;
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate; import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor; import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate; import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock; import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.formula.FormulaShifter; import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.PaneInformation; import org.apache.poi.ss.util.PaneInformation;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException; import org.apache.poi.util.RecordFormatException;


import static org.apache.logging.log4j.util.Unbox.box;

/** /**
* Low level model implementation of a Sheet (one workbook contains many sheets) * Low level model implementation of a Sheet (one workbook contains many sheets)
* This file contains the low level binary records starting at the sheets BOF and * This file contains the low level binary records starting at the sheets BOF and
* Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf * Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf
* before even attempting to use this. * before even attempting to use this.
* *
* @see org.apache.poi.hssf.model.InternalWorkbook
* @see org.apache.poi.hssf.usermodel.HSSFSheet
* @see InternalWorkbook
* @see HSSFSheet
*/ */
@Internal @Internal
public final class InternalSheet { public final class InternalSheet {
public static final short TopMargin = 2; public static final short TopMargin = 2;
public static final short BottomMargin = 3; public static final short BottomMargin = 3;


private static POILogger log = POILogFactory.getLogger(InternalSheet.class);
private static final Logger LOGGER = LogManager.getLogger(InternalSheet.class);


private List<RecordBase> _records; private List<RecordBase> _records;
protected PrintGridlinesRecord printGridlines; protected PrintGridlinesRecord printGridlines;
* *
* @return Sheet object with all values set to those read from the file * @return Sheet object with all values set to those read from the file
* *
* @see org.apache.poi.hssf.model.InternalWorkbook
* @see org.apache.poi.hssf.record.Record
* @see InternalWorkbook
* @see Record
*/ */
public static InternalSheet createSheet(RecordStream rs) { public static InternalSheet createSheet(RecordStream rs) {
return new InternalSheet(rs); return new InternalSheet(rs);
// Not a supported type // Not a supported type
// Skip onto the EOF, then complain // Skip onto the EOF, then complain
while (rs.hasNext()) { while (rs.hasNext()) {
org.apache.poi.hssf.record.Record rec = rs.getNext();
Record rec = rs.getNext();
if (rec instanceof EOFRecord) { if (rec instanceof EOFRecord) {
break; break;
} }
continue; continue;
} }


org.apache.poi.hssf.record.Record rec = rs.getNext();
Record rec = rs.getNext();
if ( recSid == IndexRecord.sid ) { if ( recSid == IndexRecord.sid ) {
// ignore INDEX record because it is only needed by Excel, // ignore INDEX record because it is only needed by Excel,
// and POI always re-calculates its contents // and POI always re-calculates its contents
// Not clear which application wrote these files. // Not clear which application wrote these files.
rra = new RowRecordsAggregate(); rra = new RowRecordsAggregate();
} else { } else {
if (log.check(POILogger.WARN)) {
log.log(POILogger.WARN, "DIMENSION record not found even though row/cells present");
}
LOGGER.atWarn().log("DIMENSION record not found even though row/cells present");
// Not sure if any tools write files like this, but Excel reads them OK // Not sure if any tools write files like this, but Excel reads them OK
} }
dimsloc = findFirstRecordLocBySid(WindowTwoRecord.sid); dimsloc = findFirstRecordLocBySid(WindowTwoRecord.sid);
// put merged cells table in the right place (regardless of where the first MergedCellsRecord was found */ // put merged cells table in the right place (regardless of where the first MergedCellsRecord was found */
RecordOrderer.addNewSheetRecord(records, _mergedCellsTable); RecordOrderer.addNewSheetRecord(records, _mergedCellsTable);
RecordOrderer.addNewSheetRecord(records, _protectionBlock); RecordOrderer.addNewSheetRecord(records, _protectionBlock);
if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited");
LOGGER.atDebug().log("sheet createSheet (existing file) exited");
} }
private static void spillAggregate(RecordAggregate ra, final List<RecordBase> recs) { private static void spillAggregate(RecordAggregate ra, final List<RecordBase> recs) {
ra.visitContainedRecords(r -> recs.add(r)); ra.visitContainedRecords(r -> recs.add(r));


private static final class RecordCloner implements RecordVisitor { private static final class RecordCloner implements RecordVisitor {


private final List<org.apache.poi.hssf.record.Record> _destList;
private final List<Record> _destList;


public RecordCloner(List<org.apache.poi.hssf.record.Record> destList) {
public RecordCloner(List<Record> destList) {
_destList = destList; _destList = destList;
} }
public void visitRecord(org.apache.poi.hssf.record.Record r) {
public void visitRecord(Record r) {
_destList.add(r.copy()); _destList.add(r.copy());
} }
} }
* @return the cloned sheet * @return the cloned sheet
*/ */
public InternalSheet cloneSheet() { public InternalSheet cloneSheet() {
List<org.apache.poi.hssf.record.Record> clonedRecords = new ArrayList<>(_records.size());
List<Record> clonedRecords = new ArrayList<>(_records.size());
for (int i = 0; i < _records.size(); i++) { for (int i = 0; i < _records.size(); i++) {
RecordBase rb = _records.get(i); RecordBase rb = _records.get(i);
if (rb instanceof RecordAggregate) { if (rb instanceof RecordAggregate) {
*/ */
rb = new DrawingRecord(); rb = new DrawingRecord();
} }
org.apache.poi.hssf.record.Record rec = ((org.apache.poi.hssf.record.Record) rb).copy();
Record rec = ((Record) rb).copy();
clonedRecords.add(rec); clonedRecords.add(rec);
} }
return createSheet(new RecordStream(clonedRecords, 0)); return createSheet(new RecordStream(clonedRecords, 0));
_mergedCellsTable = new MergedCellsTable(); _mergedCellsTable = new MergedCellsTable();
List<RecordBase> records = new ArrayList<>(32); List<RecordBase> records = new ArrayList<>(32);


log.log(POILogger.DEBUG, "Sheet createsheet from scratch called");
LOGGER.atDebug().log("Sheet createsheet from scratch called");


records.add(createBOF()); records.add(createBOF());


records.add(EOFRecord.instance); records.add(EOFRecord.instance);


_records = records; _records = records;
log.log(POILogger.DEBUG, "Sheet createsheet from scratch exit");
LOGGER.atDebug().log("Sheet createsheet from scratch exit");
} }


public RowRecordsAggregate getRowsAggregate() { public RowRecordsAggregate getRowsAggregate() {
* @param lastrow the last row index * @param lastrow the last row index
* @param lastcol the last column index * @param lastcol the last column index
* *
* @see org.apache.poi.hssf.record.DimensionsRecord
* @see DimensionsRecord
*/ */
public void setDimensions(int firstrow, short firstcol, int lastrow, short lastcol) public void setDimensions(int firstrow, short firstcol, int lastrow, short lastcol)
{ {
if (log.check( POILogger.DEBUG ))
{
log.log(POILogger.DEBUG, "Sheet.setDimensions");
log.log(POILogger.DEBUG,
(new StringBuilder("firstrow")).append(firstrow)
.append("firstcol").append(firstcol).append("lastrow")
.append(lastrow).append("lastcol").append(lastcol)
.toString());
}
LOGGER.atDebug().log("Sheet.setDimensions");
LOGGER.atDebug().log(() -> new SimpleMessage(
"firstrow" + firstrow +
"firstcol" + firstcol +
"lastrow" + lastrow +
"lastcol" + lastcol
));
_dimensions.setFirstCol(firstcol); _dimensions.setFirstCol(firstcol);
_dimensions.setFirstRow(firstrow); _dimensions.setFirstRow(firstrow);
_dimensions.setLastCol(lastcol); _dimensions.setLastCol(lastcol);
_dimensions.setLastRow(lastrow); _dimensions.setLastRow(lastrow);
log.log(POILogger.DEBUG, "Sheet.setDimensions exiting");
LOGGER.atDebug().log("Sheet.setDimensions exiting");
} }


public void visitContainedRecords(RecordVisitor rv, int offset) { public void visitContainedRecords(RecordVisitor rv, int offset) {
RecordAggregate agg = (RecordAggregate) record; RecordAggregate agg = (RecordAggregate) record;
agg.visitContainedRecords(ptv); agg.visitContainedRecords(ptv);
} else { } else {
ptv.visitRecord((org.apache.poi.hssf.record.Record) record);
ptv.visitRecord((Record) record);
} }


// If the BOF record was just serialized then add the IndexRecord // If the BOF record was just serialized then add the IndexRecord
*/ */
public void addValueRecord(int row, CellValueRecordInterface col) { public void addValueRecord(int row, CellValueRecordInterface col) {


if(log.check(POILogger.DEBUG)) {
log.log(POILogger.DEBUG, "add value record row" + row);
}
LOGGER.atDebug().log("add value record row{}", box(row));
DimensionsRecord d = _dimensions; DimensionsRecord d = _dimensions;


if (col.getColumn() >= d.getLastCol()) { if (col.getColumn() >= d.getLastCol()) {
* *
* @param row - the row of the value record you wish to remove * @param row - the row of the value record you wish to remove
* @param col - a record supporting the CellValueRecordInterface. * @param col - a record supporting the CellValueRecordInterface.
* @see org.apache.poi.hssf.record.CellValueRecordInterface
* @see CellValueRecordInterface
*/ */
public void removeValueRecord(int row, CellValueRecordInterface col) { public void removeValueRecord(int row, CellValueRecordInterface col) {


log.log(POILogger.DEBUG, "remove value record row "+row);
LOGGER.atDebug().log("remove value record row {}", box(row));
_rowsAggregate.removeCell(col); _rowsAggregate.removeCell(col);
} }




public void replaceValueRecord(CellValueRecordInterface newval) { public void replaceValueRecord(CellValueRecordInterface newval) {


if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "replaceValueRecord ");
LOGGER.atDebug().log("replaceValueRecord ");
//The ValueRecordsAggregate use a tree map underneath. //The ValueRecordsAggregate use a tree map underneath.
//The tree Map uses the CellValueRecordInterface as both the //The tree Map uses the CellValueRecordInterface as both the
//key and the value, if we dont do a remove, then //key and the value, if we dont do a remove, then
*/ */


public void addRow(RowRecord row) { public void addRow(RowRecord row) {
if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "addRow ");
LOGGER.atDebug().log("addRow ");
DimensionsRecord d = _dimensions; DimensionsRecord d = _dimensions;


if (row.getRowNumber() >= d.getLastRow()) { if (row.getRowNumber() >= d.getLastRow()) {


_rowsAggregate.insertRow(row); _rowsAggregate.insertRow(row);


if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "exit addRow");
LOGGER.atDebug().log("exit addRow");
} }


/** /**
/** /**
* get the width of a given column in units of 1/256th of a character width * get the width of a given column in units of 1/256th of a character width
* @param columnIndex index * @param columnIndex index
* @see org.apache.poi.hssf.record.DefaultColWidthRecord
* @see org.apache.poi.hssf.record.ColumnInfoRecord
* @see DefaultColWidthRecord
* @see ColumnInfoRecord
* @see #setColumnWidth(int, int) * @see #setColumnWidth(int, int)
* @return column width in units of 1/256th of a character width * @return column width in units of 1/256th of a character width
*/ */
/** /**
* Get the hidden property for a given column. * Get the hidden property for a given column.
* @param columnIndex column index * @param columnIndex column index
* @see org.apache.poi.hssf.record.DefaultColWidthRecord
* @see org.apache.poi.hssf.record.ColumnInfoRecord
* @see DefaultColWidthRecord
* @see ColumnInfoRecord
* @see #setColumnHidden(int, boolean) * @see #setColumnHidden(int, boolean)
* @return whether the column is hidden or not. * @return whether the column is hidden or not.
*/ */
/** /**
* Returns the active row * Returns the active row
* *
* @see org.apache.poi.hssf.record.SelectionRecord
* @see SelectionRecord
* @return row the active row index * @return row the active row index
*/ */
public int getActiveCellRow() { public int getActiveCellRow() {
* Sets the active row * Sets the active row
* *
* @param row the row index * @param row the row index
* @see org.apache.poi.hssf.record.SelectionRecord
* @see SelectionRecord
*/ */
public void setActiveCellRow(int row) { public void setActiveCellRow(int row) {
//shouldn't have a sheet w/o a SelectionRecord, but best to guard anyway //shouldn't have a sheet w/o a SelectionRecord, but best to guard anyway
} }


/** /**
* @see org.apache.poi.hssf.record.SelectionRecord
* @see SelectionRecord
* @return column of the active cell * @return column of the active cell
*/ */
public short getActiveCellCol() { public short getActiveCellCol() {
* Sets the active column * Sets the active column
* *
* @param col the column index * @param col the column index
* @see org.apache.poi.hssf.record.SelectionRecord
* @see SelectionRecord
*/ */
public void setActiveCellCol(short col) { public void setActiveCellCol(short col) {
//shouldn't have a sheet w/o a SelectionRecord, but best to guard anyway //shouldn't have a sheet w/o a SelectionRecord, but best to guard anyway
* *
* @return the matching record or {@code null} if it wasn't found * @return the matching record or {@code null} if it wasn't found
*/ */
public org.apache.poi.hssf.record.Record findFirstRecordBySid(short sid) {
public Record findFirstRecordBySid(short sid) {
int ix = findFirstRecordLocBySid(sid); int ix = findFirstRecordLocBySid(sid);
if (ix < 0) { if (ix < 0) {
return null; return null;
} }
return (org.apache.poi.hssf.record.Record) _records.get(ix);
return (Record) _records.get(ix);
} }


/** /**
int max = _records.size(); int max = _records.size();
for (int i=0; i< max; i++) { for (int i=0; i< max; i++) {
Object rb = _records.get(i); Object rb = _records.get(i);
if (!(rb instanceof org.apache.poi.hssf.record.Record)) {
if (!(rb instanceof Record)) {
continue; continue;
} }
org.apache.poi.hssf.record.Record record = (org.apache.poi.hssf.record.Record) rb;
Record record = (Record) rb;
if (record.getSid() == sid) { if (record.getSid() == sid) {
return i; return i;
} }

+ 46
- 45
src/java/org/apache/poi/hssf/model/InternalWorkbook.java View File



package org.apache.poi.hssf.model; package org.apache.poi.hssf.model;


import static org.apache.poi.util.POILogger.DEBUG;
import static org.apache.logging.log4j.util.Unbox.box;


import java.security.AccessControlException; import java.security.AccessControlException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ddf.EscherBSERecord; import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.ddf.EscherBoolProperty; import org.apache.poi.ddf.EscherBoolProperty;
import org.apache.poi.ddf.EscherContainerRecord; import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.hssf.extractor.OldExcelExtractor; import org.apache.poi.hssf.extractor.OldExcelExtractor;
import org.apache.poi.hssf.record.*; import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.common.UnicodeString; import org.apache.poi.hssf.record.common.UnicodeString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined; import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
import org.apache.poi.poifs.crypt.CryptoFunctions; import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName; import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException; import org.apache.poi.util.RecordFormatException;


/** /**
* Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf * Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf
* before even attempting to use this. * before even attempting to use this.
* *
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook
* @see HSSFWorkbook
*/ */
@Internal @Internal
public final class InternalWorkbook { public final class InternalWorkbook {
*/ */
public static final String OLD_WORKBOOK_DIR_ENTRY_NAME = "Book"; public static final String OLD_WORKBOOK_DIR_ENTRY_NAME = "Book";


private static final POILogger LOG = POILogFactory.getLogger(InternalWorkbook.class);
private static final Logger LOG = LogManager.getLogger(InternalWorkbook.class);


/** /**
* constant used to set the "codepage" wherever "codepage" is set in records * constant used to set the "codepage" wherever "codepage" is set in records
* @param recs an array of Record objects * @param recs an array of Record objects
* @return Workbook object * @return Workbook object
*/ */
public static InternalWorkbook createWorkbook(List<org.apache.poi.hssf.record.Record> recs) {
LOG.log(DEBUG, "Workbook (readfile) created with reclen=", recs.size());
public static InternalWorkbook createWorkbook(List<Record> recs) {
LOG.atDebug().log("Workbook (readfile) created with reclen={}", box(recs.size()));
InternalWorkbook retval = new InternalWorkbook(); InternalWorkbook retval = new InternalWorkbook();
List<org.apache.poi.hssf.record.Record> records = new ArrayList<>(recs.size() / 3);
List<Record> records = new ArrayList<>(recs.size() / 3);
retval.records.setRecords(records); retval.records.setRecords(records);


boolean eofPassed = false; boolean eofPassed = false;
for (int k = 0; k < recs.size(); k++) { for (int k = 0; k < recs.size(); k++) {
org.apache.poi.hssf.record.Record rec = recs.get(k);
Record rec = recs.get(k);
String logObj; String logObj;
switch (rec.getSid()) { switch (rec.getSid()) {


case NameRecord.sid : case NameRecord.sid :
case SupBookRecord.sid : case SupBookRecord.sid :
// LinkTable can start with either of these // LinkTable can start with either of these
LOG.log(DEBUG, "found SupBook record at " + k);
LOG.atDebug().log("found SupBook record at {}", box(k));
retval.linkTable = new LinkTable(recs, k, retval.records, retval.commentRecords); retval.linkTable = new LinkTable(recs, k, retval.records, retval.commentRecords);
k+=retval.linkTable.getRecordCount() - 1; k+=retval.linkTable.getRecordCount() - 1;
continue; continue;
if (!eofPassed) { if (!eofPassed) {
records.add(rec); records.add(rec);
} }
LOG.log(DEBUG, "found "+logObj+" record at " + k);
LOG.atTrace().log("found {} record at {}", logObj, box(k));
if (rec.getSid() == EOFRecord.sid) { if (rec.getSid() == EOFRecord.sid) {
eofPassed = true; eofPassed = true;
} }
if (retval.windowOne == null) { if (retval.windowOne == null) {
retval.windowOne = createWindowOne(); retval.windowOne = createWindowOne();
} }
LOG.log(DEBUG, "exit create workbook from existing file function");
LOG.atDebug().log("exit create workbook from existing file function");
return retval; return retval;
} }


* @return an empty workbook object * @return an empty workbook object
*/ */
public static InternalWorkbook createWorkbook() { public static InternalWorkbook createWorkbook() {
LOG.log( DEBUG, "creating new workbook from scratch" );
LOG.atDebug().log("creating new workbook from scratch");


InternalWorkbook retval = new InternalWorkbook(); InternalWorkbook retval = new InternalWorkbook();
List<org.apache.poi.hssf.record.Record> records = new ArrayList<>(30);
List<Record> records = new ArrayList<>(30);
retval.records.setRecords(records); retval.records.setRecords(records);
List<FormatRecord> formats = retval.formats; List<FormatRecord> formats = retval.formats;


records.add(InternalWorkbook.createExtendedSST()); records.add(InternalWorkbook.createExtendedSST());


records.add(EOFRecord.instance); records.add(EOFRecord.instance);
LOG.log( DEBUG, "exit create new workbook from scratch" );
LOG.atDebug().log("exit create new workbook from scratch");


return retval; return retval;
} }
*/ */


public void setSheetBof(int sheetIndex, int pos) { public void setSheetBof(int sheetIndex, int pos) {
LOG.log(DEBUG, "setting bof for sheetnum =", sheetIndex, " at pos=", pos);
LOG.atDebug().log("setting bof for sheetnum ={} at pos={}", box(sheetIndex),box(pos));


checkSheets(sheetIndex); checkSheets(sheetIndex);
getBoundSheetRec(sheetIndex) getBoundSheetRec(sheetIndex)
// also adjust order of Records, calculate the position of the Boundsheets via getBspos()... // also adjust order of Records, calculate the position of the Boundsheets via getBspos()...
int initialBspos = records.getBspos(); int initialBspos = records.getBspos();
int pos0 = initialBspos - (boundsheets.size() - 1); int pos0 = initialBspos - (boundsheets.size() - 1);
org.apache.poi.hssf.record.Record removed = records.get(pos0 + sheetNumber);
Record removed = records.get(pos0 + sheetNumber);
records.remove(pos0 + sheetNumber); records.remove(pos0 + sheetNumber);
records.add(pos0 + pos, removed); records.add(pos0 + pos, removed);
records.setBspos(initialBspos); records.setBspos(initialBspos);
* make the tabid record look like the current situation. * make the tabid record look like the current situation.
*/ */
private void fixTabIdRecord() { private void fixTabIdRecord() {
org.apache.poi.hssf.record.Record rec = records.get(records.getTabpos());
Record rec = records.get(records.getTabpos());


// see bug 55982, quite a number of documents do not have a TabIdRecord and // see bug 55982, quite a number of documents do not have a TabIdRecord and
// thus there is no way to do the fixup here, // thus there is no way to do the fixup here,
*/ */


public int getNumSheets() { public int getNumSheets() {
LOG.log(DEBUG, "getNumSheets=", boundsheets.size());
LOG.atDebug().log("getNumSheets={}", box(boundsheets.size()));
return boundsheets.size(); return boundsheets.size();
} }


*/ */


public int getNumExFormats() { public int getNumExFormats() {
LOG.log(DEBUG, "getXF=", numxfs);
LOG.atDebug().log("getXF={}", box(numxfs));
return numxfs; return numxfs;
} }


// Style records always follow after // Style records always follow after
// the ExtendedFormat records // the ExtendedFormat records
for(int i=records.getXfpos(); i<records.size(); i++) { for(int i=records.getXfpos(); i<records.size(); i++) {
org.apache.poi.hssf.record.Record r = records.get(i);
Record r = records.get(i);
if (r instanceof StyleRecord) { if (r instanceof StyleRecord) {
StyleRecord sr = (StyleRecord)r; StyleRecord sr = (StyleRecord)r;
if (sr.getXFIndex() == xfIndex) { if (sr.getXFIndex() == xfIndex) {
// Style records always follow after // Style records always follow after
// the ExtendedFormat records // the ExtendedFormat records
for(int i=records.getXfpos(); i<records.size(); i++) { for(int i=records.getXfpos(); i<records.size(); i++) {
org.apache.poi.hssf.record.Record r = records.get(i);
Record r = records.get(i);
if (r instanceof StyleRecord) { if (r instanceof StyleRecord) {
StyleRecord sr = (StyleRecord)r; StyleRecord sr = (StyleRecord)r;
if (sr.getXFIndex() == oldXf) { if (sr.getXFIndex() == oldXf) {
int addAt = -1; int addAt = -1;
for(int i=records.getXfpos(); i<records.size() && for(int i=records.getXfpos(); i<records.size() &&
addAt == -1; i++) { addAt == -1; i++) {
org.apache.poi.hssf.record.Record r = records.get(i);
Record r = records.get(i);
if(r instanceof ExtendedFormatRecord || if(r instanceof ExtendedFormatRecord ||
r instanceof StyleRecord) { r instanceof StyleRecord) {
// Keep going // Keep going
*/ */


public int addSSTString(UnicodeString string) { public int addSSTString(UnicodeString string) {
LOG.log(DEBUG, "insert to sst string='", string);
LOG.atDebug().log("insert to sst string='{}'", string);
if (sst == null) { if (sst == null) {
insertSST(); insertSST();
} }
} }
UnicodeString retval = sst.getString(str); UnicodeString retval = sst.getString(str);


LOG.log(DEBUG, "Returning SST for index=", str, " String= ", retval);
LOG.atTrace().log("Returning SST for index={} String= {}", box(str), retval);
return retval; return retval;
} }


* use this function to add a Shared String Table to an existing sheet (say * use this function to add a Shared String Table to an existing sheet (say
* generated by a different java api) without an sst.... * generated by a different java api) without an sst....
* @see #createExtendedSST() * @see #createExtendedSST()
* @see org.apache.poi.hssf.record.SSTRecord
* @see SSTRecord
*/ */


public void insertSST() { public void insertSST() {
LOG.log(DEBUG, "creating new SST via insertSST!");
LOG.atDebug().log("creating new SST via insertSST!");


sst = new SSTRecord(); sst = new SSTRecord();
records.add(records.size() - 1, createExtendedSST()); records.add(records.size() - 1, createExtendedSST());
* @return the length of serialized bytes * @return the length of serialized bytes
*/ */
public int serialize( int offset, byte[] data ) { public int serialize( int offset, byte[] data ) {
LOG.log( DEBUG, "Serializing Workbook with offsets" );
LOG.atDebug().log("Serializing Workbook with offsets");


int pos = 0; int pos = 0;


SSTRecord lSST = null; SSTRecord lSST = null;
int sstPos = 0; int sstPos = 0;
boolean wroteBoundSheets = false; boolean wroteBoundSheets = false;
for ( org.apache.poi.hssf.record.Record record : records.getRecords() ) {
for ( Record record : records.getRecords() ) {
int len = 0; int len = 0;
if (record instanceof SSTRecord) { if (record instanceof SSTRecord) {
lSST = (SSTRecord)record; lSST = (SSTRecord)record;
pos += len; pos += len;
} }


LOG.log( DEBUG, "Exiting serialize workbook" );
LOG.atDebug().log("Exiting serialize workbook");
return pos; return pos;
} }


int retval = 0; int retval = 0;


SSTRecord lSST = null; SSTRecord lSST = null;
for ( org.apache.poi.hssf.record.Record record : records.getRecords() ) {
for ( Record record : records.getRecords() ) {
if (record instanceof SSTRecord) { if (record instanceof SSTRecord) {
lSST = (SSTRecord)record; lSST = (SSTRecord)record;
} }


retval.setUsername(username); retval.setUsername(username);
} catch (AccessControlException e) { } catch (AccessControlException e) {
LOG.log(POILogger.WARN, "can't determine user.name", e);
LOG.atWarn().withThrowable(e).log("can't determine user.name");
// AccessControlException can occur in a restricted context // AccessControlException can occur in a restricted context
// (client applet/jws application or restricted security server) // (client applet/jws application or restricted security server)
retval.setUsername(defaultUserName); retval.setUsername(defaultUserName);
* Always sets the sheet's bof to 0. You'll need to set that yourself. * Always sets the sheet's bof to 0. You'll need to set that yourself.
* @param id either sheet 0,1 or 2. * @param id either sheet 0,1 or 2.
* @return record containing a BoundSheetRecord * @return record containing a BoundSheetRecord
* @see org.apache.poi.hssf.record.BoundSheetRecord
* @see org.apache.poi.hssf.record.Record
* @see BoundSheetRecord
* @see Record
*/ */
private static BoundSheetRecord createBoundSheet(int id) { private static BoundSheetRecord createBoundSheet(int id) {
return new BoundSheetRecord("Sheet" + (id+1)); return new BoundSheetRecord("Sheet" + (id+1));
* Creates a FormatRecord, inserts it, and returns the index code. * Creates a FormatRecord, inserts it, and returns the index code.
* @param formatString the format string * @param formatString the format string
* @return the index code of the format record. * @return the index code of the format record.
* @see org.apache.poi.hssf.record.FormatRecord
* @see org.apache.poi.hssf.record.Record
* @see FormatRecord
* @see Record
*/ */
public int createFormat(String formatString) { public int createFormat(String formatString) {


* *
* @return the matching record or {@code null} if it wasn't found * @return the matching record or {@code null} if it wasn't found
*/ */
public org.apache.poi.hssf.record.Record findFirstRecordBySid(short sid) {
for (org.apache.poi.hssf.record.Record record : records.getRecords() ) {
public Record findFirstRecordBySid(short sid) {
for (Record record : records.getRecords() ) {
if (record.getSid() == sid) { if (record.getSid() == sid) {
return record; return record;
} }
*/ */
public int findFirstRecordLocBySid(short sid) { public int findFirstRecordLocBySid(short sid) {
int index = 0; int index = 0;
for (org.apache.poi.hssf.record.Record record : records.getRecords() ) {
for (Record record : records.getRecords() ) {
if (record.getSid() == sid) { if (record.getSid() == sid) {
return index; return index;
} }
* *
* @return the matching record or {@code null} if it wasn't found * @return the matching record or {@code null} if it wasn't found
*/ */
public org.apache.poi.hssf.record.Record findNextRecordBySid(short sid, int pos) {
public Record findNextRecordBySid(short sid, int pos) {
int matches = 0; int matches = 0;
for (org.apache.poi.hssf.record.Record record : records.getRecords() ) {
for (Record record : records.getRecords() ) {
if (record.getSid() == sid && matches++ == pos) { if (record.getSid() == sid && matches++ == pos) {
return record; return record;
} }
return hyperlinks; return hyperlinks;
} }


public List<org.apache.poi.hssf.record.Record> getRecords() {
public List<Record> getRecords() {
return records.getRecords(); return records.getRecords();
} }


PaletteRecord palette; PaletteRecord palette;
int palettePos = records.getPalettepos(); int palettePos = records.getPalettepos();
if (palettePos != -1) { if (palettePos != -1) {
org.apache.poi.hssf.record.Record rec = records.get(palettePos);
Record rec = records.get(palettePos);
if (rec instanceof PaletteRecord) { if (rec instanceof PaletteRecord) {
palette = (PaletteRecord) rec; palette = (PaletteRecord) rec;
} else { } else {
} }


// Need to find a DrawingGroupRecord that contains a EscherDggRecord // Need to find a DrawingGroupRecord that contains a EscherDggRecord
for(org.apache.poi.hssf.record.Record r : records.getRecords() ) {
for(Record r : records.getRecords() ) {
if (!(r instanceof DrawingGroupRecord)) { if (!(r instanceof DrawingGroupRecord)) {
continue; continue;
} }
* *
* @return a new RecalcIdRecord * @return a new RecalcIdRecord
* *
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook#setForceFormulaRecalculation(boolean)
* @see HSSFWorkbook#setForceFormulaRecalculation(boolean)
*/ */
public RecalcIdRecord getRecalcId(){ public RecalcIdRecord getRecalcId(){
RecalcIdRecord record = (RecalcIdRecord)findFirstRecordBySid(RecalcIdRecord.sid); RecalcIdRecord record = (RecalcIdRecord)findFirstRecordBySid(RecalcIdRecord.sid);

+ 3
- 2
src/java/org/apache/poi/hssf/record/CFRule12Record.java View File

import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogger;

import static org.apache.logging.log4j.util.Unbox.box;


/** /**
* Conditional Formatting v12 Rule Record (0x087A). * Conditional Formatting v12 Rule Record (0x087A).
template_params = IOUtils.safelyAllocate(template_param_length, MAX_RECORD_LENGTH); template_params = IOUtils.safelyAllocate(template_param_length, MAX_RECORD_LENGTH);
in.readFully(template_params); in.readFully(template_params);
} else { } else {
LOG.log(POILogger.WARN, "CF Rule v12 template params length should be 0 or 16, found " + template_param_length);
LOG.atWarn().log("CF Rule v12 template params length should be 0 or 16, found {}", box(template_param_length));
in.readRemainder(); in.readRemainder();
} }



+ 3
- 3
src/java/org/apache/poi/hssf/record/CFRuleBase.java View File

import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.model.HSSFFormulaParser; import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.cf.BorderFormatting; import org.apache.poi.hssf.record.cf.BorderFormatting;
import org.apache.poi.hssf.record.cf.FontFormatting; import org.apache.poi.hssf.record.cf.FontFormatting;
import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianOutput; 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 * Conditional Formatting Rules. This can hold old-style rules
public static final int TEMPLATE_ABOVE_OR_EQUAL_TO_AVERAGE = 0x001D; public static final int TEMPLATE_ABOVE_OR_EQUAL_TO_AVERAGE = 0x001D;
public static final int TEMPLATE_BELOW_OR_EQUAL_TO_AVERAGE = 0x001E; public static final int TEMPLATE_BELOW_OR_EQUAL_TO_AVERAGE = 0x001E;


protected static final POILogger LOG = POILogFactory.getLogger(CFRuleBase.class);
protected static final Logger LOG = LogManager.getLogger(CFRuleBase.class);


static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot 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 alignHor = bf(0x00000001); // 0 = Horizontal alignment modified

+ 4
- 4
src/java/org/apache/poi/hssf/record/DimensionsRecord.java View File

import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Provides the minumum and maximum bounds of a sheet. * Provides the minumum and maximum bounds of a sheet.


public final class DimensionsRecord extends StandardRecord { public final class DimensionsRecord extends StandardRecord {


private static final POILogger LOG = POILogFactory.getLogger(DimensionsRecord.class);
private static final Logger LOG = LogManager.getLogger(DimensionsRecord.class);


public static final short sid = 0x200; public static final short sid = 0x200;
private int field_1_first_row; private int field_1_first_row;
field_5_zero = in.readShort(); field_5_zero = in.readShort();
//POI-61045 -- in practice, there can be an extra 2 bytes //POI-61045 -- in practice, there can be an extra 2 bytes
if (in.available() == 2) { if (in.available() == 2) {
LOG.log(POILogger.INFO, "DimensionsRecord has extra 2 bytes.");
LOG.atInfo().log("DimensionsRecord has extra 2 bytes.");
in.readShort(); in.readShort();
} }
} }

+ 6
- 4
src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java View File

import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.formula.ptg.Area3DPtg; import org.apache.poi.ss.formula.ptg.Area3DPtg;
import org.apache.poi.ss.formula.ptg.AreaPtg; import org.apache.poi.ss.formula.ptg.AreaPtg;
import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianInputStream; import org.apache.poi.util.LittleEndianInputStream;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException; import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;


import static org.apache.logging.log4j.util.Unbox.box;

/** /**
* ftPictFmla (0x0009)<p> * ftPictFmla (0x0009)<p>
* A sub-record within the OBJ record which stores a reference to an object * A sub-record within the OBJ record which stores a reference to an object
* stored in a separate entry within the OLE2 compound file. * stored in a separate entry within the OLE2 compound file.
*/ */
public final class EmbeddedObjectRefSubRecord extends SubRecord { public final class EmbeddedObjectRefSubRecord extends SubRecord {
private static final POILogger LOG = POILogFactory.getLogger(EmbeddedObjectRefSubRecord.class);
private static final Logger LOG = LogManager.getLogger(EmbeddedObjectRefSubRecord.class);
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;


int nUnexpectedPadding = remaining - dataLenAfterFormula; int nUnexpectedPadding = remaining - dataLenAfterFormula;


if (nUnexpectedPadding > 0) { if (nUnexpectedPadding > 0) {
LOG.log( POILogger.ERROR, "Discarding ", nUnexpectedPadding, " unexpected padding bytes");
LOG.atError().log("Discarding {} unexpected padding bytes", box(nUnexpectedPadding));
readRawData(in, nUnexpectedPadding); readRawData(in, nUnexpectedPadding);
remaining-=nUnexpectedPadding; remaining-=nUnexpectedPadding;
} }

+ 7
- 5
src/java/org/apache/poi/hssf/record/FeatRecord.java View File

import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.record.common.FeatFormulaErr2; import org.apache.poi.hssf.record.common.FeatFormulaErr2;
import org.apache.poi.hssf.record.common.FeatProtection; import org.apache.poi.hssf.record.common.FeatProtection;
import org.apache.poi.hssf.record.common.FeatSmartTag; import org.apache.poi.hssf.record.common.FeatSmartTag;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


/** /**
* Title: Feat (Feature) Record * Title: Feat (Feature) Record
* up with a {@link FeatHdrRecord}. * up with a {@link FeatHdrRecord}.
*/ */
public final class FeatRecord extends StandardRecord { public final class FeatRecord extends StandardRecord {
private static final POILogger LOG = POILogFactory.getLogger(FeatRecord.class);
public static final short sid = 0x0868;
private static final Logger LOG = LogManager.getLogger(FeatRecord.class);
public static final short sid = 0x0868;
// SIDs from newer versions // SIDs from newer versions
public static final short v11_sid = 0x0872; public static final short v11_sid = 0x0872;
public static final short v12_sid = 0x0878; public static final short v12_sid = 0x0878;
sharedFeature = new FeatSmartTag(in); sharedFeature = new FeatSmartTag(in);
break; break;
default: default:
LOG.log( POILogger.ERROR, "Unknown Shared Feature ", isf_sharedFeatureType, " found!");
LOG.atError().log("Unknown Shared Feature {} found!", box(isf_sharedFeatureType));
} }
} }



+ 8
- 5
src/java/org/apache/poi/hssf/record/FormatRecord.java View File

import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.model.InternalWorkbook;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;


import static org.apache.logging.log4j.util.Unbox.box;

/** /**
* Describes a number format -- those goofy strings like $(#,###) * Describes a number format -- those goofy strings like $(#,###)
*/ */
public final class FormatRecord extends StandardRecord { public final class FormatRecord extends StandardRecord {


private static final POILogger LOG = POILogFactory.getLogger(FormatRecord.class);
private static final Logger LOG = LogManager.getLogger(FormatRecord.class);


public static final short sid = 0x041E; public static final short sid = 0x041E;


* get the format index code (for built in formats) * get the format index code (for built in formats)
* *
* @return the format index code * @return the format index code
* @see org.apache.poi.hssf.model.InternalWorkbook
* @see InternalWorkbook
*/ */
public int getIndexCode() { public int getIndexCode() {
return field_1_index_code; return field_1_index_code;
} }


if (ris.available() > 0) { if (ris.available() > 0) {
LOG.log(POILogger.INFO, "FormatRecord has ", ris.available(), " unexplained bytes. Silently skipping");
LOG.atInfo().log("FormatRecord has {} unexplained bytes. Silently skipping", box(ris.available()));
//swallow what's left //swallow what's left
while (ris.available() > 0) { while (ris.available() > 0) {
ris.readByte(); ris.readByte();

+ 8
- 9
src/java/org/apache/poi/hssf/record/HyperlinkRecord.java View File



package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;


import static org.apache.logging.log4j.util.Unbox.box;
import static org.apache.poi.hpsf.ClassIDPredefined.FILE_MONIKER; import static org.apache.poi.hpsf.ClassIDPredefined.FILE_MONIKER;
import static org.apache.poi.hpsf.ClassIDPredefined.STD_MONIKER; import static org.apache.poi.hpsf.ClassIDPredefined.STD_MONIKER;
import static org.apache.poi.hpsf.ClassIDPredefined.URL_MONIKER; import static org.apache.poi.hpsf.ClassIDPredefined.URL_MONIKER;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString; import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import static org.apache.poi.util.HexDump.toHex;


import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hpsf.ClassID; import org.apache.poi.hpsf.ClassID;
import org.apache.poi.hpsf.ClassIDPredefined;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.HexRead; import org.apache.poi.util.HexRead;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException; import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;


*/ */
public final class HyperlinkRecord extends StandardRecord { public final class HyperlinkRecord extends StandardRecord {
public static final short sid = 0x01B8; public static final short sid = 0x01B8;
private static final POILogger LOG = POILogFactory.getLogger(HyperlinkRecord.class);
private static final Logger LOG = LogManager.getLogger(HyperlinkRecord.class);
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;


} }


/** /**
* @return 16-byte guid identifier Seems to always equal {@link org.apache.poi.hpsf.ClassIDPredefined#STD_MONIKER}
* @return 16-byte guid identifier Seems to always equal {@link ClassIDPredefined#STD_MONIKER}
*/ */
ClassID getGuid() { ClassID getGuid() {
return _guid; return _guid;
} }


if (in.remaining() > 0) { if (in.remaining() > 0) {
LOG.log(POILogger.WARN,
"Hyperlink data remains: " + in.remaining() +
" : " +HexDump.toHex(in.readRemainder())
);
LOG.atWarn().log("Hyperlink data remains: {} : {}", box(in.remaining()), toHex(in.readRemainder()));
} }
} }



+ 8
- 9
src/java/org/apache/poi/hssf/record/LabelRecord.java View File

import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException; import org.apache.poi.util.RecordFormatException;


import static org.apache.logging.log4j.util.Unbox.box;
import static org.apache.poi.util.HexDump.toHex;

/** /**
* Label Record (0x0204) - read only support for strings stored directly in the cell... * Label Record (0x0204) - read only support for strings stored directly in the cell...
* Don't use this (except to read), use LabelSST instead * Don't use this (except to read), use LabelSST instead
* *
* @see org.apache.poi.hssf.record.LabelSSTRecord
* @see LabelSSTRecord
*/ */
public final class LabelRecord extends Record implements CellValueRecordInterface { public final class LabelRecord extends Record implements CellValueRecordInterface {
private static final POILogger LOG = POILogFactory.getLogger(LabelRecord.class);
private static final Logger LOG = LogManager.getLogger(LabelRecord.class);


public static final short sid = 0x0204; public static final short sid = 0x0204;


} }


if (in.remaining() > 0) { if (in.remaining() > 0) {
LOG.log(POILogger.INFO,
"LabelRecord data remains: ", in.remaining(),
" : ", HexDump.toHex(in.readRemainder())
);
LOG.atInfo().log("LabelRecord data remains: {} : {}", box(in.remaining()), toHex(in.readRemainder()));
} }
} }



+ 7
- 8
src/java/org/apache/poi/hssf/record/OldLabelRecord.java View File

import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException; import org.apache.poi.util.RecordFormatException;


import static org.apache.logging.log4j.util.Unbox.box;
import static org.apache.poi.util.HexDump.toHex;

/** /**
* Biff2 - Biff 4 Label Record (0x0004 / 0x0204) - read only support for * Biff2 - Biff 4 Label Record (0x0004 / 0x0204) - read only support for
* strings stored directly in the cell, from the older file formats that * strings stored directly in the cell, from the older file formats that
* didn't use {@link LabelSSTRecord} * didn't use {@link LabelSSTRecord}
*/ */
public final class OldLabelRecord extends OldCellRecord { public final class OldLabelRecord extends OldCellRecord {
private static final POILogger LOG = POILogFactory.getLogger(OldLabelRecord.class);
private static final Logger LOG = LogManager.getLogger(OldLabelRecord.class);
//arbitrarily set, may need to increase //arbitrarily set, may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;


in.read(field_5_bytes, 0, field_4_string_len); in.read(field_5_bytes, 0, field_4_string_len);


if (in.remaining() > 0) { if (in.remaining() > 0) {
LOG.log(POILogger.INFO,
"LabelRecord data remains: ", in.remaining(),
" : ", HexDump.toHex(in.readRemainder())
);
LOG.atInfo().log("LabelRecord data remains: {} : {}", box(in.remaining()), toHex(in.readRemainder()));
} }
} }



+ 6
- 4
src/java/org/apache/poi/hssf/record/SSTDeserializer.java View File



package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.record.common.UnicodeString; import org.apache.poi.hssf.record.common.UnicodeString;
import org.apache.poi.util.IntMapper; import org.apache.poi.util.IntMapper;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


/** /**
* Handles the task of deserializing a SST string. The two main entry points are * Handles the task of deserializing a SST string. The two main entry points are
*/ */
class SSTDeserializer class SSTDeserializer
{ {
private static final POILogger LOG = POILogFactory.getLogger(SSTDeserializer.class);
private static final Logger LOG = LogManager.getLogger(SSTDeserializer.class);
private IntMapper<UnicodeString> strings; private IntMapper<UnicodeString> strings;


public SSTDeserializer( IntMapper<UnicodeString> strings ) public SSTDeserializer( IntMapper<UnicodeString> strings )
// Extract exactly the count of strings from the SST record. // Extract exactly the count of strings from the SST record.
UnicodeString str; UnicodeString str;
if (in.available() == 0 && !in.hasNextRecord()) { if (in.available() == 0 && !in.hasNextRecord()) {
LOG.log(POILogger.ERROR, "Ran out of data before creating all the strings! String at index ", i);
LOG.atError().log("Ran out of data before creating all the strings! String at index {}", box(i));
str = new UnicodeString(""); str = new UnicodeString("");
} else { } else {
str = new UnicodeString(in); str = new UnicodeString(in);

+ 5
- 5
src/java/org/apache/poi/hssf/record/SupBookRecord.java View File

import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;


/** /**
*/ */
public final class SupBookRecord extends StandardRecord { public final class SupBookRecord extends StandardRecord {


private static final POILogger LOG = POILogFactory.getLogger(SupBookRecord.class);
private static final Logger LOG = LogManager.getLogger(SupBookRecord.class);


public static final short sid = 0x01AE; public static final short sid = 0x01AE;


break; break;
case CH_LONG_VOLUME: case CH_LONG_VOLUME:
//Don't known to handle... //Don't known to handle...
LOG.log(POILogger.WARN, "Found unexpected key: ChLongVolume - IGNORING");
LOG.atWarn().log("Found unexpected key: ChLongVolume - IGNORING");
break; break;
case CH_STARTUP_DIR: case CH_STARTUP_DIR:
case CH_ALT_STARTUP_DIR: case CH_ALT_STARTUP_DIR:
case CH_LIB_DIR: case CH_LIB_DIR:
LOG.log(POILogger.WARN, "EXCEL.EXE path unkown - using this directoy instead: .");
LOG.atWarn().log("EXCEL.EXE path unknown - using this directory instead: .");
sb.append(".").append(PATH_SEPERATOR); sb.append(".").append(PATH_SEPERATOR);
break; break;
default: default:

+ 9
- 8
src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java View File

import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.CFHeader12Record; import org.apache.poi.hssf.record.CFHeader12Record;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.GenericRecordJsonWriter; import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException; import org.apache.poi.util.RecordFormatException;


import static org.apache.logging.log4j.util.Unbox.box;

/** /**
* <p>CFRecordsAggregate - aggregates Conditional Formatting records CFHeaderRecord * <p>CFRecordsAggregate - aggregates Conditional Formatting records CFHeaderRecord
* and number of up CFRuleRecord records together to simplify access to them.</p> * and number of up CFRuleRecord records together to simplify access to them.</p>
public final class CFRecordsAggregate extends RecordAggregate implements GenericRecord { public final class CFRecordsAggregate extends RecordAggregate implements GenericRecord {
/** Excel 97-2003 allows up to 3 conditional formating 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 int MAX_97_2003_CONDTIONAL_FORMAT_RULES = 3;
private static final POILogger LOG = POILogFactory.getLogger(CFRecordsAggregate.class);
private static final Logger LOG = LogManager.getLogger(CFRecordsAggregate.class);


private final CFHeaderBase header; private final CFHeaderBase header;


throw new IllegalArgumentException("rules must not be null"); throw new IllegalArgumentException("rules must not be null");
} }
if(pRules.length > MAX_97_2003_CONDTIONAL_FORMAT_RULES) { if(pRules.length > MAX_97_2003_CONDTIONAL_FORMAT_RULES) {
LOG.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");
LOG.atWarn().log("Excel versions before 2007 require that No more than " +
MAX_97_2003_CONDTIONAL_FORMAT_RULES + " rules may be specified, {} were found, this file will " +
"cause problems with old Excel versions", box(pRules.length));
} }
if (pRules.length != pHeader.getNumberOfConditionalFormats()) { if (pRules.length != pHeader.getNumberOfConditionalFormats()) {
throw new RecordFormatException("Mismatch number of rules"); throw new RecordFormatException("Mismatch number of rules");
throw new IllegalArgumentException("r must not be null"); throw new IllegalArgumentException("r must not be null");
} }
if(rules.size() >= MAX_97_2003_CONDTIONAL_FORMAT_RULES) { if(rules.size() >= MAX_97_2003_CONDTIONAL_FORMAT_RULES) {
LOG.log(POILogger.WARN, "Excel versions before 2007 cannot cope with"
LOG.atWarn().log("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"); + " - this file will cause problems with old Excel versions");
} }

+ 6
- 4
src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java View File

import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.common.Duplicatable; import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hssf.record.common.ExtendedColor; import org.apache.poi.hssf.record.common.ExtendedColor;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


/** /**
* Color Gradient / Color Scale Conditional Formatting Rule Record. * Color Gradient / Color Scale Conditional Formatting Rule Record.
* Color Scale in the UI) * Color Scale in the UI)
*/ */
public final class ColorGradientFormatting implements Duplicatable, GenericRecord { public final class ColorGradientFormatting implements Duplicatable, GenericRecord {
private static final POILogger log = POILogFactory.getLogger(ColorGradientFormatting.class);
private static final Logger LOGGER = LogManager.getLogger(ColorGradientFormatting.class);


private static final BitField clamp = BitFieldFactory.getInstance(0x01); private static final BitField clamp = BitFieldFactory.getInstance(0x01);
private static final BitField background = BitFieldFactory.getInstance(0x02); private static final BitField background = BitFieldFactory.getInstance(0x02);
int numI = in.readByte(); int numI = in.readByte();
int numG = in.readByte(); int numG = in.readByte();
if (numI != numG) { if (numI != numG) {
log.log(POILogger.WARN, "Inconsistent Color Gradient defintion, found " + numI + " vs " + numG + " entries");
LOGGER.atWarn().log("Inconsistent Color Gradient definition, found {} vs {} entries", box(numI),box(numG));
} }
options = in.readByte(); options = in.readByte();



+ 6
- 5
src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java View File



package org.apache.poi.hssf.record.cf; package org.apache.poi.hssf.record.cf;


import static org.apache.logging.log4j.util.Unbox.box;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString; import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;


import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.common.Duplicatable; import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hssf.record.common.ExtendedColor; import org.apache.poi.hssf.record.common.ExtendedColor;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Data Bar Conditional Formatting Rule Record. * Data Bar Conditional Formatting Rule Record.
*/ */
public final class DataBarFormatting implements Duplicatable, GenericRecord { public final class DataBarFormatting implements Duplicatable, GenericRecord {
private static final POILogger LOG = POILogFactory.getLogger(DataBarFormatting.class);
private static final Logger LOG = LogManager.getLogger(DataBarFormatting.class);


private static final BitField ICON_ONLY = BitFieldFactory.getInstance(0x01); private static final BitField ICON_ONLY = BitFieldFactory.getInstance(0x01);
private static final BitField REVERSED = BitFieldFactory.getInstance(0x04); private static final BitField REVERSED = BitFieldFactory.getInstance(0x04);
percentMin = in.readByte(); percentMin = in.readByte();
percentMax = in.readByte(); percentMax = in.readByte();
if (percentMin < 0 || percentMin > 100) if (percentMin < 0 || percentMin > 100)
LOG.log(POILogger.WARN, "Inconsistent Minimum Percentage found " + percentMin);
LOG.atWarn().log("Inconsistent Minimum Percentage found {}", box(percentMin));
if (percentMax < 0 || percentMax > 100) if (percentMax < 0 || percentMax > 100)
LOG.log(POILogger.WARN, "Inconsistent Maximum Percentage found " + percentMax);
LOG.atWarn().log("Inconsistent Maximum Percentage found {}", box(percentMax));


color = new ExtendedColor(in); color = new ExtendedColor(in);
thresholdMin = new DataBarThreshold(in); thresholdMin = new DataBarThreshold(in);

+ 6
- 4
src/java/org/apache/poi/hssf/record/cf/IconMultiStateFormatting.java View File

import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.common.Duplicatable; import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet; import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


/** /**
* Icon / Multi-State Conditional Formatting Rule Record. * Icon / Multi-State Conditional Formatting Rule Record.
*/ */
public final class IconMultiStateFormatting implements Duplicatable, GenericRecord { public final class IconMultiStateFormatting implements Duplicatable, GenericRecord {
private static final POILogger LOG = POILogFactory.getLogger(IconMultiStateFormatting.class);
private static final Logger LOG = LogManager.getLogger(IconMultiStateFormatting.class);


private static BitField ICON_ONLY = BitFieldFactory.getInstance(0x01); private static BitField ICON_ONLY = BitFieldFactory.getInstance(0x01);
private static BitField REVERSED = BitFieldFactory.getInstance(0x04); private static BitField REVERSED = BitFieldFactory.getInstance(0x04);
int set = in.readByte(); int set = in.readByte();
iconSet = IconSet.byId(set); iconSet = IconSet.byId(set);
if (iconSet.num != num) { if (iconSet.num != num) {
LOG.log(POILogger.WARN, "Inconsistent Icon Set defintion, found " + iconSet + " but defined as " + num + " entries");
LOG.atWarn().log("Inconsistent Icon Set definition, found {} but defined as {} entries", iconSet, box(num));
} }
options = in.readByte(); options = in.readByte();



+ 7
- 5
src/java/org/apache/poi/hssf/record/common/ExtRst.java View File

import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hssf.record.cont.ContinuableRecordOutput; import org.apache.poi.hssf.record.cont.ContinuableRecordOutput;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;


import static org.apache.logging.log4j.util.Unbox.box;

@Internal @Internal
public class ExtRst implements Comparable<ExtRst>, GenericRecord { public class ExtRst implements Comparable<ExtRst>, GenericRecord {
private static final POILogger LOG = POILogFactory.getLogger(ExtRst.class);
private static final Logger LOG = LogManager.getLogger(ExtRst.class);
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;




// Spot corrupt records // Spot corrupt records
if(reserved != 1) { if(reserved != 1) {
LOG.log(POILogger.WARN, "Warning - ExtRst has wrong magic marker, expecting 1 but found ", reserved, " - ignoring");
LOG.atWarn().log("ExtRst has wrong magic marker, expecting 1 but found {} - ignoring", box(reserved));
// Grab all the remaining data, and ignore it // Grab all the remaining data, and ignore it
for(int i=0; i<expectedLength-2; i++) { for(int i=0; i<expectedLength-2; i++) {
in.readByte(); in.readByte();


int extraDataLength = runData - (numRuns*6); int extraDataLength = runData - (numRuns*6);
if(extraDataLength < 0) { if(extraDataLength < 0) {
LOG.log( POILogger.WARN, "Warning - ExtRst overran by ", (0-extraDataLength), " bytes");
LOG.atWarn().log("ExtRst overran by {} bytes", box(-extraDataLength));
extraDataLength = 0; extraDataLength = 0;
} }
extraData = IOUtils.safelyAllocate(extraDataLength, MAX_RECORD_LENGTH); extraData = IOUtils.safelyAllocate(extraDataLength, MAX_RECORD_LENGTH);

+ 6
- 4
src/java/org/apache/poi/hssf/record/common/UnicodeString.java View File

import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.common.Duplicatable; import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.BitField; import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


/** /**
* Unicode String - just standard fields that are in several records. * Unicode String - just standard fields that are in several records.
* This is often called a XLUnicodeRichExtendedString in MS documentation.<p> * This is often called a XLUnicodeRichExtendedString in MS documentation.<p>
*/ */
public class UnicodeString implements Comparable<UnicodeString>, Duplicatable, GenericRecord { public class UnicodeString implements Comparable<UnicodeString>, Duplicatable, GenericRecord {
private static final POILogger LOG = POILogFactory.getLogger(UnicodeString.class);
private static final Logger LOG = LogManager.getLogger(UnicodeString.class);


private static final BitField highByte = BitFieldFactory.getInstance(0x1); private static final BitField highByte = BitFieldFactory.getInstance(0x1);
// 0x2 is reserved // 0x2 is reserved
if (isExtendedText() && (extensionLength > 0)) { if (isExtendedText() && (extensionLength > 0)) {
field_5_ext_rst = new ExtRst(new ContinuableRecordInput(in), extensionLength); field_5_ext_rst = new ExtRst(new ContinuableRecordInput(in), extensionLength);
if(field_5_ext_rst.getDataSize()+4 != extensionLength) { if(field_5_ext_rst.getDataSize()+4 != extensionLength) {
LOG.log(POILogger.WARN, "ExtRst was supposed to be " + extensionLength + " bytes long, but seems to actually be " + (field_5_ext_rst.getDataSize() + 4));
LOG.atWarn().log("ExtRst was supposed to be {} bytes long, but seems to actually be {}", box(extensionLength),box(field_5_ext_rst.getDataSize() + 4));
} }
} }
} }

+ 19
- 22
src/java/org/apache/poi/hssf/usermodel/EscherGraphics.java View File



package org.apache.poi.hssf.usermodel; package org.apache.poi.hssf.usermodel;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.util.NotImplemented; import org.apache.poi.util.NotImplemented;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.SuppressForbidden; import org.apache.poi.util.SuppressForbidden;


import java.awt.*; import java.awt.*;
* </blockquote> * </blockquote>
*/ */
public class EscherGraphics extends Graphics { public class EscherGraphics extends Graphics {
private static final POILogger LOG = POILogFactory.getLogger(EscherGraphics.class);
private static final Logger LOG = LogManager.getLogger(EscherGraphics.class);


private final HSSFShapeGroup escherGroup; private final HSSFShapeGroup escherGroup;
private final HSSFWorkbook workbook; private final HSSFWorkbook workbook;
@NotImplemented @NotImplemented
public void clipRect(int x, int y, int width, int height) public void clipRect(int x, int y, int width, int height)
{ {
LOG.log(POILogger.WARN,"clipRect not supported");
LOG.atWarn().log("clipRect not supported");
} }


@Override @Override
@NotImplemented @NotImplemented
public void copyArea(int x, int y, int width, int height, int dx, int dy) public void copyArea(int x, int y, int width, int height, int dx, int dy)
{ {
LOG.log(POILogger.WARN,"copyArea not supported");
LOG.atWarn().log("copyArea not supported");
} }


@Override @Override
public void drawArc(int x, int y, int width, int height, public void drawArc(int x, int y, int width, int height,
int startAngle, int arcAngle) int startAngle, int arcAngle)
{ {
LOG.log(POILogger.WARN,"drawArc not supported");
LOG.atWarn().log("drawArc not supported");
} }


@Override @Override
Color bgcolor, Color bgcolor,
ImageObserver observer) ImageObserver observer)
{ {
LOG.log(POILogger.WARN,"drawImage not supported");
LOG.atWarn().log("drawImage not supported");


return true; return true;
} }
int sx1, int sy1, int sx2, int sy2, int sx1, int sy1, int sx2, int sy2,
ImageObserver observer) ImageObserver observer)
{ {
LOG.log(POILogger.WARN,"drawImage not supported");
LOG.atWarn().log("drawImage not supported");
return true; return true;
} }


public void drawPolyline(int[] xPoints, int[] yPoints, public void drawPolyline(int[] xPoints, int[] yPoints,
int nPoints) int nPoints)
{ {
LOG.log(POILogger.WARN,"drawPolyline not supported");
LOG.atWarn().log("drawPolyline not supported");
} }


@Override @Override
@NotImplemented @NotImplemented
public void drawRect(int x, int y, int width, int height) public void drawRect(int x, int y, int width, int height)
{ {
LOG.log(POILogger.WARN,"drawRect not supported");
LOG.atWarn().log("drawRect not supported");
} }


@Override @Override
public void drawRoundRect(int x, int y, int width, int height, public void drawRoundRect(int x, int y, int width, int height,
int arcWidth, int arcHeight) int arcWidth, int arcHeight)
{ {
LOG.log(POILogger.WARN,"drawRoundRect not supported");
LOG.atWarn().log("drawRoundRect not supported");
} }


@Override @Override
public void drawString(AttributedCharacterIterator iterator, public void drawString(AttributedCharacterIterator iterator,
int x, int y) int x, int y)
{ {
if (LOG.check( POILogger.WARN ))
LOG.log(POILogger.WARN,"drawString not supported");
LOG.atWarn().log("drawString not supported");
} }


@Override @Override
public void fillArc(int x, int y, int width, int height, public void fillArc(int x, int y, int width, int height,
int startAngle, int arcAngle) int startAngle, int arcAngle)
{ {
if (LOG.check( POILogger.WARN ))
LOG.log(POILogger.WARN,"fillArc not supported");
LOG.atWarn().log("fillArc not supported");
} }


@Override @Override
* @param xPoints array of the <code>x</code> coordinates. * @param xPoints array of the <code>x</code> coordinates.
* @param yPoints array of the <code>y</code> coordinates. * @param yPoints array of the <code>y</code> coordinates.
* @param nPoints the total number of points in the polygon. * @param nPoints the total number of points in the polygon.
* @see java.awt.Graphics#drawPolygon(int[], int[], int)
* @see Graphics#drawPolygon(int[], int[], int)
*/ */
@Override @Override
public void fillPolygon(int[] xPoints, int[] yPoints, public void fillPolygon(int[] xPoints, int[] yPoints,
public void fillRoundRect(int x, int y, int width, int height, public void fillRoundRect(int x, int y, int width, int height,
int arcWidth, int arcHeight) int arcWidth, int arcHeight)
{ {
if (LOG.check( POILogger.WARN ))
LOG.log(POILogger.WARN,"fillRoundRect not supported");
LOG.atWarn().log("fillRoundRect not supported");
} }


@Override @Override
@NotImplemented @NotImplemented
public void setClip(Shape shape) public void setClip(Shape shape)
{ {
LOG.log(POILogger.WARN,"setClip not supported");
LOG.atWarn().log("setClip not supported");
} }


@Override @Override
@NotImplemented @NotImplemented
public void setPaintMode() public void setPaintMode()
{ {
LOG.log(POILogger.WARN,"setPaintMode not supported");
LOG.atWarn().log("setPaintMode not supported");
} }


@Override @Override
@NotImplemented @NotImplemented
public void setXORMode(Color color) public void setXORMode(Color color)
{ {
LOG.log(POILogger.WARN,"setXORMode not supported");
LOG.atWarn().log("setXORMode not supported");
} }


@Override @Override
@NotImplemented @NotImplemented
public void translate(int x, int y) public void translate(int x, int y)
{ {
LOG.log(POILogger.WARN,"translate not supported");
LOG.atWarn().log("translate not supported");
} }


public Color getBackground() public Color getBackground()

+ 17
- 32
src/java/org/apache/poi/hssf/usermodel/EscherGraphics2d.java View File



package org.apache.poi.hssf.usermodel; package org.apache.poi.hssf.usermodel;


import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


import java.awt.*; import java.awt.*;
import java.awt.font.FontRenderContext; import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector; import java.awt.font.GlyphVector;
import java.awt.font.TextLayout; import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Area; import java.awt.geom.Area;
import java.awt.geom.GeneralPath; import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D; import java.awt.geom.Line2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp; import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver; import java.awt.image.ImageObserver;
* </blockquote> * </blockquote>
*/ */
public final class EscherGraphics2d extends Graphics2D { public final class EscherGraphics2d extends Graphics2D {
private static final POILogger LOG = POILogFactory.getLogger(EscherGraphics2d.class);
private static final Logger LOG = LogManager.getLogger(EscherGraphics2d.class);


private EscherGraphics _escherGraphics; private EscherGraphics _escherGraphics;
private BufferedImage _img; private BufferedImage _img;
} }
else else
{ {
if (LOG.check(POILogger.WARN))
LOG.log(POILogger.WARN, "draw not fully supported");
LOG.atWarn().log("draw not fully supported");
} }
} }


public void drawArc(int x, int y, int width, int height, public void drawArc(int x, int y, int width, int height,
int startAngle, int arcAngle) int startAngle, int arcAngle)
{ {
draw(new java.awt.geom.Arc2D.Float(x, y, width, height, startAngle, arcAngle, 0));
draw(new Arc2D.Float(x, y, width, height, startAngle, arcAngle, 0));
} }


public void drawGlyphVector(GlyphVector g, float x, float y) public void drawGlyphVector(GlyphVector g, float x, float y)
public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
int sx2, int sy2, Color bgColor, ImageObserver imageobserver) int sx2, int sy2, Color bgColor, ImageObserver imageobserver)
{ {
if (LOG.check( POILogger.WARN ))
LOG.log(POILogger.WARN,"drawImage() not supported");
LOG.atWarn().log("drawImage() not supported");
return true; return true;
} }


public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
int sx2, int sy2, ImageObserver imageobserver) int sx2, int sy2, ImageObserver imageobserver)
{ {
if (LOG.check( POILogger.WARN ))
LOG.log(POILogger.WARN,"drawImage() not supported");
LOG.atWarn().log("drawImage() not supported");
return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, imageobserver); return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, imageobserver);
} }
public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, Color bgColor, ImageObserver imageobserver) public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, Color bgColor, ImageObserver imageobserver)
{ {
if (LOG.check( POILogger.WARN ))
LOG.log(POILogger.WARN,"drawImage() not supported");
LOG.atWarn().log("drawImage() not supported");
return true; return true;
} }




public void drawRoundRect(int i, int j, int k, int l, int i1, int j1) public void drawRoundRect(int i, int j, int k, int l, int i1, int j1)
{ {
draw(new java.awt.geom.RoundRectangle2D.Float(i, j, k, l, i1, j1));
draw(new RoundRectangle2D.Float(i, j, k, l, i1, j1));
} }


public void drawString(String string, float x, float y) public void drawString(String string, float x, float y)


public void fill(Shape shape) public void fill(Shape shape)
{ {
if (LOG.check( POILogger.WARN ))
LOG.log(POILogger.WARN,"fill(Shape) not supported");
LOG.atWarn().log("fill(Shape) not supported");
} }


public void fillArc(int i, int j, int k, int l, int i1, int j1) public void fillArc(int i, int j, int k, int l, int i1, int j1)
{ {
fill(new java.awt.geom.Arc2D.Float(i, j, k, l, i1, j1, 2));
fill(new Arc2D.Float(i, j, k, l, i1, j1, 2));
} }


public void fillOval(int x, int y, int width, int height) public void fillOval(int x, int y, int width, int height)
* @param xPoints array of the <code>x</code> coordinates. * @param xPoints array of the <code>x</code> coordinates.
* @param yPoints array of the <code>y</code> coordinates. * @param yPoints array of the <code>y</code> coordinates.
* @param nPoints the total number of points in the polygon. * @param nPoints the total number of points in the polygon.
* @see java.awt.Graphics#drawPolygon(int[], int[], int)
* @see Graphics#drawPolygon(int[], int[], int)
*/ */
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
{ {
public void fillRoundRect(int x, int y, int width, int height, public void fillRoundRect(int x, int y, int width, int height,
int arcWidth, int arcHeight) int arcWidth, int arcHeight)
{ {
fill(new java.awt.geom.RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
fill(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
} }


public Color getBackground() public Color getBackground()
return _paint; return _paint;
} }


public Object getRenderingHint(java.awt.RenderingHints.Key key)
public Object getRenderingHint(RenderingHints.Key key)
{ {
return getG2D().getRenderingHint(key); return getG2D().getRenderingHint(key);
} }
getEscherGraphics().setPaintMode(); getEscherGraphics().setPaintMode();
} }


public void setRenderingHint(java.awt.RenderingHints.Key key, Object obj)
public void setRenderingHint(RenderingHints.Key key, Object obj)
{ {
getG2D().setRenderingHint(key, obj); getG2D().setRenderingHint(key, obj);
} }
getTrans().concatenate(affinetransform); getTrans().concatenate(affinetransform);
} }


// Image transformImage(Image image, Rectangle rectangle, Rectangle rectangle1, ImageObserver imageobserver, Color color1)
// {
// logger.log(POILogger.WARN,"transformImage() not supported");
// return null;
// }
//
// Image transformImage(Image image, int ai[], Rectangle rectangle, ImageObserver imageobserver, Color color1)
// {
// logger.log(POILogger.WARN,"transformImage() not supported");
// return null;
// }

public void translate(double d, double d1) public void translate(double d, double d1)
{ {
getTrans().translate(d, d1); getTrans().translate(d, d1);

+ 0
- 1
src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java View File

* little other than act as a container for other shapes and groups. * little other than act as a container for other shapes and groups.
*/ */
public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShape> { public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShape> {
// private static POILogger log = POILogFactory.getLogger(HSSFPatriarch.class);
private final List<HSSFShape> _shapes = new ArrayList<>(); private final List<HSSFShape> _shapes = new ArrayList<>();


private final EscherSpgrRecord _spgrRecord; private final EscherSpgrRecord _spgrRecord;

+ 5
- 5
src/java/org/apache/poi/hssf/usermodel/HSSFPolygon.java View File



package org.apache.poi.hssf.usermodel; package org.apache.poi.hssf.usermodel;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ddf.EscherArrayProperty; import org.apache.poi.ddf.EscherArrayProperty;
import org.apache.poi.ddf.EscherBoolProperty; import org.apache.poi.ddf.EscherBoolProperty;
import org.apache.poi.ddf.EscherClientDataRecord; import org.apache.poi.ddf.EscherClientDataRecord;
import org.apache.poi.hssf.record.ObjRecord; import org.apache.poi.hssf.record.ObjRecord;
import org.apache.poi.hssf.record.TextObjectRecord; import org.apache.poi.hssf.record.TextObjectRecord;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* *
public class HSSFPolygon extends HSSFSimpleShape { public class HSSFPolygon extends HSSFSimpleShape {
public static final short OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 0x1E; public static final short OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 0x1E;


private static final POILogger LOG = POILogFactory.getLogger(HSSFPolygon.class);
private static final Logger LOG = LogManager.getLogger(HSSFPolygon.class);


public HSSFPolygon(EscherContainerRecord spContainer, ObjRecord objRecord, TextObjectRecord _textObjectRecord) { public HSSFPolygon(EscherContainerRecord spContainer, ObjRecord objRecord, TextObjectRecord _textObjectRecord) {
super(spContainer, objRecord, _textObjectRecord); super(spContainer, objRecord, _textObjectRecord);
*/ */
public void setPoints(int[] xPoints, int[] yPoints) { public void setPoints(int[] xPoints, int[] yPoints) {
if (xPoints.length != yPoints.length){ if (xPoints.length != yPoints.length){
LOG.log( POILogger.ERROR, "xPoint.length must be equal to yPoints.length");
LOG.atError().log("xPoint.length must be equal to yPoints.length");
return; return;
} }
if (xPoints.length == 0){ if (xPoints.length == 0){
LOG.log( POILogger.ERROR, "HSSFPolygon must have at least one point");
LOG.atError().log("HSSFPolygon must have at least one point");
} }
EscherArrayProperty verticesProp = new EscherArrayProperty(EscherPropertyTypes.GEOMETRY__VERTICES, false, 0); EscherArrayProperty verticesProp = new EscherArrayProperty(EscherPropertyTypes.GEOMETRY__VERTICES, false, 0);
verticesProp.setNumberOfElementsInArray(xPoints.length+1); verticesProp.setNumberOfElementsInArray(xPoints.length+1);

+ 4
- 4
src/java/org/apache/poi/hssf/usermodel/HSSFShape.java View File

import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ddf.EscherBoolProperty; import org.apache.poi.ddf.EscherBoolProperty;
import org.apache.poi.ddf.EscherChildAnchorRecord; import org.apache.poi.ddf.EscherChildAnchorRecord;
import org.apache.poi.ddf.EscherClientAnchorRecord; import org.apache.poi.ddf.EscherClientAnchorRecord;
import org.apache.poi.hssf.record.ObjRecord; import org.apache.poi.hssf.record.ObjRecord;
import org.apache.poi.ss.usermodel.Shape; import org.apache.poi.ss.usermodel.Shape;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;


/** /**
* setFlipVertical() or setFlipHorizontally(). * setFlipVertical() or setFlipHorizontally().
*/ */
public abstract class HSSFShape implements Shape { public abstract class HSSFShape implements Shape {
private static final POILogger LOG = POILogFactory.getLogger(HSSFShape.class);
private static final Logger LOG = LogManager.getLogger(HSSFShape.class);


public static final int LINEWIDTH_ONE_PT = 12700; public static final int LINEWIDTH_ONE_PT = 12700;
public static final int LINEWIDTH_DEFAULT = 9525; public static final int LINEWIDTH_DEFAULT = 9525;
LittleEndian.putInt(property.getPropertyValue(), bos); LittleEndian.putInt(property.getPropertyValue(), bos);
return LittleEndian.getShort(bos.toByteArray(), 2); return LittleEndian.getShort(bos.toByteArray(), 2);
} catch (IOException e) { } catch (IOException e) {
LOG.log(POILogger.ERROR, "can't determine rotation degree", e);
LOG.atError().withThrowable(e).log("can't determine rotation degree");
return 0; return 0;
} }
} }

+ 29
- 32
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java View File

import java.util.TreeMap; import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.poi.ddf.EscherRecord; import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.hssf.model.DrawingManager2; import org.apache.poi.hssf.model.DrawingManager2;
import org.apache.poi.hssf.model.HSSFFormulaParser; import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataValidation; import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationHelper; import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.helpers.RowShifter; import org.apache.poi.ss.usermodel.helpers.RowShifter;
import org.apache.poi.ss.util.CellAddress; import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.util.Configurator; import org.apache.poi.util.Configurator;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;

import static java.lang.System.currentTimeMillis;
import static org.apache.logging.log4j.util.Unbox.box;


/** /**
* High level representation of a worksheet. * High level representation of a worksheet.
*/ */
public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
private static final POILogger log = POILogFactory.getLogger(HSSFSheet.class);
private static final int DEBUG = POILogger.DEBUG;
public final class HSSFSheet implements Sheet {
private static final Logger LOGGER = LogManager.getLogger(HSSFSheet.class);


/** /**
* width of 1px in columns with default width in units of 1/256 of a character width * width of 1px in columns with default width in units of 1/256 of a character width
* scratch. You should not be calling this from application code (its protected anyhow). * scratch. You should not be calling this from application code (its protected anyhow).
* *
* @param workbook - The HSSF Workbook object associated with the sheet. * @param workbook - The HSSF Workbook object associated with the sheet.
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook#createSheet()
* @see HSSFWorkbook#createSheet()
*/ */
protected HSSFSheet(HSSFWorkbook workbook) { protected HSSFSheet(HSSFWorkbook workbook) {
_sheet = InternalSheet.createSheet(); _sheet = InternalSheet.createSheet();
* *
* @param workbook - The HSSF Workbook object associated with the sheet. * @param workbook - The HSSF Workbook object associated with the sheet.
* @param sheet - lowlevel Sheet object this sheet will represent * @param sheet - lowlevel Sheet object this sheet will represent
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook#createSheet()
* @see HSSFWorkbook#createSheet()
*/ */
protected HSSFSheet(HSSFWorkbook workbook, InternalSheet sheet) { protected HSSFSheet(HSSFWorkbook workbook, InternalSheet sheet) {
this._sheet = sheet; this._sheet = sheet;
} }


Iterator<CellValueRecordInterface> iter = sheet.getCellValueIterator(); Iterator<CellValueRecordInterface> iter = sheet.getCellValueIterator();
long timestart = System.currentTimeMillis();
long timestart = currentTimeMillis();


if (log.check( POILogger.DEBUG )) {
log.log(DEBUG, "Time at start of cell creating in HSSF sheet = ",
Long.valueOf(timestart));
}
LOGGER.atDebug().log("Time at start of cell creating in HSSF sheet = {}", box(timestart));
HSSFRow lastrow = null; HSSFRow lastrow = null;


// Add every cell to its row // Add every cell to its row
while (iter.hasNext()) { while (iter.hasNext()) {
CellValueRecordInterface cval = iter.next(); CellValueRecordInterface cval = iter.next();


long cellstart = System.currentTimeMillis();
long cellstart = currentTimeMillis();
HSSFRow hrow = lastrow; HSSFRow hrow = lastrow;


if (hrow == null || hrow.getRowNum() != cval.getRow()) { if (hrow == null || hrow.getRowNum() != cval.getRow()) {
hrow = createRowFromRecord(rowRec); hrow = createRowFromRecord(rowRec);
} }
} }
if (log.check( POILogger.DEBUG )) {
LOGGER.atTrace().log(() -> {
if (cval instanceof Record) { if (cval instanceof Record) {
log.log( DEBUG, "record id = ", Integer.toHexString( ( (org.apache.poi.hssf.record.Record) cval ).getSid() ) );
return new SimpleMessage("record id = " + Integer.toHexString(((Record) cval).getSid()));
} else { } else {
log.log( DEBUG, "record = ", cval );
return new SimpleMessage("record = " + cval);
} }
}
});
hrow.createCellFromRecord( cval ); hrow.createCellFromRecord( cval );
if (log.check( POILogger.DEBUG )) {
log.log( DEBUG, "record took ",
Long.valueOf( System.currentTimeMillis() - cellstart ) );
}
LOGGER.atTrace().log("record took {}ms", box(currentTimeMillis() - cellstart));


} }
if (log.check( POILogger.DEBUG )) {
log.log(DEBUG, "total sheet cell creation took ",
Long.valueOf(System.currentTimeMillis() - timestart));
}
LOGGER.atDebug().log("total sheet cell creation took {}ms", box(currentTimeMillis() - timestart));
} }


/** /**
* *
* @param rownum row number * @param rownum row number
* @return High level HSSFRow object representing a row in the sheet * @return High level HSSFRow object representing a row in the sheet
* @see org.apache.poi.hssf.usermodel.HSSFRow
* @see #removeRow(org.apache.poi.ss.usermodel.Row)
* @see HSSFRow
* @see #removeRow(Row)
*/ */
@Override @Override
public HSSFRow createRow(int rownum) { public HSSFRow createRow(int rownum) {
private HSSFEvaluationWorkbook book = HSSFEvaluationWorkbook.create(getWorkbook()); private HSSFEvaluationWorkbook book = HSSFEvaluationWorkbook.create(getWorkbook());


@Override @Override
public void visitRecord(org.apache.poi.hssf.record.Record r) {
public void visitRecord(Record r) {
if (!(r instanceof DVRecord)) { if (!(r instanceof DVRecord)) {
return; return;
} }
* Control if Excel should be asked to recalculate all formulas on this sheet * Control if Excel should be asked to recalculate all formulas on this sheet
* when the workbook is opened.<p> * when the workbook is opened.<p>
* *
* Calculating the formula values with {@link org.apache.poi.ss.usermodel.FormulaEvaluator} is the
* Calculating the formula values with {@link FormulaEvaluator} is the
* recommended solution, but this may be used for certain cases where * recommended solution, but this may be used for certain cases where
* evaluation in POI is not possible.<p> * evaluation in POI is not possible.<p>
* *
* It is recommended to force recalcuation of formulas on workbook level using * It is recommended to force recalcuation of formulas on workbook level using
* {@link org.apache.poi.ss.usermodel.Workbook#setForceFormulaRecalculation(boolean)}
* {@link Workbook#setForceFormulaRecalculation(boolean)}
* to ensure that all cross-worksheet formuals and external dependencies are updated. * to ensure that all cross-worksheet formuals and external dependencies are updated.
* *
* @param value true if the application will perform a full recalculation of * @param value true if the application will perform a full recalculation of
* this worksheet values when the workbook is opened * this worksheet values when the workbook is opened
* @see org.apache.poi.ss.usermodel.Workbook#setForceFormulaRecalculation(boolean)
* @see Workbook#setForceFormulaRecalculation(boolean)
*/ */
@Override @Override
public void setForceFormulaRecalculation(boolean value) { public void setForceFormulaRecalculation(boolean value) {
// add logic for hyperlinks etc, like in shiftRows() // add logic for hyperlinks etc, like in shiftRows()
} }


protected void insertChartRecords(List<org.apache.poi.hssf.record.Record> records) {
protected void insertChartRecords(List<Record> records) {
int window2Loc = _sheet.findFirstRecordLocBySid(WindowTwoRecord.sid); int window2Loc = _sheet.findFirstRecordLocBySid(WindowTwoRecord.sid);
_sheet.getRecords().addAll(window2Loc, records); _sheet.getRecords().addAll(window2Loc, records);
} }

+ 40
- 39
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java View File



package org.apache.poi.hssf.usermodel; package org.apache.poi.hssf.usermodel;


import static org.apache.logging.log4j.util.Unbox.box;
import static org.apache.poi.hssf.model.InternalWorkbook.OLD_WORKBOOK_DIR_ENTRY_NAME; import static org.apache.poi.hssf.model.InternalWorkbook.OLD_WORKBOOK_DIR_ENTRY_NAME;
import static org.apache.poi.hssf.model.InternalWorkbook.WORKBOOK_DIR_ENTRY_NAMES; import static org.apache.poi.hssf.model.InternalWorkbook.WORKBOOK_DIR_ENTRY_NAMES;


import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.regex.Pattern; import java.util.regex.Pattern;


import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.EncryptedDocumentException; import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.POIDocument; import org.apache.poi.POIDocument;
import org.apache.poi.ddf.EscherBSERecord; import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.hssf.record.ExtendedFormatRecord; import org.apache.poi.hssf.record.ExtendedFormatRecord;
import org.apache.poi.hssf.record.FilePassRecord; import org.apache.poi.hssf.record.FilePassRecord;
import org.apache.poi.hssf.record.FontRecord; import org.apache.poi.hssf.record.FontRecord;
import org.apache.poi.hssf.record.FormatRecord;
import org.apache.poi.hssf.record.LabelRecord; import org.apache.poi.hssf.record.LabelRecord;
import org.apache.poi.hssf.record.LabelSSTRecord; import org.apache.poi.hssf.record.LabelSSTRecord;
import org.apache.poi.hssf.record.NameRecord; import org.apache.poi.hssf.record.NameRecord;
import org.apache.poi.ss.usermodel.SheetVisibility; import org.apache.poi.ss.usermodel.SheetVisibility;
import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.WorkbookUtil;
import org.apache.poi.util.Configurator; import org.apache.poi.util.Configurator;
import org.apache.poi.util.HexDump; import org.apache.poi.util.HexDump;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayInputStream; import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianByteArrayOutputStream; import org.apache.poi.util.LittleEndianByteArrayOutputStream;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Removal; import org.apache.poi.util.Removal;


/** /**
* will construct whether they are reading or writing a workbook. It is also the * will construct whether they are reading or writing a workbook. It is also the
* top level object for creating new sheets/etc. * top level object for creating new sheets/etc.
* *
* @see org.apache.poi.hssf.model.InternalWorkbook
* @see org.apache.poi.hssf.usermodel.HSSFSheet
* @see InternalWorkbook
* @see HSSFSheet
*/ */
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook {
public final class HSSFWorkbook extends POIDocument implements Workbook {


//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;
*/ */
private static final int MAX_STYLES = 4030; private static final int MAX_STYLES = 4030;


private static final int DEBUG = POILogger.DEBUG;

/** /**
* used for compile-time performance/memory optimization. This determines the * used for compile-time performance/memory optimization. This determines the
* initial capacity for the sheet collection. Its currently set to 3. * initial capacity for the sheet collection. Its currently set to 3.
*/ */
private MissingCellPolicy missingCellPolicy = MissingCellPolicy.RETURN_NULL_AND_BLANK; private MissingCellPolicy missingCellPolicy = MissingCellPolicy.RETURN_NULL_AND_BLANK;


private static final POILogger log = POILogFactory.getLogger(HSSFWorkbook.class);
private static final Logger LOGGER = LogManager.getLogger(HSSFWorkbook.class);


/** /**
* The locator of user-defined functions. * The locator of user-defined functions.
* *
* @throws IOException if the stream cannot be read * @throws IOException if the stream cannot be read
* @see #HSSFWorkbook(POIFSFileSystem, boolean) * @see #HSSFWorkbook(POIFSFileSystem, boolean)
* @see org.apache.poi.poifs.filesystem.POIFSFileSystem
* @see POIFSFileSystem
*/ */
public HSSFWorkbook(POIFSFileSystem fs) throws IOException { public HSSFWorkbook(POIFSFileSystem fs) throws IOException {
this(fs, true); this(fs, true);
* need to. If set, will store all of the POIFSFileSystem * need to. If set, will store all of the POIFSFileSystem
* in memory * in memory
* @throws IOException if the stream cannot be read * @throws IOException if the stream cannot be read
* @see org.apache.poi.poifs.filesystem.POIFSFileSystem
* @see POIFSFileSystem
*/ */
public HSSFWorkbook(POIFSFileSystem fs, boolean preserveNodes) public HSSFWorkbook(POIFSFileSystem fs, boolean preserveNodes)
throws IOException { throws IOException {
* need to. If set, will store all of the POIFSFileSystem * need to. If set, will store all of the POIFSFileSystem
* in memory * in memory
* @throws IOException if the stream cannot be read * @throws IOException if the stream cannot be read
* @see org.apache.poi.poifs.filesystem.POIFSFileSystem
* @see POIFSFileSystem
*/ */
public HSSFWorkbook(DirectoryNode directory, POIFSFileSystem fs, boolean preserveNodes) public HSSFWorkbook(DirectoryNode directory, POIFSFileSystem fs, boolean preserveNodes)
throws IOException { throws IOException {
* need to. If set, will store all of the POIFSFileSystem * need to. If set, will store all of the POIFSFileSystem
* in memory * in memory
* @throws IOException if the stream cannot be read * @throws IOException if the stream cannot be read
* @see org.apache.poi.poifs.filesystem.POIFSFileSystem
* @see POIFSFileSystem
*/ */
public HSSFWorkbook(DirectoryNode directory, boolean preserveNodes) public HSSFWorkbook(DirectoryNode directory, boolean preserveNodes)
throws IOException { throws IOException {
// it happens to be spelled. // it happens to be spelled.
InputStream stream = directory.createDocumentInputStream(workbookName); InputStream stream = directory.createDocumentInputStream(workbookName);


List<org.apache.poi.hssf.record.Record> records = RecordFactory.createRecords(stream);
List<Record> records = RecordFactory.createRecords(stream);


workbook = InternalWorkbook.createWorkbook(records); workbook = InternalWorkbook.createWorkbook(records);
setPropertiesFromWorkbook(workbook); setPropertiesFromWorkbook(workbook);
_sheets.add(new HSSFSheet(this, sheet)); _sheets.add(new HSSFSheet(this, sheet));
} catch (UnsupportedBOFType eb) { } catch (UnsupportedBOFType eb) {
// Hopefully there's a supported one after this! // Hopefully there's a supported one after this!
log.log(POILogger.WARN, "Unsupported BOF found of type " + eb.getType());
LOGGER.atWarn().log("Unsupported BOF found of type {}", box(eb.getType()));
} }
} }


* @throws IOException if the stream cannot be read * @throws IOException if the stream cannot be read
* @see #HSSFWorkbook(InputStream, boolean) * @see #HSSFWorkbook(InputStream, boolean)
* @see #HSSFWorkbook(POIFSFileSystem) * @see #HSSFWorkbook(POIFSFileSystem)
* @see org.apache.poi.poifs.filesystem.POIFSFileSystem
* @see POIFSFileSystem
*/ */
public HSSFWorkbook(InputStream s) throws IOException { public HSSFWorkbook(InputStream s) throws IOException {
this(s, true); this(s, true);
* macros. This takes more memory, so only say yes if you * macros. This takes more memory, so only say yes if you
* need to. * need to.
* @throws IOException if the stream cannot be read * @throws IOException if the stream cannot be read
* @see org.apache.poi.poifs.filesystem.POIFSFileSystem
* @see POIFSFileSystem
* @see #HSSFWorkbook(POIFSFileSystem) * @see #HSSFWorkbook(POIFSFileSystem)
*/ */
@SuppressWarnings("resource") // POIFSFileSystem always closes the stream @SuppressWarnings("resource") // POIFSFileSystem always closes the stream
* *
* @param records a collection of sheet's records. * @param records a collection of sheet's records.
* @param offset the offset to search at * @param offset the offset to search at
* @see org.apache.poi.hssf.record.LabelRecord
* @see org.apache.poi.hssf.record.LabelSSTRecord
* @see org.apache.poi.hssf.record.SSTRecord
* @see LabelRecord
* @see LabelSSTRecord
* @see SSTRecord
*/ */


private void convertLabelRecords(List<org.apache.poi.hssf.record.Record> records, int offset) {
log.log(POILogger.DEBUG, "convertLabelRecords called");
private void convertLabelRecords(List<Record> records, int offset) {
LOGGER.atDebug().log("convertLabelRecords called");
for (int k = offset; k < records.size(); k++) { for (int k = offset; k < records.size(); k++) {
Record rec = records.get(k); Record rec = records.get(k);


records.add(k, newrec); records.add(k, newrec);
} }
} }
log.log(POILogger.DEBUG, "convertLabelRecords exit");
LOGGER.atDebug().log("convertLabelRecords exit");
} }


/** /**
* allow you to show the data of one sheet when another is seen "selected" * allow you to show the data of one sheet when another is seen "selected"
* in the tabs (at the bottom). * in the tabs (at the bottom).
* *
* @see org.apache.poi.hssf.usermodel.HSSFSheet#setSelected(boolean)
* @see HSSFSheet#setSelected(boolean)
*/ */
@Override @Override
public int getActiveSheetIndex() { public int getActiveSheetIndex() {
* @throws IllegalArgumentException if the name is null or invalid * @throws IllegalArgumentException if the name is null or invalid
* or workbook already contains a sheet with this name * or workbook already contains a sheet with this name
* @see #createSheet(String) * @see #createSheet(String)
* @see org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)
* @see WorkbookUtil#createSafeSheetName(String nameProposal)
*/ */
@Override @Override
public void setSheetName(int sheetIx, String name) { public void setSheetName(int sheetIx, String name) {
* @return index of the sheet (0 based). <tt>-1</tt> if not found * @return index of the sheet (0 based). <tt>-1</tt> if not found
*/ */
@Override @Override
public int getSheetIndex(org.apache.poi.ss.usermodel.Sheet sheet) {
public int getSheetIndex(Sheet sheet) {
return _sheets.indexOf(sheet); return _sheets.indexOf(sheet);
} }


* @return Sheet representing the new sheet. * @return Sheet representing the new sheet.
* @throws IllegalArgumentException if the name is null or invalid * @throws IllegalArgumentException if the name is null or invalid
* or workbook already contains a sheet with this name * or workbook already contains a sheet with this name
* @see org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)
* @see WorkbookUtil#createSafeSheetName(String nameProposal)
*/ */
@Override @Override
public HSSFSheet createSheet(String sheetname) { public HSSFSheet createSheet(String sheetname) {
* *
* @param newFile The new File you wish to write the XLS to * @param newFile The new File you wish to write the XLS to
* @throws IOException if anything can't be written. * @throws IOException if anything can't be written.
* @see org.apache.poi.poifs.filesystem.POIFSFileSystem
* @see POIFSFileSystem
*/ */
@Override @Override
public void write(File newFile) throws IOException { public void write(File newFile) throws IOException {
* a new POI POIFSFileSystem, passes in the workbook binary representation and * a new POI POIFSFileSystem, passes in the workbook binary representation and
* writes it out. * writes it out.
* <p> * <p>
* If {@code stream} is a {@link java.io.FileOutputStream} on a networked drive
* If {@code stream} is a {@link FileOutputStream} on a networked drive
* or has a high cost/latency associated with each written byte, * or has a high cost/latency associated with each written byte,
* consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream}
* consider wrapping the OutputStream in a {@link BufferedOutputStream}
* to improve write performance. * to improve write performance.
* *
* @param stream - the java OutputStream you wish to write the XLS to * @param stream - the java OutputStream you wish to write the XLS to
* @throws IOException if anything can't be written. * @throws IOException if anything can't be written.
* @see org.apache.poi.poifs.filesystem.POIFSFileSystem
* @see POIFSFileSystem
*/ */
@Override @Override
public void write(OutputStream stream) throws IOException { public void write(OutputStream stream) throws IOException {
*/ */
private static final class SheetRecordCollector implements RecordVisitor { private static final class SheetRecordCollector implements RecordVisitor {


private List<org.apache.poi.hssf.record.Record> _list;
private List<Record> _list;
private int _totalSize; private int _totalSize;


public SheetRecordCollector() { public SheetRecordCollector() {
} }


@Override @Override
public void visitRecord(org.apache.poi.hssf.record.Record r) {
public void visitRecord(Record r) {
_list.add(r); _list.add(r);
_totalSize += r.getRecordSize(); _totalSize += r.getRecordSize();




public int serialize(int offset, byte[] data) { public int serialize(int offset, byte[] data) {
int result = 0; int result = 0;
for (org.apache.poi.hssf.record.Record rec : _list) {
for (Record rec : _list) {
result += rec.serialize(offset + result, data); result += rec.serialize(offset + result, data);
} }
return result; return result;
* sheets, rows, cells, etc. * sheets, rows, cells, etc.
*/ */
public byte[] getBytes() { public byte[] getBytes() {
if (log.check(POILogger.DEBUG)) {
log.log(DEBUG, "HSSFWorkbook.getBytes()");
}
LOGGER.atDebug().log("HSSFWorkbook.getBytes()");


HSSFSheet[] sheets = getSheets(); HSSFSheet[] sheets = getSheets();
int nSheets = sheets.length; int nSheets = sheets.length;
* Returns the instance of HSSFDataFormat for this workbook. * Returns the instance of HSSFDataFormat for this workbook.
* *
* @return the HSSFDataFormat object * @return the HSSFDataFormat object
* @see org.apache.poi.hssf.record.FormatRecord
* @see org.apache.poi.hssf.record.Record
* @see FormatRecord
* @see Record
*/ */
@Override @Override
public HSSFDataFormat createDataFormat() { public HSSFDataFormat createDataFormat() {
public List<HSSFPictureData> getAllPictures() { public List<HSSFPictureData> getAllPictures() {
// The drawing group record always exists at the top level, so we won't need to do this recursively. // The drawing group record always exists at the top level, so we won't need to do this recursively.
List<HSSFPictureData> pictures = new ArrayList<>(); List<HSSFPictureData> pictures = new ArrayList<>();
for (org.apache.poi.hssf.record.Record r : workbook.getRecords()) {
for (Record r : workbook.getRecords()) {
if (r instanceof AbstractEscherHolderRecord) { if (r instanceof AbstractEscherHolderRecord) {
((AbstractEscherHolderRecord) r).decode(); ((AbstractEscherHolderRecord) r).decode();
List<EscherRecord> escherRecords = ((AbstractEscherHolderRecord) r).getEscherRecords(); List<EscherRecord> escherRecords = ((AbstractEscherHolderRecord) r).getEscherRecords();

+ 5
- 5
src/java/org/apache/poi/hssf/usermodel/StaticFontMetrics.java View File

import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;


import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


/** /**
* Allows the user to lookup the font metrics for a particular font without * Allows the user to lookup the font metrics for a particular font without
* font. Use a multiplier for other sizes. * font. Use a multiplier for other sizes.
*/ */
final class StaticFontMetrics { final class StaticFontMetrics {
private static final POILogger LOGGER = POILogFactory.getLogger(StaticFontMetrics.class);
private static final Logger LOGGER = LogManager.getLogger(StaticFontMetrics.class);
/** The font metrics property file we're using */ /** The font metrics property file we're using */
private static Properties fontMetricsProps; private static Properties fontMetricsProps;
/** Our cache of font details we've already looked up */ /** Our cache of font details we've already looked up */
if (propFileName != null) { if (propFileName != null) {
propFile = new File(propFileName); propFile = new File(propFileName);
if (!propFile.exists()) { if (!propFile.exists()) {
LOGGER.log(POILogger.WARN, "font_metrics.properties not found at path "+propFile.getAbsolutePath());
LOGGER.atWarn().log("font_metrics.properties not found at path {}", propFile.getAbsolutePath());
propFile = null; propFile = null;
} }
} }
} catch (SecurityException e) { } catch (SecurityException e) {
LOGGER.log(POILogger.WARN, "Can't access font.metrics.filename system property", e);
LOGGER.atWarn().withThrowable(e).log("Can't access font.metrics.filename system property");
} }


try (InputStream metricsIn = (propFile != null) try (InputStream metricsIn = (propFile != null)

+ 3
- 3
src/java/org/apache/poi/hssf/usermodel/helpers/HSSFColumnShifter.java View File



package org.apache.poi.hssf.usermodel.helpers; package org.apache.poi.hssf.usermodel.helpers;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.formula.FormulaShifter; import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.formula.eval.NotImplementedException; import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.apache.poi.ss.usermodel.helpers.ColumnShifter; import org.apache.poi.ss.usermodel.helpers.ColumnShifter;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.util.NotImplemented; import org.apache.poi.util.NotImplemented;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Helper for shifting columns up or down * Helper for shifting columns up or down
// {@link org.apache.poi.xssf.usermodel.helpers.XSSFColumnShifter} // {@link org.apache.poi.xssf.usermodel.helpers.XSSFColumnShifter}
@Beta @Beta
public final class HSSFColumnShifter extends ColumnShifter { public final class HSSFColumnShifter extends ColumnShifter {
private static final POILogger LOG = POILogFactory.getLogger(HSSFColumnShifter.class);
private static final Logger LOG = LogManager.getLogger(HSSFColumnShifter.class);


public HSSFColumnShifter(HSSFSheet sh) { public HSSFColumnShifter(HSSFSheet sh) {
super(sh); super(sh);

+ 3
- 5
src/java/org/apache/poi/hssf/usermodel/helpers/HSSFRowShifter.java View File



package org.apache.poi.hssf.usermodel.helpers; package org.apache.poi.hssf.usermodel.helpers;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.formula.FormulaShifter; import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.formula.eval.NotImplementedException; import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.helpers.RowShifter; import org.apache.poi.ss.usermodel.helpers.RowShifter;
import org.apache.poi.util.NotImplemented; import org.apache.poi.util.NotImplemented;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Helper for shifting rows up or down * Helper for shifting rows up or down
// non-Javadoc: When possible, code should be implemented in the RowShifter abstract class to avoid duplication with // non-Javadoc: When possible, code should be implemented in the RowShifter abstract class to avoid duplication with
// {@link org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter} // {@link org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter}
public final class HSSFRowShifter extends RowShifter { public final class HSSFRowShifter extends RowShifter {
private static final POILogger LOG = POILogFactory.getLogger(HSSFRowShifter.class);
private static final Logger LOG = LogManager.getLogger(HSSFRowShifter.class);


public HSSFRowShifter(HSSFSheet sh) { public HSSFRowShifter(HSSFSheet sh) {
super(sh); super(sh);

+ 5
- 5
src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java View File

import javax.crypto.ShortBufferException; import javax.crypto.ShortBufferException;


import com.zaxxer.sparsebits.SparseBitSet; import com.zaxxer.sparsebits.SparseBitSet;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.EncryptedDocumentException; import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.POIFSWriterEvent; import org.apache.poi.poifs.filesystem.POIFSWriterEvent;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.TempFile; import org.apache.poi.util.TempFile;


@Internal @Internal
public abstract class ChunkedCipherOutputStream extends FilterOutputStream { public abstract class ChunkedCipherOutputStream extends FilterOutputStream {
private static final POILogger LOG = POILogFactory.getLogger(ChunkedCipherOutputStream.class);
private static final Logger LOG = LogManager.getLogger(ChunkedCipherOutputStream.class);
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;


@Override @Override
public void close() throws IOException { public void close() throws IOException {
if (isClosed) { if (isClosed) {
LOG.log(POILogger.DEBUG, "ChunkedCipherOutputStream was already closed - ignoring");
LOG.atDebug().log("ChunkedCipherOutputStream was already closed - ignoring");
return; return;
} }


} }


if (!fileOut.delete()) { if (!fileOut.delete()) {
LOG.log(POILogger.ERROR, "Can't delete temporary encryption file: ", fileOut);
LOG.atError().log("Can't delete temporary encryption file: {}", fileOut);
} }
} catch (IOException e) { } catch (IOException e) {
throw new EncryptedDocumentException(e); throw new EncryptedDocumentException(e);

+ 4
- 4
src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptor.java View File

import javax.crypto.CipherOutputStream; import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.EncryptedDocumentException; import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.crypt.CryptoFunctions; import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.poifs.crypt.DataSpaceMapUtils; import org.apache.poi.poifs.crypt.DataSpaceMapUtils;
import org.apache.poi.util.LittleEndianByteArrayOutputStream; import org.apache.poi.util.LittleEndianByteArrayOutputStream;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianOutputStream; import org.apache.poi.util.LittleEndianOutputStream;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.TempFile; import org.apache.poi.util.TempFile;


public class StandardEncryptor extends Encryptor { public class StandardEncryptor extends Encryptor {
private static final POILogger LOG = POILogFactory.getLogger(StandardEncryptor.class);
private static final Logger LOG = LogManager.getLogger(StandardEncryptor.class);


protected StandardEncryptor() {} protected StandardEncryptor() {}


IOUtils.copy(fis, leos); IOUtils.copy(fis, leos);
} }
if (!fileOut.delete()) { if (!fileOut.delete()) {
LOG.log(POILogger.ERROR, "Can't delete temporary encryption file: ", fileOut);
LOG.atError().log("Can't delete temporary encryption file: {}", fileOut);
} }


leos.close(); leos.close();

+ 3
- 3
src/java/org/apache/poi/poifs/filesystem/POIFSDocumentPath.java View File

import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Stream; import java.util.stream.Stream;


import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


/** /**
* Class POIFSDocumentPath * Class POIFSDocumentPath


public class POIFSDocumentPath { public class POIFSDocumentPath {


private static final POILogger log = POILogFactory.getLogger(POIFSDocumentPath.class);
private static final Logger LOGGER = LogManager.getLogger(POIFSDocumentPath.class);


private final String[] components; private final String[] components;
private int hashcode; //lazy-compute hashCode private int hashcode; //lazy-compute hashCode

+ 4
- 4
src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java View File

import java.util.List; import java.util.List;


import org.apache.commons.math3.util.ArithmeticUtils; import org.apache.commons.math3.util.ArithmeticUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.EmptyFileException; import org.apache.poi.EmptyFileException;
import org.apache.poi.poifs.common.POIFSBigBlockSize; import org.apache.poi.poifs.common.POIFSBigBlockSize;
import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.storage.HeaderBlock; import org.apache.poi.poifs.storage.HeaderBlock;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* <p>This is the main class of the POIFS system; it manages the entire * <p>This is the main class of the POIFS system; it manages the entire
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;


private static final POILogger LOG = POILogFactory.getLogger(POIFSFileSystem.class);
private static final Logger LOG = LogManager.getLogger(POIFSFileSystem.class);


/** /**
* Maximum number size (in blocks) of the allocation table as supported by * Maximum number size (in blocks) of the allocation table as supported by
} }
// else not success? Try block did not complete normally // else not success? Try block did not complete normally
// just print stack trace and leave original ex to be thrown // just print stack trace and leave original ex to be thrown
LOG.log(POILogger.ERROR, "can't close input stream", e);
LOG.atError().withThrowable(e).log("can't close input stream");
} }
} }



+ 9
- 10
src/java/org/apache/poi/poifs/macros/VBAMacroReader.java View File



package org.apache.poi.poifs.macros; package org.apache.poi.poifs.macros;


import static org.apache.logging.log4j.util.Unbox.box;
import static org.apache.poi.util.StringUtil.endsWithIgnoreCase; import static org.apache.poi.util.StringUtil.endsWithIgnoreCase;
import static org.apache.poi.util.StringUtil.startsWithIgnoreCase; import static org.apache.poi.util.StringUtil.startsWithIgnoreCase;


import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentInputStream; import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.poifs.filesystem.DocumentNode; import org.apache.poi.poifs.filesystem.DocumentNode;
import org.apache.poi.util.HexDump; import org.apache.poi.util.HexDump;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.RLEDecompressingInputStream; import org.apache.poi.util.RLEDecompressingInputStream;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;


* @since 3.15-beta2 * @since 3.15-beta2
*/ */
public class VBAMacroReader implements Closeable { public class VBAMacroReader implements Closeable {
private static final POILogger LOGGER = POILogFactory.getLogger(VBAMacroReader.class);
private static final Logger LOGGER = LogManager.getLogger(VBAMacroReader.class);


//arbitrary limit on size of strings to read, etc. //arbitrary limit on size of strings to read, etc.
private static final int MAX_STRING_LENGTH = 20000; private static final int MAX_STRING_LENGTH = 20000;
} }


} }
if (records >= maxNameRecords) {
LOGGER.log(POILogger.WARN, "Hit max name records to read ("+maxNameRecords+"). Stopped early.");
}
LOGGER.atWarn().log("Hit max name records to read (" + maxNameRecords + "). Stopped early.");
} }


private static String readUnicode(InputStream is, int maxLength) throws IOException { private static String readUnicode(InputStream is, int maxLength) throws IOException {
read += 2; read += 2;
} }
if (read >= maxLength) { if (read >= maxLength) {
LOGGER.log(POILogger.WARN, "stopped reading unicode name after "+read+" bytes");
LOGGER.atWarn().log("stopped reading unicode name after {} bytes", box(read));
} }
return new String (bos.toByteArray(), StandardCharsets.UTF_16LE); return new String (bos.toByteArray(), StandardCharsets.UTF_16LE);
} }
if (module != null) { if (module != null) {
module.moduleType = ModuleType.Document; module.moduleType = ModuleType.Document;
} else { } else {
LOGGER.log(POILogger.WARN, "couldn't find module with name: "+mn);
LOGGER.atWarn().log("couldn't find module with name: {}", mn);
} }
} else if ("Module".equals(tokens[0]) && tokens.length > 1) { } else if ("Module".equals(tokens[0]) && tokens.length > 1) {
ModuleImpl module = getModule(tokens[1], moduleNameMap, modules); ModuleImpl module = getModule(tokens[1], moduleNameMap, modules);
if (module != null) { if (module != null) {
module.moduleType = ModuleType.Module; module.moduleType = ModuleType.Module;
} else { } else {
LOGGER.log(POILogger.WARN, "couldn't find module with name: "+tokens[1]);
LOGGER.atWarn().log("couldn't find module with name: {}", tokens[1]);
} }
} else if ("Class".equals(tokens[0]) && tokens.length > 1) { } else if ("Class".equals(tokens[0]) && tokens.length > 1) {
ModuleImpl module = getModule(tokens[1], moduleNameMap, modules); ModuleImpl module = getModule(tokens[1], moduleNameMap, modules);
if (module != null) { if (module != null) {
module.moduleType = ModuleType.Class; module.moduleType = ModuleType.Class;
} else { } else {
LOGGER.log(POILogger.WARN, "couldn't find module with name: "+tokens[1]);
LOGGER.atWarn().log("couldn't find module with name: {}", tokens[1]);
} }
} }
} }

+ 5
- 5
src/java/org/apache/poi/poifs/nio/FileBackedDataSource.java View File

import java.nio.channels.WritableByteChannel; import java.nio.channels.WritableByteChannel;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* A POIFS {@link DataSource} backed by a File * A POIFS {@link DataSource} backed by a File
*/ */
public class FileBackedDataSource extends DataSource implements Closeable { public class FileBackedDataSource extends DataSource implements Closeable {
private static final POILogger LOG = POILogFactory.getLogger(FileBackedDataSource.class);
private static final Logger LOG = LogManager.getLogger(FileBackedDataSource.class);


private final FileChannel channel; private final FileChannel channel;
private Long channelSize; private Long channelSize;
try { try {
CleanerUtil.getCleaner().freeBuffer(buffer); CleanerUtil.getCleaner().freeBuffer(buffer);
} catch (IOException e) { } catch (IOException e) {
LOG.log(POILogger.WARN, "Failed to unmap the buffer", e);
LOG.atWarn().withThrowable(e).log("Failed to unmap the buffer");
} }
} else { } else {
LOG.log(POILogger.DEBUG, CleanerUtil.UNMAP_NOT_SUPPORTED_REASON);
LOG.atDebug().log(CleanerUtil.UNMAP_NOT_SUPPORTED_REASON);
} }
} }
} }

+ 7
- 7
src/java/org/apache/poi/poifs/property/PropertyTable.java View File

import java.util.List; import java.util.List;
import java.util.Stack; import java.util.Stack;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.poifs.common.POIFSBigBlockSize; import org.apache.poi.poifs.common.POIFSBigBlockSize;
import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.filesystem.BATManaged; import org.apache.poi.poifs.filesystem.BATManaged;
import org.apache.poi.poifs.filesystem.POIFSStream; import org.apache.poi.poifs.filesystem.POIFSStream;
import org.apache.poi.poifs.storage.HeaderBlock; import org.apache.poi.poifs.storage.HeaderBlock;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import static org.apache.logging.log4j.util.Unbox.box;


/** /**
* This class embodies the Property Table for a {@link POIFSFileSystem}; * This class embodies the Property Table for a {@link POIFSFileSystem};
* chain of blocks. * chain of blocks.
*/ */
public final class PropertyTable implements BATManaged { public final class PropertyTable implements BATManaged {
private static final POILogger LOG = POILogFactory.getLogger(PropertyTable.class);
private static final Logger LOG = LogManager.getLogger(PropertyTable.class);


//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;
// Looks to be a truncated block // Looks to be a truncated block
// This isn't allowed, but some third party created files // This isn't allowed, but some third party created files
// sometimes do this, and we can normally read anyway // sometimes do this, and we can normally read anyway
LOG.log(POILogger.WARN, "Short Property Block, ", bb.remaining(),
" bytes instead of the expected " + _bigBigBlockSize.getBigBlockSize());
LOG.atWarn().log("Short Property Block, {} bytes instead of the expected {}", box(bb.remaining()),box(_bigBigBlockSize.getBigBlockSize()));
toRead = bb.remaining(); toRead = bb.remaining();
} }


if (! Property.isValidIndex(index)) if (! Property.isValidIndex(index))
return false; return false;
if (index < 0 || index >= _properties.size()) { if (index < 0 || index >= _properties.size()) {
LOG.log(POILogger.WARN, "Property index " + index +
"outside the valid range 0.."+_properties.size());
LOG.atWarn().log("Property index {} outside the valid range 0..{}", box(index),box(_properties.size()));
return false; return false;
} }
return true; return true;

+ 4
- 4
src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java View File

import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream; import javax.imageio.stream.MemoryCacheImageInputStream;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.sl.usermodel.PictureData.PictureType; import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* For now this class renders only images supported by the javax.imageio.ImageIO framework. * For now this class renders only images supported by the javax.imageio.ImageIO framework.
**/ **/
public class BitmapImageRenderer implements ImageRenderer { public class BitmapImageRenderer implements ImageRenderer {
private static final POILogger LOG = POILogFactory.getLogger(BitmapImageRenderer.class);
private static final Logger LOG = LogManager.getLogger(BitmapImageRenderer.class);


protected BufferedImage img; protected BufferedImage img;


// multiple locations above ... // multiple locations above ...
throw lastException; throw lastException;
} }
LOG.log(POILogger.WARN, "Content-type: "+contentType+" is not support. Image ignored.");
LOG.atWarn().log("Content-type: {} is not support. Image ignored.", contentType);
return null; return null;
} }



+ 9
- 7
src/java/org/apache/poi/sl/draw/DrawPaint.java View File

import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.stream.Stream; import java.util.stream.Stream;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.sl.usermodel.AbstractColorStyle; import org.apache.poi.sl.usermodel.AbstractColorStyle;
import org.apache.poi.sl.usermodel.ColorStyle; import org.apache.poi.sl.usermodel.ColorStyle;
import org.apache.poi.sl.usermodel.Insets2D; import org.apache.poi.sl.usermodel.Insets2D;
import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
import org.apache.poi.sl.usermodel.PlaceableShape; import org.apache.poi.sl.usermodel.PlaceableShape;
import org.apache.poi.util.Dimension2DDouble; import org.apache.poi.util.Dimension2DDouble;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;




/** /**
public class DrawPaint { public class DrawPaint {
// HSL code is public domain - see https://tips4java.wordpress.com/contact-us/ // HSL code is public domain - see https://tips4java.wordpress.com/contact-us/


private static final POILogger LOG = POILogFactory.getLogger(DrawPaint.class);
// HSL code is public domain - see https://tips4java.wordpress.com/contact-us/

private static final Logger LOG = LogManager.getLogger(DrawPaint.class);


private static final Color TRANSPARENT = new Color(1f,1f,1f,0f); private static final Color TRANSPARENT = new Color(1f,1f,1f,0f);




BufferedImage image = renderer.getImage(imgDim); BufferedImage image = renderer.getImage(imgDim);
if(image == null) { if(image == null) {
LOG.log(POILogger.ERROR, "Can't load image data");
LOG.atError().log("Can't load image data");
return TRANSPARENT; return TRANSPARENT;
} }


// TODO: check why original bitmaps scale/behave differently to vector based images // TODO: check why original bitmaps scale/behave differently to vector based images
return new DrawTexturePaint(image, s, fill, flipX, flipY, renderer instanceof BitmapImageRenderer); return new DrawTexturePaint(image, s, fill, flipX, flipY, renderer instanceof BitmapImageRenderer);
} catch (IOException e) { } catch (IOException e) {
LOG.log(POILogger.ERROR, "Can't load image data - using transparent color", e);
LOG.atError().withThrowable(e).log("Can't load image data - using transparent color");
return TRANSPARENT; return TRANSPARENT;
} }
} }
try { try {
graphics.fill(shape); graphics.fill(shape);
} catch (ArrayIndexOutOfBoundsException e) { } catch (ArrayIndexOutOfBoundsException e) {
LOG.log(POILogger.WARN, "IBM JDK failed with TexturePaintContext AIOOBE - try adding the following to the VM parameter:\n" +
LOG.atWarn().withThrowable(e).log("IBM JDK failed with TexturePaintContext AIOOBE - try adding the following to the VM parameter:\n" +
"-Xjit:exclude={sun/java2d/pipe/AlphaPaintPipe.renderPathTile(Ljava/lang/Object;[BIIIIII)V} and " + "-Xjit:exclude={sun/java2d/pipe/AlphaPaintPipe.renderPathTile(Ljava/lang/Object;[BIIIIII)V} and " +
"search for 'JIT Problem Determination for IBM SDK using -Xjit' (http://www-01.ibm.com/support/docview.wss?uid=swg21294023) " + "search for 'JIT Problem Determination for IBM SDK using -Xjit' (http://www-01.ibm.com/support/docview.wss?uid=swg21294023) " +
"for how to add/determine further excludes", e);
"for how to add/determine further excludes");
} }
} }
} }

+ 6
- 6
src/java/org/apache/poi/sl/draw/DrawPictureShape.java View File

import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.common.usermodel.PictureType; import org.apache.poi.common.usermodel.PictureType;
import org.apache.poi.poifs.filesystem.FileMagic; import org.apache.poi.poifs.filesystem.FileMagic;
import org.apache.poi.sl.usermodel.PictureData; import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.PictureShape; import org.apache.poi.sl.usermodel.PictureShape;
import org.apache.poi.sl.usermodel.RectAlign; import org.apache.poi.sl.usermodel.RectAlign;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;




public class DrawPictureShape extends DrawSimpleShape { public class DrawPictureShape extends DrawSimpleShape {
private static final POILogger LOG = POILogFactory.getLogger(DrawPictureShape.class);
private static final Logger LOG = LogManager.getLogger(DrawPictureShape.class);


public DrawPictureShape(PictureShape<?,?> shape) { public DrawPictureShape(PictureShape<?,?> shape) {
super(shape); super(shape);
return; return;
} }
} catch (IOException e) { } catch (IOException e) {
LOG.log(POILogger.ERROR, "image can't be loaded/rendered.", e);
LOG.atError().withThrowable(e).log("image can't be loaded/rendered.");
} }
} }
} }


// the fallback is the BitmapImageRenderer, at least it gracefully handles invalid images // the fallback is the BitmapImageRenderer, at least it gracefully handles invalid images
final Supplier<ImageRenderer> getFallback = () -> { final Supplier<ImageRenderer> getFallback = () -> {
LOG.log(POILogger.WARN, "No suitable image renderer found for content-type '",
contentType, "' - include poi-scratchpad (for wmf/emf) or poi-ooxml (for svg) jars!");
LOG.atWarn().log("No suitable image renderer found for content-type '{}' - include " +
"poi-scratchpad (for wmf/emf) or poi-ooxml (for svg) jars!", contentType);
return fallback; return fallback;
}; };



+ 16
- 11
src/java/org/apache/poi/sl/draw/DrawTextParagraph.java View File

import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.common.usermodel.fonts.FontGroup; import org.apache.poi.common.usermodel.fonts.FontGroup;
import org.apache.poi.common.usermodel.fonts.FontGroup.FontGroupRange; import org.apache.poi.common.usermodel.fonts.FontGroup.FontGroupRange;
import org.apache.poi.common.usermodel.fonts.FontInfo; import org.apache.poi.common.usermodel.fonts.FontInfo;
import org.apache.poi.sl.usermodel.TextShape.TextDirection; import org.apache.poi.sl.usermodel.TextShape.TextDirection;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Units; import org.apache.poi.util.Units;


import static org.apache.logging.log4j.util.Unbox.box;

public class DrawTextParagraph implements Drawable { public class DrawTextParagraph implements Drawable {
private static final POILogger LOG = POILogFactory.getLogger(DrawTextParagraph.class);
private static final Logger LOG = LogManager.getLogger(DrawTextParagraph.class);


/** Keys for passing hyperlinks to the graphics context */ /** Keys for passing hyperlinks to the graphics context */
public static final XlinkAttribute HYPERLINK_HREF = new XlinkAttribute("href"); public static final XlinkAttribute HYPERLINK_HREF = new XlinkAttribute("href");


if (partBegin < partEnd) { if (partBegin < partEnd) {
// handle (b) and (c) // handle (b) and (c)
attList.add(new AttributedStringData(TextAttribute.FAMILY, fontMapped.getFontName(Locale.ROOT), beginIndex+partBegin, beginIndex+partEnd));
if (LOG.check(POILogger.DEBUG)) {
LOG.log(POILogger.DEBUG, "mapped: ",fontMapped.getFontName(Locale.ROOT)," ",(beginIndex+partBegin)," ",(beginIndex+partEnd)," - ",runText.substring(partBegin, partEnd));
}

final String fontName = fontMapped.getFontName(Locale.ROOT);
final int startIndex = beginIndex + partBegin;
final int endIndex = beginIndex + partEnd;
attList.add(new AttributedStringData(TextAttribute.FAMILY, fontName, startIndex, endIndex));
LOG.atDebug().log("mapped: {} {} {} - {}", fontName, box(startIndex),box(endIndex),runText.substring(partBegin, partEnd));
} }


// fallback for unsupported glyphs // fallback for unsupported glyphs


if (partBegin < partEnd) { if (partBegin < partEnd) {
// handle (a) and (b) // handle (a) and (b)
attList.add(new AttributedStringData(TextAttribute.FAMILY, fontFallback.getFontName(Locale.ROOT), beginIndex+partBegin, beginIndex+partEnd));
if (LOG.check(POILogger.DEBUG)) {
LOG.log(POILogger.DEBUG, "fallback: ",fontFallback.getFontName(Locale.ROOT)," ",(beginIndex+partBegin)," ",(beginIndex+partEnd)," - ",runText.substring(partBegin, partEnd));
}
final String fontName = fontFallback.getFontName(Locale.ROOT);
final int startIndex = beginIndex + partBegin;
final int endIndex = beginIndex + partEnd;
attList.add(new AttributedStringData(TextAttribute.FAMILY, fontName, startIndex, endIndex));
LOG.atDebug().log("fallback: {} {} {} - {}", fontName, box(startIndex),box(endIndex),runText.substring(partBegin, partEnd));
} }
} }



+ 97
- 114
src/java/org/apache/poi/sl/draw/SLGraphics.java View File

package org.apache.poi.sl.draw; package org.apache.poi.sl.draw;




import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.Toolkit;
import java.awt.*;
import java.awt.font.FontRenderContext; import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector; import java.awt.font.GlyphVector;
import java.awt.font.TextLayout; import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator;
import java.util.Map; import java.util.Map;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.sl.usermodel.FreeformShape; import org.apache.poi.sl.usermodel.FreeformShape;
import org.apache.poi.sl.usermodel.GroupShape; import org.apache.poi.sl.usermodel.GroupShape;
import org.apache.poi.sl.usermodel.Insets2D; import org.apache.poi.sl.usermodel.Insets2D;
import org.apache.poi.sl.usermodel.TextRun; import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.util.NotImplemented; import org.apache.poi.util.NotImplemented;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.SuppressForbidden; import org.apache.poi.util.SuppressForbidden;


/** /**
*/ */
public class SLGraphics extends Graphics2D implements Cloneable { public class SLGraphics extends Graphics2D implements Cloneable {


private static final POILogger LOG = POILogFactory.getLogger(SLGraphics.class);
private static final Logger LOG = LogManager.getLogger(SLGraphics.class);


//The ppt object to write into. //The ppt object to write into.
private GroupShape<?,?> _group; private GroupShape<?,?> _group;
/** /**
* Gets the current font. * Gets the current font.
* @return this graphics context's current font. * @return this graphics context's current font.
* @see java.awt.Font
* @see java.awt.Graphics#setFont(Font)
* @see Font
* @see Graphics#setFont(Font)
*/ */
public Font getFont(){ public Font getFont(){
return _font; return _font;
* All subsequent text operations using this graphics context * All subsequent text operations using this graphics context
* use this font. * use this font.
* @param font the font. * @param font the font.
* @see java.awt.Graphics#getFont
* @see java.awt.Graphics#drawString(java.lang.String, int, int)
* @see java.awt.Graphics#drawBytes(byte[], int, int, int, int)
* @see java.awt.Graphics#drawChars(char[], int, int, int, int)
* @see Graphics#getFont
* @see Graphics#drawString(String, int, int)
* @see Graphics#drawBytes(byte[], int, int, int, int)
* @see Graphics#drawChars(char[], int, int, int, int)
*/ */
public void setFont(Font font){ public void setFont(Font font){
this._font = font; this._font = font;
/** /**
* Gets this graphics context's current color. * Gets this graphics context's current color.
* @return this graphics context's current color. * @return this graphics context's current color.
* @see java.awt.Color
* @see java.awt.Graphics#setColor
* @see Color
* @see Graphics#setColor
*/ */
public Color getColor(){ public Color getColor(){
return _foreground; return _foreground;
* color. All subsequent graphics operations using this graphics * color. All subsequent graphics operations using this graphics
* context use this specified color. * context use this specified color.
* @param c the new rendering color. * @param c the new rendering color.
* @see java.awt.Color
* @see java.awt.Graphics#getColor
* @see Color
* @see Graphics#getColor
*/ */
public void setColor(Color c) { public void setColor(Color c) {
setPaint(c); setPaint(c);
* @return the current <code>Graphics2D</code> <code>Paint</code>, * @return the current <code>Graphics2D</code> <code>Paint</code>,
* which defines a color or pattern. * which defines a color or pattern.
* @see #setPaint * @see #setPaint
* @see java.awt.Graphics#setColor
* @see Graphics#setColor
*/ */
public Paint getPaint(){ public Paint getPaint(){
return _paint; return _paint;
* of this <code>Graphics2D</code>. * of this <code>Graphics2D</code>.
* @param paint the <code>Paint</code> object to be used to generate * @param paint the <code>Paint</code> object to be used to generate
* color during the rendering process, or <code>null</code> * color during the rendering process, or <code>null</code>
* @see java.awt.Graphics#setColor
* @see Graphics#setColor
*/ */
public void setPaint(Paint paint){ public void setPaint(Paint paint){
if(paint == null) return; if(paint == null) return;
* @param shape the <code>Shape</code> to be rendered * @param shape the <code>Shape</code> to be rendered
* @see #setStroke * @see #setStroke
* @see #setPaint * @see #setPaint
* @see java.awt.Graphics#setColor
* @see Graphics#setColor
* @see #_transform * @see #_transform
* @see #setTransform * @see #setTransform
* @see #clip * @see #clip
* @throws NullPointerException if <code>str</code> is * @throws NullPointerException if <code>str</code> is
* <code>null</code> * <code>null</code>
* @see #setPaint * @see #setPaint
* @see java.awt.Graphics#setColor
* @see java.awt.Graphics#setFont
* @see Graphics#setColor
* @see Graphics#setFont
* @see #setTransform * @see #setTransform
* @see #setComposite * @see #setComposite
* @see #setClip * @see #setClip
* <code>Paint</code>, and <code>Composite</code>. * <code>Paint</code>, and <code>Composite</code>.
* @param shape the <code>Shape</code> to be filled * @param shape the <code>Shape</code> to be filled
* @see #setPaint * @see #setPaint
* @see java.awt.Graphics#setColor
* @see Graphics#setColor
* @see #_transform * @see #_transform
* @see #setTransform * @see #setTransform
* @see #setComposite * @see #setComposite
* The <i>user clip</i> modified by this method is independent of the * The <i>user clip</i> modified by this method is independent of the
* clipping associated with device bounds and visibility. If no clip has * clipping associated with device bounds and visibility. If no clip has
* previously been set, or if the clip has been cleared using * previously been set, or if the clip has been cleared using
* {@link java.awt.Graphics#setClip(Shape) setClip} with a
* {@link Graphics#setClip(Shape) setClip} with a
* <code>null</code> argument, the specified <code>Shape</code> becomes * <code>null</code> argument, the specified <code>Shape</code> becomes
* the new user clip. * the new user clip.
* @param s the <code>Shape</code> to be intersected with the current * @param s the <code>Shape</code> to be intersected with the current
* @return a <code>Shape</code> object representing the * @return a <code>Shape</code> object representing the
* current clipping area, or <code>null</code> if * current clipping area, or <code>null</code> if
* no clip is set. * no clip is set.
* @see java.awt.Graphics#getClipBounds()
* @see java.awt.Graphics#clipRect
* @see java.awt.Graphics#setClip(int, int, int, int)
* @see java.awt.Graphics#setClip(Shape)
* @see Graphics#getClipBounds()
* @see Graphics#clipRect
* @see Graphics#setClip(int, int, int, int)
* @see Graphics#setClip(Shape)
* @since JDK1.1 * @since JDK1.1
*/ */
@NotImplemented @NotImplemented
* at the four corners. * at the four corners.
* @param arcHeight the vertical diameter of the arc * @param arcHeight the vertical diameter of the arc
* at the four corners. * at the four corners.
* @see java.awt.Graphics#fillRoundRect
* @see Graphics#fillRoundRect
*/ */
public void drawRoundRect(int x, int y, int width, int height, public void drawRoundRect(int x, int y, int width, int height,
int arcWidth, int arcHeight){ int arcWidth, int arcHeight){
* @param str the string to be drawn. * @param str the string to be drawn.
* @param x the <i>x</i> coordinate. * @param x the <i>x</i> coordinate.
* @param y the <i>y</i> coordinate. * @param y the <i>y</i> coordinate.
* @see java.awt.Graphics#drawBytes
* @see java.awt.Graphics#drawChars
* @see Graphics#drawBytes
* @see Graphics#drawChars
*/ */
public void drawString(String str, int x, int y){ public void drawString(String str, int x, int y){
drawString(str, (float)x, (float)y); drawString(str, (float)x, (float)y);
* of the oval to be filled. * of the oval to be filled.
* @param width the width of the oval to be filled. * @param width the width of the oval to be filled.
* @param height the height of the oval to be filled. * @param height the height of the oval to be filled.
* @see java.awt.Graphics#drawOval
* @see Graphics#drawOval
*/ */
public void fillOval(int x, int y, int width, int height){ public void fillOval(int x, int y, int width, int height){
Ellipse2D oval = new Ellipse2D.Double(x, y, width, height); Ellipse2D oval = new Ellipse2D.Double(x, y, width, height);
* of the arc at the four corners. * of the arc at the four corners.
* @param arcHeight the vertical diameter * @param arcHeight the vertical diameter
* of the arc at the four corners. * of the arc at the four corners.
* @see java.awt.Graphics#drawRoundRect
* @see Graphics#drawRoundRect
*/ */
public void fillRoundRect(int x, int y, int width, int height, public void fillRoundRect(int x, int y, int width, int height,
int arcWidth, int arcHeight){ int arcWidth, int arcHeight){
* @param startAngle the beginning angle. * @param startAngle the beginning angle.
* @param arcAngle the angular extent of the arc, * @param arcAngle the angular extent of the arc,
* relative to the start angle. * relative to the start angle.
* @see java.awt.Graphics#drawArc
* @see Graphics#drawArc
*/ */
public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle){ public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle){
Arc2D arc = new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE); Arc2D arc = new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE);
* @param startAngle the beginning angle. * @param startAngle the beginning angle.
* @param arcAngle the angular extent of the arc, * @param arcAngle the angular extent of the arc,
* relative to the start angle. * relative to the start angle.
* @see java.awt.Graphics#fillArc
* @see Graphics#fillArc
*/ */
public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
Arc2D arc = new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN); Arc2D arc = new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN);
* @param xPoints an array of <i>x</i> points * @param xPoints an array of <i>x</i> points
* @param yPoints an array of <i>y</i> points * @param yPoints an array of <i>y</i> points
* @param nPoints the total number of points * @param nPoints the total number of points
* @see java.awt.Graphics#drawPolygon(int[], int[], int)
* @see Graphics#drawPolygon(int[], int[], int)
* @since JDK1.1 * @since JDK1.1
*/ */
public void drawPolyline(int[] xPoints, int[] yPoints, public void drawPolyline(int[] xPoints, int[] yPoints,
* corner of the oval to be drawn. * corner of the oval to be drawn.
* @param width the width of the oval to be drawn. * @param width the width of the oval to be drawn.
* @param height the height of the oval to be drawn. * @param height the height of the oval to be drawn.
* @see java.awt.Graphics#fillOval
* @see Graphics#fillOval
*/ */
public void drawOval(int x, int y, int width, int height){ public void drawOval(int x, int y, int width, int height){
Ellipse2D oval = new Ellipse2D.Double(x, y, width, height); Ellipse2D oval = new Ellipse2D.Double(x, y, width, height);
* non-opaque portions of the image. * non-opaque portions of the image.
* @param observer object to be notified as more of * @param observer object to be notified as more of
* the image is converted. * the image is converted.
* @see java.awt.Image
* @see java.awt.image.ImageObserver
* @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
* @see Image
* @see ImageObserver
* @see ImageObserver#imageUpdate(Image, int, int, int, int, int)
*/ */
@NotImplemented @NotImplemented
public boolean drawImage(Image img, int x, int y, public boolean drawImage(Image img, int x, int y,
* non-opaque portions of the image. * non-opaque portions of the image.
* @param observer object to be notified as more of * @param observer object to be notified as more of
* the image is converted. * the image is converted.
* @see java.awt.Image
* @see java.awt.image.ImageObserver
* @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
* @see Image
* @see ImageObserver
* @see ImageObserver#imageUpdate(Image, int, int, int, int, int)
*/ */
@NotImplemented @NotImplemented
public boolean drawImage(Image img, int x, int y, public boolean drawImage(Image img, int x, int y,
* source rectangle. * source rectangle.
* @param observer object to be notified as more of the image is * @param observer object to be notified as more of the image is
* scaled and converted. * scaled and converted.
* @see java.awt.Image
* @see java.awt.image.ImageObserver
* @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
* @see Image
* @see ImageObserver
* @see ImageObserver#imageUpdate(Image, int, int, int, int, int)
* @since JDK1.1 * @since JDK1.1
*/ */
@NotImplemented @NotImplemented
* non-opaque portions of the image. * non-opaque portions of the image.
* @param observer object to be notified as more of the image is * @param observer object to be notified as more of the image is
* scaled and converted. * scaled and converted.
* @see java.awt.Image
* @see java.awt.image.ImageObserver
* @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
* @see Image
* @see ImageObserver
* @see ImageObserver#imageUpdate(Image, int, int, int, int, int)
* @since JDK1.1 * @since JDK1.1
*/ */
@NotImplemented @NotImplemented
* the image is converted. * the image is converted.
* @return <code>false</code> if the image pixels are still changing; * @return <code>false</code> if the image pixels are still changing;
* <code>true</code> otherwise. * <code>true</code> otherwise.
* @see java.awt.Image
* @see java.awt.image.ImageObserver
* @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
* @see Image
* @see ImageObserver
* @see ImageObserver#imageUpdate(Image, int, int, int, int, int)
*/ */
@NotImplemented @NotImplemented
public boolean drawImage(Image img, int x, int y, public boolean drawImage(Image img, int x, int y,
* call <code>dispose</code> when finished using * call <code>dispose</code> when finished using
* a <code>Graphics</code> object only if it was created * a <code>Graphics</code> object only if it was created
* directly from a component or another <code>Graphics</code> object. * directly from a component or another <code>Graphics</code> object.
* @see java.awt.Graphics#finalize
* @see java.awt.Component#paint
* @see java.awt.Component#update
* @see java.awt.Component#getGraphics
* @see java.awt.Graphics#create
* @see Graphics#finalize
* @see Component#paint
* @see Component#update
* @see Component#getGraphics
* @see Graphics#create
*/ */
public void dispose() { public void dispose() {
} }
* @param xPoints a an array of <code>x</code> coordinates. * @param xPoints a an array of <code>x</code> coordinates.
* @param yPoints a an array of <code>y</code> coordinates. * @param yPoints a an array of <code>y</code> coordinates.
* @param nPoints a the total number of points. * @param nPoints a the total number of points.
* @see java.awt.Graphics#drawPolygon(int[], int[], int)
* @see Graphics#drawPolygon(int[], int[], int)
*/ */
public void fillPolygon(int[] xPoints, int[] yPoints, public void fillPolygon(int[] xPoints, int[] yPoints,
int nPoints){ int nPoints){
java.awt.Polygon polygon = new java.awt.Polygon(xPoints, yPoints, nPoints);
Polygon polygon = new Polygon(xPoints, yPoints, nPoints);
fill(polygon); fill(polygon);
} }


* of the rectangle to be filled. * of the rectangle to be filled.
* @param width the width of the rectangle to be filled. * @param width the width of the rectangle to be filled.
* @param height the height of the rectangle to be filled. * @param height the height of the rectangle to be filled.
* @see java.awt.Graphics#clearRect
* @see java.awt.Graphics#drawRect
* @see Graphics#clearRect
* @see Graphics#drawRect
*/ */
public void fillRect(int x, int y, int width, int height){ public void fillRect(int x, int y, int width, int height){
Rectangle rect = new Rectangle(x, y, width, height); Rectangle rect = new Rectangle(x, y, width, height);
* of the rectangle to be drawn. * of the rectangle to be drawn.
* @param width the width of the rectangle to be drawn. * @param width the width of the rectangle to be drawn.
* @param height the height of the rectangle to be drawn. * @param height the height of the rectangle to be drawn.
* @see java.awt.Graphics#fillRect
* @see java.awt.Graphics#clearRect
* @see Graphics#fillRect
* @see Graphics#clearRect
*/ */
public void drawRect(int x, int y, int width, int height) { public void drawRect(int x, int y, int width, int height) {
Rectangle rect = new Rectangle(x, y, width, height); Rectangle rect = new Rectangle(x, y, width, height);
* @param xPoints a an array of <code>x</code> coordinates. * @param xPoints a an array of <code>x</code> coordinates.
* @param yPoints a an array of <code>y</code> coordinates. * @param yPoints a an array of <code>y</code> coordinates.
* @param nPoints a the total number of points. * @param nPoints a the total number of points.
* @see java.awt.Graphics#fillPolygon(int[],int[],int)
* @see java.awt.Graphics#drawPolyline
* @see Graphics#fillPolygon(int[],int[],int)
* @see Graphics#drawPolyline
*/ */
public void drawPolygon(int[] xPoints, int[] yPoints, public void drawPolygon(int[] xPoints, int[] yPoints,
int nPoints){ int nPoints){
java.awt.Polygon polygon = new java.awt.Polygon(xPoints, yPoints, nPoints);
Polygon polygon = new Polygon(xPoints, yPoints, nPoints);
draw(polygon); draw(polygon);
} }


* user clip, which is independent of the clipping associated * user clip, which is independent of the clipping associated
* with device bounds and window visibility. * with device bounds and window visibility.
* @param clip the <code>Shape</code> to use to set the clip * @param clip the <code>Shape</code> to use to set the clip
* @see java.awt.Graphics#getClip()
* @see java.awt.Graphics#clipRect
* @see java.awt.Graphics#setClip(int, int, int, int)
* @see Graphics#getClip()
* @see Graphics#clipRect
* @see Graphics#setClip(int, int, int, int)
* @since JDK1.1 * @since JDK1.1
*/ */
@NotImplemented @NotImplemented
* system origin of this graphics context. * system origin of this graphics context.
* @return the bounding rectangle of the current clipping area, * @return the bounding rectangle of the current clipping area,
* or <code>null</code> if no clip is set. * or <code>null</code> if no clip is set.
* @see java.awt.Graphics#getClip
* @see java.awt.Graphics#clipRect
* @see java.awt.Graphics#setClip(int, int, int, int)
* @see java.awt.Graphics#setClip(Shape)
* @see Graphics#getClip
* @see Graphics#clipRect
* @see Graphics#setClip(int, int, int, int)
* @see Graphics#setClip(Shape)
* @since JDK1.1 * @since JDK1.1
*/ */
public Rectangle getClipBounds(){ public Rectangle getClipBounds(){
* @param iterator the iterator whose text is to be drawn * @param iterator the iterator whose text is to be drawn
* @param x the <i>x</i> coordinate. * @param x the <i>x</i> coordinate.
* @param y the <i>y</i> coordinate. * @param y the <i>y</i> coordinate.
* @see java.awt.Graphics#drawBytes
* @see java.awt.Graphics#drawChars
* @see Graphics#drawBytes
* @see Graphics#drawChars
*/ */
public void drawString(AttributedCharacterIterator iterator, public void drawString(AttributedCharacterIterator iterator,
int x, int y){ int x, int y){
* @param y the <i>y</i> coordinate of the rectangle to clear. * @param y the <i>y</i> coordinate of the rectangle to clear.
* @param width the width of the rectangle to clear. * @param width the width of the rectangle to clear.
* @param height the height of the rectangle to clear. * @param height the height of the rectangle to clear.
* @see java.awt.Graphics#fillRect(int, int, int, int)
* @see java.awt.Graphics#drawRect
* @see java.awt.Graphics#setColor(java.awt.Color)
* @see java.awt.Graphics#setPaintMode
* @see java.awt.Graphics#setXORMode(java.awt.Color)
* @see Graphics#fillRect(int, int, int, int)
* @see Graphics#drawRect
* @see Graphics#setColor(Color)
* @see Graphics#setPaintMode
* @see Graphics#setXORMode(Color)
*/ */
public void clearRect(int x, int y, int width, int height) { public void clearRect(int x, int y, int width, int height) {
Paint paint = getPaint(); Paint paint = getPaint();
* @param y the <i>y</i> coordinate of the new clip rectangle. * @param y the <i>y</i> coordinate of the new clip rectangle.
* @param width the width of the new clip rectangle. * @param width the width of the new clip rectangle.
* @param height the height of the new clip rectangle. * @param height the height of the new clip rectangle.
* @see java.awt.Graphics#clipRect
* @see java.awt.Graphics#setClip(Shape)
* @see Graphics#clipRect
* @see Graphics#setClip(Shape)
* @since JDK1.1 * @since JDK1.1
*/ */
public void setClip(int x, int y, int width, int height){ public void setClip(int x, int y, int width, int height){
* the text rendering. * the text rendering.
* *
* @return a reference to an instance of FontRenderContext. * @return a reference to an instance of FontRenderContext.
* @see java.awt.font.FontRenderContext
* @see java.awt.Font#createGlyphVector(FontRenderContext,char[])
* @see java.awt.font.TextLayout
* @see FontRenderContext
* @see Font#createGlyphVector(FontRenderContext,char[])
* @see TextLayout
* @since JDK1.2 * @since JDK1.2
*/ */
public FontRenderContext getFontRenderContext() { public FontRenderContext getFontRenderContext() {
* @param color the background color that isused in * @param color the background color that isused in
* subsequent calls to <code>clearRect</code> * subsequent calls to <code>clearRect</code>
* @see #getBackground * @see #getBackground
* @see java.awt.Graphics#clearRect
* @see Graphics#clearRect
*/ */
public void setBackground(Color color) { public void setBackground(Color color) {
if(color == null) if(color == null)
* used to render to the screen and a security manager * used to render to the screen and a security manager
* is set and its <code>checkPermission</code> method * is set and its <code>checkPermission</code> method
* does not allow the operation. * does not allow the operation.
* @see java.awt.Graphics#setXORMode
* @see java.awt.Graphics#setPaintMode
* @see java.awt.AlphaComposite
* @see Graphics#setXORMode
* @see Graphics#setPaintMode
* @see AlphaComposite
*/ */
@NotImplemented @NotImplemented
public void setComposite(Composite comp){ public void setComposite(Composite comp){
* @param y the y position in user space where the glyphs should be * @param y the y position in user space where the glyphs should be
* rendered * rendered
* *
* @see java.awt.Font#createGlyphVector(FontRenderContext, char[])
* @see java.awt.font.GlyphVector
* @see Font#createGlyphVector(FontRenderContext, char[])
* @see GlyphVector
* @see #setPaint * @see #setPaint
* @see java.awt.Graphics#setColor
* @see Graphics#setColor
* @see #setTransform * @see #setTransform
* @see #setComposite * @see #setComposite
* @see #setClip(Shape) * @see #setClip(Shape)
* @param y the y coordinate where the iterator's text is to be * @param y the y coordinate where the iterator's text is to be
* rendered * rendered
* @see #setPaint * @see #setPaint
* @see java.awt.Graphics#setColor
* @see Graphics#setColor
* @see #setTransform * @see #setTransform
* @see #setComposite * @see #setComposite
* @see #setClip * @see #setClip
* the image is converted. * the image is converted.
* @return <code>false</code> if the image pixels are still changing; * @return <code>false</code> if the image pixels are still changing;
* <code>true</code> otherwise. * <code>true</code> otherwise.
* @see java.awt.Image
* @see java.awt.image.ImageObserver
* @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
* @see Image
* @see ImageObserver
* @see ImageObserver#imageUpdate(Image, int, int, int, int, int)
*/ */
@NotImplemented @NotImplemented
public boolean drawImage(Image img, int x, int y, public boolean drawImage(Image img, int x, int y,
* Gets the font metrics for the specified font. * Gets the font metrics for the specified font.
* @return the font metrics for the specified font. * @return the font metrics for the specified font.
* @param f the specified font * @param f the specified font
* @see java.awt.Graphics#getFont
* @see java.awt.FontMetrics
* @see java.awt.Graphics#getFontMetrics()
* @see Graphics#getFont
* @see FontMetrics
* @see Graphics#getFontMetrics()
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@SuppressForbidden @SuppressForbidden
} }


private void logNotImplemented() { private void logNotImplemented() {
if (LOG.check(POILogger.WARN)) {
LOG.log(POILogger.WARN, "Not implemented");
}
LOG.atWarn().log("Not implemented");
} }
} }

+ 4
- 4
src/java/org/apache/poi/sl/draw/geom/PresetGeometries.java View File

import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource; import javax.xml.transform.stream.StreamSource;


import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.XMLHelper; import org.apache.poi.util.XMLHelper;


public final class PresetGeometries { public final class PresetGeometries {
private static final POILogger LOG = POILogFactory.getLogger(PresetGeometries.class);
private static final Logger LOG = LogManager.getLogger(PresetGeometries.class);


private final Map<String, CustomGeometry> map = new TreeMap<>(); private final Map<String, CustomGeometry> map = new TreeMap<>();


p.parse(staxReader); p.parse(staxReader);
return p.getGeom().values().stream().findFirst().orElse(null); return p.getGeom().values().stream().findFirst().orElse(null);
} catch (XMLStreamException e) { } catch (XMLStreamException e) {
LOG.log(POILogger.ERROR, "Unable to parse single custom geometry", e);
LOG.atError().withThrowable(e).log("Unable to parse single custom geometry");
return null; return null;
} }
} }

+ 4
- 4
src/java/org/apache/poi/sl/draw/geom/PresetParser.java View File

import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamReader;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.sl.usermodel.PaintStyle.PaintModifier; import org.apache.poi.sl.usermodel.PaintStyle.PaintModifier;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


@Internal @Internal
class PresetParser { class PresetParser {
} }
} }


private static final POILogger LOG = POILogFactory.getLogger(PresetParser.class);
private static final Logger LOG = LogManager.getLogger(PresetParser.class);


private Mode mode; private Mode mode;


final String name = sr.getLocalName(); final String name = sr.getLocalName();
customGeometry = new CustomGeometry(); customGeometry = new CustomGeometry();
if (geom.containsKey(name)) { if (geom.containsKey(name)) {
LOG.log(POILogger.WARN, "Duplicate definition of " + name);
LOG.atWarn().log("Duplicate definition of {}", name);
} }
geom.put(name, customGeometry); geom.put(name, customGeometry);
mode = Mode.SHAPE; mode = Mode.SHAPE;

+ 4
- 4
src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java View File

import java.util.function.Predicate; import java.util.function.Predicate;


import com.zaxxer.sparsebits.SparseBitSet; import com.zaxxer.sparsebits.SparseBitSet;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.extractor.POITextExtractor; import org.apache.poi.extractor.POITextExtractor;
import org.apache.poi.sl.usermodel.MasterSheet; import org.apache.poi.sl.usermodel.MasterSheet;
import org.apache.poi.sl.usermodel.Notes; import org.apache.poi.sl.usermodel.Notes;
import org.apache.poi.sl.usermodel.TextRun; import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.sl.usermodel.TextShape; import org.apache.poi.sl.usermodel.TextShape;
import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Common SlideShow extractor * Common SlideShow extractor
S extends Shape<S,P>, S extends Shape<S,P>,
P extends TextParagraph<S,P,? extends TextRun> P extends TextParagraph<S,P,? extends TextRun>
> implements POITextExtractor { > implements POITextExtractor {
private static final POILogger LOG = POILogFactory.getLogger(SlideShowExtractor.class);
private static final Logger LOG = LogManager.getLogger(SlideShowExtractor.class);


// placeholder text for slide numbers // placeholder text for slide numbers
private static final String SLIDE_NUMBER_PH = "‹#›"; private static final String SLIDE_NUMBER_PH = "‹#›";


if (ts.isPlaceholder()) { if (ts.isPlaceholder()) {
// don't bother about boiler plate text on master sheets // don't bother about boiler plate text on master sheets
LOG.log(POILogger.INFO, "Ignoring boiler plate (placeholder) text on slide master:", text);
LOG.atInfo().log("Ignoring boiler plate (placeholder) text on slide master: {}", text);
continue; continue;
} }



+ 5
- 5
src/java/org/apache/poi/sl/image/ImageHeaderBitmap.java View File



import javax.imageio.ImageIO; import javax.imageio.ImageIO;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Units; import org.apache.poi.util.Units;


@Internal @Internal
public class ImageHeaderBitmap { public class ImageHeaderBitmap {
private static final POILogger LOG = POILogFactory.getLogger(ImageHeaderBitmap.class);
private static final Logger LOG = LogManager.getLogger(ImageHeaderBitmap.class);
private final Dimension size; private final Dimension size;
public ImageHeaderBitmap(byte[] data, int offset) { public ImageHeaderBitmap(byte[] data, int offset) {
try { try {
img = ImageIO.read(new ByteArrayInputStream(data, offset, data.length-offset)); img = ImageIO.read(new ByteArrayInputStream(data, offset, data.length-offset));
} catch (IOException e) { } catch (IOException e) {
LOG.log(POILogger.WARN, "Can't determine image dimensions", e);
LOG.atWarn().withThrowable(e).log("Can't determine image dimensions");
} }
// set dummy size, in case of dummy dimension can't be set // set dummy size, in case of dummy dimension can't be set
size = (img == null) size = (img == null)

+ 5
- 5
src/java/org/apache/poi/sl/image/ImageHeaderEMF.java View File

import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Rectangle; import java.awt.Rectangle;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


@Internal @Internal
public class ImageHeaderEMF { public class ImageHeaderEMF {
private static final POILogger LOG = POILogFactory.getLogger(ImageHeaderEMF.class);
private static final Logger LOG = LogManager.getLogger(ImageHeaderEMF.class);


private static final String EMF_SIGNATURE = " EMF"; // 0x464D4520 (LE) private static final String EMF_SIGNATURE = " EMF"; // 0x464D4520 (LE)


int offset = off; int offset = off;
int type = (int)LittleEndian.getUInt(data, offset); offset += 4; int type = (int)LittleEndian.getUInt(data, offset); offset += 4;
if (type != 1) { if (type != 1) {
LOG.log(POILogger.WARN, "Invalid EMF picture - invalid type");
LOG.atWarn().log("Invalid EMF picture - invalid type");
deviceBounds = new Rectangle(0,0,200,200); deviceBounds = new Rectangle(0,0,200,200);
return; return;
} }
offset += 16; offset += 16;
String signature = new String(data, offset, EMF_SIGNATURE.length(), LocaleUtil.CHARSET_1252); String signature = new String(data, offset, EMF_SIGNATURE.length(), LocaleUtil.CHARSET_1252);
if (!EMF_SIGNATURE.equals(signature)) { if (!EMF_SIGNATURE.equals(signature)) {
LOG.log(POILogger.WARN, "Invalid EMF picture - invalid signature");
LOG.atWarn().log("Invalid EMF picture - invalid signature");
} }
} }



+ 5
- 5
src/java/org/apache/poi/sl/image/ImageHeaderWMF.java View File

import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Units; import org.apache.poi.util.Units;


/** /**
public class ImageHeaderWMF { public class ImageHeaderWMF {


public static final int APMHEADER_KEY = 0x9AC6CDD7; public static final int APMHEADER_KEY = 0x9AC6CDD7;
private static final POILogger LOG = POILogFactory.getLogger(ImageHeaderWMF.class);
private static final Logger LOG = LogManager.getLogger(ImageHeaderWMF.class);


@SuppressWarnings("unused") @SuppressWarnings("unused")
private final int handle; private final int handle;
int offset = off; int offset = off;
int key = LittleEndian.getInt(data, offset); offset += LittleEndianConsts.INT_SIZE; //header key int key = LittleEndian.getInt(data, offset); offset += LittleEndianConsts.INT_SIZE; //header key
if (key != APMHEADER_KEY) { if (key != APMHEADER_KEY) {
LOG.log(POILogger.WARN, "WMF file doesn't contain a placeable header - ignore parsing");
LOG.atWarn().log("WMF file doesn't contain a placeable header - ignore parsing");
handle = 0; handle = 0;
left = 0; left = 0;
top = 0; top = 0;


checksum = LittleEndian.getShort(data, offset); offset += LittleEndianConsts.SHORT_SIZE; checksum = LittleEndian.getShort(data, offset); offset += LittleEndianConsts.SHORT_SIZE;
if (checksum != getChecksum()){ if (checksum != getChecksum()){
LOG.log(POILogger.WARN, "WMF checksum does not match the header data");
LOG.atWarn().log("WMF checksum does not match the header data");
} }
} }



+ 4
- 4
src/java/org/apache/poi/sl/usermodel/ObjectData.java View File

import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.poifs.filesystem.DirectoryEntry; import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.FileMagic; import org.apache.poi.poifs.filesystem.FileMagic;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Common interface for OLE shapes, i.e. shapes linked to embedded documents * Common interface for OLE shapes, i.e. shapes linked to embedded documents
FileMagic fm = FileMagic.valueOf(is); FileMagic fm = FileMagic.valueOf(is);
return fm == FileMagic.OLE2; return fm == FileMagic.OLE2;
} catch (IOException e) { } catch (IOException e) {
POILogger LOG = POILogFactory.getLogger(ObjectData.class);
LOG.log(POILogger.WARN, "Can't determine filemagic of ole stream", e);
Logger LOG = LogManager.getLogger(ObjectData.class);
LOG.atWarn().withThrowable(e).log("Can't determine filemagic of ole stream");
return false; return false;
} }
} }

+ 4
- 4
src/java/org/apache/poi/ss/extractor/EmbeddedExtractor.java View File

import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hpsf.ClassID; import org.apache.poi.hpsf.ClassID;
import org.apache.poi.hpsf.ClassIDPredefined; import org.apache.poi.hpsf.ClassIDPredefined;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* This extractor class tries to identify various embedded documents within Excel files * This extractor class tries to identify various embedded documents within Excel files
*/ */
@Beta @Beta
public class EmbeddedExtractor implements Iterable<EmbeddedExtractor> { public class EmbeddedExtractor implements Iterable<EmbeddedExtractor> {
private static final POILogger LOG = POILogFactory.getLogger(EmbeddedExtractor.class);
private static final Logger LOG = LogManager.getLogger(EmbeddedExtractor.class);
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 1_000_000; private static final int MAX_RECORD_LENGTH = 1_000_000;


data = new EmbeddedData(od.getFileName(), od.getObjectData(), od.getContentType()); data = new EmbeddedData(od.getFileName(), od.getObjectData(), od.getContentType());
} }
} catch (Exception e) { } catch (Exception e) {
LOG.log(POILogger.WARN, "Entry not found / readable - ignoring OLE embedding", e);
LOG.atWarn().withThrowable(e).log("Entry not found / readable - ignoring OLE embedding");
} }
} else if (shape instanceof Picture) { } else if (shape instanceof Picture) {
data = extractOne((Picture)shape); data = extractOne((Picture)shape);

+ 5
- 5
src/java/org/apache/poi/ss/format/CellNumberFormatter.java View File

import java.util.TreeSet; import java.util.TreeSet;


import com.zaxxer.sparsebits.SparseBitSet; import com.zaxxer.sparsebits.SparseBitSet;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* This class implements printing out a value using a number format. * This class implements printing out a value using a number format.
*/ */
public class CellNumberFormatter extends CellFormatter { public class CellNumberFormatter extends CellFormatter {
private static final POILogger LOG = POILogFactory.getLogger(CellNumberFormatter.class);
private static final Logger LOG = LogManager.getLogger(CellNumberFormatter.class);


private final String desc; private final String desc;
private final String printfFmt; private final String printfFmt;
} }
writeSingleInteger(numeratorFmt, n, output, numeratorSpecials, mods); writeSingleInteger(numeratorFmt, n, output, numeratorSpecials, mods);
writeSingleInteger(denominatorFmt, d, output, denominatorSpecials, mods); writeSingleInteger(denominatorFmt, d, output, denominatorSpecials, mods);
} catch (RuntimeException ignored) {
LOG.log(POILogger.ERROR, "error while fraction evaluation", ignored);
} catch (RuntimeException e) {
LOG.atError().withThrowable(e).log("error while fraction evaluation");
} }
} }



+ 13
- 13
src/java/org/apache/poi/ss/formula/FormulaParser.java View File

import java.util.Locale; import java.util.Locale;
import java.util.regex.Pattern; import java.util.regex.Pattern;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.formula.constant.ErrorConstant; import org.apache.poi.ss.formula.constant.ErrorConstant;
import org.apache.poi.ss.formula.function.FunctionMetadata; import org.apache.poi.ss.formula.function.FunctionMetadata;
import org.apache.poi.ss.usermodel.FormulaError; import org.apache.poi.ss.usermodel.FormulaError;
import org.apache.poi.ss.usermodel.Name; import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.Table; import org.apache.poi.ss.usermodel.Table;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.AreaReference; import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.CellReference.NameType; import org.apache.poi.ss.util.CellReference.NameType;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* This class parses a formula string into a List of tokens in RPN order. * This class parses a formula string into a List of tokens in RPN order.
*/ */
@Internal @Internal
public final class FormulaParser { public final class FormulaParser {
private static final POILogger log = POILogFactory.getLogger(FormulaParser.class);
private static final Logger LOGGER = LogManager.getLogger(FormulaParser.class);
private final String _formulaString; private final String _formulaString;
private final int _formulaLength; private final int _formulaLength;
/** points at the next character to be read (after the {@link #look} codepoint) */ /** points at the next character to be read (after the {@link #look} codepoint) */
* parse results. * parse results.
* This class is recommended only for single threaded use. * This class is recommended only for single threaded use.
* *
* If you have a {@link org.apache.poi.hssf.usermodel.HSSFWorkbook}, and not a
* {@link org.apache.poi.ss.usermodel.Workbook}, then use the convenience method on
* {@link org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator}
* If you have a {@link HSSFWorkbook}, and not a
* {@link Workbook}, then use the convenience method on
* {@link HSSFFormulaEvaluator}
*/ */
private FormulaParser(String formula, FormulaParsingWorkbook book, int sheetIndex, int rowIndex) { private FormulaParser(String formula, FormulaParsingWorkbook book, int sheetIndex, int rowIndex) {
_formulaString = formula; _formulaString = formula;


/** /**
* Parse a formula into an array of tokens * Parse a formula into an array of tokens
* Side effect: creates name ({@link org.apache.poi.ss.usermodel.Workbook#createName})
* Side effect: creates name ({@link Workbook#createName})
* if formula contains unrecognized names (names are likely UDFs) * if formula contains unrecognized names (names are likely UDFs)
* *
* @param formula the formula to parse * @param formula the formula to parse


/** /**
* Parse a formula into an array of tokens * Parse a formula into an array of tokens
* Side effect: creates name ({@link org.apache.poi.ss.usermodel.Workbook#createName})
* Side effect: creates name ({@link Workbook#createName})
* if formula contains unrecognized names (names are likely UDFs) * if formula contains unrecognized names (names are likely UDFs)
* *
* @param formula the formula to parse * @param formula the formula to parse
/** /**
* Matches a zero or one letter-runs followed by zero or one digit-runs. * Matches a zero or one letter-runs followed by zero or one digit-runs.
* Either or both runs man optionally be prefixed with a single '$'. * Either or both runs man optionally be prefixed with a single '$'.
* (copied+modified from {@link org.apache.poi.ss.util.CellReference#CELL_REF_PATTERN})
* (copied+modified from {@link CellReference#CELL_REF_PATTERN})
*/ */
private static final Pattern CELL_REF_PATTERN = Pattern.compile("(\\$?[A-Za-z]+)?(\\$?[0-9]+)?"); private static final Pattern CELL_REF_PATTERN = Pattern.compile("(\\$?[A-Za-z]+)?(\\$?[0-9]+)?");


nameToken = _book.getNameXPtg(name, null); nameToken = _book.getNameXPtg(name, null);
if (nameToken == null) { if (nameToken == null) {
// name is not an internal or external name // name is not an internal or external name
if (log.check(POILogger.WARN)) {
log.log(POILogger.WARN,
"FormulaParser.function: Name '" + name + "' is completely unknown in the current workbook.");
}
LOGGER.atWarn().log("FormulaParser.function: Name '{}' is completely unknown in the current workbook.", name);
// name is probably the name of an unregistered User-Defined Function // name is probably the name of an unregistered User-Defined Function
switch (_book.getSpreadsheetVersion()) { switch (_book.getSpreadsheetVersion()) {
case EXCEL97: case EXCEL97:

+ 27
- 36
src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java View File

import java.util.Stack; import java.util.Stack;
import java.util.TreeSet; import java.util.TreeSet;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException; import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
import org.apache.poi.ss.formula.atp.AnalysisToolPak; import org.apache.poi.ss.formula.atp.AnalysisToolPak;
import org.apache.poi.ss.util.CellRangeAddressBase; import org.apache.poi.ss.util.CellRangeAddressBase;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;

import static org.apache.logging.log4j.util.Unbox.box;

/** /**
* Evaluates formula cells.<p/> * Evaluates formula cells.<p/>
* *
@Internal @Internal
public final class WorkbookEvaluator { public final class WorkbookEvaluator {
private static final POILogger LOG = POILogFactory.getLogger(WorkbookEvaluator.class);
private static final Logger LOG = LogManager.getLogger(WorkbookEvaluator.class);


private final EvaluationWorkbook _workbook; private final EvaluationWorkbook _workbook;
private EvaluationCache _cache; private EvaluationCache _cache;
private boolean dbgEvaluationOutputForNextEval; private boolean dbgEvaluationOutputForNextEval;


// special logger for formula evaluation output (because of possibly very large output) // special logger for formula evaluation output (because of possibly very large output)
private final POILogger EVAL_LOG = POILogFactory.getLogger("POI.FormulaEval");
private final Logger EVAL_LOG = LogManager.getLogger("POI.FormulaEval");
// current indent level for evalution; negative value for no output // current indent level for evalution; negative value for no output
private int dbgEvaluationOutputIndent = -1; private int dbgEvaluationOutputIndent = -1;


return _workbook.getName(name, sheetIndex); return _workbook.getName(name, sheetIndex);
} }


private static boolean isDebugLogEnabled() {
return LOG.check(POILogger.DEBUG);
}
private static boolean isInfoLogEnabled() {
return LOG.check(POILogger.INFO);
}
private static void logDebug(String s) {
if (isDebugLogEnabled()) {
LOG.log(POILogger.DEBUG, s);
}
}
private static void logInfo(String s) {
if (isInfoLogEnabled()) {
LOG.log(POILogger.INFO, s);
}
}
/* package */ void attachToEnvironment(CollaboratingWorkbooksEnvironment collaboratingWorkbooksEnvironment, EvaluationCache cache, int workbookIx) { /* package */ void attachToEnvironment(CollaboratingWorkbooksEnvironment collaboratingWorkbooksEnvironment, EvaluationCache cache, int workbookIx) {
_collaboratingWorkbookEnvironment = collaboratingWorkbooksEnvironment; _collaboratingWorkbookEnvironment = collaboratingWorkbooksEnvironment;
_cache = cache; _cache = cache;
throw addExceptionInfo(e, sheetIndex, rowIndex, columnIndex); throw addExceptionInfo(e, sheetIndex, rowIndex, columnIndex);
} catch (RuntimeException re) { } catch (RuntimeException re) {
if (re.getCause() instanceof WorkbookNotFoundException && _ignoreMissingWorkbooks) { if (re.getCause() instanceof WorkbookNotFoundException && _ignoreMissingWorkbooks) {
logInfo(re.getCause().getMessage() + " - Continuing with cached value!");
LOG.atInfo().log("{} - Continuing with cached value!", re.getCause().getMessage());
switch(srcCell.getCachedFormulaResultType()) { switch(srcCell.getCachedFormulaResultType()) {
case NUMERIC: case NUMERIC:
result = new NumberEval(srcCell.getNumericCellValue()); result = new NumberEval(srcCell.getNumericCellValue());
} }
return cce.getValue(); return cce.getValue();
} }
if (isDebugLogEnabled()) {
final ValueEval resultForLogging = result;
LOG.atDebug().log(()->{
String sheetName = getSheetName(sheetIndex); String sheetName = getSheetName(sheetIndex);
CellReference cr = new CellReference(rowIndex, columnIndex); CellReference cr = new CellReference(rowIndex, columnIndex);
logDebug("Evaluated " + sheetName + "!" + cr.formatAsString() + " to " + result);
}
return new SimpleMessage("Evaluated " + sheetName + "!" + cr.formatAsString() + " to " + resultForLogging);
});
// Usually (result === cce.getValue()) // Usually (result === cce.getValue())
// But sometimes: (result==ErrorEval.CIRCULAR_REF_ERROR, cce.getValue()==null) // But sometimes: (result==ErrorEval.CIRCULAR_REF_ERROR, cce.getValue()==null)
// When circular references are detected, the cache entry is only updated for // When circular references are detected, the cache entry is only updated for
return new NotImplementedException(msg, inner); return new NotImplementedException(msg, inner);
} catch (Exception e) { } catch (Exception e) {
// avoid bombing out during exception handling // avoid bombing out during exception handling
LOG.log(POILogger.ERROR, "Can't add exception info", e);
LOG.atError().withThrowable(e).log("Can't add exception info");
return inner; // preserve original exception return inner; // preserve original exception
} }
} }
dbgEvaluationOutputForNextEval = false; dbgEvaluationOutputForNextEval = false;
} }
if (dbgEvaluationOutputIndent > 0) { if (dbgEvaluationOutputIndent > 0) {
// init. indent string to needed spaces (create as substring vom very long space-only string;
// limit indendation for deep recursions)
// init. indent string to needed spaces (create as substring from very long space-only string;
// limit indentation for deep recursions)
dbgIndentStr = " "; dbgIndentStr = " ";
dbgIndentStr = dbgIndentStr.substring(0, Math.min(dbgIndentStr.length(), dbgEvaluationOutputIndent*2)); dbgIndentStr = dbgIndentStr.substring(0, Math.min(dbgIndentStr.length(), dbgEvaluationOutputIndent*2));
EVAL_LOG.log(POILogger.WARN, dbgIndentStr
+ "- evaluateFormula('" + ec.getRefEvaluatorForCurrentSheet().getSheetNameRange()
+ "'/" + new CellReference(ec.getRowIndex(), ec.getColumnIndex()).formatAsString()
+ "): " + Arrays.toString(ptgs).replaceAll("\\Qorg.apache.poi.ss.formula.ptg.\\E", ""));
String finalDbgIndentStr = dbgIndentStr;
EVAL_LOG.atWarn().log(() -> {
String message = finalDbgIndentStr
+ "- evaluateFormula('" + ec.getRefEvaluatorForCurrentSheet().getSheetNameRange()
+ "'/" + new CellReference(ec.getRowIndex(), ec.getColumnIndex()).formatAsString()
+ "): " + Arrays.toString(ptgs).replaceAll("\\Qorg.apache.poi.ss.formula.ptg.\\E", "");
return new SimpleMessage(message);
});
dbgEvaluationOutputIndent++; dbgEvaluationOutputIndent++;
} }


// since we don't know how to handle these yet :( // since we don't know how to handle these yet :(
Ptg ptg = ptgs[i]; Ptg ptg = ptgs[i];
if (dbgEvaluationOutputIndent > 0) { if (dbgEvaluationOutputIndent > 0) {
EVAL_LOG.log(POILogger.INFO, dbgIndentStr, " * ptg ", i, ": ", ptg, ", stack: ", stack);
EVAL_LOG.atInfo().log("{} * ptg {}: {}, stack: {}", dbgIndentStr, box(i),ptg, stack);
} }
if (ptg instanceof AttrPtg) { if (ptg instanceof AttrPtg) {
AttrPtg attrPtg = (AttrPtg) ptg; AttrPtg attrPtg = (AttrPtg) ptg;
// logDebug("push " + opResult); // logDebug("push " + opResult);
stack.push(opResult); stack.push(opResult);
if (dbgEvaluationOutputIndent > 0) { if (dbgEvaluationOutputIndent > 0) {
EVAL_LOG.log(POILogger.INFO, dbgIndentStr, " = ", opResult);
EVAL_LOG.atInfo().log("{} = {}", dbgIndentStr, opResult);
} }
} }


} }


if (dbgEvaluationOutputIndent > 0) { if (dbgEvaluationOutputIndent > 0) {
EVAL_LOG.log(POILogger.INFO, dbgIndentStr, "finished eval of ",
new CellReference(ec.getRowIndex(), ec.getColumnIndex()).formatAsString(),
": ", result);
EVAL_LOG.atInfo().log("{}finished eval of {}: {}", dbgIndentStr, new CellReference(ec.getRowIndex(), ec.getColumnIndex()).formatAsString(), result);
dbgEvaluationOutputIndent--; dbgEvaluationOutputIndent--;
if (dbgEvaluationOutputIndent == 1) { if (dbgEvaluationOutputIndent == 1) {
// this evaluation is done, reset indent to stop logging // this evaluation is done, reset indent to stop logging

+ 8
- 5
src/java/org/apache/poi/ss/formula/constant/ErrorConstant.java View File



package org.apache.poi.ss.formula.constant; package org.apache.poi.ss.formula.constant;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.usermodel.FormulaError; import org.apache.poi.ss.usermodel.FormulaError;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;

import static org.apache.logging.log4j.util.Unbox.box;

/** /**
* Represents a constant error code value as encoded in a constant values array. <p> * Represents a constant error code value as encoded in a constant values array. <p>
* *
* <tt>ErrorEval</tt>. * <tt>ErrorEval</tt>.
*/ */
public final class ErrorConstant { public final class ErrorConstant {
private static final POILogger LOG = POILogFactory.getLogger(ErrorConstant.class);
private static final ErrorConstant NULL = new ErrorConstant(FormulaError.NULL.getCode());
private static final Logger LOG = LogManager.getLogger(ErrorConstant.class);
private static final ErrorConstant NULL = new ErrorConstant(FormulaError.NULL.getCode());
private static final ErrorConstant DIV_0 = new ErrorConstant(FormulaError.DIV0.getCode()); private static final ErrorConstant DIV_0 = new ErrorConstant(FormulaError.DIV0.getCode());
private static final ErrorConstant VALUE = new ErrorConstant(FormulaError.VALUE.getCode()); private static final ErrorConstant VALUE = new ErrorConstant(FormulaError.VALUE.getCode());
private static final ErrorConstant REF = new ErrorConstant(FormulaError.REF.getCode()); private static final ErrorConstant REF = new ErrorConstant(FormulaError.REF.getCode());
default: break; default: break;
} }
} }
LOG.log( POILogger.WARN, "Warning - unexpected error code (", errorCode, ")");
LOG.atWarn().log("Warning - unexpected error code ({})", box(errorCode));
return new ErrorConstant(errorCode); return new ErrorConstant(errorCode);
} }



+ 5
- 5
src/java/org/apache/poi/ss/formula/functions/Rate.java View File



package org.apache.poi.ss.formula.functions; package org.apache.poi.ss.formula.functions;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.EvaluationException; import org.apache.poi.ss.formula.eval.EvaluationException;
import org.apache.poi.ss.formula.eval.NumberEval; import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.OperandResolver; import org.apache.poi.ss.formula.eval.OperandResolver;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Implements the Excel Rate function * Implements the Excel Rate function
*/ */
public class Rate implements Function { public class Rate implements Function {
private static final POILogger LOG = POILogFactory.getLogger(Rate.class);
private static final Logger LOG = LogManager.getLogger(Rate.class);
public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) { public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
if (args.length < 3) { //First 3 parameters are mandatory if (args.length < 3) { //First 3 parameters are mandatory
return ErrorEval.VALUE_INVALID; return ErrorEval.VALUE_INVALID;


checkValue(rate); checkValue(rate);
} catch (EvaluationException e) { } catch (EvaluationException e) {
LOG.log(POILogger.ERROR, "Can't evaluate rate function", e);
LOG.atError().withThrowable(e).log("Can't evaluate rate function");
return e.getErrorEval(); return e.getErrorEval();
} }



+ 8
- 8
src/java/org/apache/poi/ss/usermodel/DataFormatter.java View File

import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.format.CellFormat; import org.apache.poi.ss.format.CellFormat;
import org.apache.poi.ss.format.CellFormatResult; import org.apache.poi.ss.format.CellFormatResult;
import org.apache.poi.ss.formula.ConditionalFormattingEvaluator; import org.apache.poi.ss.formula.ConditionalFormattingEvaluator;
import org.apache.poi.ss.util.DateFormatConverter; import org.apache.poi.ss.util.DateFormatConverter;
import org.apache.poi.ss.util.NumberToTextConverter; import org.apache.poi.ss.util.NumberToTextConverter;
import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;




/** /**
* codes, etc. * codes, etc.
* <p> * <p>
* Internally, formats will be implemented using subclasses of {@link Format} * Internally, formats will be implemented using subclasses of {@link Format}
* such as {@link DecimalFormat} and {@link java.text.SimpleDateFormat}. Therefore the
* such as {@link DecimalFormat} and {@link SimpleDateFormat}. Therefore the
* formats used by this class must obey the same pattern rules as these Format * formats used by this class must obey the same pattern rules as these Format
* subclasses. This means that only legal number pattern characters ("0", "#", * subclasses. This means that only legal number pattern characters ("0", "#",
* ".", "," etc.) may appear in number formats. Other characters can be * ".", "," etc.) may appear in number formats. Other characters can be
private final PropertyChangeSupport pcs; private final PropertyChangeSupport pcs;


/** For logging any problems we find */ /** For logging any problems we find */
private static final POILogger LOG = POILogFactory.getLogger(DataFormatter.class);
private static final Logger LOG = LogManager.getLogger(DataFormatter.class);


/** /**
* Creates a formatter using the {@link Locale#getDefault() default locale}. * Creates a formatter using the {@link Locale#getDefault() default locale}.
// Wrap and return (non-cacheable - CellFormat does that) // Wrap and return (non-cacheable - CellFormat does that)
return new CellFormatResultWrapper( cfmt.apply(cellValueO) ); return new CellFormatResultWrapper( cfmt.apply(cellValueO) );
} catch (Exception e) { } catch (Exception e) {
LOG.log(POILogger.WARN, "Formatting failed for format " + formatStr + ", falling back", e);
LOG.atWarn().withThrowable(e).log("Formatting failed for format {}, falling back", formatStr);
} }
} }


try { try {
return new ExcelStyleDateFormatter(formatStr, dateSymbols); return new ExcelStyleDateFormatter(formatStr, dateSymbols);
} catch(IllegalArgumentException iae) { } catch(IllegalArgumentException iae) {
LOG.log(POILogger.DEBUG, "Formatting failed for format ", formatStr, ", falling back", iae);
LOG.atDebug().withThrowable(iae).log("Formatting failed for format {}, falling back", formatStr);
// the pattern could not be parsed correctly, // the pattern could not be parsed correctly,
// so fall back to the default number format // so fall back to the default number format
return getDefaultFormat(cellValue); return getDefaultFormat(cellValue);
try { try {
return new InternalDecimalFormatWithScale(format, symbols); return new InternalDecimalFormatWithScale(format, symbols);
} catch(IllegalArgumentException iae) { } catch(IllegalArgumentException iae) {
LOG.log(POILogger.DEBUG, "Formatting failed for format ", formatStr, ", falling back", iae);
LOG.atDebug().withThrowable(iae).log("Formatting failed for format {}, falling back", formatStr);
// the pattern could not be parsed correctly, // the pattern could not be parsed correctly,
// so fall back to the default number format // so fall back to the default number format
return getDefaultFormat(cellValue); return getDefaultFormat(cellValue);
* </p> * </p>
* *
* @param format A Format instance to be used as a default * @param format A Format instance to be used as a default
* @see java.text.Format#format
* @see Format#format
*/ */
public void setDefaultNumberFormat(Format format) { public void setDefaultNumberFormat(Format format) {
for (Map.Entry<String, Format> entry : formats.entrySet()) { for (Map.Entry<String, Format> entry : formats.entrySet()) {

+ 4
- 4
src/java/org/apache/poi/ss/usermodel/FractionFormat.java View File

import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.format.SimpleFraction; import org.apache.poi.ss.format.SimpleFraction;
import org.apache.poi.ss.formula.eval.NotImplementedException; import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* <p>Format class that handles Excel style fractions, such as "# #/#" and "#/###"</p> * <p>Format class that handles Excel style fractions, such as "# #/#" and "#/###"</p>


@SuppressWarnings("serial") @SuppressWarnings("serial")
public class FractionFormat extends Format { public class FractionFormat extends Format {
private static final POILogger LOGGER = POILogFactory.getLogger(FractionFormat.class);
private static final Logger LOGGER = LogManager.getLogger(FractionFormat.class);
private static final Pattern DENOM_FORMAT_PATTERN = Pattern.compile("(?:(#+)|(\\d+))"); private static final Pattern DENOM_FORMAT_PATTERN = Pattern.compile("(?:(#+)|(\\d+))");


//this was chosen to match the earlier limitation of max denom power //this was chosen to match the earlier limitation of max denom power
fract = SimpleFraction.buildFractionMaxDenominator(decPart.doubleValue(), maxDenom); fract = SimpleFraction.buildFractionMaxDenominator(decPart.doubleValue(), maxDenom);
} }
} catch (RuntimeException e){ } catch (RuntimeException e){
LOGGER.log(POILogger.WARN, "Can't format fraction", e);
LOGGER.atWarn().withThrowable(e).log("Can't format fraction");
return Double.toString(doubleValue.doubleValue()); return Double.toString(doubleValue.doubleValue());
} }



+ 11
- 23
src/java/org/apache/poi/ss/util/CellUtil.java View File

import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Various utility functions that make working with a cells and rows easier. The various methods * Various utility functions that make working with a cells and rows easier. The various methods
*/ */
public final class CellUtil { public final class CellUtil {
private static final POILogger log = POILogFactory.getLogger(CellUtil.class);
private static final Logger LOGGER = LogManager.getLogger(CellUtil.class);


// FIXME: Move these constants into an enum // FIXME: Move these constants into an enum
public static final String ALIGNMENT = "alignment"; public static final String ALIGNMENT = "alignment";
* <p>This is necessary because Excel has an upper limit on the number of styles that it supports.</p> * <p>This is necessary because Excel has an upper limit on the number of styles that it supports.</p>
* *
* <p>This function is more efficient than multiple calls to * <p>This function is more efficient than multiple calls to
* {@link #setCellStyleProperty(org.apache.poi.ss.usermodel.Cell, String, Object)}
* {@link #setCellStyleProperty(Cell, String, Object)}
* if adding multiple cell styles.</p> * if adding multiple cell styles.</p>
* *
* <p>For performance reasons, if this is the only cell in a workbook that uses a cell style, * <p>For performance reasons, if this is the only cell in a workbook that uses a cell style,
* same style.</p> * same style.</p>
* *
* <p>If setting more than one cell style property on a cell, use * <p>If setting more than one cell style property on a cell, use
* {@link #setCellStyleProperties(org.apache.poi.ss.usermodel.Cell, Map)},
* {@link #setCellStyleProperties(Cell, Map)},
* which is faster and does not add unnecessary intermediate CellStyles to the workbook.</p> * which is faster and does not add unnecessary intermediate CellStyles to the workbook.</p>
* *
* @param cell The cell that is to be changed. * @param cell The cell that is to be changed.
* *
* @param style cell style * @param style cell style
* @return map of format properties (String -> Object) * @return map of format properties (String -> Object)
* @see #setFormatProperties(org.apache.poi.ss.usermodel.CellStyle, org.apache.poi.ss.usermodel.Workbook, java.util.Map)
* @see #setFormatProperties(CellStyle, Workbook, Map)
*/ */
private static Map<String, Object> getFormatProperties(CellStyle style) { private static Map<String, Object> getFormatProperties(CellStyle style) {
Map<String, Object> properties = new HashMap<>(); Map<String, Object> properties = new HashMap<>();
} else if (FILL_PATTERN.equals(key)) { } else if (FILL_PATTERN.equals(key)) {
dest.put(key, getFillPattern(src, key)); dest.put(key, getFillPattern(src, key));
} else { } else {
log.log(POILogger.INFO, "Ignoring unrecognized CellUtil format properties key: ", key);
LOGGER.atInfo().log("Ignoring unrecognized CellUtil format properties key: {}", key);
} }
} }
} }
} }
// @deprecated 3.15 beta 2. getBorderStyle will only work on BorderStyle enums instead of codes in the future. // @deprecated 3.15 beta 2. getBorderStyle will only work on BorderStyle enums instead of codes in the future.
else if (value instanceof Short) { else if (value instanceof Short) {
if (log.check(POILogger.WARN)) {
log.log(POILogger.WARN, "Deprecation warning: CellUtil properties map uses Short values for "
+ name + ". Should use BorderStyle enums instead.");
}
LOGGER.atWarn().log("Deprecation warning: CellUtil properties map uses Short values for {}. Should use BorderStyle enums instead.", name);
short code = ((Short) value).shortValue(); short code = ((Short) value).shortValue();
border = BorderStyle.valueOf(code); border = BorderStyle.valueOf(code);
} }
} }
// @deprecated 3.15 beta 2. getFillPattern will only work on FillPatternType enums instead of codes in the future. // @deprecated 3.15 beta 2. getFillPattern will only work on FillPatternType enums instead of codes in the future.
else if (value instanceof Short) { else if (value instanceof Short) {
if (log.check(POILogger.WARN)) {
log.log(POILogger.WARN, "Deprecation warning: CellUtil properties map uses Short values for "
+ name + ". Should use FillPatternType enums instead.");
}
LOGGER.atWarn().log("Deprecation warning: CellUtil properties map uses Short values for {}. Should use FillPatternType enums instead.", name);
short code = ((Short) value).shortValue(); short code = ((Short) value).shortValue();
pattern = FillPatternType.forInt(code); pattern = FillPatternType.forInt(code);
} }
} }
// @deprecated 3.15 beta 2. getHorizontalAlignment will only work on HorizontalAlignment enums instead of codes in the future. // @deprecated 3.15 beta 2. getHorizontalAlignment will only work on HorizontalAlignment enums instead of codes in the future.
else if (value instanceof Short) { else if (value instanceof Short) {
if (log.check(POILogger.WARN)) {
log.log(POILogger.WARN, "Deprecation warning: CellUtil properties map used a Short value for "
+ name + ". Should use HorizontalAlignment enums instead.");
}
LOGGER.atWarn().log("Deprecation warning: CellUtil properties map used a Short value for {}. Should use HorizontalAlignment enums instead.", name);
short code = ((Short) value).shortValue(); short code = ((Short) value).shortValue();
align = HorizontalAlignment.forInt(code); align = HorizontalAlignment.forInt(code);
} }
} }
// @deprecated 3.15 beta 2. getVerticalAlignment will only work on VerticalAlignment enums instead of codes in the future. // @deprecated 3.15 beta 2. getVerticalAlignment will only work on VerticalAlignment enums instead of codes in the future.
else if (value instanceof Short) { else if (value instanceof Short) {
if (log.check(POILogger.WARN)) {
log.log(POILogger.WARN, "Deprecation warning: CellUtil properties map used a Short value for "
+ name + ". Should use VerticalAlignment enums instead.");
}
LOGGER.atWarn().log("Deprecation warning: CellUtil properties map used a Short value for {}. Should use VerticalAlignment enums instead.", name);
short code = ((Short) value).shortValue(); short code = ((Short) value).shortValue();
align = VerticalAlignment.forInt(code); align = VerticalAlignment.forInt(code);
} }

+ 4
- 4
src/java/org/apache/poi/ss/util/DateFormatConverter.java View File

import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.util.LocaleID; import org.apache.poi.util.LocaleID;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;


/** /**
* Convert java DateFormat patterns into Excel custom number formats. * Convert java DateFormat patterns into Excel custom number formats.
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class DateFormatConverter { public final class DateFormatConverter {
private static final POILogger LOG = POILogFactory.getLogger(DateFormatConverter.class);
private static final Logger LOG = LogManager.getLogger(DateFormatConverter.class);


private DateFormatConverter() { private DateFormatConverter() {
} }
} }


if (loc == null) { if (loc == null) {
LOG.log(POILogger.ERROR, "Unable to find prefix for Locale '", languageTag, "' or its parent locales.");
LOG.atError().log("Unable to find prefix for Locale '{}' or its parent locales.", languageTag);
return ""; return "";
} }



+ 8
- 8
src/java/org/apache/poi/ss/util/ImageUtils.java View File

import javax.imageio.ImageReader; import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStream;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor; import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.ss.usermodel.ClientAnchor; import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Picture; import org.apache.poi.ss.usermodel.Picture;
import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Units; import org.apache.poi.util.Units;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;


public final class ImageUtils { public final class ImageUtils {
private static final POILogger LOG = POILogFactory.getLogger(ImageUtils.class);
private static final Logger LOG = LogManager.getLogger(ImageUtils.class);


private static final int WIDTH_UNITS = 1024; private static final int WIDTH_UNITS = 1024;
private static final int HEIGHT_UNITS = 256; private static final int HEIGHT_UNITS = 256;
* Return the dimension of this image * Return the dimension of this image
* *
* @param is the stream containing the image data * @param is the stream containing the image data
* @param type type of the picture: {@link org.apache.poi.ss.usermodel.Workbook#PICTURE_TYPE_JPEG},
* {@link org.apache.poi.ss.usermodel.Workbook#PICTURE_TYPE_PNG} or {@link org.apache.poi.ss.usermodel.Workbook#PICTURE_TYPE_DIB}
* @param type type of the picture: {@link Workbook#PICTURE_TYPE_JPEG},
* {@link Workbook#PICTURE_TYPE_PNG} or {@link Workbook#PICTURE_TYPE_DIB}
* *
* @return image dimension in pixels * @return image dimension in pixels
*/ */
r.dispose(); r.dispose();
} }
} else { } else {
LOG.log(POILogger.WARN, "ImageIO found no images");
LOG.atWarn().log("ImageIO found no images");
} }
} }


} catch (IOException e) { } catch (IOException e) {
//silently return if ImageIO failed to read the image //silently return if ImageIO failed to read the image
LOG.log(POILogger.WARN, e);
LOG.atWarn().withThrowable(e).log("Failed to determine image dimensions");
} }


break; break;
default: default:
LOG.log(POILogger.WARN, "Only JPEG, PNG and DIB pictures can be automatically sized");
LOG.atWarn().log("Only JPEG, PNG and DIB pictures can be automatically sized");
} }
return size; return size;
} }

+ 0
- 177
src/java/org/apache/poi/util/CommonsLogger.java View File

/* ====================================================================
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.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* An implementation of the {@link POILogger} using the
* Apache Commons Logging framework. Which itself can be configured to
* send log to various different log frameworks and even allows to create
* a small wrapper for custom log frameworks.
*/
public class CommonsLogger implements POILogger
{
private static final LogFactory _creator = LogFactory.getFactory();
private Log log;

@Override
public void initialize(final String cat) {
this.log = _creator.getInstance(cat);
}

/**
* Log a message
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param obj1 The object to log.
*/
@Override
public void _log(final int level, final Object obj1) {
// FIXME: What happens if level is in between two levels (an even number)?
// Should this be `if (level >= FATAL) ...`?
switch (level) {
case FATAL:
if (log.isFatalEnabled()) {
log.fatal(obj1);
}
break;
case ERROR:
if (log.isErrorEnabled()) {
log.error(obj1);
}
break;
case WARN:
if (log.isWarnEnabled()) {
log.warn(obj1);
}
break;
case INFO:
if (log.isInfoEnabled()) {
log.info(obj1);
}
break;
case DEBUG:
if (log.isDebugEnabled()) {
log.debug(obj1);
}
break;
default:
if (log.isTraceEnabled()) {
log.trace(obj1);
}
break;
}
}

/**
* Log a message
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param obj1 The object to log. This is converted to a string.
* @param exception An exception to be logged
*/
@Override
public void _log(final int level, final Object obj1, final Throwable exception) {
// FIXME: What happens if level is in between two levels (an even number)?
// Should this be `if (level >= FATAL) ...`?
switch (level) {
case FATAL:
if (log.isFatalEnabled()) {
if (obj1 != null) {
log.fatal(obj1, exception);
} else {
log.fatal(exception);
}
}
break;
case ERROR:
if (log.isErrorEnabled()) {
if (obj1 != null) {
log.error(obj1, exception);
} else {
log.error(exception);
}
}
break;
case WARN:
if (log.isWarnEnabled()) {
if (obj1 != null) {
log.warn(obj1, exception);
} else {
log.warn(exception);
}
}
break;
case INFO:
if (log.isInfoEnabled()) {
if (obj1 != null) {
log.info(obj1, exception);
} else {
log.info(exception);
}
}
break;
case DEBUG:
if (log.isDebugEnabled()) {
if (obj1 != null) {
log.debug(obj1, exception);
} else {
log.debug(exception);
}
}
break;
default:
if (log.isTraceEnabled()) {
if (obj1 != null) {
log.trace(obj1, exception);
} else {
log.trace(exception);
}
}
break;
}
}

/**
* Check if a logger is enabled to log at the specified level
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
*/
@Override
public boolean check(final int level)
{
// FIXME: What happens if level is in between two levels (an even number)?
// Should this be `if (level >= FATAL) ...`?
switch (level) {
case FATAL:
return log.isFatalEnabled();
case ERROR:
return log.isErrorEnabled();
case WARN:
return log.isWarnEnabled();
case INFO:
return log.isInfoEnabled();
case DEBUG:
return log.isDebugEnabled();
default:
return false;
}
}
}


+ 5
- 2
src/java/org/apache/poi/util/Configurator.java View File

limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/** /**
* Helper for fetching int values from system properties * Helper for fetching int values from system properties
*/ */
public class Configurator { public class Configurator {
private static final POILogger LOG = POILogFactory.getLogger(Configurator.class);
private static final Logger LOG = LogManager.getLogger(Configurator.class);


public static int getIntValue(String systemProperty, int defaultValue) { public static int getIntValue(String systemProperty, int defaultValue) {
String property = System.getProperty(systemProperty); String property = System.getProperty(systemProperty);
try { try {
return Integer.parseInt(property); return Integer.parseInt(property);
} catch (Exception e) { } catch (Exception e) {
LOG.log(POILogger.ERROR, "System property -D", systemProperty, " does not contains a valid integer: ", property);
LOG.atError().log("System property -D{} does not contains a valid integer: {}", systemProperty, property);
return defaultValue; return defaultValue;
} }
} }

+ 4
- 3
src/java/org/apache/poi/util/IOUtils.java View File

import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.Checksum; import java.util.zip.Checksum;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.EmptyFileException; import org.apache.poi.EmptyFileException;


@Internal @Internal
public final class IOUtils { public final class IOUtils {
private static final POILogger LOG = POILogFactory.getLogger( IOUtils.class );
private static final Logger LOG = LogManager.getLogger(IOUtils.class);


/** /**
* The default buffer size to use for the skip() methods. * The default buffer size to use for the skip() methods.
try { try {
closeable.close(); closeable.close();
} catch ( Exception exc ) { } catch ( Exception exc ) {
LOG.log( POILogger.ERROR, "Unable to close resource: ", exc,
exc );
LOG.atError().withThrowable(exc).log("Unable to close resource");
} }
} }



+ 0
- 81
src/java/org/apache/poi/util/NullLogger.java View File

/* ====================================================================
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.util;

/**
* An empty-implementation of the {@link POILogger}.
*
* This can be used to not log anything, however the suggested approach
* in production systems is to use the {@link CommonsLogger} and configure
* proper log-handling via Apache Commons Logging.
*/
@Internal
public class NullLogger implements POILogger {
@Override
public void initialize(final String cat) {
// do nothing
}

/**
* Log a message
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param obj1 The object to log.
*/

@Override
public void _log(final int level, final Object obj1) {
// do nothing
}

/**
* Log a message
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param obj1 The object to log. This is converted to a string.
* @param exception An exception to be logged
*/
@Override
public void _log(int level, Object obj1, final Throwable exception) {
// do nothing
}

/**
* Log a message. Lazily appends Object parameters together.
* If the last parameter is a {@link Throwable} it is logged specially.
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param objs the objects to place in the message
*/
@Override
public void log(int level, Object... objs) {
// do nothing
}


/**
* Check if a logger is enabled to log at the specified level
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
*/
@Override
public boolean check(final int level) {
return false;
}
}


+ 0
- 122
src/java/org/apache/poi/util/POILogFactory.java View File


/* ====================================================================
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.util;

import java.util.HashMap;
import java.util.Map;

/**
* Provides logging without clients having to mess with
* configuration/initialization.
*
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Marc Johnson (mjohnson at apache dot org)
* @author Nicola Ken Barozzi (nicolaken at apache.org)
*/
@Internal
public final class POILogFactory {
/**
* Map of POILogger instances, with classes as keys
*/
private static final Map<String,POILogger> _loggers = new HashMap<>();

/**
* A common instance of NullLogger, as it does nothing
* we only need the one
*/
private static final POILogger _nullLogger = new NullLogger();
/**
* The name of the class to use. Initialised the
* first time we need it
*/
static String _loggerClassName;

/**
* Construct a POILogFactory.
*/
private POILogFactory() {}

/**
* Get a logger, based on a class name
*
* @param theclass the class whose name defines the log
*
* @return a POILogger for the specified class
*/
public static POILogger getLogger(final Class<?> theclass) {
return getLogger(theclass.getName());
}

/**
* Get a logger, based on a String
*
* @param cat the String that defines the log
*
* @return a POILogger for the specified class
*/
public static POILogger getLogger(final String cat) {
// If we haven't found out what logger to use yet,
// then do so now
// Don't look it up until we're first asked, so
// that our users can set the system property
// between class loading and first use
if(_loggerClassName == null) {
try {
_loggerClassName = System.getProperty("org.apache.poi.util.POILogger");
} catch(Exception e) {
// ignore any exception here
}

// Use the default logger if none specified,
// or none could be fetched
if(_loggerClassName == null) {
_loggerClassName = _nullLogger.getClass().getName();
}
}

// Short circuit for the null logger, which
// ignores all categories
if(_loggerClassName.equals(_nullLogger.getClass().getName())) {
return _nullLogger;
}


// Fetch the right logger for them, creating
// it if that's required
POILogger logger = _loggers.get(cat);
if (logger == null) {
try {
@SuppressWarnings("unchecked")
Class<? extends POILogger> loggerClass =
(Class<? extends POILogger>) Class.forName(_loggerClassName);
logger = loggerClass.getConstructor().newInstance();
logger.initialize(cat);
} catch(Exception e) {
// Give up and use the null logger
logger = _nullLogger;
_loggerClassName = _nullLogger.getClass().getName();
}

// Save for next time
_loggers.put(cat, logger);
}
return logger;
}
}

+ 0
- 128
src/java/org/apache/poi/util/POILogger.java View File

/* ====================================================================
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.util;

/**
* A logger interface that strives to make it as easy as possible for
* developers to write log calls, while simultaneously making those
* calls as cheap as possible by performing lazy evaluation of the log
* message.
*
* A logger can be selected via system properties, e.g.
* <code>
* -Dorg.apache.poi.util.POILogger=org.apache.poi.util.SystemOutLogger
* </code>
*
* The following Logger-implementations are provided:
*
* <ul>
* <li>NullLogger</li>
* <li>CommonsLogger</li>
* <li>SystemOutLogger</li>
* </ul>
*/
@Internal
public interface POILogger {

int DEBUG = 1;
int INFO = 3;
int WARN = 5;
int ERROR = 7;
int FATAL = 9;

/**
* Initialize the Logger - belongs to the SPI, called from the POILogFactory
* @param cat the String that defines the log
*/
void initialize(String cat);

/**
* Log a message - belongs to the SPI, usually not called from user code
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param obj1 The object to log. This is converted to a string.
*/
@Internal
void _log(int level, Object obj1);

/**
* Log a message - belongs to the SPI, usually not called from user code
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param obj1 The object to log. This is converted to a string.
* @param exception An exception to be logged
*/
@Internal
void _log(int level, Object obj1, final Throwable exception);


/**
* Check if a logger is enabled to log at the specified level
* This allows code to avoid building strings or evaluating functions in
* the arguments to log.
*
* An example:
* <code><pre>
* if (logger.check(POILogger.INFO)) {
* logger.log(POILogger.INFO, "Avoid concatenating ", " strings and evaluating ", functions());
* }
* </pre></code>
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
*/
boolean check(int level);

/**
* Log a message. Lazily appends Object parameters together.
* If the last parameter is a {@link Throwable} it is logged specially.
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param objs the objects to place in the message
*/
default void log(int level, Object... objs) {
if (!check(level)) return;
Throwable lastEx = null;
String msg;
if (objs.length == 0) {
msg = "";
} else if (objs.length == 1) {
if (objs[0] instanceof Throwable) {
lastEx = (Throwable)objs[0];
}
msg = objs[0].toString();
} else {
StringBuilder sb = new StringBuilder(32);
for (int i=0; i<objs.length; i++) {
if (i == objs.length-1 && objs[i] instanceof Throwable) {
lastEx = (Throwable)objs[i];
} else {
sb.append(objs[i]);
}
}
msg = sb.toString();
}
// log forging escape
msg = msg.replaceAll("[\r\n]+", " ");

if (lastEx == null) {
_log(level, msg);
} else {
_log(level, msg, lastEx);
}
}
}

+ 0
- 0
src/java/org/apache/poi/util/SLF4JLogger.java View File


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

Loading…
Cancel
Save