]> source.dussan.org Git - poi.git/commitdiff
#64411 - Provide JigSaw modules
authorAndreas Beeker <kiwiwings@apache.org>
Wed, 22 Jul 2020 22:08:33 +0000 (22:08 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Wed, 22 Jul 2020 22:08:33 +0000 (22:08 +0000)
- use classpath-build for Java 8, otherwise use modulepath
- save module-info classes to source, when using Java 9+ environment
- rename example packages - otherwise package clashes occured in the tests
- move agile encryption from ooxml to main.
  remove EncryptionInfo XmlBeans and schema and use custom xml marshalling
- move ooxml test classes which reside in the same package as their tested main class
- rename base test classes to "BaseTest..." - temporarily I've used a light version of the main test classes to test scratchpad / ooxml
- build.xml - fixed the Rhino javascript errors of the dependency-macros
- DrawTextParagraph - fixed StringIndexOutOfBounds when logging set to debug level
- use JigSaw provider interface (= Java ServiceLoader), i.e. it wasn't possible (without openening everything), to access ooxml factory classes from main factory stub

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1880164 13f79535-47bb-0310-9956-ffa450edef68

521 files changed:
build.xml
src/examples/src/org/apache/poi/crypt/examples/OOXMLPasswordsTry.java [deleted file]
src/examples/src/org/apache/poi/examples/crypt/OOXMLPasswordsTry.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hpsf/CopyCompare.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hpsf/ModifyDocumentSummaryInformation.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hpsf/ReadCustomPropertySets.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hpsf/ReadTitle.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hpsf/WriteAuthorAndTitle.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hpsf/WriteTitle.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hslf/ApacheconEU08.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hslf/BulletsDemo.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hslf/CreateHyperlink.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hslf/DataExtraction.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hslf/Graphics2DDemo.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hslf/HeadersFootersDemo.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hslf/Hyperlinks.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hslf/SoundFinder.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hslf/TableDemo.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hsmf/Msg2txt.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/eventusermodel/XLS2CSVmra.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/AddDimensionedImage.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/Alignment.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/BigExample.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/Borders.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/CellComments.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/CellTypes.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/CreateCells.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/CreateDateCells.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/EmbeddedObjects.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/EventExample.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/FrillsAndFills.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/HSSFReadWrite.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/HyperlinkFormula.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/Hyperlinks.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/InCellLists.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/MergedCells.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/NewLinesInCells.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/NewSheet.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/NewWorkbook.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/OfficeDrawing.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/OfficeDrawingWithGraphics.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/Outlines.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/ReadWriteWorkbook.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/RepeatingRowsAndColumns.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/SplitAndFreezePanes.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/WorkingWithFonts.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hssf/usermodel/ZoomSheet.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/hwpf/Word2Forrest.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/AddDimensionedImage.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/AligningCells.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/BusinessPlan.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/CalendarDemo.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/CellStyleDetails.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/ConditionalFormats.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/DrawingBorders.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/ExcelComparator.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/LinkedDropDownLists.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/LoadEmbedded.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/LoanCalculator.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/SSPerformanceTest.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/TimesheetDemo.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/ToCSV.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/formula/CalculateMortgage.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/formula/CheckFunctionsSupported.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/formula/SettingExternalFunction.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/formula/UserDefinedFunctionExample.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/formula/mortgage-calculation.xls [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/html/HSSFHtmlHelper.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/html/HtmlHelper.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/html/ToHtml.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/html/XSSFHtmlHelper.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/html/excelStyle.css [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/ss/html/package-info.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/util/TempFileUtils.java [deleted file]
src/examples/src/org/apache/poi/examples/xslf/AddVideoToPptx.java.txt [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/BarChartDemo.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/ChartFromScratch.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/DataExtraction.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/MergePresentations.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/PPTX2SVG.txt [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/PieChartDemo.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/Tutorial1.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/Tutorial2.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/Tutorial3.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/Tutorial4.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/Tutorial5.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/Tutorial6.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/Tutorial7.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/bar-chart-data.txt [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/bar-chart-template.pptx [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/pie-chart-data.txt [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/pie-chart-template.pptx [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/tutorial/Step1.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xslf/tutorial/Step2.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/eventusermodel/FromHowTo.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/eventusermodel/LoadPasswordProtectedXlsxStreaming.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/eventusermodel/XLSX2CSV.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/streaming/HybridStreaming.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/streaming/Outlining.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/streaming/SavePasswordProtectedXlsx.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/AligningCells.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/BarAndLineChart.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/BarChart.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/BigGridDemo.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/CalendarDemo.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/CellComments.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/CreateCell.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/CreatePivotTable.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/CreatePivotTable2.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/CreateTable.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/CreateUserDefinedDataFormats.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/CustomXMLMapping.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/EmbeddedObjects.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/ExcelChartWithTargetLine.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/FillsAndColors.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/FitSheetToOnePage.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/HeadersAndFooters.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/HyperlinkExample.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/IterateCells.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/LineChart.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/LoadPasswordProtectedXlsx.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/MergingCells.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/NewLinesInCells.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/Outlining.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/ScatterChart.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/SelectedSheet.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/ShiftRows.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/SplitAndFreezePanes.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkbookProperties.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithBorders.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithFonts.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithPageSetup.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithPictures.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithRichText.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xwpf/usermodel/BarChartExample.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xwpf/usermodel/BetterHeaderFooterExample.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xwpf/usermodel/ChartFromScratch.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xwpf/usermodel/HeaderFooterTable.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xwpf/usermodel/SimpleDocument.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xwpf/usermodel/SimpleDocumentWithHeader.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xwpf/usermodel/SimpleImages.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xwpf/usermodel/SimpleTable.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xwpf/usermodel/UpdateEmbeddedDoc.java [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xwpf/usermodel/bar-chart-data.txt [new file with mode: 0644]
src/examples/src/org/apache/poi/examples/xwpf/usermodel/bar-chart-template.docx [new file with mode: 0644]
src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java [deleted file]
src/examples/src/org/apache/poi/hpsf/examples/ModifyDocumentSummaryInformation.java [deleted file]
src/examples/src/org/apache/poi/hpsf/examples/ReadCustomPropertySets.java [deleted file]
src/examples/src/org/apache/poi/hpsf/examples/ReadTitle.java [deleted file]
src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java [deleted file]
src/examples/src/org/apache/poi/hpsf/examples/WriteTitle.java [deleted file]
src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java [deleted file]
src/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java [deleted file]
src/examples/src/org/apache/poi/hslf/examples/CreateHyperlink.java [deleted file]
src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java [deleted file]
src/examples/src/org/apache/poi/hslf/examples/Graphics2DDemo.java [deleted file]
src/examples/src/org/apache/poi/hslf/examples/HeadersFootersDemo.java [deleted file]
src/examples/src/org/apache/poi/hslf/examples/Hyperlinks.java [deleted file]
src/examples/src/org/apache/poi/hslf/examples/SoundFinder.java [deleted file]
src/examples/src/org/apache/poi/hslf/examples/TableDemo.java [deleted file]
src/examples/src/org/apache/poi/hsmf/examples/Msg2txt.java [deleted file]
src/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/AddDimensionedImage.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/Alignment.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/BigExample.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/Borders.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/CellComments.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/CellTypes.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/CreateCells.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/CreateDateCells.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/EmbeddedObjects.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/EventExample.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/FrillsAndFills.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/HSSFReadWrite.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/HyperlinkFormula.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/Hyperlinks.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/InCellLists.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/MergedCells.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/NewLinesInCells.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/NewSheet.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/NewWorkbook.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/OfficeDrawing.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/OfficeDrawingWithGraphics.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/Outlines.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/ReadWriteWorkbook.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/RepeatingRowsAndColumns.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/SplitAndFreezePanes.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/WorkingWithFonts.java [deleted file]
src/examples/src/org/apache/poi/hssf/usermodel/examples/ZoomSheet.java [deleted file]
src/examples/src/org/apache/poi/hwpf/Word2Forrest.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/AddDimensionedImage.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/AligningCells.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/BusinessPlan.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/CalendarDemo.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/CellStyleDetails.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/ConditionalFormats.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/DrawingBorders.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/ExcelComparator.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/LinkedDropDownLists.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/LoadEmbedded.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/LoanCalculator.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/SSPerformanceTest.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/TimesheetDemo.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/ToCSV.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/formula/CalculateMortgage.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/formula/CheckFunctionsSupported.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/formula/SettingExternalFunction.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/formula/UserDefinedFunctionExample.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/formula/mortgage-calculation.xls [deleted file]
src/examples/src/org/apache/poi/ss/examples/html/HSSFHtmlHelper.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/html/HtmlHelper.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/html/ToHtml.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/html/XSSFHtmlHelper.java [deleted file]
src/examples/src/org/apache/poi/ss/examples/html/excelStyle.css [deleted file]
src/examples/src/org/apache/poi/ss/examples/html/package-info.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/AddVideoToPptx.java.txt [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/BarChartDemo.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/ChartFromScratch.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/DataExtraction.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/MergePresentations.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/PPTX2SVG.txt [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/PieChartDemo.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/Tutorial1.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/Tutorial2.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/Tutorial3.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/Tutorial4.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/Tutorial5.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/Tutorial6.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/Tutorial7.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/bar-chart-data.txt [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/bar-chart-template.pptx [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/pie-chart-data.txt [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/pie-chart-template.pptx [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step1.java [deleted file]
src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step2.java [deleted file]
src/examples/src/org/apache/poi/xssf/eventusermodel/XLSX2CSV.java [deleted file]
src/examples/src/org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java [deleted file]
src/examples/src/org/apache/poi/xssf/eventusermodel/examples/LoadPasswordProtectedXlsxStreaming.java [deleted file]
src/examples/src/org/apache/poi/xssf/streaming/examples/DeferredGeneration.java [deleted file]
src/examples/src/org/apache/poi/xssf/streaming/examples/HybridStreaming.java [deleted file]
src/examples/src/org/apache/poi/xssf/streaming/examples/Outlining.java [deleted file]
src/examples/src/org/apache/poi/xssf/streaming/examples/SavePasswordProtectedXlsx.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/AligningCells.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/BarAndLineChart.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/BarChart.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/BigGridDemo.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/CalendarDemo.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/CellComments.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/CreateCell.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/CreatePivotTable.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/CreatePivotTable2.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/CreateTable.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/CreateUserDefinedDataFormats.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/CustomXMLMapping.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/EmbeddedObjects.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/ExcelChartWithTargetLine.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/FillsAndColors.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/FitSheetToOnePage.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/HeadersAndFooters.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/HyperlinkExample.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/IterateCells.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/LineChart.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/LoadPasswordProtectedXlsx.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/MergingCells.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/NewLinesInCells.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/Outlining.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/ScatterChart.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/SelectedSheet.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/ShiftRows.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/SplitAndFreezePanes.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkbookProperties.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithBorders.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithFonts.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithPageSetup.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithPictures.java [deleted file]
src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithRichText.java [deleted file]
src/examples/src/org/apache/poi/xwpf/usermodel/examples/BarChartExample.java [deleted file]
src/examples/src/org/apache/poi/xwpf/usermodel/examples/BetterHeaderFooterExample.java [deleted file]
src/examples/src/org/apache/poi/xwpf/usermodel/examples/ChartFromScratch.java [deleted file]
src/examples/src/org/apache/poi/xwpf/usermodel/examples/HeaderFooterTable.java [deleted file]
src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleDocument.java [deleted file]
src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleDocumentWithHeader.java [deleted file]
src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleImages.java [deleted file]
src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleTable.java [deleted file]
src/examples/src/org/apache/poi/xwpf/usermodel/examples/UpdateEmbeddedDoc.java [deleted file]
src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-data.txt [deleted file]
src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-template.docx [deleted file]
src/excelant/testcases/org/apache/poi/ss/examples/formula/CalculateMortgageFunction.java [deleted file]
src/excelant/testcases/org/apache/poi/ss/examples/formula/ExcelAntUserDefinedFunctionTestHelper.java [deleted file]
src/excelant/testcases/org/apache/poi/ss/examples/formula/TestExcelAntUserDefinedFunction.java [deleted file]
src/excelant/testcases/org/apache/poi/ss/excelant/CalculateMortgageFunction.java [new file with mode: 0644]
src/excelant/testcases/org/apache/poi/ss/excelant/ExcelAntUserDefinedFunctionTestHelper.java [new file with mode: 0644]
src/excelant/testcases/org/apache/poi/ss/excelant/TestExcelAntUserDefinedFunction.java [new file with mode: 0644]
src/excelant/testcases/org/apache/poi/ss/excelant/tests.xml
src/excelant/testcases/org/apache/poi/ss/excelant/util/TestExcelAntWorkbookUtil.java
src/integrationtest/org/apache/poi/BaseIntegrationTest.java [deleted file]
src/integrationtest/org/apache/poi/HeapDump.java [deleted file]
src/integrationtest/org/apache/poi/POIFileScanner.java [deleted file]
src/integrationtest/org/apache/poi/TestAllFiles.java [deleted file]
src/integrationtest/org/apache/poi/hssf/usermodel/RecordsStresser.java [deleted file]
src/integrationtest/org/apache/poi/stress/BaseIntegrationTest.java [new file with mode: 0644]
src/integrationtest/org/apache/poi/stress/HPSFFileHandler.java
src/integrationtest/org/apache/poi/stress/HSSFRecordsStresser.java [new file with mode: 0644]
src/integrationtest/org/apache/poi/stress/HeapDump.java [new file with mode: 0644]
src/integrationtest/org/apache/poi/stress/POIFileScanner.java [new file with mode: 0644]
src/integrationtest/org/apache/poi/stress/TestAllFiles.java [new file with mode: 0644]
src/integrationtest/org/apache/poi/stress/XSSFFileHandler.java
src/java/org/apache/poi/POIDocument.java
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbookFactory.java
src/java/org/apache/poi/poifs/crypt/ChainingMode.java
src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java
src/java/org/apache/poi/poifs/crypt/EncryptionInfo.java
src/java/org/apache/poi/poifs/crypt/EncryptionVerifier.java
src/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionInfoBuilder.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/crypt/agile/CertificateKeyEncryptor.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/crypt/agile/DataIntegrity.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/crypt/agile/EncryptionDocument.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/crypt/agile/KeyData.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/crypt/agile/KeyEncryptor.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/crypt/agile/PasswordKeyEncryptor.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/crypt/binaryrc4/BinaryRC4EncryptionVerifier.java
src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptionVerifier.java
src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionVerifier.java
src/java/org/apache/poi/poifs/crypt/xor/XOREncryptionVerifier.java
src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
src/java/org/apache/poi/ss/usermodel/WorkbookFactory.java
src/java/org/apache/poi/ss/usermodel/WorkbookProvider.java [new file with mode: 0644]
src/java/org/apache/poi/util/DefaultTempFileCreationStrategy.java
src/multimodule/examples/java9/module-info.class [new file with mode: 0644]
src/multimodule/examples/java9/module-info.java [new file with mode: 0644]
src/multimodule/excelant/java9/module-info.class [new file with mode: 0644]
src/multimodule/excelant/java9/module-info.java [new file with mode: 0644]
src/multimodule/excelant/test9/module-info.class [new file with mode: 0644]
src/multimodule/excelant/test9/module-info.java [new file with mode: 0644]
src/multimodule/integration/java9/module-info.java [new file with mode: 0644]
src/multimodule/ooxml-lite-agent/java9/module-info.class [new file with mode: 0644]
src/multimodule/ooxml-lite-agent/java9/module-info.java [new file with mode: 0644]
src/multimodule/ooxml-lite/java9/module-info.class [new file with mode: 0644]
src/multimodule/ooxml-lite/java9/module-info.java [new file with mode: 0644]
src/multimodule/ooxml-schemas/java9/module-info.class
src/multimodule/ooxml-schemas/java9/module-info.java
src/multimodule/ooxml-security/java9/module-info.class [deleted file]
src/multimodule/ooxml-security/java9/module-info.java [deleted file]
src/multimodule/ooxml/java9/module-info.class [new file with mode: 0644]
src/multimodule/ooxml/java9/module-info.java [new file with mode: 0644]
src/multimodule/ooxml/test9/module-info.class [new file with mode: 0644]
src/multimodule/ooxml/test9/module-info.java [new file with mode: 0644]
src/multimodule/poi/java9/module-info.class [new file with mode: 0644]
src/multimodule/poi/java9/module-info.java
src/multimodule/poi/test9/module-info.class [new file with mode: 0644]
src/multimodule/poi/test9/module-info.java [new file with mode: 0644]
src/multimodule/scratchpad/java9/module-info.class [new file with mode: 0644]
src/multimodule/scratchpad/java9/module-info.java [new file with mode: 0644]
src/multimodule/scratchpad/test9/module-info.class [new file with mode: 0644]
src/multimodule/scratchpad/test9/module-info.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java [deleted file]
src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java [deleted file]
src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionInfoBuilder.java [deleted file]
src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java [deleted file]
src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java [deleted file]
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbookFactory.java
src/ooxml/testcases/org/apache/poi/TestDetectAsOOXML.java [deleted file]
src/ooxml/testcases/org/apache/poi/TestEmbedded.java [deleted file]
src/ooxml/testcases/org/apache/poi/TestXMLPropertiesTextExtractor.java [deleted file]
src/ooxml/testcases/org/apache/poi/ooxml/TestDetectAsOOXML.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ooxml/TestEmbedded.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ooxml/TestXMLPropertiesTextExtractor.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ooxml/lite/OOXMLLiteAgent.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ooxml/util/OOXMLLiteAgent.java [deleted file]
src/ooxml/testcases/org/apache/poi/poifs/crypt/AllPOIFSCryptoTests.java [deleted file]
src/ooxml/testcases/org/apache/poi/poifs/crypt/TestAgileEncryptionParameters.java [deleted file]
src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java [deleted file]
src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptionInfo.java [deleted file]
src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptor.java [deleted file]
src/ooxml/testcases/org/apache/poi/poifs/crypt/TestHxxFEncryption.java [deleted file]
src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSecureTempZip.java [deleted file]
src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java [deleted file]
src/ooxml/testcases/org/apache/poi/poifs/crypt/dsig/TestSignatureInfo.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/AllPOIFSCryptoTests.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestAgileEncryptionParameters.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestDecryptor.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestEncryptionInfo.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestEncryptor.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestHxxFEncryption.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestSecureTempZip.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/sl/SLCommonUtils.java [deleted file]
src/ooxml/testcases/org/apache/poi/sl/TestFonts.java [deleted file]
src/ooxml/testcases/org/apache/poi/sl/TestHeadersFooters.java [deleted file]
src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java [deleted file]
src/ooxml/testcases/org/apache/poi/sl/TestSlide.java [deleted file]
src/ooxml/testcases/org/apache/poi/sl/TestTable.java [deleted file]
src/ooxml/testcases/org/apache/poi/sl/draw/TestDrawPictureShape.java [deleted file]
src/ooxml/testcases/org/apache/poi/sl/tests/SLCommonUtils.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/sl/tests/TestFonts.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/sl/tests/TestHeadersFooters.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/sl/tests/TestOleShape.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/sl/tests/TestSlide.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/sl/tests/TestTable.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/sl/tests/draw/TestDrawPictureShape.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/TestWorkbookFactory.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/extractor/TestEmbeddedExtractor.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/format/TestCellFormatPart.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/formula/TestFormulaParser.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/formula/TestStructuredReferences.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/formula/eval/TestXSSFCircularReferences.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/formula/functions/CountifsTests.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/formula/functions/TestProper.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/formula/functions/TestSumifsXSSF.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/formula/functions/TestVlookup.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/tests/TestWorkbookFactory.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/extractor/TestEmbeddedExtractor.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/format/TestCellFormatPart.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/formula/TestFormulaParser.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/formula/TestStructuredReferences.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/formula/eval/TestXSSFCircularReferences.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/formula/functions/CountifsTests.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/formula/functions/TestProper.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/formula/functions/TestSumifsXSSF.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/formula/functions/TestVlookup.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/BaseTestXCell.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/BaseTestXRow.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/BaseTestXSheet.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/BaseTestXWorkbook.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/ConditionalFormattingEvalTest.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/TestEmbedOLEPackage.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/TestXSSFBorderStyle.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/TestXSSFRangeCopier.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/util/TestSXSSFCellUtil.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/util/TestXSSFCellUtil.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/tests/util/TestXSSFPropertyTemplate.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/ss/usermodel/BaseTestXCell.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/usermodel/BaseTestXRow.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/usermodel/BaseTestXSheet.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/usermodel/BaseTestXWorkbook.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/usermodel/ConditionalFormattingEvalTest.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/usermodel/TestEmbedOLEPackage.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/usermodel/TestXSSFBorderStyle.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/usermodel/TestXSSFRangeCopier.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/util/TestSXSSFCellUtil.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/util/TestXSSFCellUtil.java [deleted file]
src/ooxml/testcases/org/apache/poi/ss/util/TestXSSFPropertyTemplate.java [deleted file]
src/ooxml/testcases/org/apache/poi/util/TestIdentifierManager.java [deleted file]
src/ooxml/testcases/org/apache/poi/util/TestTempFileThreaded.java [deleted file]
src/ooxml/testcases/org/apache/poi/util/tests/TestIdentifierManager.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/util/tests/TestTempFileThreaded.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/xslf/geom/TestFormulaParser.java [deleted file]
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlide.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextRun.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTheme.java
src/ooxml/testcases/org/apache/poi/xssf/AllXSSFTests.java
src/ooxml/testcases/org/apache/poi/xssf/streaming/TestDeferredSXSSFWorkbook.java
src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFCell.java
src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFRow.java
src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFSheet.java
src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbook.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/AllXSSFUsermodelTests.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestFormulaEvaluatorOnXSSF.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMatrixFormulasFromXMLSpreadsheet.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMissingWorkbookOnXSSF.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMultiSheetFormulaEvaluatorOnXSSF.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCell.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFForkedEvaluator.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFRow.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java
src/resources/main/META-INF/services/org.apache.poi.ss.usermodel.WorkbookProvider [new file with mode: 0644]
src/resources/ooxml/META-INF/services/org.apache.poi.ss.usermodel.WorkbookProvider [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/TestJDK12.java [deleted file]
src/scratchpad/testcases/org/apache/poi/TestPOIDocumentScratchpad.java [deleted file]
src/scratchpad/testcases/org/apache/poi/hslf/TestPOIDocumentScratchpad.java [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java
src/scratchpad/testcases/org/apache/poi/hslf/record/TestExObjListAtom.java
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTextRun.java
src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestHSSFChart.java [deleted file]
src/testcases/org/apache/poi/TestJDK12.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/dev/BaseTestIteratingXLS.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/dev/BaseXLSIteratingTest.java [deleted file]
src/testcases/org/apache/poi/hssf/dev/TestBiffDrawingToXml.java
src/testcases/org/apache/poi/hssf/dev/TestBiffViewer.java
src/testcases/org/apache/poi/hssf/dev/TestEFBiffViewer.java
src/testcases/org/apache/poi/hssf/dev/TestFormulaViewer.java
src/testcases/org/apache/poi/hssf/dev/TestReSave.java
src/testcases/org/apache/poi/hssf/dev/TestRecordLister.java
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFChart.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFRangeCopier.java
src/testcases/org/apache/poi/sl/TestCommonSL.java [deleted file]
src/testcases/org/apache/poi/sl/draw/geom/TestFormulaParser.java [new file with mode: 0644]
src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShow.java
src/testcases/org/apache/poi/ss/format/TestCellFormat.java
src/testcases/org/apache/poi/ss/formula/AllSSFormulaTests.java
src/testcases/org/apache/poi/ss/formula/BaseTestMissingWorkbook.java [new file with mode: 0644]
src/testcases/org/apache/poi/ss/formula/TestMissingWorkbook.java [deleted file]
src/testcases/org/apache/poi/ss/formula/eval/forked/BaseTestForkedEvaluator.java [new file with mode: 0644]
src/testcases/org/apache/poi/ss/formula/eval/forked/TestForkedEvaluator.java [deleted file]
src/testcases/org/apache/poi/ss/formula/functions/AbstractNumericTestCase.java [deleted file]
src/testcases/org/apache/poi/ss/formula/functions/BaseTestNumeric.java [new file with mode: 0644]
src/testcases/org/apache/poi/ss/formula/functions/TestFinanceLib.java
src/testcases/org/apache/poi/ss/formula/functions/TestMathX.java
src/testcases/org/apache/poi/ss/formula/functions/TestStatsLib.java
src/testcases/org/apache/poi/ss/formula/functions/TestTrunc.java
src/testcases/org/apache/poi/ss/formula/ptg/AbstractPtgTestCase.java [deleted file]
src/testcases/org/apache/poi/ss/formula/ptg/BaseTestPtg.java [new file with mode: 0644]
src/testcases/org/apache/poi/ss/formula/ptg/TestArea3DPtg.java
src/testcases/org/apache/poi/ss/formula/ptg/TestAreaErrPtg.java
src/testcases/org/apache/poi/ss/formula/ptg/TestAttrPtg.java
src/testcases/org/apache/poi/ss/formula/ptg/TestErrPtg.java
src/testcases/org/apache/poi/ss/formula/ptg/TestIntersectionPtg.java
src/testcases/org/apache/poi/ss/formula/ptg/TestPercentPtg.java
src/testcases/org/apache/poi/ss/formula/ptg/TestRangePtg.java
src/testcases/org/apache/poi/ss/formula/ptg/TestRef3DPtg.java
src/testcases/org/apache/poi/ss/formula/ptg/TestUnionPtg.java
src/testcases/org/apache/poi/ss/usermodel/BaseTestRangeCopier.java [new file with mode: 0644]
src/testcases/org/apache/poi/ss/usermodel/TestRangeCopier.java [deleted file]

index 41fc1eae7c083ca7d091dd574ac5dda28ccb2842..5c107c47afd2b32253c52913c07b50b22a54fb2b 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -54,6 +54,7 @@ under the License.
     <property name="main-tests.lib" location="${basedir}/lib/main-tests"/>
     <property name="ooxml.lib" location="${basedir}/lib/ooxml"/>
     <property name="ooxml-tests.lib" location="${basedir}/lib/ooxml-tests"/>
+    <property name="ooxml-provided.lib" location="${basedir}/lib/ooxml-provided"/>
     <property name="util.lib" location="${basedir}/lib/util"/>
 
 
@@ -153,9 +154,9 @@ under the License.
     <property name="ooxml.output.test.dir" location="build/ooxml-test-classes"/>
     <property name="ooxml.testokfile" location="build/ooxml-testokfile.txt"/>
 
-    <property name="ooxml.lite.agent" location="build/ooxml-lite-agent.jar"/>
+    <property name="ooxml.lite.agent" location="lib/ooxml-tests/ooxml-lite-agent.jar"/>
     <property name="ooxml.lite.report" location="build/ooxml-lite-report.txt"/>
-    <property name="ooxml.lite.jar" location="build/ooxml-lite-classes.jar"/>
+    <property name="ooxml.lite.jar" location="build/dist/maven/poi-ooxml-schemas/poi-ooxml-schemas-${version.id}.jar"/>
     <property name="ooxml.lite.includes" value="^(com/microsoft/schemas|org/(etsi|openxmlformats|w3/)|org/apache/poi/schemas)"/>
 
 
@@ -174,37 +175,70 @@ under the License.
     <property name="excelant.output.test.dir" location="build/excelant-test-classes"/>
     <property name="excelant.testokfile" location="build/excelant-testokfile.txt"/>
 
-
-    <scriptdef name="dependency" language="javascript" description="define properties for library dependency">
+    <macrodef name="dependency">
         <attribute name="prefix"/>
         <attribute name="artifact"/>
         <attribute name="usage"/>
-        <attribute name="packaging"/>
-        <attribute name="repo"/>
-        <attribute name="snapshot"/>
-        <attribute name="query"/>
-        <attribute name="target"/>
-        <attribute name="url"/>
-        <![CDATA[
-            var parts = attributes.get("artifact").split(/:/);
-            var packaging = attributes.get("packaging") || "jar";
-            var version = attributes.get("snapshot") || parts[2];
-            var repo = attributes.get("repo");
-            if (repo == null) {
-                repo = project.getProperty("repository.m2");
-            }
-            var query = attributes.get("query") || "";
-            var usageDir = attributes.get("usage");
-            usageDir = project.getProperty("basedir")+(usageDir.charAt(0) == '/' ? "" : "/lib/")+usageDir;
-            var jarLoc = usageDir+"/"+(attributes.get("target")||(parts[1]+"-"+parts[2]+"."+packaging));
-            var urlLoc = attributes.get("url") ||
-                repo+"/"+parts[0].replace(/\./g,"/")+"/"+parts[1]+"/"+parts[2]+"/"+
-                parts[1]+"-"+(attributes.get("snapshot") || parts[2])+"."+packaging+query;
-            project.setProperty(attributes.get("prefix")+"."+packaging, jarLoc);
-            project.setProperty(attributes.get("prefix")+".url", urlLoc);
-        ]]>
-        <!-- TODO: add library to a queue for downloading ... -->
-    </scriptdef>
+        <attribute name="packaging" default="jar"/>
+        <attribute name="repo" default="${repository.m2}"/>
+        <attribute name="snapshot" default=""/>
+        <attribute name="query" default=""/>
+        <attribute name="target" default=""/>
+        <attribute name="url" default=""/>
+
+        <sequential>
+            <local name="groupDir"/>
+            <loadresource property="groupDir">
+                <string>@{artifact}</string>
+                <filterchain>
+                    <replaceregex pattern="([^:]+).*" replace="\1"/>
+                    <replaceregex pattern="\." replace="/" flags="g"/>
+                </filterchain>
+            </loadresource>
+
+            <local name="artifactId"/>
+            <loadresource property="artifactId">
+                <string>@{artifact}</string>
+                <filterchain>
+                    <replaceregex pattern="[^:]+:([^:]+).*" replace="\1"/>
+                </filterchain>
+            </loadresource>
+
+            <local name="versionDir"/>
+            <loadresource property="versionDir">
+                <string>@{artifact}</string>
+                <filterchain>
+                    <replaceregex pattern="[^:]+:[^:]+:(.*)" replace="\1"/>
+                </filterchain>
+            </loadresource>
+
+            <local name="version"/>
+            <property name="version" value="${versionDir}" if:blank="@{snapshot}"/>
+            <property name="version" value="@{snapshot}"/>
+
+            <local name="usageDir"/>
+            <loadresource property="usageDir">
+                <string>@{usage}</string>
+                <filterchain>
+                    <replaceregex pattern="^([^/])" replace="/lib/\1"/>
+                    <prefixlines prefix="${basedir}"/>
+                </filterchain>
+            </loadresource>
+
+            <local name="jarLoc"/>
+            <property name="jarLoc" value="${usageDir}/@{target}" unless:blank="@{target}"/>
+            <property name="jarLoc" value="${usageDir}/${artifactId}-${version}.@{packaging}"/>
+
+            <local name="urlLoc"/>
+            <property name="urlLoc" value="@{url}" unless:blank="@{url}"/>
+            <property name="urlLoc" value="@{repo}/${groupDir}/${artifactId}/${versionDir}/${artifactId}-${version}.@{packaging}@{query}"/>
+
+            <property name="@{prefix}.@{packaging}" value="${jarLoc}"/>
+            <property name="@{prefix}.url" value="${urlLoc}"/>
+
+            <!-- TODO: add library to a queue for downloading ... -->
+        </sequential>
+    </macrodef>
 
 
     <!-- jars in the /lib directory, see the fetch-jars target-->
@@ -225,13 +259,13 @@ under the License.
     <dependency prefix="main.byte-buddy-agent" artifact="net.bytebuddy:byte-buddy-agent:1.10.1" usage="main-tests"/>
     <dependency prefix="main.objenesis" artifact="org.objenesis:objenesis:2.6" usage="main-tests"/>
 
-    <dependency prefix="main.ant" artifact="org.apache.ant:ant:1.10.1" usage="excelant"/>
-    <dependency prefix="main.antlauncher" artifact="org.apache.ant:ant-launcher:1.10.1" usage="excelant"/>
+    <dependency prefix="main.ant" artifact="org.apache.ant:ant:1.10.8" usage="excelant"/>
+    <dependency prefix="main.antlauncher" artifact="org.apache.ant:ant-launcher:1.10.8" usage="excelant"/>
 
     <!-- xml signature libs - not part of the distribution -->
     <dependency prefix="dsig.xmlsec" artifact="org.apache.santuario:xmlsec:2.1.5" usage="ooxml-provided"/>
-    <dependency prefix="dsig.bouncycastle-prov" artifact="org.bouncycastle:bcprov-ext-jdk15on:1.65" usage="ooxml-provided"/>
-    <dependency prefix="dsig.bouncycastle-pkix" artifact="org.bouncycastle:bcpkix-jdk15on:1.65" usage="ooxml-provided"/>
+    <dependency prefix="dsig.bouncycastle-prov" artifact="org.bouncycastle:bcprov-ext-jdk15on:1.66" usage="ooxml-provided"/>
+    <dependency prefix="dsig.bouncycastle-pkix" artifact="org.bouncycastle:bcpkix-jdk15on:1.66" usage="ooxml-provided"/>
     <dependency prefix="dsig.slf4j-api" artifact="org.slf4j:slf4j-api:1.7.30" usage="ooxml-provided"/>
 
     <!-- svg/batik libs - not part of the distribution -->
@@ -249,7 +283,7 @@ under the License.
 
     <!-- jars in the ooxml-test-lib directory, see the fetch-ooxml-jars target-->
     <dependency prefix="ooxml.test.reflections" artifact="org.reflections:reflections:0.9.11" usage="ooxml-tests"/>
-    <dependency prefix="ooxml.test.guava" artifact="com.google.guava:guava:20.0" usage="ooxml-tests"/>
+    <dependency prefix="ooxml.test.guava" artifact="com.google.guava:guava:29.0-jre" usage="ooxml-tests"/>
     <dependency prefix="ooxml.test.javassist" artifact="org.javassist:javassist:3.21.0-GA" usage="ooxml-tests"/>
 
     <!-- coverage libs -->
@@ -262,21 +296,19 @@ under the License.
     <dependency prefix="rat" artifact="org.apache.rat:apache-rat:0.12" usage="util"/>
     <dependency prefix="forbidden" artifact="de.thetaphi:forbiddenapis:2.6" usage="util"/>
 
-    <property name="maven.ooxml.xsds.version.id" value="1.4"/>
+    <property name="maven.ooxml.xsds.version.id" value="1.5"/>
 
     <!-- See https://www.ecma-international.org/publications/standards/Ecma-376.htm -->
     <!-- "Copy these file(s), free of charge" -->
     <property name="ooxml.xsds.izip.1" value="${basedir}/src/ooxml/resources/org/apache/poi/schemas/OfficeOpenXML-XMLSchema.zip"/>
     <property name="ooxml.xsds.src.dir" location="build/ooxml-xsds-src"/>
-    <property name="ooxml.xsds.src.jar" location="${ooxml.lib}/ooxml-schemas-${maven.ooxml.xsds.version.id}-sources.jar"/>
-    <property name="ooxml.xsds.jar" location="${ooxml.lib}/ooxml-schemas-${maven.ooxml.xsds.version.id}.jar"/>
+    <property name="ooxml.xsds.src.jar" location="build/dist/maven/ooxml-schemas/ooxml-schemas-${maven.ooxml.xsds.version.id}-sources.jar"/>
+    <property name="ooxml.xsds.jar" location="build/dist/maven/ooxml-schemas/ooxml-schemas-${maven.ooxml.xsds.version.id}.jar"/>
 
     <!-- additional schemas are packed into the poi schemas jar, -->
     <!-- so we don't have to care about a seperate versioning of the original ooxml schemas -->
     <property name="ooxml.xsds.izip.2" value="${basedir}/src/ooxml/resources/org/apache/poi/schemas/OpenPackagingConventions-XMLSchema.zip"/>
     <property name="ooxml.security.src.dir" location="build/ooxml-security-src"/>
-    <property name="ooxml.security.src.jar" location="${ooxml.lib}/ooxml-security-1.1-sources.jar"/>
-    <property name="ooxml.security.jar" location="${ooxml.lib}/ooxml-security-1.1.jar"/>
     <property name="ooxml.security.xsd.dir" location="src/ooxml/resources/org/apache/poi/poifs/crypt"/>
     <property name="ooxml.visio.xsd.dir" location="src/ooxml/resources/org/apache/poi/xdgf"/>
     <property name="ooxml.schema.xsdconfig.dir" location="src/ooxml/resources/org/apache/poi/schemas"/>
@@ -375,7 +407,6 @@ under the License.
         <pathelement location="${ooxml.commons-compress.jar}"/>
         <path refid="main.classpath"/>
         <pathelement location="${main.output.dir}"/>
-        <pathelement location="${ooxml.security.jar}"/>
         <pathelement location="${ooxml.test.guava.jar}"/>
         <!-- classes are omitted on test cases outside the xml-dsign area to avoid classpath poisioning -->
         <!--path refid="ooxml.xmlsec.classpath"/-->
@@ -389,18 +420,8 @@ under the License.
         <pathelement location="${svg.xmlgraphics-commons.jar}"/>
     </path>
 
-    <path id="ooxml-lite.classpath">
-        <path refid="ooxml.base.classpath"/>
-        <!-- instead of ooxml-xsds.jar use the filtered classes-->
-        <pathelement location="${ooxml.lite.jar}"/>
-        <pathelement location="${ooxml.output.dir}"/>
-        <pathelement location="${ooxml.output.test.dir}"/>
-        <pathelement location="${main.output.test.dir}"/>
-        <path refid="batik.classpath"/>
-    </path>
-
     <path id="ooxml.classpath">
-        <pathelement location="${ooxml.xsds.jar}"/> 
+        <pathelement location="${ooxml.xsds.jar}"/>
         <path refid="ooxml.base.classpath"/>
         <path refid="batik.classpath"/>
     </path>
@@ -410,38 +431,12 @@ under the License.
         <path refid="ooxml.base.classpath"/>
     </path>
 
-    <path id="test.classpath">
-        <path refid="main.classpath"/>
-        <pathelement location="${main.output.dir}"/>
-        <pathelement location="${main.output.test.dir}"/>
-        <pathelement location="${additionaljar}"/>
-    </path>
-
-    <path id="test.scratchpad.classpath">
-        <path refid="scratchpad.classpath"/>
-        <pathelement location="${main.output.test.dir}"/>
-        <pathelement location="${scratchpad.output.dir}"/>
-        <pathelement location="${scratchpad.output.test.dir}"/>
-        <pathelement location="${additionaljar}"/>
-    </path>
-
     <path id="test.ooxml.reflections.classpath">
         <pathelement location="${ooxml.test.reflections.jar}"/>
         <pathelement location="${ooxml.test.guava.jar}"/>
         <pathelement location="${ooxml.test.javassist.jar}"/>
     </path>
 
-    <path id="test.ooxml.classpath">
-        <path refid="ooxml.classpath"/>
-        <path refid="ooxml.xmlsec.classpath"/>
-        <path refid="test.jar.classpath"/>
-        <path refid="test.ooxml.reflections.classpath"/>
-        <pathelement location="${ooxml.output.dir}"/>
-        <pathelement location="${ooxml.output.test.dir}"/>
-        <pathelement location="${main.output.test.dir}"/>
-        <pathelement location="${additionaljar}"/>
-    </path>
-
     <path id="test.ooxml.lite.verify.classpath">
         <path refid="ooxml.lite.verify.classpath"/>
         <path refid="ooxml.xmlsec.classpath"/>
@@ -452,17 +447,6 @@ under the License.
         <pathelement location="${additionaljar}"/>
     </path>
 
-    <path id="test.integration.classpath">
-        <pathelement location="${integration.src.test}"/>
-        <path refid="scratchpad.classpath"/>
-        <path refid="ooxml.classpath"/>
-        <path refid="test.jar.classpath"/>
-        <pathelement location="${main.output.test.dir}"/>
-        <pathelement location="${ooxml.output.dir}"/>
-        <pathelement location="${integration.output.test.dir}"/>
-        <pathelement location="${examples.output.dir}"/>
-    </path>
-
     <path id="examples.classpath">
         <path refid="main.classpath"/>
         <pathelement location="${main.output.dir}"/>
@@ -475,16 +459,6 @@ under the License.
         <pathelement location="${ooxml.output.dir}"/>
     </path>
 
-    <path id="test.excelant.classpath">
-        <path refid="ooxml.classpath"/>
-        <path refid="test.jar.classpath"/>
-        <pathelement location="${ooxml.output.dir}"/>
-        <pathelement location="${excelant.output.dir}"/>
-        <pathelement location="${excelant.output.test.dir}"/>
-        <pathelement location="${main.output.test.dir}"/>
-        <pathelement location="${additionaljar}"/>
-    </path>
-
     <path id="javadoc.classpath">
         <path refid="main.classpath"/>
         <path refid="scratchpad.classpath"/>
@@ -494,26 +468,6 @@ under the License.
         <path path="${env.CLASSPATH}"/>
     </path>
 
-    <path id="forbiddenapis.classpath">
-        <path refid="main.classpath"/>
-        <path refid="test.jar.classpath"/>
-        <path refid="scratchpad.classpath"/>
-        <path refid="ooxml.classpath"/>
-        <path refid="ooxml.xmlsec.classpath"/>
-        <path refid="test.ooxml.reflections.classpath"/>
-        <path refid="excelant.classpath"/>
-        <path refid="examples.classpath"/>
-        <pathelement location="${examples.output.dir}"/>
-        <path path="${env.CLASSPATH}"/>
-    </path>
-
-    <path id="lib.jacoco">
-        <fileset dir="${util.lib}">
-            <include name="org.jacoco*.jar" />
-            <include name="asm-*.jar" />
-        </fileset>
-    </path>
-
     <patternset id="exclude-scratchpad-test">
         <exclude name="**/TestExtractorFactory.java"/>
         <exclude name="**/TestEmbedOLEPackage.java"/>
@@ -531,7 +485,6 @@ under the License.
     - compile     Compile all files from main, ooxml and scratchpad
     - test        Run all unit tests from main, ooxml and scratchpad
     - jar         Produce jar files
-    - jar-src     Produce source-jar files
     - assemble    Produce the zipped distribution files
     - site        Generate all documentation (Requires Apache Forrest)
     - dist        Create a distribution (Requires Apache Forrest)
@@ -610,14 +563,17 @@ under the License.
 
         <delete verbose="true" failonerror="false">
             <fileset dir="${basedir}/lib" includes="*.jar"/>
-            <fileset dir="${basedir}/lib/util">
-                <include name="asm*7.2.jar"/>
+            <fileset dir="${basedir}/lib/main-tests">
+                <include name="mockito-core-3.2.4.jar"/>
             </fileset>
             <fileset dir="${basedir}/lib/ooxml">
                 <include name="xmlbeans-3.1.0.jar"/>
             </fileset>
-            <fileset dir="${basedir}/lib/main-tests">
-                <include name="mockito-core-3.2.4.jar"/>
+            <fileset dir="${basedir}/lib/ooxml-tests">
+                <include name="guava-20.0.jar"/>
+            </fileset>
+            <fileset dir="${basedir}/lib/util">
+                <include name="asm*7.2.jar"/>
             </fileset>
         </delete>
 
@@ -719,6 +675,7 @@ under the License.
     <target name="fetch-ooxml-jars" depends="check-ooxml-jars" unless="ooxml.jars.present">
         <mkdir dir="${ooxml.lib}"/>
         <mkdir dir="${ooxml-tests.lib}"/>
+<!--        <downloadfile src="${ooxml.xml-apis.url}" dest="${ooxml.xml-apis.jar}"/>-->
         <downloadfile src="${ooxml.curvesapi.url}" dest="${ooxml.curvesapi.jar}"/>
         <downloadfile src="${ooxml.xmlbeans.url}" dest="${ooxml.xmlbeans.jar}"/>
         <downloadfile src="${ooxml.commons-compress.url}" dest="${ooxml.commons-compress.jar}"/>
@@ -760,296 +717,358 @@ under the License.
             <and>
                 <available file="${ooxml.xsds.jar}"/>
                 <available file="${ooxml.xsds.src.jar}"/>
-                <available file="${ooxml.security.jar}"/>
-                <available file="${ooxml.security.src.jar}"/>
             </and>
         </condition>
     </target>
 
-    <macrodef name="compile-ooxml-xmlbean">
-        <attribute name="classes-jar"/>
-        <attribute name="sources-jar"/>
-        <attribute name="noupa" default="false"/>
-        <attribute name="nopvr" default="false"/>
-        <attribute name="multi-src"/>
-        <attribute name="typesystemname"/>
-        <element name="xsds"/>
-        <sequential>
-            <!-- We need a fair amount of memory to compile the xml schema, -->
-            <!-- but limit it in case it goes wrong! -->
-            <!-- Pick the right amount based on 32 vs 64 bit jvm -->
-            <condition property="ooxml.memory" value="1536m" else="1024m">
-               <equals arg1="${sun.arch.data.model}" arg2="64" />
-            </condition>
+    <target name="compile-ooxml-xsds"
+        depends="init,check-compiled-ooxml-xsds"
+        unless="ooxml-compiled-xsds.present"
+        description="Unpacks the OOXML xsd files, and compiles them into XmlBeans">
 
-            <taskdef name="xmlbean"
-                     classname="org.apache.xmlbeans.impl.tool.XMLBean"
-                     classpath="${ooxml.xmlbeans.jar}"/>
+        <local name="ooxml.memory"/>
 
-            <property name="xmlbean.xsds.dir" location="build/xmlbean-xsds"/>
-            <property name="xmlbean.sources.dir" location="build/xmlbean-sources"/>
-            <property name="xmlbean.classes.dir" location="build/xmlbean-classes"/>
+        <!-- We need a fair amount of memory to compile the xml schema, -->
+        <!-- but limit it in case it goes wrong! -->
+        <!-- Pick the right amount based on 32 vs 64 bit jvm -->
+        <condition property="ooxml.memory" value="1536m" else="1024m">
+            <equals arg1="${sun.arch.data.model}" arg2="64" />
+        </condition>
 
-            <delete dir="${xmlbean.xsds.dir}"/>
-            <mkdir dir="${xmlbean.xsds.dir}"/>
-            <delete dir="${xmlbean.sources.dir}"/>
-            <mkdir dir="${xmlbean.sources.dir}"/>
-            <delete dir="${xmlbean.classes.dir}"/>
-            <mkdir dir="${xmlbean.classes.dir}"/>
+        <local name="xmlbean.xsds.dir"/>
+        <property name="xmlbean.xsds.dir" location="build/xmlbean-xsds"/>
+        <mkdir dir="${xmlbean.xsds.dir}"/>
+
+        <copy todir="${xmlbean.xsds.dir}">
+            <zipfileset src="${ooxml.xsds.izip.1}"/>
+            <fileset dir="${ooxml.visio.xsd.dir}"/>
+            <fileset dir="${ooxml.schema.xsdconfig.dir}" includes="ooxmlSchemas.xsdconfig,markup-compatibility.xsd"/>
+            <zipfileset src="${ooxml.xsds.izip.2}" includes="opc-digSig.xsd,opc-relationships.xsd"/>
+            <fileset dir="${ooxml.security.xsd.dir}" includes="signatureInfo.xsd"/>
+            <fileset dir="${ooxml.schema.xsdconfig.dir}" includes="XAdES*.xsd,*.xsdconfig,xmldsig*.xsd"/>
+        </copy>
 
-            <copy todir="${xmlbean.xsds.dir}">
-                <xsds/>
-            </copy>
+        <local name="xmlbean.sources.dir"/>
+        <local name="xmlbean.classes.dir"/>
+        <property name="xmlbean.sources.dir" location="build/xmlbean-sources"/>
+        <property name="xmlbean.classes.dir" location="build/xmlbean-classes"/>
+        <mkdir dir="${xmlbean.sources.dir}"/>
+        <mkdir dir="${xmlbean.classes.dir}"/>
+
+        <taskdef name="xmlbean"
+                 classname="org.apache.xmlbeans.impl.tool.XMLBean"
+                 classpath="${ooxml.xmlbeans.jar}"/>
+
+        <!-- javasource > 1.5 will not generate all array accessor -->
+        <xmlbean
+            schema="${xmlbean.xsds.dir}"
+            srcgendir="${xmlbean.sources.dir}"
+            classgendir="${xmlbean.classes.dir}"
+            destfile="${xmlbean.xsds.dir}.jar"
+            srconly="true"
+            javasource="1.5"
+            failonerror="true"
+            fork="true"
+            memoryMaximumSize="${ooxml.memory}"
+            typesystemname="ooxml"
+            repackage="org.apache.xmlbeans.metadata:org.apache.poi.schemas.ooxml">
+            <classpath>
+                <path location="${ooxml.xmlbeans.jar}"/>
+            </classpath>
+        </xmlbean>
 
-            <!-- javasource > 1.5 will not generate all array accessor -->
-            <xmlbean
-                    schema="${xmlbean.xsds.dir}"
-                    srcgendir="${xmlbean.sources.dir}"
-                    classgendir="${xmlbean.classes.dir}"
-                    destfile="${xmlbean.xsds.dir}.jar"
-                    srconly="true"
-                    javasource="1.5"
-                    failonerror="true"
-                    fork="true"
-                    memoryMaximumSize="${ooxml.memory}"
-                    noupa="@{noupa}"
-                    nopvr="@{nopvr}"
-                    typesystemname="@{typesystemname}"
-                    repackage="org.apache.xmlbeans.metadata:org.apache.poi.schemas.@{typesystemname}"
-                    >
-                <classpath>
-                    <path location="${ooxml.xmlbeans.jar}"/>
-                </classpath>
-            </xmlbean>
+        <javac release="8"
+               target="${jdk.version.class}"
+               source="${jdk.version.source}"
+               srcdir="${xmlbean.sources.dir}"
+               destdir="${xmlbean.classes.dir}"
+               encoding="${java.source.encoding}"
+               fork="yes"
+               debug="${compile.debug}"
+               memoryMaximumSize="${ooxml.memory}"
+               includeantruntime="false">
+            <classpath refid="ooxml.classpath"/>
+        </javac>
+
+        <javac release="9"
+               srcdir="${basedir}/src/multimodule/ooxml-schemas/java9"
+               destdir="${basedir}/src/multimodule/ooxml-schemas/java9"
+               includeantruntime="false"
+               fork="true"
+               modulepath="lib/ooxml"
+               unless:true="${isJava8}">
+            <compilerarg line="--patch-module org.apache.poi.ooxml.schemas=${xmlbean.classes.dir}"/>
+        </javac>
+
+        <mkdir dir="build/dist/maven/ooxml-schemas"/>
+
+        <jar destfile="${ooxml.xsds.jar}">
+            <fileset dir="${xmlbean.classes.dir}"/>
+            <zipfileset dir="${basedir}/src/multimodule/ooxml-schemas/java9" prefix="META-INF/versions/9" excludes="*.java"/>
+            <metainf dir="legal/"/>
+            <manifest>
+                <attribute name="Multi-Release" value="true"/>
+                <attribute name="Automatic-Module-Name" value="org.apache.poi.ooxml.schemas"/>
+                <attribute name="Built-By" value="${user.name}"/>
+                <attribute name="Specification-Title" value="Apache POI OOXML Schemas"/>
+                <attribute name="Specification-Version" value="${maven.ooxml.xsds.version.id}"/>
+                <attribute name="Specification-Vendor" value="The Apache Software Foundation"/>
+                <attribute name="Implementation-Title" value="Apache POI OOXML Schemas"/>
+                <attribute name="Implementation-Version" value="${version.id}"/>
+                <attribute name="Implementation-Vendor-Id" value="org.apache.poi"/>
+                <attribute name="Implementation-Vendor" value="The Apache Software Foundation"/>
+            </manifest>
+        </jar>
+
+        <jar destfile="${ooxml.xsds.src.jar}">
+            <fileset dir="${xmlbean.sources.dir}"/>
+            <zipfileset dir="${basedir}/src/multimodule/ooxml-schemas/java9" prefix="META-INF/versions/9/" excludes="*.class"/>
+            <metainf dir="legal"/>
+        </jar>
+    </target>
+
+    <target name="compile" depends="init, compile-main,
+            compile-scratchpad, compile-examples, compile-excelant"
+            description="Compiles the POI main classes, scratchpad and examples"/>
 
-            <echo>Forking javac with max heap size ${ooxml.memory}</echo>
+    <macrodef name="compile-jar">
+        <attribute name="module"/>
+        <attribute name="java"/>
+        <attribute name="classes"/>
+        <attribute name="test" default=""/>
+        <attribute name="test-classes" default=""/>
+        <attribute name="version" default="${version.id}"/>
+        <element name="lib"/>
+        <element name="resources" optional="true"/>
+        <element name="test-resources" optional="true"/>
+        <sequential>
+            <local name="cp_java"/>
+            <pathconvert property="cp_java" pathsep=",">
+                <path><lib/></path>
+                <regexpmapper from="^${basedir}[/\\](.*)$" to="\1/*.jar"/>
+            </pathconvert>
 
-            <javac target="${jdk.version.class}"
+            <local name="maven-name"/>
+            <loadresource property="maven-name">
+                <string>@{module}</string>
+                <filterchain>
+                    <prefixlines prefix="poi-"/>
+                    <replacestring from="poi-poi" to="poi"/>
+                </filterchain>
+            </loadresource>
+
+            <!-- compile the sources -->
+            <javac release="8"
+                   target="${jdk.version.class}"
                    source="${jdk.version.source}"
-                   srcdir="${xmlbean.sources.dir}"
-                   destdir="${xmlbean.classes.dir}"
+                   destdir="@{classes}"
+                   srcdir="@{java}"
+                   debug="${compile.debug}"
                    encoding="${java.source.encoding}"
                    fork="yes"
-                   optimize="true"
-                   memoryMaximumSize="${ooxml.memory}"
                    includeantruntime="false">
-                <classpath refid="ooxml.classpath"/>
+                <classpath>
+                    <fileset dir="${basedir}" includes="${cp_java}"/>
+                </classpath>
             </javac>
 
-            <local name="module-package"/>
-            <loadfile property="module-package" srcFile="@{multi-src}/java9/module-info.java">
-                <filterchain>
-                    <containsregex pattern=".*module ([^ ]+).*" replace="\1" flags="i"/>
-                    <striplinebreaks/>
-                </filterchain>
-            </loadfile>
-
-            <mkdir dir="${xmlbean.classes.dir}/META-INF/versions/9"/>
-
+            <!-- compile jigsaw files to sources, so we don't forget to update/provide them for Java 8 builds -->
             <javac release="9"
-                   srcdir="@{multi-src}/java9"
-                   destdir="${xmlbean.classes.dir}/META-INF/versions/9"
+                   srcdir="${basedir}/src/multimodule/@{module}/java9"
+                   destdir="${basedir}/src/multimodule/@{module}/java9"
                    includeantruntime="false"
                    fork="true"
-                   modulepath="${ooxml.lib}"
                    unless:true="${isJava8}">
-                <compilerarg line="--patch-module ${module-package}=${xmlbean.classes.dir}"/>
+                <compilerarg line="--patch-module org.apache.poi.@{module}=@{classes}"/>
+                <modulepath>
+                    <lib/>
+                </modulepath>
             </javac>
 
-            <delete file="@{classes-jar}"/>
-            <delete file="@{sources-jar}"/>
+            <mkdir dir="build/dist/maven/${maven-name}"/>
 
-            <jar destfile="@{classes-jar}" level="9">
-                <fileset dir="${xmlbean.classes.dir}"/>
-                <zipfileset prefix="META-INF/versions/9/" dir="@{multi-src}/java9" includes="**/*.class" if:true="${isJava8}"/>
-                <metainf dir="legal"/>
+            <!-- create classes jar -->
+            <jar destfile="build/dist/maven/${maven-name}/${maven-name}-@{version}.jar">
+                <fileset dir="@{classes}"/>
+                <resources/>
+                <zipfileset dir="${basedir}/src/multimodule/@{module}/java9"
+                            prefix="META-INF/versions/9"
+                            excludes="*.java"/>
+                <metainf dir="legal/"/>
                 <manifest>
                     <attribute name="Multi-Release" value="true"/>
+                    <attribute name="Automatic-Module-Name" value="org.apache.poi.@{module}"/>
+                    <attribute name="Built-By" value="${user.name}"/>
+                    <attribute name="Specification-Title" value="Apache POI"/>
+                    <attribute name="Specification-Version" value="${version.id}"/>
+                    <attribute name="Specification-Vendor" value="The Apache Software Foundation"/>
+                    <attribute name="Implementation-Title" value="Apache POI"/>
+                    <attribute name="Implementation-Version" value="${version.id}"/>
+                    <attribute name="Implementation-Vendor-Id" value="org.apache.poi"/>
+                    <attribute name="Implementation-Vendor" value="The Apache Software Foundation"/>
                 </manifest>
             </jar>
-            <jar destfile="@{sources-jar}" level="9">
-                <fileset dir="${xmlbean.sources.dir}"/>
-                <zipfileset prefix="META-INF/versions/9/" dir="@{multi-src}/java9" excludes="**/*.class"/>
-                <metainf dir="legal"/>
-            </jar>
-
-            <delete file="${xmlbean.xsds.dir}.jar"/>
-            <delete dir="${xmlbean.xsds.dir}"/>
-            <delete dir="${xmlbean.sources.dir}"/>
-            <delete dir="${xmlbean.classes.dir}"/>
-        </sequential>
-    </macrodef>
 
-    <target name="compile-ooxml-xsds"
-        depends="init,check-compiled-ooxml-xsds"
-        unless="ooxml-compiled-xsds.present"
-        description="Unpacks the OOXML xsd files, and compiles them into XmlBeans">
-        <compile-ooxml-xmlbean
-            classes-jar="${ooxml.xsds.jar}"
-            sources-jar="${ooxml.xsds.src.jar}"
-            multi-src="${basedir}/src/multimodule/ooxml-schemas"
-            typesystemname="ooxml"
-        >
-            <xsds>
-                <zipfileset src="${ooxml.xsds.izip.1}"/>
-                <fileset dir="${ooxml.visio.xsd.dir}"/>
-                <fileset dir="${ooxml.schema.xsdconfig.dir}" includes="ooxmlSchemas.xsdconfig,markup-compatibility.xsd"/>
-            </xsds>
-        </compile-ooxml-xmlbean>
-        <!-- Now do the same for the security schemas -->
-        <compile-ooxml-xmlbean
-            classes-jar="${ooxml.security.jar}"
-            sources-jar="${ooxml.security.src.jar}"
-            multi-src="${basedir}/src/multimodule/ooxml-security"
-            typesystemname="security"
-        >
-            <xsds>
-                <zipfileset src="${ooxml.xsds.izip.2}" includes="opc-digSig.xsd,opc-relationships.xsd"/>
-                <fileset dir="${ooxml.security.xsd.dir}"/>
-                <fileset dir="${ooxml.schema.xsdconfig.dir}" includes="XAdES*.xsd,*.xsdconfig,xmldsig*.xsd"/>
-            </xsds>
-        </compile-ooxml-xmlbean>
-    </target>
+            <!-- compile the tests -->
+            <javac release="8"
+                   target="${jdk.version.class}"
+                   source="${jdk.version.source}"
+                   destdir="@{test-classes}"
+                   srcdir="@{test}"
+                   debug="${compile.debug}"
+                   encoding="${java.source.encoding}"
+                   fork="yes"
+                   includeantruntime="false" unless:blank="@{test}">
+                <classpath>
+                    <fileset dir="${basedir}" includes="${cp_java}"/>
+                    <pathelement path="build/dist/maven/${maven-name}/${maven-name}-@{version}.jar"/>
+                </classpath>
+            </javac>
 
-    <target name="compile" depends="init, compile-main,
-            compile-scratchpad, compile-examples, compile-excelant"
-            description="Compiles the POI main classes, scratchpad and examples"/>
+            <!-- again, generate jigsaw files to sources ... -->
+            <local name="merged"/>
+            <pathconvert property="merged">
+                <path location="@{classes}"/>
+                <path location="@{test-classes}"/>
+            </pathconvert>
 
-    <target name="compile-main" depends="init">
-        <!-- compile the sources -->
-        <javac target="${jdk.version.class}"
-               source="${jdk.version.source}"
-               destdir="${main.output.dir}"
-               srcdir="${main.src}"
-               debug="${compile.debug}"
-               encoding="${java.source.encoding}"
-               fork="yes"
-               includeantruntime="false">
-            <classpath refid="main.classpath"/>
-        </javac>
-        <!-- compile the tests -->
-        <javac target="${jdk.version.class}"
-               source="${jdk.version.source}"
-               destdir="${main.output.test.dir}"
-               srcdir="${main.src.test}"
-               debug="${compile.debug}"
-               encoding="${java.source.encoding}"
-               fork="yes"
-               includeantruntime="false">
-            <classpath>
-                <path refid="main.classpath"/>
-                <path refid="test.jar.classpath"/>
-                <pathelement path="${main.output.dir}"/>
-            </classpath>
-        </javac>
-        <copy todir="${main.output.dir}">
-            <fileset dir="${main.resource1.dir}"/>
-        </copy>
+            <javac release="9"
+                   srcdir="${basedir}/src/multimodule/@{module}/test9"
+                   destdir="${basedir}/src/multimodule/@{module}/test9"
+                   includeantruntime="false"
+                   fork="true"
+                   unless:true="${isJava8}" unless:blank="@{test}">
+                <compilerarg line="--patch-module org.apache.poi.@{module}=${merged}"/>
+                <modulepath>
+                    <lib/>
+                </modulepath>
+            </javac>
 
+            <!-- create test classes jar - using the module-info of the tests -->
+            <jar destfile="build/dist/maven/${maven-name}-tests/${maven-name}-@{version}-tests.jar" unless:blank="@{test}">
+                <fileset dir="@{classes}"/>
+                <fileset dir="@{test-classes}">
+                    <exclude name="org/apache/poi/ooxml/lite/**"/>
+                </fileset>
+                <resources/>
+                <test-resources/>
+                <zipfileset dir="${basedir}/src/multimodule/@{module}/test9" prefix="META-INF/versions/9" excludes="*.java"/>
+                <metainf dir="legal/"/>
+                <manifest>
+                    <attribute name="Multi-Release" value="true"/>
+                    <attribute name="Automatic-Module-Name" value="org.apache.poi.@{module}"/>
+                    <attribute name="Built-By" value="${user.name}"/>
+                    <attribute name="Specification-Title" value="Apache POI"/>
+                    <attribute name="Specification-Version" value="${version.id}"/>
+                    <attribute name="Specification-Vendor" value="The Apache Software Foundation"/>
+                    <attribute name="Implementation-Title" value="Apache POI"/>
+                    <attribute name="Implementation-Version" value="${version.id}"/>
+                    <attribute name="Implementation-Vendor-Id" value="org.apache.poi"/>
+                    <attribute name="Implementation-Vendor" value="The Apache Software Foundation"/>
+                </manifest>
+            </jar>
 
-        <mkdir dir="${main.output.dir}/META-INF/versions/9"/>
+            <!-- create the sources jar -->
+            <jar destfile="build/dist/maven/${maven-name}/${maven-name}-@{version}-sources.jar">
+                <fileset dir="@{java}"/>
+                <metainf dir="legal/"/>
+<!--                <resources/>-->
+<!--                <zipfileset dir="src/multimodule/@{module}/java9" prefix="META-INF/versions/9" excludes="*.class"/>-->
+                <manifest>
+                    <attribute name="Built-By" value="${user.name}"/>
+                    <attribute name="Specification-Title" value="Apache POI"/>
+                    <attribute name="Specification-Version" value="${version.id}"/>
+                    <attribute name="Specification-Vendor" value="The Apache Software Foundation"/>
+                    <attribute name="Implementation-Title" value="Apache POI"/>
+                    <attribute name="Implementation-Version" value="${version.id}"/>
+                    <attribute name="Implementation-Vendor-Id" value="org.apache.poi"/>
+                    <attribute name="Implementation-Vendor" value="The Apache Software Foundation"/>
+                </manifest>
+            </jar>
+        </sequential>
+    </macrodef>
 
-        <javac release="9"
-               srcdir="${basedir}/src/multimodule/poi/java9"
-               destdir="${main.output.dir}/META-INF/versions/9"
-               includeantruntime="false"
-               fork="true"
-               modulepath="${main.lib}"
-               unless:true="${isJava8}">
-            <compilerarg line="--patch-module org.apache.poi.poi=${main.output.dir}"/>
-        </javac>
+    <target name="compile-main" depends="init, compile-version">
+        <compile-jar module="poi"
+            java="${main.src}" classes="${main.output.dir}"
+            test="${main.src.test}" test-classes="${main.output.test.dir}">
+            <lib>
+                <pathelement path="lib/main"/>
+                <pathelement path="lib/main-tests"/>
+            </lib>
+            <resources>
+                <fileset dir="${main.resource1.dir}"/>
+            </resources>
+        </compile-jar>
     </target>
 
     <target name="compile-scratchpad" depends="compile-main">
-        <!-- compile the sources -->
-        <javac target="${jdk.version.class}"
-               source="${jdk.version.source}"
-               destdir="${scratchpad.output.dir}"
-               srcdir="${scratchpad.src}"
-               debug="${compile.debug}"
-               encoding="${java.source.encoding}"
-               fork="yes"
-               includeantruntime="false">
-            <classpath refid="scratchpad.classpath"/>
-        </javac>
-        <!-- compile the tests -->
-        <javac target="${jdk.version.class}"
-               source="${jdk.version.source}"
-               destdir="${scratchpad.output.test.dir}"
-               srcdir="${scratchpad.src.test}"
-               debug="${compile.debug}"
-               encoding="${java.source.encoding}"
-               fork="yes"
-               includeantruntime="false">
-            <classpath>
-                <path refid="scratchpad.classpath"/>
-                <path refid="test.jar.classpath"/>
-                <pathelement location="${scratchpad.output.dir}"/>
-                <pathelement location="${main.output.test.dir}"/>
-            </classpath>
-        </javac>
-        <copy todir="${scratchpad.output.dir}">
-            <fileset dir="${scratchpad.resource1.dir}"/>
-        </copy>
+        <compile-jar module="scratchpad"
+             java="${scratchpad.src}" classes="${scratchpad.output.dir}"
+             test="${scratchpad.src.test}" test-classes="${scratchpad.output.test.dir}">
+            <lib>
+                <pathelement path="build/dist/maven/poi-tests"/>
+                <pathelement path="lib/main"/>
+                <pathelement path="lib/main-tests"/>
+            </lib>
+            <resources>
+                <fileset dir="${scratchpad.resource1.dir}"/>
+            </resources>
+        </compile-jar>
     </target>
 
     <target name="compile-examples" depends="compile-main,compile-scratchpad,compile-ooxml">
-        <javac target="${jdk.version.class}"
-               source="${jdk.version.source}"
-               destdir="${examples.output.dir}"
-               srcdir="${examples.src}"
-               debug="${compile.debug}"
-               encoding="${java.source.encoding}"
-               fork="yes"
-               includeantruntime="false">
-            <classpath>
-                <path refid="ooxml.classpath"/>
-                <pathelement path="${ooxml.output.dir}"/>
-                <pathelement location="${scratchpad.output.dir}"/>
-            </classpath>
-        </javac>
-        <copy todir="${examples.output.dir}">
-          <fileset dir="${examples.src}">
-            <include name="**/*.css"/>
-          </fileset>
-        </copy>
+        <compile-jar module="examples"
+                     java="${examples.src}" classes="${examples.output.dir}">
+            <lib>
+                <pathelement path="build/dist/maven/ooxml-schemas"/>
+                <pathelement path="build/dist/maven/poi-tests"/>
+                <pathelement path="build/dist/maven/poi-scratchpad-tests"/>
+                <pathelement path="build/dist/maven/poi-ooxml-tests"/>
+                <pathelement path="lib/main"/>
+                <pathelement path="lib/ooxml"/>
+            </lib>
+        </compile-jar>
     </target>
 
     <target name="compile-ooxml" depends="compile-main,compile-scratchpad,compile-ooxml-xsds">
-        <!-- compile the sources -->
-        <javac target="${jdk.version.class}"
-               source="${jdk.version.source}"
-               destdir="${ooxml.output.dir}"
-               srcdir="${ooxml.src}"
-               debug="${compile.debug}"
-               encoding="${java.source.encoding}"
-               fork="yes"
-               includeantruntime="false">
-            <classpath>
-                <path refid="ooxml.classpath"/>
-                <path refid="ooxml.xmlsec.classpath"/>
-            </classpath>
-        </javac>
-        <!-- compile the tests -->
-        <javac target="${jdk.version.class}"
-               source="${jdk.version.source}"
-               destdir="${ooxml.output.test.dir}"
-               srcdir="${ooxml.src.test}"
-               debug="${compile.debug}"
-               encoding="${java.source.encoding}"
-               fork="yes"
-               includeantruntime="false">
-            <classpath>
-                <path refid="ooxml.classpath"/>
-                <path refid="ooxml.xmlsec.classpath"/>
-                <path refid="test.ooxml.classpath"/>
-                <pathelement path="${ooxml.output.dir}"/>
-                <pathelement path="${main.output.test.dir}"/>
-            </classpath>
+        <compile-jar module="ooxml"
+             java="${ooxml.src}" classes="${ooxml.output.dir}"
+             test="${ooxml.src.test}" test-classes="${ooxml.output.test.dir}">
+            <lib>
+                <pathelement path="build/dist/maven/poi-tests"/>
+                <pathelement path="build/dist/maven/poi-scratchpad-tests"/>
+                <pathelement path="build/dist/maven/ooxml-schemas"/>
+                <pathelement path="lib/main"/>
+                <pathelement path="lib/main-tests"/>
+                <pathelement path="lib/ooxml"/>
+                <pathelement path="lib/ooxml-provided"/>
+                <pathelement path="lib/ooxml-tests"/>
+            </lib>
+            <resources>
+                <fileset dir="${ooxml.resource1.dir}"/>
+            </resources>
+        </compile-jar>
+
+        <!-- create ooxml-lite-agent jar -->
+        <javac release="9"
+               srcdir="${basedir}/src/multimodule/ooxml-lite-agent/java9"
+               destdir="${basedir}/src/multimodule/ooxml-lite-agent/java9"
+               includeantruntime="false"
+               fork="true"
+               unless:true="${isJava8}">
+            <compilerarg line="--patch-module org.apache.poi.ooxml_lite=${ooxml.output.test.dir}"/>
         </javac>
-        <copy todir="${ooxml.output.dir}">
-            <fileset dir="${ooxml.resource1.dir}"/>
-        </copy>
+
+        <jar destfile="${ooxml.lite.agent}">
+            <fileset dir="${ooxml.output.test.dir}" includes="org/apache/poi/ooxml/lite/**"/>
+            <zipfileset dir="${basedir}/src/multimodule/ooxml-lite-agent/java9" prefix="META-INF/versions/9" excludes="*.java"/>
+            <manifest>
+                <attribute name="Multi-Release" value="true"/>
+                <attribute name="Automatic-Module-Name" value="org.apache.poi.ooxml_lite"/>
+                <attribute name="Premain-Class" value="org.apache.poi.ooxml.lite.OOXMLLiteAgent"/>
+            </manifest>
+        </jar>
     </target>
 
     <macrodef name="poiunit" xmlns:jacoco="antlib:org.jacoco.ant">
@@ -1057,103 +1076,82 @@ under the License.
         <attribute name="heap" default="512"/>
         <attribute name="showoutput" default="false"/>
         <attribute name="jacocodest" default="build/jacoco-dest.exec"/>
+        <attribute name="modulepath-ref"/>
         <element name="elements" implicit="true"/>
         <sequential>
             <local name="no.jit.sherlock"/>
             <!-- see http://www-01.ibm.com/support/docview.wss?uid=swg21294023 on how to determine the method strings -->
-            <property name="no.jit.sherlock">
-                sun/java2d/pipe/AAShapePipe.renderTiles(Lsun/java2d/SunGraphics2D;Ljava/awt/Shape;Lsun/java2d/pipe/AATileGenerator;[I)V
-                sun/java2d/pipe/AlphaPaintPipe.renderPathTile(Ljava/lang/Object;[BIIIIII)V
-                java/awt/TexturePaintContext.getRaster(IIII)Ljava/awt/image/Raster;
-            </property>
-            <script language="javascript">
-                var before = project.getProperty("no.jit.sherlock");
-                project.setProperty("no.jit.sherlock", before.trim().replace(/ *(\S+) */g,"exclude={$1}").replace(/\s/g,","));
-            </script>
+            <loadresource property="no.jit.sherlock">
+                <string>
+                    sun/java2d/pipe/AAShapePipe.renderTiles(Lsun/java2d/SunGraphics2D;Ljava/awt/Shape;Lsun/java2d/pipe/AATileGenerator;[I)V
+                    sun/java2d/pipe/AlphaPaintPipe.renderPathTile(Ljava/lang/Object;[BIIIIII)V
+                    java/awt/TexturePaintContext.getRaster(IIII)Ljava/awt/image/Raster;
+                </string>
+                <filterchain>
+                    <trim/>
+                    <ignoreblank/>
+                    <prefixlines prefix=",exclude={"/>
+                    <suffixlines suffix="}"/>
+                    <striplinebreaks/>
+                </filterchain>
+            </loadresource>
 
             <local name="ooxml.lite.agent.exists"/>
             <available property="ooxml.lite.agent.exists" file="${ooxml.lite.agent}"/>
 
+            <local name="cp_java"/>
+            <pathconvert property="cp_java" pathsep=",">
+                <path refid="@{modulepath-ref}"/>
+                <regexpmapper from="^${basedir}[/\\](.*)$" to="\1/*.jar"/>
+            </pathconvert>
+
             <jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="@{jacocodest}">
                 <junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
-                       failureproperty="@{failureproperty}" showoutput="@{showoutput}">
+                       failureproperty="@{failureproperty}" showoutput="@{showoutput}" filtertrace="off">
                     <syspropertyset refid="junit.properties"/>
                     <sysproperty key="java.io.tmpdir" value="${tempdir}"/>
                     <jvmarg value="-Xmx@{heap}M"/>
                     <jvmarg value="-ea"/>
 
-                    <!-- some "add-opens" are needed for Java 10, but not for 11+ -->
-                    <jvmarg value="--add-modules=java.xml.bind" if:true="${addOpens10}" />
-                    <jvmarg value="--add-opens=java.base/java.lang=java.xml.bind" if:true="${addOpens10}" />
-
                     <!-- some "add-opens" and other properties are needed when running with Java 9 or newer -->
                     <sysproperty key="sun.reflect.debugModuleAccessChecks" value="true" if:true="${addOpens}" />
                     <sysproperty key="com.sun.xml.bind.v2.bytecode.ClassTailor.noOptimize" value="true" if:true="${addOpens}" />
                     <jvmarg value="--illegal-access=warn" if:true="${addOpens}" />
-                    <jvmarg value="--add-opens=java.xml/com.sun.org.apache.xerces.internal.util=ALL-UNNAMED" if:true="${addOpens}" />
-                    <jvmarg value="--add-opens=java.base/java.io=ALL-UNNAMED" if:true="${addOpens}" />
-                    <jvmarg value="--add-opens=java.base/java.nio=ALL-UNNAMED" if:true="${addOpens}" />
-                    <jvmarg value="--add-opens=java.base/java.lang=ALL-UNNAMED" if:true="${addOpens}" />
-                    <jvmarg value="--add-opens=java.base/jdk.internal.ref=ALL-UNNAMED" if:true="${addOpens}" />
-
                     <jvmarg value="-javaagent:${ooxml.lite.agent}=${ooxml.lite.report}|${ooxml.lite.includes}" if:true="${ooxml.lite.agent.exists}"/>
 
                     <!-- jvmarg value="-Duser.timezone=UTC"/ -->
                     <jvmarg value="${file.leak.detector}" />
-                    <jvmarg value="-Xjit:verbose={compileStart|compileEnd},vlog=build/jit.log,${no.jit.sherlock}" if:true="${isIBMVM}"/>
+                    <jvmarg value="-Xjit:verbose={compileStart|compileEnd},vlog=build/jit.log${no.jit.sherlock}" if:true="${isIBMVM}"/>
                     <formatter type="plain"/>
                     <formatter type="xml"/>
+                    <modulepath refid="@{modulepath-ref}" unless:true="${isJava8}"/>
+                    <classpath if:true="${isJava8}">
+                        <fileset dir="${basedir}" includes="${cp_java}"/>
+                    </classpath>
                     <elements/>
                 </junit>
             </jacoco:coverage>
         </sequential>
     </macrodef>
 
-    <target name="retest-ooxml" depends="jar">
-        <delete dir="${ooxml.reports.test}"/>
-        <delete dir="${ooxml.output.test.dir}"/>
-        <mkdir dir="${ooxml.reports.test}"/>
-        <mkdir dir="${ooxml.output.test.dir}"/>
-        <!-- compile the sources -->
-        <javac target="${jdk.version.class}"
-               source="${jdk.version.source}"
-               destdir="${ooxml.output.dir}"
-               srcdir="${ooxml.src}"
-               debug="${compile.debug}"
-               encoding="${java.source.encoding}"
-               fork="yes"
-               includeantruntime="false">
-            <classpath>
-                <path refid="ooxml.lite.verify.classpath"/>
-                <path refid="ooxml.xmlsec.classpath"/>
-            </classpath>
-        </javac>
-        <!-- compile the tests -->
-        <javac target="${jdk.version.class}"
-               source="${jdk.version.source}"
-               destdir="${ooxml.output.test.dir}"
-               srcdir="${ooxml.src.test}"
-               debug="${compile.debug}"
-               encoding="${java.source.encoding}"
-               fork="yes"
-               includeantruntime="false">
-            <classpath>
-                <path refid="ooxml.classpath"/>
-                <path refid="ooxml.xmlsec.classpath"/>
-                <path refid="test.ooxml.lite.verify.classpath"/>
-                <pathelement path="${ooxml.output.dir}"/>
-                <pathelement path="${main.output.test.dir}"/>
-            </classpath>
-        </javac>
-        <copy todir="${ooxml.output.dir}">
-            <fileset dir="${ooxml.resource1.dir}"/>
-        </copy>
+    <target name="retest-ooxml" depends="jar"
+        description="run ooxml tests with poi-ooxml-schemas (= lite schema)">
+        <path id="restest.modules">
+            <pathelement path="build/dist/maven/poi-tests"/>
+            <pathelement path="build/dist/maven/poi-scratchpad-tests"/>
+            <pathelement path="build/dist/maven/poi-ooxml-tests"/>
+            <pathelement path="build/dist/maven/poi-ooxml-schemas"/>
+            <pathelement path="lib/main"/>
+            <pathelement path="lib/main-tests"/>
+            <pathelement path="lib/ooxml"/>
+            <pathelement path="lib/ooxml-provided"/>
+            <pathelement path="lib/ooxml-tests"/>
+        </path>
 
-        <poiunit failureproperty="ooxml.test.failed" heap="768">
-            <classpath>
-                <path refid="test.ooxml.lite.verify.classpath"/>
-                <path refid="test.jar.classpath"/>
-            </classpath>
+        <poiunit failureproperty="ooxml.test.failed" heap="768"
+            modulepath-ref="restest.modules">
+            <jvmarg line="--add-modules org.apache.poi.ooxml" unless:true="${isJava8}"/>
+            <jvmarg line="--add-modules org.apache.poi.scratchpad" unless:true="${isJava8}"/>
             <batchtest todir="${ooxml.reports.test}">
                 <fileset dir="${ooxml.src.test}">
                     <include name="**/${testpattern}.java"/>
@@ -1168,40 +1166,26 @@ under the License.
     </target>
 
     <target name="compile-excelant" depends="compile-main,compile-ooxml">
-        <!-- compile the sources -->
-        <javac target="${jdk.version.class}"
-               source="${jdk.version.source}"
-               destdir="${excelant.output.dir}"
-               srcdir="${excelant.src}"
-               debug="${compile.debug}"
-               encoding="${java.source.encoding}"
-               fork="yes"
-               includeantruntime="false">
-            <classpath refid="excelant.classpath"/>
-        </javac>
-        <!-- compile the tests -->
-        <javac target="${jdk.version.class}"
-               source="${jdk.version.source}"
-               destdir="${excelant.output.test.dir}"
-               srcdir="${excelant.src.test}"
-               debug="${compile.debug}"
-               encoding="${java.source.encoding}"
-               fork="yes"
-               includeantruntime="false">
-            <classpath>
-                <path refid="excelant.classpath"/>
-                <path refid="test.jar.classpath"/>
-                <pathelement location="${excelant.output.dir}"/>
-                <pathelement path="${main.output.test.dir}"/>
-            </classpath>
-        </javac>
-        <copy todir="${excelant.output.dir}">
-            <fileset dir="${excelant.resource.dir}"/>
-        </copy>
+        <compile-jar module="excelant"
+            java="${excelant.src}" classes="${excelant.output.dir}"
+            test="${excelant.src.test}" test-classes="${excelant.output.test.dir}">
+            <lib>
+                <pathelement path="build/dist/maven/poi-tests"/>
+                <pathelement path="build/dist/maven/poi-scratchpad-tests"/>
+                <pathelement path="build/dist/maven/poi-ooxml-tests"/>
+                <pathelement path="lib/main"/>
+                <pathelement path="lib/main-tests"/>
+                <pathelement path="lib/excelant"/>
+            </lib>
+            <resources>
+                <fileset dir="${excelant.resource.dir}"/>
+            </resources>
+        </compile-jar>
     </target>
 
     <target name="compile-integration" depends="compile-scratchpad, compile-main, compile-ooxml, compile-examples">
-        <javac target="${jdk.version.class}"
+        <javac release="8"
+               target="${jdk.version.class}"
                source="${jdk.version.source}"
                destdir="${integration.output.test.dir}"
                srcdir="${integration.src.test}"
@@ -1221,9 +1205,37 @@ under the License.
             </classpath>
             <exclude name="**/HeapDump**" if:true="${isIBMVM}"/>
         </javac>
-        <!--copy todir="${integration.output.dir}">
-            <fileset dir="${integration.resource1.dir}"/>
-        </copy-->
+
+
+        <mkdir dir="${integration.output.test.dir}/META-INF/versions/9"/>
+
+        <javac release="9"
+               srcdir="${basedir}/src/multimodule/integration/java9"
+               destdir="${integration.output.test.dir}/META-INF/versions/9"
+               includeantruntime="false"
+               fork="true"
+               unless:true="${isJava8}">
+            <compilerarg line="--patch-module org.apache.poi.stress=${integration.output.test.dir}"/>
+            <modulepath>
+                <pathelement path="build/dist/maven/poi"/>
+                <pathelement path="build/dist/maven/poi-ooxml"/>
+                <pathelement path="build/dist/maven/poi-scratchpad"/>
+                <pathelement path="build/dist/maven/poi-examples"/>
+                <pathelement path="${main.lib}"/>
+                <pathelement path="${main-tests.lib}"/>
+                <pathelement path="${ooxml.lib}"/>
+                <pathelement path="${ooxml-provided.lib}"/>
+            </modulepath>
+        </javac>
+
+        <manifest file="build/poi-manifest.mf">
+            <attribute name="Multi-Release" value="true"/>
+            <attribute name="Automatic-Module-Name" value="org.apache.poi.stress"/>
+        </manifest>
+
+        <jar destfile="lib/ooxml-tests/poi-integration.jar"
+             basedir="${integration.output.test.dir}"
+             manifest="build/poi-manifest.mf"/>
     </target>
 
     <target name="-version-java-check">
@@ -1264,7 +1276,12 @@ under the License.
     <target name="jacocotask" depends="">
         <echo message="Coverage reporting: ${coverage.enabled}"/>
         <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
-            <classpath refid="lib.jacoco"/>
+            <classpath>
+                <fileset dir="${util.lib}">
+                    <include name="org.jacoco*.jar" />
+                    <include name="asm-*.jar" />
+                </fileset>
+            </classpath>
         </taskdef>
     </target>
 
@@ -1361,11 +1378,17 @@ under the License.
     <target name="test-main" unless="main.test.notRequired"
             depends="compile-main, -test-main-check,jacocotask"
             description="tests POI classes that deal with the Microsoft Office binary (BIFF8) file formats (excludes OOXML)">
-        <poiunit failureproperty="main.test.failed" heap="256" showoutput="true" jacocodest="build/jacoco-main.exec">
-            <classpath>
-                <path refid="test.classpath"/>
-                <path refid="test.jar.classpath"/>
-            </classpath>
+
+        <path id="test-main.modules">
+            <pathelement path="build/dist/maven/poi-tests"/>
+            <pathelement path="lib/main"/>
+            <pathelement path="lib/main-tests"/>
+        </path>
+
+        <poiunit failureproperty="main.test.failed" heap="256" showoutput="true" jacocodest="build/jacoco-main.exec"
+            modulepath-ref="test-main.modules">
+            <jvmarg line="--add-modules org.apache.poi.poi" unless:true="${isJava8}"/>
+
             <batchtest todir="${main.reports.test}">
                 <fileset dir="${main.src.test}">
                     <include name="**/${testpattern}.java"/>
@@ -1377,6 +1400,7 @@ under the License.
                 </fileset>
             </batchtest>
         </poiunit>
+
         <delete file="${main.testokfile}"/>
         <antcall target="-test-main-write-testfile"/>
     </target>
@@ -1409,14 +1433,22 @@ under the License.
         </uptodate>
     </target>
 
-    <target name="test-scratchpad" depends="jacocotask,compile-main,compile-scratchpad,-test-scratchpad-check,test-scratchpad-download-resources"
+
+    <target name="test-scratchpad" depends="jacocotask,compile-scratchpad,-test-scratchpad-check,test-scratchpad-download-resources"
             unless="scratchpad.test.notRequired"
             description="test non-OOXML scratchpad classes">
-        <poiunit failureproperty="scratchpad.test.failed" heap="512" jacocodest="build/jacoco-scratchpad.exec">
-            <classpath>
-                <path refid="test.scratchpad.classpath"/>
-                <path refid="test.jar.classpath"/>
-            </classpath>
+
+        <path id="test-scratchpad.modules">
+            <pathelement path="build/dist/maven/poi-tests"/>
+            <pathelement path="build/dist/maven/poi-scratchpad-tests"/>
+            <pathelement path="lib/main"/>
+            <pathelement path="lib/main-tests"/>
+        </path>
+
+        <poiunit failureproperty="scratchpad.test.failed" heap="512" jacocodest="build/jacoco-scratchpad.exec"
+            modulepath-ref="test-scratchpad.modules">
+            <jvmarg line="--add-modules org.apache.poi.scratchpad" unless:true="${isJava8}"/>
+
             <batchtest todir="${scratchpad.reports.test}">
                 <fileset dir="${scratchpad.src.test}">
                     <include name="**/${testpattern}.java"/>
@@ -1443,44 +1475,43 @@ under the License.
     </target>
 
     <macrodef name="ooxml-test-runner" xmlns:jacoco="antlib:org.jacoco.ant">
-        <attribute name="classpath"/>
+        <attribute name="modulepath-ref"/>
         <attribute name="type"/>
         <sequential>
-            <poiunit failureproperty="ooxml.test.failed" heap="768" jacocodest="build/jacoco-@{type}.exec">
-                <classpath>
-                    <path refid="@{classpath}"/>
-                    <path refid="test.jar.classpath"/>
-                </classpath>
+            <poiunit failureproperty="ooxml.test.failed" heap="768" jacocodest="build/jacoco-@{type}.exec"
+                modulepath-ref="@{modulepath-ref}">
+                <jvmarg line="--add-modules org.apache.poi.ooxml" unless:true="${isJava8}"/>
+                <jvmarg line="--add-modules org.apache.poi.scratchpad" unless:true="${isJava8}"/>
+
                 <batchtest todir="${ooxml.reports.test}">
                     <fileset dir="${ooxml.src.test}">
                         <include name="**/${testpattern}.java"/>
                         <exclude name="**/TestUnfixedBugs.java"/>
                         <exclude name="**/All*Tests.java"/>
-                        <exclude name="**/TestSignatureInfo.java"/>
                         <exclude name="**/${testexcludepattern}.java"/>
                         <patternset refid="exclude-scratchpad-test" if:true="${scratchpad.ignore}"/>
                     </fileset>
                 </batchtest>
             </poiunit>
-
-            <poiunit failureproperty="ooxml.xmlsec.test.failed" heap="768" jacocodest="build/jacoco-@{type}-xmlsec.exec">
-                <classpath>
-                    <path refid="@{classpath}"/>
-                    <path refid="test.jar.classpath"/>
-                    <path refid="ooxml.xmlsec.classpath"/>
-                </classpath>
-                <batchtest todir="${ooxml.reports.test}">
-                    <fileset dir="${ooxml.src.test}">
-                        <include name="**/TestSignatureInfo.java"/>
-                    </fileset>
-                </batchtest>
-            </poiunit>
         </sequential>
     </macrodef>
 
-    <target name="test-ooxml" depends="compile-main,compile-ooxml,-test-ooxml-check,jacocotask,-ooxml-lite-agent" unless="ooxml.test.notRequired"
+    <target name="test-ooxml" depends="compile-main,compile-ooxml,-test-ooxml-check,jacocotask" unless="ooxml.test.notRequired"
             description="test OOXML classes">
-        <ooxml-test-runner classpath="test.ooxml.classpath" type="ooxml"/>
+        <path id="test-ooxml.modules">
+            <!-- full schema -->
+            <pathelement path="build/dist/maven/ooxml-schemas"/>
+            <pathelement path="build/dist/maven/poi-tests"/>
+            <pathelement path="build/dist/maven/poi-ooxml-tests"/>
+            <pathelement path="build/dist/maven/poi-scratchpad-tests"/>
+            <pathelement path="lib/main"/>
+            <pathelement path="lib/main-tests"/>
+            <pathelement path="lib/ooxml"/>
+            <pathelement path="lib/ooxml-provided"/>
+            <pathelement path="lib/ooxml-tests"/>
+        </path>
+
+        <ooxml-test-runner modulepath-ref="test-ooxml.modules" type="ooxml"/>
         <delete file="${ooxml.testokfile}"/>
         <antcall target="-test-ooxml-write-testfile"/>
     </target>
@@ -1496,12 +1527,28 @@ under the License.
         </uptodate>
     </target>
 
-    <target name="test-integration" depends="compile-integration,-test-integration-check,jacocotask,-ooxml-lite-agent"
+    <target name="test-integration" depends="compile-integration,-test-integration-check,jacocotask"
             unless="integration.test.notRequired">
         <propertyreset name="org.apache.poi.util.POILogger" value="org.apache.poi.util.CommonsLogger"/>
         <delete dir="build" includes="test-integration.log*"/>
-        <poiunit failureproperty="integration.test.failed" heap="1512" showoutput="true" jacocodest="build/jacoco-integration.exec">
-            <classpath refid="test.integration.classpath"/>
+
+        <path id="test-integration.modules">
+            <pathelement path="build/dist/maven/poi"/>
+            <pathelement path="build/dist/maven/poi-ooxml"/>
+            <pathelement path="build/dist/maven/poi-scratchpad"/>
+            <pathelement path="build/dist/maven/poi-examples"/>
+            <pathelement path="build/dist/maven/ooxml-schemas"/>
+            <pathelement path="lib/main"/>
+            <pathelement path="lib/main-tests"/>
+            <pathelement path="lib/ooxml"/>
+            <pathelement path="lib/ooxml-provided"/>
+            <pathelement path="lib/ooxml-tests"/>
+        </path>
+
+        <poiunit failureproperty="integration.test.failed" heap="1512" showoutput="true" jacocodest="build/jacoco-integration.exec"
+            modulepath-ref="test-integration.modules">
+            <jvmarg line="--add-modules org.apache.poi.stress" unless:true="${isJava8}"/>
+
             <batchtest todir="${integration.reports.test}">
                 <fileset dir="${integration.src.test}">
                     <include name="**/${testpattern}.java"/>
@@ -1520,41 +1567,97 @@ under the License.
 
     <!-- the ooxml lite agent collects referenced schema files while other junit tests are run, -->
     <!-- therefore its best to compile the ooxml lite jar after all usual tests are done -->
-    <target name="compile-ooxml-lite" depends="compile-ooxml,-ooxml-lite-agent,test-ooxml">
+    <target name="compile-ooxml-lite" depends="test-ooxml">
         <echo message="Create ooxml-lite schemas"/>
+        <local name="lite.exports"/>
+        <loadresource property="lite.exports">
+            <file file="${ooxml.lite.report}"/>
+            <filterchain>
+                <tokenfilter>
+                    <replaceregex pattern="[/\\][^/\\]+$" replace=""/>
+                    <replaceregex pattern="[/\\]" replace="." flags="g"/>
+                </tokenfilter>
+                <linecontainsregexp negate="true" regexp="\.impl$"/>
+                <sortfilter/>
+                <uniqfilter/>
+                <prefixlines prefix="    exports "/>
+                <suffixlines suffix=";"/>
+            </filterchain>
+        </loadresource>
 
-        <copy file="${ooxml.lite.report}" tofile="${ooxml.lite.report}-pat" overwrite="true"/>
-        <replaceregexp file="${ooxml.lite.report}-pat" byline="true" match="(.*)" replace="\1.class${line.separator}\1$*.class"/>
+        <local name="full.schema"/>
+        <loadresource property="full.schema">
+            <file file="${basedir}/src/multimodule/ooxml-schemas/java9/module-info.java"/>
+            <filterchain>
+                <linecontains negate="true" matchany="true">
+                    <contains value="exports"/>
+                    <contains value="}"/>
+                </linecontains>
+            </filterchain>
+        </loadresource>
 
-        <patternset id="xsbfiles">
-            <includesfile name="${ooxml.lite.report}-pat"/>
-            <include name="org/apache/poi/schemas/*/system/**/*.xsb"/>
-            <include name="org/apache/poi/schemas/*/element/**/*.xsb"/>
-        </patternset>
+        <echo output="${basedir}/src/multimodule/ooxml-lite/java9/module-info.java">${full.schema}${lite.exports}}</echo>
+
+        <javac release="9"
+               srcdir="${basedir}/src/multimodule/ooxml-lite/java9"
+               destdir="${basedir}/src/multimodule/ooxml-lite/java9"
+               includeantruntime="false"
+               fork="true"
+               unless:true="${isJava8}">
+            <compilerarg line="--patch-module org.apache.poi.ooxml.schemas=${ooxml.xsds.jar}"/>
+            <modulepath>
+                <pathelement path="lib/ooxml"/>
+            </modulepath>
+        </javac>
+
+        <local name="lite.classes"/>
+        <loadresource property="lite.classes">
+            <file file="${ooxml.lite.report}"/>
+            <filterchain>
+                <tokenfilter>
+                    <replaceregex pattern="(.*)" replace="\1.class \1$*.class "/>
+                </tokenfilter>
+                <striplinebreaks/>
+            </filterchain>
+        </loadresource>
+
+        <mkdir dir="build/dist/maven/poi-ooxml-schemas"/>
 
         <jar destfile="${ooxml.lite.jar}" duplicate="preserve">
+            <zipfileset dir="${basedir}/src/multimodule/ooxml-lite/java9" prefix="META-INF/versions/9" excludes="*.java"/>
             <zipfileset src="${ooxml.xsds.jar}">
-                <patternset refid="xsbfiles"/>
-            </zipfileset>
-            <zipfileset src="${ooxml.security.jar}">
-                <patternset refid="xsbfiles"/>
+                <patternset includes="${lite.classes}">
+                    <include name="org/apache/poi/schemas/*/system/**/*.xsb"/>
+                    <include name="org/apache/poi/schemas/*/element/**/*.xsb"/>
+                </patternset>
             </zipfileset>
+            <zipfileset dir="src/multimodule/ooxml-schemas/java9" prefix="META-INF/versions/9" excludes="*.java"/>
+            <manifest>
+                <attribute name="Multi-Release" value="true"/>
+                <attribute name="Automatic-Module-Name" value="org.apache.poi.ooxml.schemas"/>
+            </manifest>
         </jar>
     </target>
 
-    <target name="test-ooxml-lite" depends="jacocotask,compile-ooxml-xsds,compile-ooxml-lite">
+    <target name="test-ooxml-lite" depends="jacocotask,compile-ooxml-lite">
         <delete file="${ooxml.testokfile}"/>
         <echo message="Running ooxml tests against 'poi-ooxml-schemas'"/>
-        <ooxml-test-runner classpath="ooxml-lite.classpath" type="ooxml-lite"/>
-    </target>
 
-    <target name="-ooxml-lite-agent" depends="jacocotask,compile-ooxml-xsds,compile-ooxml">
-        <jar destfile="${ooxml.lite.agent}">
-            <fileset dir="${ooxml.output.test.dir}" includes="org/apache/poi/ooxml/util/OOXMLLiteAgent*.class"/>
-            <manifest>
-                <attribute name="Premain-Class" value="org.apache.poi.ooxml.util.OOXMLLiteAgent"/>
-            </manifest>
-        </jar>
+        <path id="test-ooxml-lite.modules">
+            <!-- lite schema -->
+            <pathelement path="build/dist/maven/poi-ooxml-schemas"/>
+            <pathelement path="build/dist/maven/poi-tests"/>
+            <pathelement path="build/dist/maven/poi-ooxml-tests"/>
+            <pathelement path="build/dist/maven/poi-scratchpad-tests"/>
+            <pathelement path="lib/main"/>
+            <pathelement path="lib/main-tests"/>
+            <pathelement path="lib/ooxml"/>
+            <pathelement path="lib/ooxml-provided"/>
+            <pathelement path="lib/ooxml-tests"/>
+        </path>
+
+
+        <ooxml-test-runner modulepath-ref="test-ooxml-lite.modules" type="ooxml-lite"/>
     </target>
 
     <!-- Section: test-excelant -->
@@ -1569,10 +1672,27 @@ under the License.
         <echo file="${excelant.testokfile}" append="false" message="testok"/>
     </target>
 
-    <target name="test-excelant" depends="compile-excelant,-test-excelant-check,jacocotask"
+    <target name="test-excelant" depends="compile-excelant,compile-ooxml-lite,-test-excelant-check,jacocotask"
             unless="excelant.test.notRequired">
-        <poiunit failureproperty="excelant.test.failed" jacocodest="build/jacoco-excelant.exec">
-            <classpath refid="test.excelant.classpath"/>
+
+        <path id="test-excelant.modules">
+            <pathelement path="lib/main"/>
+            <pathelement path="lib/main-tests"/>
+            <pathelement path="lib/ooxml"/>
+            <pathelement path="lib/ooxml-tests"/>
+            <pathelement path="lib/ooxml-provided"/>
+            <pathelement path="lib/excelant"/>
+            <pathelement path="build/dist/maven/poi-tests"/>
+            <pathelement path="build/dist/maven/poi-ooxml-tests"/>
+            <pathelement path="build/dist/maven/poi-ooxml-schemas"/>
+            <pathelement path="build/dist/maven/poi-scratchpad-tests"/>
+            <pathelement path="build/dist/maven/poi-excelant-tests"/>
+        </path>
+
+        <poiunit failureproperty="excelant.test.failed" jacocodest="build/jacoco-excelant.exec"
+            modulepath-ref="test-excelant.modules">
+            <jvmarg line="--add-modules org.apache.poi.excelant" unless:true="${isJava8}"/>
+
             <batchtest todir="${excelant.reports.test}">
                 <fileset dir="${excelant.src.test}">
                     <include name="**/${testpattern}.java"/>
@@ -1768,6 +1888,7 @@ under the License.
 
     <target name="-manifest">
         <manifest file="build/poi-manifest.mf">
+            <attribute name="Multi-Release" value="true"/>
             <attribute name="Built-By" value="${user.name}"/>
             <attribute name="Specification-Title" value="Apache POI"/>
             <attribute name="Specification-Version" value="${version.id}"/>
@@ -1781,6 +1902,9 @@ under the License.
 
     <macrodef name="maven-jar">
         <attribute name="src"/>
+        <attribute name="module"/>
+        <element name="elements" implicit="true" optional="true"/>
+
         <sequential>
             <local name="destfile"/>
             <pathconvert property="destfile" targetos="unix">
@@ -1799,35 +1923,46 @@ under the License.
                     </chainedmapper>
                 </mapper>
             </pathconvert>
+
             <local name="isjar"/>
             <condition property="isjar">
                 <contains string="@{src}" substring=".jar"/>
             </condition>
 
-            <jar destfile="build/dist/maven/${destfile}.jar"
-                 manifest="build/poi-manifest.mf">
+            <mkdir dir="@{src}/META-INF/versions/9"/>
+
+            <javac release="9"
+                   srcdir="${basedir}/src/multimodule/@{module}/java9"
+                   destdir="@{src}/META-INF/versions/9"
+                   includeantruntime="false"
+                   fork="true"
+                   modulepath="${main.lib}"
+                   unless:true="${isJava8}">
+                <compilerarg line="--patch-module org.apache.poi.@{module}=@{src}"/>
+                <elements/>
+            </javac>
+
+            <jar destfile="build/dist/maven/${destfile}.jar">
                 <fileset dir="@{src}" unless:true="${isjar}"/>
                 <zipfileset src="@{src}" if:true="${isjar}"/>
                 <metainf dir="legal/"/>
+                <manifest>
+                    <attribute name="Multi-Release" value="true"/>
+                    <attribute name="Automatic-Module-Name" value="org.apache.poi.@{module}"/>
+                    <attribute name="Built-By" value="${user.name}"/>
+                    <attribute name="Specification-Title" value="Apache POI"/>
+                    <attribute name="Specification-Version" value="${version.id}"/>
+                    <attribute name="Specification-Vendor" value="The Apache Software Foundation"/>
+                    <attribute name="Implementation-Title" value="Apache POI"/>
+                    <attribute name="Implementation-Version" value="${version.id}"/>
+                    <attribute name="Implementation-Vendor-Id" value="org.apache.poi"/>
+                    <attribute name="Implementation-Vendor" value="The Apache Software Foundation"/>
+                </manifest>
             </jar>
         </sequential>
     </macrodef>
 
-    <target name="jar" depends="compile, compile-version, compile-ooxml-lite, -manifest" description="Creates jar files for distribution">
-        <maven-jar src="${main.output.dir}"/>
-        <maven-jar src="${scratchpad.output.dir}"/>
-        <maven-jar src="${ooxml.output.dir}"/>
-        <maven-jar src="${examples.output.dir}"/>
-        <maven-jar src="${excelant.output.dir}"/>
-        <maven-jar src="${ooxml.lite.jar}"/>
-    </target>
-
-    <target name="jar-src" depends="compile, compile-version, -manifest" description="Sources for Maven">
-        <maven-jar src="${main.src}"/>
-        <maven-jar src="${scratchpad.src}"/>
-        <maven-jar src="${ooxml.src}"/>
-        <maven-jar src="${examples.src}"/>
-        <maven-jar src="${excelant.src}"/>
+    <target name="jar" depends="compile, compile-ooxml-lite" description="Creates jar files for distribution">
     </target>
 
     <target name="integration-test-jar" depends="compile-integration,-manifest" description="target for packaging the integration-test code for mass regression test runs">
@@ -1893,7 +2028,7 @@ under the License.
         </copy>
     </target>
 
-    <target name="assemble" depends="jar,jar-src,jar-javadocs" description="Produce the zipped distribution files">
+    <target name="assemble" depends="jar,jar-javadocs" description="Produce the zipped distribution files">
         <property name="zipdir" value="${jar.name}-${version.id}"/>
 
         <mappedresources id="legal-files" cache="true">
@@ -2096,6 +2231,19 @@ under the License.
                  classname="de.thetaphi.forbiddenapis.ant.AntTask"
                  classpath="${forbidden.jar}"/>
 
+        <path id="forbiddenapis.classpath">
+            <fileset dir="lib/main" includes="*.jar"/>
+            <fileset dir="lib/main-tests" includes="*.jar"/>
+            <fileset dir="lib/ooxml" includes="*.jar"/>
+            <fileset dir="lib/ooxml-tests" includes="*.jar"/>
+            <fileset dir="lib/ooxml-provided" includes="*.jar"/>
+            <fileset dir="lib/excelant" includes="*.jar"/>
+            <pathelement location="${ooxml.xsds.jar}"/>
+            <pathelement location="build/dist/maven/poi-examples/poi-examples-${version.id}.jar"/>
+            <path path="${env.CLASSPATH}"/>
+        </path>
+
+
         <!-- first check rules that apply to all the source code -->
         <forbiddenapis
                  classpathref="forbiddenapis.classpath"
@@ -2112,16 +2260,16 @@ under the License.
             -->
             <signaturesFileset file="src/resources/devtools/forbidden-signatures.txt"/>
             <!-- sources -->
-            <fileset dir="${main.output.dir}"/>
-            <fileset dir="${ooxml.output.dir}"/>
-            <fileset dir="${scratchpad.output.dir}"/>
-            <fileset dir="${excelant.output.dir}"/>
+            <!-- zipfileset src="build/dist/maven/poi/poi-5.0.0-SNAPSHOT.jar"/ -->
+            <!-- zipfileset src="build/dist/maven/poi-ooxml/poi-ooxml-5.0.0-SNAPSHOT.jar"/ -->
+            <zipfileset src="build/dist/maven/poi-scratchpad/poi-scratchpad-5.0.0-SNAPSHOT.jar"/>
+            <zipfileset src="build/dist/maven/poi-excelant/poi-excelant-5.0.0-SNAPSHOT.jar"/>
             <!--
             <fileset dir="${examples.output.dir}"/>
             -->
-            <!-- test-sources -->
-            <fileset dir="${main.output.test.dir}"/>
-            <fileset dir="${ooxml.output.test.dir}"/>
+            <!-- test-sources (incl. sources) -->
+            <zipfileset src="build/dist/maven/poi-tests/poi-${version.id}-tests.jar"/>
+            <zipfileset src="build/dist/maven/poi-ooxml-tests/poi-ooxml-${version.id}-tests.jar"/>
             <!--
             <fileset dir="${scratchpad.output.test.dir}"/>
             <fileset dir="${excelant.output.test.dir}"/>
@@ -2137,11 +2285,12 @@ under the License.
             >
             <signaturesFileset file="src/resources/devtools/forbidden-signatures-prod.txt"/>
             <!-- sources -->
-            <fileset dir="${main.output.dir}"/>
-            <fileset dir="${ooxml.output.dir}"/>
-            <fileset dir="${scratchpad.output.dir}"/>
-            <fileset dir="${excelant.output.dir}"/>
-            <fileset dir="${integration.output.test.dir}"/>
+            <zipfileset src="build/dist/maven/poi/poi-5.0.0-SNAPSHOT.jar"/>
+            <zipfileset src="build/dist/maven/poi-ooxml/poi-ooxml-5.0.0-SNAPSHOT.jar"/>
+            <zipfileset src="build/dist/maven/poi-scratchpad/poi-scratchpad-5.0.0-SNAPSHOT.jar"/>
+            <zipfileset src="build/dist/maven/poi-excelant/poi-excelant-5.0.0-SNAPSHOT.jar"/>
+
+            <zipfileset src="lib/ooxml-tests/poi-integration.jar"/>
         </forbiddenapis>
     </target>
 
@@ -2238,7 +2387,6 @@ under the License.
             <auxClasspath path="${dsig.slf4j-api.jar}" />
             <auxClasspath path="${dsig.xmlsec.jar}" />
             <auxClasspath path="${ooxml.xsds.jar}" />
-            <auxClasspath path="${ooxml.security.jar}" />
             <auxClasspath path="${ooxml.curvesapi.jar}" />
             <auxClasspath path="${ooxml.xmlbeans.jar}" />
             <auxClasspath path="${ooxml.commons-compress.jar}" />
diff --git a/src/examples/src/org/apache/poi/crypt/examples/OOXMLPasswordsTry.java b/src/examples/src/org/apache/poi/crypt/examples/OOXMLPasswordsTry.java
deleted file mode 100644 (file)
index 261020f..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.crypt.examples;
-
-import java.io.File;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.security.GeneralSecurityException;
-import java.util.Optional;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
-
-import org.apache.poi.poifs.crypt.Decryptor;
-import org.apache.poi.poifs.crypt.EncryptionInfo;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-
-/**
- * Tries a list of possible passwords for an OOXML protected file
- *
- * Note that this isn't very fast, and is aimed at when you have
- *  just a few passwords to check.
- * For serious processing, you'd be best off grabbing the hash
- *  out with POI or office2john.py, then running that against
- *  "John The Ripper" or GPU enabled version of "hashcat"
- */
-public final class OOXMLPasswordsTry {
-
-    private OOXMLPasswordsTry() {}
-
-    @SuppressWarnings({"java:S106","java:S4823"})
-    public static void main(String[] args) throws Exception {
-        if (args.length < 2) {
-            System.err.println("Use:");
-            System.err.println("  OOXMLPasswordsTry <file.ooxml> <wordlist>");
-            System.exit(1);
-        }
-        String ooxml = args[0];
-        String words = args[1];
-
-        System.out.println("Trying passwords from " + words + " against " + ooxml);
-        System.out.println();
-
-        try (POIFSFileSystem fs = new POIFSFileSystem(new File(ooxml), true)) {
-            EncryptionInfo info = new EncryptionInfo(fs);
-            Decryptor d = Decryptor.getInstance(info);
-
-            final long start = System.currentTimeMillis();
-            final int[] count = { 0 };
-            Predicate<String> counter = s -> {
-                if (++count[0] % 1000 == 0) {
-                    int secs = (int) ((System.currentTimeMillis() - start) / 1000);
-                    System.out.println("Done " + count[0] + " passwords, " + secs + " seconds, last password " + s);
-                }
-                return true;
-            };
-
-            // Try each password in turn, reporting progress
-            try (Stream<String> lines = Files.lines(Paths.get(words))) {
-                Optional<String> found = lines.filter(counter).filter(w -> isValid(d, w)).findFirst();
-                System.out.println(found.map(s -> "Password found: " + s).orElse("Error - No password matched"));
-            }
-        }
-    }
-
-    private static boolean isValid(Decryptor dec, String password) {
-        try {
-            return dec.verifyPassword(password);
-        } catch (GeneralSecurityException e) {
-            return false;
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/examples/crypt/OOXMLPasswordsTry.java b/src/examples/src/org/apache/poi/examples/crypt/OOXMLPasswordsTry.java
new file mode 100644 (file)
index 0000000..406d6dc
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  ====================================================================
+ *    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.examples.crypt;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * Tries a list of possible passwords for an OOXML protected file
+ *
+ * Note that this isn't very fast, and is aimed at when you have
+ *  just a few passwords to check.
+ * For serious processing, you'd be best off grabbing the hash
+ *  out with POI or office2john.py, then running that against
+ *  "John The Ripper" or GPU enabled version of "hashcat"
+ */
+public final class OOXMLPasswordsTry {
+
+    private OOXMLPasswordsTry() {}
+
+    @SuppressWarnings({"java:S106","java:S4823"})
+    public static void main(String[] args) throws Exception {
+        if (args.length < 2) {
+            System.err.println("Use:");
+            System.err.println("  OOXMLPasswordsTry <file.ooxml> <wordlist>");
+            System.exit(1);
+        }
+        String ooxml = args[0];
+        String words = args[1];
+
+        System.out.println("Trying passwords from " + words + " against " + ooxml);
+        System.out.println();
+
+        try (POIFSFileSystem fs = new POIFSFileSystem(new File(ooxml), true)) {
+            EncryptionInfo info = new EncryptionInfo(fs);
+            Decryptor d = Decryptor.getInstance(info);
+
+            final long start = System.currentTimeMillis();
+            final int[] count = { 0 };
+            Predicate<String> counter = s -> {
+                if (++count[0] % 1000 == 0) {
+                    int secs = (int) ((System.currentTimeMillis() - start) / 1000);
+                    System.out.println("Done " + count[0] + " passwords, " + secs + " seconds, last password " + s);
+                }
+                return true;
+            };
+
+            // Try each password in turn, reporting progress
+            try (Stream<String> lines = Files.lines(Paths.get(words))) {
+                Optional<String> found = lines.filter(counter).filter(w -> isValid(d, w)).findFirst();
+                System.out.println(found.map(s -> "Password found: " + s).orElse("Error - No password matched"));
+            }
+        }
+    }
+
+    private static boolean isValid(Decryptor dec, String password) {
+        try {
+            return dec.verifyPassword(password);
+        } catch (GeneralSecurityException e) {
+            return false;
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hpsf/CopyCompare.java b/src/examples/src/org/apache/poi/examples/hpsf/CopyCompare.java
new file mode 100644 (file)
index 0000000..6c1189e
--- /dev/null
@@ -0,0 +1,193 @@
+/* ====================================================================
+   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.examples.hpsf;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.poi.hpsf.DocumentSummaryInformation;
+import org.apache.poi.hpsf.HPSFException;
+import org.apache.poi.hpsf.HPSFRuntimeException;
+import org.apache.poi.hpsf.PropertySet;
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.hpsf.WritingNotSupportedException;
+import org.apache.poi.poifs.eventfilesystem.POIFSReader;
+import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.DocumentInputStream;
+import org.apache.poi.poifs.filesystem.EntryUtils;
+import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.TempFile;
+
+/**
+ * <p>This class copies a POI file system to a new file and compares the copy
+ * with the original.</p>
+ * <p>
+ * <p>Property set streams are copied logically, i.e. the application
+ * establishes a {@link org.apache.poi.hpsf.PropertySet} of an original property
+ * set, creates a {@link org.apache.poi.hpsf.PropertySet} and writes the
+ * {@link org.apache.poi.hpsf.PropertySet} to the destination POI file
+ * system. - Streams which are no property set streams are copied bit by
+ * bit.</p>
+ * <p>
+ * <p>The comparison of the POI file systems is done logically. That means that
+ * the two disk files containing the POI file systems do not need to be
+ * exactly identical. However, both POI file systems must contain the same
+ * files, and most of these files must be bitwise identical. Property set
+ * streams, however, are compared logically: they must have the same sections
+ * with the same attributes, and the sections must contain the same properties.
+ * Details like the ordering of the properties do not matter.</p>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class CopyCompare {
+    private CopyCompare() {}
+
+    /**
+     * Runs the example program. The application expects one or two arguments:
+     *
+     * <ol>
+     * <li>The first argument is the disk file name of the POI filesystem to copy.</li>
+     * <li>The second argument is optional. If it is given, it is the name of
+     * a disk file the copy of the POI filesystem will be written to. If it is
+     * not given, the copy will be written to a temporary file which will be
+     * deleted at the end of the program.</li>
+     * </ol>
+     *
+     * @param args Command-line arguments.
+     * @throws IOException                  if any I/O exception occurs.
+     * @throws UnsupportedEncodingException if a character encoding is not
+     *                                      supported.
+     */
+    public static void main(final String[] args) throws IOException {
+        String originalFileName = null;
+        String copyFileName = null;
+
+        // Check the command-line arguments.
+        if (args.length == 1) {
+            originalFileName = args[0];
+            File f = TempFile.createTempFile("CopyOfPOIFileSystem-", ".ole2");
+            f.deleteOnExit();
+            copyFileName = f.getAbsolutePath();
+        } else if (args.length == 2) {
+            originalFileName = args[0];
+            copyFileName = args[1];
+        } else {
+            System.err.println("Usage: CopyCompare originPOIFS [copyPOIFS]");
+            System.exit(1);
+        }
+
+
+        // Read the origin POIFS using the eventing API.
+        final POIFSReader r = new POIFSReader();
+        try (final POIFSFileSystem poiFs = new POIFSFileSystem();
+             OutputStream fos = new FileOutputStream(copyFileName)) {
+            r.registerListener(e -> handleEvent(poiFs, e));
+            r.setNotifyEmptyDirectories(true);
+
+            r.read(new File(originalFileName));
+
+            // Write the new POIFS to disk.
+            poiFs.writeFilesystem(fos);
+        }
+
+        // Read all documents from the original POI file system and compare them with
+        // the equivalent document from the copy.
+        try (POIFSFileSystem opfs = new POIFSFileSystem(new File(originalFileName));
+             POIFSFileSystem cpfs = new POIFSFileSystem(new File(copyFileName))) {
+            final DirectoryEntry oRoot = opfs.getRoot();
+            final DirectoryEntry cRoot = cpfs.getRoot();
+            System.out.println(EntryUtils.areDirectoriesIdentical(oRoot, cRoot) ? "Equal" : "Not equal");
+        }
+    }
+
+    private interface InputStreamSupplier {
+        InputStream get() throws IOException, WritingNotSupportedException;
+    }
+
+    /**
+     * The method is called by POI's eventing API for each file in the origin POIFS.
+     */
+    public static void handleEvent(final POIFSFileSystem poiFs, final POIFSReaderEvent event) {
+        // The following declarations are shortcuts for accessing the "event" object.
+        final DocumentInputStream stream = event.getStream();
+
+        try {
+
+            // Find out whether the current document is a property set stream or not.
+            InputStreamSupplier su;
+            if (stream != null && PropertySet.isPropertySetStream(stream)) {
+                // Yes, the current document is a property set stream. Let's create
+                // a PropertySet instance from it.
+                PropertySet ps = PropertySetFactory.create(stream);
+
+                // Copy the property set to the destination POI file system.
+                final PropertySet mps;
+                if (ps instanceof DocumentSummaryInformation) {
+                    mps = new DocumentSummaryInformation(ps);
+                } else if (ps instanceof SummaryInformation) {
+                    mps = new SummaryInformation(ps);
+                } else {
+                    mps = new PropertySet(ps);
+                }
+                su = mps::toInputStream;
+            } else {
+                // No, the current document is not a property set stream.
+                // We copy it unmodified to the destination POIFS.
+                su = event::getStream;
+            }
+
+            try (InputStream is = su.get()) {
+                final POIFSDocumentPath path = event.getPath();
+
+                // Ensures that the directory hierarchy for a document in a POI fileystem is in place.
+                // Get the root directory. It does not have to be created since it always exists in a POIFS.
+                DirectoryEntry de = poiFs.getRoot();
+                if (File.separator.equals(path.toString())) {
+                    de.setStorageClsid(event.getStorageClassId());
+                }
+
+                for (int i=0; i<path.length(); i++) {
+                    String subDir = path.getComponent(i);
+                    if (de.hasEntry(subDir)) {
+                        de = (DirectoryEntry)de.getEntry(subDir);
+                    } else {
+                        de = de.createDirectory(subDir);
+                        if (i == path.length()-1) {
+                            de.setStorageClsid(event.getStorageClassId());
+                        }
+                    }
+                }
+
+                if (event.getName() != null) {
+                    de.createDocument(event.getName(), is);
+                }
+            }
+
+        } catch (HPSFException | IOException ex) {
+            // According to the definition of the processPOIFSReaderEvent method we cannot pass checked
+            // exceptions to the caller.
+            throw new HPSFRuntimeException("Could not read file " + event.getPath() + "/" + event.getName(), ex);
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hpsf/ModifyDocumentSummaryInformation.java b/src/examples/src/org/apache/poi/examples/hpsf/ModifyDocumentSummaryInformation.java
new file mode 100644 (file)
index 0000000..cf26fee
--- /dev/null
@@ -0,0 +1,159 @@
+/* ====================================================================
+   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.examples.hpsf;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Date;
+
+import org.apache.poi.hpsf.CustomProperties;
+import org.apache.poi.hpsf.DocumentSummaryInformation;
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * <p>This is a sample application showing how to easily modify properties in
+ * the summary information and in the document summary information. The
+ * application reads the name of a POI filesystem from the command line and
+ * performs the following actions:</p>
+ *
+ * <ul>
+ *
+ * <li><p>Open the POI filesystem.</p></li>
+ *
+ * <li><p>Read the summary information.</p></li>
+ *
+ * <li><p>Read and print the "author" property.</p></li>
+ *
+ * <li><p>Change the author to "Rainer Klute".</p></li>
+ *
+ * <li><p>Read the document summary information.</p></li>
+ *
+ * <li><p>Read and print the "category" property.</p></li>
+ *
+ * <li><p>Change the category to "POI example".</p></li>
+ *
+ * <li><p>Read the custom properties (if available).</p></li>
+ *
+ * <li><p>Insert a new custom property.</p></li>
+ *
+ * <li><p>Write the custom properties back to the document summary
+ * information.</p></li>
+ *
+ * <li><p>Write the summary information to the POI filesystem.</p></li>
+ *
+ * <li><p>Write the document summary information to the POI filesystem.</p></li>
+ *
+ * <li><p>Write the POI filesystem back to the original file.</p></li>
+ *
+ * </ol>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class ModifyDocumentSummaryInformation {
+
+    private ModifyDocumentSummaryInformation() {}
+
+    /**
+     * <p>Main method - see class description.</p>
+     *
+     * @param args The command-line parameters.
+     */
+    public static void main(final String[] args) throws Exception {
+        /* Read the name of the POI filesystem to modify from the command line.
+         * For brevity to boundary check is performed on the command-line
+         * arguments. */
+        File summaryFile = new File(args[0]);
+
+        /* Open the POI filesystem. */
+        try (POIFSFileSystem poifs = new POIFSFileSystem(summaryFile, false)) {
+
+            /* Read the summary information. */
+            DirectoryEntry dir = poifs.getRoot();
+            SummaryInformation si;
+            try {
+                si = (SummaryInformation) PropertySetFactory.create(
+                        dir, SummaryInformation.DEFAULT_STREAM_NAME);
+            } catch (FileNotFoundException ex) {
+                // There is no summary information yet. We have to create a new one
+                si = PropertySetFactory.newSummaryInformation();
+            }
+            assert(si != null);
+
+            /* Change the author to "Rainer Klute". Any former author value will
+             * be lost. If there has been no author yet, it will be created. */
+            si.setAuthor("Rainer Klute");
+            System.out.println("Author changed to " + si.getAuthor() + ".");
+
+
+            /* Handling the document summary information is analogous to handling
+             * the summary information. An additional feature, however, are the
+             * custom properties. */
+
+            /* Read the document summary information. */
+            DocumentSummaryInformation dsi;
+            try {
+                dsi = (DocumentSummaryInformation) PropertySetFactory.create(
+                        dir, DocumentSummaryInformation.DEFAULT_STREAM_NAME);
+            } catch (FileNotFoundException ex) {
+                /* There is no document summary information yet. We have to create a
+                 * new one. */
+                dsi = PropertySetFactory.newDocumentSummaryInformation();
+            }
+            assert(dsi != null);
+
+            /* Change the category to "POI example". Any former category value will
+             * be lost. If there has been no category yet, it will be created. */
+            dsi.setCategory("POI example");
+            System.out.println("Category changed to " + dsi.getCategory() + ".");
+
+            /* Read the custom properties. If there are no custom properties yet,
+             * the application has to create a new CustomProperties object. It will
+             * serve as a container for custom properties. */
+            CustomProperties customProperties = dsi.getCustomProperties();
+            if (customProperties == null)
+                customProperties = new CustomProperties();
+
+            /* Insert some custom properties into the container. */
+            customProperties.put("Key 1", "Value 1");
+            customProperties.put("Schl\u00fcssel 2", "Wert 2");
+            customProperties.put("Sample Number", 12345);
+            customProperties.put("Sample Boolean", Boolean.TRUE);
+            customProperties.put("Sample Date", new Date());
+
+            /* Read a custom property. */
+            Object value = customProperties.get("Sample Number");
+            System.out.println("Custom Sample Number is now " + value);
+
+            /* Write the custom properties back to the document summary
+             * information. */
+            dsi.setCustomProperties(customProperties);
+
+            /* Write the summary information and the document summary information
+             * to the POI filesystem. */
+            si.write(dir, SummaryInformation.DEFAULT_STREAM_NAME);
+            dsi.write(dir, DocumentSummaryInformation.DEFAULT_STREAM_NAME);
+
+            /* Write the POI filesystem back to the original file. Please note that
+             * in production code you should take care when write directly to the
+             * origin, to make sure you don't loose things on error */
+            poifs.writeFilesystem();
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hpsf/ReadCustomPropertySets.java b/src/examples/src/org/apache/poi/examples/hpsf/ReadCustomPropertySets.java
new file mode 100644 (file)
index 0000000..ca8cba1
--- /dev/null
@@ -0,0 +1,109 @@
+/* ====================================================================
+   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.examples.hpsf;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.hpsf.HPSFRuntimeException;
+import org.apache.poi.hpsf.NoPropertySetStreamException;
+import org.apache.poi.hpsf.Property;
+import org.apache.poi.hpsf.PropertySet;
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.Section;
+import org.apache.poi.poifs.eventfilesystem.POIFSReader;
+import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
+
+/**
+ * <p>Sample application showing how to read a document's custom property set.
+ * Call it with the document's file name as command-line parameter.</p>
+ *
+ * <p>Explanations can be found in the HPSF HOW-TO.</p>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class ReadCustomPropertySets {
+
+    private ReadCustomPropertySets() {}
+
+    /**
+     * <p>Runs the example program.</p>
+     *
+     * @param args Command-line arguments (unused).
+     * @throws IOException if any I/O exception occurs.
+     */
+    public static void main(final String[] args) throws IOException {
+        final String filename = args[0];
+        POIFSReader r = new POIFSReader();
+
+        /* Register a listener for *all* documents. */
+        r.registerListener(ReadCustomPropertySets::processPOIFSReaderEvent);
+        r.read(new File(filename));
+    }
+
+
+    public static void processPOIFSReaderEvent(final POIFSReaderEvent event) {
+        final String streamName = event.getPath() + event.getName();
+        PropertySet ps;
+        try {
+            ps = PropertySetFactory.create(event.getStream());
+        } catch (NoPropertySetStreamException ex) {
+            out("No property set stream: \"" + streamName + "\"");
+            return;
+        } catch (Exception ex) {
+            throw new HPSFRuntimeException("Property set stream \"" + streamName + "\": " + ex);
+        }
+
+        /* Print the name of the property set stream: */
+        out("Property set stream \"" + streamName + "\":");
+
+        /* Print the number of sections: */
+        final long sectionCount = ps.getSectionCount();
+        out("   No. of sections: " + sectionCount);
+
+        /* Print the list of sections: */
+        List<Section> sections = ps.getSections();
+        int nr = 0;
+        for (Section sec : sections) {
+            /* Print a single section: */
+            out("   Section " + nr++ + ":");
+            String s = sec.getFormatID().toString();
+            s = s.substring(0, s.length() - 1);
+            out("      Format ID: " + s);
+
+            /* Print the number of properties in this section. */
+            int propertyCount = sec.getPropertyCount();
+            out("      No. of properties: " + propertyCount);
+
+            /* Print the properties: */
+            Property[] properties = sec.getProperties();
+            for (Property p : properties) {
+                /* Print a single property: */
+                long id = p.getID();
+                long type = p.getType();
+                Object value = p.getValue();
+                out("      Property ID: " + id + ", type: " + type +
+                        ", value: " + value);
+            }
+        }
+    }
+
+    private static void out(final String msg) {
+        System.out.println(msg);
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hpsf/ReadTitle.java b/src/examples/src/org/apache/poi/examples/hpsf/ReadTitle.java
new file mode 100644 (file)
index 0000000..b901a89
--- /dev/null
@@ -0,0 +1,64 @@
+/* ====================================================================
+   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.examples.hpsf;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.poifs.eventfilesystem.POIFSReader;
+import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
+
+/**
+ * <p>Sample application showing how to read a OLE 2 document's
+ * title. Call it with the document's file name as command line
+ * parameter.</p>
+ *
+ * <p>Explanations can be found in the HPSF HOW-TO.</p>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class ReadTitle {
+    private ReadTitle() {}
+
+    /**
+     * <p>Runs the example program.</p>
+     *
+     * @param args Command-line arguments. The first command-line argument must
+     * be the name of a POI filesystem to read.
+     * @throws IOException if any I/O exception occurs.
+     */
+    public static void main(final String[] args) throws IOException {
+        final String filename = args[0];
+        POIFSReader r = new POIFSReader();
+        r.registerListener(ReadTitle::processPOIFSReaderEvent, SummaryInformation.DEFAULT_STREAM_NAME);
+        r.read(new File(filename));
+    }
+
+
+    private static void processPOIFSReaderEvent(final POIFSReaderEvent event) {
+        SummaryInformation si;
+        try {
+            si = (SummaryInformation) PropertySetFactory.create(event.getStream());
+        } catch (Exception ex) {
+            throw new RuntimeException("Property set stream \"" + event.getPath() + event.getName() + "\": " + ex);
+        }
+        final String title = si.getTitle();
+        System.out.println(title != null ? "Title: \"" + title + "\"" : "Document has no title.");
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hpsf/WriteAuthorAndTitle.java b/src/examples/src/org/apache/poi/examples/hpsf/WriteAuthorAndTitle.java
new file mode 100644 (file)
index 0000000..94ceaf6
--- /dev/null
@@ -0,0 +1,174 @@
+/* ====================================================================
+   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.examples.hpsf;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.hpsf.HPSFRuntimeException;
+import org.apache.poi.hpsf.MarkUnsupportedException;
+import org.apache.poi.hpsf.NoPropertySetStreamException;
+import org.apache.poi.hpsf.PropertySet;
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.Section;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.hpsf.Variant;
+import org.apache.poi.hpsf.WritingNotSupportedException;
+import org.apache.poi.hpsf.wellknown.PropertyIDMap;
+import org.apache.poi.poifs.eventfilesystem.POIFSReader;
+import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.DocumentInputStream;
+import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * <p>This class is a sample application which shows how to write or modify the
+ * author and title property of an OLE 2 document. This could be done in two
+ * different ways:</p>
+ *
+ * <ul>
+ *
+ * <li><p>The first approach is to open the OLE 2 file as a POI filesystem
+ * (see class {@link POIFSFileSystem}), read the summary information property
+ * set (see classes {@link SummaryInformation} and {@link PropertySet}), write
+ * the author and title properties into it and write the property set back into
+ * the POI filesystem.</p></li>
+ *
+ * <li><p>The second approach does not modify the original POI filesystem, but
+ * instead creates a new one. All documents from the original POIFS are copied
+ * to the destination POIFS, except for the summary information stream. The
+ * latter is modified by setting the author and title property before writing
+ * it to the destination POIFS. It there are several summary information streams
+ * in the original POIFS - e.g. in subordinate directories - they are modified
+ * just the same.</p></li>
+ *
+ * </ul>
+ *
+ * <p>This sample application takes the second approach. It expects the name of
+ * the existing POI filesystem's name as its first command-line parameter and
+ * the name of the output POIFS as the second command-line argument. The
+ * program then works as described above: It copies nearly all documents
+ * unmodified from the input POI filesystem to the output POI filesystem. If it
+ * encounters a summary information stream it reads its properties. Then it sets
+ * the "author" and "title" properties to new values and writes the modified
+ * summary information stream into the output file.</p>
+ *
+ * <p>Further explanations can be found in the HPSF HOW-TO.</p>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class WriteAuthorAndTitle {
+    private WriteAuthorAndTitle() {}
+
+    /**
+     * <p>Runs the example program.</p>
+     *
+     * @param args Command-line arguments. The first command-line argument must
+     * be the name of a POI filesystem to read.
+     * @throws IOException if any I/O exception occurs.
+     */
+    public static void main(final String[] args) throws IOException {
+        /* Check whether we have exactly two command-line arguments. */
+        if (args.length != 2) {
+            System.err.println("Usage: WriteAuthorAndTitle originPOIFS destinationPOIFS");
+            System.exit(1);
+        }
+
+        /* Read the names of the origin and destination POI filesystems. */
+        final String srcName = args[0];
+        final String dstName = args[1];
+
+        /* Read the origin POIFS using the eventing API. The real work is done
+         * in the class ModifySICopyTheRest which is registered here as a
+         * POIFSReader. */
+        try (POIFSFileSystem poifs = new POIFSFileSystem();
+             OutputStream out = new FileOutputStream(dstName)) {
+            final POIFSReader r = new POIFSReader();
+            r.registerListener(e -> handleEvent(poifs, e));
+            r.read(new File(srcName));
+
+            /* Write the new POIFS to disk. */
+            poifs.writeFilesystem(out);
+        }
+    }
+
+    private interface InputStreamSupplier {
+        InputStream get() throws IOException, WritingNotSupportedException;
+    }
+
+    /**
+     * The method is called by POI's eventing API for each file in the origin POIFS.
+     */
+    private static void handleEvent(final POIFSFileSystem poiFs, final POIFSReaderEvent event) {
+        // The following declarations are shortcuts for accessing the "event" object.
+        final DocumentInputStream stream = event.getStream();
+
+        try {
+            final InputStreamSupplier isSup;
+
+            // Find out whether the current document is a property set stream or not.
+            if (PropertySet.isPropertySetStream(stream)) {
+                // Yes, the current document is a property set stream. Let's create a PropertySet instance from it.
+                PropertySet ps = PropertySetFactory.create(stream);
+
+                // Now we know that we really have a property set.
+                // The next step is to find out whether it is a summary information or not.
+                if (ps.isSummaryInformation()) {
+                    // Create a mutable property set as a copy of the original read-only property set.
+                    ps = new PropertySet(ps);
+
+                    // Retrieve the section containing the properties to modify.
+                    // A summary information property set contains exactly one section.
+                    final Section s = ps.getSections().get(0);
+
+                    // Set the properties.
+                    s.setProperty(PropertyIDMap.PID_AUTHOR, Variant.VT_LPSTR, "Rainer Klute");
+                    s.setProperty(PropertyIDMap.PID_TITLE, Variant.VT_LPWSTR, "Test");
+                }
+
+                isSup = ps::toInputStream;
+            } else {
+                // No, the current document is not a property set stream. We copy it unmodified to the destination POIFS.
+                isSup = event::getStream;
+            }
+
+            try (InputStream is = isSup.get()) {
+                final POIFSDocumentPath path = event.getPath();
+
+                // Ensures that the directory hierarchy for a document in a POI fileystem is in place.
+                // Get the root directory. It does not have to be created since it always exists in a POIFS.
+                DirectoryEntry de = poiFs.getRoot();
+
+                for (int i=0; i<path.length(); i++) {
+                    String subDir = path.getComponent(i);
+                    de = (de.hasEntry(subDir)) ? (DirectoryEntry)de.getEntry(subDir) : de.createDirectory(subDir);
+                }
+
+                de.createDocument(event.getName(), is);
+            }
+
+        } catch (MarkUnsupportedException | WritingNotSupportedException | IOException | NoPropertySetStreamException ex) {
+            // According to the definition of the processPOIFSReaderEvent method we cannot pass checked
+            // exceptions to the caller.
+            throw new HPSFRuntimeException("Could not read file " + event.getPath() + "/" + event.getName(), ex);
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hpsf/WriteTitle.java b/src/examples/src/org/apache/poi/examples/hpsf/WriteTitle.java
new file mode 100644 (file)
index 0000000..a9a50cf
--- /dev/null
@@ -0,0 +1,104 @@
+/* ====================================================================
+   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.examples.hpsf;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.hpsf.Property;
+import org.apache.poi.hpsf.PropertySet;
+import org.apache.poi.hpsf.Section;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.hpsf.Variant;
+import org.apache.poi.hpsf.WritingNotSupportedException;
+import org.apache.poi.hpsf.wellknown.PropertyIDMap;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * <p>This class is a simple sample application showing how to create a property
+ * set and write it to disk.</p>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class WriteTitle {
+
+    private WriteTitle() {}
+
+    /**
+     * <p>Runs the example program.</p>
+     *
+     * @param args Command-line arguments. The first and only command-line
+     * argument is the name of the POI file system to create.
+     * @throws IOException if any I/O exception occurs.
+     * @throws WritingNotSupportedException if HPSF does not (yet) support
+     * writing a certain property type.
+     */
+    public static void main(final String[] args)
+    throws WritingNotSupportedException, IOException
+    {
+        /* Check whether we have exactly one command-line argument. */
+        if (args.length != 1)
+        {
+            System.err.println("Usage: " + WriteTitle.class.getName() + "destinationPOIFS");
+            System.exit(1);
+        }
+
+        final String fileName = args[0];
+
+        /* Create a mutable property set. Initially it contains a single section
+         * with no properties. */
+        final PropertySet mps = new PropertySet();
+
+        /* Retrieve the section the property set already contains. */
+        final Section ms = mps.getSections().get(0);
+
+        /* Turn the property set into a summary information property. This is
+         * done by setting the format ID of its first section to
+         * SectionIDMap.SUMMARY_INFORMATION_ID. */
+        ms.setFormatID(SummaryInformation.FORMAT_ID);
+
+        /* Create an empty property. */
+        final Property p = new Property();
+
+        /* Fill the property with appropriate settings so that it specifies the
+         * document's title. */
+        p.setID(PropertyIDMap.PID_TITLE);
+        p.setType(Variant.VT_LPWSTR);
+        p.setValue("Sample title");
+
+        /* Place the property into the section. */
+        ms.setProperty(p);
+
+        /* Create the POI file system the property set is to be written to.
+         * For writing the property set into a POI file system it has to be
+         * handed over to the POIFS.createDocument() method as an input stream
+         * which produces the bytes making out the property set stream. */
+        try (final POIFSFileSystem poiFs = new POIFSFileSystem();
+             final InputStream is = mps.toInputStream();
+             final FileOutputStream fos = new FileOutputStream(fileName)) {
+
+            /* Create the summary information property set in the POI file
+             * system. It is given the default name most (if not all) summary
+             * information property sets have. */
+            poiFs.createDocument(is, SummaryInformation.DEFAULT_STREAM_NAME);
+
+            /* Write the whole POI file system to a disk file. */
+            poiFs.writeFilesystem(fos);
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hslf/ApacheconEU08.java b/src/examples/src/org/apache/poi/examples/hslf/ApacheconEU08.java
new file mode 100644 (file)
index 0000000..53d3c46
--- /dev/null
@@ -0,0 +1,460 @@
+/* ====================================================================
+   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.examples.hslf;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.geom.Rectangle2D;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.sl.draw.DrawTableShape;
+import org.apache.poi.sl.draw.SLGraphics;
+import org.apache.poi.sl.usermodel.AutoShape;
+import org.apache.poi.sl.usermodel.GroupShape;
+import org.apache.poi.sl.usermodel.ShapeType;
+import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.TableCell;
+import org.apache.poi.sl.usermodel.TableShape;
+import org.apache.poi.sl.usermodel.TextBox;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.sl.usermodel.TextRun;
+import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
+import org.apache.poi.sl.usermodel.VerticalAlignment;
+
+/**
+ * Presentation for Fast Feather Track on ApacheconEU 2008
+ *
+ * @author Yegor Kozlov
+ */
+@SuppressWarnings("java:S1192")
+public final class ApacheconEU08 {
+
+    private ApacheconEU08() {}
+
+    public static void main(String[] args) throws IOException {
+        // use HSLFSlideShow or XMLSlideShow
+        try (SlideShow<?,?> ppt = new HSLFSlideShow()) {
+            ppt.setPageSize(new Dimension(720, 540));
+
+            slide1(ppt);
+            slide2(ppt);
+            slide3(ppt);
+            slide4(ppt);
+            slide5(ppt);
+            slide6(ppt);
+            slide7(ppt);
+            slide8(ppt);
+            slide9(ppt);
+            slide10(ppt);
+            slide11(ppt);
+            slide12(ppt);
+
+            String ext = ppt.getClass().getName().contains("HSLF") ? "ppt" : "pptx";
+            try (FileOutputStream out = new FileOutputStream("apachecon_eu_08." + ext)) {
+                ppt.write(out);
+            }
+        }
+    }
+
+    public static void slide1(SlideShow<?,?> ppt) throws IOException {
+        Slide<?,?> slide = ppt.createSlide();
+
+        TextBox<?,?> box1 = slide.createTextBox();
+        box1.setTextPlaceholder(TextPlaceholder.CENTER_TITLE);
+        box1.setText("POI-HSLF");
+        box1.setAnchor(new Rectangle(54, 78, 612, 115));
+
+        TextBox<?,?> box2 = slide.createTextBox();
+        box2.setTextPlaceholder(TextPlaceholder.CENTER_BODY);
+        box2.setText("Java API To Access Microsoft PowerPoint Format Files");
+        box2.setAnchor(new Rectangle(108, 204, 504, 138));
+
+        TextBox<?,?> box3 = slide.createTextBox();
+        box3.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(32d);
+        box3.setText(
+                "Yegor Kozlov\r" +
+                "yegor - apache - org");
+        box3.setHorizontalCentered(true);
+        box3.setAnchor(new Rectangle(206, 348, 310, 84));
+    }
+
+    public static void slide2(SlideShow<?,?> ppt) throws IOException {
+        Slide<?,?> slide = ppt.createSlide();
+
+        TextBox<?,?> box1 = slide.createTextBox();
+        box1.setTextPlaceholder(TextPlaceholder.TITLE);
+        box1.setText("What is HSLF?");
+        box1.setAnchor(new Rectangle(36, 21, 648, 90));
+
+        TextBox<?,?> box2 = slide.createTextBox();
+        box2.setTextPlaceholder(TextPlaceholder.BODY);
+        box2.setText("HorribleSLideshowFormat is the POI Project's pure Java implementation " +
+                "of the Powerpoint binary file format. \r" +
+                "POI sub-project since 2005\r" +
+                "Started by Nick Burch, Yegor Kozlov joined soon after");
+        box2.setAnchor(new Rectangle(36, 126, 648, 356));
+    }
+
+    public static void slide3(SlideShow<?,?> ppt) throws IOException {
+        Slide<?,?> slide = ppt.createSlide();
+
+        TextBox<?,?> box1 = slide.createTextBox();
+        box1.setTextPlaceholder(TextPlaceholder.TITLE);
+        box1.setText("HSLF in a Nutshell");
+        box1.setAnchor(new Rectangle(36, 15, 648, 65));
+
+        TextBox<?,?> box2 = slide.createTextBox();
+        box2.setTextPlaceholder(TextPlaceholder.BODY);
+        box2.setText(
+            "HSLF provides a way to read, create and modify MS PowerPoint presentations\r" +
+            "Pure Java API - you don't need PowerPoint to read and write *.ppt files\r" +
+            "Comprehensive support of PowerPoint objects\r" +
+                "Rich text\r" +
+                "Tables\r" +
+                "Shapes\r" +
+                "Pictures\r" +
+                "Master slides\r" +
+            "Access to low level data structures"
+        );
+
+        List<? extends TextParagraph<?,?,?>> tp = box2.getTextParagraphs();
+        for (int i : new byte[]{0,1,2,8}) {
+            tp.get(i).getTextRuns().get(0).setFontSize(28d);
+        }
+        for (int i : new byte[]{3,4,5,6,7}) {
+            tp.get(i).getTextRuns().get(0).setFontSize(24d);
+            tp.get(i).setIndentLevel(1);
+        }
+        box2.setAnchor(new Rectangle(36, 80, 648, 400));
+    }
+
+    public static void slide4(SlideShow<?,?> ppt) throws IOException {
+        Slide<?,?> slide = ppt.createSlide();
+
+        String[][] txt1 = {
+            {"Note"},
+            {"This presentation was created programmatically using POI HSLF"}
+        };
+        TableShape<?,?> table1 = slide.createTable(2, 1);
+        for (int i = 0; i < txt1.length; i++) {
+            for (int j = 0; j < txt1[i].length; j++) {
+                TableCell<?,?> cell = table1.getCell(i, j);
+                cell.setText(txt1[i][j]);
+                TextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
+                rt.setFontSize(10d);
+                rt.setFontFamily("Arial");
+                rt.setBold(true);
+                if(i == 0){
+                    rt.setFontSize(32d);
+                    rt.setFontColor(Color.white);
+                    cell.setFillColor(new Color(0, 153, 204));
+                } else {
+                    rt.setFontSize(28d);
+                    cell.setFillColor(new Color(235, 239, 241));
+                }
+                cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
+            }
+        }
+
+        DrawTableShape dts = new DrawTableShape(table1);
+        dts.setAllBorders(1.0, Color.black);
+        dts.setOutsideBorders(4.0);
+
+        table1.setColumnWidth(0, 450);
+        table1.setRowHeight(0, 50);
+        table1.setRowHeight(1, 80);
+
+        Dimension dim = ppt.getPageSize();
+        Rectangle2D oldAnchor = table1.getAnchor();
+        table1.setAnchor(new Rectangle2D.Double((dim.width-450)/2d, 100, oldAnchor.getWidth(), oldAnchor.getHeight()));
+
+        TextBox<?,?> box1 = slide.createTextBox();
+        box1.setHorizontalCentered(true);
+        box1.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(24d);
+        box1.setText("The source code is available at\r" +
+                "http://people.apache.org/~yegor/apachecon_eu08/");
+        box1.setAnchor(new Rectangle(80, 356, 553, 65));
+    }
+
+    public static void slide5(SlideShow<?,?> ppt) throws IOException {
+        Slide<?,?> slide = ppt.createSlide();
+
+        TextBox<?,?> box1 = slide.createTextBox();
+        box1.setTextPlaceholder(TextPlaceholder.TITLE);
+        box1.setText("HSLF in Action - 1\rData Extraction");
+        box1.setAnchor(new Rectangle(36, 21, 648, 100));
+
+        TextBox<?,?> box2 = slide.createTextBox();
+        box2.setTextPlaceholder(TextPlaceholder.BODY);
+        box2.setText(
+                "Text from slides and notes\r" +
+                "Images\r" +
+                "Shapes and their properties (type, position in the slide, color, font, etc.)");
+        box2.setAnchor(new Rectangle(36, 150, 648, 300));
+    }
+
+    public static void slide6(SlideShow<?,?> ppt) throws IOException {
+        Slide<?,?> slide = ppt.createSlide();
+
+        TextBox<?,?> box1 = slide.createTextBox();
+        box1.setTextPlaceholder(TextPlaceholder.TITLE);
+        box1.setText("HSLF in Action - 2");
+        box1.setAnchor(new Rectangle(36, 20, 648, 90));
+
+        TextBox<?,?> box2 = slide.createTextBox();
+        box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(18d);
+        box2.setText("Creating a simple presentation from scratch");
+        box2.setAnchor(new Rectangle(170, 100, 364, 30));
+
+        TextBox<?,?> box3 = slide.createTextBox();
+        TextRun rt3 = box3.getTextParagraphs().get(0).getTextRuns().get(0);
+        rt3.setFontFamily("Courier New");
+        rt3.setFontSize(8d);
+        box3.setText(
+                "SlideShow ppt = new SlideShow();\u000b" +
+                "Slide slide = ppt.createSlide();\u000b" +
+                "\u000b" +
+                "TextBox box2 = new TextBox();\u000b" +
+                "box2.setHorizontalAlignment(TextBox.AlignCenter);\u000b" +
+                "box2.setVerticalAlignment(TextBox.AnchorMiddle);\u000b" +
+                "box2.getTextRun().setText(\"Java Code\");\u000b" +
+                "box2.getFill().setForegroundColor(new Color(187, 224, 227));\u000b" +
+                "box2.setLineColor(Color.black);\u000b" +
+                "box2.setLineWidth(0.75);\u000b" +
+                "box2.setAnchor(new Rectangle(66, 243, 170, 170));\u000b" +
+                "slide.addShape(box2);\u000b" +
+                "\u000b" +
+                "TextBox box3 = new TextBox();\u000b" +
+                "box3.setHorizontalAlignment(TextBox.AlignCenter);\u000b" +
+                "box3.setVerticalAlignment(TextBox.AnchorMiddle);\u000b" +
+                "box3.getTextRun().setText(\"*.ppt file\");\u000b" +
+                "box3.setLineWidth(0.75);\u000b" +
+                "box3.setLineColor(Color.black);\u000b" +
+                "box3.getFill().setForegroundColor(new Color(187, 224, 227));\u000b" +
+                "box3.setAnchor(new Rectangle(473, 243, 170, 170));\u000b" +
+                "slide.addShape(box3);\u000b" +
+                "\u000b" +
+                "AutoShape box4 = new AutoShape(ShapeTypes.Arrow);\u000b" +
+                "box4.getFill().setForegroundColor(new Color(187, 224, 227));\u000b" +
+                "box4.setLineWidth(0.75);\u000b" +
+                "box4.setLineColor(Color.black);\u000b" +
+                "box4.setAnchor(new Rectangle(253, 288, 198, 85));\u000b" +
+                "slide.addShape(box4);\u000b" +
+                "\u000b" +
+                "FileOutputStream out = new FileOutputStream(\"hslf-demo.ppt\");\u000b" +
+                "ppt.write(out);\u000b" +
+                "out.close();");
+        box3.setAnchor(new Rectangle(30, 150, 618, 411));
+        box3.setHorizontalCentered(true);
+    }
+
+    public static void slide7(SlideShow<?,?> ppt) throws IOException {
+        Slide<?,?> slide = ppt.createSlide();
+
+        TextBox<?,?> box2 = slide.createTextBox();
+        box2.setHorizontalCentered(true);
+        box2.setVerticalAlignment(VerticalAlignment.MIDDLE);
+        box2.setText("Java Code");
+        box2.setFillColor(new Color(187, 224, 227));
+        box2.setStrokeStyle(0.75, Color.black);
+        box2.setAnchor(new Rectangle(66, 243, 170, 170));
+
+        TextBox<?,?> box3 = slide.createTextBox();
+        box3.setHorizontalCentered(true);
+        box3.setVerticalAlignment(VerticalAlignment.MIDDLE);
+        box3.setText("*.ppt file");
+        box3.setFillColor(new Color(187, 224, 227));
+        box3.setStrokeStyle(0.75, Color.black);
+        box3.setAnchor(new Rectangle(473, 243, 170, 170));
+
+        AutoShape<?,?> box4 = slide.createAutoShape();
+        box4.setShapeType(ShapeType.RIGHT_ARROW);
+        box4.setFillColor(new Color(187, 224, 227));
+        box4.setStrokeStyle(0.75, Color.black);
+        box4.setAnchor(new Rectangle(253, 288, 198, 85));
+    }
+
+    public static void slide8(SlideShow<?,?> ppt) throws IOException {
+        Slide<?,?> slide = ppt.createSlide();
+
+        TextBox<?,?> box1 = slide.createTextBox();
+        box1.setTextPlaceholder(TextPlaceholder.TITLE);
+        box1.setText("Wait, there is more!");
+        box1.setAnchor(new Rectangle(36, 21, 648, 90));
+
+        TextBox<?,?> box2 = slide.createTextBox();
+        box2.setTextPlaceholder(TextPlaceholder.BODY);
+        box2.setText(
+                "Rich text\r" +
+                "Tables\r" +
+                "Pictures (JPEG, PNG, BMP, WMF, PICT)\r" +
+                "Comprehensive formatting features");
+        box2.setAnchor(new Rectangle(36, 126, 648, 356));
+    }
+
+    public static void slide9(SlideShow<?,?> ppt) throws IOException {
+        Slide<?,?> slide = ppt.createSlide();
+
+        TextBox<?,?> box1 = slide.createTextBox();
+        box1.setTextPlaceholder(TextPlaceholder.TITLE);
+        box1.setText("HSLF in Action - 3");
+        box1.setAnchor(new Rectangle(36, 20, 648, 50));
+
+        TextBox<?,?> box2 = slide.createTextBox();
+        box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(18d);
+        box2.setText("PPGraphics2D: PowerPoint Graphics2D driver");
+        box2.setAnchor(new Rectangle(178, 70, 387, 30));
+
+        TextBox<?,?> box3 = slide.createTextBox();
+        TextRun rt3 = box3.getTextParagraphs().get(0).getTextRuns().get(0);
+        rt3.setFontFamily("Courier New");
+        rt3.setFontSize(8d);
+        box3.setText(
+                "//bar chart data. The first value is the bar color, the second is the width\u000b" +
+                "Object[] def = new Object[]{\u000b" +
+                "    Color.yellow, new Integer(100),\u000b" +
+                "    Color.green, new Integer(150),\u000b" +
+                "    Color.gray, new Integer(75),\u000b" +
+                "    Color.red, new Integer(200),\u000b" +
+                "};\u000b" +
+                "\u000b" +
+                "SlideShow ppt = new SlideShow();\u000b" +
+                "Slide slide = ppt.createSlide();\u000b" +
+                "\u000b" +
+                "ShapeGroup group = new ShapeGroup();\u000b" +
+                "//define position of the drawing in the slide\u000b" +
+                "Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);\u000b" +
+                "group.setAnchor(bounds);\u000b" +
+                "slide.addShape(group);\u000b" +
+                "Graphics2D graphics = new PPGraphics2D(group);\u000b" +
+                "\u000b" +
+                "//draw a simple bar graph\u000b" +
+                "int x = bounds.x + 50, y = bounds.y + 50;\u000b" +
+                "graphics.setFont(new Font(\"Arial\", Font.BOLD, 10));\u000b" +
+                "for (int i = 0, idx = 1; i < def.length; i+=2, idx++) {\u000b" +
+                "    graphics.setColor(Color.black);\u000b" +
+                "    int width = ((Integer)def[i+1]).intValue();\u000b" +
+                "    graphics.drawString(\"Q\" + idx, x-20, y+20);\u000b" +
+                "    graphics.drawString(width + \"%\", x + width + 10, y + 20);\u000b" +
+                "    graphics.setColor((Color)def[i]);\u000b" +
+                "    graphics.fill(new Rectangle(x, y, width, 30));\u000b" +
+                "    y += 40;\u000b" +
+                "}\u000b" +
+                "graphics.setColor(Color.black);\u000b" +
+                "graphics.setFont(new Font(\"Arial\", Font.BOLD, 14));\u000b" +
+                "graphics.draw(bounds);\u000b" +
+                "graphics.drawString(\"Performance\", x + 70, y + 40);\u000b" +
+                "\u000b" +
+                "FileOutputStream out = new FileOutputStream(\"hslf-demo.ppt\");\u000b" +
+                "ppt.write(out);\u000b" +
+                "out.close();");
+        box3.setAnchor(new Rectangle(96, 110, 499, 378));
+        box3.setHorizontalCentered(true);
+    }
+
+    public static void slide10(SlideShow<?,?> ppt) throws IOException {
+        //bar chart data. The first value is the bar color, the second is the width
+        Object[] def = new Object[]{
+            Color.yellow, 100,
+            Color.green, 150,
+            Color.gray, 75,
+            Color.red, 200,
+        };
+
+        Slide<?,?> slide = ppt.createSlide();
+
+        GroupShape<?,?> group = slide.createGroup();
+        //define position of the drawing in the slide
+        Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);
+        group.setAnchor(bounds);
+        Graphics2D graphics = new SLGraphics(group);
+
+        //draw a simple bar graph
+        int x = bounds.x + 50;
+        int y = bounds.y + 50;
+        graphics.setFont(new Font("Arial", Font.BOLD, 10));
+        for (int i = 0, idx = 1; i < def.length; i+=2, idx++) {
+            graphics.setColor(Color.black);
+            int width = (Integer) def[i + 1];
+            graphics.drawString("Q" + idx, x-20, y+20);
+            graphics.drawString(width + "%", x + width + 10, y + 20);
+            graphics.setColor((Color)def[i]);
+            graphics.fill(new Rectangle(x, y, width, 30));
+            y += 40;
+        }
+        graphics.setColor(Color.black);
+        graphics.setFont(new Font("Arial", Font.BOLD, 14));
+        graphics.draw(bounds);
+        graphics.drawString("Performance", x + 70, y + 40);
+
+    }
+
+    public static void slide11(SlideShow<?,?> ppt) throws IOException {
+        Slide<?,?> slide = ppt.createSlide();
+
+        TextBox<?,?> box1 = slide.createTextBox();
+        box1.setTextPlaceholder(TextPlaceholder.TITLE);
+        box1.setText("HSLF Development Plans");
+        box1.setAnchor(new Rectangle(36, 21, 648, 90));
+
+        TextBox<?,?> box2 = slide.createTextBox();
+        box2.setTextPlaceholder(TextPlaceholder.BODY);
+        box2.setText(
+            "Support for more PowerPoint functionality\r" +
+            "Rendering slides into java.awt.Graphics2D\r" +
+                "A way to export slides into images or other formats\r" +
+            "Integration with Apache FOP - Formatting Objects Processor\r" +
+                "Transformation of XSL-FO into PPT\r" +
+                "PPT2PDF transcoder"
+        );
+
+        List<? extends TextParagraph<?,?,?>> tp = box2.getTextParagraphs();
+        for (int i : new byte[]{0,1,3}) {
+            tp.get(i).getTextRuns().get(0).setFontSize(28d);
+        }
+        for (int i : new byte[]{2,4,5}) {
+            tp.get(i).getTextRuns().get(0).setFontSize(24d);
+            tp.get(i).setIndentLevel(1);
+        }
+
+        box2.setAnchor(new Rectangle(36, 126, 648, 400));
+    }
+
+    public static void slide12(SlideShow<?,?> ppt) throws IOException {
+        Slide<?,?> slide = ppt.createSlide();
+
+        TextBox<?,?> box1 = slide.createTextBox();
+        box1.setTextPlaceholder(TextPlaceholder.CENTER_TITLE);
+        box1.setText("Questions?");
+        box1.setAnchor(new Rectangle(54, 167, 612, 115));
+
+        TextBox<?,?> box2 = slide.createTextBox();
+        box2.setTextPlaceholder(TextPlaceholder.CENTER_BODY);
+        box2.setText(
+                "https://poi.apache.org/hslf/\r" +
+                "http://people.apache.org/~yegor");
+        box2.setAnchor(new Rectangle(108, 306, 504, 138));
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hslf/BulletsDemo.java b/src/examples/src/org/apache/poi/examples/hslf/BulletsDemo.java
new file mode 100644 (file)
index 0000000..5ab8b86
--- /dev/null
@@ -0,0 +1,60 @@
+/* ====================================================================
+   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.examples.hslf;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFTextBox;
+import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
+
+/**
+ * How to create a single-level bulleted list
+ * and change some of the bullet attributes
+ */
+public final class BulletsDemo {
+
+    public static void main(String[] args) throws IOException {
+        try (HSLFSlideShow ppt = new HSLFSlideShow()) {
+            HSLFSlide slide = ppt.createSlide();
+
+            HSLFTextBox shape = new HSLFTextBox();
+            HSLFTextParagraph rt = shape.getTextParagraphs().get(0);
+            rt.getTextRuns().get(0).setFontSize(42d);
+            rt.setBullet(true);
+            rt.setIndent(0d);  //bullet offset
+            rt.setLeftMargin(50d);   //text offset (should be greater than bullet offset)
+            rt.setBulletChar('\u263A'); //bullet character
+            shape.setText(
+                    "January\r" +
+                            "February\r" +
+                            "March\r" +
+                            "April");
+            slide.addShape(shape);
+
+            shape.setAnchor(new java.awt.Rectangle(50, 50, 500, 300));  //position of the text box in the slide
+            slide.addShape(shape);
+
+            try (FileOutputStream out = new FileOutputStream("bullets.ppt")) {
+                ppt.write(out);
+            }
+        }
+   }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hslf/CreateHyperlink.java b/src/examples/src/org/apache/poi/examples/hslf/CreateHyperlink.java
new file mode 100644 (file)
index 0000000..be8a227
--- /dev/null
@@ -0,0 +1,64 @@
+/* ====================================================================
+   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.examples.hslf;
+
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hslf.usermodel.HSLFHyperlink;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFTextBox;
+
+/**
+ * Demonstrates how to create hyperlinks in PowerPoint presentations
+ */
+public final class CreateHyperlink {
+
+    private CreateHyperlink() {}
+
+    public static void main(String[] args) throws IOException {
+        try (HSLFSlideShow ppt = new HSLFSlideShow()) {
+            HSLFSlide slideA = ppt.createSlide();
+            ppt.createSlide();
+            HSLFSlide slideC = ppt.createSlide();
+
+            // link to a URL
+            HSLFTextBox textBox1 = slideA.createTextBox();
+            textBox1.setText("Apache POI");
+            textBox1.setAnchor(new Rectangle(100, 100, 200, 50));
+
+            HSLFHyperlink link1 = textBox1.getTextParagraphs().get(0).getTextRuns().get(0).createHyperlink();
+            link1.linkToUrl("http://www.apache.org");
+            link1.setLabel(textBox1.getText());
+
+            // link to another slide
+            HSLFTextBox textBox2 = slideA.createTextBox();
+            textBox2.setText("Go to slide #3");
+            textBox2.setAnchor(new Rectangle(100, 300, 200, 50));
+
+            HSLFHyperlink link2 = textBox2.getTextParagraphs().get(0).getTextRuns().get(0).createHyperlink();
+            link2.linkToSlide(slideC);
+
+            try (FileOutputStream out = new FileOutputStream("hyperlink.ppt")) {
+                ppt.write(out);
+            }
+        }
+   }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hslf/DataExtraction.java b/src/examples/src/org/apache/poi/examples/hslf/DataExtraction.java
new file mode 100644 (file)
index 0000000..6996dc8
--- /dev/null
@@ -0,0 +1,148 @@
+/* ====================================================================
+   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.examples.hslf;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.hslf.usermodel.HSLFObjectData;
+import org.apache.poi.hslf.usermodel.HSLFObjectShape;
+import org.apache.poi.hslf.usermodel.HSLFPictureData;
+import org.apache.poi.hslf.usermodel.HSLFPictureShape;
+import org.apache.poi.hslf.usermodel.HSLFShape;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFSoundData;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.usermodel.Paragraph;
+import org.apache.poi.hwpf.usermodel.Range;
+import org.apache.poi.util.IOUtils;
+
+/**
+ * Demonstrates how you can extract misc embedded data from a ppt file
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class DataExtraction {
+
+    private DataExtraction() {}
+
+    public static void main(String[] args) throws Exception {
+
+        if (args.length == 0) {
+            usage();
+            return;
+        }
+
+        try (FileInputStream fis = new FileInputStream(args[0]);
+            HSLFSlideShow ppt = new HSLFSlideShow(fis)) {
+
+            //extract all sound files embedded in this presentation
+            HSLFSoundData[] sound = ppt.getSoundData();
+            for (HSLFSoundData aSound : sound) {
+                handleSound(aSound);
+            }
+
+            int oleIdx = -1;
+            int picIdx = -1;
+            for (HSLFSlide slide : ppt.getSlides()) {
+                //extract embedded OLE documents
+                for (HSLFShape shape : slide.getShapes()) {
+                    if (shape instanceof HSLFObjectShape) {
+                        handleShape((HSLFObjectShape) shape, ++oleIdx);
+                    } else if (shape instanceof HSLFPictureShape) {
+                        handlePicture((HSLFPictureShape) shape, ++picIdx);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void handleShape(HSLFObjectShape ole, int oleIdx) throws IOException {
+        HSLFObjectData data = ole.getObjectData();
+        String name = ole.getInstanceName();
+        switch (name == null ? "" : name) {
+            case "Worksheet":
+                //read xls
+                handleWorkbook(data, name, oleIdx);
+                break;
+            case "Document":
+                //read the word document
+                handleDocument(data, name, oleIdx);
+                break;
+            default:
+                handleUnknown(data, ole.getProgId(), oleIdx);
+                break;
+        }
+
+    }
+
+    private static void handleWorkbook(HSLFObjectData data, String name, int oleIdx) throws IOException {
+        try (InputStream is = data.getInputStream();
+             HSSFWorkbook wb = new HSSFWorkbook(is);
+             FileOutputStream out = new FileOutputStream(name + "-(" + (oleIdx) + ").xls")) {
+            wb.write(out);
+        }
+    }
+
+    private static void handleDocument(HSLFObjectData data, String name, int oleIdx) throws IOException {
+        try (InputStream is = data.getInputStream();
+             HWPFDocument doc = new HWPFDocument(is);
+             FileOutputStream out = new FileOutputStream(name + "-(" + (oleIdx) + ").doc")) {
+            Range r = doc.getRange();
+            for (int k = 0; k < r.numParagraphs(); k++) {
+                Paragraph p = r.getParagraph(k);
+                System.out.println(p.text());
+            }
+
+            //save on disk
+            doc.write(out);
+        }
+    }
+
+    private static void handleUnknown(HSLFObjectData data, String name, int oleIdx) throws IOException {
+        try (InputStream is = data.getInputStream();
+             FileOutputStream out = new FileOutputStream(name + "-" + (oleIdx + 1) + ".dat")) {
+            IOUtils.copy(is, out);
+        }
+    }
+
+    private static void handlePicture(HSLFPictureShape p, int picIdx) throws IOException {
+        HSLFPictureData data = p.getPictureData();
+        String ext = data.getType().extension;
+        try (FileOutputStream out = new FileOutputStream("pict-" + picIdx + ext)) {
+            out.write(data.getData());
+        }
+    }
+
+    private static void handleSound(HSLFSoundData aSound) throws IOException {
+        String type = aSound.getSoundType();  //*.wav
+        String name = aSound.getSoundName();  //typically file name
+
+        //save the sound  on disk
+        try (FileOutputStream out = new FileOutputStream(name + type)) {
+            out.write(aSound.getData());
+        }
+    }
+
+    private static void usage(){
+        System.out.println("Usage: DataExtraction  ppt");
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hslf/Graphics2DDemo.java b/src/examples/src/org/apache/poi/examples/hslf/Graphics2DDemo.java
new file mode 100644 (file)
index 0000000..938b52e
--- /dev/null
@@ -0,0 +1,82 @@
+/* ====================================================================
+   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.examples.hslf;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+
+import org.apache.poi.hslf.usermodel.HSLFGroupShape;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.sl.draw.SLGraphics;
+
+/**
+ * Demonstrates how to draw into a slide using the HSLF Graphics2D driver.
+ */
+public final class Graphics2DDemo {
+
+    private Graphics2DDemo() {}
+
+    /**
+     * A simple bar chart demo
+     */
+    public static void main(String[] args) throws Exception {
+        try (HSLFSlideShow ppt = new HSLFSlideShow();
+             FileOutputStream out = new FileOutputStream("hslf-graphics.ppt")) {
+            //bar chart data. The first value is the bar color, the second is the width
+            Object[] def = {
+                    Color.yellow, 40,
+                    Color.green, 60,
+                    Color.gray, 30,
+                    Color.red, 80,
+            };
+
+            HSLFSlide slide = ppt.createSlide();
+
+            HSLFGroupShape group = new HSLFGroupShape();
+            //define position of the drawing in the slide
+            Rectangle bounds = new Rectangle(200, 100, 350, 300);
+            group.setAnchor(bounds);
+            group.setInteriorAnchor(new Rectangle(0, 0, 100, 100));
+            slide.addShape(group);
+            Graphics2D graphics = new SLGraphics(group);
+
+            //draw a simple bar graph
+            int x = 10, y = 10;
+            graphics.setFont(new Font("Arial", Font.BOLD, 10));
+            for (int i = 0, idx = 1; i < def.length; i += 2, idx++) {
+                graphics.setColor(Color.black);
+                int width = (Integer) def[i + 1];
+                graphics.drawString("Q" + idx, x - 5, y + 10);
+                graphics.drawString(width + "%", x + width + 3, y + 10);
+                graphics.setColor((Color) def[i]);
+                graphics.fill(new Rectangle(x, y, width, 10));
+                y += 15;
+            }
+            graphics.setColor(Color.black);
+            graphics.setFont(new Font("Arial", Font.BOLD, 14));
+            graphics.draw(group.getInteriorAnchor());
+            graphics.drawString("Performance", x + 30, y + 10);
+
+            ppt.write(out);
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hslf/HeadersFootersDemo.java b/src/examples/src/org/apache/poi/examples/hslf/HeadersFootersDemo.java
new file mode 100644 (file)
index 0000000..4dd4349
--- /dev/null
@@ -0,0 +1,50 @@
+/* ====================================================================
+   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.examples.hslf;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hslf.model.HeadersFooters;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+
+/**
+ * Demonstrates how to set headers / footers
+ */
+public final class HeadersFootersDemo {
+    private HeadersFootersDemo() {}
+
+    public static void main(String[] args) throws IOException {
+        try (HSLFSlideShow ppt = new HSLFSlideShow()) {
+            HeadersFooters slideHeaders = ppt.getSlideHeadersFooters();
+            slideHeaders.setFootersText("Created by POI-HSLF");
+            slideHeaders.setSlideNumberVisible(true);
+            slideHeaders.setDateTimeText("custom date time");
+
+            HeadersFooters notesHeaders = ppt.getNotesHeadersFooters();
+            notesHeaders.setFootersText("My notes footers");
+            notesHeaders.setHeaderText("My notes header");
+
+            ppt.createSlide();
+
+            try (FileOutputStream out = new FileOutputStream("headers_footers.ppt")) {
+                ppt.write(out);
+            }
+        }
+    }
+
+}
diff --git a/src/examples/src/org/apache/poi/examples/hslf/Hyperlinks.java b/src/examples/src/org/apache/poi/examples/hslf/Hyperlinks.java
new file mode 100644 (file)
index 0000000..307178d
--- /dev/null
@@ -0,0 +1,77 @@
+/* ====================================================================
+   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.examples.hslf;
+
+import java.io.FileInputStream;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.poi.hslf.usermodel.HSLFHyperlink;
+import org.apache.poi.hslf.usermodel.HSLFSimpleShape;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
+import org.apache.poi.hslf.usermodel.HSLFTextRun;
+
+/**
+ * Demonstrates how to read hyperlinks from  a presentation
+ */
+@SuppressWarnings({"java:S106", "java:S4823"})
+public final class Hyperlinks {
+
+    private Hyperlinks() {}
+
+    public static void main(String[] args) throws Exception {
+        for (String arg : args) {
+            try (FileInputStream is = new FileInputStream(arg);
+                 HSLFSlideShow ppt = new HSLFSlideShow(is)) {
+
+                for (HSLFSlide slide : ppt.getSlides()) {
+                    System.out.println("\nslide " + slide.getSlideNumber());
+
+                    // read hyperlinks from the slide's text runs
+                    System.out.println("- reading hyperlinks from the text runs");
+                    slide.getTextParagraphs().stream().
+                        flatMap(List::stream).
+                        map(HSLFTextParagraph::getTextRuns).
+                        flatMap(List::stream).
+                        forEach(run -> out(run.getHyperlink(), run));
+
+                    // in PowerPoint you can assign a hyperlink to a shape without text,
+                    // for example to a Line object. The code below demonstrates how to
+                    // read such hyperlinks
+                    System.out.println("- reading hyperlinks from the slide's shapes");
+                    slide.getShapes().stream().
+                        filter(sh -> sh instanceof HSLFSimpleShape).
+                        forEach(sh -> out(((HSLFSimpleShape) sh).getHyperlink(), null));
+                }
+            }
+        }
+    }
+
+    private static void out(HSLFHyperlink link, HSLFTextRun run) {
+        if (link == null) {
+            return;
+        }
+        String rawText = run == null ? null : run.getRawText();
+        //in ppt end index is inclusive
+        String formatStr = "title: %1$s, address: %2$s" + (rawText == null ? "" : ", start: %3$s, end: %4$s, substring: %5$s");
+        String line = String.format(Locale.ROOT, formatStr, link.getLabel(), link.getAddress(), link.getStartIndex(), link.getEndIndex(), rawText);
+        System.out.println(line);
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hslf/SoundFinder.java b/src/examples/src/org/apache/poi/examples/hslf/SoundFinder.java
new file mode 100644 (file)
index 0000000..0f6929f
--- /dev/null
@@ -0,0 +1,69 @@
+/* ====================================================================
+   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.examples.hslf;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.apache.poi.hslf.record.InteractiveInfoAtom;
+import org.apache.poi.hslf.record.RecordTypes;
+import org.apache.poi.hslf.usermodel.HSLFShape;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFSoundData;
+
+/**
+ * For each slide iterate over shapes and found associated sound data.
+ */
+@SuppressWarnings({"java:S106", "java:S4823"})
+public final class SoundFinder {
+    private SoundFinder() {}
+
+    public static void main(String[] args) throws IOException {
+        try (FileInputStream fis = new FileInputStream(args[0])) {
+            try (HSLFSlideShow ppt = new HSLFSlideShow(fis)) {
+                HSLFSoundData[] sounds = ppt.getSoundData();
+
+                for (HSLFSlide slide : ppt.getSlides()) {
+                    for (HSLFShape shape : slide.getShapes()) {
+                        int soundRef = getSoundReference(shape);
+                        if (soundRef == -1) continue;
+
+
+                        System.out.println("Slide[" + slide.getSlideNumber() + "], shape[" + shape.getShapeId() + "], soundRef: " + soundRef);
+                        System.out.println("  " + sounds[soundRef].getSoundName());
+                        System.out.println("  " + sounds[soundRef].getSoundType());
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Check if a given shape is associated with a sound.
+     * @return 0-based reference to a sound in the sound collection
+     * or -1 if the shape is not associated with a sound
+     */
+    private static int getSoundReference(HSLFShape shape){
+        int soundRef = -1;
+        //dive into the shape container and search for InteractiveInfoAtom
+        InteractiveInfoAtom info = shape.getClientDataRecord(RecordTypes.InteractiveInfo.typeID);
+        if (info != null && info.getAction() == InteractiveInfoAtom.ACTION_MEDIA) {
+            soundRef = info.getSoundRef();
+        }
+        return soundRef;
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hslf/TableDemo.java b/src/examples/src/org/apache/poi/examples/hslf/TableDemo.java
new file mode 100644 (file)
index 0000000..561ec71
--- /dev/null
@@ -0,0 +1,132 @@
+/* ====================================================================
+   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.examples.hslf;
+
+import java.awt.Color;
+import java.io.FileOutputStream;
+
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFTable;
+import org.apache.poi.hslf.usermodel.HSLFTableCell;
+import org.apache.poi.hslf.usermodel.HSLFTextRun;
+import org.apache.poi.sl.draw.DrawTableShape;
+import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
+import org.apache.poi.sl.usermodel.VerticalAlignment;
+
+/**
+ * Demonstrates how to create tables
+ */
+public final class TableDemo {
+
+    //test data for the first table
+    static final String[][] txt1 = {
+        {"INPUT FILE", "NUMBER OF RECORDS"},
+        {"Item File", "11,559"},
+        {"Vendor File", "502"},
+        {"Purchase History File - # of PO\u2019s\r(12/01/04 - 05/31/06)", "12,852"},
+        {"Purchase History File - # of PO Lines\r(12/01/04 - 05/31/06)", "53,523" },
+        {"Total PO History Spend", "$10,172,038"}
+    };
+
+    //test data for the second taable
+    static final String[][] txt2 = {
+        {"Data Source"},
+        {"CAS Internal Metrics - Item Master Summary\r" +
+         "CAS Internal Metrics - Vendor Summary\r" +
+         "CAS Internal Metrics - PO History Summary"}
+    };
+
+
+    public static void main(String[] args) throws Exception {
+        try (HSLFSlideShow ppt = new HSLFSlideShow()) {
+            HSLFSlide slide = ppt.createSlide();
+            create1stTable(slide);
+            create2ndTable(slide);
+
+            try (FileOutputStream out = new FileOutputStream("hslf-table.ppt")) {
+                ppt.write(out);
+            }
+        }
+    }
+
+    static void create1stTable(HSLFSlide slide) {
+        //six rows, two columns
+        HSLFTable table1 = slide.createTable(6, 2);
+        for (int i = 0; i < txt1.length; i++) {
+            for (int j = 0; j < txt1[i].length; j++) {
+                HSLFTableCell cell = table1.getCell(i, j);
+                HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
+                rt.setFontFamily("Arial");
+                rt.setFontSize(10d);
+                if(i == 0){
+                    cell.getFill().setForegroundColor(new Color(227, 227, 227));
+                } else {
+                    rt.setBold(true);
+                }
+                cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
+                cell.setHorizontalCentered(true);
+                cell.setText(txt1[i][j]);
+            }
+        }
+
+        DrawTableShape dts1 = new DrawTableShape(table1);
+        dts1.setAllBorders(1.0, Color.black);
+
+        table1.setColumnWidth(0, 300);
+        table1.setColumnWidth(1, 150);
+
+        int pgWidth = slide.getSlideShow().getPageSize().width;
+        table1.moveTo((pgWidth - table1.getAnchor().getWidth())/2., 100.);
+    }
+
+    static void create2ndTable(HSLFSlide slide) {
+        //two rows, one column
+        HSLFTable table2 = slide.createTable(2, 1);
+        for (int i = 0; i < txt2.length; i++) {
+            for (int j = 0; j < txt2[i].length; j++) {
+                HSLFTableCell cell = table2.getCell(i, j);
+                HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
+                rt.setFontSize(10d);
+                rt.setFontFamily("Arial");
+                if(i == 0){
+                    cell.getFill().setForegroundColor(new Color(0, 51, 102));
+                    rt.setFontColor(Color.white);
+                    rt.setBold(true);
+                    rt.setFontSize(14d);
+                    cell.setHorizontalCentered(true);
+                } else {
+                    rt.getTextParagraph().setBullet(true);
+                    rt.setFontSize(12d);
+                    rt.getTextParagraph().setTextAlign(TextAlign.LEFT);
+                    cell.setHorizontalCentered(false);
+                }
+                cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
+                cell.setText(txt2[i][j]);
+            }
+        }
+        table2.setColumnWidth(0, 300);
+        table2.setRowHeight(0, 30);
+        table2.setRowHeight(1, 70);
+
+        DrawTableShape dts2 = new DrawTableShape(table2);
+        dts2.setOutsideBorders(Color.black, 1.0);
+
+        table2.moveTo(200, 400);
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hsmf/Msg2txt.java b/src/examples/src/org/apache/poi/examples/hsmf/Msg2txt.java
new file mode 100644 (file)
index 0000000..a4756a2
--- /dev/null
@@ -0,0 +1,158 @@
+/* ====================================================================
+   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.examples.hsmf;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import org.apache.poi.hsmf.MAPIMessage;
+import org.apache.poi.hsmf.datatypes.AttachmentChunks;
+import org.apache.poi.hsmf.exceptions.ChunkNotFoundException;
+
+/**
+ * Reads one or several Outlook MSG files and for each of them creates
+ * a text file from available chunks and a directory that contains
+ * attachments.
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public class Msg2txt {
+
+       /**
+        * The stem used to create file names for the text file and the directory
+        * that contains the attachments.
+        */
+       private String fileNameStem;
+
+       /**
+        * The Outlook MSG file being processed.
+        */
+       private MAPIMessage msg;
+
+       public Msg2txt(String fileName) throws IOException {
+               fileNameStem = fileName;
+               if(fileNameStem.endsWith(".msg") || fileNameStem.endsWith(".MSG")) {
+                       fileNameStem = fileNameStem.substring(0, fileNameStem.length() - 4);
+               }
+               msg = new MAPIMessage(fileName);
+       }
+
+       /**
+        * Processes the message.
+        *
+        * @throws IOException if an exception occurs while writing the message out
+        */
+       public void processMessage() throws IOException {
+               String txtFileName = fileNameStem + ".txt";
+               String attDirName = fileNameStem + "-att";
+        try (PrintWriter txtOut = new PrintWriter(txtFileName)) {
+            try {
+                String displayFrom = msg.getDisplayFrom();
+                txtOut.println("From: " + displayFrom);
+            } catch (ChunkNotFoundException e) {
+                // ignore
+            }
+            try {
+                String displayTo = msg.getDisplayTo();
+                txtOut.println("To: " + displayTo);
+            } catch (ChunkNotFoundException e) {
+                // ignore
+            }
+            try {
+                String displayCC = msg.getDisplayCC();
+                txtOut.println("CC: " + displayCC);
+            } catch (ChunkNotFoundException e) {
+                // ignore
+            }
+            try {
+                String displayBCC = msg.getDisplayBCC();
+                txtOut.println("BCC: " + displayBCC);
+            } catch (ChunkNotFoundException e) {
+                // ignore
+            }
+            try {
+                String subject = msg.getSubject();
+                txtOut.println("Subject: " + subject);
+            } catch (ChunkNotFoundException e) {
+                // ignore
+            }
+            try {
+                String body = msg.getTextBody();
+                txtOut.println(body);
+            } catch (ChunkNotFoundException e) {
+                System.err.println("No message body");
+            }
+
+            AttachmentChunks[] attachments = msg.getAttachmentFiles();
+            if (attachments.length > 0) {
+                File d = new File(attDirName);
+                if (d.mkdir()) {
+                    for (AttachmentChunks attachment : attachments) {
+                        processAttachment(attachment, d);
+                    }
+                } else {
+                    System.err.println("Can't create directory " + attDirName);
+                }
+            }
+        }
+       }
+
+       /**
+        * Processes a single attachment: reads it from the Outlook MSG file and
+        * writes it to disk as an individual file.
+        *
+        * @param attachment the chunk group describing the attachment
+        * @param dir the directory in which to write the attachment file
+        * @throws IOException when any of the file operations fails
+        */
+       public void processAttachment(AttachmentChunks attachment,
+             File dir) throws IOException {
+          String fileName = attachment.getAttachFileName().toString();
+          if(attachment.getAttachLongFileName() != null) {
+             fileName = attachment.getAttachLongFileName().toString();
+          }
+
+               File f = new File(dir, fileName);
+        try (OutputStream fileOut = new FileOutputStream(f)) {
+            fileOut.write(attachment.getAttachData().getValue());
+        }
+       }
+
+       /**
+        * Processes the list of arguments as a list of names of Outlook MSG files.
+        *
+        * @param args the list of MSG files to process
+        */
+       public static void main(String[] args) {
+               if(args.length <= 0) {
+                       System.err.println("No files names provided");
+               } else {
+                       for (String arg : args) {
+                               try {
+                                       Msg2txt processor = new Msg2txt(arg);
+                                       processor.processMessage();
+                               } catch (IOException e) {
+                                       System.err.println("Could not process " + arg + ": " + e);
+                               }
+                       }
+               }
+       }
+
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/eventusermodel/XLS2CSVmra.java b/src/examples/src/org/apache/poi/examples/hssf/eventusermodel/XLS2CSVmra.java
new file mode 100644 (file)
index 0000000..42056d0
--- /dev/null
@@ -0,0 +1,327 @@
+/* ====================================================================
+   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.examples.hssf.eventusermodel;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener;
+import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
+import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
+import org.apache.poi.hssf.eventusermodel.HSSFListener;
+import org.apache.poi.hssf.eventusermodel.HSSFRequest;
+import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;
+import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
+import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
+import org.apache.poi.hssf.record.BOFRecord;
+import org.apache.poi.hssf.record.BlankRecord;
+import org.apache.poi.hssf.record.BoolErrRecord;
+import org.apache.poi.hssf.record.BoundSheetRecord;
+import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.LabelRecord;
+import org.apache.poi.hssf.record.LabelSSTRecord;
+import org.apache.poi.hssf.record.NoteRecord;
+import org.apache.poi.hssf.record.NumberRecord;
+import org.apache.poi.hssf.record.RKRecord;
+import org.apache.poi.hssf.record.SSTRecord;
+import org.apache.poi.hssf.record.StringRecord;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * A XLS -> CSV processor, that uses the MissingRecordAware
+ *  EventModel code to ensure it outputs all columns and rows.
+ * @author Nick Burch
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public class XLS2CSVmra implements HSSFListener {
+       private int minColumns;
+       private POIFSFileSystem fs;
+       private PrintStream output;
+
+       private int lastRowNumber;
+       private int lastColumnNumber;
+
+       /** Should we output the formula, or the value it has? */
+       private boolean outputFormulaValues = true;
+
+       /** For parsing Formulas */
+       private SheetRecordCollectingListener workbookBuildingListener;
+       private HSSFWorkbook stubWorkbook;
+
+       // Records we pick up as we process
+       private SSTRecord sstRecord;
+       private FormatTrackingHSSFListener formatListener;
+
+       /** So we known which sheet we're on */
+       private int sheetIndex = -1;
+       private BoundSheetRecord[] orderedBSRs;
+       private List<BoundSheetRecord> boundSheetRecords = new ArrayList<>();
+
+       // For handling formulas with string results
+       private int nextRow;
+       private int nextColumn;
+       private boolean outputNextStringRecord;
+
+       /**
+        * Creates a new XLS -> CSV converter
+        * @param fs The POIFSFileSystem to process
+        * @param output The PrintStream to output the CSV to
+        * @param minColumns The minimum number of columns to output, or -1 for no minimum
+        */
+       public XLS2CSVmra(POIFSFileSystem fs, PrintStream output, int minColumns) {
+               this.fs = fs;
+               this.output = output;
+               this.minColumns = minColumns;
+       }
+
+       /**
+        * Creates a new XLS -> CSV converter
+        * @param filename The file to process
+        * @param minColumns The minimum number of columns to output, or -1 for no minimum
+        */
+       public XLS2CSVmra(String filename, int minColumns) throws IOException, FileNotFoundException {
+               this(
+                               new POIFSFileSystem(new FileInputStream(filename)),
+                               System.out, minColumns
+               );
+       }
+
+       /**
+        * Initiates the processing of the XLS file to CSV
+        */
+       public void process() throws IOException {
+               MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
+               formatListener = new FormatTrackingHSSFListener(listener);
+
+               HSSFEventFactory factory = new HSSFEventFactory();
+               HSSFRequest request = new HSSFRequest();
+
+               if(outputFormulaValues) {
+                       request.addListenerForAllRecords(formatListener);
+               } else {
+                       workbookBuildingListener = new SheetRecordCollectingListener(formatListener);
+                       request.addListenerForAllRecords(workbookBuildingListener);
+               }
+
+               factory.processWorkbookEvents(request, fs);
+       }
+
+       /**
+        * Main HSSFListener method, processes events, and outputs the
+        *  CSV as the file is processed.
+        */
+       @Override
+    public void processRecord(org.apache.poi.hssf.record.Record record) {
+               int thisRow = -1;
+               int thisColumn = -1;
+               String thisStr = null;
+
+               switch (record.getSid())
+               {
+               case BoundSheetRecord.sid:
+                       boundSheetRecords.add((BoundSheetRecord)record);
+                       break;
+               case BOFRecord.sid:
+                       BOFRecord br = (BOFRecord)record;
+                       if(br.getType() == BOFRecord.TYPE_WORKSHEET) {
+                               // Create sub workbook if required
+                               if(workbookBuildingListener != null && stubWorkbook == null) {
+                                       stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
+                               }
+
+                               // Output the worksheet name
+                               // Works by ordering the BSRs by the location of
+                               //  their BOFRecords, and then knowing that we
+                               //  process BOFRecords in byte offset order
+                               sheetIndex++;
+                               if(orderedBSRs == null) {
+                                       orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
+                               }
+                               output.println();
+                               output.println(
+                                               orderedBSRs[sheetIndex].getSheetname() +
+                                               " [" + (sheetIndex+1) + "]:"
+                               );
+                       }
+                       break;
+
+               case SSTRecord.sid:
+                       sstRecord = (SSTRecord) record;
+                       break;
+
+               case BlankRecord.sid:
+                       BlankRecord brec = (BlankRecord) record;
+
+                       thisRow = brec.getRow();
+                       thisColumn = brec.getColumn();
+                       thisStr = "";
+                       break;
+               case BoolErrRecord.sid:
+                       BoolErrRecord berec = (BoolErrRecord) record;
+
+                       thisRow = berec.getRow();
+                       thisColumn = berec.getColumn();
+                       thisStr = "";
+                       break;
+
+               case FormulaRecord.sid:
+                       FormulaRecord frec = (FormulaRecord) record;
+
+                       thisRow = frec.getRow();
+                       thisColumn = frec.getColumn();
+
+                       if(outputFormulaValues) {
+                               if(Double.isNaN( frec.getValue() )) {
+                                       // Formula result is a string
+                                       // This is stored in the next record
+                                       outputNextStringRecord = true;
+                                       nextRow = frec.getRow();
+                                       nextColumn = frec.getColumn();
+                               } else {
+                                       thisStr = formatListener.formatNumberDateCell(frec);
+                               }
+                       } else {
+                               thisStr = '"' +
+                                       HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"';
+                       }
+                       break;
+               case StringRecord.sid:
+                       if(outputNextStringRecord) {
+                               // String for formula
+                               StringRecord srec = (StringRecord)record;
+                               thisStr = srec.getString();
+                               thisRow = nextRow;
+                               thisColumn = nextColumn;
+                               outputNextStringRecord = false;
+                       }
+                       break;
+
+               case LabelRecord.sid:
+                       LabelRecord lrec = (LabelRecord) record;
+
+                       thisRow = lrec.getRow();
+                       thisColumn = lrec.getColumn();
+                       thisStr = '"' + lrec.getValue() + '"';
+                       break;
+               case LabelSSTRecord.sid:
+                       LabelSSTRecord lsrec = (LabelSSTRecord) record;
+
+                       thisRow = lsrec.getRow();
+                       thisColumn = lsrec.getColumn();
+                       if(sstRecord == null) {
+                               thisStr = '"' + "(No SST Record, can't identify string)" + '"';
+                       } else {
+                               thisStr = '"' + sstRecord.getString(lsrec.getSSTIndex()).toString() + '"';
+                       }
+                       break;
+               case NoteRecord.sid:
+                       NoteRecord nrec = (NoteRecord) record;
+
+                       thisRow = nrec.getRow();
+                       thisColumn = nrec.getColumn();
+                       // TODO: Find object to match nrec.getShapeId()
+                       thisStr = '"' + "(TODO)" + '"';
+                       break;
+               case NumberRecord.sid:
+                       NumberRecord numrec = (NumberRecord) record;
+
+                       thisRow = numrec.getRow();
+                       thisColumn = numrec.getColumn();
+
+                       // Format
+                       thisStr = formatListener.formatNumberDateCell(numrec);
+                       break;
+               case RKRecord.sid:
+                       RKRecord rkrec = (RKRecord) record;
+
+                       thisRow = rkrec.getRow();
+                       thisColumn = rkrec.getColumn();
+                       thisStr = '"' + "(TODO)" + '"';
+                       break;
+               default:
+                       break;
+               }
+
+               // Handle new row
+               if(thisRow != -1 && thisRow != lastRowNumber) {
+                       lastColumnNumber = -1;
+               }
+
+               // Handle missing column
+               if(record instanceof MissingCellDummyRecord) {
+                       MissingCellDummyRecord mc = (MissingCellDummyRecord)record;
+                       thisRow = mc.getRow();
+                       thisColumn = mc.getColumn();
+                       thisStr = "";
+               }
+
+               // If we got something to print out, do so
+               if(thisStr != null) {
+                       if(thisColumn > 0) {
+                               output.print(',');
+                       }
+                       output.print(thisStr);
+               }
+
+               // Update column and row count
+               if(thisRow > -1)
+                       lastRowNumber = thisRow;
+               if(thisColumn > -1)
+                       lastColumnNumber = thisColumn;
+
+               // Handle end of row
+               if(record instanceof LastCellOfRowDummyRecord) {
+                       // Print out any missing commas if needed
+                       if(minColumns > 0) {
+                               // Columns are 0 based
+                               if(lastColumnNumber == -1) { lastColumnNumber = 0; }
+                               for(int i=lastColumnNumber; i<(minColumns); i++) {
+                                       output.print(',');
+                               }
+                       }
+
+                       // We're onto a new row
+                       lastColumnNumber = -1;
+
+                       // End the row
+                       output.println();
+               }
+       }
+
+       public static void main(String[] args) throws Exception {
+               if(args.length < 1) {
+                       System.err.println("Use:");
+                       System.err.println("  XLS2CSVmra <xls file> [min columns]");
+                       System.exit(1);
+               }
+
+               int minColumns = -1;
+               if(args.length >= 2) {
+                       minColumns = Integer.parseInt(args[1]);
+               }
+
+               XLS2CSVmra xls2csv = new XLS2CSVmra(args[0], minColumns);
+               xls2csv.process();
+       }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/AddDimensionedImage.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/AddDimensionedImage.java
new file mode 100644 (file)
index 0000000..129f932
--- /dev/null
@@ -0,0 +1,23 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+/* Placeholder - this is now handled in the Common SS example **/
+public class AddDimensionedImage extends org.apache.poi.examples.ss.AddDimensionedImage {
+}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/Alignment.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/Alignment.java
new file mode 100644 (file)
index 0000000..25affcb
--- /dev/null
@@ -0,0 +1,72 @@
+
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+
+/**
+ * Shows how various alignment options work.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class Alignment {
+    public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet = wb.createSheet("new sheet");
+            HSSFRow row = sheet.createRow(2);
+            createCell(wb, row, 0, HorizontalAlignment.CENTER);
+            createCell(wb, row, 1, HorizontalAlignment.CENTER_SELECTION);
+            createCell(wb, row, 2, HorizontalAlignment.FILL);
+            createCell(wb, row, 3, HorizontalAlignment.GENERAL);
+            createCell(wb, row, 4, HorizontalAlignment.JUSTIFY);
+            createCell(wb, row, 5, HorizontalAlignment.LEFT);
+            createCell(wb, row, 6, HorizontalAlignment.RIGHT);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+
+    /**
+     * Creates a cell and aligns it a certain way.
+     *
+     * @param wb        the workbook
+     * @param row       the row to create the cell in
+     * @param column    the column number to create the cell in
+     * @param align     the alignment for the cell.
+     */
+    private static void createCell(HSSFWorkbook wb, HSSFRow row, int column, HorizontalAlignment align) {
+        HSSFCell cell = row.createCell(column);
+        cell.setCellValue("Align It");
+        HSSFCellStyle cellStyle = wb.createCellStyle();
+        cellStyle.setAlignment(align);
+        cell.setCellStyle(cellStyle);
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/BigExample.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/BigExample.java
new file mode 100644 (file)
index 0000000..f50391a
--- /dev/null
@@ -0,0 +1,169 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFDataFormat;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+
+/**
+ * Demonstrates many features of the user API at once.  Used in the HOW-TO guide.
+ */
+public class BigExample {
+    public static void main(String[] args) throws IOException {
+        int rownum;
+
+        // create a new workbook
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            // create a new sheet
+            HSSFSheet s = wb.createSheet();
+            // declare a row object reference
+            HSSFRow r;
+            // declare a cell object reference
+            HSSFCell c;
+            // create 3 cell styles
+            HSSFCellStyle cs = wb.createCellStyle();
+            HSSFCellStyle cs2 = wb.createCellStyle();
+            HSSFCellStyle cs3 = wb.createCellStyle();
+            // create 2 fonts objects
+            HSSFFont f = wb.createFont();
+            HSSFFont f2 = wb.createFont();
+
+            //set font 1 to 12 point type
+            f.setFontHeightInPoints((short) 12);
+            //make it red
+            f.setColor(HSSFColorPredefined.RED.getIndex());
+            // make it bold
+            //arial is the default font
+            f.setBold(true);
+
+            //set font 2 to 10 point type
+            f2.setFontHeightInPoints((short) 10);
+            //make it the color at palette index 0xf (white)
+            f2.setColor(HSSFColorPredefined.WHITE.getIndex());
+            //make it bold
+            f2.setBold(true);
+
+            //set cell style
+            cs.setFont(f);
+            //set the cell format see HSSFDataFormat for a full list
+            cs.setDataFormat(HSSFDataFormat.getBuiltinFormat("($#,##0_);[Red]($#,##0)"));
+
+            //set a thin border
+            cs2.setBorderBottom(BorderStyle.THIN);
+            //fill w fg fill color
+            cs2.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+            // set foreground fill to red
+            cs2.setFillForegroundColor(HSSFColorPredefined.RED.getIndex());
+
+            // set the font
+            cs2.setFont(f2);
+
+            // set the sheet name to HSSF Test
+            wb.setSheetName(0, "HSSF Test");
+            // create a sheet with 300 rows (0-299)
+            for (rownum = 0; rownum < 300; rownum++) {
+                // create a row
+                r = s.createRow(rownum);
+                // on every other row
+                if ((rownum % 2) == 0) {
+                    // make the row height bigger  (in twips - 1/20 of a point)
+                    r.setHeight((short) 0x249);
+                }
+
+                // create 50 cells (0-49) (the += 2 becomes apparent later
+                for (int cellnum = 0; cellnum < 50; cellnum += 2) {
+                    // create a numeric cell
+                    c = r.createCell(cellnum);
+                    // do some goofy math to demonstrate decimals
+                    c.setCellValue((rownum * 10000.0) + cellnum
+                            + (rownum / 1000.0)
+                            + (cellnum / 10000.0));
+
+                    // on every other row
+                    if ((rownum % 2) == 0) {
+                        // set this cell to the first cell style we defined
+                        c.setCellStyle(cs);
+                    }
+
+                    // create a string cell (see why += 2 in the
+                    c = r.createCell(cellnum + 1);
+
+                    // set the cell's string value to "TEST"
+                    c.setCellValue("TEST");
+                    // make this column a bit wider
+                    s.setColumnWidth(cellnum + 1, (int) ((50 * 8) / ((double) 1 / 20)));
+
+                    // on every other row
+                    if ((rownum % 2) == 0) {
+                        // set this to the white on red cell style
+                        // we defined above
+                        c.setCellStyle(cs2);
+                    }
+
+                }
+            }
+
+            //draw a thick black border on the row at the bottom using BLANKS
+            // advance 2 rows
+            rownum++;
+            rownum++;
+
+            r = s.createRow(rownum);
+
+            // define the third style to be the default
+            // except with a thick black border at the bottom
+            cs3.setBorderBottom(BorderStyle.THICK);
+
+            //create 50 cells
+            for (int cellnum = 0; cellnum < 50; cellnum++) {
+                //create a blank type cell (no value)
+                c = r.createCell(cellnum);
+                // set it to the thick black border style
+                c.setCellStyle(cs3);
+            }
+
+            //end draw thick black border
+
+
+            // demonstrate adding/naming and deleting a sheet
+            // create a sheet, set its title then delete it
+            wb.createSheet();
+            wb.setSheetName(1, "DeletedSheet");
+            wb.removeSheetAt(1);
+            //end deleted sheet
+
+            // create a new file
+            try (FileOutputStream out = new FileOutputStream("workbook.xls")) {
+                // write the workbook to the output stream
+                // close our file (don't blow out our file handles
+                wb.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/Borders.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/Borders.java
new file mode 100644 (file)
index 0000000..fba3b33
--- /dev/null
@@ -0,0 +1,64 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
+import org.apache.poi.ss.usermodel.BorderStyle;
+
+/**
+ * Demonstrates how to create borders around cells.
+ */
+public class Borders {
+    public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet = wb.createSheet("new sheet");
+
+            // Create a row and put some cells in it. Rows are 0 based.
+            HSSFRow row = sheet.createRow(1);
+
+            // Create a cell and put a value in it.
+            HSSFCell cell = row.createCell(1);
+            cell.setCellValue(4);
+
+            // Style the cell with borders all around.
+            HSSFCellStyle style = wb.createCellStyle();
+            style.setBorderBottom(BorderStyle.THIN);
+            style.setBottomBorderColor(HSSFColorPredefined.BLACK.getIndex());
+            style.setBorderLeft(BorderStyle.THIN);
+            style.setLeftBorderColor(HSSFColorPredefined.GREEN.getIndex());
+            style.setBorderRight(BorderStyle.THIN);
+            style.setRightBorderColor(HSSFColorPredefined.BLUE.getIndex());
+            style.setBorderTop(BorderStyle.MEDIUM_DASHED);
+            style.setTopBorderColor(HSSFColorPredefined.ORANGE.getIndex());
+            cell.setCellStyle(style);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/CellComments.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/CellComments.java
new file mode 100644 (file)
index 0000000..6b6434b
--- /dev/null
@@ -0,0 +1,124 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFComment;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.Comment;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.RichTextString;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+
+/**
+ * Demonstrates how to work with excel cell comments.<p>
+ *
+ * Excel comment is a kind of a text shape,
+ * so inserting a comment is very similar to placing a text box in a worksheet
+ */
+public class CellComments {
+
+    public static void main(String[] args) throws IOException  {
+        createWorkbook(false, ".xls");
+        createWorkbook(true, ".xlsx");
+    }
+
+    private static void createWorkbook(boolean xssf, String extension) throws IOException {
+        try (Workbook wb = WorkbookFactory.create(xssf)) {
+            Sheet sheet = wb.createSheet("Cell comments in POI " + extension);
+            CreationHelper creationHelper = wb.getCreationHelper();
+
+            // Create the drawing patriarch. This is the top level container for all shapes including cell comments.
+            Drawing<?> patr = sheet.createDrawingPatriarch();
+
+            //create a cell in row 3
+            Cell cell1 = sheet.createRow(3).createCell(1);
+            cell1.setCellValue(creationHelper.createRichTextString("Hello, World"));
+
+            //anchor defines size and position of the comment in worksheet
+            ClientAnchor clientAnchor = creationHelper.createClientAnchor();
+            clientAnchor.setCol1(4);
+            clientAnchor.setRow1(2);
+            clientAnchor.setCol2(6);
+            clientAnchor.setRow2(5);
+            Comment comment1 = patr.createCellComment(clientAnchor);
+
+            // set text in the comment
+            comment1.setString(creationHelper.createRichTextString("We can set comments in POI"));
+
+            //set comment author.
+            //you can see it in the status bar when moving mouse over the commented cell
+            comment1.setAuthor("Apache Software Foundation");
+
+            // The first way to assign comment to a cell is via Cell.setCellComment method
+            cell1.setCellComment(comment1);
+
+            //create another cell in row 6
+            Cell cell2 = sheet.createRow(6).createCell(1);
+            cell2.setCellValue(36.6);
+
+
+            clientAnchor = creationHelper.createClientAnchor();
+            clientAnchor.setCol1(4);
+            clientAnchor.setRow1(8);
+            clientAnchor.setCol2(6);
+            clientAnchor.setRow2(11);
+            Comment comment2 = patr.createCellComment(clientAnchor);
+            //modify background color of the comment, only available in HSSF currently
+            if (wb instanceof HSSFWorkbook) {
+                ((HSSFComment) comment2).setFillColor(204, 236, 255);
+            }
+
+            RichTextString string = creationHelper.createRichTextString("Normal body temperature");
+
+            //apply custom font to the text in the comment
+            Font font = wb.createFont();
+            font.setFontName("Arial");
+            font.setFontHeightInPoints((short) 10);
+            font.setBold(true);
+            font.setColor(IndexedColors.RED.getIndex());
+            string.applyFont(font);
+
+            comment2.setString(string);
+            comment2.setVisible(true); //by default comments are hidden. This one is always visible.
+
+            comment2.setAuthor("Bill Gates");
+
+            /*
+             * The second way to assign comment to a cell is to implicitly specify its row and column.
+             * Note, it is possible to set row and column of a non-existing cell.
+             * It works, the comment is visible.
+             */
+            comment2.setRow(6);
+            comment2.setColumn(1);
+
+            try (FileOutputStream out = new FileOutputStream("poi_comment" + extension)) {
+                wb.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/CellTypes.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/CellTypes.java
new file mode 100644 (file)
index 0000000..5ba1656
--- /dev/null
@@ -0,0 +1,46 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Date;
+
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.FormulaError;
+
+public class CellTypes {
+    public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet = wb.createSheet("new sheet");
+            HSSFRow row = sheet.createRow(2);
+            row.createCell(0).setCellValue(1.1);
+            row.createCell(1).setCellValue(new Date());
+            row.createCell(2).setCellValue("a string");
+            row.createCell(3).setCellValue(true);
+            row.createCell(4).setCellErrorValue(FormulaError.NUM);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/CreateCells.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/CreateCells.java
new file mode 100644 (file)
index 0000000..8994d6f
--- /dev/null
@@ -0,0 +1,55 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Illustrates how to create cell values.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class CreateCells {
+    public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet = wb.createSheet("new sheet");
+
+            // Create a row and put some cells in it. Rows are 0 based.
+            HSSFRow row = sheet.createRow(0);
+            // Create a cell and put a value in it.
+            HSSFCell cell = row.createCell(0);
+            cell.setCellValue(1);
+
+            // Or do it on one line.
+            row.createCell(1).setCellValue(1.2);
+            row.createCell(2).setCellValue("This is a string");
+            row.createCell(3).setCellValue(true);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/CreateDateCells.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/CreateDateCells.java
new file mode 100644 (file)
index 0000000..b77e0d1
--- /dev/null
@@ -0,0 +1,62 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Date;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFDataFormat;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * An example on how to cells with dates.  The important thing to note
+ * about dates is that they are really normal numeric cells that are
+ * formatted specially.
+ */
+public class CreateDateCells {
+    public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet = wb.createSheet("new sheet");
+
+            // Create a row and put some cells in it. Rows are 0 based.
+            HSSFRow row = sheet.createRow(0);
+
+            // Create a cell and put a date value in it.  The first cell is not styled as a date.
+            HSSFCell cell = row.createCell(0);
+            cell.setCellValue(new Date());
+
+            // we style the second cell as a date (and time).  It is important to create a new cell style from the workbook
+            // otherwise you can end up modifying the built in style and effecting not only this cell but other cells.
+            HSSFCellStyle cellStyle = wb.createCellStyle();
+            cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("m/d/yy h:mm"));
+            cell = row.createCell(1);
+            cell.setCellValue(new Date());
+            cell.setCellStyle(cellStyle);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/EmbeddedObjects.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/EmbeddedObjects.java
new file mode 100644 (file)
index 0000000..149c908
--- /dev/null
@@ -0,0 +1,78 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.Closeable;
+import java.io.FileInputStream;
+
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hssf.usermodel.HSSFObjectData;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.Entry;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * Demonstrates how you can extract embedded data from a .xls file
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class EmbeddedObjects {
+    private EmbeddedObjects() {}
+
+    @SuppressWarnings("unused")
+    public static void main(String[] args) throws Exception {
+        try (
+            FileInputStream fis = new FileInputStream(args[0]);
+            POIFSFileSystem fs = new POIFSFileSystem(fis);
+            HSSFWorkbook workbook = new HSSFWorkbook(fs)
+        ) {
+            for (HSSFObjectData obj : workbook.getAllEmbeddedObjects()) {
+                //the OLE2 Class Name of the object
+                String oleName = obj.getOLE2ClassName();
+                DirectoryNode dn = (obj.hasDirectoryEntry()) ? (DirectoryNode) obj.getDirectory() : null;
+                Closeable document = null;
+                switch (oleName) {
+                    case "Worksheet":
+                        document = new HSSFWorkbook(dn, fs, false);
+                        break;
+                    case "Document":
+                        document = new HWPFDocument(dn);
+                        break;
+                    case "Presentation":
+                        document = new HSLFSlideShow(dn);
+                        break;
+                    default:
+                        if (dn != null) {
+                            // The DirectoryEntry is a DocumentNode. Examine its entries to find out what it is
+                            for (Entry entry : dn) {
+                                String name = entry.getName();
+                            }
+                        } else {
+                            // There is no DirectoryEntry
+                            // Recover the object's data from the HSSFObjectData instance.
+                            byte[] objectData = obj.getObjectData();
+                        }
+                        break;
+                }
+                if (document != null) {
+                    document.close();
+                }
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/EventExample.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/EventExample.java
new file mode 100644 (file)
index 0000000..0e71406
--- /dev/null
@@ -0,0 +1,122 @@
+
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
+import org.apache.poi.hssf.eventusermodel.HSSFListener;
+import org.apache.poi.hssf.eventusermodel.HSSFRequest;
+import org.apache.poi.hssf.record.BOFRecord;
+import org.apache.poi.hssf.record.BoundSheetRecord;
+import org.apache.poi.hssf.record.LabelSSTRecord;
+import org.apache.poi.hssf.record.NumberRecord;
+import org.apache.poi.hssf.record.RowRecord;
+import org.apache.poi.hssf.record.SSTRecord;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * This example shows how to use the event API for reading a file.
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public class EventExample implements HSSFListener {
+    private SSTRecord sstrec;
+
+    /**
+     * This method listens for incoming records and handles them as required.
+     * @param record    The record that was found while reading.
+     */
+    @Override
+    public void processRecord(org.apache.poi.hssf.record.Record record)
+    {
+        switch (record.getSid())
+        {
+            // the BOFRecord can represent either the beginning of a sheet or the workbook
+            case BOFRecord.sid:
+                BOFRecord bof = (BOFRecord) record;
+                if (bof.getType() == BOFRecord.TYPE_WORKBOOK)
+                {
+                    System.out.println("Encountered workbook");
+                    // assigned to the class level member
+                } else if (bof.getType() == BOFRecord.TYPE_WORKSHEET)
+                {
+                    System.out.println("Encountered sheet reference");
+                }
+                break;
+            case BoundSheetRecord.sid:
+                BoundSheetRecord bsr = (BoundSheetRecord) record;
+                System.out.println("New sheet named: " + bsr.getSheetname());
+                break;
+            case RowRecord.sid:
+                RowRecord rowrec = (RowRecord) record;
+                System.out.println("Row found, first column at "
+                        + rowrec.getFirstCol() + " last column at " + rowrec.getLastCol());
+                break;
+            case NumberRecord.sid:
+                NumberRecord numrec = (NumberRecord) record;
+                System.out.println("Cell found with value " + numrec.getValue()
+                        + " at row " + numrec.getRow() + " and column " + numrec.getColumn());
+                break;
+                // SSTRecords store a array of unique strings used in Excel.
+            case SSTRecord.sid:
+                sstrec = (SSTRecord) record;
+                for (int k = 0; k < sstrec.getNumUniqueStrings(); k++)
+                {
+                    System.out.println("String table value " + k + " = " + sstrec.getString(k));
+                }
+                break;
+            case LabelSSTRecord.sid:
+                LabelSSTRecord lrec = (LabelSSTRecord) record;
+                System.out.println("String cell found with value "
+                        + sstrec.getString(lrec.getSSTIndex()));
+                break;
+        }
+    }
+
+    /**
+     * Read an excel file and spit out what we find.
+     *
+     * @param args      Expect one argument that is the file to read.
+     * @throws IOException  When there is an error processing the file.
+     */
+    public static void main(String[] args) throws IOException
+    {
+        // create a new file input stream with the input file specified
+        // at the command line
+        try (FileInputStream fin = new FileInputStream(args[0])) {
+            // create a new org.apache.poi.poifs.filesystem.Filesystem
+            try (POIFSFileSystem poifs = new POIFSFileSystem(fin)) {
+                // get the Workbook (excel part) stream in a InputStream
+                try (InputStream din = poifs.createDocumentInputStream("Workbook")) {
+                    // construct out HSSFRequest object
+                    HSSFRequest req = new HSSFRequest();
+                    // lazy listen for ALL records with the listener shown above
+                    req.addListenerForAllRecords(new EventExample());
+                    // create our event factory
+                    HSSFEventFactory factory = new HSSFEventFactory();
+                    // process our events based on the document input stream
+                    factory.processEvents(req, din);
+                }
+            }
+        }
+        System.out.println("done.");
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/FrillsAndFills.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/FrillsAndFills.java
new file mode 100644 (file)
index 0000000..ca2a61e
--- /dev/null
@@ -0,0 +1,64 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
+import org.apache.poi.ss.usermodel.FillPatternType;
+
+/**
+ * Shows how to use various fills.
+ */
+public class FrillsAndFills {
+    public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet = wb.createSheet("new sheet");
+
+            // Create a row and put some cells in it. Rows are 0 based.
+            HSSFRow row = sheet.createRow(1);
+
+            // Aqua background
+            HSSFCellStyle style = wb.createCellStyle();
+            style.setFillBackgroundColor(HSSFColorPredefined.AQUA.getIndex());
+            style.setFillPattern(FillPatternType.BIG_SPOTS);
+            HSSFCell cell = row.createCell(1);
+            cell.setCellValue("X");
+            cell.setCellStyle(style);
+
+            // Orange "foreground", foreground being the fill foreground not the font color.
+            style = wb.createCellStyle();
+            style.setFillForegroundColor(HSSFColorPredefined.ORANGE.getIndex());
+            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+            cell = row.createCell(2);
+            cell.setCellValue("X");
+            cell.setCellStyle(style);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/HSSFReadWrite.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/HSSFReadWrite.java
new file mode 100644 (file)
index 0000000..f53065d
--- /dev/null
@@ -0,0 +1,251 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFDataFormat;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFRichTextString;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+/**
+ * File for HSSF testing/examples
+ *
+ * THIS IS NOT THE MAIN HSSF FILE!! This is a utility for testing functionality.
+ * It does contain sample API usage that may be educational to regular API
+ * users.
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class HSSFReadWrite {
+
+       private HSSFReadWrite() {}
+
+       /**
+        * creates an {@link HSSFWorkbook} with the specified OS filename.
+        */
+       private static HSSFWorkbook readFile(String filename) throws IOException {
+               try (FileInputStream fis = new FileInputStream(filename)) {
+                       return new HSSFWorkbook(fis);        // NOSONAR - should not be closed here
+               }
+       }
+
+       /**
+        * given a filename this outputs a sample sheet with just a set of
+        * rows/cells.
+        */
+       private static void testCreateSampleSheet(String outputFilename) throws IOException {
+               try (HSSFWorkbook wb = new HSSFWorkbook();
+                        FileOutputStream out = new FileOutputStream(outputFilename)) {
+                       HSSFSheet s = wb.createSheet();
+                       HSSFCellStyle cs = wb.createCellStyle();
+                       HSSFCellStyle cs2 = wb.createCellStyle();
+                       HSSFCellStyle cs3 = wb.createCellStyle();
+                       HSSFFont f = wb.createFont();
+                       HSSFFont f2 = wb.createFont();
+
+                       f.setFontHeightInPoints((short) 12);
+                       f.setColor((short) 0xA);
+                       f.setBold(true);
+                       f2.setFontHeightInPoints((short) 10);
+                       f2.setColor((short) 0xf);
+                       f2.setBold(true);
+                       cs.setFont(f);
+                       cs.setDataFormat(HSSFDataFormat.getBuiltinFormat("($#,##0_);[Red]($#,##0)"));
+                       cs2.setBorderBottom(BorderStyle.THIN);
+                       cs2.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+                       cs2.setFillForegroundColor((short) 0xA);
+                       cs2.setFont(f2);
+                       wb.setSheetName(0, "HSSF Test");
+                       int rownum;
+                       for (rownum = 0; rownum < 300; rownum++) {
+                               HSSFRow r = s.createRow(rownum);
+                               if ((rownum % 2) == 0) {
+                                       r.setHeight((short) 0x249);
+                               }
+
+                               for (int cellnum = 0; cellnum < 50; cellnum += 2) {
+                                       HSSFCell c = r.createCell(cellnum);
+                                       c.setCellValue((rownum * 10000.0) + cellnum
+                                                       + (rownum / 1000.0) + (cellnum / 10000.0));
+                                       if ((rownum % 2) == 0) {
+                                               c.setCellStyle(cs);
+                                       }
+                                       c = r.createCell(cellnum + 1);
+                                       c.setCellValue(new HSSFRichTextString("TEST"));
+                                       // 50 characters divided by 1/20th of a point
+                                       s.setColumnWidth(cellnum + 1, (int) (50 * 8 / 0.05));
+                                       if ((rownum % 2) == 0) {
+                                               c.setCellStyle(cs2);
+                                       }
+                               }
+                       }
+
+                       // draw a thick black border on the row at the bottom using BLANKS
+                       rownum++;
+                       rownum++;
+                       HSSFRow r = s.createRow(rownum);
+                       cs3.setBorderBottom(BorderStyle.THICK);
+                       for (int cellnum = 0; cellnum < 50; cellnum++) {
+                               HSSFCell c = r.createCell(cellnum);
+                               c.setCellStyle(cs3);
+                       }
+                       s.addMergedRegion(new CellRangeAddress(0, 3, 0, 3));
+                       s.addMergedRegion(new CellRangeAddress(100, 110, 100, 110));
+
+                       // end draw thick black border
+                       // create a sheet, set its title then delete it
+                       wb.createSheet();
+                       wb.setSheetName(1, "DeletedSheet");
+                       wb.removeSheetAt(1);
+
+                       // end deleted sheet
+                       wb.write(out);
+               }
+       }
+
+       /**
+     * Method main
+     *
+     * Given 1 argument takes that as the filename, inputs it and dumps the
+     * cell values/types out to sys.out.<br>
+     *
+     * given 2 arguments where the second argument is the word "write" and the
+     * first is the filename - writes out a sample (test) spreadsheet
+     * see {@link HSSFReadWrite#testCreateSampleSheet(String)}.<br>
+     *
+     * given 2 arguments where the first is an input filename and the second
+     * an output filename (not write), attempts to fully read in the
+     * spreadsheet and fully write it out.<br>
+     *
+     * given 3 arguments where the first is an input filename and the second an
+     * output filename (not write) and the third is "modify1", attempts to read in the
+     * spreadsheet, deletes rows 0-24, 74-99.  Changes cell at row 39, col 3 to
+     * "MODIFIED CELL" then writes it out.  Hence this is "modify test 1".  If you
+     * take the output from the write test, you'll have a valid scenario.
+     */
+       public static void main(String[] args) throws Exception {
+               if (args.length < 1) {
+                       System.err.println("At least one argument expected");
+                       return;
+               }
+
+               String fileName = args[0];
+               if (args.length < 2) {
+
+                       try (HSSFWorkbook wb = HSSFReadWrite.readFile(fileName)) {
+                               System.out.println("Data dump:\n");
+
+                               for (int k = 0; k < wb.getNumberOfSheets(); k++) {
+                                       HSSFSheet sheet = wb.getSheetAt(k);
+                                       int rows = sheet.getPhysicalNumberOfRows();
+                                       System.out.println("Sheet " + k + " \"" + wb.getSheetName(k) + "\" has " + rows + " row(s).");
+                                       for (int r = 0; r < rows; r++) {
+                                               HSSFRow row = sheet.getRow(r);
+                                               if (row == null) {
+                                                       continue;
+                                               }
+
+                                               System.out.println("\nROW " + row.getRowNum() + " has " + row.getPhysicalNumberOfCells() + " cell(s).");
+                                               for (int c = 0; c < row.getLastCellNum(); c++) {
+                                                       HSSFCell cell = row.getCell(c);
+                                                       String value;
+
+                                                       if (cell != null) {
+                                                               switch (cell.getCellType()) {
+
+                                                                       case FORMULA:
+                                                                               value = "FORMULA value=" + cell.getCellFormula();
+                                                                               break;
+
+                                                                       case NUMERIC:
+                                                                               value = "NUMERIC value=" + cell.getNumericCellValue();
+                                                                               break;
+
+                                                                       case STRING:
+                                                                               value = "STRING value=" + cell.getStringCellValue();
+                                                                               break;
+
+                                                                       case BLANK:
+                                                                               value = "<BLANK>";
+                                                                               break;
+
+                                                                       case BOOLEAN:
+                                                                               value = "BOOLEAN value-" + cell.getBooleanCellValue();
+                                                                               break;
+
+                                                                       case ERROR:
+                                                                               value = "ERROR value=" + cell.getErrorCellValue();
+                                                                               break;
+
+                                                                       default:
+                                                                               value = "UNKNOWN value of type " + cell.getCellType();
+                                                               }
+                                                               System.out.println("CELL col=" + cell.getColumnIndex() + " VALUE=" + value);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               } else if (args.length == 2) {
+                       if ("write".equalsIgnoreCase(args[1])) {
+                               System.out.println("Write mode");
+                               long time = System.currentTimeMillis();
+                               HSSFReadWrite.testCreateSampleSheet(fileName);
+
+                               System.out.println("" + (System.currentTimeMillis() - time) + " ms generation time");
+                       } else {
+                               System.out.println("readwrite test");
+                               try (HSSFWorkbook wb = HSSFReadWrite.readFile(fileName);
+                                        FileOutputStream stream = new FileOutputStream(args[1])) {
+                                       wb.write(stream);
+                               }
+                       }
+               } else if (args.length == 3 && "modify1".equalsIgnoreCase(args[2])) {
+                       // delete row 0-24, row 74 - 99 && change cell 3 on row 39 to string "MODIFIED CELL!!"
+
+                       try (HSSFWorkbook wb = HSSFReadWrite.readFile(fileName);
+                                FileOutputStream stream = new FileOutputStream(args[1])) {
+                               HSSFSheet sheet = wb.getSheetAt(0);
+
+                               for (int k = 0; k < 25; k++) {
+                                       HSSFRow row = sheet.getRow(k);
+                                       sheet.removeRow(row);
+                               }
+                               for (int k = 74; k < 100; k++) {
+                                       HSSFRow row = sheet.getRow(k);
+                                       sheet.removeRow(row);
+                               }
+                               HSSFRow row = sheet.getRow(39);
+                               HSSFCell cell = row.getCell(3);
+                               cell.setCellValue("MODIFIED CELL!!!!!");
+
+                               wb.write(stream);
+                       }
+               }
+       }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/HyperlinkFormula.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/HyperlinkFormula.java
new file mode 100644 (file)
index 0000000..96fa30a
--- /dev/null
@@ -0,0 +1,45 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Test if hyperlink formula, with url that got more than 127 characters, works
+ */
+public class HyperlinkFormula {
+    public static void main(String[] args) throws IOException {
+       try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet = wb.createSheet("new sheet");
+            HSSFRow row = sheet.createRow(0);
+
+            HSSFCell cell = row.createCell(0);
+            cell.setCellFormula("HYPERLINK(\"http://127.0.0.1:8080/toto/truc/index.html?test=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\", \"test\")");
+
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/Hyperlinks.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/Hyperlinks.java
new file mode 100644 (file)
index 0000000..ae4a37e
--- /dev/null
@@ -0,0 +1,97 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.common.usermodel.HyperlinkType;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFCreationHelper;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFHyperlink;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
+import org.apache.poi.ss.usermodel.Font;
+
+/**
+ * Demonstrates how to create hyperlinks.
+ */
+public class Hyperlinks {
+
+    public static void main(String[] args) throws IOException  {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFCreationHelper helper = wb.getCreationHelper();
+
+            //cell style for hyperlinks
+            //by default hyperlinks are blue and underlined
+            HSSFCellStyle hlinkStyle = wb.createCellStyle();
+            HSSFFont hlinkFont = wb.createFont();
+            hlinkFont.setUnderline(Font.U_SINGLE);
+            hlinkFont.setColor(HSSFColorPredefined.BLUE.getIndex());
+            hlinkStyle.setFont(hlinkFont);
+
+            HSSFCell cell;
+            HSSFSheet sheet = wb.createSheet("Hyperlinks");
+
+            //URL
+            cell = sheet.createRow(0).createCell(0);
+            cell.setCellValue("URL Link");
+            HSSFHyperlink link = helper.createHyperlink(HyperlinkType.URL);
+            link.setAddress("https://poi.apache.org/");
+            cell.setHyperlink(link);
+            cell.setCellStyle(hlinkStyle);
+
+            //link to a file in the current directory
+            cell = sheet.createRow(1).createCell(0);
+            cell.setCellValue("File Link");
+            link = helper.createHyperlink(HyperlinkType.FILE);
+            link.setAddress("link1.xls");
+            cell.setHyperlink(link);
+            cell.setCellStyle(hlinkStyle);
+
+            //e-mail link
+            cell = sheet.createRow(2).createCell(0);
+            cell.setCellValue("Email Link");
+            link = helper.createHyperlink(HyperlinkType.EMAIL);
+            //note, if subject contains white spaces, make sure they are url-encoded
+            link.setAddress("mailto:poi@apache.org?subject=Hyperlinks");
+            cell.setHyperlink(link);
+            cell.setCellStyle(hlinkStyle);
+
+            //link to a place in this workbook
+
+            //create a target sheet and cell
+            HSSFSheet sheet2 = wb.createSheet("Target Sheet");
+            sheet2.createRow(0).createCell(0).setCellValue("Target Cell");
+
+            cell = sheet.createRow(3).createCell(0);
+            cell.setCellValue("Worksheet Link");
+            link = helper.createHyperlink(HyperlinkType.DOCUMENT);
+            link.setAddress("'Target Sheet'!A1");
+            cell.setHyperlink(link);
+            cell.setCellStyle(hlinkStyle);
+
+            try (FileOutputStream out = new FileOutputStream("hssf-links.xls")) {
+                wb.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/InCellLists.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/InCellLists.java
new file mode 100644 (file)
index 0000000..76d0172
--- /dev/null
@@ -0,0 +1,541 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFDataFormat;
+import org.apache.poi.hssf.usermodel.HSSFRichTextString;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * This class contains code that demonstrates how to insert plain, numbered
+ * and bulleted lists into an Excel spreadsheet cell.
+ *
+ * Look at the code contained in the demonstrateMethodCalls() method. It calls
+ * other methods that create plain, numbered and bulleted single and
+ * multi-level lists. The demonstrateMethodCalls() method appears at the top
+ * of the class definition.
+ *
+ * Though different methods are provided to construct single and multi-level
+ * plain, numbered and bulleted lists, close examination will reveal that they
+ * are not strictly necessary. If the inputs to the listInCell() and
+ * multilLevelListInCell() methods are constructed to include the bullet
+ * character or the item numbers then these methods alone may be sufficient.
+ *
+ * @author Mark Beardsley [msb at apache.org]
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public class InCellLists {
+
+    // This character looks like a solid, black, loser case letter 'o'
+    // positioned up from the base line of the text.
+    private static final char BULLET_CHARACTER = '\u2022';
+
+    // The tab character - \t - cannot be used to create a tab space
+    // within a cell as it is rendered as a square. Therefore, four
+    // spaces are used to simulate that character.
+    private static final String TAB = "    ";
+
+    /**
+     * Call each of the list creation methods.
+     *
+     * @param outputFilename A String that encapsulates the name of and path to
+     *                       the Excel spreadsheet file this code will create.
+     */
+    public void demonstrateMethodCalls(String outputFilename) throws IOException {
+        try (HSSFWorkbook workbook = new HSSFWorkbook()) {
+            HSSFSheet sheet = workbook.createSheet("In Cell Lists");
+            HSSFRow row = sheet.createRow(0);
+
+            // Create a cell at A1 and insert a single, bulleted, item into
+            // that cell.
+            HSSFCell cell = row.createCell(0);
+            this.bulletedItemInCell(workbook, "List Item", cell);
+
+            // Create a cell at A2 and insert a plain list - that is one
+            // whose items are neither bulleted or numbered - into that cell.
+            row = sheet.createRow(1);
+            cell = row.createCell(0);
+            List<String> listItems = new ArrayList<>();
+            listItems.add("List Item One.");
+            listItems.add("List Item Two.");
+            listItems.add("List Item Three.");
+            listItems.add("List Item Four.");
+            this.listInCell(workbook, listItems, cell);
+            // The row height and cell width are set here to ensure that the
+            // list may be seen.
+            row.setHeight((short) 1100);
+            sheet.setColumnWidth(0, 9500);
+
+            // Create a cell at A3 and insert a numbered list into that cell.
+            // Note that a couple of items have been added to the listItems
+            // ArrayList
+            row = sheet.createRow(2);
+            cell = row.createCell(0);
+            listItems.add("List Item Five.");
+            listItems.add("List Item Six.");
+            this.numberedListInCell(workbook, listItems, cell, 1, 2);
+            row.setHeight((short) 1550);
+
+            // Create a cell at A4 and insert a numbered list into that cell.
+            // Note that a couple of items have been added to the listItems
+            // ArrayList
+            row = sheet.createRow(3);
+            cell = row.createCell(0);
+            listItems.add("List Item Seven.");
+            listItems.add("List Item Eight.");
+            listItems.add("List Item Nine.");
+            listItems.add("List Item Ten.");
+            this.bulletedListInCell(workbook, listItems, cell);
+            row.setHeight((short) 2550);
+
+            // Insert a plain, multi-level list into cell A5. Note that
+            // the major difference here is that the list items are passed as
+            // an ArrayList of MultiLevelListItems. Note that an ArrayList
+            // of instances of an inner class was used here in preference to
+            // a Hashtable or HashMap as the ArrayList will preserve the
+            // ordering of the items added to it; the first item added will
+            // be the first item recovered and the last item added, the last
+            // item recovered. Alternatively, a LinkedHashMap could be used
+            // to preserve order.
+            row = sheet.createRow(4);
+            cell = row.createCell(0);
+            List<MultiLevelListItem> multiLevelListItems = new ArrayList<>();
+            listItems = new ArrayList<>();
+            listItems.add("ML List Item One - Sub Item One.");
+            listItems.add("ML List Item One - Sub Item Two.");
+            listItems.add("ML List Item One - Sub Item Three.");
+            listItems.add("ML List Item One - Sub Item Four.");
+            multiLevelListItems.add(new MultiLevelListItem("List Item One.", listItems));
+            // Passing either null or an empty ArrayList will signal that
+            // there are no lower level items associated with the top level
+            // item
+            multiLevelListItems.add(new MultiLevelListItem("List Item Two.", null));
+            multiLevelListItems.add(new MultiLevelListItem("List Item Three.", null));
+            listItems = new ArrayList<>();
+            listItems.add("ML List Item Four - Sub Item One.");
+            listItems.add("ML List Item Four - Sub Item Two.");
+            listItems.add("ML List Item Four - Sub Item Three.");
+            multiLevelListItems.add(new MultiLevelListItem("List Item Four.", listItems));
+            this.multiLevelListInCell(workbook, multiLevelListItems, cell);
+            row.setHeight((short) 2800);
+
+            // Insert a numbered multi-level list into cell A6. Note that the
+            // same ArrayList as constructed for the above plain multi-level
+            // list example will be re-used
+            row = sheet.createRow(5);
+            cell = row.createCell(0);
+            this.multiLevelNumberedListInCell(workbook, multiLevelListItems,
+                    cell, 1, 1, 1, 2);
+            row.setHeight((short) 2800);
+
+            // Insert a numbered multi-level list into cell A7. Note that the
+            // same ArrayList as constructed for the plain multi-level list
+            // example will be re-used
+            row = sheet.createRow(6);
+            cell = row.createCell(0);
+            this.multiLevelBulletedListInCell(workbook, multiLevelListItems, cell);
+            row.setHeight((short) 2800);
+
+            // Save the completed workbook
+            try (FileOutputStream fos = new FileOutputStream(new File(outputFilename))) {
+                workbook.write(fos);
+            }
+        } catch (IOException ioEx) {
+            System.out.println("Caught a: " + ioEx.getClass().getName());
+            System.out.println("Message: " + ioEx.getMessage());
+            System.out.println("Stacktrace follows...........");
+            ioEx.printStackTrace(System.out);
+        }
+    }
+
+    /**
+     * Inserts a single bulleted item into a cell.
+     *
+     * @param workbook A reference to the HSSFWorkbook that 'contains' the
+     *                 cell.
+     * @param listItem An instance of the String class encapsulating the
+     *                 items text.
+     * @param cell An instance of the HSSFCell class that encapsulates a
+     *             reference to the spreadsheet cell into which the list item
+     *             will be written.
+     */
+    public void bulletedItemInCell(HSSFWorkbook workbook, String listItem, HSSFCell cell) {
+        // A format String must be built to ensure that the contents of the
+        // cell appear as a bulleted item.
+        HSSFDataFormat format = workbook.createDataFormat();
+        String formatString = InCellLists.BULLET_CHARACTER + " @";
+        int formatIndex = format.getFormat(formatString);
+
+        // Construct an HSSFCellStyle and set it's data formt to use the
+        // object created above.
+        HSSFCellStyle bulletStyle = workbook.createCellStyle();
+        bulletStyle.setDataFormat((short)formatIndex);
+
+        // Set the cells contents and style.
+        cell.setCellValue(new HSSFRichTextString(listItem));
+        cell.setCellStyle(bulletStyle);
+    }
+
+    /**
+     * Inserts a list of plain items - that is items that are neither
+     * numbered or bulleted - into a single cell.
+     *
+     * @param workbook A reference to the HSSFWorkbook that 'contains' the
+     *                 cell.
+     * @param listItems An ArrayList whose elements encapsulate the text for
+     *                  the list's items.
+     * @param cell An instance of the HSSFCell class that encapsulates a
+     *             reference to the spreadsheet cell into which the list
+     *             will be written.
+     */
+    public void listInCell(HSSFWorkbook workbook, List<String> listItems, HSSFCell cell) {
+        StringBuilder buffer = new StringBuilder();
+        HSSFCellStyle wrapStyle = workbook.createCellStyle();
+        wrapStyle.setWrapText(true);
+        for(String listItem : listItems) {
+            buffer.append(listItem);
+            buffer.append("\n");
+        }
+        // The StringBuilder's contents are the source for the contents
+        // of the cell.
+        cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
+        cell.setCellStyle(wrapStyle);
+    }
+
+    /**
+     * Inserts a numbered list into a single cell.
+     *
+     * @param workbook A reference to the HSSFWorkbook that 'contains' the
+     *                 cell.
+     * @param listItems An ArrayList whose elements encapsulate the text for
+     *                  the lists items.
+     * @param cell An instance of the HSSFCell class that encapsulates a
+     *             reference to the spreadsheet cell into which the list
+     *             will be written.
+     * @param startingValue A primitive int containing the number for the first
+     *                      item in the list.
+     * @param increment A primitive int containing the value that should be used
+     *                  to calculate subsequent item numbers.
+     */
+    public void numberedListInCell(HSSFWorkbook workbook,
+                                   List<String> listItems,
+                                   HSSFCell cell,
+                                   int startingValue,
+                                   int increment) {
+        StringBuilder buffer = new StringBuilder();
+        int itemNumber = startingValue;
+        // Note that again, an HSSFCellStye object is required and that
+        // it's wrap text property should be set to 'true'
+        HSSFCellStyle wrapStyle = workbook.createCellStyle();
+        wrapStyle.setWrapText(true);
+        // Note that the basic method is identical to the listInCell() method
+        // with one difference; a number prefixed to the items text.
+        for(String listItem : listItems) {
+            buffer.append(itemNumber).append(". ");
+            buffer.append(listItem);
+            buffer.append("\n");
+            itemNumber += increment;
+        }
+        // The StringBuilder's contents are the source for the contents
+        // of the cell.
+        cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
+        cell.setCellStyle(wrapStyle);
+    }
+
+    /**
+     * Insert a bulleted list into a cell.
+     *
+     * @param workbook A reference to the HSSFWorkbook that 'contains' the
+     *                 cell.
+     * @param listItems An ArrayList whose elements encapsulate the text for
+     *                  the lists items.
+     * @param cell An instance of the HSSFCell class that encapsulates a
+     *             reference to the spreadsheet cell into which the list
+     *             will be written.
+     */
+    public void bulletedListInCell(HSSFWorkbook workbook,
+                                   List<String> listItems,
+                                   HSSFCell cell) {
+        StringBuilder buffer = new StringBuilder();
+        // Note that again, an HSSFCellStye object is required and that
+        // it's wrap text property should be set to 'true'
+        HSSFCellStyle wrapStyle = workbook.createCellStyle();
+        wrapStyle.setWrapText(true);
+        // Note that the basic method is identical to the listInCell() method
+        // with one difference; the bullet character prefixed to the items text.
+        for(String listItem : listItems) {
+            buffer.append(InCellLists.BULLET_CHARACTER + " ");
+            buffer.append(listItem);
+            buffer.append("\n");
+        }
+        // The StringBuilder's contents are the source for the contents
+        // of the cell.
+        cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
+        cell.setCellStyle(wrapStyle);
+    }
+
+    /**
+     * Insert a multi-level list into a cell.
+     *
+     * @param workbook A reference to the HSSFWorkbook that 'contains' the
+     *                 cell.
+     * @param multiLevelListItems An ArrayList whose elements contain instances
+     *                            of the MultiLevelListItem class. Each element
+     *                            encapsulates the text for the high level item
+     *                            along with an ArrayList. Each element of this
+     *                            ArrayList encapsulates the text for a lower
+     *                            level item.
+     * @param cell An instance of the HSSFCell class that encapsulates a
+     *             reference to the spreadsheet cell into which the list
+     *             will be written.
+     */
+    public void multiLevelListInCell(HSSFWorkbook workbook,
+                                     List<MultiLevelListItem> multiLevelListItems,
+                                     HSSFCell cell) {
+        StringBuilder buffer = new StringBuilder();
+        // Note that again, an HSSFCellStye object is required and that
+        // it's wrap text property should be set to 'true'
+        HSSFCellStyle wrapStyle = workbook.createCellStyle();
+        wrapStyle.setWrapText(true);
+        // Step through the ArrayList of MultilLevelListItem instances.
+        for(MultiLevelListItem multiLevelListItem : multiLevelListItems) {
+            // For each element in the ArrayList, get the text for the high
+            // level list item......
+            buffer.append(multiLevelListItem.getItemText());
+            buffer.append("\n");
+            // and then an ArrayList whose elements encapsulate the text
+            // for the lower level list items.
+            List<String> lowerLevelItems = multiLevelListItem.getLowerLevelItems();
+            if (lowerLevelItems == null || lowerLevelItems.isEmpty()) {
+                continue;
+            }
+            for(String item : lowerLevelItems) {
+                buffer.append(InCellLists.TAB);
+                buffer.append(item);
+                buffer.append("\n");
+            }
+        }
+        // The StringBuilder's contents are the source for the contents
+        // of the cell.
+        cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
+        cell.setCellStyle(wrapStyle);
+    }
+
+    /**
+     * Insert a multi-level list into a cell.
+     *
+     * @param workbook A reference to the HSSFWorkbook that 'contains' the
+     *                 cell.
+     * @param multiLevelListItems An ArrayList whose elements contain instances
+     *                            of the MultiLevelListItem class. Each element
+     *                            encapsulates the text for the high level item
+     *                            along with an ArrayList. Each element of this
+     *                            ArrayList encapsulates the text for a lower
+     *                            level item.
+     * @param cell An instance of the HSSFCell class that encapsulates a
+     *             reference to the spreadsheet cell into which the list
+     *             will be written.
+     * @param highLevelStartingValue A primitive int containing the number
+     *                               for the first high level item in the list.
+     * @param highLevelIncrement A primitive int containing the value that
+     *                           should be used to calculate the number of
+     *                           subsequent high level item.
+     * @param lowLevelStartingValue A primitive int will containing the number
+     *                              for the first low level item associated
+     *                              with a high level item.
+     * @param lowLevelIncrement A primitive int containing the value that
+     *                          should be used to calculate the number of
+     *                          subsequent low level item.
+     */
+    public void multiLevelNumberedListInCell(HSSFWorkbook workbook,
+                                             List<MultiLevelListItem> multiLevelListItems,
+                                             HSSFCell cell,
+                                             int highLevelStartingValue,
+                                             int highLevelIncrement,
+                                             int lowLevelStartingValue,
+                                             int lowLevelIncrement) {
+        StringBuilder buffer = new StringBuilder();
+        int highLevelItemNumber = highLevelStartingValue;
+        // Note that again, an HSSFCellStye object is required and that
+        // it's wrap text property should be set to 'true'
+        HSSFCellStyle wrapStyle = workbook.createCellStyle();
+        wrapStyle.setWrapText(true);
+        // Step through the ArrayList of MultilLevelListItem instances.
+        for(MultiLevelListItem multiLevelListItem : multiLevelListItems) {
+            // For each element in the ArrayList, get the text for the high
+            // level list item......
+            buffer.append(highLevelItemNumber);
+            buffer.append(". ");
+            buffer.append(multiLevelListItem.getItemText());
+            buffer.append("\n");
+            // and then an ArrayList whose elements encapsulate the text
+            // for the lower level list items.
+            List<String> lowerLevelItems = multiLevelListItem.getLowerLevelItems();
+            if(lowerLevelItems != null && !lowerLevelItems.isEmpty()) {
+                int lowLevelItemNumber = lowLevelStartingValue;
+                for(String item : lowerLevelItems) {
+                    buffer.append(InCellLists.TAB);
+                    buffer.append(highLevelItemNumber);
+                    buffer.append(".");
+                    buffer.append(lowLevelItemNumber);
+                    buffer.append(" ");
+                    buffer.append(item);
+                    buffer.append("\n");
+                    lowLevelItemNumber += lowLevelIncrement;
+                }
+            }
+            highLevelItemNumber += highLevelIncrement;
+        }
+        // The StringBuilder's contents are the source for the contents
+        // of the cell.
+        cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
+        cell.setCellStyle(wrapStyle);
+    }
+
+    /**
+     * Insert a bulleted multi-level list into a cell.
+     *
+     * @param workbook A reference to the HSSFWorkbook that 'contains' the
+     *                 cell.
+     * @param multiLevelListItems An ArrayList whose elements contain instances
+     *                            of the MultiLevelListItem class. Each element
+     *                            encapsulates the text for the high level item
+     *                            along with an ArrayList. Each element of this
+     *                            ArrayList encapsulates the text for a lower
+     *                            level item.
+     * @param cell An instance of the HSSFCell class that encapsulates a
+     *             reference to the spreadsheet cell into which the list
+     *             will be written.
+     */
+    public void multiLevelBulletedListInCell(HSSFWorkbook workbook,
+                                             List<MultiLevelListItem> multiLevelListItems,
+                                             HSSFCell cell) {
+        StringBuilder buffer = new StringBuilder();
+        // Note that again, an HSSFCellStye object is required and that
+        // it's wrap text property should be set to 'true'
+        HSSFCellStyle wrapStyle = workbook.createCellStyle();
+        wrapStyle.setWrapText(true);
+        // Step through the ArrayList of MultilLevelListItem instances.
+        for(MultiLevelListItem multiLevelListItem : multiLevelListItems) {
+            // For each element in the ArrayList, get the text for the high
+            // level list item......
+            buffer.append(InCellLists.BULLET_CHARACTER);
+            buffer.append(" ");
+            buffer.append(multiLevelListItem.getItemText());
+            buffer.append("\n");
+            // and then an ArrayList whose elements encapsulate the text
+            // for the lower level list items.
+            List<String> lowerLevelItems = multiLevelListItem.getLowerLevelItems();
+            if(lowerLevelItems != null && !lowerLevelItems.isEmpty()) {
+                for(String item : lowerLevelItems) {
+                    buffer.append(InCellLists.TAB);
+                    buffer.append(InCellLists.BULLET_CHARACTER);
+                    buffer.append(" ");
+                    buffer.append(item);
+                    buffer.append("\n");
+                }
+            }
+        }
+        // The StringBuilder's contents are the source for the contents
+        // of the cell.
+        cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
+        cell.setCellStyle(wrapStyle);
+    }
+
+    /**
+     * The main entry point to the program. Demonstrates how to call the method
+     * that will create an Excel workbook containing many different sorts of
+     * lists.
+     *
+     * @param args the command line arguments.
+     */
+    public static void main(String[] args) throws IOException {
+        new InCellLists().demonstrateMethodCalls("Latest In Cell List.xls");
+    }
+
+    /**
+     * An instance of this inner class models an item or element in a
+     * multi-level list. Each multi-level list item consists of the text for the
+     * high level items and an ArrayList containing the text for each of the
+     * associated lower level items. When written into a cell, each multi-level
+     * list item will have this general appearance.
+     *
+     *     Item One
+     *         Sub Item One.
+     *         Sub Item Two.
+     *     Item Two
+     *         Sub Item One.
+     *         Sub Item Two.
+     *     etc.
+     *
+     * It would be quite possible to modify this class to model much more
+     * complex list structures descending through two, three or even more
+     * levels.
+     */
+    public final class MultiLevelListItem {
+
+        private String itemText;
+        private List<String> lowerLevelItems;
+
+        /**
+         * Create a new instance of the MultiLevelListItem class using the
+         * following parameters.
+         *
+         * @param itemText A String that encapsulates the text for the high
+         *                 level list item.
+         * @param lowerLevelItems An ArrayList whose elements encapsulate the
+         *                        text for the associated lower level list
+         *                        items.
+         */
+        public MultiLevelListItem(String itemText, List<String> lowerLevelItems) {
+            this.itemText = itemText;
+            this.lowerLevelItems = lowerLevelItems;
+        }
+
+        /**
+         * Get the text for the high level list item.
+         *
+         * @return A String that encapsulates the text for the high level list
+         *         item.
+         */
+        public String getItemText() {
+            return(this.itemText);
+        }
+
+        /**
+         * Get the text for the associated lower level list items.
+         *
+         * @return An ArrayList whose elements each encapsulate the text for a
+         *         single associated lower level list item.
+         */
+        public List<String> getLowerLevelItems() {
+            return lowerLevelItems;
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/MergedCells.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/MergedCells.java
new file mode 100644 (file)
index 0000000..16114b2
--- /dev/null
@@ -0,0 +1,49 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+/**
+ * An example of how to merge regions of cells.
+ */
+public class MergedCells {
+   public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+             HSSFSheet sheet = wb.createSheet("new sheet");
+
+             HSSFRow row = sheet.createRow(1);
+             HSSFCell cell = row.createCell(1);
+             cell.setCellValue("This is a test of merging");
+
+             sheet.addMergedRegion(new CellRangeAddress(1, 1, 1, 2));
+
+             // Write the output to a file
+             try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                  wb.write(fileOut);
+             }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/NewLinesInCells.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/NewLinesInCells.java
new file mode 100644 (file)
index 0000000..487668d
--- /dev/null
@@ -0,0 +1,57 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Demonstrates how to use newlines in cells.
+ */
+public class NewLinesInCells {
+    public static void main( String[] args ) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+                       HSSFSheet s = wb.createSheet();
+                       HSSFFont f2 = wb.createFont();
+
+                       HSSFCellStyle cs = wb.createCellStyle();
+
+                       cs.setFont(f2);
+                       // Word Wrap MUST be turned on
+                       cs.setWrapText(true);
+
+                       HSSFRow r = s.createRow(2);
+                       r.setHeight((short) 0x349);
+                       HSSFCell c = r.createCell(2);
+                       c.setCellValue("Use \n with word wrap on to create a new line");
+                       c.setCellStyle(cs);
+                       s.setColumnWidth(2, (int) ((50 * 8) / ((double) 1 / 20)));
+
+                       try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                               wb.write(fileOut);
+                       }
+               }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/NewSheet.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/NewSheet.java
new file mode 100644 (file)
index 0000000..d2d8f31
--- /dev/null
@@ -0,0 +1,44 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.util.WorkbookUtil;
+
+/**
+ * Creates a new workbook with a sheet that's been explicitly defined.
+ */
+public abstract class NewSheet {
+    public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            wb.createSheet("new sheet");
+            // create with default name
+            wb.createSheet();
+            final String name = "second sheet";
+            // setting sheet name later
+            wb.setSheetName(1, WorkbookUtil.createSafeSheetName(name));
+
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/NewWorkbook.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/NewWorkbook.java
new file mode 100644 (file)
index 0000000..16c0e04
--- /dev/null
@@ -0,0 +1,38 @@
+
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * This example creates a new blank workbook.  This workbook will contain a single blank sheet.
+ */
+public class NewWorkbook {
+    public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/OfficeDrawing.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/OfficeDrawing.java
new file mode 100644 (file)
index 0000000..4603864
--- /dev/null
@@ -0,0 +1,330 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFChildAnchor;
+import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFPatriarch;
+import org.apache.poi.hssf.usermodel.HSSFPicture;
+import org.apache.poi.hssf.usermodel.HSSFPolygon;
+import org.apache.poi.hssf.usermodel.HSSFRichTextString;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFShape;
+import org.apache.poi.hssf.usermodel.HSSFShapeGroup;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFSimpleShape;
+import org.apache.poi.hssf.usermodel.HSSFTextbox;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * Demonstrates how to use the office drawing capabilities of POI.
+ */
+public final class OfficeDrawing {
+    private OfficeDrawing() {}
+
+    public static void main(String[] args) throws IOException {
+        // Create the workbook and sheets.
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet1 = wb.createSheet("new sheet");
+            HSSFSheet sheet2 = wb.createSheet("second sheet");
+            HSSFSheet sheet3 = wb.createSheet("third sheet");
+            HSSFSheet sheet4 = wb.createSheet("fourth sheet");
+            HSSFSheet sheet5 = wb.createSheet("fifth sheet");
+
+            // Draw stuff in them
+            drawSheet1(sheet1);
+            drawSheet2(sheet2);
+            drawSheet3(sheet3);
+            drawSheet4(sheet4, wb);
+            drawSheet5(sheet5, wb);
+
+            // Write the file out.
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+
+    private static void drawSheet1( HSSFSheet sheet1 )
+    {
+        // Create a row and size one of the cells reasonably large.
+        HSSFRow row = sheet1.createRow(2);
+        row.setHeight((short) 2800);
+        row.createCell(1);
+        sheet1.setColumnWidth(2, 9000);
+
+        // Create the drawing patriarch.  This is the top level container for
+        // all shapes.
+        HSSFPatriarch patriarch = sheet1.createDrawingPatriarch();
+
+        // Draw some lines and an oval.
+        drawLinesToCenter( patriarch );
+        drawManyLines( patriarch );
+        drawOval( patriarch );
+        drawPolygon( patriarch );
+
+        // Draw a rectangle.
+        HSSFSimpleShape rect = patriarch.createSimpleShape( new HSSFClientAnchor(100, 100, 900, 200, (short)0, 0, (short)0, 0) );
+        rect.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE);
+    }
+
+    private static void drawSheet2( HSSFSheet sheet2 )
+    {
+        // Create a row and size one of the cells reasonably large.
+        HSSFRow row = sheet2.createRow(2);
+        row.createCell(1);
+        row.setHeightInPoints(240);
+        sheet2.setColumnWidth(2, 9000);
+
+        // Create the drawing patriarch.  This is the top level container for
+        // all shapes. This will clear out any existing shapes for that sheet.
+        HSSFPatriarch patriarch = sheet2.createDrawingPatriarch();
+
+        // Draw a grid in one of the cells.
+        drawGrid( patriarch );
+    }
+
+    private static void drawSheet3( HSSFSheet sheet3 )
+    {
+        // Create a row and size one of the cells reasonably large
+        HSSFRow row = sheet3.createRow(2);
+        row.setHeightInPoints(140);
+        row.createCell(1);
+        sheet3.setColumnWidth(2, 9000);
+
+        // Create the drawing patriarch.  This is the top level container for
+        // all shapes. This will clear out any existing shapes for that sheet.
+        HSSFPatriarch patriarch = sheet3.createDrawingPatriarch();
+
+        // Create a shape group.
+        HSSFShapeGroup group = patriarch.createGroup(
+                new HSSFClientAnchor(0,0,900,200,(short)2,2,(short)2,2));
+
+        // Create a couple of lines in the group.
+        HSSFSimpleShape shape1 = group.createShape(new HSSFChildAnchor(3,3,500,500));
+        shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+        ( (HSSFChildAnchor) shape1.getAnchor() ).setAnchor((short)3,3,500,500);
+        HSSFSimpleShape shape2 = group.createShape(new HSSFChildAnchor((short)1,200,400,600));
+        shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+
+    }
+
+    private static void drawSheet4( HSSFSheet sheet4, HSSFWorkbook wb )
+    {
+        // Create the drawing patriarch.  This is the top level container for
+        // all shapes. This will clear out any existing shapes for that sheet.
+        HSSFPatriarch patriarch = sheet4.createDrawingPatriarch();
+
+        // Create a couple of textboxes
+        HSSFTextbox textbox1 = patriarch.createTextbox(
+                new HSSFClientAnchor(0,0,0,0,(short)1,1,(short)2,2));
+        textbox1.setString(new HSSFRichTextString("This is a test") );
+        HSSFTextbox textbox2 = patriarch.createTextbox(
+                new HSSFClientAnchor(0,0,900,100,(short)3,3,(short)3,4));
+        textbox2.setString(new HSSFRichTextString("Woo") );
+        textbox2.setFillColor(200,0,0);
+        textbox2.setLineStyle(HSSFShape.LINESTYLE_DOTGEL);
+
+        // Create third one with some fancy font styling.
+        HSSFTextbox textbox3 = patriarch.createTextbox(
+                new HSSFClientAnchor(0,0,900,100,(short)4,4,(short)5,4+1));
+        HSSFFont font = wb.createFont();
+        font.setItalic(true);
+        font.setUnderline(Font.U_DOUBLE);
+        HSSFRichTextString string = new HSSFRichTextString("Woo!!!");
+        string.applyFont(2,5,font);
+        textbox3.setString(string );
+        textbox3.setFillColor(0x08000030);
+        textbox3.setLineStyle(HSSFShape.LINESTYLE_NONE);  // no line around the textbox.
+        textbox3.setNoFill(true);    // make it transparent
+    }
+
+    private static void drawSheet5( HSSFSheet sheet5, HSSFWorkbook wb ) throws IOException
+    {
+
+        // Create the drawing patriarch.  This is the top level container for
+        // all shapes. This will clear out any existing shapes for that sheet.
+        HSSFPatriarch patriarch = sheet5.createDrawingPatriarch();
+
+        HSSFClientAnchor anchor;
+        anchor = new HSSFClientAnchor(0,0,0,255,(short)2,2,(short)4,7);
+        anchor.setAnchorType( AnchorType.MOVE_DONT_RESIZE );
+        patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4.png", wb ));
+
+        anchor = new HSSFClientAnchor(0,0,0,255,(short)4,2,(short)5,7);
+        anchor.setAnchorType( AnchorType.MOVE_DONT_RESIZE );
+        patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4edited.png", wb ));
+
+        anchor = new HSSFClientAnchor(0,0,1023,255,(short)6,2,(short)8,7);
+        anchor.setAnchorType( AnchorType.MOVE_DONT_RESIZE );
+        HSSFPicture picture = patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4s.png", wb ));
+        //Reset the image to the original size.
+        picture.resize();
+        picture.setLineStyle( HSSFShape.LINESTYLE_DASHDOTGEL );
+
+    }
+
+    private static int loadPicture( String path, HSSFWorkbook wb ) throws IOException
+    {
+        int pictureIndex;
+        try (FileInputStream fis = new FileInputStream(path);
+             ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
+            int c;
+            while ((c = fis.read()) != -1)
+                bos.write(c);
+            pictureIndex = wb.addPicture(bos.toByteArray(), Workbook.PICTURE_TYPE_PNG);
+        }
+        return pictureIndex;
+    }
+
+    private static void drawOval( HSSFPatriarch patriarch )
+    {
+        // Create an oval and style to taste.
+        HSSFClientAnchor a = new HSSFClientAnchor();
+        a.setAnchor((short)2, 2, 20, 20, (short) 2, 2, 190, 80);
+        HSSFSimpleShape s = patriarch.createSimpleShape(a);
+        s.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
+        s.setLineStyleColor(10,10,10);
+        s.setFillColor(90,10,200);
+        s.setLineWidth(HSSFShape.LINEWIDTH_ONE_PT * 3);
+        s.setLineStyle(HSSFShape.LINESTYLE_DOTSYS);
+    }
+
+    private static void drawPolygon( HSSFPatriarch patriarch )
+    {
+        //        HSSFClientAnchor a = new HSSFClientAnchor( 0, 0, 1023, 255, (short) 2, 2, (short) 3, 3 );
+        //        HSSFPolygon p = patriarch.createPolygon(a);
+        //        p.setPolygonDrawArea(100,100);
+        //        p.setPoints( new int[]{30, 90, 50}, new int[]{88, 5, 44} );
+
+
+        HSSFClientAnchor a = new HSSFClientAnchor();
+        a.setAnchor( (short) 2, 2, 0, 0, (short) 3, 3, 1023, 255 );
+        HSSFShapeGroup g = patriarch.createGroup( a );
+        g.setCoordinates(0,0,200,200);
+        HSSFPolygon p1 = g.createPolygon( new HSSFChildAnchor( 0, 0, 200, 200 ) );
+        p1.setPolygonDrawArea( 100, 100 );
+        p1.setPoints( new int[]{0, 90, 50}, new int[]{5, 5, 44} );
+        p1.setFillColor( 0, 255, 0 );
+        HSSFPolygon p2 = g.createPolygon( new HSSFChildAnchor( 20, 20, 200, 200 ) );
+        p2.setPolygonDrawArea( 200, 200 );
+        p2.setPoints( new int[]{120, 20, 150}, new int[]{105, 30, 195} );
+        p2.setFillColor( 255, 0, 0 );
+    }
+
+    private static void drawManyLines( HSSFPatriarch patriarch )
+    {
+        // Draw bunch of lines
+        int x1 = 100;
+        int y1 = 100;
+        int x2 = 800;
+        int y2 = 200;
+        int color = 0;
+        for (int i = 0; i < 10; i++)
+        {
+            HSSFClientAnchor a2 = new HSSFClientAnchor();
+            a2.setAnchor((short) 2, 2, x1, y1, (short) 2, 2, x2, y2);
+            HSSFSimpleShape shape2 = patriarch.createSimpleShape(a2);
+            shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+            shape2.setLineStyleColor(color);
+            y1 -= 10;
+            y2 -= 10;
+            color += 30;
+        }
+    }
+
+    private static void drawGrid( HSSFPatriarch patriarch )
+    {
+        // This draws a grid of lines.  Since the coordinates space fixed at
+        // 1024 by 256 we use a ratio to get a reasonably square grids.
+
+        double xRatio = 3.22;
+        double yRatio = 0.6711;
+
+        int x1 = 0;
+        int y1 = 0;
+        int x2 = 0;
+        int y2 = 200;
+        for (int i = 0; i < 20; i++)
+        {
+            HSSFClientAnchor a2 = new HSSFClientAnchor();
+            a2.setAnchor((short) 2, 2, (int) ( x1 * xRatio ), (int) ( y1 * yRatio ),
+                    (short) 2, 2, (int) ( x2 * xRatio ), (int) ( y2 * yRatio ));
+            HSSFSimpleShape shape2 = patriarch.createSimpleShape(a2);
+            shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+
+            x1 += 10;
+            x2 += 10;
+        }
+
+        x1 = 0;
+        y1 = 0;
+        x2 = 200;
+        y2 = 0;
+        for (int i = 0; i < 20; i++)
+        {
+            HSSFClientAnchor a2 = new HSSFClientAnchor();
+            a2.setAnchor((short) 2, 2, (int) ( x1 * xRatio ), (int) ( y1 * yRatio ),
+                    (short) 2, 2, (int) ( x2 * xRatio ), (int) ( y2 * yRatio ));
+            HSSFSimpleShape shape2 = patriarch.createSimpleShape(a2);
+            shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+
+            y1 += 10;
+            y2 += 10;
+        }
+    }
+
+    private static void drawLinesToCenter( HSSFPatriarch patriarch )
+    {
+        // Draw some lines from and to the corners
+        {
+            HSSFClientAnchor a1 = new HSSFClientAnchor();
+            a1.setAnchor( (short)2, 2, 0, 0, (short) 2, 2, 512, 128);
+            HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
+            shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+        }
+        {
+            HSSFClientAnchor a1 = new HSSFClientAnchor();
+            a1.setAnchor( (short)2, 2, 512, 128, (short) 2, 2, 1024, 0);
+            HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
+            shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+        }
+        {
+            HSSFClientAnchor a1 = new HSSFClientAnchor();
+            a1.setAnchor( (short)1, 1, 0, 0, (short) 1, 1, 512, 100);
+            HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
+            shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+        }
+        {
+            HSSFClientAnchor a1 = new HSSFClientAnchor();
+            a1.setAnchor( (short)1, 1, 512, 100, (short) 1, 1, 1024, 0);
+            HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
+            shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+        }
+
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/OfficeDrawingWithGraphics.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/OfficeDrawingWithGraphics.java
new file mode 100644 (file)
index 0000000..eca55d4
--- /dev/null
@@ -0,0 +1,113 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.RenderingHints;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.EscherGraphics;
+import org.apache.poi.hssf.usermodel.EscherGraphics2d;
+import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
+import org.apache.poi.hssf.usermodel.HSSFPatriarch;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFShapeGroup;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Demonstrates the use of the EscherGraphics2d library.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class OfficeDrawingWithGraphics {
+    public static void main( String[] args ) throws IOException {
+        // Create a workbook with one sheet and size the first three somewhat
+        // larger so we can fit the chemical structure diagram in.
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet = wb.createSheet("my drawing");
+            sheet.setColumnWidth(1, 256 * 27);
+            HSSFRow row1 = sheet.createRow(0);
+            row1.setHeightInPoints(10 * 15f);
+            HSSFRow row2 = sheet.createRow(1);
+            row2.setHeightInPoints(5 * 15f);
+            HSSFRow row3 = sheet.createRow(2);
+            row3.setHeightInPoints(10 * 15f);
+
+            // Add some cells so we can test that the anchoring works when we
+            // sort them.
+            row1.createCell(0).setCellValue("C");
+            row2.createCell(0).setCellValue("A");
+            row3.createCell(0).setCellValue("B");
+
+            // Create the top level drawing patriarch.
+            HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
+
+            HSSFClientAnchor a;
+            HSSFShapeGroup group;
+            EscherGraphics g;
+            EscherGraphics2d g2d;
+            // Anchor entirely within one cell.
+            a = new HSSFClientAnchor(0, 0, 1023, 255, (short) 1, 0, (short) 1, 0);
+            group = patriarch.createGroup(a);
+            group.setCoordinates(0, 0, 320, 276);
+            float verticalPointsPerPixel = a.getAnchorHeightInPoints(sheet) / Math.abs(group.getY2() - group.getY1());
+            g = new EscherGraphics(group, wb, Color.black, verticalPointsPerPixel);
+            g2d = new EscherGraphics2d(g);
+            drawStar(g2d);
+
+            a = new HSSFClientAnchor(0, 0, 1023, 255, (short) 1, 1, (short) 1, 1);
+            group = patriarch.createGroup(a);
+            group.setCoordinates(0, 0, 640, 276);
+            verticalPointsPerPixel = a.getAnchorHeightInPoints(sheet) / Math.abs(group.getY2() - group.getY1());
+//        verticalPixelsPerPoint = (float)Math.abs(group.getY2() - group.getY1()) / a.getAnchorHeightInPoints(sheet);
+            g = new EscherGraphics(group, wb, Color.black, verticalPointsPerPixel);
+            g2d = new EscherGraphics2d(g);
+            drawStar(g2d);
+
+            try (FileOutputStream out = new FileOutputStream("workbook.xls")) {
+                wb.write(out);
+            }
+        }
+    }
+
+    private static void drawStar( EscherGraphics2d g2d )
+    {
+        g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
+        for (double i = 0; i < Math.PI; i += 0.1)
+        {
+            g2d.setColor( new Color((int)(i * 5343062d) ) );
+            int x1 = (int) ( Math.cos(i) * 160.0 ) + 160;
+            int y1 = (int) ( Math.sin(i) * 138.0 ) + 138;
+            int x2 = (int) ( -Math.cos(i) * 160.0 ) + 160;
+            int y2 = (int) ( -Math.sin(i) * 138.0 ) + 138;
+            g2d.setStroke(new BasicStroke(2));
+            g2d.drawLine(x1,y1,x2,y2);
+        }
+        g2d.setFont(new Font("SansSerif",Font.BOLD | Font.ITALIC, 20));
+        g2d.drawString("EscherGraphics2d",70,100);
+        g2d.setColor(Color.yellow);
+        g2d.fillOval( 160-20,138-20,40,40);
+        g2d.setColor(Color.black);
+        g2d.fillPolygon(new int[] {-10+160,0+160,10+160,0+160}, new int[] {0+138,10+138,0+138,-10+138}, 4);
+        g2d.drawPolygon(new int[] {-160+160,0+160,160+160,0+160}, new int[] {0+138,138+138,0+138,-138+138}, 4);
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/Outlines.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/Outlines.java
new file mode 100644 (file)
index 0000000..d059a3d
--- /dev/null
@@ -0,0 +1,181 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.Closeable;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
+/**
+ * Creates outlines.
+ */
+public class Outlines implements Closeable {
+    public static void main(String[] args)
+    throws IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+        POILogger LOGGER = POILogFactory.getLogger(Outlines.class);
+        for (int i=1; i<=13; i++) {
+            try (Outlines o = new Outlines()) {
+                String log = (String) Outlines.class.getDeclaredMethod("test" + i).invoke(o);
+                String filename = "outline" + i + ".xls";
+                o.writeOut(filename);
+                LOGGER.log(POILogger.INFO, filename + " written. " + log);
+            }
+        }
+    }
+
+    private final HSSFWorkbook wb = new HSSFWorkbook();
+    private final HSSFSheet sheet1 = wb.createSheet("new sheet");
+
+    public void writeOut(String filename) throws IOException {
+        try (FileOutputStream fileOut = new FileOutputStream(filename)) {
+            wb.write(fileOut);
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        wb.close();
+    }
+
+    public String test1() {
+        sheet1.groupColumn(4, 7);
+
+        for (int row = 0; row < 200; row++) {
+            HSSFRow r = sheet1.createRow(row);
+            for (int column = 0; column < 200; column++) {
+                HSSFCell c = r.createCell(column);
+                c.setCellValue(column);
+            }
+        }
+        return "Two expanded groups.";
+    }
+
+    public String test2() {
+        sheet1.groupColumn(2, 10);
+        sheet1.groupColumn(4, 7);
+        sheet1.setColumnGroupCollapsed(4, true);
+        return "Two groups.  Inner group collapsed.";
+    }
+
+    public String test3() {
+        sheet1.groupColumn(2, 10);
+        sheet1.groupColumn(4, 7);
+        sheet1.setColumnGroupCollapsed(4, true);
+        sheet1.setColumnGroupCollapsed(2, true);
+        return "Two groups.  Both collapsed.";
+    }
+
+    public String test4() {
+        sheet1.groupColumn(2, 10);
+        sheet1.groupColumn(4, 7);
+        sheet1.setColumnGroupCollapsed(4, true);
+        sheet1.setColumnGroupCollapsed(2, true);
+
+        sheet1.setColumnGroupCollapsed(4, false);
+        return "Two groups.  Collapsed then inner group expanded.";
+    }
+
+    public String test5() {
+        sheet1.groupColumn(2, 10);
+        sheet1.groupColumn(4, 7);
+        sheet1.setColumnGroupCollapsed(4, true);
+        sheet1.setColumnGroupCollapsed(2, true);
+
+        sheet1.setColumnGroupCollapsed(4, false);
+        sheet1.setColumnGroupCollapsed(3, false);
+        return "Two groups.  Collapsed then reexpanded.";
+    }
+
+    public String test6() {
+        sheet1.groupColumn(2, 10);
+        sheet1.groupColumn(4, 10);
+        sheet1.setColumnGroupCollapsed(4, true);
+        sheet1.setColumnGroupCollapsed(2, true);
+
+        sheet1.setColumnGroupCollapsed(3, false);
+        return "Two groups with matching end points.  Second group collapsed.";
+    }
+
+    public String test7() {
+        sheet1.groupRow(5, 14);
+        sheet1.groupRow(7, 10);
+        return "Row outlines.";
+    }
+
+    public String test8() {
+        sheet1.groupRow(5, 14);
+        sheet1.groupRow(7, 10);
+        sheet1.setRowGroupCollapsed(7, true);
+        return "Row outlines.  Inner group collapsed.";
+    }
+
+    public String test9() {
+        sheet1.groupRow(5, 14);
+        sheet1.groupRow(7, 10);
+        sheet1.setRowGroupCollapsed(7, true);
+        sheet1.setRowGroupCollapsed(5, true);
+        return "Row outlines.  Both collapsed.";
+    }
+
+    public String test10() {
+        sheet1.groupRow(5, 14);
+        sheet1.groupRow(7, 10);
+        sheet1.setRowGroupCollapsed(7, true);
+        sheet1.setRowGroupCollapsed(5, true);
+        sheet1.setRowGroupCollapsed(8, false);
+        return "Row outlines.  Collapsed then inner group expanded.";
+    }
+
+    public String test11() {
+        sheet1.groupRow(5, 14);
+        sheet1.groupRow(7, 10);
+        sheet1.setRowGroupCollapsed(7, true);
+        sheet1.setRowGroupCollapsed(5, true);
+        sheet1.setRowGroupCollapsed(8, false);
+        sheet1.setRowGroupCollapsed(14, false);
+        return "Row outlines.  Collapsed then expanded.";
+    }
+
+    public String test12() {
+        sheet1.groupRow(5, 14);
+        sheet1.groupRow(7, 14);
+        sheet1.setRowGroupCollapsed(7, true);
+        sheet1.setRowGroupCollapsed(5, true);
+        sheet1.setRowGroupCollapsed(6, false);
+        return "Row outlines.  Two row groups with matching end points.  Second group collapsed.";
+    }
+
+    public String test13() {
+        sheet1.groupRow(5, 14);
+        sheet1.groupRow(7, 14);
+        sheet1.groupRow(16, 19);
+
+        sheet1.groupColumn(4, 7);
+        sheet1.groupColumn(9, 12);
+        sheet1.groupColumn(10, 11);
+        return "Mixed bag.";
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/ReadWriteWorkbook.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/ReadWriteWorkbook.java
new file mode 100644 (file)
index 0000000..e36b7ad
--- /dev/null
@@ -0,0 +1,56 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * This example demonstrates opening a workbook, modifying it and writing
+ * the results back out.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class ReadWriteWorkbook {
+    public static void main(String[] args) throws IOException {
+        try (FileInputStream fileIn = new FileInputStream("workbook.xls")) {
+            POIFSFileSystem fs = new POIFSFileSystem(fileIn);
+            HSSFWorkbook wb = new HSSFWorkbook(fs);
+            HSSFSheet sheet = wb.getSheetAt(0);
+            HSSFRow row = sheet.getRow(2);
+            if (row == null)
+                row = sheet.createRow(2);
+            HSSFCell cell = row.getCell(3);
+            if (cell == null)
+                cell = row.createCell(3);
+            cell.setCellValue("a test");
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("workbookout.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/RepeatingRowsAndColumns.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/RepeatingRowsAndColumns.java
new file mode 100644 (file)
index 0000000..db737cd
--- /dev/null
@@ -0,0 +1,64 @@
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+public class RepeatingRowsAndColumns {
+    public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet1 = wb.createSheet("first sheet");
+            HSSFSheet sheet2 = wb.createSheet("second sheet");
+            HSSFSheet sheet3 = wb.createSheet("third sheet");
+
+            HSSFFont boldFont = wb.createFont();
+            boldFont.setFontHeightInPoints((short) 22);
+            boldFont.setBold(true);
+
+            HSSFCellStyle boldStyle = wb.createCellStyle();
+            boldStyle.setFont(boldFont);
+
+            HSSFRow row = sheet1.createRow(1);
+            HSSFCell cell = row.createCell(0);
+            cell.setCellValue("This quick brown fox");
+            cell.setCellStyle(boldStyle);
+
+            // Set the columns to repeat from column 0 to 2 on the first sheet
+            sheet1.setRepeatingColumns(CellRangeAddress.valueOf("A:C"));
+            // Set the rows to repeat from row 0 to 2 on the second sheet.
+            sheet2.setRepeatingRows(CellRangeAddress.valueOf("1:3"));
+            // Set the the repeating rows and columns on the third sheet.
+            CellRangeAddress cra = CellRangeAddress.valueOf("D1:E2");
+            sheet3.setRepeatingColumns(cra);
+            sheet3.setRepeatingRows(cra);
+
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/SplitAndFreezePanes.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/SplitAndFreezePanes.java
new file mode 100644 (file)
index 0000000..54c3879
--- /dev/null
@@ -0,0 +1,51 @@
+
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Sheet;
+
+public class SplitAndFreezePanes {
+    public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet1 = wb.createSheet("new sheet");
+            HSSFSheet sheet2 = wb.createSheet("second sheet");
+            HSSFSheet sheet3 = wb.createSheet("third sheet");
+            HSSFSheet sheet4 = wb.createSheet("fourth sheet");
+
+            // Freeze just one row
+            sheet1.createFreezePane(0, 1, 0, 1);
+            // Freeze just one column
+            sheet2.createFreezePane(1, 0, 1, 0);
+            // Freeze the columns and rows (forget about scrolling position of the lower right quadrant).
+            sheet3.createFreezePane(2, 2);
+            // Create a split with the lower left side being the active quadrant
+            sheet4.createSplitPane(2000, 2000, 0, 0, Sheet.PANE_LOWER_LEFT);
+
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/WorkingWithFonts.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/WorkingWithFonts.java
new file mode 100644 (file)
index 0000000..0c87a33
--- /dev/null
@@ -0,0 +1,63 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Demonstrates how to create and use fonts.
+ */
+public class WorkingWithFonts {
+    public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet = wb.createSheet("new sheet");
+
+            // Create a row and put some cells in it. Rows are 0 based.
+            HSSFRow row = sheet.createRow(1);
+
+            // Create a new font and alter it.
+            HSSFFont font = wb.createFont();
+            font.setFontHeightInPoints((short) 24);
+            font.setFontName("Courier New");
+            font.setItalic(true);
+            font.setStrikeout(true);
+
+            // Fonts are set into a style so create a new one to use.
+            HSSFCellStyle style = wb.createCellStyle();
+            style.setFont(font);
+
+            // Create a cell and put a value in it.
+            HSSFCell cell = row.createCell(1);
+            cell.setCellValue("This is a test of fonts");
+            cell.setCellStyle(style);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hssf/usermodel/ZoomSheet.java b/src/examples/src/org/apache/poi/examples/hssf/usermodel/ZoomSheet.java
new file mode 100644 (file)
index 0000000..e958489
--- /dev/null
@@ -0,0 +1,45 @@
+
+/* ====================================================================
+   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.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Sets the zoom magnication for a sheet.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class ZoomSheet
+{
+    public static void main(String[] args) throws IOException {
+        try (HSSFWorkbook wb = new HSSFWorkbook()) {
+            HSSFSheet sheet1 = wb.createSheet("new sheet");
+            sheet1.setZoom(75);   // 75 percent magnification
+
+            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/hwpf/Word2Forrest.java b/src/examples/src/org/apache/poi/examples/hwpf/Word2Forrest.java
new file mode 100644 (file)
index 0000000..937da16
--- /dev/null
@@ -0,0 +1,226 @@
+/* ====================================================================
+   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.examples.hwpf;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.model.StyleDescription;
+import org.apache.poi.hwpf.model.StyleSheet;
+import org.apache.poi.hwpf.usermodel.CharacterRun;
+import org.apache.poi.hwpf.usermodel.Paragraph;
+import org.apache.poi.hwpf.usermodel.Range;
+
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class Word2Forrest
+{
+  Writer _out;
+  HWPFDocument _doc;
+
+  @SuppressWarnings("unused")
+  public Word2Forrest(HWPFDocument doc, OutputStream stream) throws IOException
+  {
+      _out = new OutputStreamWriter (stream, StandardCharsets.UTF_8);
+    _doc = doc;
+
+    init ();
+    openDocument ();
+    openBody ();
+
+    Range r = doc.getRange ();
+    StyleSheet styleSheet = doc.getStyleSheet ();
+
+    int sectionLevel = 0;
+    int lenParagraph = r.numParagraphs ();
+    boolean inCode = false;
+    for (int x = 0; x < lenParagraph; x++)
+    {
+      Paragraph p = r.getParagraph (x);
+      String text = p.text ();
+      if (text.trim ().length () == 0)
+      {
+        continue;
+      }
+      StyleDescription paragraphStyle = styleSheet.getStyleDescription (p.
+        getStyleIndex ());
+      String styleName = paragraphStyle.getName();
+      if (styleName.startsWith ("Heading"))
+      {
+        if (inCode)
+        {
+          closeSource();
+          inCode = false;
+        }
+
+        int headerLevel = Integer.parseInt (styleName.substring (8));
+        if (headerLevel > sectionLevel)
+        {
+          openSection ();
+        }
+        else
+        {
+          for (int y = 0; y < (sectionLevel - headerLevel) + 1; y++)
+          {
+            closeSection ();
+          }
+          openSection ();
+        }
+        sectionLevel = headerLevel;
+        openTitle ();
+        writePlainText (text);
+        closeTitle ();
+      }
+      else
+      {
+        int cruns = p.numCharacterRuns ();
+        CharacterRun run = p.getCharacterRun (0);
+        String fontName = run.getFontName();
+        if (fontName.startsWith ("Courier"))
+        {
+          if (!inCode)
+          {
+            openSource ();
+            inCode = true;
+          }
+          writePlainText (p.text());
+        }
+        else
+        {
+          if (inCode)
+          {
+            inCode = false;
+            closeSource();
+          }
+          openParagraph();
+          writePlainText(p.text());
+          closeParagraph();
+        }
+      }
+    }
+    for (int x = 0; x < sectionLevel; x++)
+    {
+      closeSection();
+    }
+    closeBody();
+    closeDocument();
+    _out.flush();
+
+  }
+
+    public void init ()
+      throws IOException
+    {
+      _out.write ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
+      _out.write ("<!DOCTYPE document PUBLIC \"-//APACHE//DTD Documentation V1.1//EN\" \"./dtd/document-v11.dtd\">\r\n");
+    }
+
+    public void openDocument ()
+      throws IOException
+    {
+      _out.write ("<document>\r\n");
+    }
+    public void closeDocument ()
+      throws IOException
+    {
+      _out.write ("</document>\r\n");
+    }
+
+
+    public void openBody ()
+      throws IOException
+    {
+      _out.write ("<body>\r\n");
+    }
+
+    public void closeBody ()
+      throws IOException
+    {
+      _out.write ("</body>\r\n");
+    }
+
+
+    public void openSection ()
+      throws IOException
+    {
+      _out.write ("<section>");
+
+    }
+
+    public void closeSection ()
+      throws IOException
+    {
+      _out.write ("</section>");
+
+    }
+
+    public void openTitle ()
+      throws IOException
+    {
+      _out.write ("<title>");
+    }
+
+    public void closeTitle ()
+      throws IOException
+    {
+      _out.write ("</title>");
+    }
+
+    public void writePlainText (String text)
+      throws IOException
+    {
+      _out.write (text);
+    }
+
+    public void openParagraph ()
+      throws IOException
+    {
+      _out.write ("<p>");
+    }
+
+    public void closeParagraph ()
+      throws IOException
+    {
+      _out.write ("</p>");
+    }
+
+    public void openSource ()
+      throws IOException
+    {
+      _out.write ("<source><![CDATA[");
+    }
+    public void closeSource ()
+      throws IOException
+    {
+      _out.write ("]]></source>");
+    }
+
+
+    public static void main(String[] args) throws IOException {
+      try (InputStream is = new FileInputStream(args[0]);
+           OutputStream out = new FileOutputStream("test.xml")) {
+        new Word2Forrest(new HWPFDocument(is), out);
+      }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/AddDimensionedImage.java b/src/examples/src/org/apache/poi/examples/ss/AddDimensionedImage.java
new file mode 100644 (file)
index 0000000..6e10203
--- /dev/null
@@ -0,0 +1,1011 @@
+/* ====================================================================
+   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.examples.ss;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Locale;
+
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;
+import org.apache.poi.ss.usermodel.Drawing;
+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.util.CellReference;
+import org.apache.poi.util.IOUtils;
+
+
+/**
+ * Demonstrates how to add an image to a worksheet and set that images size
+ * to a specific number of millimetres irrespective of the width of the columns
+ * or height of the rows. Overridden methods are provided so that the location
+ * of the image - the cells row and column coordinates that define the top
+ * left hand corners of the image - can be identified either in the familiar
+ * Excel manner - A1 for instance - or using POI's methodology of a column and
+ * row index where 0, 0 would indicate cell A1.
+ *
+ * The best way to make use of these techniques is to delay adding the image to
+ * the sheet until all other work has been completed. That way, the sizes of
+ * all rows and columns will have been adjusted - assuming that step was
+ * necessary. Even though the anchors type is set to prevent the image moving
+ * or re-sizing, this setting does not have any effect until the sheet is being
+ * viewed using the Excel application.
+ *
+ * The key to the process is the ClientAnchor class. It defines methods that allow
+ * us to define the location of an image by specifying the following;
+ *
+ *      * How far - in terms of coordinate positions - the image should be inset
+ *      from the left hand border of a cell.
+ *      * How far - in terms of coordinate positions - the image should be inset
+ *      from the from the top of the cell.
+ *      * How far - in terms of coordinate positions - the right hand edge of
+ *      the image should protrude into a cell (measured from the cells left hand
+ *      edge to the images right hand edge).
+ *      * How far - in terms of coordinate positions - the bottom edge of the
+ *      image should protrude into a row (measured from the cells top edge to
+ *      the images bottom edge).
+ *      * The index of the column that contains the cell whose top left hand
+ *      corner should be aligned with the top left hand corner of the image.
+ *      * The index of the row that contains the cell whose top left hand corner
+ *      should be aligned with the images top left hand corner.
+ *      * The index of the column that contains the cell whose top left hand
+ *      corner should be aligned with the images bottom right hand corner
+ *      * The index number of the row that contains the cell whose top left
+ *      hand corner should be aligned with the images bottom right hand corner.
+ *
+ * It can be used to add an image into cell A1, for example, in the following
+ * manner;
+ *
+ *      ClientAnchor anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
+ *
+ *      anchor.setDx1(0);
+ *      anchor.setDy1(0);
+ *      anchor.setDx2(0);
+ *      anchor.setDy2(0);
+ *      anchor.setCol1(0);
+ *      anchor.setRow1(0);
+ *      anchor.setCol2(1);
+ *      anchor.setRow2(1);
+ *
+ * Taken together, the first four methods define the locations of the top left
+ * and bottom right hand corners of the image if you imagine that the image is
+ * represented by a simple rectangle. The setDx1() and setDy1() methods locate
+ * the top left hand corner of the image while setDx2() and and Dy2() locate the
+ * bottom right hand corner of the image. An individual image can be inserted
+ * into a single cell or is can lie across many cells and the latter four methods
+ * are used to define just where the image should be positioned. They do this by
+ * again by identifying where the top left and bottom right hand corners of the
+ * image should be located but this time in terms of the indexes of the cells
+ * in which those corners should be located. The setCol1() and setRow1() methods
+ * together identify the cell that should contain the top left hand corner of
+ * the image while setCol2() and setRow2() do the same for the images bottom
+ * right hand corner.
+ *
+ * Knowing that, it is possible to look again at the example above and to see
+ * that the top left hand corner of the image will be located in cell A1 (0, 0)
+ * and it will be aligned with the very top left hand corner of the cell. Likewise,
+ * the bottom right hand corner of the image will be located in cell B2 (1, 1) and
+ * it will again be aligned with the top left hand corner of the cell. This has the
+ * effect of making the image seem to occupy the whole of cell A1. Interestingly, it
+ * also has an effect on the images resizing behaviour because testing has
+ * demonstrated that if the image is wholly contained within one cell and is not
+ * 'attached' for want of a better word, to a neighbouring cell, then that image
+ * will not increase in size in response to the user dragging the column wider
+ * or the cell higher.
+ *
+ * The following example demonstrates a slightly different way to insert an
+ * image into cell A1 and to ensure that it occupies the whole of the cell. This
+ * is accomplished by specifying the the images bottom right hand corner should be
+ * aligned with the bottom right hand corner of the cell. It is also a case
+ * where the image will not increase in size if the user increases the size of
+ * the enclosing cell - irrespective of the anchors type - but it will reduce in
+ * size if the cell is made smaller.
+ *
+ *      ClientAnchor anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
+ *
+ *      anchor.setDx1(0);
+ *      anchor.setDy1(0);
+ *      anchor.setDx2(1023);
+ *      anchor.setDy2(255);
+ *      anchor.setCol1(0);
+ *      anchor.setRow1(0);
+ *      anchor.setCol2(0);
+ *      anchor.setRow2(0);
+ *
+ * Note that the final four method calls all pass the same value and seem to
+ * indicate that the images top left hand corner is aligned with the top left
+ * hand corner of cell A1 and that it's bottom right hand corner is also
+ * aligned with the top left hand corner of cell A1. Yet, running this code
+ * would see the image fully occupying cell A1. That is the result of the
+ * values passed to parameters three and four; these I have referred to as
+ * determining the images coordinates within the cell. They indicate that the
+ * image should occupy - in order - the full width of the column and the full
+ * height of the row.
+ *
+ * The co-ordinate values shown are the maxima; and they are independent of
+ * row height/column width and of the font used. Passing 255 will always result
+ * in the image occupying the full height of the row and passing 1023 will
+ * always result in the image occupying the full width of the column. They help
+ * in situations where an image is larger than a column/row and must overlap
+ * into the next column/row. Using them does mean, however, that it is often
+ * necessary to perform conversions between Excels characters units, points,
+ * pixels and millimetres in order to establish how many rows/columns an image
+ * should occupy and just what the various insets ought to be.
+ *
+ * Note that the setDx1(int) and setDy1(int) methods of the ClientAchor class
+ * are not made use of in the code that follows. It would be fairly trivial
+ * however to extend this example further and provide methods that would centre
+ * an image within a cell or allow the user to specify that a plain border a
+ * fixed number of millimetres wide should wrap around the image. Those first
+ * two parameters would make this sort of functionality perfectly possible.
+ *
+ * Owing to the various conversions used, the actual size of the image may vary
+ * from that required; testing has so far found this to be in the region of
+ * plus or minus two millimetres. Most likely by modifying the way the
+ * calculations are performed - possibly using double(s) throughout and
+ * rounding the values at the correct point - it is likely that these errors
+ * could be reduced or removed.
+ *
+ * A note concerning Excels image resizing behaviour. The ClientAnchor
+ * class contains a method called setAnchorType(int) which can be used to
+ * determine how Excel will resize an image in response to the user increasing
+ * or decreasing the dimensions of the cell containing the image. There are
+ * three values that can be passed to this method; 0 = To move and size the
+ * image with the cell, 2 = To move but don't size the image with the cell,
+ * 3 = To prevent the image from moving or being resized along with the cell. If
+ * an image is inserted using this class and placed into a single cell then if
+ * the setAnchorType(int) method is called and a value of either 0 or 2 passed
+ * to it, the resultant resizing behaviour may be a surprise. The image will not
+ * grow in size of the column is made wider or the row higher but it will shrink
+ * if the columns width or rows height are reduced.
+ *
+ * @author Mark Beardsley [msb at apache.org] and Mark Southern [southern at scripps.edu]
+ * @version 1.00 5th August 2009.
+ *          2.00 26th February 2010.
+ *               Ported to make use of the the SS usermodel classes.
+ *               Ability to reuse the Drawing Patriarch so that multiple images
+ *               can be inserted without unintentionally erasing earlier images.
+ *               Check on image type added; i.e. jpg, jpeg or png.
+ *               The String used to contain the files name is now converted
+ *               into a URL.
+ *          2.10 17th May 2012
+ *               Corrected gross error that occurred when using the code with
+ *               XSSF or SXSSF workbooks. In short, the code did not correctly
+ *               calculate the size of the image(s) owing to the use of EMUs
+ *               within the OOXML file format. That problem has largely been
+ *               corrected although it should be mentioned that images are not
+ *               sized with the same level of accuracy. Discrepancies of up to
+ *               2mm have been noted in testing. Further investigation will
+ *               continue to rectify this issue.
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public class AddDimensionedImage {
+
+    // Four constants that determine how - and indeed whether - the rows
+    // and columns an image may overlie should be expanded to accommodate that
+    // image.
+    // Passing EXPAND_ROW will result in the height of a row being increased
+    // to accommodate the image if it is not already larger. The image will
+    // be layed across one or more columns.
+    // Passing EXPAND_COLUMN will result in the width of the column being
+    // increased to accommodate the image if it is not already larger. The image
+    // will be layed across one or many rows.
+    // Passing EXPAND_ROW_AND_COLUMN will result in the height of the row
+    // bing increased along with the width of the column to accomdate the
+    // image if either is not already larger.
+    // Passing OVERLAY_ROW_AND_COLUMN will result in the image being layed
+    // over one or more rows and columns. No row or column will be resized,
+    // instead, code will determine how many rows and columns the image should
+    // overlie.
+    public static final int EXPAND_ROW = 1;
+    public static final int EXPAND_COLUMN = 2;
+    public static final int EXPAND_ROW_AND_COLUMN = 3;
+    public static final int OVERLAY_ROW_AND_COLUMN = 7;
+
+    // Modified to support EMU - English Metric Units - used within the OOXML
+    // workbooks, this multoplier is used to convert between measurements in
+    // millimetres and in EMUs
+    private static final int EMU_PER_MM = 36000;
+
+    /**
+     * Add an image to a worksheet.
+     *
+     * @param cellNumber A String that contains the location of the cell whose
+     *                   top left hand corner should be aligned with the top
+     *                   left hand corner of the image; for example "A1", "A2"
+     *                   etc. This is to support the familiar Excel syntax.
+     *                   Whilst images are are not actually inserted into cells
+     *                   this provides a convenient method of indicating where
+     *                   the image should be positioned on the sheet.
+     * @param sheet A reference to the sheet that contains the cell referenced
+     *              above.
+     * @param drawing An instance of the DrawingPatriarch class. This is now
+     *                passed into the method where it was, previously, recovered
+     *                from the sheet in order to allow multiple pictures be
+     *                inserted. If the patriarch was not 'cached in this manner
+     *                each time it was created any previously positioned images
+     *                would be simply over-written.
+     * @param imageFile An instance of the URL class that encapsulates the name
+     *                  of and path to the image that is to be 'inserted into'
+     *                  the sheet.
+     * @param reqImageWidthMM A primitive double that contains the required
+     *                        width of the image in millimetres.
+     * @param reqImageHeightMM A primitive double that contains the required
+     *                         height of the image in millimetres.
+     * @param resizeBehaviour A primitive int whose value will determine how
+     *                        the code should react if the image is larger than
+     *                        the cell referenced by the cellNumber parameter.
+     *                        Four constants are provided to determine what
+     *                        should happen;
+     *                          AddDimensionedImage.EXPAND_ROW
+     *                          AddDimensionedImage.EXPAND_COLUMN
+     *                          AddDimensionedImage.EXPAND_ROW_AND_COLUMN
+     *                          AddDimensionedImage.OVERLAY_ROW_AND_COLUMN
+     * @throws java.io.FileNotFoundException If the file containing the image
+     *                                       cannot be located.
+     * @throws java.io.IOException If a problem occurs whilst reading the file
+     *                             of image data.
+     * @throws java.lang.IllegalArgumentException If an invalid value is passed
+     *                                            to the resizeBehaviour
+     *                                            parameter.
+     */
+    public void addImageToSheet(String cellNumber, Sheet sheet, Drawing<?> drawing,
+            URL imageFile, double reqImageWidthMM, double reqImageHeightMM,
+            int resizeBehaviour) throws IOException, IllegalArgumentException {
+        // Convert the String into column and row indices then chain the
+        // call to the overridden addImageToSheet() method.
+        CellReference cellRef = new CellReference(cellNumber);
+        this.addImageToSheet(cellRef.getCol(), cellRef.getRow(), sheet, drawing,
+                imageFile, reqImageWidthMM, reqImageHeightMM,resizeBehaviour);
+    }
+
+    /**
+     * Add an image to a worksheet.
+     *
+     * @param colNumber A primitive int that contains the index number of a
+     *                  column on the worksheet; POI column indices are zero
+     *                  based. Together with the rowNumber parameter's value,
+     *                  this parameter identifies a cell on the worksheet. The
+     *                  images top left hand corner will be aligned with the
+     *                  top left hand corner of this cell.
+     * @param rowNumber A primitive int that contains the index number of a row
+     *                  on the worksheet; POI row indices are zero based.
+     *                  Together with the rowNumber parameter's value, this
+     *                  parameter identifies a cell on the worksheet. The
+     *                  images top left hand corner will be aligned with the
+     *                  top left hand corner of this cell.
+     * @param sheet A reference to the sheet that contains the cell identified
+     *              by the two parameters above.
+     * @param drawing An instance of the DrawingPatriarch class. This is now
+     *                passed into the method where it was, previously, recovered
+     *                from the sheet in order to allow multiple pictures be
+     *                inserted. If the patriarch was not 'cached in this manner
+     *                each time it was created any previously positioned images
+     *                would be simply over-written.
+     * @param imageFile An instance of the URL class that encapsulates the name
+     *                  of and path to the image that is to be 'inserted into'
+     *                  the sheet.
+     * @param reqImageWidthMM A primitive double that contains the required
+     *                        width of the image in millimetres.
+     * @param reqImageHeightMM A primitive double that contains the required
+     *                         height of the image in millimetres.
+     * @param resizeBehaviour A primitive int whose value will determine how
+     *                        the code should react if the image is larger than
+     *                        the cell referenced by the colNumber and
+     *                        rowNumber parameters. Four constants are provided
+     *                        to determine what should happen;
+     *                          AddDimensionedImage.EXPAND_ROW
+     *                          AddDimensionedImage.EXPAND_COLUMN
+     *                          AddDimensionedImage.EXPAND_ROW_AND_COLUMN
+     *                          AddDimensionedImage.OVERLAY_ROW_AND_COLUMN
+     * @throws java.io.FileNotFoundException If the file containing the image
+     *                                       cannot be located.
+     * @throws java.io.IOException If a problem occurs whilst reading the file
+     *                             of image data.
+     * @throws java.lang.IllegalArgumentException If an invalid value is passed
+     *                                            to the resizeBehaviour
+     *                                            parameter or if the extension
+     *                                            of the image file indicates that
+     *                                            it is of a type that cannot
+     *                                            currently be added to the worksheet.
+     */
+    public void addImageToSheet(int colNumber, int rowNumber, Sheet sheet, Drawing<?> drawing,
+            URL imageFile, double reqImageWidthMM, double reqImageHeightMM,
+            int resizeBehaviour) throws IOException,
+                                                     IllegalArgumentException {
+        ClientAnchor anchor;
+        ClientAnchorDetail rowClientAnchorDetail;
+        ClientAnchorDetail colClientAnchorDetail;
+        int imageType;
+
+        // Validate the resizeBehaviour parameter.
+        if((resizeBehaviour != AddDimensionedImage.EXPAND_COLUMN) &&
+           (resizeBehaviour != AddDimensionedImage.EXPAND_ROW) &&
+           (resizeBehaviour != AddDimensionedImage.EXPAND_ROW_AND_COLUMN) &&
+           (resizeBehaviour != AddDimensionedImage.OVERLAY_ROW_AND_COLUMN)) {
+            throw new IllegalArgumentException("Invalid value passed to the " +
+                    "resizeBehaviour parameter of AddDimensionedImage.addImageToSheet()");
+        }
+
+        // Call methods to calculate how the image and sheet should be
+        // manipulated to accommodate the image; columns and then rows.
+        colClientAnchorDetail = this.fitImageToColumns(sheet, colNumber,
+                reqImageWidthMM, resizeBehaviour);
+        rowClientAnchorDetail = this.fitImageToRows(sheet, rowNumber,
+                reqImageHeightMM, resizeBehaviour);
+
+        // Having determined if and how to resize the rows, columns and/or the
+        // image, create the ClientAnchor object to position the image on
+        // the worksheet. Note how the two ClientAnchorDetail records are
+        // interrogated to recover the row/column co-ordinates and any insets.
+        // The first two parameters are not used currently but could be if the
+        // need arose to extend the functionality of this code by adding the
+        // ability to specify that a clear 'border' be placed around the image.
+        anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
+
+        anchor.setDx1(0);
+        anchor.setDy1(0);
+        if (colClientAnchorDetail != null) {
+            anchor.setDx2(colClientAnchorDetail.getInset());
+            anchor.setCol1(colClientAnchorDetail.getFromIndex());
+            anchor.setCol2(colClientAnchorDetail.getToIndex());
+        }
+        if (rowClientAnchorDetail != null) {
+            anchor.setDy2(rowClientAnchorDetail.getInset());
+            anchor.setRow1(rowClientAnchorDetail.getFromIndex());
+            anchor.setRow2(rowClientAnchorDetail.getToIndex());
+        }
+
+        // For now, set the anchor type to do not move or resize the
+        // image as the size of the row/column is adjusted. This could easily
+        // become another parameter passed to the method. Please read the note
+        // above regarding the behaviour of image resizing.
+        anchor.setAnchorType(AnchorType.MOVE_AND_RESIZE);
+
+        // Now, add the picture to the workbook. Note that unlike the similar
+        // method in the HSSF Examples section, the image type is checked. First,
+        // the image files location is identified by interrogating the URL passed
+        // to the method, the images type is identified before it is added to the
+        // sheet.
+        String sURL = imageFile.toString().toLowerCase(Locale.ROOT);
+       if( sURL.endsWith(".png") ) {
+            imageType = Workbook.PICTURE_TYPE_PNG;
+       }
+       else if( sURL.endsWith(".jpg") || sURL.endsWith(".jpeg") ) {
+            imageType = Workbook.PICTURE_TYPE_JPEG;
+       }
+       else  {
+            throw new IllegalArgumentException("Invalid Image file : " +
+                sURL);
+       }
+        int index = sheet.getWorkbook().addPicture(
+            IOUtils.toByteArray(imageFile.openStream()), imageType);
+        drawing.createPicture(anchor, index);
+    }
+
+    /**
+     * Determines whether the sheets columns should be re-sized to accommodate
+     * the image, adjusts the columns width if necessary and creates then
+     * returns a ClientAnchorDetail object that facilitates construction of
+     * an ClientAnchor that will fix the image on the sheet and establish
+     * it's size.
+     *
+     * @param sheet A reference to the sheet that will 'contain' the image.
+     * @param colNumber A primitive int that contains the index number of a
+     *                  column on the sheet.
+     * @param reqImageWidthMM A primitive double that contains the required
+     *                        width of the image in millimetres
+     * @param resizeBehaviour A primitive int whose value will indicate how the
+     *                        width of the column should be adjusted if the
+     *                        required width of the image is greater than the
+     *                        width of the column.
+     * @return An instance of the ClientAnchorDetail class that will contain
+     *         the index number of the column containing the cell whose top
+     *         left hand corner also defines the top left hand corner of the
+     *         image, the index number column containing the cell whose top
+     *         left hand corner also defines the bottom right hand corner of
+     *         the image and an inset that determines how far the right hand
+     *         edge of the image can protrude into the next column - expressed
+     *         as a specific number of coordinate positions.
+     */
+    private ClientAnchorDetail fitImageToColumns(Sheet sheet, int colNumber,
+            double reqImageWidthMM, int resizeBehaviour) {
+
+        double colWidthMM;
+        double colCoordinatesPerMM;
+        int pictureWidthCoordinates;
+        ClientAnchorDetail colClientAnchorDetail = null;
+
+        // Get the colum's width in millimetres
+        colWidthMM = ConvertImageUnits.widthUnits2Millimetres(
+                (short)sheet.getColumnWidth(colNumber));
+
+        // Check that the column's width will accommodate the image at the
+        // required dimension. If the width of the column is LESS than the
+        // required width of the image, decide how the application should
+        // respond - resize the column or overlay the image across one or more
+        // columns.
+        if(colWidthMM < reqImageWidthMM) {
+
+            // Should the column's width simply be expanded?
+            if((resizeBehaviour == AddDimensionedImage.EXPAND_COLUMN) ||
+               (resizeBehaviour == AddDimensionedImage.EXPAND_ROW_AND_COLUMN)) {
+                // Set the width of the column by converting the required image
+                // width from millimetres into Excel's column width units.
+                sheet.setColumnWidth(colNumber,
+                        ConvertImageUnits.millimetres2WidthUnits(reqImageWidthMM));
+                // To make the image occupy the full width of the column, convert
+                // the required width of the image into co-ordinates. This value
+                // will become the inset for the ClientAnchorDetail class that
+                // is then instantiated.
+                if(sheet instanceof HSSFSheet) {
+                    colWidthMM = reqImageWidthMM;
+                    colCoordinatesPerMM = colWidthMM == 0 ? 0
+                        : ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS / colWidthMM;
+                    pictureWidthCoordinates = (int)(reqImageWidthMM * colCoordinatesPerMM);
+
+                }
+                else {
+                    pictureWidthCoordinates = (int)reqImageWidthMM * AddDimensionedImage.EMU_PER_MM;
+                }
+                colClientAnchorDetail = new ClientAnchorDetail(colNumber,
+                        colNumber, pictureWidthCoordinates);
+            }
+            // If the user has chosen to overlay both rows and columns or just
+            // to expand ONLY the size of the rows, then calculate how to lay
+            // the image out across one or more columns.
+            else if ((resizeBehaviour == AddDimensionedImage.OVERLAY_ROW_AND_COLUMN) ||
+                     (resizeBehaviour == AddDimensionedImage.EXPAND_ROW)) {
+                colClientAnchorDetail = this.calculateColumnLocation(sheet,
+                        colNumber, reqImageWidthMM);
+            }
+        }
+        // If the column is wider than the image.
+        else {
+            if(sheet instanceof HSSFSheet) {
+                // Mow many co-ordinate positions are there per millimetre?
+                colCoordinatesPerMM = ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS /
+                    colWidthMM;
+                // Given the width of the image, what should be it's co-ordinate?
+                pictureWidthCoordinates = (int)(reqImageWidthMM * colCoordinatesPerMM);
+            }
+            else {
+                pictureWidthCoordinates = (int)reqImageWidthMM *
+                        AddDimensionedImage.EMU_PER_MM;
+            }
+            colClientAnchorDetail = new ClientAnchorDetail(colNumber,
+                    colNumber, pictureWidthCoordinates);
+        }
+        return(colClientAnchorDetail);
+    }
+
+    /**
+     * Determines whether the sheets row should be re-sized to accommodate
+     * the image, adjusts the rows height if necessary and creates then
+     * returns a ClientAnchorDetail object that facilitates construction of
+     * a ClientAnchor that will fix the image on the sheet and establish
+     * it's size.
+     *
+     * @param sheet A reference to the sheet that will 'contain' the image.
+     * @param rowNumber A primitive int that contains the index number of a
+     *                  row on the sheet.
+     * @param reqImageHeightMM A primitive double that contains the required
+     *                         height of the image in millimetres
+     * @param resizeBehaviour A primitive int whose value will indicate how the
+     *                        height of the row should be adjusted if the
+     *                        required height of the image is greater than the
+     *                        height of the row.
+     * @return An instance of the ClientAnchorDetail class that will contain
+     *         the index number of the row containing the cell whose top
+     *         left hand corner also defines the top left hand corner of the
+     *         image, the index number of the row containing the cell whose
+     *         top left hand corner also defines the bottom right hand
+     *         corner of the image and an inset that determines how far the
+     *         bottom edge of the image can protrude into the next (lower)
+     *         row - expressed as a specific number of coordinate positions.
+     */
+    private ClientAnchorDetail fitImageToRows(Sheet sheet, int rowNumber,
+            double reqImageHeightMM, int resizeBehaviour) {
+        Row row;
+        double rowHeightMM;
+        double rowCoordinatesPerMM;
+        int pictureHeightCoordinates;
+        ClientAnchorDetail rowClientAnchorDetail = null;
+
+        // Get the row and it's height
+        row = sheet.getRow(rowNumber);
+        if(row == null) {
+            // Create row if it does not exist.
+            row = sheet.createRow(rowNumber);
+        }
+
+        // Get the row's height in millimetres
+        rowHeightMM = row.getHeightInPoints() / ConvertImageUnits.POINTS_PER_MILLIMETRE;
+
+        // Check that the row's height will accommodate the image at the required
+        // dimensions. If the height of the row is LESS than the required height
+        // of the image, decide how the application should respond - resize the
+        // row or overlay the image across a series of rows.
+        if(rowHeightMM < reqImageHeightMM) {
+            if((resizeBehaviour == AddDimensionedImage.EXPAND_ROW) ||
+               (resizeBehaviour == AddDimensionedImage.EXPAND_ROW_AND_COLUMN)) {
+                row.setHeightInPoints((float)(reqImageHeightMM *
+                        ConvertImageUnits.POINTS_PER_MILLIMETRE));
+                if(sheet instanceof HSSFSheet) {
+                    rowHeightMM = reqImageHeightMM;
+                    rowCoordinatesPerMM = rowHeightMM == 0 ? 0
+                        : ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS / rowHeightMM;
+                    pictureHeightCoordinates = (int)(reqImageHeightMM *
+                            rowCoordinatesPerMM);
+                }
+                else {
+                    pictureHeightCoordinates = (int)(reqImageHeightMM *
+                            AddDimensionedImage.EMU_PER_MM);
+                }
+                rowClientAnchorDetail = new ClientAnchorDetail(rowNumber,
+                        rowNumber, pictureHeightCoordinates);
+            }
+            // If the user has chosen to overlay both rows and columns or just
+            // to expand ONLY the size of the columns, then calculate how to lay
+            // the image out ver one or more rows.
+            else if((resizeBehaviour == AddDimensionedImage.OVERLAY_ROW_AND_COLUMN) ||
+                    (resizeBehaviour == AddDimensionedImage.EXPAND_COLUMN)) {
+                rowClientAnchorDetail = this.calculateRowLocation(sheet,
+                        rowNumber, reqImageHeightMM);
+            }
+        }
+        // Else, if the image is smaller than the space available
+        else {
+            if(sheet instanceof HSSFSheet) {
+                rowCoordinatesPerMM = ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS /
+                    rowHeightMM;
+                pictureHeightCoordinates = (int)(reqImageHeightMM * rowCoordinatesPerMM);
+            }
+            else {
+                pictureHeightCoordinates = (int)(reqImageHeightMM *
+                        AddDimensionedImage.EMU_PER_MM);
+            }
+            rowClientAnchorDetail = new ClientAnchorDetail(rowNumber,
+                        rowNumber, pictureHeightCoordinates);
+        }
+        return(rowClientAnchorDetail);
+    }
+
+    /**
+     * If the image is to overlie more than one column, calculations need to be
+     * performed to determine how many columns and whether the image will
+     * overlie just a part of one column in order to be presented at the
+     * required size.
+     *
+     * @param sheet The sheet that will 'contain' the image.
+     * @param startingColumn A primitive int whose value is the index of the
+     *                       column that contains the cell whose top left hand
+     *                       corner should be aligned with the top left hand
+     *                       corner of the image.
+     * @param reqImageWidthMM A primitive double whose value will indicate the
+     *                        required width of the image in millimetres.
+     * @return An instance of the ClientAnchorDetail class that will contain
+     *         the index number of the column containing the cell whose top
+     *         left hand corner also defines the top left hand corner of the
+     *         image, the index number column containing the cell whose top
+     *         left hand corner also defines the bottom right hand corner of
+     *         the image and an inset that determines how far the right hand
+     *         edge of the image can protrude into the next column - expressed
+     *         as a specific number of coordinate positions.
+     */
+    private ClientAnchorDetail calculateColumnLocation(Sheet sheet,
+                                                       int startingColumn,
+                                                       double reqImageWidthMM) {
+        ClientAnchorDetail anchorDetail;
+        double totalWidthMM = 0.0D;
+        double colWidthMM = 0.0D;
+        double overlapMM;
+        double coordinatePositionsPerMM;
+        int toColumn = startingColumn;
+        int inset;
+
+        // Calculate how many columns the image will have to
+        // span in order to be presented at the required size.
+        while(totalWidthMM < reqImageWidthMM) {
+            colWidthMM = ConvertImageUnits.widthUnits2Millimetres(
+                    (short)(sheet.getColumnWidth(toColumn)));
+            // Note use of the cell border width constant. Testing with an image
+            // declared to fit exactly into one column demonstrated that it's
+            // width was greater than the width of the column the POI returned.
+            // Further, this difference was a constant value that I am assuming
+            // related to the cell's borders. Either way, that difference needs
+            // to be allowed for in this calculation.
+            totalWidthMM += (colWidthMM + ConvertImageUnits.CELL_BORDER_WIDTH_MILLIMETRES);
+            toColumn++;
+        }
+        // De-crement by one the last column value.
+        toColumn--;
+        // Highly unlikely that this will be true but, if the width of a series
+        // of columns is exactly equal to the required width of the image, then
+        // simply build a ClientAnchorDetail object with an inset equal to the
+        // total number of co-ordinate positions available in a column, a
+        // from column co-ordinate (top left hand corner) equal to the value
+        // of the startingColumn parameter and a to column co-ordinate equal
+        // to the toColumn variable.
+        //
+        // Convert both values to ints to perform the test.
+        if((int)totalWidthMM == (int)reqImageWidthMM) {
+            // A problem could occur if the image is sized to fit into one or
+            // more columns. If that occurs, the value in the toColumn variable
+            // will be in error. To overcome this, there are two options, to
+            // ibcrement the toColumn variable's value by one or to pass the
+            // total number of co-ordinate positions to the third paramater
+            // of the ClientAnchorDetail constructor. For no sepcific reason,
+            // the latter option is used below.
+            if(sheet instanceof HSSFSheet) {
+                anchorDetail = new ClientAnchorDetail(startingColumn,
+                    toColumn, ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS);
+            }
+            else {
+                anchorDetail = new ClientAnchorDetail(startingColumn,
+                    toColumn, (int)reqImageWidthMM * AddDimensionedImage.EMU_PER_MM);
+            }
+        }
+        // In this case, the image will overlap part of another column and it is
+        // necessary to calculate just how much - this will become the inset
+        // for the ClientAnchorDetail object.
+        else {
+            // Firstly, claculate how much of the image should overlap into
+            // the next column.
+            overlapMM = reqImageWidthMM - (totalWidthMM - colWidthMM);
+
+            // When the required size is very close indded to the column size,
+            // the calcaulation above can produce a negative value. To prevent
+            // problems occuring in later caculations, this is simply removed
+            // be setting the overlapMM value to zero.
+            if(overlapMM < 0) {
+                overlapMM = 0.0D;
+            }
+
+            if(sheet instanceof HSSFSheet) {
+                // Next, from the columns width, calculate how many co-ordinate
+                // positons there are per millimetre
+                coordinatePositionsPerMM = (colWidthMM == 0) ? 0
+                    : ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS / colWidthMM;
+                // From this figure, determine how many co-ordinat positions to
+                // inset the left hand or bottom edge of the image.
+                inset = (int)(coordinatePositionsPerMM * overlapMM);
+            }
+            else {
+                inset = (int)overlapMM * AddDimensionedImage.EMU_PER_MM;
+            }
+
+            // Now create the ClientAnchorDetail object, setting the from and to
+            // columns and the inset.
+            anchorDetail = new ClientAnchorDetail(startingColumn, toColumn, inset);
+        }
+        return(anchorDetail);
+    }
+
+    /**
+     * If the image is to overlie more than one rows, calculations need to be
+     * performed to determine how many rows and whether the image will
+     * overlie just a part of one row in order to be presented at the
+     * required size.
+     *
+     * @param sheet The sheet that will 'contain' the image.
+     * @param startingRow A primitive int whose value is the index of the row
+     *                    that contains the cell whose top left hand corner
+     *                    should be aligned with the top left hand corner of
+     *                    the image.
+     * @param reqImageHeightMM A primitive double whose value will indicate the
+     *                         required height of the image in millimetres.
+     * @return An instance of the ClientAnchorDetail class that will contain
+     *         the index number of the row containing the cell whose top
+     *         left hand corner also defines the top left hand corner of the
+     *         image, the index number of the row containing the cell whose top
+     *         left hand corner also defines the bottom right hand corner of
+     *         the image and an inset that determines how far the bottom edge
+     *         can protrude into the next (lower) row - expressed as a specific
+     *         number of co-ordinate positions.
+     */
+    private ClientAnchorDetail calculateRowLocation(Sheet sheet,
+            int startingRow, double reqImageHeightMM) {
+        ClientAnchorDetail clientAnchorDetail;
+        Row row;
+        double rowHeightMM = 0.0D;
+        double totalRowHeightMM = 0.0D;
+        double overlapMM;
+        double rowCoordinatesPerMM;
+        int toRow = startingRow;
+        int inset;
+
+        // Step through the rows in the sheet and accumulate a total of their
+        // heights.
+        while(totalRowHeightMM < reqImageHeightMM) {
+            row = sheet.getRow(toRow);
+            // Note, if the row does not already exist on the sheet then create
+            // it here.
+            if(row == null) {
+                row = sheet.createRow(toRow);
+            }
+            // Get the row's height in millimetres and add to the running total.
+            rowHeightMM = row.getHeightInPoints() /
+                    ConvertImageUnits.POINTS_PER_MILLIMETRE;
+            totalRowHeightMM += rowHeightMM;
+            toRow++;
+        }
+        // Owing to the way the loop above works, the rowNumber will have been
+        // incremented one row too far. Undo that here.
+        toRow--;
+        // Check to see whether the image should occupy an exact number of
+        // rows. If so, build the ClientAnchorDetail record to point
+        // to those rows and with an inset of the total number of co-ordinate
+        // position in the row.
+        //
+        // To overcome problems that can occur with comparing double values for
+        // equality, cast both to int(s) to truncate the value; VERY crude and
+        // I do not really like it!!
+        if((int)totalRowHeightMM == (int)reqImageHeightMM) {
+            if(sheet instanceof HSSFSheet) {
+                clientAnchorDetail = new ClientAnchorDetail(startingRow, toRow,
+                    ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS);
+            }
+            else {
+                clientAnchorDetail = new ClientAnchorDetail(startingRow, toRow,
+                    (int)reqImageHeightMM * AddDimensionedImage.EMU_PER_MM);
+            }
+        }
+        else {
+            // Calculate how far the image will project into the next row. Note
+            // that the height of the last row assessed is subtracted from the
+            // total height of all rows assessed so far.
+            overlapMM = reqImageHeightMM - (totalRowHeightMM - rowHeightMM);
+
+            // To prevent an exception being thrown when the required width of
+            // the image is very close indeed to the column size.
+            if(overlapMM < 0) {
+                overlapMM = 0.0D;
+            }
+
+            if(sheet instanceof HSSFSheet) {
+                rowCoordinatesPerMM = (rowHeightMM == 0) ? 0
+                    : ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS / rowHeightMM;
+                inset = (int)(overlapMM * rowCoordinatesPerMM);
+            }
+            else {
+                inset = (int)overlapMM * AddDimensionedImage.EMU_PER_MM;
+            }
+            clientAnchorDetail = new ClientAnchorDetail(startingRow,
+                        toRow, inset);
+        }
+        return(clientAnchorDetail);
+    }
+
+    /**
+     * The main entry point to the program. It contains code that demonstrates
+     * one way to use the program.
+     *
+     * Note, the code is not restricted to use on new workbooks only. If an
+     * image is to be inserted into an existing workbook. just open that
+     * workbook, gat a reference to a sheet and pass that;
+     *
+     *      AddDimensionedImage addImage = new AddDimensionedImage();
+     *
+     *      File file = new File("....... Existing Workbook .......");
+     *      FileInputStream fis = new FileInputStream(file);
+     *      Workbook workbook = new HSSFWorkbook(fis);
+     *      HSSFSheet sheet = workbook.getSheetAt(0);
+     *      addImage.addImageToSheet("C3", sheet, "image.jpg", 30, 20,
+     *          AddDimensionedImage.EXPAND.ROW);
+     *
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) throws IOException {
+        if(args.length < 2){
+               System.err.println("Usage: AddDimensionedImage imageFile outputFile");
+               return;
+       }
+
+        final String imageFile = args[0];
+        final String outputFile = args[1];
+
+        try (final Workbook workbook = new HSSFWorkbook();
+             final FileOutputStream fos = new FileOutputStream(outputFile)) {   // OR XSSFWorkbook
+            Sheet sheet = workbook.createSheet("Picture Test");
+            new AddDimensionedImage().addImageToSheet("B5", sheet, sheet.createDrawingPatriarch(),
+                    new File(imageFile).toURI().toURL(), 100, 40,
+                    AddDimensionedImage.EXPAND_ROW_AND_COLUMN);
+            workbook.write(fos);
+        }
+    }
+
+    /**
+     * The HSSFClientAnchor class accepts eight arguments. In order, these are;
+     *
+     *      * How far the left hand edge of the image is inset from the left hand
+     *      edge of the cell
+     *      * How far the top edge of the image is inset from the top of the cell
+     *      * How far the right hand edge of the image is inset from the left
+     *      hand edge of the cell
+     *      * How far the bottom edge of the image is inset from the top of the
+     *      cell.
+     *      * Together, arguments five and six determine the column and row
+     *      coordinates of the cell whose top left hand corner will be aligned
+     *      with the images top left hand corner.
+     *      * Together, arguments seven and eight determine the column and row
+     *      coordinates of the cell whose top left hand corner will be aligned
+     *      with the images bottom right hand corner.
+     *
+     * An instance of the ClientAnchorDetail class provides three of the eight
+     * parameters, one of the coordinates for the images top left hand corner,
+     * one of the coordinates for the images bottom right hand corner and
+     * either how far the image should be inset from the top or the left hand
+     * edge of the cell.
+     *
+     * @author Mark Beardsley [msb at apache.org]
+     * @version 1.00 5th August 2009.
+     */
+    public class ClientAnchorDetail {
+
+        private int fromIndex;
+        private int toIndex;
+        private int inset;
+
+        /**
+         * Create a new instance of the ClientAnchorDetail class using the
+         * following parameters.
+         *
+         * @param fromIndex A primitive int that contains one of the
+         *                  coordinates (row or column index) for the top left
+         *                  hand corner of the image.
+         * @param toIndex A primitive int that contains one of the
+         *                coordinates (row or column index) for the bottom
+         *                right hand corner of the image.
+         * @param inset A primitive int that contains a value which indicates
+         *              how far the image should be inset from the top or the
+         *              left hand edge of a cell.
+         */
+        public ClientAnchorDetail(int fromIndex, int toIndex, int inset) {
+            this.fromIndex = fromIndex;
+            this.toIndex = toIndex;
+            this.inset = inset;
+        }
+
+        /**
+         * Get one of the number of the column or row that contains the cell
+         * whose top left hand corner will be aligned with the top left hand
+         * corner of the image.
+         *
+         * @return The value - row or column index - for one of the coordinates
+         *         of the top left hand corner of the image.
+         */
+        public int getFromIndex() {
+            return(this.fromIndex);
+        }
+
+        /**
+         * Get one of the number of the column or row that contains the cell
+         * whose top left hand corner will be aligned with the bottom right hand
+         * corner of the image.
+         *
+         * @return The value - row or column index - for one of the coordinates
+         *         of the bottom right hand corner of the image.
+         */
+        public int getToIndex() {
+            return(this.toIndex);
+        }
+
+        /**
+         * Get the images offset from the edge of a cell.
+         *
+         * @return How far either the right hand or bottom edge of the image is
+         *         inset from the left hand or top edge of a cell.
+         */
+        public int getInset() {
+            return(this.inset);
+        }
+    }
+
+    /**
+     * Utility methods used to convert Excels character based column and row
+     * size measurements into pixels and/or millimetres. The class also contains
+     * various constants that are required in other calculations.
+     *
+     * @author xio[darjino@hotmail.com]
+     * @version 1.01 30th July 2009.
+     *      Added by Mark Beardsley [msb at apache.org].
+     *          Additional constants.
+     *          widthUnits2Millimetres() and millimetres2Units() methods.
+     */
+    public static class ConvertImageUnits {
+
+        // Each cell conatins a fixed number of co-ordinate points; this number
+        // does not vary with row height or column width or with font. These two
+        // constants are defined below.
+        public static final int TOTAL_COLUMN_COORDINATE_POSITIONS = 1023;
+        public static final int TOTAL_ROW_COORDINATE_POSITIONS = 255;
+        // The resoultion of an image can be expressed as a specific number
+        // of pixels per inch. Displays and printers differ but 96 pixels per
+        // inch is an acceptable standard to beging with.
+        public static final int PIXELS_PER_INCH = 96;
+        // Cnstants that defines how many pixels and points there are in a
+        // millimetre. These values are required for the conversion algorithm.
+        public static final double PIXELS_PER_MILLIMETRES = 3.78;
+        public static final double POINTS_PER_MILLIMETRE = 2.83;
+        // The column width returned by HSSF and the width of a picture when
+        // positioned to exactly cover one cell are different by almost exactly
+        // 2mm - give or take rounding errors. This constant allows that
+        // additional amount to be accounted for when calculating how many
+        // celles the image ought to overlie.
+        public static final double CELL_BORDER_WIDTH_MILLIMETRES = 2.0D;
+        public static final short EXCEL_COLUMN_WIDTH_FACTOR = 256;
+        public static final int UNIT_OFFSET_LENGTH = 7;
+        private static final int[] UNIT_OFFSET_MAP = { 0, 36, 73, 109, 146, 182, 219 };
+
+        /**
+        * pixel units to excel width units(units of 1/256th of a character width)
+        */
+        public static short pixel2WidthUnits(int pxs) {
+            short widthUnits = (short) (EXCEL_COLUMN_WIDTH_FACTOR *
+                    (pxs / UNIT_OFFSET_LENGTH));
+            widthUnits += UNIT_OFFSET_MAP[(pxs % UNIT_OFFSET_LENGTH)];
+            return widthUnits;
+        }
+
+        /**
+         * excel width units(units of 1/256th of a character width) to pixel
+         * units.
+         */
+        public static int widthUnits2Pixel(short widthUnits) {
+            int pixels = (widthUnits / EXCEL_COLUMN_WIDTH_FACTOR)
+                    * UNIT_OFFSET_LENGTH;
+            int offsetWidthUnits = widthUnits % EXCEL_COLUMN_WIDTH_FACTOR;
+            pixels += Math.round(offsetWidthUnits /
+                    ((float) EXCEL_COLUMN_WIDTH_FACTOR / UNIT_OFFSET_LENGTH));
+            return pixels;
+        }
+
+        /**
+         * Convert Excels width units into millimetres.
+         *
+         * @param widthUnits The width of the column or the height of the
+         *                   row in Excels units.
+         * @return A primitive double that contains the columns width or rows
+         *         height in millimetres.
+         */
+        public static double widthUnits2Millimetres(short widthUnits) {
+            return(ConvertImageUnits.widthUnits2Pixel(widthUnits) /
+                   ConvertImageUnits.PIXELS_PER_MILLIMETRES);
+        }
+
+        /**
+         * Convert into millimetres Excels width units..
+         *
+         * @param millimetres A primitive double that contains the columns
+         *                    width or rows height in millimetres.
+         * @return A primitive int that contains the columns width or rows
+         *         height in Excels units.
+         */
+        public static int millimetres2WidthUnits(double millimetres) {
+            return(ConvertImageUnits.pixel2WidthUnits((int)(millimetres *
+                    ConvertImageUnits.PIXELS_PER_MILLIMETRES)));
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/AligningCells.java b/src/examples/src/org/apache/poi/examples/ss/AligningCells.java
new file mode 100644 (file)
index 0000000..af86efc
--- /dev/null
@@ -0,0 +1,81 @@
+/* ====================================================================
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.ss;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Shows how various alignment options work.
+ */
+public class AligningCells {
+
+    public static void main(String[] args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+
+            Sheet sheet = wb.createSheet();
+            Row row = sheet.createRow(2);
+            row.setHeightInPoints(30);
+            for (int i = 0; i < 8; i++) {
+                //column width is set in units of 1/256th of a character width
+                sheet.setColumnWidth(i, 256 * 15);
+            }
+
+            createCell(wb, row, 0, HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
+            createCell(wb, row, 1, HorizontalAlignment.CENTER_SELECTION, VerticalAlignment.BOTTOM);
+            createCell(wb, row, 2, HorizontalAlignment.FILL, VerticalAlignment.CENTER);
+            createCell(wb, row, 3, HorizontalAlignment.GENERAL, VerticalAlignment.CENTER);
+            createCell(wb, row, 4, HorizontalAlignment.JUSTIFY, VerticalAlignment.JUSTIFY);
+            createCell(wb, row, 5, HorizontalAlignment.LEFT, VerticalAlignment.TOP);
+            createCell(wb, row, 6, HorizontalAlignment.RIGHT, VerticalAlignment.TOP);
+
+            // Write the output to a file
+            try (OutputStream fileOut = new FileOutputStream("ss-example-align.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+
+    /**
+     * Creates a cell and aligns it a certain way.
+     *
+     * @param wb     the workbook
+     * @param row    the row to create the cell in
+     * @param column the column number to create the cell in
+     * @param halign the horizontal alignment for the cell.
+     */
+    private static void createCell(Workbook wb, Row row, int column, HorizontalAlignment halign, VerticalAlignment valign) {
+        CreationHelper ch = wb.getCreationHelper();
+        Cell cell = row.createCell(column);
+        cell.setCellValue(ch.createRichTextString("Align It"));
+        CellStyle cellStyle = wb.createCellStyle();
+        cellStyle.setAlignment(halign);
+        cellStyle.setVerticalAlignment(valign);
+        cell.setCellStyle(cellStyle);
+    }
+}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/examples/ss/BusinessPlan.java b/src/examples/src/org/apache/poi/examples/ss/BusinessPlan.java
new file mode 100644 (file)
index 0000000..59ccc6f
--- /dev/null
@@ -0,0 +1,344 @@
+/* ====================================================================
+   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.examples.ss;
+
+import java.io.FileOutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.DataFormat;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.PrintSetup;
+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.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * A business plan demo
+ * Usage:
+ *  BusinessPlan -xls|xlsx
+ *
+ * @author Yegor Kozlov
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class BusinessPlan {
+
+    private static final String[] titles = {
+            "ID", "Project Name", "Owner", "Days", "Start", "End"};
+
+    //sample data to fill the sheet.
+    private static final String[][] data = {
+            {"1.0", "Marketing Research Tactical Plan", "J. Dow", "70", "9-Jul", null,
+                "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x"},
+            null,
+            {"1.1", "Scope Definition Phase", "J. Dow", "10", "9-Jul", null,
+                "x", "x", null, null,  null, null, null, null, null, null, null},
+            {"1.1.1", "Define research objectives", "J. Dow", "3", "9-Jul", null,
+                    "x", null, null, null,  null, null, null, null, null, null, null},
+            {"1.1.2", "Define research requirements", "S. Jones", "7", "10-Jul", null,
+                "x", "x", null, null,  null, null, null, null, null, null, null},
+            {"1.1.3", "Determine in-house resource or hire vendor", "J. Dow", "2", "15-Jul", null,
+                "x", "x", null, null,  null, null, null, null, null, null, null},
+            null,
+            {"1.2", "Vendor Selection Phase", "J. Dow", "19", "19-Jul", null,
+                null, "x", "x", "x",  "x", null, null, null, null, null, null},
+            {"1.2.1", "Define vendor selection criteria", "J. Dow", "3", "19-Jul", null,
+                null, "x", null, null,  null, null, null, null, null, null, null},
+            {"1.2.2", "Develop vendor selection questionnaire", "S. Jones, T. Wates", "2", "22-Jul", null,
+                null, "x", "x", null,  null, null, null, null, null, null, null},
+            {"1.2.3", "Develop Statement of Work", "S. Jones", "4", "26-Jul", null,
+                null, null, "x", "x",  null, null, null, null, null, null, null},
+            {"1.2.4", "Evaluate proposal", "J. Dow, S. Jones", "4", "2-Aug", null,
+                null, null, null, "x",  "x", null, null, null, null, null, null},
+            {"1.2.5", "Select vendor", "J. Dow", "1", "6-Aug", null,
+                null, null, null, null,  "x", null, null, null, null, null, null},
+            null,
+            {"1.3", "Research Phase", "G. Lee", "47", "9-Aug", null,
+                null, null, null, null,  "x", "x", "x", "x", "x", "x", "x"},
+            {"1.3.1", "Develop market research information needs questionnaire", "G. Lee", "2", "9-Aug", null,
+                null, null, null, null,  "x", null, null, null, null, null, null},
+            {"1.3.2", "Interview marketing group for market research needs", "G. Lee", "2", "11-Aug", null,
+                null, null, null, null,  "x", "x", null, null, null, null, null},
+            {"1.3.3", "Document information needs", "G. Lee, S. Jones", "1", "13-Aug", null,
+                null, null, null, null,  null, "x", null, null, null, null, null},
+    };
+
+    private BusinessPlan() {}
+
+    public static void main(String[] args) throws Exception {
+        Workbook wb;
+
+        if(args.length > 0 && args[0].equals("-xls")) wb = new HSSFWorkbook();
+        else wb = new XSSFWorkbook();
+
+        final SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM");
+
+        Map<String, CellStyle> styles = createStyles(wb);
+
+        Sheet sheet = wb.createSheet("Business Plan");
+
+        //turn off gridlines
+        sheet.setDisplayGridlines(false);
+        sheet.setPrintGridlines(false);
+        sheet.setFitToPage(true);
+        sheet.setHorizontallyCenter(true);
+        PrintSetup printSetup = sheet.getPrintSetup();
+        printSetup.setLandscape(true);
+
+        //the following three statements are required only for HSSF
+        sheet.setAutobreaks(true);
+        printSetup.setFitHeight((short)1);
+        printSetup.setFitWidth((short)1);
+
+        //the header row: centered text in 48pt font
+        Row headerRow = sheet.createRow(0);
+        headerRow.setHeightInPoints(12.75f);
+        for (int i = 0; i < titles.length; i++) {
+            Cell cell = headerRow.createCell(i);
+            cell.setCellValue(titles[i]);
+            cell.setCellStyle(styles.get("header"));
+        }
+        //columns for 11 weeks starting from 9-Jul
+        Calendar calendar = Calendar.getInstance();
+        int year = calendar.get(Calendar.YEAR);
+
+        calendar.setTime(fmt.parse("9-Jul"));
+        calendar.set(Calendar.YEAR, year);
+        for (int i = 0; i < 11; i++) {
+            Cell cell = headerRow.createCell(titles.length + i);
+            cell.setCellValue(calendar);
+            cell.setCellStyle(styles.get("header_date"));
+            calendar.roll(Calendar.WEEK_OF_YEAR, true);
+        }
+        //freeze the first row
+        sheet.createFreezePane(0, 1);
+
+        Row row;
+        Cell cell;
+        int rownum = 1;
+        for (int i = 0; i < data.length; i++, rownum++) {
+            row = sheet.createRow(rownum);
+            if(data[i] == null) continue;
+
+            for (int j = 0; j < data[i].length; j++) {
+                cell = row.createCell(j);
+                String styleName;
+                boolean isHeader = i == 0 || data[i-1] == null;
+                switch(j){
+                    case 0:
+                        if(isHeader) {
+                            styleName = "cell_b";
+                            cell.setCellValue(Double.parseDouble(data[i][j]));
+                        } else {
+                            styleName = "cell_normal";
+                            cell.setCellValue(data[i][j]);
+                        }
+                        break;
+                    case 1:
+                        if(isHeader) {
+                            styleName = i == 0 ? "cell_h" : "cell_bb";
+                        } else {
+                            styleName = "cell_indented";
+                        }
+                        cell.setCellValue(data[i][j]);
+                        break;
+                    case 2:
+                        styleName = isHeader ? "cell_b" : "cell_normal";
+                        cell.setCellValue(data[i][j]);
+                        break;
+                    case 3:
+                        styleName = isHeader ? "cell_b_centered" : "cell_normal_centered";
+                        cell.setCellValue(Integer.parseInt(data[i][j]));
+                        break;
+                    case 4: {
+                        calendar.setTime(fmt.parse(data[i][j]));
+                        calendar.set(Calendar.YEAR, year);
+                        cell.setCellValue(calendar);
+                        styleName = isHeader ? "cell_b_date" : "cell_normal_date";
+                        break;
+                    }
+                    case 5: {
+                        int r = rownum + 1;
+                        String fmla = "IF(AND(D"+r+",E"+r+"),E"+r+"+D"+r+",\"\")";
+                        cell.setCellFormula(fmla);
+                        styleName = isHeader ? "cell_bg" : "cell_g";
+                        break;
+                    }
+                    default:
+                        styleName = data[i][j] != null ? "cell_blue" : "cell_normal";
+                }
+
+                cell.setCellStyle(styles.get(styleName));
+            }
+        }
+
+        //group rows for each phase, row numbers are 0-based
+        sheet.groupRow(4, 6);
+        sheet.groupRow(9, 13);
+        sheet.groupRow(16, 18);
+
+        //set column widths, the width is measured in units of 1/256th of a character width
+        sheet.setColumnWidth(0, 256*6);
+        sheet.setColumnWidth(1, 256*33);
+        sheet.setColumnWidth(2, 256*20);
+        sheet.setZoom(75); //75% scale
+
+
+        // Write the output to a file
+        String file = "businessplan.xls";
+        if(wb instanceof XSSFWorkbook) file += "x";
+        FileOutputStream out = new FileOutputStream(file);
+        wb.write(out);
+        out.close();
+
+        wb.close();
+    }
+
+    /**
+     * create a library of cell styles
+     */
+    private static Map<String, CellStyle> createStyles(Workbook wb){
+        Map<String, CellStyle> styles = new HashMap<>();
+        DataFormat df = wb.createDataFormat();
+
+        CellStyle style;
+        Font headerFont = wb.createFont();
+        headerFont.setBold(true);
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setFont(headerFont);
+        styles.put("header", style);
+
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setFont(headerFont);
+        style.setDataFormat(df.getFormat("d-mmm"));
+        styles.put("header_date", style);
+
+        Font font1 = wb.createFont();
+        font1.setBold(true);
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.LEFT);
+        style.setFont(font1);
+        styles.put("cell_b", style);
+
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setFont(font1);
+        styles.put("cell_b_centered", style);
+
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.RIGHT);
+        style.setFont(font1);
+        style.setDataFormat(df.getFormat("d-mmm"));
+        styles.put("cell_b_date", style);
+
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.RIGHT);
+        style.setFont(font1);
+        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setDataFormat(df.getFormat("d-mmm"));
+        styles.put("cell_g", style);
+
+        Font font2 = wb.createFont();
+        font2.setColor(IndexedColors.BLUE.getIndex());
+        font2.setBold(true);
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.LEFT);
+        style.setFont(font2);
+        styles.put("cell_bb", style);
+
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.RIGHT);
+        style.setFont(font1);
+        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setDataFormat(df.getFormat("d-mmm"));
+        styles.put("cell_bg", style);
+
+        Font font3 = wb.createFont();
+        font3.setFontHeightInPoints((short)14);
+        font3.setColor(IndexedColors.DARK_BLUE.getIndex());
+        font3.setBold(true);
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.LEFT);
+        style.setFont(font3);
+        style.setWrapText(true);
+        styles.put("cell_h", style);
+
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.LEFT);
+        style.setWrapText(true);
+        styles.put("cell_normal", style);
+
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setWrapText(true);
+        styles.put("cell_normal_centered", style);
+
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.RIGHT);
+        style.setWrapText(true);
+        style.setDataFormat(df.getFormat("d-mmm"));
+        styles.put("cell_normal_date", style);
+
+        style = createBorderedStyle(wb);
+        style.setAlignment(HorizontalAlignment.LEFT);
+        style.setIndention((short)1);
+        style.setWrapText(true);
+        styles.put("cell_indented", style);
+
+        style = createBorderedStyle(wb);
+        style.setFillForegroundColor(IndexedColors.BLUE.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        styles.put("cell_blue", style);
+
+        return styles;
+    }
+
+    private static CellStyle createBorderedStyle(Workbook wb){
+        BorderStyle thin = BorderStyle.THIN;
+        short black = IndexedColors.BLACK.getIndex();
+
+        CellStyle style = wb.createCellStyle();
+        style.setBorderRight(thin);
+        style.setRightBorderColor(black);
+        style.setBorderBottom(thin);
+        style.setBottomBorderColor(black);
+        style.setBorderLeft(thin);
+        style.setLeftBorderColor(black);
+        style.setBorderTop(thin);
+        style.setTopBorderColor(black);
+        return style;
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/CalendarDemo.java b/src/examples/src/org/apache/poi/examples/ss/CalendarDemo.java
new file mode 100644 (file)
index 0000000..f11c1e0
--- /dev/null
@@ -0,0 +1,258 @@
+/* ====================================================================
+   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.examples.ss;
+
+import java.io.FileOutputStream;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.PrintSetup;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * A  monthly calendar created using Apache POI. Each month is on a separate sheet.
+ * <pre>
+ * Usage:
+ * CalendarDemo -xls|xlsx <year>
+ * </pre>
+ *
+ * @author Yegor Kozlov
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class CalendarDemo {
+
+    private static final String[] days = {
+            "Sunday", "Monday", "Tuesday",
+            "Wednesday", "Thursday", "Friday", "Saturday"};
+
+    private static final String[]  months = {
+            "January", "February", "March","April", "May", "June","July", "August",
+            "September","October", "November", "December"};
+
+    private CalendarDemo() {}
+
+    public static void main(String[] args) throws Exception {
+
+        Calendar calendar = Calendar.getInstance();
+        boolean xlsx = true;
+        for (String arg : args) {
+            if (arg.charAt(0) == '-') {
+                xlsx = arg.equals("-xlsx");
+            } else {
+                calendar.set(Calendar.YEAR, Integer.parseInt(arg));
+            }
+        }
+        int year = calendar.get(Calendar.YEAR);
+
+        try (Workbook wb = xlsx ? new XSSFWorkbook() : new HSSFWorkbook()) {
+
+            Map<String, CellStyle> styles = createStyles(wb);
+
+            for (int month = 0; month < 12; month++) {
+                calendar.set(Calendar.MONTH, month);
+                calendar.set(Calendar.DAY_OF_MONTH, 1);
+                //create a sheet for each month
+                Sheet sheet = wb.createSheet(months[month]);
+
+                //turn off gridlines
+                sheet.setDisplayGridlines(false);
+                sheet.setPrintGridlines(false);
+                sheet.setFitToPage(true);
+                sheet.setHorizontallyCenter(true);
+                PrintSetup printSetup = sheet.getPrintSetup();
+                printSetup.setLandscape(true);
+
+                //the following three statements are required only for HSSF
+                sheet.setAutobreaks(true);
+                printSetup.setFitHeight((short) 1);
+                printSetup.setFitWidth((short) 1);
+
+                //the header row: centered text in 48pt font
+                Row headerRow = sheet.createRow(0);
+                headerRow.setHeightInPoints(80);
+                Cell titleCell = headerRow.createCell(0);
+                titleCell.setCellValue(months[month] + " " + year);
+                titleCell.setCellStyle(styles.get("title"));
+                sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$N$1"));
+
+                //header with month titles
+                Row monthRow = sheet.createRow(1);
+                for (int i = 0; i < days.length; i++) {
+                    //set column widths, the width is measured in units of 1/256th of a character width
+                    sheet.setColumnWidth(i * 2, 5 * 256); //the column is 5 characters wide
+                    sheet.setColumnWidth(i * 2 + 1, 13 * 256); //the column is 13 characters wide
+                    sheet.addMergedRegion(new CellRangeAddress(1, 1, i * 2, i * 2 + 1));
+                    Cell monthCell = monthRow.createCell(i * 2);
+                    monthCell.setCellValue(days[i]);
+                    monthCell.setCellStyle(styles.get("month"));
+                }
+
+                int cnt = 1, day = 1;
+                int rownum = 2;
+                for (int j = 0; j < 6; j++) {
+                    Row row = sheet.createRow(rownum++);
+                    row.setHeightInPoints(100);
+                    for (int i = 0; i < days.length; i++) {
+                        Cell dayCell_1 = row.createCell(i * 2);
+                        Cell dayCell_2 = row.createCell(i * 2 + 1);
+
+                        int day_of_week = calendar.get(Calendar.DAY_OF_WEEK);
+                        if (cnt >= day_of_week && calendar.get(Calendar.MONTH) == month) {
+                            dayCell_1.setCellValue(day);
+                            calendar.set(Calendar.DAY_OF_MONTH, ++day);
+
+                            if (i == 0 || i == days.length - 1) {
+                                dayCell_1.setCellStyle(styles.get("weekend_left"));
+                                dayCell_2.setCellStyle(styles.get("weekend_right"));
+                            } else {
+                                dayCell_1.setCellStyle(styles.get("workday_left"));
+                                dayCell_2.setCellStyle(styles.get("workday_right"));
+                            }
+                        } else {
+                            dayCell_1.setCellStyle(styles.get("grey_left"));
+                            dayCell_2.setCellStyle(styles.get("grey_right"));
+                        }
+                        cnt++;
+                    }
+                    if (calendar.get(Calendar.MONTH) > month) break;
+                }
+            }
+
+            // Write the output to a file
+            String file = "calendar.xls";
+            if (wb instanceof XSSFWorkbook) file += "x";
+
+            try (FileOutputStream out = new FileOutputStream(file)) {
+                wb.write(out);
+            }
+        }
+    }
+
+    /**
+     * cell styles used for formatting calendar sheets
+     */
+    private static Map<String, CellStyle> createStyles(Workbook wb){
+        Map<String, CellStyle> styles = new HashMap<>();
+
+        short borderColor = IndexedColors.GREY_50_PERCENT.getIndex();
+
+        CellStyle style;
+        Font titleFont = wb.createFont();
+        titleFont.setFontHeightInPoints((short)48);
+        titleFont.setColor(IndexedColors.DARK_BLUE.getIndex());
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setFont(titleFont);
+        styles.put("title", style);
+
+        Font monthFont = wb.createFont();
+        monthFont.setFontHeightInPoints((short)12);
+        monthFont.setColor(IndexedColors.WHITE.getIndex());
+        monthFont.setBold(true);
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setFont(monthFont);
+        styles.put("month", style);
+
+        Font dayFont = wb.createFont();
+        dayFont.setFontHeightInPoints((short)14);
+        dayFont.setBold(true);
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.LEFT);
+        style.setVerticalAlignment(VerticalAlignment.TOP);
+        style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setLeftBorderColor(borderColor);
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(borderColor);
+        style.setFont(dayFont);
+        styles.put("weekend_left", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.TOP);
+        style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setRightBorderColor(borderColor);
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(borderColor);
+        styles.put("weekend_right", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.LEFT);
+        style.setVerticalAlignment(VerticalAlignment.TOP);
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setFillForegroundColor(IndexedColors.WHITE.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setLeftBorderColor(borderColor);
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(borderColor);
+        style.setFont(dayFont);
+        styles.put("workday_left", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.TOP);
+        style.setFillForegroundColor(IndexedColors.WHITE.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setRightBorderColor(borderColor);
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(borderColor);
+        styles.put("workday_right", style);
+
+        style = wb.createCellStyle();
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(borderColor);
+        styles.put("grey_left", style);
+
+        style = wb.createCellStyle();
+        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setRightBorderColor(borderColor);
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(borderColor);
+        styles.put("grey_right", style);
+
+        return styles;
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/CellStyleDetails.java b/src/examples/src/org/apache/poi/examples/ss/CellStyleDetails.java
new file mode 100644 (file)
index 0000000..5081bfc
--- /dev/null
@@ -0,0 +1,98 @@
+/* ====================================================================
+   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.examples.ss;
+
+import java.io.File;
+
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Color;
+import org.apache.poi.ss.usermodel.DataFormatter;
+import org.apache.poi.ss.usermodel.Font;
+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.WorkbookFactory;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+
+/**
+ * Demonstrates how to read excel styles for cells
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class CellStyleDetails {
+    private CellStyleDetails() {}
+
+    public static void main(String[] args) throws Exception {
+        if(args.length == 0) {
+           throw new IllegalArgumentException("Filename must be given");
+        }
+
+        try (Workbook wb = WorkbookFactory.create(new File(args[0]))) {
+            DataFormatter formatter = new DataFormatter();
+
+            for (int sn = 0; sn < wb.getNumberOfSheets(); sn++) {
+                Sheet sheet = wb.getSheetAt(sn);
+                System.out.println("Sheet #" + sn + " : " + sheet.getSheetName());
+
+                for (Row row : sheet) {
+                    System.out.println("  Row " + row.getRowNum());
+
+                    for (Cell cell : row) {
+                        CellReference ref = new CellReference(cell);
+                        System.out.print("    " + ref.formatAsString());
+                        System.out.print(" (" + cell.getColumnIndex() + ") ");
+
+                        CellStyle style = cell.getCellStyle();
+                        System.out.print("Format=" + style.getDataFormatString() + " ");
+                        System.out.print("FG=" + renderColor(style.getFillForegroundColorColor()) + " ");
+                        System.out.print("BG=" + renderColor(style.getFillBackgroundColorColor()) + " ");
+
+                        Font font = wb.getFontAt(style.getFontIndexAsInt());
+                        System.out.print("Font=" + font.getFontName() + " ");
+                        System.out.print("FontColor=");
+                        if (font instanceof HSSFFont) {
+                            System.out.print(renderColor(((HSSFFont) font).getHSSFColor((HSSFWorkbook) wb)));
+                        }
+                        if (font instanceof XSSFFont) {
+                            System.out.print(renderColor(((XSSFFont) font).getXSSFColor()));
+                        }
+
+                        System.out.println();
+                        System.out.println("        " + formatter.formatCellValue(cell));
+                    }
+                }
+
+                System.out.println();
+            }
+        }
+    }
+
+    private static String renderColor(Color color) {
+       if(color instanceof HSSFColor) {
+          return ((HSSFColor)color).getHexString();
+       } else if(color instanceof XSSFColor) {
+          return ((XSSFColor)color).getARGBHex();
+       } else {
+          return "(none)";
+       }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/ConditionalFormats.java b/src/examples/src/org/apache/poi/examples/ss/ConditionalFormats.java
new file mode 100644 (file)
index 0000000..22eec96
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ *  ====================================================================
+ *    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.examples.ss;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.ConditionalFormattingEvaluator;
+import org.apache.poi.ss.formula.EvaluationConditionalFormatRule;
+import org.apache.poi.ss.formula.WorkbookEvaluatorProvider;
+import org.apache.poi.ss.usermodel.BuiltinFormats;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.ColorScaleFormatting;
+import org.apache.poi.ss.usermodel.ComparisonOperator;
+import org.apache.poi.ss.usermodel.ConditionalFormattingRule;
+import org.apache.poi.ss.usermodel.ConditionalFormattingThreshold.RangeType;
+import org.apache.poi.ss.usermodel.DataBarFormatting;
+import org.apache.poi.ss.usermodel.ExtendedColor;
+import org.apache.poi.ss.usermodel.FontFormatting;
+import org.apache.poi.ss.usermodel.IconMultiStateFormatting;
+import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.PatternFormatting;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.SheetConditionalFormatting;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Excel Conditional Formatting -- Examples
+ *
+ * <p>
+ *   Partly based on the code snippets from
+ *   http://www.contextures.com/xlcondformat03.html
+ * </p>
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class ConditionalFormats {
+
+    private ConditionalFormats() {}
+
+    /**
+     * generates a sample workbook with conditional formatting,
+     * and prints out a summary of applied formats for one sheet
+     * @param args pass "-xls" to generate an HSSF workbook, default is XSSF
+     */
+    public static void main(String[] args) throws IOException {
+        final boolean isHSSF = args.length > 0 && args[0].equals("-xls");
+        try (Workbook wb = isHSSF ? new HSSFWorkbook() : new XSSFWorkbook()) {
+
+            sameCell(wb.createSheet("Same Cell"));
+            multiCell(wb.createSheet("MultiCell"));
+            overlapping(wb.createSheet("Overlapping"));
+            errors(wb.createSheet("Errors"));
+            hideDupplicates(wb.createSheet("Hide Dups"));
+            formatDuplicates(wb.createSheet("Duplicates"));
+            inList(wb.createSheet("In List"));
+            expiry(wb.createSheet("Expiry"));
+            shadeAlt(wb.createSheet("Shade Alt"));
+            shadeBands(wb.createSheet("Shade Bands"));
+            iconSets(wb.createSheet("Icon Sets"));
+            colourScales(wb.createSheet("Colour Scales"));
+            dataBars(wb.createSheet("Data Bars"));
+
+            // print overlapping rule results
+            evaluateRules(wb, "Overlapping");
+
+            // Write the output to a file
+            String file = "cf-poi.xls";
+            if (wb instanceof XSSFWorkbook) {
+                file += "x";
+            }
+            try (FileOutputStream out = new FileOutputStream(file)) {
+                wb.write(out);
+            }
+            System.out.println("Generated: " + file);
+        }
+    }
+
+    /**
+     * Highlight cells based on their values
+     */
+    static void sameCell(Sheet sheet) {
+        sheet.createRow(0).createCell(0).setCellValue(84);
+        sheet.createRow(1).createCell(0).setCellValue(74);
+        sheet.createRow(2).createCell(0).setCellValue(50);
+        sheet.createRow(3).createCell(0).setCellValue(51);
+        sheet.createRow(4).createCell(0).setCellValue(49);
+        sheet.createRow(5).createCell(0).setCellValue(41);
+
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        // Condition 1: Cell Value Is   greater than  70   (Blue Fill)
+        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule(ComparisonOperator.GT, "70");
+        PatternFormatting fill1 = rule1.createPatternFormatting();
+        fill1.setFillBackgroundColor(IndexedColors.BLUE.index);
+        fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+        // Condition 2: Cell Value Is  less than      50   (Green Fill)
+        ConditionalFormattingRule rule2 = sheetCF.createConditionalFormattingRule(ComparisonOperator.LT, "50");
+        PatternFormatting fill2 = rule2.createPatternFormatting();
+        fill2.setFillBackgroundColor(IndexedColors.GREEN.index);
+        fill2.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+        CellRangeAddress[] regions = {
+                CellRangeAddress.valueOf("A1:A6")
+        };
+
+        sheetCF.addConditionalFormatting(regions, rule1, rule2);
+
+        sheet.getRow(0).createCell(2).setCellValue("<== Condition 1: Cell Value Is greater than 70 (Blue Fill)");
+        sheet.getRow(4).createCell(2).setCellValue("<== Condition 2: Cell Value Is less than 50 (Green Fill)");
+    }
+
+    /**
+     * Highlight multiple cells based on a formula
+     */
+    static void multiCell(Sheet sheet) {
+        // header row
+        Row row0 = sheet.createRow(0);
+        row0.createCell(0).setCellValue("Units");
+        row0.createCell(1).setCellValue("Cost");
+        row0.createCell(2).setCellValue("Total");
+
+        Row row1 = sheet.createRow(1);
+        row1.createCell(0).setCellValue(71);
+        row1.createCell(1).setCellValue(29);
+        row1.createCell(2).setCellValue(2059);
+
+        Row row2 = sheet.createRow(2);
+        row2.createCell(0).setCellValue(85);
+        row2.createCell(1).setCellValue(29);
+        row2.createCell(2).setCellValue(2059);
+
+        Row row3 = sheet.createRow(3);
+        row3.createCell(0).setCellValue(71);
+        row3.createCell(1).setCellValue(29);
+        row3.createCell(2).setCellValue(2059);
+
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        // Condition 1: Formula Is   =$B2>75   (Blue Fill)
+        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("$A2>75");
+        PatternFormatting fill1 = rule1.createPatternFormatting();
+        fill1.setFillBackgroundColor(IndexedColors.BLUE.index);
+        fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+        CellRangeAddress[] regions = {
+                CellRangeAddress.valueOf("A2:C4")
+        };
+
+        sheetCF.addConditionalFormatting(regions, rule1);
+
+        sheet.getRow(2).createCell(4).setCellValue("<== Condition 1: Formula Is =$B2>75   (Blue Fill)");
+    }
+
+    /**
+     * Multiple conditional formatting rules can apply to
+     *  one cell, some combining, some beating others.
+     * Done in order of the rules added to the
+     *  SheetConditionalFormatting object
+     */
+    static void overlapping(Sheet sheet) {
+        for (int i=0; i<40; i++) {
+            int rn = i+1;
+            Row r = sheet.createRow(i);
+            r.createCell(0).setCellValue("This is row " + rn + " (" + i + ")");
+            String str = "";
+            if (rn%2 == 0) {
+                str = str + "even ";
+            }
+            if (rn%3 == 0) {
+                str = str + "x3 ";
+            }
+            if (rn%5 == 0) {
+                str = str + "x5 ";
+            }
+            if (rn%10 == 0) {
+                str = str + "x10 ";
+            }
+            if (str.length() == 0) {
+                str = "nothing special...";
+            }
+            r.createCell(1).setCellValue("It is " + str);
+        }
+        sheet.autoSizeColumn(0);
+        sheet.autoSizeColumn(1);
+
+        sheet.getRow(1).createCell(3).setCellValue("Even rows are blue");
+        sheet.getRow(2).createCell(3).setCellValue("Multiples of 3 have a grey background");
+        sheet.getRow(4).createCell(3).setCellValue("Multiples of 5 are bold");
+        sheet.getRow(9).createCell(3).setCellValue("Multiples of 10 are red (beats even)");
+
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        // Condition 1: Row divides by 10, red (will beat #1)
+        ConditionalFormattingRule rule1 =
+                sheetCF.createConditionalFormattingRule("MOD(ROW(),10)=0");
+        FontFormatting font1 = rule1.createFontFormatting();
+        font1.setFontColorIndex(IndexedColors.RED.index);
+
+        // Condition 2: Row is even, blue
+        ConditionalFormattingRule rule2 =
+                sheetCF.createConditionalFormattingRule("MOD(ROW(),2)=0");
+        FontFormatting font2 = rule2.createFontFormatting();
+        font2.setFontColorIndex(IndexedColors.BLUE.index);
+
+        // Condition 3: Row divides by 5, bold
+        ConditionalFormattingRule rule3 =
+                sheetCF.createConditionalFormattingRule("MOD(ROW(),5)=0");
+        FontFormatting font3 = rule3.createFontFormatting();
+        font3.setFontStyle(false, true);
+
+        // Condition 4: Row divides by 3, grey background
+        ConditionalFormattingRule rule4 =
+                sheetCF.createConditionalFormattingRule("MOD(ROW(),3)=0");
+        PatternFormatting fill4 = rule4.createPatternFormatting();
+        fill4.setFillBackgroundColor(IndexedColors.GREY_25_PERCENT.index);
+        fill4.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+        // Apply
+        CellRangeAddress[] regions = {
+                CellRangeAddress.valueOf("A1:F41")
+        };
+
+        sheetCF.addConditionalFormatting(regions, rule1);
+        sheetCF.addConditionalFormatting(regions, rule2);
+        sheetCF.addConditionalFormatting(regions, rule3);
+        sheetCF.addConditionalFormatting(regions, rule4);
+    }
+
+    /**
+     *  Use Excel conditional formatting to check for errors,
+     *  and change the font colour to match the cell colour.
+     *  In this example, if formula result is  #DIV/0! then it will have white font colour.
+     */
+    static void errors(Sheet sheet) {
+        sheet.createRow(0).createCell(0).setCellValue(84);
+        sheet.createRow(1).createCell(0).setCellValue(0);
+        sheet.createRow(2).createCell(0).setCellFormula("ROUND(A1/A2,0)");
+        sheet.createRow(3).createCell(0).setCellValue(0);
+        sheet.createRow(4).createCell(0).setCellFormula("ROUND(A6/A4,0)");
+        sheet.createRow(5).createCell(0).setCellValue(41);
+
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        // Condition 1: Formula Is   =ISERROR(C2)   (White Font)
+        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("ISERROR(A1)");
+        FontFormatting font = rule1.createFontFormatting();
+        font.setFontColorIndex(IndexedColors.WHITE.index);
+
+        CellRangeAddress[] regions = {
+                CellRangeAddress.valueOf("A1:A6")
+        };
+
+        sheetCF.addConditionalFormatting(regions, rule1);
+
+        sheet.getRow(2).createCell(1).setCellValue("<== The error in this cell is hidden. Condition: Formula Is   =ISERROR(C2)   (White Font)");
+        sheet.getRow(4).createCell(1).setCellValue("<== The error in this cell is hidden. Condition: Formula Is   =ISERROR(C2)   (White Font)");
+    }
+
+    /**
+     * Use Excel conditional formatting to hide the duplicate values,
+     * and make the list easier to read. In this example, when the table is sorted by Region,
+     * the second (and subsequent) occurences of each region name will have white font colour.
+     */
+    static void hideDupplicates(Sheet sheet) {
+        sheet.createRow(0).createCell(0).setCellValue("City");
+        sheet.createRow(1).createCell(0).setCellValue("Boston");
+        sheet.createRow(2).createCell(0).setCellValue("Boston");
+        sheet.createRow(3).createCell(0).setCellValue("Chicago");
+        sheet.createRow(4).createCell(0).setCellValue("Chicago");
+        sheet.createRow(5).createCell(0).setCellValue("New York");
+
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        // Condition 1: Formula Is   =A2=A1   (White Font)
+        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("A2=A1");
+        FontFormatting font = rule1.createFontFormatting();
+        font.setFontColorIndex(IndexedColors.WHITE.index);
+
+        CellRangeAddress[] regions = {
+                CellRangeAddress.valueOf("A2:A6")
+        };
+
+        sheetCF.addConditionalFormatting(regions, rule1);
+
+        sheet.getRow(1).createCell(1).setCellValue("<== the second (and subsequent) " +
+                "occurences of each region name will have white font colour.  " +
+                "Condition: Formula Is   =A2=A1   (White Font)");
+    }
+
+    /**
+     * Use Excel conditional formatting to highlight duplicate entries in a column.
+     */
+    static void formatDuplicates(Sheet sheet) {
+        sheet.createRow(0).createCell(0).setCellValue("Code");
+        sheet.createRow(1).createCell(0).setCellValue(4);
+        sheet.createRow(2).createCell(0).setCellValue(3);
+        sheet.createRow(3).createCell(0).setCellValue(6);
+        sheet.createRow(4).createCell(0).setCellValue(3);
+        sheet.createRow(5).createCell(0).setCellValue(5);
+        sheet.createRow(6).createCell(0).setCellValue(8);
+        sheet.createRow(7).createCell(0).setCellValue(0);
+        sheet.createRow(8).createCell(0).setCellValue(2);
+        sheet.createRow(9).createCell(0).setCellValue(8);
+        sheet.createRow(10).createCell(0).setCellValue(6);
+
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        // Condition 1: Formula Is   =A2=A1   (White Font)
+        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("COUNTIF($A$2:$A$11,A2)>1");
+        FontFormatting font = rule1.createFontFormatting();
+        font.setFontStyle(false, true);
+        font.setFontColorIndex(IndexedColors.BLUE.index);
+
+        CellRangeAddress[] regions = {
+                CellRangeAddress.valueOf("A2:A11")
+        };
+
+        sheetCF.addConditionalFormatting(regions, rule1);
+
+        sheet.getRow(2).createCell(1).setCellValue("<== Duplicates numbers in the column are highlighted.  " +
+                "Condition: Formula Is =COUNTIF($A$2:$A$11,A2)>1   (Blue Font)");
+    }
+
+    /**
+     * Use Excel conditional formatting to highlight items that are in a list on the worksheet.
+     */
+    static void inList(Sheet sheet) {
+        sheet.createRow(0).createCell(0).setCellValue("Codes");
+        sheet.createRow(1).createCell(0).setCellValue("AA");
+        sheet.createRow(2).createCell(0).setCellValue("BB");
+        sheet.createRow(3).createCell(0).setCellValue("GG");
+        sheet.createRow(4).createCell(0).setCellValue("AA");
+        sheet.createRow(5).createCell(0).setCellValue("FF");
+        sheet.createRow(6).createCell(0).setCellValue("XX");
+        sheet.createRow(7).createCell(0).setCellValue("CC");
+
+        sheet.getRow(0).createCell(2).setCellValue("Valid");
+        sheet.getRow(1).createCell(2).setCellValue("AA");
+        sheet.getRow(2).createCell(2).setCellValue("BB");
+        sheet.getRow(3).createCell(2).setCellValue("CC");
+
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        // Condition 1: Formula Is   =A2=A1   (White Font)
+        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("COUNTIF($C$2:$C$4,A2)");
+        PatternFormatting fill1 = rule1.createPatternFormatting();
+        fill1.setFillBackgroundColor(IndexedColors.LIGHT_BLUE.index);
+        fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+        CellRangeAddress[] regions = {
+                CellRangeAddress.valueOf("A2:A8")
+        };
+
+        sheetCF.addConditionalFormatting(regions, rule1);
+
+        sheet.getRow(2).createCell(3).setCellValue("<== Use Excel conditional formatting to highlight items that are in a list on the worksheet");
+    }
+
+    /**
+     *  Use Excel conditional formatting to highlight payments that are due in the next thirty days.
+     *  In this example, Due dates are entered in cells A2:A4.
+     */
+    static void expiry(Sheet sheet) {
+        CellStyle style = sheet.getWorkbook().createCellStyle();
+        style.setDataFormat((short)BuiltinFormats.getBuiltinFormat("d-mmm"));
+
+        sheet.createRow(0).createCell(0).setCellValue("Date");
+        sheet.createRow(1).createCell(0).setCellFormula("TODAY()+29");
+        sheet.createRow(2).createCell(0).setCellFormula("A2+1");
+        sheet.createRow(3).createCell(0).setCellFormula("A3+1");
+
+        for(int rownum = 1; rownum <= 3; rownum++) {
+            sheet.getRow(rownum).getCell(0).setCellStyle(style);
+        }
+
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        // Condition 1: Formula Is   =A2=A1   (White Font)
+        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("AND(A2-TODAY()>=0,A2-TODAY()<=30)");
+        FontFormatting font = rule1.createFontFormatting();
+        font.setFontStyle(false, true);
+        font.setFontColorIndex(IndexedColors.BLUE.index);
+
+        CellRangeAddress[] regions = {
+                CellRangeAddress.valueOf("A2:A4")
+        };
+
+        sheetCF.addConditionalFormatting(regions, rule1);
+
+        sheet.getRow(0).createCell(1).setCellValue("Dates within the next 30 days are highlighted");
+    }
+
+    /**
+     * Use Excel conditional formatting to shade alternating rows on the worksheet
+     */
+    static void shadeAlt(Sheet sheet) {
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        // Condition 1: Formula Is   =A2=A1   (White Font)
+        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("MOD(ROW(),2)");
+        PatternFormatting fill1 = rule1.createPatternFormatting();
+        fill1.setFillBackgroundColor(IndexedColors.LIGHT_GREEN.index);
+        fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+        CellRangeAddress[] regions = {
+                CellRangeAddress.valueOf("A1:Z100")
+        };
+
+        sheetCF.addConditionalFormatting(regions, rule1);
+
+        sheet.createRow(0).createCell(1).setCellValue("Shade Alternating Rows");
+        sheet.createRow(1).createCell(1).setCellValue("Condition: Formula Is  =MOD(ROW(),2)   (Light Green Fill)");
+    }
+
+    /**
+     * You can use Excel conditional formatting to shade bands of rows on the worksheet.
+     * In this example, 3 rows are shaded light grey, and 3 are left with no shading.
+     * In the MOD function, the total number of rows in the set of banded rows (6) is entered.
+     */
+    static void shadeBands(Sheet sheet) {
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("MOD(ROW(),6)<3");
+        PatternFormatting fill1 = rule1.createPatternFormatting();
+        fill1.setFillBackgroundColor(IndexedColors.GREY_25_PERCENT.index);
+        fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+        CellRangeAddress[] regions = {
+                CellRangeAddress.valueOf("A1:Z100")
+        };
+
+        sheetCF.addConditionalFormatting(regions, rule1);
+
+        sheet.createRow(0).createCell(1).setCellValue("Shade Bands of Rows");
+        sheet.createRow(1).createCell(1).setCellValue("Condition: Formula Is  =MOD(ROW(),6)<2   (Light Grey Fill)");
+    }
+
+    /**
+     * Icon Sets / Multi-States allow you to have icons shown which vary
+     *  based on the values, eg Red traffic light / Yellow traffic light /
+     *  Green traffic light
+     */
+    static void iconSets(Sheet sheet) {
+        sheet.createRow(0).createCell(0).setCellValue("Icon Sets");
+        Row r = sheet.createRow(1);
+        r.createCell(0).setCellValue("Reds");
+        r.createCell(1).setCellValue(0);
+        r.createCell(2).setCellValue(0);
+        r.createCell(3).setCellValue(0);
+        r = sheet.createRow(2);
+        r.createCell(0).setCellValue("Yellows");
+        r.createCell(1).setCellValue(5);
+        r.createCell(2).setCellValue(5);
+        r.createCell(3).setCellValue(5);
+        r = sheet.createRow(3);
+        r.createCell(0).setCellValue("Greens");
+        r.createCell(1).setCellValue(10);
+        r.createCell(2).setCellValue(10);
+        r.createCell(3).setCellValue(10);
+
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        CellRangeAddress[] regions = { CellRangeAddress.valueOf("B1:B4") };
+        ConditionalFormattingRule rule1 =
+                sheetCF.createConditionalFormattingRule(IconSet.GYR_3_TRAFFIC_LIGHTS);
+        IconMultiStateFormatting im1 = rule1.getMultiStateFormatting();
+        im1.getThresholds()[0].setRangeType(RangeType.MIN);
+        im1.getThresholds()[1].setRangeType(RangeType.PERCENT);
+        im1.getThresholds()[1].setValue(33d);
+        im1.getThresholds()[2].setRangeType(RangeType.MAX);
+        sheetCF.addConditionalFormatting(regions, rule1);
+
+        regions = new CellRangeAddress[] { CellRangeAddress.valueOf("C1:C4") };
+        ConditionalFormattingRule rule2 =
+                sheetCF.createConditionalFormattingRule(IconSet.GYR_3_FLAGS);
+        IconMultiStateFormatting im2 = rule1.getMultiStateFormatting();
+        im2.getThresholds()[0].setRangeType(RangeType.PERCENT);
+        im2.getThresholds()[0].setValue(0d);
+        im2.getThresholds()[1].setRangeType(RangeType.PERCENT);
+        im2.getThresholds()[1].setValue(33d);
+        im2.getThresholds()[2].setRangeType(RangeType.PERCENT);
+        im2.getThresholds()[2].setValue(67d);
+        sheetCF.addConditionalFormatting(regions, rule2);
+
+        regions = new CellRangeAddress[] { CellRangeAddress.valueOf("D1:D4") };
+        ConditionalFormattingRule rule3 =
+                sheetCF.createConditionalFormattingRule(IconSet.GYR_3_SYMBOLS_CIRCLE);
+        IconMultiStateFormatting im3 = rule1.getMultiStateFormatting();
+        im3.setIconOnly(true);
+        im3.getThresholds()[0].setRangeType(RangeType.MIN);
+        im3.getThresholds()[1].setRangeType(RangeType.NUMBER);
+        im3.getThresholds()[1].setValue(3d);
+        im3.getThresholds()[2].setRangeType(RangeType.NUMBER);
+        im3.getThresholds()[2].setValue(7d);
+        sheetCF.addConditionalFormatting(regions, rule3);
+    }
+
+    /**
+     * Color Scales / Colour Scales / Colour Gradients allow you shade the
+     *  background colour of the cell based on the values, eg from Red to
+     *  Yellow to Green.
+     */
+    static void colourScales(Sheet sheet) {
+        sheet.createRow(0).createCell(0).setCellValue("Colour Scales");
+        Row r = sheet.createRow(1);
+        r.createCell(0).setCellValue("Red-Yellow-Green");
+        for (int i=1; i<=7; i++) {
+            r.createCell(i).setCellValue((i-1)*5.0);
+        }
+        r = sheet.createRow(2);
+        r.createCell(0).setCellValue("Red-White-Blue");
+        for (int i=1; i<=9; i++) {
+            r.createCell(i).setCellValue((i-1)*5.0);
+        }
+        r = sheet.createRow(3);
+        r.createCell(0).setCellValue("Blue-Green");
+        for (int i=1; i<=16; i++) {
+            r.createCell(i).setCellValue((i-1));
+        }
+        sheet.setColumnWidth(0, 5000);
+
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        CellRangeAddress[] regions = { CellRangeAddress.valueOf("B2:H2") };
+        ConditionalFormattingRule rule1 =
+                sheetCF.createConditionalFormattingColorScaleRule();
+        ColorScaleFormatting cs1 = rule1.getColorScaleFormatting();
+        cs1.getThresholds()[0].setRangeType(RangeType.MIN);
+        cs1.getThresholds()[1].setRangeType(RangeType.PERCENTILE);
+        cs1.getThresholds()[1].setValue(50d);
+        cs1.getThresholds()[2].setRangeType(RangeType.MAX);
+        ((ExtendedColor)cs1.getColors()[0]).setARGBHex("FFF8696B");
+        ((ExtendedColor)cs1.getColors()[1]).setARGBHex("FFFFEB84");
+        ((ExtendedColor)cs1.getColors()[2]).setARGBHex("FF63BE7B");
+        sheetCF.addConditionalFormatting(regions, rule1);
+
+        regions = new CellRangeAddress[] { CellRangeAddress.valueOf("B3:J3") };
+        ConditionalFormattingRule rule2 =
+                sheetCF.createConditionalFormattingColorScaleRule();
+        ColorScaleFormatting cs2 = rule2.getColorScaleFormatting();
+        cs2.getThresholds()[0].setRangeType(RangeType.MIN);
+        cs2.getThresholds()[1].setRangeType(RangeType.PERCENTILE);
+        cs2.getThresholds()[1].setValue(50d);
+        cs2.getThresholds()[2].setRangeType(RangeType.MAX);
+        ((ExtendedColor)cs2.getColors()[0]).setARGBHex("FFF8696B");
+        ((ExtendedColor)cs2.getColors()[1]).setARGBHex("FFFCFCFF");
+        ((ExtendedColor)cs2.getColors()[2]).setARGBHex("FF5A8AC6");
+        sheetCF.addConditionalFormatting(regions, rule2);
+
+        regions = new CellRangeAddress[] { CellRangeAddress.valueOf("B4:Q4") };
+        ConditionalFormattingRule rule3=
+                sheetCF.createConditionalFormattingColorScaleRule();
+        ColorScaleFormatting cs3 = rule3.getColorScaleFormatting();
+        cs3.setNumControlPoints(2);
+        cs3.getThresholds()[0].setRangeType(RangeType.MIN);
+        cs3.getThresholds()[1].setRangeType(RangeType.MAX);
+        ((ExtendedColor)cs3.getColors()[0]).setARGBHex("FF5A8AC6");
+        ((ExtendedColor)cs3.getColors()[1]).setARGBHex("FF63BE7B");
+        sheetCF.addConditionalFormatting(regions, rule3);
+    }
+
+    /**
+     * DataBars / Data-Bars allow you to have bars shown vary
+     *  based on the values, from full to empty
+     */
+    static void dataBars(Sheet sheet) {
+        sheet.createRow(0).createCell(0).setCellValue("Data Bars");
+        Row r = sheet.createRow(1);
+        r.createCell(1).setCellValue("Green Positive");
+        r.createCell(2).setCellValue("Blue Mix");
+        r.createCell(3).setCellValue("Red Negative");
+        r = sheet.createRow(2);
+        r.createCell(1).setCellValue(0);
+        r.createCell(2).setCellValue(0);
+        r.createCell(3).setCellValue(0);
+        r = sheet.createRow(3);
+        r.createCell(1).setCellValue(5);
+        r.createCell(2).setCellValue(-5);
+        r.createCell(3).setCellValue(-5);
+        r = sheet.createRow(4);
+        r.createCell(1).setCellValue(10);
+        r.createCell(2).setCellValue(10);
+        r.createCell(3).setCellValue(-10);
+        r = sheet.createRow(5);
+        r.createCell(1).setCellValue(5);
+        r.createCell(2).setCellValue(5);
+        r.createCell(3).setCellValue(-5);
+        r = sheet.createRow(6);
+        r.createCell(1).setCellValue(20);
+        r.createCell(2).setCellValue(-10);
+        r.createCell(3).setCellValue(-20);
+        sheet.setColumnWidth(0, 3000);
+        sheet.setColumnWidth(1, 5000);
+        sheet.setColumnWidth(2, 5000);
+        sheet.setColumnWidth(3, 5000);
+
+        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+        ExtendedColor color = sheet.getWorkbook().getCreationHelper().createExtendedColor();
+        color.setARGBHex("FF63BE7B");
+        CellRangeAddress[] regions = { CellRangeAddress.valueOf("B2:B7") };
+        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule(color);
+        DataBarFormatting db1 = rule1.getDataBarFormatting();
+        db1.getMinThreshold().setRangeType(RangeType.MIN);
+        db1.getMaxThreshold().setRangeType(RangeType.MAX);
+        sheetCF.addConditionalFormatting(regions, rule1);
+
+        color = sheet.getWorkbook().getCreationHelper().createExtendedColor();
+        color.setARGBHex("FF5A8AC6");
+        regions = new CellRangeAddress[] { CellRangeAddress.valueOf("C2:C7") };
+        ConditionalFormattingRule rule2 = sheetCF.createConditionalFormattingRule(color);
+        DataBarFormatting db2 = rule2.getDataBarFormatting();
+        db2.getMinThreshold().setRangeType(RangeType.MIN);
+        db2.getMaxThreshold().setRangeType(RangeType.MAX);
+        sheetCF.addConditionalFormatting(regions, rule2);
+
+        color = sheet.getWorkbook().getCreationHelper().createExtendedColor();
+        color.setARGBHex("FFF8696B");
+        regions = new CellRangeAddress[] { CellRangeAddress.valueOf("D2:D7") };
+        ConditionalFormattingRule rule3 = sheetCF.createConditionalFormattingRule(color);
+        DataBarFormatting db3 = rule3.getDataBarFormatting();
+        db3.getMinThreshold().setRangeType(RangeType.MIN);
+        db3.getMaxThreshold().setRangeType(RangeType.MAX);
+        sheetCF.addConditionalFormatting(regions, rule3);
+    }
+
+    /**
+     * Print out a summary of the conditional formatting rules applied to cells on the given sheet.
+     * Only cells with a matching rule are printed, and for those, all matching rules are sumarized.
+     */
+    static void evaluateRules(Workbook wb, String sheetName) {
+        final WorkbookEvaluatorProvider wbEvalProv = (WorkbookEvaluatorProvider) wb.getCreationHelper().createFormulaEvaluator();
+        final ConditionalFormattingEvaluator cfEval = new ConditionalFormattingEvaluator(wb, wbEvalProv);
+        // if cell values have changed, clear cached format results
+        cfEval.clearAllCachedValues();
+
+        final Sheet sheet = wb.getSheet(sheetName);
+        for (Row r : sheet) {
+            for (Cell c : r) {
+                final List<EvaluationConditionalFormatRule> rules = cfEval.getConditionalFormattingForCell(c);
+                // check rules list for null, although current implementation will return an empty list, not null, then do what you want with results
+                if (rules == null || rules.isEmpty()) {
+                    continue;
+                }
+                final CellReference ref = ConditionalFormattingEvaluator.getRef(c);
+                if (rules.isEmpty()) {
+                    continue;
+                }
+
+                System.out.println("\n"
+                  + ref.formatAsString()
+                  + " has conditional formatting.");
+
+                for (EvaluationConditionalFormatRule rule : rules) {
+                    ConditionalFormattingRule cf = rule.getRule();
+
+                    StringBuilder b = new StringBuilder();
+                    b.append("\tRule ")
+                     .append(rule.getFormattingIndex())
+                     .append(": ");
+
+                    // check for color scale
+                    if (cf.getColorScaleFormatting() != null) {
+                        b.append("\n\t\tcolor scale (caller must calculate bucket)");
+                    }
+                    // check for data bar
+                    if (cf.getDataBarFormatting() != null) {
+                        b.append("\n\t\tdata bar (caller must calculate bucket)");
+                    }
+                    // check for icon set
+                    if (cf.getMultiStateFormatting() != null) {
+                        b.append("\n\t\ticon set (caller must calculate icon bucket)");
+                    }
+                    // check for fill
+                    if (cf.getPatternFormatting() != null) {
+                        final PatternFormatting fill = cf.getPatternFormatting();
+                        b.append("\n\t\tfill pattern ")
+                         .append(fill.getFillPattern())
+                         .append(" color index ")
+                         .append(fill.getFillBackgroundColor());
+                    }
+                    // font stuff
+                    if (cf.getFontFormatting() != null) {
+                        final FontFormatting ff = cf.getFontFormatting();
+                        b.append("\n\t\tfont format ")
+                         .append("color index ")
+                         .append(ff.getFontColorIndex());
+                        if (ff.isBold()) {
+                            b.append(" bold");
+                        }
+                        if (ff.isItalic()) {
+                            b.append(" italic");
+                        }
+                        if (ff.isStruckout()) {
+                            b.append(" strikeout");
+                        }
+                        b.append(" underline index ")
+                         .append(ff.getUnderlineType());
+                    }
+
+                    System.out.println(b);
+                }
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/DrawingBorders.java b/src/examples/src/org/apache/poi/examples/ss/DrawingBorders.java
new file mode 100644 (file)
index 0000000..f98d64b
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *  ====================================================================
+ *    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.examples.ss;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.BorderExtent;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.IndexedColors;
+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.util.CellRangeAddress;
+import org.apache.poi.ss.util.PropertyTemplate;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Excel Border Drawing - examples
+ *
+ * <p>
+ * Partly based on the code snippets from
+ * org.apache.poi.ss.examples.ConditionalFormats
+ * </p>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class DrawingBorders {
+
+    private DrawingBorders() {}
+
+    public static void main(String[] args) throws IOException {
+        try (Workbook wb = (args.length > 0 && args[0].equals("-xls"))
+            ? new HSSFWorkbook() : new XSSFWorkbook()) {
+            // add a sheet, and put some values into it
+            Sheet sh1 = wb.createSheet("Sheet1");
+            Row r = sh1.createRow(0);
+            Cell c = r.createCell(1);
+            c.setCellValue("All Borders Medium Width");
+            r = sh1.createRow(4);
+            c = r.createCell(1);
+            c.setCellValue("Medium Outside / Thin Inside Borders");
+            r = sh1.createRow(8);
+            c = r.createCell(1);
+            c.setCellValue("Colored Borders");
+
+            // draw borders (three 3x3 grids)
+            PropertyTemplate pt = new PropertyTemplate();
+            // #1) these borders will all be medium in default color
+            pt.drawBorders(new CellRangeAddress(1, 3, 1, 3),
+                    BorderStyle.MEDIUM, BorderExtent.ALL);
+            // #2) these cells will have medium outside borders and thin inside borders
+            pt.drawBorders(new CellRangeAddress(5, 7, 1, 3),
+                    BorderStyle.MEDIUM, BorderExtent.OUTSIDE);
+            pt.drawBorders(new CellRangeAddress(5, 7, 1, 3), BorderStyle.THIN,
+                    BorderExtent.INSIDE);
+            // #3) these cells will all be medium weight with different colors for the
+            //     outside, inside horizontal, and inside vertical borders. The center
+            //     cell will have no borders.
+            pt.drawBorders(new CellRangeAddress(9, 11, 1, 3),
+                    BorderStyle.MEDIUM, IndexedColors.RED.getIndex(),
+                    BorderExtent.OUTSIDE);
+            pt.drawBorders(new CellRangeAddress(9, 11, 1, 3),
+                    BorderStyle.MEDIUM, IndexedColors.BLUE.getIndex(),
+                    BorderExtent.INSIDE_VERTICAL);
+            pt.drawBorders(new CellRangeAddress(9, 11, 1, 3),
+                    BorderStyle.MEDIUM, IndexedColors.GREEN.getIndex(),
+                    BorderExtent.INSIDE_HORIZONTAL);
+            pt.drawBorders(new CellRangeAddress(10, 10, 2, 2),
+                    BorderStyle.NONE,
+                    BorderExtent.ALL);
+
+            // apply borders to sheet
+            pt.applyBorders(sh1);
+
+            // add another sheet and apply the borders to it
+            Sheet sh2 = wb.createSheet("Sheet2");
+            pt.applyBorders(sh2);
+
+            // Write the output to a file
+            String file = "db-poi.xls" + (wb instanceof XSSFWorkbook ? "x" : "");
+            try (FileOutputStream out = new FileOutputStream(file)) {
+                wb.write(out);
+            }
+            System.out.println("Generated: " + file);
+        }
+    }
+
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/ExcelComparator.java b/src/examples/src/org/apache/poi/examples/ss/ExcelComparator.java
new file mode 100644 (file)
index 0000000..825b72b
--- /dev/null
@@ -0,0 +1,685 @@
+/* ====================================================================
+   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.examples.ss;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.Color;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+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.WorkbookFactory;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+
+/**
+ * Utility to compare Excel File Contents cell by cell for all sheets.
+ *
+ * <p>This utility will be used to compare Excel File Contents cell by cell for all sheets programmatically.</p>
+ *
+ * <p>Below are the list of Attribute comparison supported in this version.</p>
+ *
+ * <ul>
+ * <li>Cell Alignment</li>
+ * <li>Cell Border Attributes</li>
+ * <li>Cell Data</li>
+ * <li>Cell Data-Type</li>
+ * <li>Cell Fill Color</li>
+ * <li>Cell Fill pattern</li>
+ * <li>Cell Font Attributes</li>
+ * <li>Cell Font Family</li>
+ * <li>Cell Font Size</li>
+ * <li>Cell Protection</li>
+ * <li>Name of the sheets</li>
+ * <li>Number of Columns</li>
+ * <li>Number of Rows</li>
+ * <li>Number of Sheet</li>
+ * </ul>
+ *
+ * <p>(Some of the above attribute comparison only work for *.xlsx format currently. In future it can be enhanced.)</p>
+ *
+ * <p><b>Usage:</b></p>
+ *
+ * <pre>
+ * {@code
+ *  Workbook wb1 = WorkbookFactory.create(new File("workBook1.xls"));
+ *  Workbook wb2 = WorkbookFactory.create(new File("workBook2.xls"));
+ *  List<String> listOfDifferences = ExcelComparator.compare(wb1, wb2);
+ *  for (String differences : listOfDifferences)
+ *      System.out.println(differences);
+ *  System.out.println("DifferenceFound = "+ excelFileDifference.isDifferenceFound);
+ *  }
+ * </pre>
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public class ExcelComparator {
+
+    private static final String CELL_DATA_DOES_NOT_MATCH = "Cell Data does not Match ::";
+    private static final String CELL_FONT_ATTRIBUTES_DOES_NOT_MATCH = "Cell Font Attributes does not Match ::";
+
+    private static class Locator {
+        Workbook workbook;
+        Sheet sheet;
+        Row row;
+        Cell cell;
+    }
+
+    List<String> listOfDifferences = new ArrayList<>();
+
+    public static void main(String[] args) throws Exception {
+        if (args.length != 2 || !(new File(args[0]).exists()) || !(new File(args[1]).exists())) {
+            System.err.println("java -cp <classpath> "+ExcelComparator.class.getCanonicalName()+" <workbook1.xls/x> <workbook2.xls/x");
+            System.exit(-1);
+        }
+
+        try (Workbook wb1 = WorkbookFactory.create(new File(args[0]), null, true)) {
+            try (Workbook wb2 = WorkbookFactory.create(new File(args[1]), null, true)) {
+                for (String d : ExcelComparator.compare(wb1, wb2)) {
+                    System.out.println(d);
+                }
+            }
+        }
+    }
+
+    /**
+     * Utility to compare Excel File Contents cell by cell for all sheets.
+     *
+     * @param wb1 the workbook1
+     * @param wb2 the workbook2
+     * @return the Excel file difference containing a flag and a list of differences
+     */
+    public static List<String> compare(Workbook wb1, Workbook wb2) {
+        Locator loc1 = new Locator();
+        Locator loc2 = new Locator();
+        loc1.workbook = wb1;
+        loc2.workbook = wb2;
+
+        ExcelComparator excelComparator = new ExcelComparator();
+        excelComparator.compareNumberOfSheets(loc1, loc2 );
+        excelComparator.compareSheetNames(loc1, loc2);
+        excelComparator.compareSheetData(loc1, loc2);
+
+        return excelComparator.listOfDifferences;
+    }
+
+    /**
+     * Compare data in all sheets.
+     */
+    private void compareDataInAllSheets(Locator loc1, Locator loc2) {
+        for (int i = 0; i < loc1.workbook.getNumberOfSheets(); i++) {
+            if (loc2.workbook.getNumberOfSheets() <= i) {
+                return;
+            }
+
+            loc1.sheet = loc1.workbook.getSheetAt(i);
+            loc2.sheet = loc2.workbook.getSheetAt(i);
+
+            compareDataInSheet(loc1, loc2);
+        }
+    }
+
+    private void compareDataInSheet(Locator loc1, Locator loc2) {
+        for (int j = 0; j <= loc1.sheet.getLastRowNum(); j++) {
+            if (loc2.sheet.getLastRowNum() <= j) {
+                return;
+            }
+
+            loc1.row = loc1.sheet.getRow(j);
+            loc2.row = loc2.sheet.getRow(j);
+
+            if ((loc1.row == null) || (loc2.row == null)) {
+                continue;
+            }
+
+            compareDataInRow(loc1, loc2);
+        }
+    }
+
+    private void compareDataInRow(Locator loc1, Locator loc2) {
+        for (int k = 0; k <= loc1.row.getLastCellNum(); k++) {
+            if (loc2.row.getLastCellNum() <= k) {
+                return;
+            }
+
+            loc1.cell = loc1.row.getCell(k);
+            loc2.cell = loc2.row.getCell(k);
+
+            if ((loc1.cell == null) || (loc2.cell == null)) {
+                continue;
+            }
+
+            compareDataInCell(loc1, loc2);
+        }
+    }
+
+    private void compareDataInCell(Locator loc1, Locator loc2) {
+        if (isCellTypeMatches(loc1, loc2)) {
+            final CellType loc1cellType = loc1.cell.getCellType();
+            switch(loc1cellType) {
+                case BLANK:
+                case STRING:
+                case ERROR:
+                    isCellContentMatches(loc1,loc2);
+                    break;
+                case BOOLEAN:
+                    isCellContentMatchesForBoolean(loc1,loc2);
+                    break;
+                case FORMULA:
+                    isCellContentMatchesForFormula(loc1,loc2);
+                    break;
+                case NUMERIC:
+                    if (DateUtil.isCellDateFormatted(loc1.cell)) {
+                        isCellContentMatchesForDate(loc1,loc2);
+                    } else {
+                        isCellContentMatchesForNumeric(loc1,loc2);
+                    }
+                    break;
+                default:
+                    throw new IllegalStateException("Unexpected cell type: " + loc1cellType);
+            }
+        }
+
+        isCellFillPatternMatches(loc1,loc2);
+        isCellAlignmentMatches(loc1,loc2);
+        isCellHiddenMatches(loc1,loc2);
+        isCellLockedMatches(loc1,loc2);
+        isCellFontFamilyMatches(loc1,loc2);
+        isCellFontSizeMatches(loc1,loc2);
+        isCellFontBoldMatches(loc1,loc2);
+        isCellUnderLineMatches(loc1,loc2);
+        isCellFontItalicsMatches(loc1,loc2);
+        isCellBorderMatches(loc1,loc2,'t');
+        isCellBorderMatches(loc1,loc2,'l');
+        isCellBorderMatches(loc1,loc2,'b');
+        isCellBorderMatches(loc1,loc2,'r');
+        isCellFillBackGroundMatches(loc1,loc2);
+    }
+
+    /**
+     * Compare number of columns in sheets.
+     */
+    private void compareNumberOfColumnsInSheets(Locator loc1, Locator loc2) {
+        for (int i = 0; i < loc1.workbook.getNumberOfSheets(); i++) {
+            if (loc2.workbook.getNumberOfSheets() <= i) {
+                return;
+            }
+
+            loc1.sheet = loc1.workbook.getSheetAt(i);
+            loc2.sheet = loc2.workbook.getSheetAt(i);
+
+            Iterator<Row> ri1 = loc1.sheet.rowIterator();
+            Iterator<Row> ri2 = loc2.sheet.rowIterator();
+
+            int num1 = (ri1.hasNext()) ? ri1.next().getPhysicalNumberOfCells() : 0;
+            int num2 = (ri2.hasNext()) ? ri2.next().getPhysicalNumberOfCells() : 0;
+
+            if (num1 != num2) {
+                String str = String.format(Locale.ROOT, "%s\nworkbook1 -> %s [%d] != workbook2 -> %s [%d]",
+                    "Number Of Columns does not Match ::",
+                    loc1.sheet.getSheetName(), num1,
+                    loc2.sheet.getSheetName(), num2
+                );
+                listOfDifferences.add(str);
+            }
+        }
+    }
+
+    /**
+     * Compare number of rows in sheets.
+     */
+    private void compareNumberOfRowsInSheets(Locator loc1, Locator loc2) {
+        for (int i = 0; i < loc1.workbook.getNumberOfSheets(); i++) {
+            if (loc2.workbook.getNumberOfSheets() <= i) {
+                return;
+            }
+
+            loc1.sheet = loc1.workbook.getSheetAt(i);
+            loc2.sheet = loc2.workbook.getSheetAt(i);
+
+            int num1 = loc1.sheet.getPhysicalNumberOfRows();
+            int num2 = loc2.sheet.getPhysicalNumberOfRows();
+
+            if (num1 != num2) {
+                String str = String.format(Locale.ROOT, "%s\nworkbook1 -> %s [%d] != workbook2 -> %s [%d]",
+                    "Number Of Rows does not Match ::",
+                    loc1.sheet.getSheetName(), num1,
+                    loc2.sheet.getSheetName(), num2
+                );
+                listOfDifferences.add(str);
+            }
+        }
+
+    }
+
+    /**
+     * Compare number of sheets.
+     */
+    private void compareNumberOfSheets(Locator loc1, Locator loc2) {
+        int num1 = loc1.workbook.getNumberOfSheets();
+        int num2 = loc2.workbook.getNumberOfSheets();
+        if (num1 != num2) {
+            String str = String.format(Locale.ROOT, "%s\nworkbook1 [%d] != workbook2 [%d]",
+                "Number of Sheets do not match ::",
+                num1, num2
+            );
+
+            listOfDifferences.add(str);
+
+        }
+    }
+
+    /**
+     * Compare sheet data.
+     */
+    private void compareSheetData(Locator loc1, Locator loc2) {
+        compareNumberOfRowsInSheets(loc1, loc2);
+        compareNumberOfColumnsInSheets(loc1, loc2);
+        compareDataInAllSheets(loc1, loc2);
+
+    }
+
+    /**
+     * Compare sheet names.
+     */
+    private void compareSheetNames(Locator loc1, Locator loc2) {
+        for (int i = 0; i < loc1.workbook.getNumberOfSheets(); i++) {
+            String name1 = loc1.workbook.getSheetName(i);
+            String name2 = (loc2.workbook.getNumberOfSheets() > i) ? loc2.workbook.getSheetName(i) : "";
+
+            if (!name1.equals(name2)) {
+                String str = String.format(Locale.ROOT, "%s\nworkbook1 -> %s [%d] != workbook2 -> %s [%d]",
+                    "Name of the sheets do not match ::", name1, i+1, name2, i+1
+                );
+                listOfDifferences.add(str);
+            }
+        }
+    }
+
+    /**
+     * Formats the message.
+     */
+    private void addMessage(Locator loc1, Locator loc2, String messageStart, String value1, String value2) {
+        String str =
+            String.format(Locale.ROOT, "%s\nworkbook1 -> %s -> %s [%s] != workbook2 -> %s -> %s [%s]",
+                messageStart,
+                loc1.sheet.getSheetName(), new CellReference(loc1.cell).formatAsString(), value1,
+                loc2.sheet.getSheetName(), new CellReference(loc2.cell).formatAsString(), value2
+            );
+        listOfDifferences.add(str);
+    }
+
+    /**
+     * Checks if cell alignment matches.
+     */
+    private void isCellAlignmentMatches(Locator loc1, Locator loc2) {
+        if(loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+            return;
+        }
+
+        HorizontalAlignment align1 = loc1.cell.getCellStyle().getAlignment();
+        HorizontalAlignment align2 = loc2.cell.getCellStyle().getAlignment();
+        if (align1 != align2) {
+            addMessage(loc1, loc2,
+                "Cell Alignment does not Match ::",
+                align1.name(),
+                align2.name()
+            );
+        }
+    }
+
+    /**
+     * Checks if cell border bottom matches.
+     */
+    private void isCellBorderMatches(Locator loc1, Locator loc2, char borderSide) {
+        if (!(loc1.cell instanceof XSSFCell) ||
+                loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+            return;
+        }
+
+        XSSFCellStyle style1 = ((XSSFCell)loc1.cell).getCellStyle();
+        XSSFCellStyle style2 = ((XSSFCell)loc2.cell).getCellStyle();
+        boolean b1, b2;
+        String borderName;
+        switch (borderSide) {
+            case 't': default:
+                b1 = style1.getBorderTop() == BorderStyle.THIN;
+                b2 = style2.getBorderTop() == BorderStyle.THIN;
+                borderName = "TOP";
+                break;
+            case 'b':
+                b1 = style1.getBorderBottom() == BorderStyle.THIN;
+                b2 = style2.getBorderBottom() == BorderStyle.THIN;
+                borderName = "BOTTOM";
+                break;
+            case 'l':
+                b1 = style1.getBorderLeft() == BorderStyle.THIN;
+                b2 = style2.getBorderLeft() == BorderStyle.THIN;
+                borderName = "LEFT";
+                break;
+            case 'r':
+                b1 = style1.getBorderRight() == BorderStyle.THIN;
+                b2 = style2.getBorderRight() == BorderStyle.THIN;
+                borderName = "RIGHT";
+                break;
+        }
+        if (b1 != b2) {
+            addMessage(loc1, loc2,
+                "Cell Border Attributes does not Match ::",
+                (b1 ? "" : "NOT ")+borderName+" BORDER",
+                (b2 ? "" : "NOT ")+borderName+" BORDER"
+            );
+        }
+    }
+
+    /**
+     * Checks if cell content matches.
+     */
+    private void isCellContentMatches(Locator loc1, Locator loc2) {
+        String str1 = loc1.cell.toString();
+        String str2 = loc2.cell.toString();
+        if (!str1.equals(str2)) {
+            addMessage(loc1,loc2,CELL_DATA_DOES_NOT_MATCH,str1,str2);
+        }
+    }
+
+    /**
+     * Checks if cell content matches for boolean.
+     */
+    private void isCellContentMatchesForBoolean(Locator loc1, Locator loc2) {
+        boolean b1 = loc1.cell.getBooleanCellValue();
+        boolean b2 = loc2.cell.getBooleanCellValue();
+        if (b1 != b2) {
+            addMessage(loc1,loc2,CELL_DATA_DOES_NOT_MATCH,Boolean.toString(b1),Boolean.toString(b2));
+        }
+    }
+
+    /**
+     * Checks if cell content matches for date.
+     */
+    private void isCellContentMatchesForDate(Locator loc1, Locator loc2) {
+        Date date1 = loc1.cell.getDateCellValue();
+        Date date2 = loc2.cell.getDateCellValue();
+        if (!date1.equals(date2)) {
+            addMessage(loc1, loc2, CELL_DATA_DOES_NOT_MATCH, date1.toString(), date2.toString());
+        }
+    }
+
+
+    /**
+     * Checks if cell content matches for formula.
+     */
+    private void isCellContentMatchesForFormula(Locator loc1, Locator loc2) {
+        // TODO: actually evaluate the formula / NPE checks
+        String form1 = loc1.cell.getCellFormula();
+        String form2 = loc2.cell.getCellFormula();
+        if (!form1.equals(form2)) {
+            addMessage(loc1, loc2, CELL_DATA_DOES_NOT_MATCH, form1, form2);
+        }
+    }
+
+    /**
+     * Checks if cell content matches for numeric.
+     */
+    private void isCellContentMatchesForNumeric(Locator loc1, Locator loc2) {
+        // TODO: Check for NaN
+        double num1 = loc1.cell.getNumericCellValue();
+        double num2 = loc2.cell.getNumericCellValue();
+        if (num1 != num2) {
+            addMessage(loc1, loc2, CELL_DATA_DOES_NOT_MATCH, Double.toString(num1), Double.toString(num2));
+        }
+    }
+
+    private String getCellFillBackground(Locator loc) {
+        Color col = loc.cell.getCellStyle().getFillForegroundColorColor();
+        return (col instanceof XSSFColor) ? ((XSSFColor)col).getARGBHex() : "NO COLOR";
+    }
+
+    /**
+     * Checks if cell file back ground matches.
+     */
+    private void isCellFillBackGroundMatches(Locator loc1, Locator loc2) {
+        if(loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+            return;
+        }
+
+        String col1 = getCellFillBackground(loc1);
+        String col2 = getCellFillBackground(loc2);
+        if (!col1.equals(col2)) {
+            addMessage(loc1, loc2, "Cell Fill Color does not Match ::", col1, col2);
+        }
+    }
+    /**
+     * Checks if cell fill pattern matches.
+     */
+    private void isCellFillPatternMatches(Locator loc1, Locator loc2) {
+        if(loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+            return;
+        }
+
+        FillPatternType fill1 = loc1.cell.getCellStyle().getFillPattern();
+        FillPatternType fill2 = loc2.cell.getCellStyle().getFillPattern();
+        if (fill1 != fill2) {
+            addMessage(loc1, loc2,
+                "Cell Fill pattern does not Match ::",
+                fill1.name(),
+                fill2.name()
+            );
+        }
+    }
+
+    /**
+     * Checks if cell font bold matches.
+     */
+    private void isCellFontBoldMatches(Locator loc1, Locator loc2) {
+        if (!(loc1.cell instanceof XSSFCell) ||
+                loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+            return;
+        }
+
+        if(hasInvalidFontIndex(loc1, loc2)) {
+            return;
+        }
+
+        boolean b1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getBold();
+        boolean b2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getBold();
+        if (b1 != b2) {
+            addMessage(loc1, loc2,
+                CELL_FONT_ATTRIBUTES_DOES_NOT_MATCH,
+                (b1 ? "" : "NOT ")+"BOLD",
+                (b2 ? "" : "NOT ")+"BOLD"
+            );
+        }
+    }
+
+    /**
+     * Checks if cell font family matches.
+     */
+    private void isCellFontFamilyMatches(Locator loc1, Locator loc2) {
+        if (!(loc1.cell instanceof XSSFCell) ||
+                loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+            return;
+        }
+
+        if(hasInvalidFontIndex(loc1, loc2)) {
+            return;
+        }
+
+        String family1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getFontName();
+        String family2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getFontName();
+        if (!family1.equals(family2)) {
+            addMessage(loc1, loc2, "Cell Font Family does not Match ::", family1, family2);
+        }
+    }
+
+    private boolean hasInvalidFontIndex(Locator loc1, Locator loc2) {
+        int fontIdx1 = loc1.cell.getCellStyle().getFontIndexAsInt();
+        int fontCount1 = ((XSSFWorkbook)loc1.workbook).getStylesSource().getFonts().size();
+        int fontIdx2 = loc2.cell.getCellStyle().getFontIndexAsInt();
+        int fontCount2 = ((XSSFWorkbook)loc2.workbook).getStylesSource().getFonts().size();
+
+        if(fontIdx1 >= fontCount1 || fontIdx2 >= fontCount2) {
+            addMessage(loc1, loc2, "Corrupted file, cell style references a font which is not defined", Integer.toString(fontIdx1), Integer.toString(fontIdx2));
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Checks if cell font italics matches.
+     */
+    private void isCellFontItalicsMatches(Locator loc1, Locator loc2) {
+        if (!(loc1.cell instanceof XSSFCell) ||
+                loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+            return;
+        }
+
+        if(hasInvalidFontIndex(loc1, loc2)) {
+            return;
+        }
+
+        boolean b1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getItalic();
+        boolean b2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getItalic();
+        if (b1 != b2) {
+            addMessage(loc1, loc2,
+                CELL_FONT_ATTRIBUTES_DOES_NOT_MATCH,
+                (b1 ? "" : "NOT ")+"ITALICS",
+                (b2 ? "" : "NOT ")+"ITALICS"
+            );
+        }
+    }
+
+    /**
+     * Checks if cell font size matches.
+     */
+    private void isCellFontSizeMatches(Locator loc1, Locator loc2) {
+        if (!(loc1.cell instanceof XSSFCell) ||
+                loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+            return;
+        }
+
+        if(hasInvalidFontIndex(loc1, loc2)) {
+            return;
+        }
+
+        short size1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getFontHeightInPoints();
+        short size2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getFontHeightInPoints();
+        if (size1 != size2) {
+            addMessage(loc1, loc2,
+                "Cell Font Size does not Match ::",
+                Short.toString(size1),
+                Short.toString(size2)
+            );
+        }
+    }
+
+    /**
+     * Checks if cell hidden matches.
+     */
+    private void isCellHiddenMatches(Locator loc1, Locator loc2) {
+        if (loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+            return;
+        }
+
+        boolean b1 = loc1.cell.getCellStyle().getHidden();
+        boolean b2 = loc1.cell.getCellStyle().getHidden();
+        if (b1 != b2) {
+            addMessage(loc1, loc2,
+                "Cell Visibility does not Match ::",
+                (b1 ? "" : "NOT ")+"HIDDEN",
+                (b2 ? "" : "NOT ")+"HIDDEN"
+            );
+        }
+    }
+
+    /**
+     * Checks if cell locked matches.
+     */
+    private void isCellLockedMatches(Locator loc1, Locator loc2) {
+        if (loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+            return;
+        }
+
+        boolean b1 = loc1.cell.getCellStyle().getLocked();
+        boolean b2 = loc1.cell.getCellStyle().getLocked();
+        if (b1 != b2) {
+            addMessage(loc1, loc2,
+                    "Cell Protection does not Match ::",
+                (b1 ? "" : "NOT ")+"LOCKED",
+                (b2 ? "" : "NOT ")+"LOCKED"
+            );
+        }
+    }
+
+    /**
+     * Checks if cell type matches.
+     */
+    private boolean isCellTypeMatches(Locator loc1, Locator loc2) {
+        CellType type1 = loc1.cell.getCellType();
+        CellType type2 = loc2.cell.getCellType();
+        if (type1 == type2) {
+            return true;
+        }
+
+        addMessage(loc1, loc2,
+            "Cell Data-Type does not Match in :: ",
+            type1.name(), type2.name()
+        );
+        return false;
+    }
+
+    /**
+     * Checks if cell under line matches.
+     */
+    private void isCellUnderLineMatches(Locator loc1, Locator loc2) {
+        // TODO: distinguish underline type
+
+        if (!(loc1.cell instanceof XSSFCell) ||
+                loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+            return;
+        }
+
+        if(hasInvalidFontIndex(loc1, loc2)) {
+            return;
+        }
+
+        byte b1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getUnderline();
+        byte b2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getUnderline();
+        if (b1 != b2) {
+            addMessage(loc1, loc2,
+                CELL_FONT_ATTRIBUTES_DOES_NOT_MATCH,
+                (b1 == 1 ? "" : "NOT ")+"UNDERLINE",
+                (b2 == 1 ? "" : "NOT ")+"UNDERLINE"
+            );
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/examples/ss/LinkedDropDownLists.java b/src/examples/src/org/apache/poi/examples/ss/LinkedDropDownLists.java
new file mode 100644 (file)
index 0000000..5cbc63b
--- /dev/null
@@ -0,0 +1,206 @@
+   /* ====================================================================
+   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.examples.ss;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.DataValidation;
+import org.apache.poi.ss.usermodel.DataValidationConstraint;
+import org.apache.poi.ss.usermodel.DataValidationHelper;
+import org.apache.poi.ss.usermodel.Name;
+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.util.CellRangeAddressList;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates one technique that may be used to create linked or dependent
+ * drop down lists. This refers to a situation in which the selection made
+ * in one drop down list affects the options that are displayed in the second
+ * or subsequent drop down list(s). In this example, the value the user selects
+ * from the down list in cell A1 will affect the values displayed in the linked
+ * drop down list in cell B1. For the sake of simplicity, the data for the drop
+ * down lists is included on the same worksheet but this does not have to be the
+ * case; the data could appear on a separate sheet. If this were done, then the
+ * names for the regions would have to be different, they would have to include
+ * the name of the sheet.
+ *
+ * There are two keys to this technique. The first is the use of named area or
+ * regions of cells to hold the data for the drop down lists and the second is
+ * making use of the INDIRECT() function to convert a name into the addresses
+ * of the cells it refers to.
+ *
+ * Note that whilst this class builds just two linked drop down lists, there is
+ * nothing to prevent more being created. Quite simply, use the value selected
+ * by the user in one drop down list to determine what is shown in another and the
+ * value selected in that drop down list to determine what is shown in a third,
+ * and so on. Also, note that the data for the drop down lists is contained on
+ * contained on the same sheet as the validations themselves. This is done simply
+ * for simplicity and there is nothing to prevent a separate sheet being created
+ * and used to hold the data. If this is done then problems may be encountered
+ * if the sheet is opened with OpenOffice Calc. To prevent these problems, it is
+ * better to include the name of the sheet when calling the setRefersToFormula()
+ * method.
+ *
+ * @author Mark Beardsley [msb at apache.org]
+ * @version 1.00 30th March 2012
+ */
+public class LinkedDropDownLists {
+
+    LinkedDropDownLists(String workbookName) throws IOException {
+        // Using the ss.usermodel allows this class to support both binary
+        // and xml based workbooks. The choice of which one to create is
+        // made by checking the file extension.
+        try (Workbook workbook = workbookName.endsWith(".xlsx") ? new XSSFWorkbook() : new HSSFWorkbook()) {
+
+            // Build the sheet that will hold the data for the validations. This
+            // must be done first as it will create names that are referenced
+            // later.
+            Sheet sheet = workbook.createSheet("Linked Validations");
+            LinkedDropDownLists.buildDataSheet(sheet);
+
+            // Build the first data validation to occupy cell A1. Note
+            // that it retrieves it's data from the named area or region called
+            // CHOICES. Further information about this can be found in the
+            // static buildDataSheet() method below.
+            CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0);
+            DataValidationHelper dvHelper = sheet.getDataValidationHelper();
+            DataValidationConstraint dvConstraint = dvHelper.createFormulaListConstraint("CHOICES");
+            DataValidation validation = dvHelper.createValidation(dvConstraint, addressList);
+            sheet.addValidationData(validation);
+
+            // Now, build the linked or dependent drop down list that will
+            // occupy cell B1. The key to the whole process is the use of the
+            // INDIRECT() function. In the buildDataSheet(0 method, a series of
+            // named regions are created and the names of three of them mirror
+            // the options available to the user in the first drop down list
+            // (in cell A1). Using the INDIRECT() function makes it possible
+            // to convert the selection the user makes in that first drop down
+            // into the addresses of a named region of cells and then to use
+            // those cells to populate the second drop down list.
+            addressList = new CellRangeAddressList(0, 0, 1, 1);
+            dvConstraint = dvHelper.createFormulaListConstraint(
+                    "INDIRECT(UPPER($A$1))");
+            validation = dvHelper.createValidation(dvConstraint, addressList);
+            sheet.addValidationData(validation);
+
+            try (FileOutputStream fos = new FileOutputStream(workbookName)) {
+                workbook.write(fos);
+            }
+        }
+    }
+
+    /**
+     * Called to populate the named areas/regions. The contents of the cells on
+     * row one will be used to populate the first drop down list. The contents of
+     * the cells on rows two, three and four will be used to populate the second
+     * drop down list, just which row will be determined by the choice the user
+     * makes in the first drop down list.
+     *
+     * In all cases, the approach is to create a row, create and populate cells
+     * with data and then specify a name that identifies those cells. With the
+     * exception of the first range, the names that are chosen for each range
+     * of cells are quite important. In short, each of the options the user
+     * could select in the first drop down list is used as the name for another
+     * range of cells. Thus, in this example, the user can select either
+     * 'Animal', 'Vegetable' or 'Mineral' in the first drop down and so the
+     * sheet contains ranges named 'ANIMAL', 'VEGETABLE' and 'MINERAL'.
+     *
+     * @param dataSheet An instance of a class that implements the Sheet Sheet
+     *        interface (HSSFSheet or XSSFSheet).
+     */
+    private static void buildDataSheet(Sheet dataSheet) {
+        Row row = null;
+        Cell cell = null;
+        Name name = null;
+
+        // The first row will hold the data for the first validation.
+        row = dataSheet.createRow(10);
+        cell = row.createCell(0);
+        cell.setCellValue("Animal");
+        cell = row.createCell(1);
+        cell.setCellValue("Vegetable");
+        cell = row.createCell(2);
+        cell.setCellValue("Mineral");
+        name = dataSheet.getWorkbook().createName();
+        name.setRefersToFormula("$A$11:$C$11");
+        name.setNameName("CHOICES");
+
+        // The next three rows will hold the data that will be used to
+        // populate the second, or linked, drop down list.
+        row = dataSheet.createRow(11);
+        cell = row.createCell(0);
+        cell.setCellValue("Lion");
+        cell = row.createCell(1);
+        cell.setCellValue("Tiger");
+        cell = row.createCell(2);
+        cell.setCellValue("Leopard");
+        cell = row.createCell(3);
+        cell.setCellValue("Elephant");
+        cell = row.createCell(4);
+        cell.setCellValue("Eagle");
+        cell = row.createCell(5);
+        cell.setCellValue("Horse");
+        cell = row.createCell(6);
+        cell.setCellValue("Zebra");
+        name = dataSheet.getWorkbook().createName();
+        name.setRefersToFormula("$A$12:$G$12");
+        name.setNameName("ANIMAL");
+
+        row = dataSheet.createRow(12);
+        cell = row.createCell(0);
+        cell.setCellValue("Cabbage");
+        cell = row.createCell(1);
+        cell.setCellValue("Cauliflower");
+        cell = row.createCell(2);
+        cell.setCellValue("Potato");
+        cell = row.createCell(3);
+        cell.setCellValue("Onion");
+        cell = row.createCell(4);
+        cell.setCellValue("Beetroot");
+        cell = row.createCell(5);
+        cell.setCellValue("Asparagus");
+        cell = row.createCell(6);
+        cell.setCellValue("Spinach");
+        cell = row.createCell(7);
+        cell.setCellValue("Chard");
+        name = dataSheet.getWorkbook().createName();
+        name.setRefersToFormula("$A$13:$H$13");
+        name.setNameName("VEGETABLE");
+
+        row = dataSheet.createRow(13);
+        cell = row.createCell(0);
+        cell.setCellValue("Bauxite");
+        cell = row.createCell(1);
+        cell.setCellValue("Quartz");
+        cell = row.createCell(2);
+        cell.setCellValue("Feldspar");
+        cell = row.createCell(3);
+        cell.setCellValue("Shist");
+        cell = row.createCell(4);
+        cell.setCellValue("Shale");
+        cell = row.createCell(5);
+        cell.setCellValue("Mica");
+        name = dataSheet.getWorkbook().createName();
+        name.setRefersToFormula("$A$14:$F$14");
+        name.setNameName("MINERAL");
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/LoadEmbedded.java b/src/examples/src/org/apache/poi/examples/ss/LoadEmbedded.java
new file mode 100644 (file)
index 0000000..3c52ecf
--- /dev/null
@@ -0,0 +1,134 @@
+/* ====================================================================
+   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.examples.ss;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hssf.usermodel.HSSFObjectData;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.Entry;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.xmlbeans.XmlException;
+
+/**
+ * Loads embedded resources from Workbooks. Code taken from the website:
+ *  https://poi.apache.org/spreadsheet/quick-guide.html#Embedded
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class LoadEmbedded {
+    private LoadEmbedded() {}
+
+    public static void main(String[] args) throws IOException, EncryptedDocumentException, OpenXML4JException, XmlException {
+       Workbook wb = WorkbookFactory.create(new File(args[0]));
+       loadEmbedded(wb);
+   }
+
+   public static void loadEmbedded(Workbook wb) throws IOException, InvalidFormatException, OpenXML4JException, XmlException {
+       if (wb instanceof HSSFWorkbook) {
+           loadEmbedded((HSSFWorkbook)wb);
+       }
+       else if (wb instanceof XSSFWorkbook) {
+           loadEmbedded((XSSFWorkbook)wb);
+       }
+       else {
+           throw new IllegalArgumentException(wb.getClass().getName());
+       }
+   }
+
+   public static void loadEmbedded(HSSFWorkbook workbook) throws IOException {
+       for (HSSFObjectData obj : workbook.getAllEmbeddedObjects()) {
+           //the OLE2 Class Name of the object
+           String oleName = obj.getOLE2ClassName();
+           if (oleName.equals("Worksheet")) {
+               DirectoryNode dn = (DirectoryNode) obj.getDirectory();
+               HSSFWorkbook embeddedWorkbook = new HSSFWorkbook(dn, false);
+               embeddedWorkbook.close();
+           } else if (oleName.equals("Document")) {
+               DirectoryNode dn = (DirectoryNode) obj.getDirectory();
+               HWPFDocument embeddedWordDocument = new HWPFDocument(dn);
+               embeddedWordDocument.close();
+           }  else if (oleName.equals("Presentation")) {
+               DirectoryNode dn = (DirectoryNode) obj.getDirectory();
+               SlideShow<?,?> embeddedSlieShow = new HSLFSlideShow(dn);
+               embeddedSlieShow.close();
+           } else {
+               if(obj.hasDirectoryEntry()){
+                   // The DirectoryEntry is a DocumentNode. Examine its entries to find out what it is
+                   DirectoryNode dn = (DirectoryNode) obj.getDirectory();
+                   for (Entry entry : dn) {
+                       //System.out.println(oleName + "." + entry.getName());
+                   }
+               } else {
+                   // There is no DirectoryEntry
+                   // Recover the object's data from the HSSFObjectData instance.
+                   byte[] objectData = obj.getObjectData();
+               }
+           }
+       }
+   }
+
+   public static void loadEmbedded(XSSFWorkbook workbook) throws IOException, InvalidFormatException, OpenXML4JException, XmlException {
+       for (PackagePart pPart : workbook.getAllEmbeddedParts()) {
+           String contentType = pPart.getContentType();
+           if (contentType.equals("application/vnd.ms-excel")) {
+               // Excel Workbook - either binary or OpenXML
+               HSSFWorkbook embeddedWorkbook = new HSSFWorkbook(pPart.getInputStream());
+               embeddedWorkbook.close();
+           } else if (contentType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
+               // Excel Workbook - OpenXML file format
+               XSSFWorkbook embeddedWorkbook = new XSSFWorkbook(pPart.getInputStream());
+               embeddedWorkbook.close();
+           } else if (contentType.equals("application/msword")) {
+               // Word Document - binary (OLE2CDF) file format
+               HWPFDocument document = new HWPFDocument(pPart.getInputStream());
+               document.close();
+           } else if (contentType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
+               // Word Document - OpenXML file format
+               XWPFDocument document = new XWPFDocument(pPart.getInputStream());
+               document.close();
+           } else if (contentType.equals("application/vnd.ms-powerpoint")) {
+               // PowerPoint Document - binary file format
+               HSLFSlideShow slideShow = new HSLFSlideShow(pPart.getInputStream());
+               slideShow.close();
+           } else if (contentType.equals("application/vnd.openxmlformats-officedocument.presentationml.presentation")) {
+               // PowerPoint Document - OpenXML file format
+               XMLSlideShow slideShow = new XMLSlideShow(pPart.getInputStream());
+               slideShow.close();
+           } else {
+               // Any other type of embedded object.
+               System.out.println("Unknown Embedded Document: " + contentType);
+               InputStream inputStream = pPart.getInputStream();
+               inputStream.close();
+           }
+       }
+   }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/LoanCalculator.java b/src/examples/src/org/apache/poi/examples/ss/LoanCalculator.java
new file mode 100644 (file)
index 0000000..28d1c64
--- /dev/null
@@ -0,0 +1,319 @@
+/* ====================================================================
+   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.examples.ss;
+
+import java.io.FileOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Name;
+import org.apache.poi.ss.usermodel.PrintSetup;
+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.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Simple Loan Calculator. Demonstrates advance usage of cell formulas and named ranges.
+ *
+ * Usage:
+ *   LoanCalculator -xls|xlsx
+ *
+ * @author Yegor Kozlov
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class LoanCalculator {
+
+    private LoanCalculator() {}
+
+    public static void main(String[] args) throws Exception {
+        Workbook wb;
+
+        if(args.length > 0 && args[0].equals("-xls")) wb = new HSSFWorkbook();
+        else wb = new XSSFWorkbook();
+
+        Map<String, CellStyle> styles = createStyles(wb);
+        Sheet sheet = wb.createSheet("Loan Calculator");
+        sheet.setPrintGridlines(false);
+        sheet.setDisplayGridlines(false);
+
+        PrintSetup printSetup = sheet.getPrintSetup();
+        printSetup.setLandscape(true);
+        sheet.setFitToPage(true);
+        sheet.setHorizontallyCenter(true);
+
+        sheet.setColumnWidth(0, 3*256);
+        sheet.setColumnWidth(1, 3*256);
+        sheet.setColumnWidth(2, 11*256);
+        sheet.setColumnWidth(3, 14*256);
+        sheet.setColumnWidth(4, 14*256);
+        sheet.setColumnWidth(5, 14*256);
+        sheet.setColumnWidth(6, 14*256);
+
+        createNames(wb);
+
+        Row titleRow = sheet.createRow(0);
+        titleRow.setHeightInPoints(35);
+        for (int i = 1; i <= 7; i++) {
+            titleRow.createCell(i).setCellStyle(styles.get("title"));
+        }
+        Cell titleCell = titleRow.getCell(2);
+        titleCell.setCellValue("Simple Loan Calculator");
+        sheet.addMergedRegion(CellRangeAddress.valueOf("$C$1:$H$1"));
+
+        Row row = sheet.createRow(2);
+        Cell cell = row.createCell(4);
+        cell.setCellValue("Enter values");
+        cell.setCellStyle(styles.get("item_right"));
+
+        row = sheet.createRow(3);
+        cell = row.createCell(2);
+        cell.setCellValue("Loan amount");
+        cell.setCellStyle(styles.get("item_left"));
+        cell = row.createCell(4);
+        cell.setCellStyle(styles.get("input_$"));
+        cell.setAsActiveCell();
+
+        row = sheet.createRow(4);
+        cell = row.createCell(2);
+        cell.setCellValue("Annual interest rate");
+        cell.setCellStyle(styles.get("item_left"));
+        cell = row.createCell(4);
+        cell.setCellStyle(styles.get("input_%"));
+
+        row = sheet.createRow(5);
+        cell = row.createCell(2);
+        cell.setCellValue("Loan period in years");
+        cell.setCellStyle(styles.get("item_left"));
+        cell = row.createCell(4);
+        cell.setCellStyle(styles.get("input_i"));
+
+        row = sheet.createRow(6);
+        cell = row.createCell(2);
+        cell.setCellValue("Start date of loan");
+        cell.setCellStyle(styles.get("item_left"));
+        cell = row.createCell(4);
+        cell.setCellStyle(styles.get("input_d"));
+
+        row = sheet.createRow(8);
+        cell = row.createCell(2);
+        cell.setCellValue("Monthly payment");
+        cell.setCellStyle(styles.get("item_left"));
+        cell = row.createCell(4);
+        cell.setCellFormula("IF(Values_Entered,Monthly_Payment,\"\")");
+        cell.setCellStyle(styles.get("formula_$"));
+
+        row = sheet.createRow(9);
+        cell = row.createCell(2);
+        cell.setCellValue("Number of payments");
+        cell.setCellStyle(styles.get("item_left"));
+        cell = row.createCell(4);
+        cell.setCellFormula("IF(Values_Entered,Loan_Years*12,\"\")");
+        cell.setCellStyle(styles.get("formula_i"));
+
+        row = sheet.createRow(10);
+        cell = row.createCell(2);
+        cell.setCellValue("Total interest");
+        cell.setCellStyle(styles.get("item_left"));
+        cell = row.createCell(4);
+        cell.setCellFormula("IF(Values_Entered,Total_Cost-Loan_Amount,\"\")");
+        cell.setCellStyle(styles.get("formula_$"));
+
+        row = sheet.createRow(11);
+        cell = row.createCell(2);
+        cell.setCellValue("Total cost of loan");
+        cell.setCellStyle(styles.get("item_left"));
+        cell = row.createCell(4);
+        cell.setCellFormula("IF(Values_Entered,Monthly_Payment*Number_of_Payments,\"\")");
+        cell.setCellStyle(styles.get("formula_$"));
+
+
+        // Write the output to a file
+        String file = "loan-calculator.xls";
+        if(wb instanceof XSSFWorkbook) file += "x";
+        FileOutputStream out = new FileOutputStream(file);
+        wb.write(out);
+        out.close();
+    }
+
+    /**
+     * cell styles used for formatting calendar sheets
+     */
+    private static Map<String, CellStyle> createStyles(Workbook wb){
+        Map<String, CellStyle> styles = new HashMap<>();
+
+        CellStyle style;
+        Font titleFont = wb.createFont();
+        titleFont.setFontHeightInPoints((short)14);
+        titleFont.setFontName("Trebuchet MS");
+        style = wb.createCellStyle();
+        style.setFont(titleFont);
+        style.setBorderBottom(BorderStyle.DOTTED);
+        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        styles.put("title", style);
+
+        Font itemFont = wb.createFont();
+        itemFont.setFontHeightInPoints((short)9);
+        itemFont.setFontName("Trebuchet MS");
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.LEFT);
+        style.setFont(itemFont);
+        styles.put("item_left", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.RIGHT);
+        style.setFont(itemFont);
+        styles.put("item_right", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.RIGHT);
+        style.setFont(itemFont);
+        style.setBorderRight(BorderStyle.DOTTED);
+        style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderBottom(BorderStyle.DOTTED);
+        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderLeft(BorderStyle.DOTTED);
+        style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderTop(BorderStyle.DOTTED);
+        style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setDataFormat(wb.createDataFormat().getFormat("_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)"));
+        styles.put("input_$", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.RIGHT);
+        style.setFont(itemFont);
+        style.setBorderRight(BorderStyle.DOTTED);
+        style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderBottom(BorderStyle.DOTTED);
+        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderLeft(BorderStyle.DOTTED);
+        style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderTop(BorderStyle.DOTTED);
+        style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setDataFormat(wb.createDataFormat().getFormat("0.000%"));
+        styles.put("input_%", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.RIGHT);
+        style.setFont(itemFont);
+        style.setBorderRight(BorderStyle.DOTTED);
+        style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderBottom(BorderStyle.DOTTED);
+        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderLeft(BorderStyle.DOTTED);
+        style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderTop(BorderStyle.DOTTED);
+        style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setDataFormat(wb.createDataFormat().getFormat("0"));
+        styles.put("input_i", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setFont(itemFont);
+        style.setDataFormat(wb.createDataFormat().getFormat("m/d/yy"));
+        styles.put("input_d", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.RIGHT);
+        style.setFont(itemFont);
+        style.setBorderRight(BorderStyle.DOTTED);
+        style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderBottom(BorderStyle.DOTTED);
+        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderLeft(BorderStyle.DOTTED);
+        style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderTop(BorderStyle.DOTTED);
+        style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setDataFormat(wb.createDataFormat().getFormat("$##,##0.00"));
+        style.setBorderBottom(BorderStyle.DOTTED);
+        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        styles.put("formula_$", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.RIGHT);
+        style.setFont(itemFont);
+        style.setBorderRight(BorderStyle.DOTTED);
+        style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderBottom(BorderStyle.DOTTED);
+        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderLeft(BorderStyle.DOTTED);
+        style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setBorderTop(BorderStyle.DOTTED);
+        style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setDataFormat(wb.createDataFormat().getFormat("0"));
+        style.setBorderBottom(BorderStyle.DOTTED);
+        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        styles.put("formula_i", style);
+
+        return styles;
+    }
+
+    //define named ranges for the inputs and formulas
+    public static void createNames(Workbook wb){
+        Name name;
+
+        name = wb.createName();
+        name.setNameName("Interest_Rate");
+        name.setRefersToFormula("'Loan Calculator'!$E$5");
+
+        name = wb.createName();
+        name.setNameName("Loan_Amount");
+        name.setRefersToFormula("'Loan Calculator'!$E$4");
+
+        name = wb.createName();
+        name.setNameName("Loan_Start");
+        name.setRefersToFormula("'Loan Calculator'!$E$7");
+
+        name = wb.createName();
+        name.setNameName("Loan_Years");
+        name.setRefersToFormula("'Loan Calculator'!$E$6");
+
+        name = wb.createName();
+        name.setNameName("Number_of_Payments");
+        name.setRefersToFormula("'Loan Calculator'!$E$10");
+
+        name = wb.createName();
+        name.setNameName("Monthly_Payment");
+        name.setRefersToFormula("-PMT(Interest_Rate/12,Number_of_Payments,Loan_Amount)");
+
+        name = wb.createName();
+        name.setNameName("Total_Cost");
+        name.setRefersToFormula("'Loan Calculator'!$E$12");
+
+        name = wb.createName();
+        name.setNameName("Total_Interest");
+        name.setRefersToFormula("'Loan Calculator'!$E$11");
+
+        name = wb.createName();
+        name.setNameName("Values_Entered");
+        name.setRefersToFormula("IF(Loan_Amount*Interest_Rate*Loan_Years*Loan_Start>0,1,0)");
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/SSPerformanceTest.java b/src/examples/src/org/apache/poi/examples/ss/SSPerformanceTest.java
new file mode 100644 (file)
index 0000000..a5b7eb7
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ *  ====================================================================
+ *    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.examples.ss;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ooxml.POIXMLTypeLoader;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class SSPerformanceTest {
+    private SSPerformanceTest() {}
+
+    public static void main(String[] args) throws IOException {
+        if (args.length < 4) {
+            usage("need at least four command arguments");
+        }
+
+        String type = args[0];
+        int rows = parseInt(args[1], "Failed to parse rows value as integer");
+        int cols = parseInt(args[2], "Failed to parse cols value as integer");
+        boolean saveFile = parseInt(args[3], "Failed to parse saveFile value as integer") != 0;
+
+        boolean warmup = false;
+        for(int arg = 4; arg < args.length;arg++) {
+            if(args[arg].equals("--unsynchronized-xmlbeans")) {
+                POIXMLTypeLoader.DEFAULT_XML_OPTIONS.setUnsynchronized();
+            }
+            if(args[arg].equals("--with-warmup-run")) {
+                warmup = true;
+            }
+        }
+
+        if(warmup) {
+            System.out.println("Performing a warmup run first");
+            runWithArgs(type, rows, cols, saveFile);
+        }
+
+        long timeStarted = System.currentTimeMillis();
+        runWithArgs(type, rows, cols, saveFile);
+        long timeFinished = System.currentTimeMillis();
+
+        System.out.printf("Elapsed %.2f seconds for arguments %s\n", ((double)timeFinished - timeStarted) / 1000, Arrays.toString(args));
+    }
+
+    private static void runWithArgs(String type, int rows, int cols, boolean saveFile) throws IOException {
+        try (Workbook workBook = createWorkbook(type)) {
+            boolean isHType = workBook instanceof HSSFWorkbook;
+            addContent(workBook, isHType, rows, cols);
+
+            if (saveFile) {
+                String fileName = type + "_" + rows + "_" + cols + "." + getFileSuffix(type);
+                saveFile(workBook, fileName);
+            }
+        }
+    }
+
+    private static void addContent(Workbook workBook, boolean isHType, int rows, int cols) {
+        Map<String, CellStyle> styles = createStyles(workBook);
+
+        Sheet sheet = workBook.createSheet("Main Sheet");
+
+        Cell headerCell = sheet.createRow(0).createCell(0);
+        headerCell.setCellValue("Header text is spanned across multiple cells");
+        headerCell.setCellStyle(styles.get("header"));
+        sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$F$1"));
+
+        int sheetNo = 0;
+        int rowIndexInSheet = 1;
+        double value = 0;
+        Calendar calendar = Calendar.getInstance();
+        for (int rowIndex = 0; rowIndex < rows; rowIndex++) {
+            if (isHType && sheetNo != rowIndex / 0x10000) {
+                sheet = workBook.createSheet("Spillover from sheet " + (++sheetNo));
+                headerCell.setCellValue("Header text is spanned across multiple cells");
+                headerCell.setCellStyle(styles.get("header"));
+                sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$F$1"));
+                rowIndexInSheet = 1;
+            }
+
+            Row row = sheet.createRow(rowIndexInSheet);
+            for (int colIndex = 0; colIndex < cols; colIndex++) {
+                value = populateCell(styles, value, calendar, rowIndex, row, colIndex);
+            }
+            rowIndexInSheet++;
+        }
+    }
+
+    private static double populateCell(Map<String, CellStyle> styles, double value, Calendar calendar, int rowIndex, Row row, int colIndex) {
+        Cell cell = row.createCell(colIndex);
+        String address = new CellReference(cell).formatAsString();
+        switch (colIndex){
+            case 0:
+                // column A: default number format
+                cell.setCellValue(value++);
+                break;
+            case 1:
+                // column B: #,##0
+                cell.setCellValue(value++);
+                cell.setCellStyle(styles.get("#,##0.00"));
+                break;
+            case 2:
+                // column C: $#,##0.00
+                cell.setCellValue(value++);
+                cell.setCellStyle(styles.get("$#,##0.00"));
+                break;
+            case 3:
+                // column D: red bold text on yellow background
+                cell.setCellValue(address);
+                cell.setCellStyle(styles.get("red-bold"));
+                break;
+            case 4:
+                // column E: boolean
+                // TODO booleans are shown as 1/0 instead of TRUE/FALSE
+                cell.setCellValue(rowIndex % 2 == 0);
+                break;
+            case 5:
+                // column F:  date / time
+                cell.setCellValue(calendar);
+                cell.setCellStyle(styles.get("m/d/yyyy"));
+                calendar.roll(Calendar.DAY_OF_YEAR, -1);
+                break;
+            case 6:
+                // column F: formula
+                // TODO formulas are not yet supported  in SXSSF
+                //cell.setCellFormula("SUM(A" + (rowIndex+1) + ":E" + (rowIndex+1)+ ")");
+                //break;
+            default:
+                cell.setCellValue(value++);
+                break;
+        }
+        return value;
+    }
+
+    private static void saveFile(Workbook workBook, String fileName) {
+        try {
+            FileOutputStream out = new FileOutputStream(fileName);
+            workBook.write(out);
+            out.close();
+        } catch (IOException ioe) {
+            System.err.println("Error: failed to write to file \"" + fileName + "\", reason=" + ioe.getMessage());
+        }
+    }
+
+    static Map<String, CellStyle> createStyles(Workbook wb) {
+        Map<String, CellStyle> styles = new HashMap<>();
+        CellStyle style;
+
+        Font headerFont = wb.createFont();
+        headerFont.setFontHeightInPoints((short) 14);
+        headerFont.setBold(true);
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setFont(headerFont);
+        style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        styles.put("header", style);
+
+        Font monthFont = wb.createFont();
+        monthFont.setFontHeightInPoints((short)12);
+        monthFont.setColor(IndexedColors.RED.getIndex());
+        monthFont.setBold(true);
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setFont(monthFont);
+        styles.put("red-bold", style);
+
+        String[] nfmt = {"#,##0.00", "$#,##0.00", "m/d/yyyy"};
+        for(String fmt : nfmt){
+            style = wb.createCellStyle();
+            style.setDataFormat(wb.createDataFormat().getFormat(fmt));
+            styles.put(fmt, style);
+        }
+
+        return styles;
+    }
+
+
+    static void usage(String message) {
+        System.err.println(message);
+        System.err.println("usage: java SSPerformanceTest HSSF|XSSF|SXSSF rows cols saveFile (0|1)? [--unsynchronized-xmlbeans] [--with-warmup-run]");
+        System.exit(1);
+    }
+
+    static Workbook createWorkbook(String type) {
+        if ("HSSF".equals(type))
+            return new HSSFWorkbook();
+        else if ("XSSF".equals(type))
+            return new XSSFWorkbook();
+        else if ("SXSSF".equals(type))
+            return new SXSSFWorkbook();
+
+        usage("Unknown type \"" + type + "\"");
+        throw new IllegalArgumentException("Should not reach this point");
+    }
+
+    static String getFileSuffix(String type) {
+        if ("HSSF".equals(type))
+            return "xls";
+        else if ("XSSF".equals(type))
+            return "xlsx";
+        else if ("SXSSF".equals(type))
+            return "xlsx";
+        return null;
+    }
+
+    static int parseInt(String value, String msg) {
+        try {
+            return Integer.parseInt(value);
+        } catch (NumberFormatException e) {
+            usage(msg);
+        }
+        return 0;
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/TimesheetDemo.java b/src/examples/src/org/apache/poi/examples/ss/TimesheetDemo.java
new file mode 100644 (file)
index 0000000..77b55c8
--- /dev/null
@@ -0,0 +1,234 @@
+/* ====================================================================
+   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.examples.ss;
+
+import java.io.FileOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.PrintSetup;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * A weekly timesheet created using Apache POI.
+ * Usage:
+ *  TimesheetDemo -xls|xlsx
+ *
+ * @author Yegor Kozlov
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class TimesheetDemo {
+    private static final String[] titles = {
+            "Person",  "ID", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",
+            "Total\nHrs", "Overtime\nHrs", "Regular\nHrs"
+    };
+
+    private static final Object[][] sample_data = {
+            {"Yegor Kozlov", "YK", 5.0, 8.0, 10.0, 5.0, 5.0, 7.0, 6.0},
+            {"Gisella Bronzetti", "GB", 4.0, 3.0, 1.0, 3.5, null, null, 4.0},
+    };
+
+    private TimesheetDemo() {}
+
+    public static void main(String[] args) throws Exception {
+        Workbook wb;
+
+        if(args.length > 0 && args[0].equals("-xls")) wb = new HSSFWorkbook();
+        else wb = new XSSFWorkbook();
+
+        Map<String, CellStyle> styles = createStyles(wb);
+
+        Sheet sheet = wb.createSheet("Timesheet");
+        PrintSetup printSetup = sheet.getPrintSetup();
+        printSetup.setLandscape(true);
+        sheet.setFitToPage(true);
+        sheet.setHorizontallyCenter(true);
+
+        //title row
+        Row titleRow = sheet.createRow(0);
+        titleRow.setHeightInPoints(45);
+        Cell titleCell = titleRow.createCell(0);
+        titleCell.setCellValue("Weekly Timesheet");
+        titleCell.setCellStyle(styles.get("title"));
+        sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$L$1"));
+
+        //header row
+        Row headerRow = sheet.createRow(1);
+        headerRow.setHeightInPoints(40);
+        Cell headerCell;
+        for (int i = 0; i < titles.length; i++) {
+            headerCell = headerRow.createCell(i);
+            headerCell.setCellValue(titles[i]);
+            headerCell.setCellStyle(styles.get("header"));
+        }
+
+        int rownum = 2;
+        for (int i = 0; i < 10; i++) {
+            Row row = sheet.createRow(rownum++);
+            for (int j = 0; j < titles.length; j++) {
+                Cell cell = row.createCell(j);
+                if(j == 9){
+                    //the 10th cell contains sum over week days, e.g. SUM(C3:I3)
+                    String ref = "C" +rownum+ ":I" + rownum;
+                    cell.setCellFormula("SUM("+ref+")");
+                    cell.setCellStyle(styles.get("formula"));
+                } else if (j == 11){
+                    cell.setCellFormula("J" +rownum+ "-K" + rownum);
+                    cell.setCellStyle(styles.get("formula"));
+                } else {
+                    cell.setCellStyle(styles.get("cell"));
+                }
+            }
+        }
+
+        //row with totals below
+        Row sumRow = sheet.createRow(rownum++);
+        sumRow.setHeightInPoints(35);
+        Cell cell;
+        cell = sumRow.createCell(0);
+        cell.setCellStyle(styles.get("formula"));
+        cell = sumRow.createCell(1);
+        cell.setCellValue("Total Hrs:");
+        cell.setCellStyle(styles.get("formula"));
+
+        for (int j = 2; j < 12; j++) {
+            cell = sumRow.createCell(j);
+            String ref = (char)('A' + j) + "3:" + (char)('A' + j) + "12";
+            cell.setCellFormula("SUM(" + ref + ")");
+            if(j >= 9) cell.setCellStyle(styles.get("formula_2"));
+            else cell.setCellStyle(styles.get("formula"));
+        }
+        rownum++;
+        sumRow = sheet.createRow(rownum++);
+        sumRow.setHeightInPoints(25);
+        cell = sumRow.createCell(0);
+        cell.setCellValue("Total Regular Hours");
+        cell.setCellStyle(styles.get("formula"));
+        cell = sumRow.createCell(1);
+        cell.setCellFormula("L13");
+        cell.setCellStyle(styles.get("formula_2"));
+        sumRow = sheet.createRow(rownum++);
+        sumRow.setHeightInPoints(25);
+        cell = sumRow.createCell(0);
+        cell.setCellValue("Total Overtime Hours");
+        cell.setCellStyle(styles.get("formula"));
+        cell = sumRow.createCell(1);
+        cell.setCellFormula("K13");
+        cell.setCellStyle(styles.get("formula_2"));
+
+        //set sample data
+        for (int i = 0; i < sample_data.length; i++) {
+            Row row = sheet.getRow(2 + i);
+            for (int j = 0; j < sample_data[i].length; j++) {
+                if(sample_data[i][j] == null) continue;
+
+                if(sample_data[i][j] instanceof String) {
+                    row.getCell(j).setCellValue((String)sample_data[i][j]);
+                } else {
+                    row.getCell(j).setCellValue((Double)sample_data[i][j]);
+                }
+            }
+        }
+
+        //finally set column widths, the width is measured in units of 1/256th of a character width
+        sheet.setColumnWidth(0, 30*256); //30 characters wide
+        for (int i = 2; i < 9; i++) {
+            sheet.setColumnWidth(i, 6*256);  //6 characters wide
+        }
+        sheet.setColumnWidth(10, 10*256); //10 characters wide
+
+        // Write the output to a file
+        String file = "timesheet.xls";
+        if(wb instanceof XSSFWorkbook) file += "x";
+        FileOutputStream out = new FileOutputStream(file);
+        wb.write(out);
+        out.close();
+    }
+
+    /**
+     * Create a library of cell styles
+     */
+    private static Map<String, CellStyle> createStyles(Workbook wb){
+        Map<String, CellStyle> styles = new HashMap<>();
+        CellStyle style;
+        Font titleFont = wb.createFont();
+        titleFont.setFontHeightInPoints((short)18);
+        titleFont.setBold(true);
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setFont(titleFont);
+        styles.put("title", style);
+
+        Font monthFont = wb.createFont();
+        monthFont.setFontHeightInPoints((short)11);
+        monthFont.setColor(IndexedColors.WHITE.getIndex());
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setFont(monthFont);
+        style.setWrapText(true);
+        styles.put("header", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setWrapText(true);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setRightBorderColor(IndexedColors.BLACK.getIndex());
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
+        style.setBorderTop(BorderStyle.THIN);
+        style.setTopBorderColor(IndexedColors.BLACK.getIndex());
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
+        styles.put("cell", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setDataFormat(wb.createDataFormat().getFormat("0.00"));
+        styles.put("formula", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setDataFormat(wb.createDataFormat().getFormat("0.00"));
+        styles.put("formula_2", style);
+
+        return styles;
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/ToCSV.java b/src/examples/src/org/apache/poi/examples/ss/ToCSV.java
new file mode 100644 (file)
index 0000000..f334667
--- /dev/null
@@ -0,0 +1,741 @@
+/* ====================================================================
+   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.examples.ss;
+
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.DataFormatter;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+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.WorkbookFactory;
+
+/**
+ * Demonstrates <em>one</em> way to convert an Excel spreadsheet into a CSV
+ * file. This class makes the following assumptions;
+ * <list>
+ * <li>1. Where the Excel workbook contains more that one worksheet, then a single
+ *    CSV file will contain the data from all of the worksheets.</li>
+ * <li>2. The data matrix contained in the CSV file will be square. This means that
+ *    the number of fields in each record of the CSV file will match the number
+ *    of cells in the longest row found in the Excel workbook. Any short records
+ *    will be 'padded' with empty fields - an empty field is represented in the
+ *    the CSV file in this way - ,,.</li>
+ * <li>3. Empty fields will represent missing cells.</li>
+ * <li>4. A record consisting of empty fields will be used to represent an empty row
+ *    in the Excel workbook.</li>
+ * </list>
+ * Therefore, if the worksheet looked like this;
+ *
+ * <pre>
+ *  ___________________________________________
+ *     |       |       |       |       |       |
+ *     |   A   |   B   |   C   |   D   |   E   |
+ *  ___|_______|_______|_______|_______|_______|
+ *     |       |       |       |       |       |
+ *   1 |   1   |   2   |   3   |   4   |   5   |
+ *  ___|_______|_______|_______|_______|_______|
+ *     |       |       |       |       |       |
+ *   2 |       |       |       |       |       |
+ *  ___|_______|_______|_______|_______|_______|
+ *     |       |       |       |       |       |
+ *   3 |       |   A   |       |   B   |       |
+ *  ___|_______|_______|_______|_______|_______|
+ *     |       |       |       |       |       |
+ *   4 |       |       |       |       |   Z   |
+ *  ___|_______|_______|_______|_______|_______|
+ *     |       |       |       |       |       |
+ *   5 | 1,400 |       |  250  |       |       |
+ *  ___|_______|_______|_______|_______|_______|
+ *
+ * </pre>
+ *
+ * Then, the resulting CSV file will contain the following lines (records);
+ * <pre>
+ * 1,2,3,4,5
+ * ,,,,
+ * ,A,,B,
+ * ,,,,Z
+ * "1,400",,250,,
+ * </pre><p>
+ * Typically, the comma is used to separate each of the fields that, together,
+ * constitute a single record or line within the CSV file. This is not however
+ * a hard and fast rule and so this class allows the user to determine which
+ * character is used as the field separator and assumes the comma if none other
+ * is specified.
+ * </p><p>
+ * If a field contains the separator then it will be escaped. If the file should
+ * obey Excel's CSV formatting rules, then the field will be surrounded with
+ * speech marks whilst if it should obey UNIX conventions, each occurrence of
+ * the separator will be preceded by the backslash character.
+ * </p><p>
+ * If a field contains an end of line (EOL) character then it too will be
+ * escaped. If the file should obey Excel's CSV formatting rules then the field
+ * will again be surrounded by speech marks. On the other hand, if the file
+ * should follow UNIX conventions then a single backslash will precede the
+ * EOL character. There is no single applicable standard for UNIX and some
+ * appications replace the CR with \r and the LF with \n but this class will
+ * not do so.
+ * </p><p>
+ * If the field contains double quotes then that character will be escaped. It
+ * seems as though UNIX does not define a standard for this whilst Excel does.
+ * Should the CSV file have to obey Excel's formmating rules then the speech
+ * mark character will be escaped with a second set of speech marks. Finally, an
+ * enclosing set of speah marks will also surround the entire field. Thus, if
+ * the following line of text appeared in a cell - "Hello" he said - it would
+ * look like this when converted into a field within a CSV file - """Hello"" he
+ * said".
+ * </p><p>
+ * Finally, it is worth noting that talk of CSV 'standards' is really slightly
+ * missleading as there is no such thing. It may well be that the code in this
+ * class has to be modified to produce files to suit a specific application
+ * or requirement.
+ * </p>
+ * @author Mark B
+ * @version 1.00 9th April 2010
+ *          1.10 13th April 2010 - Added support for processing all Excel
+ *                                 workbooks in a folder along with the ability
+ *                                 to specify a field separator character.
+ *          2.00 14th April 2010 - Added support for embedded characters; the
+ *                                 field separator, EOL and double quotes or
+ *                                 speech marks. In addition, gave the client
+ *                                 the ability to select how these are handled,
+ *                                 either obeying Excel's or UNIX formatting
+ *                                 conventions.
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public class ToCSV {
+
+    private Workbook workbook;
+    private ArrayList<ArrayList<String>> csvData;
+    private int maxRowWidth;
+    private int formattingConvention;
+    private DataFormatter formatter;
+    private FormulaEvaluator evaluator;
+    private String separator;
+
+    private static final String CSV_FILE_EXTENSION = ".csv";
+    private static final String DEFAULT_SEPARATOR = ",";
+
+    /**
+     * Identifies that the CSV file should obey Excel's formatting conventions
+     * with regard to escaping certain embedded characters - the field separator,
+     * speech mark and end of line (EOL) character
+     */
+    public static final int EXCEL_STYLE_ESCAPING = 0;
+
+    /**
+     * Identifies that the CSV file should obey UNIX formatting conventions
+     * with regard to escaping certain embedded characters - the field separator
+     * and end of line (EOL) character
+     */
+    public static final int UNIX_STYLE_ESCAPING = 1;
+
+    /**
+     * Process the contents of a folder, convert the contents of each Excel
+     * workbook into CSV format and save the resulting file to the specified
+     * folder using the same name as the original workbook with the .xls or
+     * .xlsx extension replaced by .csv. This method will ensure that the
+     * CSV file created contains the comma field separator and that embedded
+     * characters such as the field separator, the EOL and double quotes are
+     * escaped in accordance with Excel's convention.
+     *
+     * @param strSource An instance of the String class that encapsulates the
+     *        name of and path to either a folder containing those Excel
+     *        workbook(s) or the name of and path to an individual Excel workbook
+     *        that is/are to be converted.
+     * @param strDestination An instance of the String class encapsulating the
+     *        name of and path to a folder that will contain the resulting CSV
+     *        files.
+     * @throws java.io.FileNotFoundException Thrown if any file cannot be located
+     *         on the filesystem during processing.
+     * @throws java.io.IOException Thrown if the filesystem encounters any
+     *         problems during processing.
+     * @throws java.lang.IllegalArgumentException Thrown if the values passed
+     *         to the strSource parameter refers to a file or folder that does not
+     *         exist or if the value passed to the strDestination paramater refers
+     *         to a folder that does not exist or simply does not refer to a
+     *         folder.
+     */
+    public void convertExcelToCSV(String strSource, String strDestination)
+                       throws FileNotFoundException, IOException,
+                              IllegalArgumentException {
+
+        // Simply chain the call to the overloaded convertExcelToCSV(String,
+        // String, String, int) method, pass the default separator and ensure
+        // that certain embedded characters are escaped in accordance with
+        // Excel's formatting conventions
+        this.convertExcelToCSV(strSource, strDestination,
+                ToCSV.DEFAULT_SEPARATOR, ToCSV.EXCEL_STYLE_ESCAPING);
+    }
+
+    /**
+     * Process the contents of a folder, convert the contents of each Excel
+     * workbook into CSV format and save the resulting file to the specified
+     * folder using the same name as the original workbook with the .xls or
+     * .xlsx extension replaced by .csv. This method allows the client to
+     * define the field separator but will ensure that embedded characters such
+     * as the field separator, the EOL and double quotes are escaped in
+     * accordance with Excel's convention.
+     *
+     * @param strSource An instance of the String class that encapsulates the
+     *        name of and path to either a folder containing those Excel
+     *        workbook(s) or the name of and path to an individual Excel workbook
+     *        that is/are to be converted.
+     * @param strDestination An instance of the String class encapsulating the
+     *        name of and path to a folder that will contain the resulting CSV
+     *        files.
+     * @param separator An instance of the String class that encapsulates the
+     *        character or characters the client wishes to use as the field
+     *        separator.
+     * @throws java.io.FileNotFoundException Thrown if any file cannot be located
+     *         on the filesystem during processing.
+     * @throws java.io.IOException Thrown if the filesystem encounters any
+     *         problems during processing.
+     * @throws java.lang.IllegalArgumentException Thrown if the values passed
+     *         to the strSource parameter refers to a file or folder that does not
+     *         exist or if the value passed to the strDestination paramater refers
+     *         to a folder that does not exist or simply does not refer to a
+     *         folder.
+     */
+    public void convertExcelToCSV(String strSource, String strDestination,
+                                  String separator)
+                       throws FileNotFoundException, IOException,
+                              IllegalArgumentException {
+
+        // Simply chain the call to the overloaded convertExcelToCSV(String,
+        // String, String, int) method and ensure that certain embedded
+        // characters are escaped in accordance with Excel's formatting
+        // conventions
+        this.convertExcelToCSV(strSource, strDestination,
+                separator, ToCSV.EXCEL_STYLE_ESCAPING);
+    }
+
+    /**
+     * Process the contents of a folder, convert the contents of each Excel
+     * workbook into CSV format and save the resulting file to the specified
+     * folder using the same name as the original workbook with the .xls or
+     * .xlsx extension replaced by .csv
+     *
+     * @param strSource An instance of the String class that encapsulates the
+     *        name of and path to either a folder containing those Excel
+     *        workbook(s) or the name of and path to an individual Excel workbook
+     *        that is/are to be converted.
+     * @param strDestination An instance of the String class encapsulating the name
+     *        of and path to a folder that will contain the resulting CSV files.
+     * @param formattingConvention A primitive int whose value will determine
+     *        whether certain embedded characters should be escaped in accordance
+     *        with Excel's or UNIX formatting conventions. Two constants are
+     *        defined to support this option; ToCSV.EXCEL_STYLE_ESCAPING and
+     *        ToCSV.UNIX_STYLE_ESCAPING
+     * @param separator An instance of the String class encapsulating the
+     *        characters or characters that should be used to separate items
+     *        on a line within the CSV file.
+     * @throws java.io.FileNotFoundException Thrown if any file cannot be located
+     *         on the filesystem during processing.
+     * @throws java.io.IOException Thrown if the filesystem encounters any
+     *         problems during processing.
+     * @throws java.lang.IllegalArgumentException Thrown if the values passed
+     *         to the strSource parameter refers to a file or folder that does not
+     *         exist, if the value passed to the strDestination paramater refers
+     *         to a folder that does not exist,  if the value passed to the
+     *         strDestination parameter does not refer to a folder or if the
+     *         value passed to the formattingConvention parameter is other than
+     *         one of the values defined by the constants ToCSV.EXCEL_STYLE_ESCAPING
+     *         and ToCSV.UNIX_STYLE_ESCAPING.
+     */
+    public void convertExcelToCSV(String strSource, String strDestination,
+                                  String separator, int formattingConvention)
+                       throws FileNotFoundException, IOException,
+                              IllegalArgumentException {
+        // Check that the source file/folder exists.
+        File source = new File(strSource);
+        if(!source.exists()) {
+            throw new IllegalArgumentException("The source for the Excel " +
+                    "file(s) cannot be found at " + source);
+        }
+
+        // Ensure thaat the folder the user has chosen to save the CSV files
+        // away into firstly exists and secondly is a folder rather than, for
+        // instance, a data file.
+        File destination = new File(strDestination);
+        if(!destination.exists()) {
+            throw new IllegalArgumentException("The destination directory " + destination + " for the " +
+                    "converted CSV file(s) does not exist.");
+        }
+        if(!destination.isDirectory()) {
+            throw new IllegalArgumentException("The destination " + destination + " for the CSV " +
+                    "file(s) is not a directory/folder.");
+        }
+
+        // Ensure the value passed to the formattingConvention parameter is
+        // within range.
+        if(formattingConvention != ToCSV.EXCEL_STYLE_ESCAPING &&
+           formattingConvention != ToCSV.UNIX_STYLE_ESCAPING) {
+            throw new IllegalArgumentException("The value passed to the " +
+                    "formattingConvention parameter is out of range: " + formattingConvention + ", expecting one of " +
+                    ToCSV.EXCEL_STYLE_ESCAPING + " or " + ToCSV.UNIX_STYLE_ESCAPING);
+        }
+
+        // Copy the spearator character and formatting convention into local
+        // variables for use in other methods.
+        this.separator = separator;
+        this.formattingConvention = formattingConvention;
+
+        // Check to see if the sourceFolder variable holds a reference to
+        // a file or a folder full of files.
+        final File[] filesList;
+        if(source.isDirectory()) {
+            // Get a list of all of the Excel spreadsheet files (workbooks) in
+            // the source folder/directory
+            filesList = source.listFiles(new ExcelFilenameFilter());
+        }
+        else {
+            // Assume that it must be a file handle - although there are other
+            // options the code should perhaps check - and store the reference
+            // into the filesList variable.
+            filesList = new File[]{source};
+        }
+
+        // Step through each of the files in the source folder and for each
+        // open the workbook, convert it's contents to CSV format and then
+        // save the resulting file away into the folder specified by the
+        // contents of the destination variable. Note that the name of the
+        // csv file will be created by taking the name of the Excel file,
+        // removing the extension and replacing it with .csv. Note that there
+        // is one drawback with this approach; if the folder holding the files
+        // contains two workbooks whose names match but one is a binary file
+        // (.xls) and the other a SpreadsheetML file (.xlsx), then the names
+        // for both CSV files will be identical and one CSV file will,
+        // therefore, over-write the other.
+        if (filesList != null) {
+            for(File excelFile : filesList) {
+                // Open the workbook
+                this.openWorkbook(excelFile);
+
+                // Convert it's contents into a CSV file
+                this.convertToCSV();
+
+                // Build the name of the csv folder from that of the Excel workbook.
+                // Simply replace the .xls or .xlsx file extension with .csv
+                String destinationFilename = excelFile.getName();
+                destinationFilename = destinationFilename.substring(
+                        0, destinationFilename.lastIndexOf('.')) +
+                        ToCSV.CSV_FILE_EXTENSION;
+
+                // Save the CSV file away using the newly constricted file name
+                // and to the specified directory.
+                this.saveCSVFile(new File(destination, destinationFilename));
+            }
+        }
+    }
+
+    /**
+     * Open an Excel workbook ready for conversion.
+     *
+     * @param file An instance of the File class that encapsulates a handle
+     *        to a valid Excel workbook. Note that the workbook can be in
+     *        either binary (.xls) or SpreadsheetML (.xlsx) format.
+     * @throws java.io.FileNotFoundException Thrown if the file cannot be located.
+     * @throws java.io.IOException Thrown if a problem occurs in the file system.
+     */
+    private void openWorkbook(File file) throws FileNotFoundException,
+                                           IOException {
+        System.out.println("Opening workbook [" + file.getName() + "]");
+        try (FileInputStream fis = new FileInputStream(file)) {
+
+            // Open the workbook and then create the FormulaEvaluator and
+            // DataFormatter instances that will be needed to, respectively,
+            // force evaluation of forumlae found in cells and create a
+            // formatted String encapsulating the cells contents.
+            this.workbook = WorkbookFactory.create(fis);
+            this.evaluator = this.workbook.getCreationHelper().createFormulaEvaluator();
+            this.formatter = new DataFormatter(true);
+        }
+    }
+
+    /**
+     * Called to convert the contents of the currently opened workbook into
+     * a CSV file.
+     */
+    private void convertToCSV() {
+        Sheet sheet;
+        Row row;
+        int lastRowNum;
+        this.csvData = new ArrayList<>();
+
+        System.out.println("Converting files contents to CSV format.");
+
+        // Discover how many sheets there are in the workbook....
+        int numSheets = this.workbook.getNumberOfSheets();
+
+        // and then iterate through them.
+        for(int i = 0; i < numSheets; i++) {
+
+            // Get a reference to a sheet and check to see if it contains
+            // any rows.
+            sheet = this.workbook.getSheetAt(i);
+            if(sheet.getPhysicalNumberOfRows() > 0) {
+                // Note down the index number of the bottom-most row and
+                // then iterate through all of the rows on the sheet starting
+                // from the very first row - number 1 - even if it is missing.
+                // Recover a reference to the row and then call another method
+                // which will strip the data from the cells and build lines
+                // for inclusion in the resylting CSV file.
+                lastRowNum = sheet.getLastRowNum();
+                for(int j = 0; j <= lastRowNum; j++) {
+                    row = sheet.getRow(j);
+                    this.rowToCSV(row);
+                }
+            }
+        }
+    }
+
+    /**
+     * Called to actually save the data recovered from the Excel workbook
+     * as a CSV file.
+     *
+     * @param file An instance of the File class that encapsulates a handle
+     *             referring to the CSV file.
+     * @throws java.io.FileNotFoundException Thrown if the file cannot be found.
+     * @throws java.io.IOException Thrown to indicate and error occurred in the
+     *                             underylying file system.
+     */
+    private void saveCSVFile(File file) throws FileNotFoundException, IOException {
+        ArrayList<String> line;
+        StringBuilder buffer;
+        String csvLineElement;
+
+        // Open a writer onto the CSV file.
+        try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
+
+            System.out.println("Saving the CSV file [" + file.getName() + "]");
+
+            // Step through the elements of the ArrayList that was used to hold
+            // all of the data recovered from the Excel workbooks' sheets, rows
+            // and cells.
+            for(int i = 0; i < this.csvData.size(); i++) {
+                buffer = new StringBuilder();
+
+                // Get an element from the ArrayList that contains the data for
+                // the workbook. This element will itself be an ArrayList
+                // containing Strings and each String will hold the data recovered
+                // from a single cell. The for() loop is used to recover elements
+                // from this 'row' ArrayList one at a time and to write the Strings
+                // away to a StringBuilder thus assembling a single line for inclusion
+                // in the CSV file. If a row was empty or if it was short, then
+                // the ArrayList that contains it's data will also be shorter than
+                // some of the others. Therefore, it is necessary to check within
+                // the for loop to ensure that the ArrayList contains data to be
+                // processed. If it does, then an element will be recovered and
+                // appended to the StringBuilder.
+                line = this.csvData.get(i);
+                for(int j = 0; j < this.maxRowWidth; j++) {
+                    if(line.size() > j) {
+                        csvLineElement = line.get(j);
+                        if(csvLineElement != null) {
+                            buffer.append(this.escapeEmbeddedCharacters(
+                                    csvLineElement));
+                        }
+                    }
+                    if(j < (this.maxRowWidth - 1)) {
+                        buffer.append(this.separator);
+                    }
+                }
+
+                // Once the line is built, write it away to the CSV file.
+                bw.write(buffer.toString().trim());
+
+                // Condition the inclusion of new line characters so as to
+                // avoid an additional, superfluous, new line at the end of
+                // the file.
+                if(i < (this.csvData.size() - 1)) {
+                    bw.newLine();
+                }
+            }
+        }
+    }
+
+    /**
+     * Called to convert a row of cells into a line of data that can later be
+     * output to the CSV file.
+     *
+     * @param row An instance of either the HSSFRow or XSSFRow classes that
+     *            encapsulates information about a row of cells recovered from
+     *            an Excel workbook.
+     */
+    private void rowToCSV(Row row) {
+        Cell cell;
+        int lastCellNum;
+        ArrayList<String> csvLine = new ArrayList<>();
+
+        // Check to ensure that a row was recovered from the sheet as it is
+        // possible that one or more rows between other populated rows could be
+        // missing - blank. If the row does contain cells then...
+        if(row != null) {
+
+            // Get the index for the right most cell on the row and then
+            // step along the row from left to right recovering the contents
+            // of each cell, converting that into a formatted String and
+            // then storing the String into the csvLine ArrayList.
+            lastCellNum = row.getLastCellNum();
+            for(int i = 0; i <= lastCellNum; i++) {
+                cell = row.getCell(i);
+                if(cell == null) {
+                    csvLine.add("");
+                }
+                else {
+                    if(cell.getCellType() != CellType.FORMULA) {
+                        csvLine.add(this.formatter.formatCellValue(cell));
+                    }
+                    else {
+                        csvLine.add(this.formatter.formatCellValue(cell, this.evaluator));
+                    }
+                }
+            }
+            // Make a note of the index number of the right most cell. This value
+            // will later be used to ensure that the matrix of data in the CSV file
+            // is square.
+            if(lastCellNum > this.maxRowWidth) {
+                this.maxRowWidth = lastCellNum;
+            }
+        }
+        this.csvData.add(csvLine);
+    }
+
+    /**
+     * Checks to see whether the field - which consists of the formatted
+     * contents of an Excel worksheet cell encapsulated within a String - contains
+     * any embedded characters that must be escaped. The method is able to
+     * comply with either Excel's or UNIX formatting conventions in the
+     * following manner;
+     *
+     * With regard to UNIX conventions, if the field contains any embedded
+     * field separator or EOL characters they will each be escaped by prefixing
+     * a leading backspace character. These are the only changes that have yet
+     * emerged following some research as being required.
+     *
+     * Excel has other embedded character escaping requirements, some that emerged
+     * from empirical testing, other through research. Firstly, with regards to
+     * any embedded speech marks ("), each occurrence should be escaped with
+     * another speech mark and the whole field then surrounded with speech marks.
+     * Thus if a field holds <em>"Hello" he said</em> then it should be modified
+     * to appear as <em>"""Hello"" he said"</em>. Furthermore, if the field
+     * contains either embedded separator or EOL characters, it should also
+     * be surrounded with speech marks. As a result <em>1,400</em> would become
+     * <em>"1,400"</em> assuming that the comma is the required field separator.
+     * This has one consequence in, if a field contains embedded speech marks
+     * and embedded separator characters, checks for both are not required as the
+     * additional set of speech marks that should be placed around ay field
+     * containing embedded speech marks will also account for the embedded
+     * separator.
+     *
+     * It is worth making one further note with regard to embedded EOL
+     * characters. If the data in a worksheet is exported as a CSV file using
+     * Excel itself, then the field will be surounded with speech marks. If the
+     * resulting CSV file is then re-imports into another worksheet, the EOL
+     * character will result in the original simgle field occupying more than
+     * one cell. This same 'feature' is replicated in this classes behaviour.
+     *
+     * @param field An instance of the String class encapsulating the formatted
+     *        contents of a cell on an Excel worksheet.
+     * @return A String that encapsulates the formatted contents of that
+     *         Excel worksheet cell but with any embedded separator, EOL or
+     *         speech mark characters correctly escaped.
+     */
+    private String escapeEmbeddedCharacters(String field) {
+        StringBuilder buffer;
+
+        // If the fields contents should be formatted to confrom with Excel's
+        // convention....
+        if(this.formattingConvention == ToCSV.EXCEL_STYLE_ESCAPING) {
+
+            // Firstly, check if there are any speech marks (") in the field;
+            // each occurrence must be escaped with another set of spech marks
+            // and then the entire field should be enclosed within another
+            // set of speech marks. Thus, "Yes" he said would become
+            // """Yes"" he said"
+            if(field.contains("\"")) {
+                buffer = new StringBuilder(field.replaceAll("\"", "\\\"\\\""));
+                buffer.insert(0, "\"");
+                buffer.append("\"");
+            }
+            else {
+                // If the field contains either embedded separator or EOL
+                // characters, then escape the whole field by surrounding it
+                // with speech marks.
+                buffer = new StringBuilder(field);
+                if((buffer.indexOf(this.separator)) > -1 ||
+                         (buffer.indexOf("\n")) > -1) {
+                    buffer.insert(0, "\"");
+                    buffer.append("\"");
+                }
+            }
+            return(buffer.toString().trim());
+        }
+        // The only other formatting convention this class obeys is the UNIX one
+        // where any occurrence of the field separator or EOL character will
+        // be escaped by preceding it with a backslash.
+        else {
+            if(field.contains(this.separator)) {
+                field = field.replaceAll(this.separator, ("\\\\" + this.separator));
+            }
+            if(field.contains("\n")) {
+                field = field.replaceAll("\n", "\\\\\n");
+            }
+            return(field);
+        }
+    }
+
+    /**
+     * The main() method contains code that demonstrates how to use the class.
+     *
+     * @param args An array containing zero, one or more elements all of type
+     *        String. Each element will encapsulate an argument specified by the
+     *        user when running the program from the command prompt.
+     */
+    public static void main(String[] args) {
+        // Check the number of arguments passed to the main method. There
+        // must be two, three or four; the name of and path to either the folder
+        // containing the Excel files or an individual Excel workbook that is/are
+        // to be converted, the name of and path to the folder to which the CSV
+        // files should be written, - optionally - the separator character
+        // that should be used to separate individual items (fields) on the
+        // lines (records) of the CSV file and - again optionally - an integer
+        // that idicates whether the CSV file ought to obey Excel's or UNIX
+        // convnetions with regard to formatting fields that contain embedded
+        // separator, Speech mark or EOL character(s).
+        //
+        // Note that the names of the CSV files will be derived from those
+        // of the Excel file(s). Put simply the .xls or .xlsx extension will be
+        // replaced with .csv. Therefore, if the source folder contains files
+        // with matching names but different extensions - Test.xls and Test.xlsx
+        // for example - then the CSV file generated from one will overwrite
+        // that generated from the other.
+        ToCSV converter;
+        boolean converted = true;
+        long startTime = System.currentTimeMillis();
+        try {
+            converter = new ToCSV();
+            if(args.length == 2) {
+                // Just the Source File/Folder and Destination Folder were
+                // passed to the main method.
+                converter.convertExcelToCSV(args[0], args[1]);
+            }
+            else if(args.length == 3) {
+                // The Source File/Folder, Destination Folder and Separator
+                // were passed to the main method.
+                converter.convertExcelToCSV(args[0], args[1], args[2]);
+            }
+            else if(args.length == 4) {
+                // The Source File/Folder, Destination Folder, Separator and
+                // Formatting Convnetion were passed to the main method.
+                converter.convertExcelToCSV(args[0], args[1],
+                                            args[2], Integer.parseInt(args[3]));
+            }
+            else {
+                // None or more than four parameters were passed so display
+                //a Usage message.
+                System.out.println("Usage: java ToCSV [Source File/Folder] " +
+                    "[Destination Folder] [Separator] [Formatting Convention]\n" +
+                    "\tSource File/Folder\tThis argument should contain the name of and\n" +
+                    "\t\t\t\tpath to either a single Excel workbook or a\n" +
+                    "\t\t\t\tfolder containing one or more Excel workbooks.\n" +
+                    "\tDestination Folder\tThe name of and path to the folder that the\n" +
+                    "\t\t\t\tCSV files should be written out into. The\n" +
+                    "\t\t\t\tfolder must exist before running the ToCSV\n" +
+                    "\t\t\t\tcode as it will not check for or create it.\n" +
+                    "\tSeparator\t\tOptional. The character or characters that\n" +
+                    "\t\t\t\tshould be used to separate fields in the CSV\n" +
+                    "\t\t\t\trecord. If no value is passed then the comma\n" +
+                    "\t\t\t\twill be assumed.\n" +
+                    "\tFormatting Convention\tOptional. This argument can take one of two\n" +
+                    "\t\t\t\tvalues. Passing 0 (zero) will result in a CSV\n" +
+                    "\t\t\t\tfile that obeys Excel's formatting conventions\n" +
+                    "\t\t\t\twhilst passing 1 (one) will result in a file\n" +
+                    "\t\t\t\tthat obeys UNIX formatting conventions. If no\n" +
+                    "\t\t\t\tvalue is passed, then the CSV file produced\n" +
+                    "\t\t\t\twill obey Excel's formatting conventions.");
+                converted = false;
+            }
+        }
+        // It is not wise to have such a wide catch clause - Exception is very
+        // close to being at the top of the inheritance hierarchy - though it
+        // will suffice for this example as it is really not possible to recover
+        // easilly from an exceptional set of circumstances at this point in the
+        // program. It should however, ideally be replaced with one or more
+        // catch clauses optimised to handle more specific problems.
+        catch(Exception ex) {
+            System.out.println("Caught an: " + ex.getClass().getName());
+            System.out.println("Message: " + ex.getMessage());
+            System.out.println("Stacktrace follows:.....");
+            ex.printStackTrace(System.out);
+            converted = false;
+        }
+
+        if (converted) {
+            System.out.println("Conversion took " +
+                  ((System.currentTimeMillis() - startTime)/1000) + " seconds");
+        }
+    }
+
+    /**
+     * An instance of this class can be used to control the files returned
+     * be a call to the listFiles() method when made on an instance of the
+     * File class and that object refers to a folder/directory
+     */
+    static class ExcelFilenameFilter implements FilenameFilter {
+
+        /**
+         * Determine those files that will be returned by a call to the
+         * listFiles() method. In this case, the name of the file must end with
+         * either of the following two extension; '.xls' or '.xlsx'. For the
+         * future, it is very possible to parameterise this and allow the
+         * containing class to pass, for example, an array of Strings to this
+         * class on instantiation. Each element in that array could encapsulate
+         * a valid file extension - '.xls', '.xlsx', '.xlt', '.xlst', etc. These
+         * could then be used to control which files were returned by the call
+         * to the listFiles() method.
+         *
+         * @param file An instance of the File class that encapsulates a handle
+         *             referring to the folder/directory that contains the file.
+         * @param name An instance of the String class that encapsulates the
+         *             name of the file.
+         * @return A boolean value that indicates whether the file should be
+         *         included in the array retirned by the call to the listFiles()
+         *         method. In this case true will be returned if the name of the
+         *         file ends with either '.xls' or '.xlsx' and false will be
+         *         returned in all other instances.
+         */
+        @Override
+        public boolean accept(File file, String name) {
+            return(name.endsWith(".xls") || name.endsWith(".xlsx"));
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/formula/CalculateMortgage.java b/src/examples/src/org/apache/poi/examples/ss/formula/CalculateMortgage.java
new file mode 100644 (file)
index 0000000..2675df1
--- /dev/null
@@ -0,0 +1,91 @@
+/* ====================================================================
+   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.examples.ss.formula;
+
+import org.apache.poi.ss.formula.OperationEvaluationContext;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.EvaluationException;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.OperandResolver;
+import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
+
+/**
+ * A simple user-defined function to calculate principal and interest.
+ *
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ *
+ */
+public class CalculateMortgage implements FreeRefFunction {
+
+    @Override
+    public ValueEval evaluate( ValueEval[] args, OperationEvaluationContext ec ) {
+
+        // verify that we have enough data
+        if (args.length != 3) {
+            return ErrorEval.VALUE_INVALID;
+        }
+
+        // declare doubles for values
+        double principal, rate, years,  result;
+        try {
+            // extract values as ValueEval
+            ValueEval v1 = OperandResolver.getSingleValue( args[0],
+                                                           ec.getRowIndex(),
+                                                           ec.getColumnIndex() ) ;
+            ValueEval v2 = OperandResolver.getSingleValue( args[1],
+                                                           ec.getRowIndex(),
+                                                           ec.getColumnIndex() ) ;
+            ValueEval v3 = OperandResolver.getSingleValue( args[2],
+                                                           ec.getRowIndex(),
+                                                           ec.getColumnIndex() ) ;
+
+            // get data as doubles
+            principal  = OperandResolver.coerceValueToDouble( v1 ) ;
+            rate  = OperandResolver.coerceValueToDouble( v2 ) ;
+            years = OperandResolver.coerceValueToDouble( v3 ) ;
+
+            result = calculateMortgagePayment( principal, rate, years ) ;
+            System.out.println( "Result = " + result ) ;
+
+            checkValue(result);
+
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+
+        return new NumberEval( result ) ;
+    }
+
+    public double calculateMortgagePayment( double p, double r, double y ) {
+        double i = r / 12 ;
+        double n = y * 12 ;
+
+        return p * (( i * Math.pow((1 + i),n ) ) / ( Math.pow((1 + i),n) - 1));
+    }
+    /**
+     * Excel does not support infinities and NaNs, rather, it gives a #NUM! error in these cases
+     *
+     * @throws EvaluationException (#NUM!) if <tt>result</tt> is <tt>NaN</> or <tt>Infinity</tt>
+     */
+     private void checkValue(double result) throws EvaluationException {
+         if (Double.isNaN(result) || Double.isInfinite(result)) {
+             throw new EvaluationException(ErrorEval.NUM_ERROR);
+         }
+     }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/formula/CheckFunctionsSupported.java b/src/examples/src/org/apache/poi/examples/ss/formula/CheckFunctionsSupported.java
new file mode 100644 (file)
index 0000000..4135c80
--- /dev/null
@@ -0,0 +1,162 @@
+/* ====================================================================
+   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.examples.ss.formula;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.poi.ss.formula.eval.NotImplementedException;
+import org.apache.poi.ss.formula.eval.NotImplementedFunctionException;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+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.WorkbookFactory;
+import org.apache.poi.ss.util.CellReference;
+
+/**
+ * Attempts to re-evaluate all the formulas in the workbook, and
+ *  reports what (if any) formula functions used are not (currently)
+ *  supported by Apache POI.
+ *
+ * <p>This provides examples of how to evaluate formulas in excel
+ *  files using Apache POI, along with how to handle errors whilst
+ *  doing so.
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public class CheckFunctionsSupported {
+    public static void main(String[] args) throws Exception {
+        if (args.length < 1) {
+            System.err.println("Use:");
+            System.err.println("  CheckFunctionsSupported <filename>");
+            return;
+        }
+
+        Workbook wb = WorkbookFactory.create(new File(args[0]));
+        CheckFunctionsSupported check = new CheckFunctionsSupported(wb);
+
+        // Fetch all the problems
+        List<FormulaEvaluationProblems> problems = new ArrayList<>();
+        for (int sn=0; sn<wb.getNumberOfSheets(); sn++) {
+            problems.add(check.getEvaluationProblems(sn));
+        }
+
+        // Produce an overall summary
+        Set<String> unsupportedFunctions = new TreeSet<>();
+        for (FormulaEvaluationProblems p : problems) {
+            unsupportedFunctions.addAll(p.unsupportedFunctions);
+        }
+        if (unsupportedFunctions.isEmpty()) {
+            System.out.println("There are no unsupported formula functions used");
+        } else {
+            System.out.println("Unsupported formula functions:");
+            for (String function : unsupportedFunctions) {
+                System.out.println("  " + function);
+            }
+            System.out.println("Total unsupported functions = " + unsupportedFunctions.size());
+        }
+
+        // Report sheet by sheet
+        for (int sn=0; sn<wb.getNumberOfSheets(); sn++) {
+            String sheetName = wb.getSheetName(sn);
+            FormulaEvaluationProblems probs = problems.get(sn);
+
+            System.out.println();
+            System.out.println("Sheet = " + sheetName);
+
+            if (probs.unevaluatableCells.isEmpty()) {
+                System.out.println(" All cells evaluated without error");
+            } else {
+                for (CellReference cr : probs.unevaluatableCells.keySet()) {
+                    System.out.println(" " + cr.formatAsString() + " - " +
+                            probs.unevaluatableCells.get(cr));
+                }
+            }
+        }
+    }
+
+    private final Workbook workbook;
+    private final FormulaEvaluator evaluator;
+    public CheckFunctionsSupported(Workbook workbook) {
+        this.workbook = workbook;
+        this.evaluator = workbook.getCreationHelper().createFormulaEvaluator();
+    }
+
+    public Set<String> getUnsupportedFunctions(String sheetName) {
+        return getUnsupportedFunctions(workbook.getSheet(sheetName));
+    }
+    public Set<String> getUnsupportedFunctions(int sheetIndex) {
+        return getUnsupportedFunctions(workbook.getSheetAt(sheetIndex));
+    }
+    public Set<String> getUnsupportedFunctions(Sheet sheet) {
+        FormulaEvaluationProblems problems = getEvaluationProblems(sheet);
+        return problems.unsupportedFunctions;
+    }
+
+    public FormulaEvaluationProblems getEvaluationProblems(String sheetName) {
+        return getEvaluationProblems(workbook.getSheet(sheetName));
+    }
+    public FormulaEvaluationProblems getEvaluationProblems(int sheetIndex) {
+        return getEvaluationProblems(workbook.getSheetAt(sheetIndex));
+    }
+    public FormulaEvaluationProblems getEvaluationProblems(Sheet sheet) {
+        Set<String> unsupportedFunctions = new HashSet<>();
+        Map<CellReference,Exception> unevaluatableCells = new HashMap<>();
+
+        for (Row r : sheet) {
+            for (Cell c : r) {
+                try {
+                    evaluator.evaluate(c);
+                } catch (Exception e) {
+                    if (e instanceof NotImplementedException && e.getCause() != null) {
+                        // Has been wrapped with cell details, but we know those
+                        e = (Exception)e.getCause();
+                    }
+
+                    if (e instanceof NotImplementedFunctionException) {
+                        NotImplementedFunctionException nie = (NotImplementedFunctionException)e;
+                        unsupportedFunctions.add(nie.getFunctionName());
+                    }
+                    unevaluatableCells.put(new CellReference(c), e);
+                }
+            }
+        }
+
+        return new FormulaEvaluationProblems(unsupportedFunctions, unevaluatableCells);
+    }
+
+    public static class FormulaEvaluationProblems {
+        /** Which used functions are unsupported by POI at this time */
+        private final Set<String> unsupportedFunctions;
+        /** Which cells had unevaluatable formulas, and why? */
+        private final Map<CellReference,Exception> unevaluatableCells;
+
+        protected FormulaEvaluationProblems(Set<String> unsupportedFunctions,
+                             Map<CellReference, Exception> unevaluatableCells) {
+            this.unsupportedFunctions = Collections.unmodifiableSet(unsupportedFunctions);
+            this.unevaluatableCells = Collections.unmodifiableMap(unevaluatableCells);
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/formula/SettingExternalFunction.java b/src/examples/src/org/apache/poi/examples/ss/formula/SettingExternalFunction.java
new file mode 100644 (file)
index 0000000..49feb3f
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *  ====================================================================
+ *    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.examples.ss.formula;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.poi.ss.formula.OperationEvaluationContext;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
+import org.apache.poi.ss.formula.udf.UDFFinder;
+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.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates how to use functions provided by third-party add-ins, e.g. Bloomberg Excel Add-in.
+ *
+ * There can be situations when you are not interested in formula evaluation,
+ * you just need to set the formula  and the workbook will be evaluation by the client.
+ */
+public class SettingExternalFunction {
+
+    /**
+     * wrap external functions in a plugin
+     */
+    public static class BloombergAddIn implements UDFFinder {
+        private final Map<String, FreeRefFunction> _functionsByName;
+
+        public BloombergAddIn() {
+            // dummy function that returns NA
+            // don't care about the implementation, we are not interested in evaluation
+            // and this method will never be called
+            FreeRefFunction NA = new FreeRefFunction() {
+                @Override
+                public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
+                    return ErrorEval.NA;
+                }
+            };
+            _functionsByName = new HashMap<>();
+            _functionsByName.put("BDP", NA);
+            _functionsByName.put("BDH", NA);
+            _functionsByName.put("BDS", NA);
+        }
+
+        @Override
+        public FreeRefFunction findFunction(String name) {
+            return _functionsByName.get(name.toUpperCase(Locale.ROOT));
+        }
+
+    }
+
+    public static void main( String[] args ) throws IOException {
+
+        try (Workbook wb = new XSSFWorkbook()) {  // or new HSSFWorkbook()
+
+            // register the add-in
+            wb.addToolPack(new BloombergAddIn());
+
+            Sheet sheet = wb.createSheet();
+            Row row = sheet.createRow(0);
+            row.createCell(0).setCellFormula("BDP(\"GOOG Equity\",\"CHG_PCT_YTD\")/100");
+            row.createCell(1).setCellFormula("BDH(\"goog us equity\",\"EBIT\",\"1/1/2005\",\"12/31/2009\",\"per=cy\",\"curr=USD\") ");
+            row.createCell(2).setCellFormula("BDS(\"goog us equity\",\"top_20_holders_public_filings\") ");
+
+            try (FileOutputStream out = new FileOutputStream("bloomberg-demo.xlsx")) {
+                wb.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/formula/UserDefinedFunctionExample.java b/src/examples/src/org/apache/poi/examples/ss/formula/UserDefinedFunctionExample.java
new file mode 100644 (file)
index 0000000..939fd9a
--- /dev/null
@@ -0,0 +1,80 @@
+/* ====================================================================
+   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.examples.ss.formula;
+
+import java.io.File;
+
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
+import org.apache.poi.ss.formula.udf.DefaultUDFFinder;
+import org.apache.poi.ss.formula.udf.UDFFinder;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellValue;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+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.WorkbookFactory;
+import org.apache.poi.ss.util.CellReference;
+
+
+/**
+ * An example class of how to invoke a User Defined Function for a given
+ * XLS instance using POI's UDFFinder implementation.
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class UserDefinedFunctionExample {
+
+    private UserDefinedFunctionExample() {}
+
+    public static void main(String[] args ) throws Exception {
+
+        if(  args.length != 2 ) {
+            // e.g. src/examples/src/org/apache/poi/ss/examples/formula/mortgage-calculation.xls Sheet1!B4
+            System.out.println( "usage: UserDefinedFunctionExample fileName cellId" ) ;
+            return;
+        }
+
+        System.out.println( "fileName: " + args[0] ) ;
+        System.out.println( "cell: " + args[1] ) ;
+
+        File workbookFile = new File( args[0] ) ;
+
+        try (Workbook workbook = WorkbookFactory.create(workbookFile, null, true)) {
+            String[] functionNames = {"calculatePayment"};
+            FreeRefFunction[] functionImpls = {new CalculateMortgage()};
+
+            UDFFinder udfToolpack = new DefaultUDFFinder(functionNames, functionImpls);
+
+            // register the user-defined function in the workbook
+            workbook.addToolPack(udfToolpack);
+
+            FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
+
+            CellReference cr = new CellReference(args[1]);
+            String sheetName = cr.getSheetName();
+            Sheet sheet = workbook.getSheet(sheetName);
+            int rowIdx = cr.getRow();
+            int colIdx = cr.getCol();
+            Row row = sheet.getRow(rowIdx);
+            Cell cell = row.getCell(colIdx);
+
+            CellValue value = evaluator.evaluate(cell);
+
+            System.out.println("returns value: " + value);
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/formula/mortgage-calculation.xls b/src/examples/src/org/apache/poi/examples/ss/formula/mortgage-calculation.xls
new file mode 100644 (file)
index 0000000..4e71ba8
Binary files /dev/null and b/src/examples/src/org/apache/poi/examples/ss/formula/mortgage-calculation.xls differ
diff --git a/src/examples/src/org/apache/poi/examples/ss/html/HSSFHtmlHelper.java b/src/examples/src/org/apache/poi/examples/ss/html/HSSFHtmlHelper.java
new file mode 100644 (file)
index 0000000..4614a31
--- /dev/null
@@ -0,0 +1,66 @@
+/* ====================================================================
+   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.examples.ss.html;
+
+import java.util.Formatter;
+
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFPalette;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
+import org.apache.poi.ss.usermodel.CellStyle;
+
+/**
+ * Implementation of {@link HtmlHelper} for HSSF files.
+ */
+public class HSSFHtmlHelper implements HtmlHelper {
+    private final HSSFWorkbook wb;
+    private final HSSFPalette colors;
+
+    private static final HSSFColor HSSF_AUTO = HSSFColorPredefined.AUTOMATIC.getColor();
+
+    public HSSFHtmlHelper(HSSFWorkbook wb) {
+        this.wb = wb;
+        // If there is no custom palette, then this creates a new one that is
+        // a copy of the default
+        colors = wb.getCustomPalette();
+    }
+
+    @Override
+    public void colorStyles(CellStyle style, Formatter out) {
+        HSSFCellStyle cs = (HSSFCellStyle) style;
+        out.format("  /* fill pattern = %d */%n", cs.getFillPattern().getCode());
+        styleColor(out, "background-color", cs.getFillForegroundColor());
+        styleColor(out, "color", cs.getFont(wb).getColor());
+        styleColor(out, "border-left-color", cs.getLeftBorderColor());
+        styleColor(out, "border-right-color", cs.getRightBorderColor());
+        styleColor(out, "border-top-color", cs.getTopBorderColor());
+        styleColor(out, "border-bottom-color", cs.getBottomBorderColor());
+    }
+
+    private void styleColor(Formatter out, String attr, short index) {
+        HSSFColor color = colors.getColor(index);
+        if (index == HSSF_AUTO.getIndex() || color == null) {
+            out.format("  /* %s: index = %d */%n", attr, index);
+        } else {
+            short[] rgb = color.getTriplet();
+            out.format("  %s: #%02x%02x%02x; /* index = %d */%n", attr, rgb[0],
+                    rgb[1], rgb[2], index);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/examples/ss/html/HtmlHelper.java b/src/examples/src/org/apache/poi/examples/ss/html/HtmlHelper.java
new file mode 100644 (file)
index 0000000..8747ad4
--- /dev/null
@@ -0,0 +1,40 @@
+/* ====================================================================
+   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.examples.ss.html;
+
+import java.util.Formatter;
+
+import org.apache.poi.ss.usermodel.CellStyle;
+
+/**
+ * This interface is used where code wants to be independent of the workbook
+ * formats.  If you are writing such code, you can add a method to this
+ * interface, and then implement it for both HSSF and XSSF workbooks, letting
+ * the driving code stay independent of format.
+ *
+ * @author Ken Arnold, Industrious Media LLC
+ */
+public interface HtmlHelper {
+    /**
+     * Outputs the appropriate CSS style for the given cell style.
+     *
+     * @param style The cell style.
+     * @param out   The place to write the output.
+     */
+    void colorStyles(CellStyle style, Formatter out);
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/html/ToHtml.java b/src/examples/src/org/apache/poi/examples/ss/html/ToHtml.java
new file mode 100644 (file)
index 0000000..930de56
--- /dev/null
@@ -0,0 +1,508 @@
+/* ====================================================================
+   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.examples.ss.html;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.format.CellFormat;
+import org.apache.poi.ss.format.CellFormatResult;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * This example shows how to display a spreadsheet in HTML using the classes for
+ * spreadsheet display.
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class ToHtml {
+    private final Workbook wb;
+    private final Appendable output;
+    private boolean completeHTML;
+    private Formatter out;
+    private boolean gotBounds;
+    private int firstColumn;
+    private int endColumn;
+    private HtmlHelper helper;
+
+    private static final String DEFAULTS_CLASS = "excelDefaults";
+    private static final String COL_HEAD_CLASS = "colHeader";
+    private static final String ROW_HEAD_CLASS = "rowHeader";
+
+    private static final Map<HorizontalAlignment, String> HALIGN = mapFor(
+            HorizontalAlignment.LEFT, "left",
+            HorizontalAlignment.CENTER, "center",
+            HorizontalAlignment.RIGHT, "right",
+            HorizontalAlignment.FILL, "left",
+            HorizontalAlignment.JUSTIFY, "left",
+            HorizontalAlignment.CENTER_SELECTION, "center");
+
+    private static final Map<VerticalAlignment, String> VALIGN = mapFor(
+            VerticalAlignment.BOTTOM, "bottom",
+            VerticalAlignment.CENTER, "middle",
+            VerticalAlignment.TOP, "top");
+
+    private static final Map<BorderStyle, String> BORDER = mapFor(
+            BorderStyle.DASH_DOT, "dashed 1pt",
+            BorderStyle.DASH_DOT_DOT, "dashed 1pt",
+            BorderStyle.DASHED, "dashed 1pt",
+            BorderStyle.DOTTED, "dotted 1pt",
+            BorderStyle.DOUBLE, "double 3pt",
+            BorderStyle.HAIR, "solid 1px",
+            BorderStyle.MEDIUM, "solid 2pt",
+            BorderStyle.MEDIUM_DASH_DOT, "dashed 2pt",
+            BorderStyle.MEDIUM_DASH_DOT_DOT, "dashed 2pt",
+            BorderStyle.MEDIUM_DASHED, "dashed 2pt",
+            BorderStyle.NONE, "none",
+            BorderStyle.SLANTED_DASH_DOT, "dashed 2pt",
+            BorderStyle.THICK, "solid 3pt",
+            BorderStyle.THIN, "dashed 1pt");
+
+    private static final int IDX_TABLE_WIDTH = -2;
+    private static final int IDX_HEADER_COL_WIDTH = -1;
+
+
+    @SuppressWarnings({"unchecked"})
+    private static <K, V> Map<K, V> mapFor(Object... mapping) {
+        Map<K, V> map = new HashMap<>();
+        for (int i = 0; i < mapping.length; i += 2) {
+            map.put((K) mapping[i], (V) mapping[i + 1]);
+        }
+        return map;
+    }
+
+    /**
+     * Creates a new examples to HTML for the given workbook.
+     *
+     * @param wb     The workbook.
+     * @param output Where the HTML output will be written.
+     *
+     * @return An object for converting the workbook to HTML.
+     */
+    public static ToHtml create(Workbook wb, Appendable output) {
+        return new ToHtml(wb, output);
+    }
+
+    /**
+     * Creates a new examples to HTML for the given workbook.  If the path ends
+     * with "<tt>.xlsx</tt>" an {@link XSSFWorkbook} will be used; otherwise
+     * this will use an {@link HSSFWorkbook}.
+     *
+     * @param path   The file that has the workbook.
+     * @param output Where the HTML output will be written.
+     *
+     * @return An object for converting the workbook to HTML.
+     */
+    public static ToHtml create(String path, Appendable output)
+            throws IOException {
+        return create(new FileInputStream(path), output);
+    }
+
+    /**
+     * Creates a new examples to HTML for the given workbook.  This attempts to
+     * detect whether the input is XML (so it should create an {@link
+     * XSSFWorkbook} or not (so it should create an {@link HSSFWorkbook}).
+     *
+     * @param in     The input stream that has the workbook.
+     * @param output Where the HTML output will be written.
+     *
+     * @return An object for converting the workbook to HTML.
+     */
+    public static ToHtml create(InputStream in, Appendable output)
+            throws IOException {
+        Workbook wb = WorkbookFactory.create(in);
+        return create(wb, output);
+    }
+
+    private ToHtml(Workbook wb, Appendable output) {
+        if (wb == null) {
+            throw new NullPointerException("wb");
+        }
+        if (output == null) {
+            throw new NullPointerException("output");
+        }
+        this.wb = wb;
+        this.output = output;
+        setupColorMap();
+    }
+
+    private void setupColorMap() {
+        if (wb instanceof HSSFWorkbook) {
+            helper = new HSSFHtmlHelper((HSSFWorkbook) wb);
+        } else if (wb instanceof XSSFWorkbook) {
+            helper = new XSSFHtmlHelper();
+        } else {
+            throw new IllegalArgumentException(
+                    "unknown workbook type: " + wb.getClass().getSimpleName());
+        }
+    }
+
+    /**
+     * Run this class as a program
+     *
+     * @param args The command line arguments.
+     *
+     * @throws Exception Exception we don't recover from.
+     */
+    public static void main(String[] args) throws Exception {
+        if(args.length < 2){
+            System.err.println("usage: ToHtml inputWorkbook outputHtmlFile");
+            return;
+        }
+
+        try (
+                FileWriter fw = new FileWriter(args[1]);
+                PrintWriter pw = new PrintWriter(fw)
+            ) {
+            ToHtml toHtml = create(args[0], pw);
+            toHtml.setCompleteHTML(true);
+            toHtml.printPage();
+        }
+    }
+
+    public void setCompleteHTML(boolean completeHTML) {
+        this.completeHTML = completeHTML;
+    }
+
+    public void printPage() throws IOException {
+        try {
+            ensureOut();
+            if (completeHTML) {
+                out.format(
+                        "<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>%n");
+                out.format("<html>%n");
+                out.format("<head>%n");
+                out.format("</head>%n");
+                out.format("<body>%n");
+            }
+
+            print();
+
+            if (completeHTML) {
+                out.format("</body>%n");
+                out.format("</html>%n");
+            }
+        } finally {
+            IOUtils.closeQuietly(out);
+            if (output instanceof Closeable) {
+                IOUtils.closeQuietly((Closeable) output);
+            }
+        }
+    }
+
+    public void print() {
+        printInlineStyle();
+        printSheets();
+    }
+
+    private void printInlineStyle() {
+        //out.format("<link href=\"excelStyle.css\" rel=\"stylesheet\" type=\"text/css\">%n");
+        out.format("<style type=\"text/css\">%n");
+        printStyles();
+        out.format("</style>%n");
+    }
+
+    private void ensureOut() {
+        if (out == null) {
+            out = new Formatter(output);
+        }
+    }
+
+    public void printStyles() {
+        ensureOut();
+
+        // First, copy the base css
+        try (BufferedReader in = new BufferedReader(new InputStreamReader(
+                getClass().getResourceAsStream("excelStyle.css")))){
+            String line;
+            while ((line = in.readLine()) != null) {
+                out.format("%s%n", line);
+            }
+        } catch (IOException e) {
+            throw new IllegalStateException("Reading standard css", e);
+        }
+
+        // now add css for each used style
+        Set<CellStyle> seen = new HashSet<>();
+        for (int i = 0; i < wb.getNumberOfSheets(); i++) {
+            Sheet sheet = wb.getSheetAt(i);
+            Iterator<Row> rows = sheet.rowIterator();
+            while (rows.hasNext()) {
+                Row row = rows.next();
+                for (Cell cell : row) {
+                    CellStyle style = cell.getCellStyle();
+                    if (!seen.contains(style)) {
+                        printStyle(style);
+                        seen.add(style);
+                    }
+                }
+            }
+        }
+    }
+
+    private void printStyle(CellStyle style) {
+        out.format(".%s .%s {%n", DEFAULTS_CLASS, styleName(style));
+        styleContents(style);
+        out.format("}%n");
+    }
+
+    private void styleContents(CellStyle style) {
+        styleOut("text-align", style.getAlignment(), HALIGN);
+        styleOut("vertical-align", style.getVerticalAlignment(), VALIGN);
+        fontStyle(style);
+        borderStyles(style);
+        helper.colorStyles(style, out);
+    }
+
+    private void borderStyles(CellStyle style) {
+        styleOut("border-left", style.getBorderLeft(), BORDER);
+        styleOut("border-right", style.getBorderRight(), BORDER);
+        styleOut("border-top", style.getBorderTop(), BORDER);
+        styleOut("border-bottom", style.getBorderBottom(), BORDER);
+    }
+
+    private void fontStyle(CellStyle style) {
+        Font font = wb.getFontAt(style.getFontIndexAsInt());
+
+        if (font.getBold()) {
+            out.format("  font-weight: bold;%n");
+        }
+        if (font.getItalic()) {
+            out.format("  font-style: italic;%n");
+        }
+
+        int fontheight = font.getFontHeightInPoints();
+        if (fontheight == 9) {
+            //fix for stupid ol Windows
+            fontheight = 10;
+        }
+        out.format("  font-size: %dpt;%n", fontheight);
+
+        // Font color is handled with the other colors
+    }
+
+    private String styleName(CellStyle style) {
+        if (style == null) {
+            style = wb.getCellStyleAt((short) 0);
+        }
+        StringBuilder sb = new StringBuilder();
+        try (Formatter fmt = new Formatter(sb)) {
+            fmt.format("style_%02x", style.getIndex());
+            return fmt.toString();
+        }
+    }
+
+    private <K> void styleOut(String attr, K key, Map<K, String> mapping) {
+        String value = mapping.get(key);
+        if (value != null) {
+            out.format("  %s: %s;%n", attr, value);
+        }
+    }
+
+    private static CellType ultimateCellType(Cell c) {
+        CellType type = c.getCellType();
+        if (type == CellType.FORMULA) {
+            type = c.getCachedFormulaResultType();
+        }
+        return type;
+    }
+
+    private void printSheets() {
+        ensureOut();
+        Sheet sheet = wb.getSheetAt(0);
+        printSheet(sheet);
+    }
+
+    public void printSheet(Sheet sheet) {
+        ensureOut();
+        Map<Integer, Integer> widths = computeWidths(sheet);
+        int tableWidth = widths.get(IDX_TABLE_WIDTH);
+        out.format("<table class=%s style=\"width:%dpx;\">%n", DEFAULTS_CLASS, tableWidth);
+        printCols(widths);
+        printSheetContent(sheet);
+        out.format("</table>%n");
+    }
+
+    /**
+     * computes the column widths, defined by the sheet.
+     *
+     * @param sheet The sheet for which to compute widths
+     * @return Map with key: column index; value: column width in pixels
+     *     <br>special keys:
+     *     <br>{@link #IDX_HEADER_COL_WIDTH} - width of the header column
+     *     <br>{@link #IDX_TABLE_WIDTH} - width of the entire table
+     */
+    private Map<Integer, Integer> computeWidths(Sheet sheet) {
+        Map<Integer, Integer> ret = new TreeMap<>();
+        int tableWidth = 0;
+
+        ensureColumnBounds(sheet);
+
+        // compute width of the header column
+        int lastRowNum = sheet.getLastRowNum();
+        int headerCharCount = String.valueOf(lastRowNum).length();
+        int headerColWidth = widthToPixels((headerCharCount + 1) * 256.0);
+        ret.put(IDX_HEADER_COL_WIDTH, headerColWidth);
+        tableWidth += headerColWidth;
+
+        for (int i = firstColumn; i < endColumn; i++) {
+            int colWidth = widthToPixels(sheet.getColumnWidth(i));
+            ret.put(i, colWidth);
+            tableWidth += colWidth;
+        }
+
+        ret.put(IDX_TABLE_WIDTH, tableWidth);
+        return ret ;
+    }
+
+    /**
+     * Probably platform-specific, but appears to be a close approximation on some systems
+     * @param widthUnits POI's native width unit (twips)
+     * @return the approximate number of pixels for a typical display
+     */
+    protected int widthToPixels(final double widthUnits) {
+        return Math.toIntExact(Math.round(widthUnits * 9 / 256));
+    }
+
+    private void printCols(Map<Integer, Integer> widths) {
+        int headerColWidth = widths.get(IDX_HEADER_COL_WIDTH);
+        out.format("<col style=\"width:%dpx\"/>%n", headerColWidth);
+        for (int i = firstColumn; i < endColumn; i++) {
+            int colWidth = widths.get(i);
+            out.format("<col style=\"width:%dpx;\"/>%n", colWidth);
+        }
+    }
+
+    private void ensureColumnBounds(Sheet sheet) {
+        if (gotBounds) {
+            return;
+        }
+
+        Iterator<Row> iter = sheet.rowIterator();
+        firstColumn = (iter.hasNext() ? Integer.MAX_VALUE : 0);
+        endColumn = 0;
+        while (iter.hasNext()) {
+            Row row = iter.next();
+            short firstCell = row.getFirstCellNum();
+            if (firstCell >= 0) {
+                firstColumn = Math.min(firstColumn, firstCell);
+                endColumn = Math.max(endColumn, row.getLastCellNum());
+            }
+        }
+        gotBounds = true;
+    }
+
+    private void printColumnHeads() {
+        out.format("<thead>%n");
+        out.format("  <tr class=%s>%n", COL_HEAD_CLASS);
+        out.format("    <th class=%s>&#x25CA;</th>%n", COL_HEAD_CLASS);
+        //noinspection UnusedDeclaration
+        StringBuilder colName = new StringBuilder();
+        for (int i = firstColumn; i < endColumn; i++) {
+            colName.setLength(0);
+            int cnum = i;
+            do {
+                colName.insert(0, (char) ('A' + cnum % 26));
+                cnum /= 26;
+            } while (cnum > 0);
+            out.format("    <th class=%s>%s</th>%n", COL_HEAD_CLASS, colName);
+        }
+        out.format("  </tr>%n");
+        out.format("</thead>%n");
+    }
+
+    private void printSheetContent(Sheet sheet) {
+        printColumnHeads();
+
+        out.format("<tbody>%n");
+        Iterator<Row> rows = sheet.rowIterator();
+        while (rows.hasNext()) {
+            Row row = rows.next();
+
+            out.format("  <tr>%n");
+            out.format("    <td class=%s>%d</td>%n", ROW_HEAD_CLASS,
+                    row.getRowNum() + 1);
+            for (int i = firstColumn; i < endColumn; i++) {
+                String content = "&nbsp;";
+                String attrs = "";
+                CellStyle style = null;
+                if (i >= row.getFirstCellNum() && i < row.getLastCellNum()) {
+                    Cell cell = row.getCell(i);
+                    if (cell != null) {
+                        style = cell.getCellStyle();
+                        attrs = tagStyle(cell, style);
+                        //Set the value that is rendered for the cell
+                        //also applies the format
+                        CellFormat cf = CellFormat.getInstance(
+                                style.getDataFormatString());
+                        CellFormatResult result = cf.apply(cell);
+                        content = result.text; //never null
+                        if (content.isEmpty()) {
+                            content = "&nbsp;";
+                        }
+                    }
+                }
+                out.format("    <td class=%s %s>%s</td>%n", styleName(style),
+                        attrs, content);
+            }
+            out.format("  </tr>%n");
+        }
+        out.format("</tbody>%n");
+    }
+
+    private String tagStyle(Cell cell, CellStyle style) {
+        if (style.getAlignment() == HorizontalAlignment.GENERAL) {
+            switch (ultimateCellType(cell)) {
+            case STRING:
+                return "style=\"text-align: left;\"";
+            case BOOLEAN:
+            case ERROR:
+                return "style=\"text-align: center;\"";
+            case NUMERIC:
+            default:
+                // "right" is the default
+                break;
+            }
+        }
+        return "";
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/html/XSSFHtmlHelper.java b/src/examples/src/org/apache/poi/examples/ss/html/XSSFHtmlHelper.java
new file mode 100644 (file)
index 0000000..40bd504
--- /dev/null
@@ -0,0 +1,59 @@
+/* ====================================================================
+   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.examples.ss.html;
+
+import java.util.Formatter;
+
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+
+/**
+ * Implementation of {@link HtmlHelper} for XSSF files.
+ *
+ * @author Ken Arnold, Industrious Media LLC
+ */
+public class XSSFHtmlHelper implements HtmlHelper {
+    @Override
+    public void colorStyles(CellStyle style, Formatter out) {
+        XSSFCellStyle cs = (XSSFCellStyle) style;
+        styleColor(out, "background-color", cs.getFillForegroundXSSFColor());
+        styleColor(out, "text-color", cs.getFont().getXSSFColor());
+    }
+
+    private void styleColor(Formatter out, String attr, XSSFColor color) {
+        if (color == null || color.isAuto()) {
+            return;
+        }
+
+        byte[] rgb = color.getRGB();
+        if (rgb == null) {
+            return;
+        }
+
+        // This is done twice -- rgba is new with CSS 3, and browser that don't
+        // support it will ignore the rgba specification and stick with the
+        // solid color, which is declared first
+        out.format("  %s: #%02x%02x%02x;%n", attr, rgb[0], rgb[1], rgb[2]);
+        byte[] argb = color.getARGB();
+        if (argb == null) {
+            return;
+        }
+        out.format("  %s: rgba(0x%02x, 0x%02x, 0x%02x, 0x%02x);%n", attr,
+                argb[3], argb[0], argb[1], argb[2]);
+    }
+}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/examples/ss/html/excelStyle.css b/src/examples/src/org/apache/poi/examples/ss/html/excelStyle.css
new file mode 100644 (file)
index 0000000..f056123
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+   ====================================================================
+   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.
+   ====================================================================
+ */
+/*
+ * This is the default style sheet for html generated by ToHtml
+ *
+ * @author Ken Arnold, Industrious Media LLC
+ */
+.excelDefaults {
+       background-color: white;
+       color: black;
+       text-decoration: none;
+       direction: ltr;
+       text-transform: none;
+       text-indent: 0;
+       letter-spacing: 0;
+       word-spacing: 0;
+       white-space: pre-wrap;
+       unicode-bidi: normal;
+       background-image: none;
+       text-shadow: none;
+       list-style-image: none;
+       list-style-type: none;
+       padding: 0;
+       margin: 0;
+       border-collapse: collapse;
+       vertical-align: bottom;
+       font-style: normal;
+       font-family: sans-serif;
+       font-variant: normal;
+       font-weight: normal;
+       font-size: 10pt;
+       text-align: right;
+       table-layout: fixed;
+       word-wrap: break-word;
+       overflow-wrap: break-word;
+}
+
+.excelDefaults td {
+       padding: 1px 5px;
+       border: 1px solid silver;
+}
+
+.excelDefaults .colHeader {
+       background-color: silver;
+       font-weight: bold;
+       border: 1px solid black;
+       text-align: center;
+       padding: 1px 5px;
+}
+
+.excelDefaults .rowHeader {
+       background-color: silver;
+       font-weight: bold;
+       border: 1px solid black;
+       text-align: right;
+       padding: 1px 5px;
+}
diff --git a/src/examples/src/org/apache/poi/examples/ss/html/package-info.java b/src/examples/src/org/apache/poi/examples/ss/html/package-info.java
new file mode 100644 (file)
index 0000000..1b41376
--- /dev/null
@@ -0,0 +1,22 @@
+/* ====================================================================
+   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.
+==================================================================== */
+
+/**
+ * This package contains an example that uses POI to convert a workbook into
+ * an HTML representation of the data.  It can use both XSSF and HSSF workbooks.
+ */
+package org.apache.poi.examples.ss.html;
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/examples/util/TempFileUtils.java b/src/examples/src/org/apache/poi/examples/util/TempFileUtils.java
deleted file mode 100644 (file)
index b5ad6ea..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.examples.util;
-
-import java.io.File;
-
-import org.apache.poi.util.TempFile;
-
-public final class TempFileUtils {
-    private TempFileUtils() {
-    }
-
-    @SuppressWarnings("java:S106")
-    public static void checkTempFiles() {
-        String tmpDir = System.getProperty(TempFile.JAVA_IO_TMPDIR) + "/poifiles";
-        File tempDir = new File(tmpDir);
-        if(tempDir.exists()) {
-            String[] tempFiles = tempDir.list();
-            if(tempFiles != null && tempFiles.length > 0) {
-                System.out.println("found files in poi temp dir " + tempDir.getAbsolutePath());
-                for(String filename : tempFiles) {
-                    System.out.println("file: " + filename);
-                }
-            }
-        } else {
-            System.out.println("unable to find poi temp dir");
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/AddVideoToPptx.java.txt b/src/examples/src/org/apache/poi/examples/xslf/AddVideoToPptx.java.txt
new file mode 100644 (file)
index 0000000..2d32c4d
--- /dev/null
@@ -0,0 +1,251 @@
+/*\r
+ *  ====================================================================\r
+ *    Licensed to the Apache Software Foundation (ASF) under one or more\r
+ *    contributor license agreements.  See the NOTICE file distributed with\r
+ *    this work for additional information regarding copyright ownership.\r
+ *    The ASF licenses this file to You under the Apache License, Version 2.0\r
+ *    (the "License"); you may not use this file except in compliance with\r
+ *    the License.  You may obtain a copy of the License at\r
+ *\r
+ *        http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *    Unless required by applicable law or agreed to in writing, software\r
+ *    distributed under the License is distributed on an "AS IS" BASIS,\r
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *    See the License for the specific language governing permissions and\r
+ *    limitations under the License.\r
+ * ==================================================================== \r
+ */\r
+\r
+package org.apache.poi.xslf.usermodel;\r
+\r
+import java.awt.Rectangle;\r
+import java.awt.image.BufferedImage;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.net.URL;\r
+import java.text.DecimalFormat;\r
+\r
+import javax.imageio.ImageIO;\r
+import javax.xml.namespace.QName;\r
+\r
+import org.apache.poi.openxml4j.opc.PackagePart;\r
+import org.apache.poi.openxml4j.opc.PackagePartName;\r
+import org.apache.poi.openxml4j.opc.PackageRelationship;\r
+import org.apache.poi.openxml4j.opc.PackagingURIHelper;\r
+import org.apache.poi.openxml4j.opc.TargetMode;\r
+import org.apache.poi.sl.usermodel.PictureData.PictureType;\r
+import org.apache.xmlbeans.XmlCursor;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;\r
+import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.CTExtension;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.CTTLCommonMediaNodeData;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.CTTLCommonTimeNodeData;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.CTTimeNodeList;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeIndefinite;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeFillType;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeRestartType;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeType;\r
+\r
+import com.xuggle.mediatool.IMediaReader;\r
+import com.xuggle.mediatool.MediaListenerAdapter;\r
+import com.xuggle.mediatool.ToolFactory;\r
+import com.xuggle.mediatool.event.IVideoPictureEvent;\r
+import com.xuggle.xuggler.Global;\r
+import com.xuggle.xuggler.IContainer;\r
+import com.xuggle.xuggler.io.InputOutputStreamHandler;\r
+\r
+/**\r
+ * Adding multiple videos to a slide\r
+ * \r
+ * need the Xuggler 5.4 jars:\r
+ *  &lt;repositories&gt;\r
+ *  &lt;repository&gt;\r
+ *  &lt;id&gt;xuggle repo&lt;/id&gt;\r
+ *  &lt;url&gt;http://xuggle.googlecode.com/svn/trunk/repo/share/java/&lt;/url&gt;\r
+ *  &lt;/repository&gt;\r
+ *  &lt;/repositories&gt;\r
+ *  ...\r
+ *  &lt;dependency&gt;\r
+ *  &lt;groupId&gt;xuggle&lt;/groupId&gt;\r
+ *  &lt;artifactId&gt;xuggle-xuggler&lt;/artifactId&gt;\r
+ *  &lt;version&gt;5.4&lt;/version&gt;\r
+ *  &lt;/dependency&gt;\r
+ * \r
+ * @see <a href="http://stackoverflow.com/questions/15197300/apache-poi-xslf-adding-movie-to-the-slide">Apache POI XSLF Adding movie to the slide</a>\r
+ * @see <a href="http://apache-poi.1045710.n5.nabble.com/Question-about-embedded-video-in-PPTX-files-tt5718461.html">Question about embedded video in PPTX files</a>\r
+ */\r
+public class AddVideoToPptx {\r
+    static DecimalFormat df_time = new DecimalFormat("0.####");\r
+\r
+    public static void main(String[] args) throws Exception {\r
+        URL video = new URL("http://archive.org/download/test-mpeg/test-mpeg.mpg");\r
+        // URL video = new URL("file:test-mpeg.mpg");\r
+\r
+        XMLSlideShow pptx = new XMLSlideShow();\r
+\r
+        // add video file\r
+        String videoFileName = video.getPath().substring(video.getPath().lastIndexOf('/')+1);\r
+        PackagePartName partName = PackagingURIHelper.createPartName("/ppt/media/"+videoFileName);\r
+        PackagePart part = pptx.getPackage().createPart(partName, "video/mpeg");\r
+        OutputStream partOs = part.getOutputStream();\r
+        InputStream fis = video.openStream();\r
+        byte buf[] = new byte[1024];\r
+        for (int readBytes; (readBytes = fis.read(buf)) != -1; partOs.write(buf, 0, readBytes));\r
+        fis.close();\r
+        partOs.close();\r
+\r
+        XSLFSlide slide1 = pptx.createSlide();\r
+        XSLFPictureShape pv1 = addPreview(pptx, slide1, part, 5, 50, 50);\r
+        addVideo(pptx, slide1, part, pv1, 5);\r
+        addTimingInfo(slide1, pv1);\r
+        XSLFPictureShape pv2 = addPreview(pptx, slide1, part, 9, 50, 250);\r
+        addVideo(pptx, slide1, part, pv2, 9);\r
+        addTimingInfo(slide1, pv2);\r
+\r
+        FileOutputStream fos = new FileOutputStream("pptx-with-video.pptx");\r
+        pptx.write(fos);\r
+        fos.close();\r
+        \r
+        pptx.close();\r
+    }\r
+\r
+    static XSLFPictureShape addPreview(XMLSlideShow pptx, XSLFSlide slide1, PackagePart videoPart, double seconds, int x, int y) throws IOException {\r
+        // get preview after 5 sec.\r
+        IContainer ic = IContainer.make();\r
+        InputOutputStreamHandler iosh = new InputOutputStreamHandler(videoPart.getInputStream());\r
+        if (ic.open(iosh, IContainer.Type.READ, null) < 0) return null;\r
+\r
+        IMediaReader mediaReader = ToolFactory.makeReader(ic);\r
+\r
+        // stipulate that we want BufferedImages created in BGR 24bit color space\r
+        mediaReader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);\r
+\r
+        ImageSnapListener isl = new ImageSnapListener(seconds);\r
+        mediaReader.addListener(isl);\r
+\r
+        // read out the contents of the media file and\r
+        // dispatch events to the attached listener\r
+        while (!isl.hasFired && mediaReader.readPacket() == null) ;\r
+\r
+        mediaReader.close();\r
+        ic.close();\r
+\r
+        // add snapshot\r
+        BufferedImage image1 = isl.image;\r
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();\r
+        ImageIO.write(image1, "jpeg", bos);\r
+        XSLFPictureData snap = pptx.addPicture(bos.toByteArray(), PictureType.JPEG);\r
+        XSLFPictureShape pic1 = slide1.createPicture(snap);\r
+        pic1.setAnchor(new Rectangle(x, y, image1.getWidth(), image1.getHeight()));\r
+        return pic1;\r
+    }\r
+\r
+    static void addVideo(XMLSlideShow pptx, XSLFSlide slide1, PackagePart videoPart, XSLFPictureShape pic1, double seconds) throws IOException {\r
+\r
+        // add video shape\r
+        PackagePartName partName = videoPart.getPartName();\r
+        PackageRelationship prsEmbed1 = slide1.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, "http://schemas.microsoft.com/office/2007/relationships/media");\r
+        PackageRelationship prsExec1 = slide1.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/video");\r
+        CTPicture xpic1 = (CTPicture)pic1.getXmlObject();\r
+        CTHyperlink link1 = xpic1.getNvPicPr().getCNvPr().addNewHlinkClick();\r
+        link1.setId("");\r
+        link1.setAction("ppaction://media");\r
+\r
+        // add video relation\r
+        CTApplicationNonVisualDrawingProps nvPr = xpic1.getNvPicPr().getNvPr();\r
+        nvPr.addNewVideoFile().setLink(prsExec1.getId());\r
+        CTExtension ext = nvPr.addNewExtLst().addNewExt();\r
+        // see http://msdn.microsoft.com/en-us/library/dd950140(v=office.12).aspx\r
+        ext.setUri("{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}");\r
+        String p14Ns = "http://schemas.microsoft.com/office/powerpoint/2010/main";\r
+        XmlCursor cur = ext.newCursor();\r
+        cur.toEndToken();\r
+        cur.beginElement(new QName(p14Ns, "media", "p14"));\r
+        cur.insertNamespace("p14", p14Ns);\r
+        cur.insertAttributeWithValue(new QName(STRelationshipId.type.getName().getNamespaceURI(), "embed"), prsEmbed1.getId());\r
+        cur.beginElement(new QName(p14Ns, "trim", "p14"));\r
+        cur.insertAttributeWithValue("st", df_time.format(seconds*1000.0));\r
+        cur.dispose();\r
+\r
+    }\r
+\r
+    static void addTimingInfo(XSLFSlide slide1, XSLFPictureShape pic1) {\r
+        // add slide timing information, so video can be controlled\r
+        CTSlide xslide = slide1.getXmlObject();\r
+        CTTimeNodeList ctnl;\r
+        if (!xslide.isSetTiming()) {\r
+            CTTLCommonTimeNodeData ctn = xslide.addNewTiming().addNewTnLst().addNewPar().addNewCTn();\r
+            ctn.setDur(STTLTimeIndefinite.INDEFINITE);\r
+            ctn.setRestart(STTLTimeNodeRestartType.NEVER);\r
+            ctn.setNodeType(STTLTimeNodeType.TM_ROOT);\r
+            ctnl = ctn.addNewChildTnLst();\r
+        } else {\r
+            ctnl = xslide.getTiming().getTnLst().getParArray(0).getCTn().getChildTnLst();\r
+        }\r
+\r
+        CTTLCommonMediaNodeData cmedia = ctnl.addNewVideo().addNewCMediaNode();\r
+        cmedia.setVol(80000);\r
+        CTTLCommonTimeNodeData ctn = cmedia.addNewCTn();\r
+        ctn.setFill(STTLTimeNodeFillType.HOLD);\r
+        ctn.setDisplay(false);\r
+        ctn.addNewStCondLst().addNewCond().setDelay(STTLTimeIndefinite.INDEFINITE);\r
+        cmedia.addNewTgtEl().addNewSpTgt().setSpid(""+pic1.getShapeId());\r
+    }\r
+\r
+\r
+    static class ImageSnapListener extends MediaListenerAdapter {\r
+        final double SECONDS_BETWEEN_FRAMES;\r
+        final long MICRO_SECONDS_BETWEEN_FRAMES;\r
+        boolean hasFired = false;\r
+        BufferedImage image = null;\r
+\r
+        // The video stream index, used to ensure we display frames from one and\r
+        // only one video stream from the media container.\r
+        int mVideoStreamIndex = -1;\r
+\r
+        // Time of last frame write\r
+        long mLastPtsWrite = Global.NO_PTS;\r
+\r
+        public ImageSnapListener(double seconds) {\r
+            SECONDS_BETWEEN_FRAMES = seconds;\r
+            MICRO_SECONDS_BETWEEN_FRAMES =\r
+                    (long)(Global.DEFAULT_PTS_PER_SECOND * SECONDS_BETWEEN_FRAMES);\r
+        }\r
+\r
+\r
+        @Override\r
+        public void onVideoPicture(IVideoPictureEvent event) {\r
+\r
+            if (event.getStreamIndex() != mVideoStreamIndex) {\r
+                // if the selected video stream id is not yet set, go ahead an\r
+                // select this lucky video stream\r
+                if (mVideoStreamIndex != -1) return;\r
+                mVideoStreamIndex = event.getStreamIndex();\r
+            }\r
+\r
+            long evtTS = event.getTimeStamp();\r
+\r
+            // if uninitialized, back date mLastPtsWrite to get the very first frame\r
+            if (mLastPtsWrite == Global.NO_PTS)\r
+                mLastPtsWrite = Math.max(0, evtTS - MICRO_SECONDS_BETWEEN_FRAMES);\r
+\r
+            // if it's time to write the next frame\r
+            if (evtTS - mLastPtsWrite >= MICRO_SECONDS_BETWEEN_FRAMES) {\r
+                if (!hasFired) {\r
+                    image = event.getImage();\r
+                    hasFired = true;\r
+                }\r
+                // update last write time\r
+                mLastPtsWrite += MICRO_SECONDS_BETWEEN_FRAMES;\r
+            }\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/src/examples/src/org/apache/poi/examples/xslf/BarChartDemo.java b/src/examples/src/org/apache/poi/examples/xslf/BarChartDemo.java
new file mode 100644 (file)
index 0000000..6864c69
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ *  ====================================================================
+ *    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.examples.xslf;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.chart.AxisOrientation;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFChart;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+/**
+ * Build a bar chart from a template pptx
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class BarChartDemo {
+    private BarChartDemo() {}
+
+    private static void usage(){
+        System.out.println("Usage: BarChartDemo <bar-chart-template.pptx> <bar-chart-data.txt>");
+        System.out.println("    bar-chart-template.pptx     template with a bar chart");
+        System.out.println("    bar-chart-data.txt          the model to set. First line is chart title, " +
+                "then go pairs {axis-label value}");
+    }
+
+    public static void main(String[] args) throws Exception {
+        if(args.length < 2) {
+            usage();
+            return;
+        }
+
+        try (FileInputStream argIS = new FileInputStream(args[0]);
+            BufferedReader modelReader = new BufferedReader(new FileReader(args[1]))) {
+
+            String chartTitle = modelReader.readLine();  // first line is chart title
+            String[] series = modelReader.readLine().split(",");
+
+            // Category Axis Data
+            List<String> listLanguages = new ArrayList<>(10);
+
+            // Values
+            List<Double> listCountries = new ArrayList<>(10);
+            List<Double> listSpeakers = new ArrayList<>(10);
+
+            // set model
+            String ln;
+            while((ln = modelReader.readLine()) != null) {
+                String[] vals = ln.split(",");
+                listCountries.add(Double.valueOf(vals[0]));
+                listSpeakers.add(Double.valueOf(vals[1]));
+                listLanguages.add(vals[2]);
+            }
+            String[] categories = listLanguages.toArray(new String[0]);
+            Double[] values1 = listCountries.toArray(new Double[0]);
+            Double[] values2 = listSpeakers.toArray(new Double[0]);
+
+            try (XMLSlideShow pptx = new XMLSlideShow(argIS)) {
+                XSLFSlide slide = pptx.getSlides().get(0);
+                setBarData(findChart(slide), chartTitle, series, categories, values1, values2);
+
+                XSLFChart chart = findChart(pptx.createSlide().importContent(slide));
+                setColumnData(chart, "Column variant");
+
+                // save the result
+                try (OutputStream out = new FileOutputStream("bar-chart-demo-output.pptx")) {
+                    pptx.write(out);
+                }
+            }
+        }
+    }
+
+    private static void setBarData(XSLFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
+        final List<XDDFChartData> data = chart.getChartSeries();
+        final XDDFBarChartData bar = (XDDFBarChartData) data.get(0);
+
+        final int numOfPoints = categories.length;
+        final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_LANGUAGES, COLUMN_LANGUAGES));
+        final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_COUNTRIES, COLUMN_COUNTRIES));
+        final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_SPEAKERS, COLUMN_SPEAKERS));
+        final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, COLUMN_LANGUAGES);
+        final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, COLUMN_COUNTRIES);
+        values1[6] = 16.0; // if you ever want to change the underlying data, it has to be done before building the data source
+        final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, COLUMN_SPEAKERS);
+
+        XDDFChartData.Series series1 = bar.getSeries(0);
+        series1.replaceData(categoriesData, valuesData);
+        series1.setTitle(series[0], chart.setSheetTitle(series[0], COLUMN_COUNTRIES));
+        XDDFChartData.Series series2 = bar.addSeries(categoriesData, valuesData2);
+        series2.setTitle(series[1], chart.setSheetTitle(series[1], COLUMN_SPEAKERS));
+
+        chart.plot(bar);
+        chart.setTitleText(chartTitle); // https://stackoverflow.com/questions/30532612
+        // chart.setTitleOverlay(overlay);
+
+        // adjust font size for readability
+        bar.getCategoryAxis().getOrAddTextProperties().setFontSize(11.5);
+        chart.getTitle().getOrAddTextProperties().setFontSize(18.2);
+    }
+
+    private static void setColumnData(XSLFChart chart, String chartTitle) {
+        // Series Text
+        List<XDDFChartData> series = chart.getChartSeries();
+        XDDFBarChartData bar = (XDDFBarChartData) series.get(0);
+
+        // in order to transform a bar chart into a column chart, you just need to change the bar direction
+        bar.setBarDirection(BarDirection.COL);
+
+        // looking for "Stacked Bar Chart"? uncomment the following line
+        // bar.setBarGrouping(BarGrouping.STACKED);
+
+        // additionally, you can adjust the axes
+        bar.getCategoryAxis().setOrientation(AxisOrientation.MAX_MIN);
+        bar.getValueAxes().get(0).setPosition(AxisPosition.TOP);
+    }
+
+    private static XSLFChart findChart(XSLFSlide slide) {
+        // find chart in the slide
+        XSLFChart chart = null;
+        for(POIXMLDocumentPart part : slide.getRelations()){
+            if(part instanceof XSLFChart){
+                chart = (XSLFChart) part;
+                break;
+            }
+        }
+
+        if(chart == null) {
+            throw new IllegalStateException("chart not found in the template");
+        }
+        return chart;
+    }
+
+    private static final int COLUMN_LANGUAGES = 0;
+    private static final int COLUMN_COUNTRIES = 1;
+    private static final int COLUMN_SPEAKERS = 2;
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/ChartFromScratch.java b/src/examples/src/org/apache/poi/examples/xslf/ChartFromScratch.java
new file mode 100644 (file)
index 0000000..d012744
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ *  ====================================================================
+ *    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.examples.xslf;
+
+import java.awt.geom.Rectangle2D;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.util.Units;
+import org.apache.poi.xddf.usermodel.chart.AxisCrossBetween;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.AxisTickMark;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.BarGrouping;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFChart;
+import org.apache.poi.xslf.usermodel.XSLFGraphicFrame;
+import org.apache.poi.xslf.usermodel.XSLFShape;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+/**
+ * Build a chart without reading template file
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class ChartFromScratch {
+    private ChartFromScratch() {}
+
+    private static void usage(){
+        System.out.println("Usage: ChartFromScratch <bar-chart-data.txt>");
+        System.out.println("    bar-chart-data.txt          the model to set. First line is chart title, " +
+                "then go pairs {axis-label value}");
+    }
+
+    public static void main(String[] args) throws Exception {
+        if(args.length < 1) {
+            usage();
+            return;
+        }
+
+        try (BufferedReader modelReader = new BufferedReader(new FileReader(args[0]))) {
+
+            String chartTitle = modelReader.readLine();  // first line is chart title
+            String[] series = modelReader.readLine().split(",");
+
+            // Category Axis Data
+            List<String> listLanguages = new ArrayList<>(10);
+
+            // Values
+            List<Double> listCountries = new ArrayList<>(10);
+            List<Double> listSpeakers = new ArrayList<>(10);
+
+            // set model
+            String ln;
+            while((ln = modelReader.readLine()) != null) {
+                String[] vals = ln.split(",");
+                listCountries.add(Double.valueOf(vals[0]));
+                listSpeakers.add(Double.valueOf(vals[1]));
+                listLanguages.add(vals[2]);
+            }
+
+            String[] categories = listLanguages.toArray(new String[0]);
+            Double[] values1 = listCountries.toArray(new Double[0]);
+            Double[] values2 = listSpeakers.toArray(new Double[0]);
+
+            try (XMLSlideShow ppt = new XMLSlideShow()) {
+                createSlideWithChart(ppt, chartTitle, series, categories, values1, values2);
+                createSlideWithChart(ppt, chartTitle, series, categories, values1, values2);
+                createSlideWithChart(ppt, chartTitle, series, categories, values1, values2);
+                // save the result
+                try (OutputStream out = new FileOutputStream("chart-from-scratch.pptx")) {
+                    ppt.write(out);
+                }
+            }
+            try (FileInputStream is = new FileInputStream("chart-from-scratch.pptx")) {
+                try (XMLSlideShow ppt = new XMLSlideShow(is)) {
+                    for (XSLFSlide slide : ppt.getSlides()) {
+                        for (XSLFShape shape : slide.getShapes()) {
+                            if (shape instanceof XSLFGraphicFrame) {
+                                XSLFGraphicFrame frame = (XSLFGraphicFrame) shape;
+                                if (frame.hasChart()) {
+                                    System.out.println(frame.getChart().getTitleShape().getText());
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        System.out.println("Done");
+    }
+
+    private static void createSlideWithChart(XMLSlideShow ppt, String chartTitle, String[] series, String[] categories,
+            Double[] values1, Double[] values2) {
+        XSLFSlide slide = ppt.createSlide();
+        XSLFChart chart = ppt.createChart();
+        Rectangle2D rect2D = new java.awt.Rectangle(fromCM(1.5), fromCM(4), fromCM(22), fromCM(14));
+        slide.addChart(chart, rect2D);
+        setBarData(chart, chartTitle, series, categories, values1, values2);
+    }
+
+    private static int fromCM(double cm) {
+        return (int) (Math.rint(cm * Units.EMU_PER_CENTIMETER));
+    }
+
+    private static void setBarData(XSLFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
+        // Use a category axis for the bottom axis.
+        XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
+        bottomAxis.setTitle(series[2]);
+        XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+        leftAxis.setTitle(series[0]+","+series[1]);
+        leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
+        leftAxis.setMajorTickMark(AxisTickMark.OUT);
+        leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
+
+        final int numOfPoints = categories.length;
+        final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_LANGUAGES, COLUMN_LANGUAGES));
+        final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_COUNTRIES, COLUMN_COUNTRIES));
+        final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_SPEAKERS, COLUMN_SPEAKERS));
+        final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, COLUMN_LANGUAGES);
+        final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, COLUMN_COUNTRIES);
+        valuesData.setFormatCode("General");
+        values1[6] = 16.0; // if you ever want to change the underlying data, it has to be done before building the data source
+        final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, COLUMN_SPEAKERS);
+        valuesData2.setFormatCode("General");
+
+
+        XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
+        bar.setBarGrouping(BarGrouping.CLUSTERED);
+
+        XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData);
+        series1.setTitle(series[0], chart.setSheetTitle(series[0], COLUMN_COUNTRIES));
+
+        XDDFBarChartData.Series series2 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData2);
+        series2.setTitle(series[1], chart.setSheetTitle(series[1], COLUMN_SPEAKERS));
+
+        bar.setVaryColors(true);
+        bar.setBarDirection(BarDirection.COL);
+        chart.plot(bar);
+
+        XDDFChartLegend legend = chart.getOrAddLegend();
+        legend.setPosition(LegendPosition.LEFT);
+        legend.setOverlay(false);
+
+        chart.setTitleText(chartTitle);
+        chart.setTitleOverlay(false);
+        chart.setAutoTitleDeleted(false);
+    }
+
+    private static final int COLUMN_LANGUAGES = 0;
+    private static final int COLUMN_COUNTRIES = 1;
+    private static final int COLUMN_SPEAKERS = 2;
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/DataExtraction.java b/src/examples/src/org/apache/poi/examples/xslf/DataExtraction.java
new file mode 100644 (file)
index 0000000..40a7c7f
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *  ====================================================================
+ *    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.examples.xslf;
+
+import java.awt.Dimension;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFPictureData;
+import org.apache.poi.xslf.usermodel.XSLFPictureShape;
+import org.apache.poi.xslf.usermodel.XSLFShape;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextShape;
+
+/**
+ * Demonstrates how you can extract data from a .pptx file
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class DataExtraction {
+    private DataExtraction() {}
+
+    public static void main(String[] args) throws IOException {
+
+        PrintStream out = System.out;
+
+        if (args.length == 0) {
+           out.println("Input file is required");
+           return;
+        }
+
+        FileInputStream is = new FileInputStream(args[0]);
+        try (XMLSlideShow ppt = new XMLSlideShow(is)) {
+            is.close();
+
+            // Get the document's embedded files.
+            for (PackagePart p : ppt.getAllEmbeddedParts()) {
+                String type = p.getContentType();
+                // typically file name
+                String name = p.getPartName().getName();
+                out.println("Embedded file (" + type + "): " + name);
+
+                InputStream pIs = p.getInputStream();
+                // make sense of the part data
+                pIs.close();
+
+            }
+
+            // Get the document's embedded files.
+            for (XSLFPictureData data : ppt.getPictureData()) {
+                String type = data.getContentType();
+                String name = data.getFileName();
+                out.println("Picture (" + type + "): " + name);
+
+                InputStream pIs = data.getInputStream();
+                // make sense of the image data
+                pIs.close();
+            }
+
+            // size of the canvas in points
+            Dimension pageSize = ppt.getPageSize();
+            out.println("Pagesize: " + pageSize);
+
+            for (XSLFSlide slide : ppt.getSlides()) {
+                for (XSLFShape shape : slide) {
+                    if (shape instanceof XSLFTextShape) {
+                        XSLFTextShape txShape = (XSLFTextShape) shape;
+                        out.println(txShape.getText());
+                    } else if (shape instanceof XSLFPictureShape) {
+                        XSLFPictureShape pShape = (XSLFPictureShape) shape;
+                        XSLFPictureData pData = pShape.getPictureData();
+                        out.println(pData.getFileName());
+                    } else {
+                        out.println("Process me: " + shape.getClass());
+                    }
+                }
+            }
+        }
+    }
+
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/MergePresentations.java b/src/examples/src/org/apache/poi/examples/xslf/MergePresentations.java
new file mode 100644 (file)
index 0000000..89ae0b1
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  ====================================================================
+ *    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.examples.xslf;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+/**
+ * Merge multiple pptx presentations together
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class MergePresentations {
+    private MergePresentations() {}
+
+    public static void main(String[] args) throws Exception {
+        try (XMLSlideShow ppt = new XMLSlideShow()) {
+            for (String arg : args) {
+                try (FileInputStream is = new FileInputStream(arg);
+                     XMLSlideShow src = new XMLSlideShow(is)) {
+                    for (XSLFSlide srcSlide : src.getSlides()) {
+                        ppt.createSlide().importContent(srcSlide);
+                    }
+                }
+            }
+
+            try (FileOutputStream out = new FileOutputStream("merged.pptx")) {
+                ppt.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/PPTX2SVG.txt b/src/examples/src/org/apache/poi/examples/xslf/PPTX2SVG.txt
new file mode 100644 (file)
index 0000000..dbe089a
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ *  ====================================================================
+ *    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.xslf.usermodel;
+
+import org.apache.batik.dom.svg.SVGDOMImplementation;
+import org.apache.batik.svggen.SVGGraphics2D;
+import org.apache.batik.transcoder.wmf.tosvg.WMFPainter;
+import org.apache.batik.transcoder.wmf.tosvg.WMFRecordStore;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+
+import javax.imageio.ImageIO;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.DataInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+/**
+ * Convert each slide of a .pptx presentation into SVG
+ *
+ * @author Yegor Kozlov
+ */
+public class PPTX2SVG {
+
+    static void usage() {
+        System.out.println("Usage: PPTX2SVG  <pptx file>");
+    }
+
+    public static void main(String[] args) throws Exception {
+        if (args.length == 0) {
+            usage();
+            return;
+        }
+
+        String file = args[0];
+
+        System.out.println("Processing " + file);
+
+        // read the .pptx file
+        XMLSlideShow ppt = new XMLSlideShow(OPCPackage.open(file));
+
+        Dimension pgsize = ppt.getPageSize();
+
+        // convert each slide into a .svg file
+        XSLFSlide[] slide = ppt.getSlides();
+        for (int i = 0; i < slide.length; i++) {
+            // Create initial SVG DOM
+            DOMImplementation domImpl = SVGDOMImplementation.getDOMImplementation();
+            Document doc = domImpl.createDocument("http://www.w3.org/2000/svg", "svg", null);
+            //Use Batik SVG Graphics2D driver
+            SVGGraphics2D graphics = new SVGGraphics2D(doc);
+            graphics.setRenderingHint(XSLFRenderingHint.IMAGE_RENDERER, new WMFImageRender());
+            graphics.setSVGCanvasSize(pgsize);
+
+            String title = slide[i].getTitle();
+            System.out.println("Rendering slide " + (i + 1) + (title == null ? "" : ": " + title));
+
+            // draw stuff. All the heavy-lifting happens here
+            slide[i].draw(graphics);
+
+            // save the result.
+            int sep = file.lastIndexOf(".");
+            String fname = file.substring(0, sep == -1 ? file.length() : sep) + "-" + (i + 1) + ".svg";
+            OutputStreamWriter out =
+                    new OutputStreamWriter(new FileOutputStream(fname), "UTF-8");
+            DOMSource domSource = new DOMSource(graphics.getRoot());
+            StreamResult streamResult = new StreamResult(out);
+            TransformerFactory tf = TransformerFactory.newInstance();
+            Transformer serializer = tf.newTransformer();
+            serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+            serializer.transform(domSource, streamResult);
+            out.flush();
+            out.close();
+        }
+        System.out.println("Done");
+    }
+
+    /**
+     * Image renderer with support for .wmf images
+     */
+    static class WMFImageRender extends XSLFImageRendener {
+
+        /**
+         * Use Apache Batik to render WMF,
+         * delegate all other types of images to the javax.imageio framework
+       */
+        @Override
+        public boolean drawImage(Graphics2D graphics, XSLFPictureData data,
+                                 Rectangle2D anchor) {
+            try {
+                // see what type of image we are
+                PackagePart part = data.getPackagePart();
+                String contentType = part.getContentType();
+                if (contentType.equals("image/x-wmf")) {
+                    WMFRecordStore currentStore = new WMFRecordStore();
+                    currentStore.read(new DataInputStream(part.getInputStream()));
+                    int wmfwidth = currentStore.getWidthPixels();
+                    float conv = (float) anchor.getWidth() / wmfwidth;
+
+                    // Build a painter for the RecordStore
+                    WMFPainter painter = new WMFPainter(currentStore,
+                            (int) anchor.getX(), (int) anchor.getY(), conv);
+                    painter.paint(graphics);
+                } else {
+                    BufferedImage img = ImageIO.read(data.getPackagePart().getInputStream());
+                    graphics.drawImage(img,
+                            (int) anchor.getX(), (int) anchor.getY(),
+                            (int) anchor.getWidth(), (int) anchor.getHeight(), null);
+                }
+            } catch (Exception e) {
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * Convert data form the supplied package part into a BufferedImage.
+         * This method is used to create texture paint.
+         */
+        @Override
+        public BufferedImage readImage(PackagePart packagePart) throws IOException {
+            String contentType = packagePart.getContentType();
+            if (contentType.equals("image/x-wmf")) {
+                try {
+                    WMFRecordStore currentStore = new WMFRecordStore();
+                    currentStore.read(new DataInputStream(packagePart.getInputStream()));
+                    int wmfwidth = currentStore.getWidthPixels();
+                    int wmfheight = currentStore.getHeightPixels();
+
+                    BufferedImage img = new BufferedImage(wmfwidth, wmfheight, BufferedImage.TYPE_INT_RGB);
+                    Graphics2D graphics = img.createGraphics();
+
+                    // Build a painter for the RecordStore
+                    WMFPainter painter = new WMFPainter(currentStore, 0, 0, 1.0f);
+                    painter.paint(graphics);
+
+                    return img;
+                } catch (IOException e) {
+                    return null;
+                }
+            } else {
+                return ImageIO.read(packagePart.getInputStream());
+            }
+        }
+
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/PieChartDemo.java b/src/examples/src/org/apache/poi/examples/xslf/PieChartDemo.java
new file mode 100644 (file)
index 0000000..9f0ca73
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  ====================================================================
+ *    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.examples.xslf;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFChart;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+/**
+ * Build a pie chart from a template pptx
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class PieChartDemo {
+    private PieChartDemo() {}
+
+    private static void usage(){
+        System.out.println("Usage: PieChartDemo <pie-chart-template.pptx> <pie-chart-data.txt>");
+        System.out.println("    pie-chart-template.pptx     template with a pie chart");
+        System.out.println("    pie-chart-data.txt          the model to set. First line is chart title, " +
+                "then go pairs {axis-label value}");
+    }
+
+    public static void main(String[] args) throws Exception {
+        if(args.length < 2) {
+            usage();
+            return;
+        }
+
+        try (FileInputStream argIS = new FileInputStream(args[0]);
+            BufferedReader modelReader = new BufferedReader(new FileReader(args[1]))) {
+            String chartTitle = modelReader.readLine();  // first line is chart title
+
+            try (XMLSlideShow pptx = new XMLSlideShow(argIS)) {
+                XSLFSlide slide = pptx.getSlides().get(0);
+
+                // find chart in the slide
+                XSLFChart chart = null;
+                for (POIXMLDocumentPart part : slide.getRelations()) {
+                    if (part instanceof XSLFChart) {
+                        chart = (XSLFChart) part;
+                        break;
+                    }
+                }
+
+                   if(chart == null) {
+                       throw new IllegalStateException("chart not found in the template");
+                   }
+
+                   // Series Text
+                   List<XDDFChartData> series = chart.getChartSeries();
+                   XDDFPieChartData pie = (XDDFPieChartData) series.get(0);
+
+                   // Category Axis Data
+                   List<String> listCategories = new ArrayList<>(3);
+
+                   // Values
+                   List<Double> listValues = new ArrayList<>(3);
+
+                   // set model
+                   String ln;
+                   while((ln = modelReader.readLine()) != null){
+                       String[] vals = ln.split("\\s+");
+                       listCategories.add(vals[0]);
+                       listValues.add(Double.valueOf(vals[1]));
+                   }
+                   String[] categories = listCategories.toArray(new String[0]);
+                   Double[] values = listValues.toArray(new Double[0]);
+
+                   final int numOfPoints = categories.length;
+                   final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
+                   final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
+                   final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange);
+                   final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values, valuesDataRange);
+
+                   XDDFPieChartData.Series firstSeries = (XDDFPieChartData.Series) pie.getSeries(0);
+                   firstSeries.replaceData(categoriesData, valuesData);
+                   firstSeries.setTitle(chartTitle, chart.setSheetTitle(chartTitle, 0));
+                   firstSeries.setExplosion(25L);
+                   chart.plot(pie);
+
+                // save the result
+                try (OutputStream out = new FileOutputStream("pie-chart-demo-output.pptx")) {
+                    pptx.write(out);
+                }
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/Tutorial1.java b/src/examples/src/org/apache/poi/examples/xslf/Tutorial1.java
new file mode 100644 (file)
index 0000000..d1b4768
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  ====================================================================
+ *    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.examples.xslf;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.xslf.usermodel.SlideLayout;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFSlideLayout;
+import org.apache.poi.xslf.usermodel.XSLFSlideMaster;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextShape;
+
+/**
+ * Demonstrates how to create slides with predefined layout
+ * and fill the placeholder shapes
+ */
+public final class Tutorial1 {
+    private Tutorial1() {}
+
+    public static void main(String[] args) throws IOException{
+        try (XMLSlideShow ppt = new XMLSlideShow()) {
+            // XSLFSlide#createSlide() with no arguments creates a blank slide
+            /*XSLFSlide blankSlide =*/
+            ppt.createSlide();
+
+
+            XSLFSlideMaster master = ppt.getSlideMasters().get(0);
+
+            XSLFSlideLayout layout1 = master.getLayout(SlideLayout.TITLE);
+            XSLFSlide slide1 = ppt.createSlide(layout1);
+            XSLFTextShape[] ph1 = slide1.getPlaceholders();
+            XSLFTextShape titlePlaceholder1 = ph1[0];
+            titlePlaceholder1.setText("This is a title");
+            XSLFTextShape subtitlePlaceholder1 = ph1[1];
+            subtitlePlaceholder1.setText("this is a subtitle");
+
+            XSLFSlideLayout layout2 = master.getLayout(SlideLayout.TITLE_AND_CONTENT);
+            XSLFSlide slide2 = ppt.createSlide(layout2);
+            XSLFTextShape[] ph2 = slide2.getPlaceholders();
+            XSLFTextShape titlePlaceholder2 = ph2[0];
+            titlePlaceholder2.setText("This is a title");
+            XSLFTextShape bodyPlaceholder = ph2[1];
+            // we are going to add text by paragraphs. Clear the default placehoder text before that
+            bodyPlaceholder.clearText();
+            XSLFTextParagraph p1 = bodyPlaceholder.addNewTextParagraph();
+            p1.setIndentLevel(0);
+            p1.addNewTextRun().setText("Level1 text");
+            XSLFTextParagraph p2 = bodyPlaceholder.addNewTextParagraph();
+            p2.setIndentLevel(1);
+            p2.addNewTextRun().setText("Level2 text");
+            XSLFTextParagraph p3 = bodyPlaceholder.addNewTextParagraph();
+            p3.setIndentLevel(2);
+            p3.addNewTextRun().setText("Level3 text");
+
+            try (FileOutputStream out = new FileOutputStream("slides.pptx")) {
+                ppt.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/Tutorial2.java b/src/examples/src/org/apache/poi/examples/xslf/Tutorial2.java
new file mode 100644 (file)
index 0000000..78afd70
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *  ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one or more
+ *    contributor license agreements.  See the NOTICE file distributed with
+ *    this work for additional information regarding copyright ownership.
+ *    The ASF licenses this file to You under the Apache License, Version 2.0
+ *    (the "License"); you may not use this file except in compliance with
+ *    the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextBox;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+
+/**
+ * Basic paragraph and text formatting
+ */
+public final class Tutorial2 {
+    private Tutorial2() {}
+
+    public static void main(String[] args) throws IOException{
+        try (XMLSlideShow ppt = new XMLSlideShow()) {
+            XSLFSlide slide1 = ppt.createSlide();
+            XSLFTextBox shape1 = slide1.createTextBox();
+            // initial height of the text box is 100 pt but
+            Rectangle anchor = new Rectangle(10, 100, 300, 100);
+            shape1.setAnchor(anchor);
+
+            XSLFTextParagraph p1 = shape1.addNewTextParagraph();
+            XSLFTextRun r1 = p1.addNewTextRun();
+            r1.setText("Paragraph Formatting");
+            r1.setFontSize(24d);
+            r1.setFontColor(new Color(85, 142, 213));
+
+            XSLFTextParagraph p2 = shape1.addNewTextParagraph();
+            // If spaceBefore >= 0, then space is a percentage of normal line height.
+            // If spaceBefore < 0, the absolute value of linespacing is the spacing in points
+            p2.setSpaceBefore(-20d); // 20 pt from the previous paragraph
+            p2.setSpaceAfter(300d); // 3 lines after the paragraph
+            XSLFTextRun r2 = p2.addNewTextRun();
+            r2.setText("Paragraph  properties apply to all text residing within the corresponding paragraph.");
+            r2.setFontSize(16d);
+
+            XSLFTextParagraph p3 = shape1.addNewTextParagraph();
+
+            XSLFTextRun r3 = p3.addNewTextRun();
+            r3.setText("Run Formatting");
+            r3.setFontSize(24d);
+            r3.setFontColor(new Color(85, 142, 213));
+
+            XSLFTextParagraph p4 = shape1.addNewTextParagraph();
+            p4.setSpaceBefore(-20d); // 20 pt from the previous paragraph
+            p4.setSpaceAfter(300d); // 3 lines after the paragraph
+            XSLFTextRun r4 = p4.addNewTextRun();
+            r4.setFontSize(16d);
+            r4.setText(
+                    "Run level formatting is the most granular property level and allows " +
+                            "for the specifying of all low level text properties. The text run is " +
+                            "what all paragraphs are derived from and thus specifying various " +
+                            "properties per run will allow for a diversely formatted text paragraph.");
+
+            // resize the shape to fit text
+            shape1.resizeToFitText();
+
+            try (FileOutputStream out = new FileOutputStream("text.pptx")) {
+                ppt.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/Tutorial3.java b/src/examples/src/org/apache/poi/examples/xslf/Tutorial3.java
new file mode 100644 (file)
index 0000000..420605e
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  ====================================================================
+ *    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.examples.xslf;
+
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.sl.usermodel.Placeholder;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextShape;
+
+/**
+ * How to set slide title
+ */
+public final class Tutorial3 {
+    private Tutorial3() {}
+
+    public static void main(String[] args) throws IOException{
+        try (XMLSlideShow ppt = new XMLSlideShow()) {
+            XSLFSlide slide = ppt.createSlide();
+
+            XSLFTextShape titleShape = slide.createTextBox();
+            titleShape.setPlaceholder(Placeholder.TITLE);
+            titleShape.setText("This is a slide title");
+            titleShape.setAnchor(new Rectangle(50, 50, 400, 100));
+
+            try (FileOutputStream out = new FileOutputStream("title.pptx")) {
+                ppt.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/Tutorial4.java b/src/examples/src/org/apache/poi/examples/xslf/Tutorial4.java
new file mode 100644 (file)
index 0000000..a39e903
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *  ====================================================================
+ *    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.examples.xslf;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.sl.usermodel.TableCell.BorderEdge;
+import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTable;
+import org.apache.poi.xslf.usermodel.XSLFTableCell;
+import org.apache.poi.xslf.usermodel.XSLFTableRow;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+
+/**
+ * PPTX Tables
+ */
+public final class Tutorial4 {
+    private Tutorial4() {}
+
+    public static void main(String[] args) throws IOException{
+        try (XMLSlideShow ppt = new XMLSlideShow()) {
+            // XSLFSlide#createSlide() with no arguments creates a blank slide
+            XSLFSlide slide = ppt.createSlide();
+
+            XSLFTable tbl = slide.createTable();
+            tbl.setAnchor(new Rectangle(50, 50, 450, 300));
+
+            int numColumns = 3;
+            int numRows = 5;
+            XSLFTableRow headerRow = tbl.addRow();
+            headerRow.setHeight(50);
+            // header
+            for (int i = 0; i < numColumns; i++) {
+                XSLFTableCell th = headerRow.addCell();
+                XSLFTextParagraph p = th.addNewTextParagraph();
+                p.setTextAlign(TextAlign.CENTER);
+                XSLFTextRun r = p.addNewTextRun();
+                r.setText("Header " + (i + 1));
+                r.setBold(true);
+                r.setFontColor(Color.white);
+                th.setFillColor(new Color(79, 129, 189));
+                th.setBorderWidth(BorderEdge.bottom, 2.0);
+                th.setBorderColor(BorderEdge.bottom, Color.white);
+
+                tbl.setColumnWidth(i, 150);  // all columns are equally sized
+            }
+
+            // rows
+
+            for (int rownum = 0; rownum < numRows; rownum++) {
+                XSLFTableRow tr = tbl.addRow();
+                tr.setHeight(50);
+                // header
+                for (int i = 0; i < numColumns; i++) {
+                    XSLFTableCell cell = tr.addCell();
+                    XSLFTextParagraph p = cell.addNewTextParagraph();
+                    XSLFTextRun r = p.addNewTextRun();
+
+                    r.setText("Cell " + (i + 1));
+                    if (rownum % 2 == 0)
+                        cell.setFillColor(new Color(208, 216, 232));
+                    else
+                        cell.setFillColor(new Color(233, 247, 244));
+
+                }
+            }
+
+            try (FileOutputStream out = new FileOutputStream("table.pptx")) {
+                ppt.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/Tutorial5.java b/src/examples/src/org/apache/poi/examples/xslf/Tutorial5.java
new file mode 100644 (file)
index 0000000..cc459a1
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  ====================================================================
+ *    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.examples.xslf;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.sl.usermodel.PictureData.PictureType;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFPictureData;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+/**
+ * Images
+ */
+public final class Tutorial5 {
+    private Tutorial5() {}
+
+    public static void main(String[] args) throws IOException{
+        try (XMLSlideShow ppt = new XMLSlideShow()) {
+            XSLFSlide slide = ppt.createSlide();
+
+            File img = new File(System.getProperty("POI.testdata.path", "test-data"), "slideshow/clock.jpg");
+            XSLFPictureData pictureData = ppt.addPicture(img, PictureType.PNG);
+
+            /*XSLFPictureShape shape =*/
+            slide.createPicture(pictureData);
+
+            try (FileOutputStream out = new FileOutputStream("images.pptx")) {
+                ppt.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/Tutorial6.java b/src/examples/src/org/apache/poi/examples/xslf/Tutorial6.java
new file mode 100644 (file)
index 0000000..1648e21
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one or more
+ *    contributor license agreements.  See the NOTICE file distributed with
+ *    this work for additional information regarding copyright ownership.
+ *    The ASF licenses this file to You under the Apache License, Version 2.0
+ *    (the "License"); you may not use this file except in compliance with
+ *    the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFHyperlink;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextBox;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+
+/**
+ * Hyperlinks
+ */
+public final class Tutorial6 {
+    private Tutorial6() {}
+
+    public static void main(String[] args) throws IOException{
+        try (XMLSlideShow ppt = new XMLSlideShow()) {
+            XSLFSlide slide1 = ppt.createSlide();
+            XSLFSlide slide2 = ppt.createSlide();
+
+            XSLFTextBox shape1 = slide1.createTextBox();
+            shape1.setAnchor(new Rectangle(50, 50, 200, 50));
+            XSLFTextRun r1 = shape1.addNewTextParagraph().addNewTextRun();
+            XSLFHyperlink link1 = r1.createHyperlink();
+            r1.setText("https://poi.apache.org"); // visible text
+            link1.setAddress("https://poi.apache.org");  // link address
+
+            XSLFTextBox shape2 = slide1.createTextBox();
+            shape2.setAnchor(new Rectangle(300, 50, 200, 50));
+            XSLFTextRun r2 = shape2.addNewTextParagraph().addNewTextRun();
+            XSLFHyperlink link2 = r2.createHyperlink();
+            r2.setText("Go to the second slide"); // visible text
+            link2.linkToSlide(slide2);  // link address
+
+
+            try (FileOutputStream out = new FileOutputStream("hyperlinks.pptx")) {
+                ppt.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/Tutorial7.java b/src/examples/src/org/apache/poi/examples/xslf/Tutorial7.java
new file mode 100644 (file)
index 0000000..d617de8
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  ====================================================================
+ *    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.examples.xslf;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.sl.usermodel.AutoNumberingScheme;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextBox;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+
+/**
+ * Bullets and numbering
+ */
+public final class Tutorial7 {
+    private Tutorial7() {}
+
+    public static void main(String[] args) throws IOException {
+        try (XMLSlideShow ppt = new XMLSlideShow()) {
+            XSLFSlide slide = ppt.createSlide();
+            XSLFTextBox shape = slide.createTextBox();
+            shape.setAnchor(new Rectangle(50, 50, 400, 200));
+
+            XSLFTextParagraph p1 = shape.addNewTextParagraph();
+            p1.setIndentLevel(0);
+            p1.setBullet(true);
+            XSLFTextRun r1 = p1.addNewTextRun();
+            r1.setText("Bullet1");
+
+            XSLFTextParagraph p2 = shape.addNewTextParagraph();
+            // indentation before text
+            p2.setLeftMargin(60d);
+            // the bullet is set 40 pt before the text
+            p2.setIndent(-40d);
+            p2.setBullet(true);
+            // customize bullets
+            p2.setBulletFontColor(Color.red);
+            p2.setBulletFont("Wingdings");
+            p2.setBulletCharacter("\u0075");
+            p2.setIndentLevel(1);
+            XSLFTextRun r2 = p2.addNewTextRun();
+            r2.setText("Bullet2");
+
+            // the next three paragraphs form an auto-numbered list
+            XSLFTextParagraph p3 = shape.addNewTextParagraph();
+            p3.setBulletAutoNumber(AutoNumberingScheme.alphaLcParenRight, 1);
+            p3.setIndentLevel(2);
+            XSLFTextRun r3 = p3.addNewTextRun();
+            r3.setText("Numbered List Item - 1");
+
+            XSLFTextParagraph p4 = shape.addNewTextParagraph();
+            p4.setBulletAutoNumber(AutoNumberingScheme.alphaLcParenRight, 2);
+            p4.setIndentLevel(2);
+            XSLFTextRun r4 = p4.addNewTextRun();
+            r4.setText("Numbered List Item - 2");
+
+            XSLFTextParagraph p5 = shape.addNewTextParagraph();
+            p5.setBulletAutoNumber(AutoNumberingScheme.alphaLcParenRight, 3);
+            p5.setIndentLevel(2);
+            XSLFTextRun r5 = p5.addNewTextRun();
+            r5.setText("Numbered List Item - 3");
+
+            shape.resizeToFitText();
+
+            try (FileOutputStream out = new FileOutputStream("list.pptx")) {
+                ppt.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/bar-chart-data.txt b/src/examples/src/org/apache/poi/examples/xslf/bar-chart-data.txt
new file mode 100644 (file)
index 0000000..22c7b86
--- /dev/null
@@ -0,0 +1,12 @@
+10 languages with most speakers as first language\r
+countries,speakers,language\r
+58,315,العربية\r
+4,243,বাংলা\r
+38,1299,中文\r
+118,378,English\r
+4,260,हिन्दी\r
+2,128,日本語\r
+15,223,português\r
+6,119,ਪੰਜਾਬੀ\r
+18,154,Русский язык\r
+31,442,español\r
diff --git a/src/examples/src/org/apache/poi/examples/xslf/bar-chart-template.pptx b/src/examples/src/org/apache/poi/examples/xslf/bar-chart-template.pptx
new file mode 100644 (file)
index 0000000..e4d2613
Binary files /dev/null and b/src/examples/src/org/apache/poi/examples/xslf/bar-chart-template.pptx differ
diff --git a/src/examples/src/org/apache/poi/examples/xslf/pie-chart-data.txt b/src/examples/src/org/apache/poi/examples/xslf/pie-chart-data.txt
new file mode 100644 (file)
index 0000000..40b6959
--- /dev/null
@@ -0,0 +1,4 @@
+My Chart\r
+First 1.0\r
+Second 3.0\r
+Third 4.0
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/examples/xslf/pie-chart-template.pptx b/src/examples/src/org/apache/poi/examples/xslf/pie-chart-template.pptx
new file mode 100644 (file)
index 0000000..33d28e1
Binary files /dev/null and b/src/examples/src/org/apache/poi/examples/xslf/pie-chart-template.pptx differ
diff --git a/src/examples/src/org/apache/poi/examples/xslf/tutorial/Step1.java b/src/examples/src/org/apache/poi/examples/xslf/tutorial/Step1.java
new file mode 100644 (file)
index 0000000..2d384a8
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one or more
+ *    contributor license agreements.  See the NOTICE file distributed with
+ *    this work for additional information regarding copyright ownership.
+ *    The ASF licenses this file to You under the Apache License, Version 2.0
+ *    (the "License"); you may not use this file except in compliance with
+ *    the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf.tutorial;
+
+import java.io.FileInputStream;
+
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFShape;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+import org.apache.poi.xslf.usermodel.XSLFTextShape;
+
+/**
+ * Reading a .pptx presentation and printing basic shape properties
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class Step1 {
+    private Step1() {}
+
+    public static void main(String[] args) throws Exception {
+        if(args.length == 0)  {
+            System.out.println("Input file is required");
+            return;
+        }
+
+        FileInputStream fis = new FileInputStream(args[0]);
+        try (XMLSlideShow ppt = new XMLSlideShow(fis)) {
+            fis.close();
+
+            for (XSLFSlide slide : ppt.getSlides()) {
+                System.out.println("Title: " + slide.getTitle());
+
+                for (XSLFShape shape : slide.getShapes()) {
+                    if (shape instanceof XSLFTextShape) {
+                        XSLFTextShape tsh = (XSLFTextShape) shape;
+                        for (XSLFTextParagraph p : tsh) {
+                            System.out.println("Paragraph level: " + p.getIndentLevel());
+                            for (XSLFTextRun r : p) {
+                                System.out.println(r.getRawText());
+                                System.out.println("  bold: " + r.isBold());
+                                System.out.println("  italic: " + r.isItalic());
+                                System.out.println("  underline: " + r.isUnderlined());
+                                System.out.println("  font.family: " + r.getFontFamily());
+                                System.out.println("  font.size: " + r.getFontSize());
+                                System.out.println("  font.color: " + r.getFontColor());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xslf/tutorial/Step2.java b/src/examples/src/org/apache/poi/examples/xslf/tutorial/Step2.java
new file mode 100644 (file)
index 0000000..68fcf14
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  ====================================================================
+ *    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.examples.xslf.tutorial;
+
+import java.io.FileOutputStream;
+
+import org.apache.poi.xslf.usermodel.SlideLayout;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFSlideLayout;
+import org.apache.poi.xslf.usermodel.XSLFSlideMaster;
+import org.apache.poi.xslf.usermodel.XSLFTextShape;
+
+/**
+ * Create slides from pre-defined slide layouts
+ */
+public final class Step2 {
+    private Step2() {}
+
+    public static void main(String[] args) throws Exception{
+        try (XMLSlideShow ppt = new XMLSlideShow()) {
+
+            // first see what slide layouts are available by default
+            System.out.println("Available slide layouts:");
+            for (XSLFSlideMaster master : ppt.getSlideMasters()) {
+                for (XSLFSlideLayout layout : master.getSlideLayouts()) {
+                    System.out.println(layout.getType());
+                }
+            }
+
+            // blank slide
+        /*XSLFSlide blankSlide =*/
+            ppt.createSlide();
+
+            XSLFSlideMaster defaultMaster = ppt.getSlideMasters().get(0);
+
+            // title slide
+            XSLFSlideLayout titleLayout = defaultMaster.getLayout(SlideLayout.TITLE);
+            XSLFSlide slide1 = ppt.createSlide(titleLayout);
+            XSLFTextShape title1 = slide1.getPlaceholder(0);
+            title1.setText("First Title");
+
+            // title and content
+            XSLFSlideLayout titleBodyLayout = defaultMaster.getLayout(SlideLayout.TITLE_AND_CONTENT);
+            XSLFSlide slide2 = ppt.createSlide(titleBodyLayout);
+
+            XSLFTextShape title2 = slide2.getPlaceholder(0);
+            title2.setText("Second Title");
+
+            XSLFTextShape body2 = slide2.getPlaceholder(1);
+            body2.clearText(); // unset any existing text
+            body2.addNewTextParagraph().addNewTextRun().setText("First paragraph");
+            body2.addNewTextParagraph().addNewTextRun().setText("Second paragraph");
+            body2.addNewTextParagraph().addNewTextRun().setText("Third paragraph");
+
+
+            try (FileOutputStream out = new FileOutputStream("step2.pptx")) {
+                ppt.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/eventusermodel/FromHowTo.java b/src/examples/src/org/apache/poi/examples/xssf/eventusermodel/FromHowTo.java
new file mode 100644 (file)
index 0000000..4b376a9
--- /dev/null
@@ -0,0 +1,163 @@
+/* ====================================================================
+   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.examples.xssf.eventusermodel;
+
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackageAccess;
+import org.apache.poi.util.XMLHelper;
+import org.apache.poi.xssf.eventusermodel.XSSFReader;
+import org.apache.poi.xssf.model.SharedStringsTable;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * XSSF and SAX (Event API) basic example.
+ * See {@link XLSX2CSV} for a fuller example of doing
+ *  XSLX processing with the XSSF Event code.
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public class FromHowTo {
+    public void processFirstSheet(String filename) throws Exception {
+        try (OPCPackage pkg = OPCPackage.open(filename, PackageAccess.READ)) {
+            XSSFReader r = new XSSFReader(pkg);
+            SharedStringsTable sst = r.getSharedStringsTable();
+
+            XMLReader parser = fetchSheetParser(sst);
+
+            // process the first sheet
+            try (InputStream sheet = r.getSheetsData().next()) {
+                               InputSource sheetSource = new InputSource(sheet);
+                               parser.parse(sheetSource);
+                       }
+        }
+    }
+
+    public void processAllSheets(String filename) throws Exception {
+        try (OPCPackage pkg = OPCPackage.open(filename, PackageAccess.READ)) {
+            XSSFReader r = new XSSFReader(pkg);
+            SharedStringsTable sst = r.getSharedStringsTable();
+
+            XMLReader parser = fetchSheetParser(sst);
+
+            Iterator<InputStream> sheets = r.getSheetsData();
+            while (sheets.hasNext()) {
+                System.out.println("Processing new sheet:\n");
+                try (InputStream sheet = sheets.next()) {
+                                       InputSource sheetSource = new InputSource(sheet);
+                                       parser.parse(sheetSource);
+                               }
+                System.out.println();
+            }
+        }
+    }
+
+    public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException, ParserConfigurationException {
+        XMLReader parser = XMLHelper.newXMLReader();
+        ContentHandler handler = new SheetHandler(sst);
+        parser.setContentHandler(handler);
+        return parser;
+    }
+
+    /**
+     * See org.xml.sax.helpers.DefaultHandler javadocs
+     */
+    private static class SheetHandler extends DefaultHandler {
+        private final SharedStringsTable sst;
+        private String lastContents;
+        private boolean nextIsString;
+        private boolean inlineStr;
+        private final LruCache<Integer,String> lruCache = new LruCache<>(50);
+
+        private static class LruCache<A,B> extends LinkedHashMap<A, B> {
+            private final int maxEntries;
+
+            public LruCache(final int maxEntries) {
+                super(maxEntries + 1, 1.0f, true);
+                this.maxEntries = maxEntries;
+            }
+
+            @Override
+            protected boolean removeEldestEntry(final Map.Entry<A, B> eldest) {
+                return super.size() > maxEntries;
+            }
+        }
+
+        private SheetHandler(SharedStringsTable sst) {
+            this.sst = sst;
+        }
+
+        @Override
+        public void startElement(String uri, String localName, String name,
+                                 Attributes attributes) throws SAXException {
+            // c => cell
+            if(name.equals("c")) {
+                // Print the cell reference
+                System.out.print(attributes.getValue("r") + " - ");
+                // Figure out if the value is an index in the SST
+                String cellType = attributes.getValue("t");
+                nextIsString = cellType != null && cellType.equals("s");
+                inlineStr = cellType != null && cellType.equals("inlineStr");
+            }
+            // Clear contents cache
+            lastContents = "";
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String name)
+                throws SAXException {
+            // Process the last contents as required.
+            // Do now, as characters() may be called more than once
+            if(nextIsString) {
+                Integer idx = Integer.valueOf(lastContents);
+                lastContents = lruCache.get(idx);
+                if (lastContents == null && !lruCache.containsKey(idx)) {
+                    lastContents = sst.getItemAt(idx).getString();
+                    lruCache.put(idx, lastContents);
+                }
+                nextIsString = false;
+            }
+
+            // v => contents of a cell
+            // Output after we've seen the string contents
+            if(name.equals("v") || (inlineStr && name.equals("c"))) {
+                System.out.println(lastContents);
+            }
+        }
+
+        @Override
+        public void characters(char[] ch, int start, int length) throws SAXException { // NOSONAR
+            lastContents += new String(ch, start, length);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        FromHowTo howto = new FromHowTo();
+        howto.processFirstSheet(args[0]);
+        howto.processAllSheets(args[0]);
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/eventusermodel/LoadPasswordProtectedXlsxStreaming.java b/src/examples/src/org/apache/poi/examples/xssf/eventusermodel/LoadPasswordProtectedXlsxStreaming.java
new file mode 100644 (file)
index 0000000..96ba25e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *  ====================================================================
+ *    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.examples.xssf.eventusermodel;
+
+import java.io.InputStream;
+
+import org.apache.poi.examples.xssf.usermodel.LoadPasswordProtectedXlsx;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.poifs.crypt.temp.AesZipFileZipEntrySource;
+import org.apache.poi.xssf.eventusermodel.XSSFReader;
+import org.apache.poi.xssf.eventusermodel.XSSFReader.SheetIterator;
+
+/**
+ * An example that loads a password protected workbook and counts the sheets.
+ * The example highlights how to do this in streaming way.
+ * <p><ul>
+ * <li>The example demonstrates that all temp files are removed.
+ * <li><code>AesZipFileZipEntrySource</code> is used to ensure that temp files are encrypted.
+ * </ul><p>
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class LoadPasswordProtectedXlsxStreaming {
+
+    private LoadPasswordProtectedXlsxStreaming() {}
+
+    public static void main(String[] args) throws Exception {
+        LoadPasswordProtectedXlsx.execute(args, LoadPasswordProtectedXlsxStreaming::printSheetCount);
+    }
+
+    private static void printSheetCount(final InputStream inputStream) throws Exception {
+        try (AesZipFileZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(inputStream);
+             OPCPackage pkg = OPCPackage.open(source)) {
+            XSSFReader reader = new XSSFReader(pkg);
+            SheetIterator iter = (SheetIterator)reader.getSheetsData();
+            int count = 0;
+            while(iter.hasNext()) {
+                iter.next();
+                count++;
+            }
+            System.out.println("sheet count: " + count);
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/eventusermodel/XLSX2CSV.java b/src/examples/src/org/apache/poi/examples/xssf/eventusermodel/XLSX2CSV.java
new file mode 100644 (file)
index 0000000..1786538
--- /dev/null
@@ -0,0 +1,251 @@
+/* ====================================================================
+   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.examples.xssf.eventusermodel;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackageAccess;
+import org.apache.poi.ss.usermodel.DataFormatter;
+import org.apache.poi.ss.util.CellAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.util.XMLHelper;
+import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
+import org.apache.poi.xssf.eventusermodel.XSSFReader;
+import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
+import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
+import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor;
+import org.apache.poi.xssf.model.SharedStrings;
+import org.apache.poi.xssf.model.Styles;
+import org.apache.poi.xssf.model.StylesTable;
+import org.apache.poi.xssf.usermodel.XSSFComment;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+/**
+ * A rudimentary XLSX -> CSV processor modeled on the
+ * POI sample program XLS2CSVmra from the package
+ * org.apache.poi.hssf.eventusermodel.examples.
+ * As with the HSSF version, this tries to spot missing
+ *  rows and cells, and output empty entries for them.
+ * <p>
+ * Data sheets are read using a SAX parser to keep the
+ * memory footprint relatively small, so this should be
+ * able to read enormous workbooks.  The styles table and
+ * the shared-string table must be kept in memory.  The
+ * standard POI styles table class is used, but a custom
+ * (read-only) class is used for the shared string table
+ * because the standard POI SharedStringsTable grows very
+ * quickly with the number of unique strings.
+ * <p>
+ * For a more advanced implementation of SAX event parsing
+ * of XLSX files, see {@link XSSFEventBasedExcelExtractor}
+ * and {@link XSSFSheetXMLHandler}. Note that for many cases,
+ * it may be possible to simply use those with a custom
+ * {@link SheetContentsHandler} and no SAX code needed of
+ * your own!
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public class XLSX2CSV {
+    /**
+     * Uses the XSSF Event SAX helpers to do most of the work
+     *  of parsing the Sheet XML, and outputs the contents
+     *  as a (basic) CSV.
+     */
+    private class SheetToCSV implements SheetContentsHandler {
+        private boolean firstCellOfRow;
+        private int currentRow = -1;
+        private int currentCol = -1;
+
+        private void outputMissingRows(int number) {
+            for (int i=0; i<number; i++) {
+                for (int j=0; j<minColumns; j++) {
+                    output.append(',');
+                }
+                output.append('\n');
+            }
+        }
+
+        @Override
+        public void startRow(int rowNum) {
+            // If there were gaps, output the missing rows
+            outputMissingRows(rowNum-currentRow-1);
+            // Prepare for this row
+            firstCellOfRow = true;
+            currentRow = rowNum;
+            currentCol = -1;
+        }
+
+        @Override
+        public void endRow(int rowNum) {
+            // Ensure the minimum number of columns
+            for (int i=currentCol; i<minColumns; i++) {
+                output.append(',');
+            }
+            output.append('\n');
+        }
+
+        @Override
+        public void cell(String cellReference, String formattedValue,
+                XSSFComment comment) {
+            if (firstCellOfRow) {
+                firstCellOfRow = false;
+            } else {
+                output.append(',');
+            }
+
+            // gracefully handle missing CellRef here in a similar way as XSSFCell does
+            if(cellReference == null) {
+                cellReference = new CellAddress(currentRow, currentCol).formatAsString();
+            }
+
+            // Did we miss any cells?
+            int thisCol = (new CellReference(cellReference)).getCol();
+            int missedCols = thisCol - currentCol - 1;
+            for (int i=0; i<missedCols; i++) {
+                output.append(',');
+            }
+            currentCol = thisCol;
+
+            // Number or string?
+            try {
+                //noinspection ResultOfMethodCallIgnored
+                Double.parseDouble(formattedValue);
+                output.append(formattedValue);
+            } catch (NumberFormatException e) {
+                output.append('"');
+                output.append(formattedValue);
+                output.append('"');
+            }
+        }
+    }
+
+
+    ///////////////////////////////////////
+
+    private final OPCPackage xlsxPackage;
+
+    /**
+     * Number of columns to read starting with leftmost
+     */
+    private final int minColumns;
+
+    /**
+     * Destination for data
+     */
+    private final PrintStream output;
+
+    /**
+     * Creates a new XLSX -> CSV examples
+     *
+     * @param pkg        The XLSX package to process
+     * @param output     The PrintStream to output the CSV to
+     * @param minColumns The minimum number of columns to output, or -1 for no minimum
+     */
+    public XLSX2CSV(OPCPackage pkg, PrintStream output, int minColumns) {
+        this.xlsxPackage = pkg;
+        this.output = output;
+        this.minColumns = minColumns;
+    }
+
+    /**
+     * Parses and shows the content of one sheet
+     * using the specified styles and shared-strings tables.
+     *
+     * @param styles The table of styles that may be referenced by cells in the sheet
+     * @param strings The table of strings that may be referenced by cells in the sheet
+     * @param sheetInputStream The stream to read the sheet-data from.
+
+     * @exception java.io.IOException An IO exception from the parser,
+     *            possibly from a byte stream or character stream
+     *            supplied by the application.
+     * @throws SAXException if parsing the XML data fails.
+     */
+    public void processSheet(
+            Styles styles,
+            SharedStrings strings,
+            SheetContentsHandler sheetHandler,
+            InputStream sheetInputStream) throws IOException, SAXException {
+        DataFormatter formatter = new DataFormatter();
+        InputSource sheetSource = new InputSource(sheetInputStream);
+        try {
+            XMLReader sheetParser = XMLHelper.newXMLReader();
+            ContentHandler handler = new XSSFSheetXMLHandler(
+                  styles, null, strings, sheetHandler, formatter, false);
+            sheetParser.setContentHandler(handler);
+            sheetParser.parse(sheetSource);
+         } catch(ParserConfigurationException e) {
+            throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage());
+         }
+    }
+
+    /**
+     * Initiates the processing of the XLS workbook file to CSV.
+     *
+     * @throws IOException If reading the data from the package fails.
+     * @throws SAXException if parsing the XML data fails.
+     */
+    public void process() throws IOException, OpenXML4JException, SAXException {
+        ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(this.xlsxPackage);
+        XSSFReader xssfReader = new XSSFReader(this.xlsxPackage);
+        StylesTable styles = xssfReader.getStylesTable();
+        XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
+        int index = 0;
+        while (iter.hasNext()) {
+            try (InputStream stream = iter.next()) {
+                String sheetName = iter.getSheetName();
+                this.output.println();
+                this.output.println(sheetName + " [index=" + index + "]:");
+                processSheet(styles, strings, new SheetToCSV(), stream);
+            }
+            ++index;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        if (args.length < 1) {
+            System.err.println("Use:");
+            System.err.println("  XLSX2CSV <xlsx file> [min columns]");
+            return;
+        }
+
+        File xlsxFile = new File(args[0]);
+        if (!xlsxFile.exists()) {
+            System.err.println("Not found or not a file: " + xlsxFile.getPath());
+            return;
+        }
+
+        int minColumns = -1;
+        if (args.length >= 2)
+            minColumns = Integer.parseInt(args[1]);
+
+        // The package open is instantaneous, as it should be.
+        try (OPCPackage p = OPCPackage.open(xlsxFile.getPath(), PackageAccess.READ)) {
+            XLSX2CSV xlsx2csv = new XLSX2CSV(p, System.out, minColumns);
+            xlsx2csv.process();
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/streaming/HybridStreaming.java b/src/examples/src/org/apache/poi/examples/xssf/streaming/HybridStreaming.java
new file mode 100644 (file)
index 0000000..f131e5b
--- /dev/null
@@ -0,0 +1,78 @@
+/* ====================================================================
+   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.examples.xssf.streaming;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
+import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
+import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
+import org.apache.poi.xssf.usermodel.XSSFComment;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
+import org.xml.sax.SAXException;
+
+/**
+ * This demonstrates how a hybrid approach to workbook read can be taken, using
+ * a mix of traditional XSSF and streaming one particular worksheet (perhaps one
+ * which is too big for the ordinary DOM parse).
+ */
+public class HybridStreaming {
+
+    private static final String SHEET_TO_STREAM = "large sheet";
+
+    public static void main(String[] args) throws IOException, SAXException {
+        try (InputStream sourceBytes = new FileInputStream("workbook.xlsx")) {
+            XSSFWorkbook workbook = new XSSFWorkbook(sourceBytes) {
+                /**
+                 * Avoid DOM parse of large sheet
+                 */
+                @Override
+                public void parseSheet(java.util.Map<String, XSSFSheet> shIdMap, CTSheet ctSheet) {
+                    if (!SHEET_TO_STREAM.equals(ctSheet.getName())) {
+                        super.parseSheet(shIdMap, ctSheet);
+                    }
+                }
+            };
+
+            // Having avoided a DOM-based parse of the sheet, we can stream it instead.
+            ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(workbook.getPackage());
+            new XSSFSheetXMLHandler(workbook.getStylesSource(), strings, createSheetContentsHandler(), false);
+            workbook.close();
+        }
+    }
+
+    private static SheetContentsHandler createSheetContentsHandler() {
+        return new SheetContentsHandler() {
+
+            @Override
+            public void startRow(int rowNum) {
+            }
+
+            @Override
+            public void endRow(int rowNum) {
+            }
+
+            @Override
+            public void cell(String cellReference, String formattedValue, XSSFComment comment) {
+            }
+        };
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/streaming/Outlining.java b/src/examples/src/org/apache/poi/examples/xssf/streaming/Outlining.java
new file mode 100644 (file)
index 0000000..bd558e9
--- /dev/null
@@ -0,0 +1,54 @@
+/* ====================================================================
+   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.examples.xssf.streaming;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+
+public class Outlining {
+
+       public static void main(String[] args) throws IOException {
+               Outlining o = new Outlining();
+               o.collapseRow();
+       }
+
+       private void collapseRow() throws IOException {
+               try (SXSSFWorkbook wb2 = new SXSSFWorkbook(100)) {
+                       SXSSFSheet sheet2 = wb2.createSheet("new sheet");
+
+                       int rowCount = 20;
+                       for (int i = 0; i < rowCount; i++) {
+                               sheet2.createRow(i);
+                       }
+
+                       sheet2.groupRow(4, 9);
+                       sheet2.groupRow(11, 19);
+
+                       sheet2.setRowGroupCollapsed(4, true);
+
+                       try (FileOutputStream fileOut = new FileOutputStream("outlining_collapsed.xlsx")) {
+                               wb2.write(fileOut);
+                       } finally {
+                               wb2.dispose();
+                       }
+               }
+       }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/streaming/SavePasswordProtectedXlsx.java b/src/examples/src/org/apache/poi/examples/xssf/streaming/SavePasswordProtectedXlsx.java
new file mode 100644 (file)
index 0000000..f991047
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *  ====================================================================
+ *    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.examples.xssf.streaming;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+
+import org.apache.poi.examples.util.TempFileUtils;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.EncryptionMode;
+import org.apache.poi.poifs.crypt.Encryptor;
+import org.apache.poi.poifs.crypt.temp.EncryptedTempData;
+import org.apache.poi.poifs.crypt.temp.SXSSFWorkbookWithCustomZipEntrySource;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.streaming.SXSSFCell;
+import org.apache.poi.xssf.streaming.SXSSFRow;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+
+/**
+ * An example that outputs a simple generated workbook that is password protected.
+ * The example highlights how to do this in streaming way.
+ * <p><ul>
+ * <li>The example demonstrates that all temp files are removed.
+ * <li><code>SXSSFWorkbookWithCustomZipEntrySource</code> extends SXSSFWorkbook to ensure temp files are encrypted.
+ * </ul><p>
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class SavePasswordProtectedXlsx {
+
+    private SavePasswordProtectedXlsx() {}
+
+    public static void main(String[] args) throws Exception {
+        if(args.length != 2) {
+            throw new IllegalArgumentException("Expected 2 params: filename and password");
+        }
+        TempFileUtils.checkTempFiles();
+        String filename = args[0];
+        String password = args[1];
+        SXSSFWorkbookWithCustomZipEntrySource wb = new SXSSFWorkbookWithCustomZipEntrySource();
+        try {
+            for(int i = 0; i < 10; i++) {
+                SXSSFSheet sheet = wb.createSheet("Sheet" + i);
+                for(int r = 0; r < 1000; r++) {
+                    SXSSFRow row = sheet.createRow(r);
+                    for(int c = 0; c < 100; c++) {
+                        SXSSFCell cell = row.createCell(c);
+                        cell.setCellValue("abcd");
+                    }
+                }
+            }
+            EncryptedTempData tempData = new EncryptedTempData();
+            try {
+                wb.write(tempData.getOutputStream());
+                save(tempData.getInputStream(), filename, password);
+                System.out.println("Saved " + filename);
+            } finally {
+                tempData.dispose();
+            }
+        } finally {
+            wb.close();
+            wb.dispose();
+        }
+        TempFileUtils.checkTempFiles();
+    }
+
+    public static void save(final InputStream inputStream, final String filename, final String pwd)
+            throws InvalidFormatException, IOException, GeneralSecurityException {
+
+        try (POIFSFileSystem fs = new POIFSFileSystem();
+             OPCPackage opc = OPCPackage.open(inputStream);
+             FileOutputStream fos = new FileOutputStream(filename)) {
+            EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
+            Encryptor enc = Encryptor.getInstance(info);
+            enc.confirmPassword(pwd);
+            opc.save(enc.getDataStream(fs));
+            fs.writeFilesystem(fos);
+        } finally {
+            IOUtils.closeQuietly(inputStream);
+        }
+    }
+
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/AligningCells.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/AligningCells.java
new file mode 100644 (file)
index 0000000..17a92d3
--- /dev/null
@@ -0,0 +1,139 @@
+/* ====================================================================
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTRowImpl;
+
+/**
+ * Shows how various alignment options work.
+ *
+ * Modified by Cristian Petrula, Romania on May 26, 2010
+ * New method was added centerAcrossSelection to center a column content over
+ * one selection using {@link HorizontalAlignment#CENTER_SELECTION}
+ * To create this method example was change for XSSF only and the previous
+ * AligningCells.java example has been moved into the SS examples folder.
+ */
+public class AligningCells {
+
+    public static void main(String[] args) throws IOException {
+        try (XSSFWorkbook wb = new XSSFWorkbook()) {
+
+            XSSFSheet sheet = wb.createSheet();
+            XSSFRow row = sheet.createRow(2);
+            row.setHeightInPoints(30);
+            for (int i = 0; i < 8; i++) {
+                //column width is set in units of 1/256th of a character width
+                sheet.setColumnWidth(i, 256 * 15);
+            }
+
+            createCell(wb, row, 0, HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
+            createCell(wb, row, 1, HorizontalAlignment.CENTER_SELECTION, VerticalAlignment.BOTTOM);
+            createCell(wb, row, 2, HorizontalAlignment.FILL, VerticalAlignment.CENTER);
+            createCell(wb, row, 3, HorizontalAlignment.GENERAL, VerticalAlignment.CENTER);
+            createCell(wb, row, 4, HorizontalAlignment.JUSTIFY, VerticalAlignment.JUSTIFY);
+            createCell(wb, row, 5, HorizontalAlignment.LEFT, VerticalAlignment.TOP);
+            createCell(wb, row, 6, HorizontalAlignment.RIGHT, VerticalAlignment.TOP);
+
+            //center text over B4, C4, D4
+            row = sheet.createRow(3);
+            centerAcrossSelection(wb, row, 1, 3, VerticalAlignment.CENTER);
+
+            // Write the output to a file
+            try (OutputStream fileOut = new FileOutputStream("xssf-align.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+
+    /**
+     * Creates a cell and aligns it a certain way.
+     *
+     * @param wb     the workbook
+     * @param row    the row to create the cell in
+     * @param column the column number to create the cell in
+     * @param halign the horizontal alignment for the cell.
+     */
+    private static void createCell(XSSFWorkbook wb, XSSFRow row, int column,
+                                   HorizontalAlignment halign, VerticalAlignment valign) {
+        CreationHelper ch = wb.getCreationHelper();
+        XSSFCell cell = row.createCell(column);
+        cell.setCellValue(ch.createRichTextString("Align It"));
+        CellStyle cellStyle = wb.createCellStyle();
+        cellStyle.setAlignment(halign);
+        cellStyle.setVerticalAlignment(valign);
+        cell.setCellStyle(cellStyle);
+    }
+
+    /**
+     * Center a text over multiple columns using ALIGN_CENTER_SELECTION
+     *
+     * @param wb the workbook
+     * @param row the row to create the cell in
+     * @param start_column  the column number to create the cell in and where the selection starts
+     * @param end_column    the column number where the selection ends
+     * @param valign the horizontal alignment for the cell.
+     */
+    private static void centerAcrossSelection(XSSFWorkbook wb, XSSFRow row,
+            int start_column, int end_column, VerticalAlignment valign) {
+        CreationHelper ch = wb.getCreationHelper();
+
+        // Create cell style with ALIGN_CENTER_SELECTION
+        XSSFCellStyle cellStyle = wb.createCellStyle();
+        cellStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);
+        cellStyle.setVerticalAlignment(valign);
+
+        // Create cells over the selected area
+        for (int i = start_column; i <= end_column; i++) {
+            XSSFCell cell = row.createCell(i);
+            cell.setCellStyle(cellStyle);
+        }
+
+        // Set value to the first cell
+        XSSFCell cell = row.getCell(start_column);
+        cell.setCellValue(ch.createRichTextString("Align It"));
+
+        // Make the selection
+        CTRowImpl ctRow = (CTRowImpl) row.getCTRow();
+
+        // Add object with format start_coll:end_coll. For example 1:3 will span from
+        // cell 1 to cell 3, where the column index starts with 0
+        //
+        // You can add multiple spans for one row
+        Object span = start_column + ":" + end_column;
+
+        List<Object> spanList = new ArrayList<>();
+        spanList.add(span);
+
+        //add spns to the row
+        ctRow.setSpans(spanList);
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/BarAndLineChart.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/BarAndLineChart.java
new file mode 100644 (file)
index 0000000..e5cf054
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ *  ====================================================================
+ *    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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.util.Random;
+
+import org.apache.poi.common.usermodel.fonts.FontGroup;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xddf.usermodel.PresetColor;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFFillProperties;
+import org.apache.poi.xddf.usermodel.XDDFLineProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LayoutMode;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.MarkerStyle;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFCategoryDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFLineChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFManualLayout;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xddf.usermodel.text.UnderlineType;
+import org.apache.poi.xddf.usermodel.text.XDDFFont;
+import org.apache.poi.xddf.usermodel.text.XDDFRunProperties;
+import org.apache.poi.xddf.usermodel.text.XDDFTextParagraph;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFChart;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+// original contributions by Axel Richter on https://stackoverflow.com/questions/47065690
+// additional title formatting from https://stackoverflow.com/questions/50418856
+// and legend positioning from https://stackoverflow.com/questions/49615379
+// this would probably be an answer for https://stackoverflow.com/questions/36447925 too
+public final class BarAndLineChart {
+
+    private static final int NUM_OF_ROWS = 7;
+    private static final Random RNG = new Random();
+
+    private BarAndLineChart() {}
+
+    public static void main(String[] args) throws Exception {
+        try (XSSFWorkbook wb = new XSSFWorkbook()) {
+            XSSFSheet sheet = wb.createSheet("Sheet1");
+
+            XSSFRow row = sheet.createRow(0);
+            row.createCell(0);
+            row.createCell(1).setCellValue("Bars");
+            row.createCell(2).setCellValue("Lines");
+
+            XSSFCell cell;
+            for (int r = 1; r < NUM_OF_ROWS; r++) {
+                row = sheet.createRow(r);
+                cell = row.createCell(0);
+                cell.setCellValue("C" + r);
+                cell = row.createCell(1);
+                cell.setCellValue(RNG.nextDouble());
+                cell = row.createCell(2);
+                cell.setCellValue(RNG.nextDouble() * 10);
+            }
+
+            XSSFDrawing drawing = sheet.createDrawingPatriarch();
+            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 4, 0, 11, 15);
+
+            XSSFChart chart = drawing.createChart(anchor);
+            chart.setTitleText("This is my title");
+            chart.setTitleOverlay(true);
+            XDDFRunProperties properties = new XDDFRunProperties();
+            properties.setBold(true);
+            properties.setItalic(true);
+            properties.setUnderline(UnderlineType.DOT_DOT_DASH_HEAVY);
+            properties.setFontSize(22.5);
+            XDDFFont[] fonts = new XDDFFont[] {
+                    new XDDFFont(FontGroup.LATIN, "Calibri", null, null, null),
+                    new XDDFFont(FontGroup.COMPLEX_SCRIPT, "Liberation Sans", null, null, null)
+                    };
+            properties.setFonts(fonts);
+            properties.setLineProperties(new XDDFLineProperties(
+                    new XDDFSolidFillProperties(XDDFColor.from(PresetColor.SIENNA))));
+            XDDFTextParagraph paragraph = chart.getTitle().getBody().getParagraph(0);
+            paragraph.setDefaultRunProperties(properties);
+
+            // the data sources
+            XDDFCategoryDataSource xs = XDDFDataSourcesFactory.fromStringCellRange(sheet,
+                    new CellRangeAddress(1, NUM_OF_ROWS - 1, 0, 0));
+            XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
+                    new CellRangeAddress(1, NUM_OF_ROWS - 1, 1, 1));
+            XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
+                    new CellRangeAddress(1, NUM_OF_ROWS - 1, 2, 2));
+
+            // cat axis 1 (bars)
+            XDDFCategoryAxis barCategories = chart.createCategoryAxis(AxisPosition.BOTTOM);
+
+            // val axis 1 (left)
+            XDDFValueAxis leftValues = chart.createValueAxis(AxisPosition.LEFT);
+            leftValues.crossAxis(barCategories);
+            barCategories.crossAxis(leftValues);
+
+            // cat axis 2 (lines)
+            XDDFCategoryAxis lineCategories = chart.createCategoryAxis(AxisPosition.BOTTOM);
+            lineCategories.setVisible(false); // this cat axis is deleted
+
+            // val axis 2 (right)
+            XDDFValueAxis rightValues = chart.createValueAxis(AxisPosition.RIGHT);
+            // this value axis crosses its category axis at max value
+            rightValues.setCrosses(AxisCrosses.MAX);
+            rightValues.crossAxis(lineCategories);
+            lineCategories.crossAxis(rightValues);
+
+            // the bar chart
+            XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, barCategories, leftValues);
+            XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(xs, ys1);
+            series1.setTitle(null, new CellReference(sheet.getSheetName(), 0, 1, true,true));
+            bar.setVaryColors(true);
+            bar.setBarDirection(BarDirection.COL);
+            chart.plot(bar);
+
+            // the line chart on secondary axis
+            XDDFLineChartData lines = (XDDFLineChartData) chart.createData(ChartTypes.LINE, lineCategories,
+                    rightValues);
+
+            //uncomment below line if only primary axis required and comment above line
+            // the line chart on primary axis
+            /*XDDFLineChartData lines = (XDDFLineChartData) chart.createData(ChartTypes.LINE, lineCategories,
+                    leftValues);*/
+
+
+            XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) lines.addSeries(xs, ys2);
+            series2.setTitle(null, new CellReference(sheet.getSheetName(), 0, 2, true, true));
+            series2.setSmooth(false);
+            series2.setMarkerStyle(MarkerStyle.DIAMOND);
+            series2.setMarkerSize((short)14);
+            lines.setVaryColors(true);
+            chart.plot(lines);
+
+            // some colors
+            XDDFFillProperties solidChartreuse = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.CHARTREUSE));
+            XDDFFillProperties solidTurquoise = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.TURQUOISE));
+            XDDFLineProperties solidLines = new XDDFLineProperties(solidTurquoise);
+            series1.setFillProperties(solidChartreuse);
+            series1.setLineProperties(solidLines); // bar border color different from fill
+            series2.setLineProperties(solidLines);
+
+            // legend
+            XDDFChartLegend legend = chart.getOrAddLegend();
+            legend.setPosition(LegendPosition.LEFT);
+            legend.setOverlay(false);
+            XDDFManualLayout layout = legend.getOrAddManualLayout();
+            layout.setXMode(LayoutMode.EDGE);
+            layout.setYMode(LayoutMode.EDGE);
+            layout.setX(0.00); //left edge of the chart
+            layout.setY(0.25); //25% of chart's height from top edge of the chart
+
+            try (FileOutputStream fileOut = new FileOutputStream("BarAndLineChart.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/BarChart.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/BarChart.java
new file mode 100644 (file)
index 0000000..2a3c6a7
--- /dev/null
@@ -0,0 +1,124 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.PresetColor;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xssf.usermodel.XSSFChart;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Line chart example.
+ */
+public final class BarChart {
+    private BarChart() {}
+
+    public static void main(String[] args) throws IOException {
+        try (XSSFWorkbook wb = new XSSFWorkbook()) {
+            XSSFSheet sheet = wb.createSheet("barchart");
+            final int NUM_OF_ROWS = 3;
+            final int NUM_OF_COLUMNS = 10;
+
+            // Create a row and put some cells in it. Rows are 0 based.
+            Row row;
+            Cell cell;
+            for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) {
+                row = sheet.createRow((short) rowIndex);
+                for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
+                    cell = row.createCell((short) colIndex);
+                    cell.setCellValue(colIndex * (rowIndex + 1.0));
+                }
+            }
+
+            XSSFDrawing drawing = sheet.createDrawingPatriarch();
+            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);
+
+            XSSFChart chart = drawing.createChart(anchor);
+            chart.setTitleText("x = 2x and x = 3x");
+            chart.setTitleOverlay(false);
+            XDDFChartLegend legend = chart.getOrAddLegend();
+            legend.setPosition(LegendPosition.TOP_RIGHT);
+
+            // Use a category axis for the bottom axis.
+            XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
+            bottomAxis.setTitle("x"); // https://stackoverflow.com/questions/32010765
+            XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+            leftAxis.setTitle("f(x)");
+            leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
+
+            XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
+            XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1));
+            XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1));
+
+            XDDFChartData data = chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
+            XDDFChartData.Series series1 = data.addSeries(xs, ys1);
+            series1.setTitle("2x", null); // https://stackoverflow.com/questions/21855842
+            XDDFChartData.Series series2 = data.addSeries(xs, ys2);
+            series2.setTitle("3x", null);
+            chart.plot(data);
+
+            // in order to transform a bar chart into a column chart, you just need to change the bar direction
+            XDDFBarChartData bar = (XDDFBarChartData) data;
+            bar.setBarDirection(BarDirection.COL);
+            // looking for "Stacked Bar Chart"? uncomment the following line
+            // bar.setBarGrouping(BarGrouping.STACKED);
+
+            solidFillSeries(data, 0, PresetColor.CHARTREUSE);
+            solidFillSeries(data, 1, PresetColor.TURQUOISE);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("ooxml-bar-chart.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+
+    private static void solidFillSeries(XDDFChartData data, int index, PresetColor color) {
+        XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
+        XDDFChartData.Series series = data.getSeries().get(index);
+        XDDFShapeProperties properties = series.getShapeProperties();
+        if (properties == null) {
+            properties = new XDDFShapeProperties();
+        }
+        properties.setFillProperties(fill);
+        series.setShapeProperties(properties);
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/BigGridDemo.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/BigGridDemo.java
new file mode 100644 (file)
index 0000000..2afc73a
--- /dev/null
@@ -0,0 +1,303 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Calendar;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.poi.openxml4j.opc.internal.ZipHelper;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFDataFormat;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates a workaround you can use to generate large workbooks and avoid OutOfMemory exception.
+ *
+ * Note - You probably <em>don't want to use this approach any more</em>! POI
+ *  now includes the SXSSF which handles all of this for you, you should
+ *  be using that instead! This code remains mostly for historical interest.
+ * <p>
+ * See <a "https://poi.apache.org/spreadsheet/how-to.html#sxssf">
+ *     https://poi.apache.org/spreadsheet/how-to.html#sxssf</a>.
+ * <p>
+ * If you really want to use this approach, which is also the one that SXSSF
+ * does for you, it works as follows:
+ *
+ * 1. create a template workbook, create sheets and global objects such as cell styles, number formats, etc.
+ * 2. create an application that streams data in a text file
+ * 3. Substitute the sheet in the template with the generated data
+ *
+ * <p>
+ *  Since 3.8 POI provides a low-memory footprint SXSSF API, which implements
+ *  ths "BigGridDemo" strategy. SXSSF is an API-compatible streaming extension
+ *  of XSSF to be used when very large spreadsheets have to be produced, and
+ *  heap space is limited. SXSSF achieves its low memory footprint by limiting
+ *  access to the rows that are within a sliding window, while XSSF gives access
+ *  to all rows in the document. Older rows that are no longer in the window
+ *  become inaccessible, as they are written to the disk.
+ * </p>
+ * See <a "https://poi.apache.org/spreadsheet/how-to.html#sxssf">
+ *     https://poi.apache.org/spreadsheet/how-to.html#sxssf</a>.
+ */
+public final class BigGridDemo {
+    private static final String XML_ENCODING = "UTF-8";
+
+    private static final Random rnd = new Random();
+
+    private BigGridDemo() {}
+
+    public static void main(String[] args) throws Exception {
+
+        // Step 1. Create a template file. Setup sheets and workbook-level objects such as
+        // cell styles, number formats, etc.
+
+        try (XSSFWorkbook wb = new XSSFWorkbook()) {
+            XSSFSheet sheet = wb.createSheet("Big Grid");
+
+            Map<String, XSSFCellStyle> styles = createStyles(wb);
+            //name of the zip entry holding sheet data, e.g. /xl/worksheets/sheet1.xml
+            String sheetRef = sheet.getPackagePart().getPartName().getName();
+
+            //save the template
+            try (FileOutputStream os = new FileOutputStream("template.xlsx")) {
+                wb.write(os);
+            }
+
+            //Step 2. Generate XML file.
+            File tmp = File.createTempFile("sheet", ".xml");
+            try (
+                    FileOutputStream stream = new FileOutputStream(tmp);
+                    Writer fw = new OutputStreamWriter(stream, XML_ENCODING)
+                ) {
+                generate(fw, styles);
+            }
+
+            //Step 3. Substitute the template entry with the generated data
+            try (FileOutputStream out = new FileOutputStream("big-grid.xlsx")) {
+                substitute(new File("template.xlsx"), tmp, sheetRef.substring(1), out);
+            }
+        }
+    }
+
+    /**
+     * Create a library of cell styles.
+     */
+    private static Map<String, XSSFCellStyle> createStyles(XSSFWorkbook wb){
+        Map<String, XSSFCellStyle> styles = new HashMap<>();
+        XSSFDataFormat fmt = wb.createDataFormat();
+
+        XSSFCellStyle style1 = wb.createCellStyle();
+        style1.setAlignment(HorizontalAlignment.RIGHT);
+        style1.setDataFormat(fmt.getFormat("0.0%"));
+        styles.put("percent", style1);
+
+        XSSFCellStyle style2 = wb.createCellStyle();
+        style2.setAlignment(HorizontalAlignment.CENTER);
+        style2.setDataFormat(fmt.getFormat("0.0X"));
+        styles.put("coeff", style2);
+
+        XSSFCellStyle style3 = wb.createCellStyle();
+        style3.setAlignment(HorizontalAlignment.RIGHT);
+        style3.setDataFormat(fmt.getFormat("$#,##0.00"));
+        styles.put("currency", style3);
+
+        XSSFCellStyle style4 = wb.createCellStyle();
+        style4.setAlignment(HorizontalAlignment.RIGHT);
+        style4.setDataFormat(fmt.getFormat("mmm dd"));
+        styles.put("date", style4);
+
+        XSSFCellStyle style5 = wb.createCellStyle();
+        XSSFFont headerFont = wb.createFont();
+        headerFont.setBold(true);
+        style5.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+        style5.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style5.setFont(headerFont);
+        styles.put("header", style5);
+
+        return styles;
+    }
+
+    private static void generate(Writer out, Map<String, XSSFCellStyle> styles) throws Exception {
+
+        Calendar calendar = Calendar.getInstance();
+
+        SpreadsheetWriter sw = new SpreadsheetWriter(out);
+        sw.beginSheet();
+
+        //insert header row
+        sw.insertRow(0);
+        int styleIndex = styles.get("header").getIndex();
+        sw.createCell(0, "Title", styleIndex);
+        sw.createCell(1, "% Change", styleIndex);
+        sw.createCell(2, "Ratio", styleIndex);
+        sw.createCell(3, "Expenses", styleIndex);
+        sw.createCell(4, "Date", styleIndex);
+
+        sw.endRow();
+
+        //write data rows
+        for (int rownum = 1; rownum < 100000; rownum++) {
+            sw.insertRow(rownum);
+
+            sw.createCell(0, "Hello, " + rownum + "!");
+            sw.createCell(1, (double)rnd.nextInt(100)/100, styles.get("percent").getIndex());
+            sw.createCell(2, (double)rnd.nextInt(10)/10, styles.get("coeff").getIndex());
+            sw.createCell(3, rnd.nextInt(10000), styles.get("currency").getIndex());
+            sw.createCell(4, calendar, styles.get("date").getIndex());
+
+            sw.endRow();
+
+            calendar.roll(Calendar.DAY_OF_YEAR, 1);
+        }
+        sw.endSheet();
+    }
+
+    /**
+     *
+     * @param zipfile the template file
+     * @param tmpfile the XML file with the sheet data
+     * @param entry the name of the sheet entry to substitute, e.g. xl/worksheets/sheet1.xml
+     * @param out the stream to write the result to
+     */
+    private static void substitute(File zipfile, File tmpfile, String entry, OutputStream out) throws IOException {
+        try (ZipFile zip = ZipHelper.openZipFile(zipfile)) {
+            try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(out)) {
+                Enumeration<? extends ZipArchiveEntry> en = zip.getEntries();
+                while (en.hasMoreElements()) {
+                    ZipArchiveEntry ze = en.nextElement();
+                    if (!ze.getName().equals(entry)) {
+                        zos.putArchiveEntry(new ZipArchiveEntry(ze.getName()));
+                        try (InputStream is = zip.getInputStream(ze)) {
+                            copyStream(is, zos);
+                        }
+                        zos.closeArchiveEntry();
+                    }
+                }
+                zos.putArchiveEntry(new ZipArchiveEntry(entry));
+                try (InputStream is = new FileInputStream(tmpfile)) {
+                    copyStream(is, zos);
+                }
+                zos.closeArchiveEntry();
+            }
+        }
+    }
+
+    private static void copyStream(InputStream in, OutputStream out) throws IOException {
+        byte[] chunk = new byte[1024];
+        int count;
+        while ((count = in.read(chunk)) >=0 ) {
+          out.write(chunk,0,count);
+        }
+    }
+
+    /**
+     * Writes spreadsheet data in a Writer.
+     * (YK: in future it may evolve in a full-featured API for streaming data in Excel)
+     */
+    public static class SpreadsheetWriter {
+        private final Writer _out;
+        private int _rownum;
+
+        SpreadsheetWriter(Writer out){
+            _out = out;
+        }
+
+        void beginSheet() throws IOException {
+            _out.write("<?xml version=\"1.0\" encoding=\""+XML_ENCODING+"\"?>" +
+                    "<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">" );
+            _out.write("<sheetData>\n");
+        }
+
+        void endSheet() throws IOException {
+            _out.write("</sheetData>");
+            _out.write("</worksheet>");
+        }
+
+        /**
+         * Insert a new row
+         *
+         * @param rownum 0-based row number
+         */
+        void insertRow(int rownum) throws IOException {
+            _out.write("<row r=\""+(rownum+1)+"\">\n");
+            this._rownum = rownum;
+        }
+
+        /**
+         * Insert row end marker
+         */
+        void endRow() throws IOException {
+            _out.write("</row>\n");
+        }
+
+        public void createCell(int columnIndex, String value, int styleIndex) throws IOException {
+            String ref = new CellReference(_rownum, columnIndex).formatAsString();
+            _out.write("<c r=\""+ref+"\" t=\"inlineStr\"");
+            if(styleIndex != -1) {
+                _out.write(" s=\""+styleIndex+"\"");
+            }
+            _out.write(">");
+            _out.write("<is><t>"+value+"</t></is>");
+            _out.write("</c>");
+        }
+
+        public void createCell(int columnIndex, String value) throws IOException {
+            createCell(columnIndex, value, -1);
+        }
+
+        public void createCell(int columnIndex, double value, int styleIndex) throws IOException {
+            String ref = new CellReference(_rownum, columnIndex).formatAsString();
+            _out.write("<c r=\""+ref+"\" t=\"n\"");
+            if(styleIndex != -1) {
+                _out.write(" s=\""+styleIndex+"\"");
+            }
+            _out.write(">");
+            _out.write("<v>"+value+"</v>");
+            _out.write("</c>");
+        }
+
+        public void createCell(int columnIndex, double value) throws IOException {
+            createCell(columnIndex, value, -1);
+        }
+
+        public void createCell(int columnIndex, Calendar value, int styleIndex) throws IOException {
+            createCell(columnIndex, DateUtil.getExcelDate(value, false), styleIndex);
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/CalendarDemo.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/CalendarDemo.java
new file mode 100644 (file)
index 0000000..b97ef1a
--- /dev/null
@@ -0,0 +1,241 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.PrintOrientation;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+import org.apache.poi.xssf.usermodel.XSSFPrintSetup;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * A  monthly calendar created using Apache POI. Each month is on a separate sheet.
+ * This is a version of org.apache.poi.ss.examples.CalendarDemo that demonstrates
+ * some XSSF features not avaiable when using common HSSF-XSSF interfaces.
+ *
+ * <pre>
+ * Usage:
+ * CalendarDemo <year>
+ * </pre>
+ *
+ * @author Yegor Kozlov
+ */
+public class CalendarDemo {
+
+    private static final String[] days = {
+            "Sunday", "Monday", "Tuesday",
+            "Wednesday", "Thursday", "Friday", "Saturday"};
+
+    private static final String[]  months = {
+            "January", "February", "March","April", "May", "June","July", "August",
+            "September","October", "November", "December"};
+
+    public static void main(String[] args) throws Exception {
+
+        Calendar calendar = Calendar.getInstance();
+        if(args.length > 0) calendar.set(Calendar.YEAR, Integer.parseInt(args[0]));
+
+        int year = calendar.get(Calendar.YEAR);
+
+        try (XSSFWorkbook wb = new XSSFWorkbook()) {
+            Map<String, XSSFCellStyle> styles = createStyles(wb);
+
+            for (int month = 0; month < 12; month++) {
+                calendar.set(Calendar.MONTH, month);
+                calendar.set(Calendar.DAY_OF_MONTH, 1);
+                //create a sheet for each month
+                XSSFSheet sheet = wb.createSheet(months[month]);
+
+                //turn off gridlines
+                sheet.setDisplayGridlines(false);
+                sheet.setPrintGridlines(false);
+                XSSFPrintSetup printSetup = sheet.getPrintSetup();
+                printSetup.setOrientation(PrintOrientation.LANDSCAPE);
+                sheet.setFitToPage(true);
+                sheet.setHorizontallyCenter(true);
+
+                //the header row: centered text in 48pt font
+                XSSFRow headerRow = sheet.createRow(0);
+                headerRow.setHeightInPoints(80);
+                XSSFCell titleCell = headerRow.createCell(0);
+                titleCell.setCellValue(months[month] + " " + year);
+                titleCell.setCellStyle(styles.get("title"));
+                sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$N$1"));
+
+                //header with month titles
+                XSSFRow monthRow = sheet.createRow(1);
+                for (int i = 0; i < days.length; i++) {
+                    //for compatibility with HSSF we have to set column width in units of 1/256th of a character width
+                    sheet.setColumnWidth(i * 2, 5 * 256); //the column is 5 characters wide
+                    sheet.setColumnWidth(i * 2 + 1, 13 * 256); //the column is 13 characters wide
+                    sheet.addMergedRegion(new CellRangeAddress(1, 1, i * 2, i * 2 + 1));
+                    XSSFCell monthCell = monthRow.createCell(i * 2);
+                    monthCell.setCellValue(days[i]);
+                    monthCell.setCellStyle(styles.get("month"));
+                }
+
+                int cnt = 1, day = 1;
+                int rownum = 2;
+                for (int j = 0; j < 6; j++) {
+                    XSSFRow row = sheet.createRow(rownum++);
+                    row.setHeightInPoints(100);
+                    for (int i = 0; i < days.length; i++) {
+                        XSSFCell dayCell_1 = row.createCell(i * 2);
+                        XSSFCell dayCell_2 = row.createCell(i * 2 + 1);
+
+                        int day_of_week = calendar.get(Calendar.DAY_OF_WEEK);
+                        if (cnt >= day_of_week && calendar.get(Calendar.MONTH) == month) {
+                            dayCell_1.setCellValue(day);
+                            calendar.set(Calendar.DAY_OF_MONTH, ++day);
+
+                            if (i == 0 || i == days.length - 1) {
+                                dayCell_1.setCellStyle(styles.get("weekend_left"));
+                                dayCell_2.setCellStyle(styles.get("weekend_right"));
+                            } else {
+                                dayCell_1.setCellStyle(styles.get("workday_left"));
+                                dayCell_2.setCellStyle(styles.get("workday_right"));
+                            }
+                        } else {
+                            dayCell_1.setCellStyle(styles.get("grey_left"));
+                            dayCell_2.setCellStyle(styles.get("grey_right"));
+                        }
+                        cnt++;
+                    }
+                    if (calendar.get(Calendar.MONTH) > month) break;
+                }
+            }
+
+            // Write the output to a file
+            try (FileOutputStream out = new FileOutputStream("calendar-" + year + ".xlsx")) {
+                wb.write(out);
+            }
+
+        }
+    }
+
+    /**
+     * cell styles used for formatting calendar sheets
+     */
+    private static Map<String, XSSFCellStyle> createStyles(XSSFWorkbook wb){
+        Map<String, XSSFCellStyle> styles = new HashMap<>();
+
+        XSSFCellStyle style;
+        XSSFFont titleFont = wb.createFont();
+        titleFont.setFontHeightInPoints((short)48);
+        titleFont.setColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setFont(titleFont);
+        styles.put("title", style);
+
+        XSSFFont monthFont = wb.createFont();
+        monthFont.setFontHeightInPoints((short)12);
+        monthFont.setColor(new XSSFColor(new java.awt.Color(255, 255, 255), wb.getStylesSource().getIndexedColors()));
+        monthFont.setBold(true);
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setFont(monthFont);
+        styles.put("month", style);
+
+        XSSFFont dayFont = wb.createFont();
+        dayFont.setFontHeightInPoints((short)14);
+        dayFont.setBold(true);
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.LEFT);
+        style.setVerticalAlignment(VerticalAlignment.TOP);
+        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(228, 232, 243), wb.getStylesSource().getIndexedColors()));
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setLeftBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        style.setFont(dayFont);
+        styles.put("weekend_left", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.TOP);
+        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(228, 232, 243), wb.getStylesSource().getIndexedColors()));
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setRightBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        styles.put("weekend_right", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.LEFT);
+        style.setVerticalAlignment(VerticalAlignment.TOP);
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(255, 255, 255), wb.getStylesSource().getIndexedColors()));
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setLeftBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        style.setFont(dayFont);
+        styles.put("workday_left", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.TOP);
+        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(255, 255, 255), wb.getStylesSource().getIndexedColors()));
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setRightBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        styles.put("workday_right", style);
+
+        style = wb.createCellStyle();
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(234, 234, 234), wb.getStylesSource().getIndexedColors()));
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        styles.put("grey_left", style);
+
+        style = wb.createCellStyle();
+        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(234, 234, 234), wb.getStylesSource().getIndexedColors()));
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setRightBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+        styles.put("grey_right", style);
+
+        return styles;
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/CellComments.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/CellComments.java
new file mode 100644 (file)
index 0000000..eb57577
--- /dev/null
@@ -0,0 +1,88 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.Comment;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.RichTextString;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates how to work with excel cell comments.
+ *
+ * <p>
+ * Excel comment is a kind of a text shape,
+ * so inserting a comment is very similar to placing a text box in a worksheet
+ * </p>
+ *
+ * @author Yegor Kozlov
+ */
+public class CellComments {
+    public static void main(String[] args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {
+
+            CreationHelper factory = wb.getCreationHelper();
+
+            Sheet sheet = wb.createSheet();
+
+            Cell cell1 = sheet.createRow(3).createCell(5);
+            cell1.setCellValue("F4");
+
+            Drawing<?> drawing = sheet.createDrawingPatriarch();
+
+            ClientAnchor anchor = factory.createClientAnchor();
+
+            Comment comment1 = drawing.createCellComment(anchor);
+            RichTextString str1 = factory.createRichTextString("Hello, World!");
+            comment1.setString(str1);
+            comment1.setAuthor("Apache POI");
+            cell1.setCellComment(comment1);
+
+            Cell cell2 = sheet.createRow(2).createCell(2);
+            cell2.setCellValue("C3");
+
+            Comment comment2 = drawing.createCellComment(anchor);
+            RichTextString str2 = factory.createRichTextString("XSSF can set cell comments");
+            //apply custom font to the text in the comment
+            Font font = wb.createFont();
+            font.setFontName("Arial");
+            font.setFontHeightInPoints((short) 14);
+            font.setBold(true);
+            font.setColor(IndexedColors.RED.getIndex());
+            str2.applyFont(font);
+
+            comment2.setString(str2);
+            comment2.setAuthor("Apache POI");
+            comment2.setAddress(new CellAddress("C3"));
+
+            try (FileOutputStream out = new FileOutputStream("comments.xlsx")) {
+                wb.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/CreateCell.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/CreateCell.java
new file mode 100644 (file)
index 0000000..36e93de
--- /dev/null
@@ -0,0 +1,88 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Date;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.RichTextString;
+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.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Illustrates how to create cell and set values of different types.
+ */
+public class CreateCell {
+
+    public static void main(String[] args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+            CreationHelper creationHelper = wb.getCreationHelper();
+            Sheet sheet = wb.createSheet("new sheet");
+
+            // Create a row and put some cells in it. Rows are 0 based.
+            Row row = sheet.createRow((short) 0);
+            // Create a cell and put a value in it.
+            Cell cell = row.createCell((short) 0);
+            cell.setCellValue(1);
+
+            //numeric value
+            row.createCell(1).setCellValue(1.2);
+
+            //plain string value
+            row.createCell(2).setCellValue("This is a string cell");
+
+            //rich text string
+            RichTextString str = creationHelper.createRichTextString("Apache");
+            Font font = wb.createFont();
+            font.setItalic(true);
+            font.setUnderline(Font.U_SINGLE);
+            str.applyFont(font);
+            row.createCell(3).setCellValue(str);
+
+            //boolean value
+            row.createCell(4).setCellValue(true);
+
+            //formula
+            row.createCell(5).setCellFormula("SUM(A1:B1)");
+
+            //date
+            CellStyle style = wb.createCellStyle();
+            style.setDataFormat(creationHelper.createDataFormat().getFormat("m/d/yy h:mm"));
+            cell = row.createCell(6);
+            cell.setCellValue(new Date());
+            cell.setCellStyle(style);
+
+            //hyperlink
+            row.createCell(7).setCellFormula("SUM(A1:B1)");
+            cell.setCellFormula("HYPERLINK(\"http://google.com\",\"Google\")");
+
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("ooxml-cell.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/CreatePivotTable.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/CreatePivotTable.java
new file mode 100644 (file)
index 0000000..991dd2f
--- /dev/null
@@ -0,0 +1,106 @@
+/* ====================================================================
+ 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.examples.xssf.usermodel;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.ss.SpreadsheetVersion;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.DataConsolidateFunction;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFPivotTable;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+public class CreatePivotTable {
+
+    public static void main(String[] args) throws FileNotFoundException, IOException, InvalidFormatException {
+        try (XSSFWorkbook wb = new XSSFWorkbook()) {
+            XSSFSheet sheet = wb.createSheet();
+
+            //Create some data to build the pivot table on
+            setCellData(sheet);
+
+            AreaReference source = new AreaReference("A1:D4", SpreadsheetVersion.EXCEL2007);
+            CellReference position = new CellReference("H5");
+            // Create a pivot table on this sheet, with H5 as the top-left cell..
+            // The pivot table's data source is on the same sheet in A1:D4
+            XSSFPivotTable pivotTable = sheet.createPivotTable(source, position);
+            //Configure the pivot table
+            //Use first column as row label
+            pivotTable.addRowLabel(0);
+            //Sum up the second column
+            pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1);
+            //Set the third column as filter
+            pivotTable.addColumnLabel(DataConsolidateFunction.AVERAGE, 2);
+            //Add filter on forth column
+            pivotTable.addReportFilter(3);
+
+            try (FileOutputStream fileOut = new FileOutputStream("ooxml-pivottable.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+
+    public static void setCellData(XSSFSheet sheet){
+        Row row1 = sheet.createRow(0);
+        // Create a cell and put a value in it.
+        Cell cell11 = row1.createCell(0);
+        cell11.setCellValue("Names");
+        Cell cell12 = row1.createCell(1);
+        cell12.setCellValue("#");
+        Cell cell13 = row1.createCell(2);
+        cell13.setCellValue("%");
+        Cell cell14 = row1.createCell(3);
+        cell14.setCellValue("Human");
+
+        Row row2 = sheet.createRow(1);
+        Cell cell21 = row2.createCell(0);
+        cell21.setCellValue("Jane");
+        Cell cell22 = row2.createCell(1);
+        cell22.setCellValue(10);
+        Cell cell23 = row2.createCell(2);
+        cell23.setCellValue(100);
+        Cell cell24 = row2.createCell(3);
+        cell24.setCellValue("Yes");
+
+        Row row3 = sheet.createRow(2);
+        Cell cell31 = row3.createCell(0);
+        cell31.setCellValue("Tarzan");
+        Cell cell32 = row3.createCell(1);
+        cell32.setCellValue(5);
+        Cell cell33 = row3.createCell(2);
+        cell33.setCellValue(90);
+        Cell cell34 = row3.createCell(3);
+        cell34.setCellValue("Yes");
+
+        Row row4 = sheet.createRow(3);
+        Cell cell41 = row4.createCell(0);
+        cell41.setCellValue("Terk");
+        Cell cell42 = row4.createCell(1);
+        cell42.setCellValue(10);
+        Cell cell43 = row4.createCell(2);
+        cell43.setCellValue(90);
+        Cell cell44 = row4.createCell(3);
+        cell44.setCellValue("No");
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/CreatePivotTable2.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/CreatePivotTable2.java
new file mode 100644 (file)
index 0000000..7ba0c78
--- /dev/null
@@ -0,0 +1,124 @@
+/* ====================================================================
+ 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.examples.xssf.usermodel;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.ss.SpreadsheetVersion;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.DataConsolidateFunction;
+import org.apache.poi.ss.usermodel.DataFormat;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFPivotTable;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+public class CreatePivotTable2 {
+
+    public static void main(String[] args) throws FileNotFoundException, IOException, InvalidFormatException {
+        try (XSSFWorkbook wb = new XSSFWorkbook()) {
+            XSSFSheet sheet = wb.createSheet();
+
+            //Create some data to build the pivot table on
+            setCellData(sheet);
+
+            AreaReference source = new AreaReference("A1:E7", SpreadsheetVersion.EXCEL2007);
+            CellReference position = new CellReference("H1");
+            // Create a pivot table on this sheet, with H1 as the top-left cell..
+            // The pivot table's data source is on the same sheet in A1:E7
+            XSSFPivotTable pivotTable = sheet.createPivotTable(source, position);
+            //Configure the pivot table
+            //Use first column as row label
+            pivotTable.addRowLabel(0);
+            //Sum up the second column with column title and data format
+            pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1, "Values", "#,##0.00");
+            //Use third column (month) as columns (side by side)
+            pivotTable.addColLabel(3, "DD.MM.YYYY");
+
+            //Add filter on forth column
+            pivotTable.addReportFilter(4);
+
+            try (FileOutputStream fileOut = new FileOutputStream("ooxml-pivottable2.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+
+    public static void setCellData(XSSFSheet sheet){
+        Calendar cal1 = Calendar.getInstance();
+        cal1.set(2017, 0, 1, 0, 0, 0);
+        Calendar cal2 = Calendar.getInstance();
+        cal2.set(2017, 1, 1, 0, 0, 0);
+        Row row1 = sheet.createRow(0);
+        // Create a cell and put a value in it.
+        // first row are column titles
+        Cell cell11 = row1.createCell(0);
+        cell11.setCellValue("Names");
+        Cell cell12 = row1.createCell(1);
+        cell12.setCellValue("Values");
+        Cell cell13 = row1.createCell(2);
+        cell13.setCellValue("%");
+        Cell cell14 = row1.createCell(3);
+        cell14.setCellValue("Month");
+        Cell cell15 = row1.createCell(4);
+        cell15.setCellValue("No");
+
+        CellStyle csDbl = sheet.getWorkbook().createCellStyle();
+        DataFormat dfDbl = sheet.getWorkbook().createDataFormat();
+        csDbl.setDataFormat(dfDbl.getFormat("#,##0.00"));
+
+        CellStyle csDt = sheet.getWorkbook().createCellStyle();
+        DataFormat dfDt = sheet.getWorkbook().createDataFormat();
+        csDt.setDataFormat(dfDt.getFormat("dd/MM/yyyy"));
+        // data
+        setDataRow(sheet, 1, "Jane", 1120.5, 100, cal1.getTime(), 1, csDbl, csDt);
+        setDataRow(sheet, 2, "Jane", 1453.2, 95, cal2.getTime(), 2, csDbl, csDt);
+
+        setDataRow(sheet, 3, "Tarzan", 1869.8, 88, cal1.getTime(), 1, csDbl, csDt);
+        setDataRow(sheet, 4, "Tarzan", 1536.2, 92, cal2.getTime(), 2, csDbl, csDt);
+
+        setDataRow(sheet, 5, "Terk", 1624.1, 75, cal1.getTime(), 1, csDbl, csDt);
+        setDataRow(sheet, 6, "Terk", 1569.3, 82, cal2.getTime(), 2, csDbl, csDt);
+        sheet.autoSizeColumn(3);
+    }
+
+    public static void setDataRow(XSSFSheet sheet, int rowNum, String name, double v1, int v2, Date dt, int no, CellStyle csDbl, CellStyle csDt){
+        Row row = sheet.createRow(rowNum);
+        // set the values for one row
+        Cell c1 = row.createCell(0);
+        c1.setCellValue(name);
+        Cell c2 = row.createCell(1);
+        c2.setCellValue(v1);
+        c2.setCellStyle(csDbl);
+        Cell c3 = row.createCell(2);
+        c3.setCellValue(v2);
+        Cell c4 = row.createCell(3);
+        c4.setCellValue(dt);
+        c4.setCellStyle(csDt);
+        Cell c5 = row.createCell(4);
+        c5.setCellValue(no);
+    }
+
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/CreateTable.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/CreateTable.java
new file mode 100644 (file)
index 0000000..7e1d56a
--- /dev/null
@@ -0,0 +1,87 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFTable;
+import org.apache.poi.xssf.usermodel.XSSFTableStyleInfo;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates how to create a simple table using Apache POI.
+ */
+public class CreateTable {
+
+    public static void main(String[] args) throws IOException {
+
+        try (XSSFWorkbook wb = new XSSFWorkbook()) {
+            XSSFSheet sheet = wb.createSheet();
+
+            // Set which area the table should be placed in
+            AreaReference reference = wb.getCreationHelper().createAreaReference(
+                    new CellReference(0, 0), new CellReference(2, 2));
+
+            // Create
+            XSSFTable table = sheet.createTable(reference);
+            table.setName("Test");
+            table.setDisplayName("Test_Table");
+
+            // For now, create the initial style in a low-level way
+            table.getCTTable().addNewTableStyleInfo();
+            table.getCTTable().getTableStyleInfo().setName("TableStyleMedium2");
+
+            // Style the table
+            XSSFTableStyleInfo style = (XSSFTableStyleInfo) table.getStyle();
+            style.setName("TableStyleMedium2");
+            style.setShowColumnStripes(false);
+            style.setShowRowStripes(true);
+            style.setFirstColumn(false);
+            style.setLastColumn(false);
+            style.setShowRowStripes(true);
+            style.setShowColumnStripes(true);
+
+            // Set the values for the table
+            XSSFRow row;
+            XSSFCell cell;
+            for (int i = 0; i < 3; i++) {
+                // Create row
+                row = sheet.createRow(i);
+                for (int j = 0; j < 3; j++) {
+                    // Create cell
+                    cell = row.createCell(j);
+                    if (i == 0) {
+                        cell.setCellValue("Column" + (j + 1));
+                    } else {
+                        cell.setCellValue((i + 1.0) * (j + 1.0));
+                    }
+                }
+            }
+
+            // Save
+            try (FileOutputStream fileOut = new FileOutputStream("ooxml-table.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/CreateUserDefinedDataFormats.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/CreateUserDefinedDataFormats.java
new file mode 100644 (file)
index 0000000..03d88d6
--- /dev/null
@@ -0,0 +1,67 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.DataFormat;
+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.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * How to set user-defined date formats
+ */
+public class CreateUserDefinedDataFormats {
+
+
+    public static void main(String[]args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {  //or new HSSFWorkbook();
+            Sheet sheet = wb.createSheet("format sheet");
+            CellStyle style;
+            DataFormat format = wb.createDataFormat();
+            Row row;
+            Cell cell;
+            short rowNum = 0;
+            short colNum = 0;
+
+            row = sheet.createRow(rowNum);
+            cell = row.createCell(colNum);
+            cell.setCellValue(11111.25);
+            style = wb.createCellStyle();
+            style.setDataFormat(format.getFormat("0.0"));
+            cell.setCellStyle(style);
+
+            row = sheet.createRow(++rowNum);
+            cell = row.createCell(colNum);
+            cell.setCellValue(11111.25);
+            style = wb.createCellStyle();
+            style.setDataFormat(format.getFormat("#,##0.0000"));
+            cell.setCellStyle(style);
+
+            try (FileOutputStream fileOut = new FileOutputStream("ooxml_dataFormat.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/CustomXMLMapping.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/CustomXMLMapping.java
new file mode 100644 (file)
index 0000000..ebc04a4
--- /dev/null
@@ -0,0 +1,47 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.ByteArrayOutputStream;
+
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.xssf.extractor.XSSFExportToXml;
+import org.apache.poi.xssf.usermodel.XSSFMap;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Print all custom XML mappings registered in the given workbook
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class CustomXMLMapping {
+
+    private CustomXMLMapping() {}
+
+    public static void main(String[] args) throws Exception {
+        try (OPCPackage pkg = OPCPackage.open(args[0]);
+             XSSFWorkbook wb = new XSSFWorkbook(pkg)) {
+            for (XSSFMap map : wb.getCustomXMLMappings()) {
+                XSSFExportToXml exporter = new XSSFExportToXml(map);
+
+                ByteArrayOutputStream os = new ByteArrayOutputStream();
+                exporter.exportToXML(os, true);
+                String xml = os.toString("UTF-8");
+                System.out.println(xml);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/EmbeddedObjects.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/EmbeddedObjects.java
new file mode 100644 (file)
index 0000000..b4af95c
--- /dev/null
@@ -0,0 +1,67 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.Closeable;
+import java.io.InputStream;
+
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+
+/**
+ * Demonstrates how you can extract embedded data from a .xlsx file
+ */
+public class EmbeddedObjects {
+    public static void main(String[] args) throws Exception {
+        try (XSSFWorkbook workbook = new XSSFWorkbook(args[0])) {
+            for (PackagePart pPart : workbook.getAllEmbeddedParts()) {
+                String contentType = pPart.getContentType();
+                try (InputStream is = pPart.getInputStream()) {
+                    Closeable document;
+                    if (contentType.equals("application/vnd.ms-excel")) {
+                        // Excel Workbook - either binary or OpenXML
+                        document = new HSSFWorkbook(is);
+                    } else if (contentType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
+                        // Excel Workbook - OpenXML file format
+                        document = new XSSFWorkbook(is);
+                    } else if (contentType.equals("application/msword")) {
+                        // Word Document - binary (OLE2CDF) file format
+                        document = new HWPFDocument(is);
+                    } else if (contentType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
+                        // Word Document - OpenXML file format
+                        document = new XWPFDocument(is);
+                    } else if (contentType.equals("application/vnd.ms-powerpoint")) {
+                        // PowerPoint Document - binary file format
+                        document = new HSLFSlideShow(is);
+                    } else if (contentType.equals("application/vnd.openxmlformats-officedocument.presentationml.presentation")) {
+                        // PowerPoint Document - OpenXML file format
+                        document = new XMLSlideShow(is);
+                    } else {
+                        // Any other type of embedded object.
+                        document = is;
+                    }
+                    document.close();
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/ExcelChartWithTargetLine.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/ExcelChartWithTargetLine.java
new file mode 100644 (file)
index 0000000..01cdaf5
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ *  ====================================================================
+ *    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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xddf.usermodel.PresetColor;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFFillProperties;
+import org.apache.poi.xddf.usermodel.XDDFLineProperties;
+import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.AxisTickLabelPosition;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFCategoryDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFLegendEntry;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFScatterChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xddf.usermodel.text.XDDFRunProperties;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFChart;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * This example is based on original contributions by Axel Richter on StackOverflow.
+ *
+ * <em>Note from original author</em>:
+ * This only works for Excel since OpenOffice or LibreOffice Calc is not able having series having literal numeric values set.
+ *
+ * @see <a href="https://stackoverflow.com/questions/50772989/">Create target marker in a bar chart with openxmlformats</a>
+ * @see <a href="https://stackoverflow.com/questions/50873700/">Change axis color and font of the chart in openxmlformats</a>
+ * @see <a href="https://stackoverflow.com/questions/51530552/">Change colors of line chart Apache POI</a>
+ */
+public final class ExcelChartWithTargetLine {
+    private ExcelChartWithTargetLine() {}
+
+    private static final int NUM_OF_ROWS = 6;
+
+    private static void createChart(XSSFChart chart, XSSFSheet sheet, int[] chartedCols, double target) {
+        // some colors
+        XDDFFillProperties[] fills = new XDDFFillProperties[] {
+            new XDDFSolidFillProperties(XDDFColor.from(PresetColor.TURQUOISE)),
+            new XDDFSolidFillProperties(XDDFColor.from(PresetColor.CHARTREUSE)),
+            new XDDFSolidFillProperties(XDDFColor.from(PresetColor.LAVENDER)),
+            new XDDFSolidFillProperties(XDDFColor.from(PresetColor.CHOCOLATE)),
+            new XDDFSolidFillProperties(XDDFColor.from(PresetColor.TOMATO)),
+            new XDDFSolidFillProperties(XDDFColor.from(PresetColor.PLUM))
+        };
+        XDDFLineProperties solidTurquoise = new XDDFLineProperties(fills[0]);
+        XDDFLineProperties solidTomato = new XDDFLineProperties(fills[4]);
+        XDDFLineProperties solidPlum = new XDDFLineProperties(fills[5]);
+        XDDFSolidFillProperties solidAlmond = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.BLANCHED_ALMOND));
+        XDDFSolidFillProperties solidGray = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.DARK_SLATE_GRAY));
+
+
+        // the bar chart
+
+        XDDFCategoryAxis barCategories = chart.createCategoryAxis(AxisPosition.BOTTOM);
+        XDDFValueAxis leftValues = chart.createValueAxis(AxisPosition.LEFT);
+        leftValues.crossAxis(barCategories);
+        barCategories.crossAxis(leftValues);
+
+        // from https://stackoverflow.com/questions/50873700/
+        // colored major grid lines
+        leftValues.getOrAddMajorGridProperties().setLineProperties(solidTomato);
+        //colored axis line
+        leftValues.getOrAddShapeProperties().setLineProperties(solidPlum);
+        // axis font
+        XDDFRunProperties props = leftValues.getOrAddTextProperties();
+        props.setFontSize(14.0);
+        props.setFillProperties(fills[5]);
+
+        XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, barCategories, leftValues);
+        bar.setVaryColors(true);
+        bar.setBarDirection(chartedCols.length > 1 ? BarDirection.COL : BarDirection.BAR);
+
+        for (int c : chartedCols) {
+            // the data sources
+            XDDFCategoryDataSource xs = XDDFDataSourcesFactory.fromStringCellRange(sheet,
+                    new CellRangeAddress(1, NUM_OF_ROWS, 0, 0));
+            XDDFNumericalDataSource<Double> ys = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
+                    new CellRangeAddress(1, NUM_OF_ROWS, c, c));
+            XDDFBarChartData.Series series = (XDDFBarChartData.Series) bar.addSeries(xs, ys);
+            series.setTitle(null, new CellReference(sheet.getSheetName(), 0, c, true, true));
+            series.setFillProperties(fills[c]);
+            series.setLineProperties(solidTurquoise); // bar border color different from fill
+        }
+        chart.plot(bar);
+
+
+        // target line
+        // line of a scatter chart from 0 (min) to 1 (max) having value of target
+
+        XDDFValueAxis scatterX = chart.createValueAxis(AxisPosition.TOP);
+        scatterX.setVisible(false);
+        scatterX.setTickLabelPosition(AxisTickLabelPosition.NONE);
+        XDDFValueAxis scatterY = chart.createValueAxis(AxisPosition.RIGHT);
+        scatterY.setVisible(false);
+        scatterY.setTickLabelPosition(AxisTickLabelPosition.NONE);
+        scatterX.crossAxis(scatterY);
+        scatterY.crossAxis(scatterX);
+        if (chartedCols.length > 1) {
+            scatterX.setMaximum(1.0);
+        } else {
+            scatterY.setMaximum(1.0);
+        }
+
+        XDDFScatterChartData scatter = (XDDFScatterChartData) chart.createData(ChartTypes.SCATTER, scatterX, scatterY);
+        scatter.setVaryColors(true);
+
+        //  This only works for Excel since OpenOffice or LibreOffice Calc does not support literal numeric data series.
+        XDDFNumericalDataSource<Double> targetDS = XDDFDataSourcesFactory.fromArray(new Double[] { target, target });
+        XDDFNumericalDataSource<Double> zeroOneDS = XDDFDataSourcesFactory.fromArray(new Double[] { 0.0, 1.0 });
+
+        if (chartedCols.length > 1) {
+            // BarDirection.COL then X axis is from 0 to 1 and Y axis is target axis
+            scatter.addSeries(zeroOneDS, targetDS).setLineProperties(solidTurquoise);
+        } else {
+            // BarDirection.BAR then X axis is target axis and Y axis is from 0 to 1
+            scatter.addSeries(targetDS, zeroOneDS).setLineProperties(solidTurquoise);
+        }
+
+        chart.plot(scatter);
+
+
+        // legend
+        if (chartedCols.length > 1) {
+            XDDFChartLegend legend = chart.getOrAddLegend();
+            legend.setPosition(LegendPosition.LEFT);
+            legend.setOverlay(false);
+
+            // delete additional target line series legend entry
+            XDDFLegendEntry entry = legend.addEntry();
+            entry.setIndex(0);
+            entry.setDelete(true);
+        }
+
+
+        // from https://stackoverflow.com/questions/51530552/
+        // customize the chart
+
+        // do not auto delete the title
+        chart.setAutoTitleDeleted(false);
+
+        // plot area background and border line
+        XDDFShapeProperties chartProps = chart.getOrAddShapeProperties();
+        chartProps.setFillProperties(solidAlmond);
+        chartProps.setLineProperties(new XDDFLineProperties(solidGray));
+
+        // line style of cat axis
+        XDDFLineProperties categoriesProps = new XDDFLineProperties(solidGray);
+        categoriesProps.setWidth(2.1);
+        barCategories.getOrAddShapeProperties().setLineProperties(categoriesProps);
+    }
+
+    private static XSSFClientAnchor createAnchor(XSSFDrawing drawing, int[] chartedCols) {
+        if (chartedCols.length > 1) {
+            return drawing.createAnchor(0, 0, 0, 0, 0, 8, 10, 23);
+        } else {
+            return drawing.createAnchor(0, 0, 0, 0, 0, 8, 5, 23);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        try (XSSFWorkbook workbook = new XSSFWorkbook()) {
+            XSSFSheet sheet = workbook.createSheet("targetline");
+            final int NUM_OF_COLUMNS = 4;
+
+            // create some data
+            XSSFRow row;
+            XSSFCell cell;
+            String[] headings = new String[] { "Year", "Male", "Female", "Other" };
+            int rowIndex = 0;
+            row = sheet.createRow(rowIndex);
+            for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
+                cell = row.createCell(colIndex);
+                cell.setCellValue(headings[colIndex]);
+            }
+            double[][] values = new double[][] { new double[] { 1980, 56.0, 44.1, 12.2 },
+                    new double[] { 1985, 34.5, 41.0, 4 }, new double[] { 1990, 65.0, 68.5, 9.1 },
+                    new double[] { 1995, 34.7, 47.6, 4.9 }, new double[] { 2000, 23.0, 64.5, 11.1 },
+                    new double[] { 2005, 56.3, 69.8, 9.5 } };
+            for (; rowIndex < NUM_OF_ROWS; rowIndex++) {
+                row = sheet.createRow(rowIndex + 1);
+                for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
+                    cell = row.createCell(colIndex);
+                    cell.setCellValue(values[rowIndex][colIndex]);
+                }
+            }
+
+            int[] chartedCols = new int[] {  1,  2  , 3  };
+
+            XSSFDrawing drawing = sheet.createDrawingPatriarch();
+            XSSFClientAnchor anchor = createAnchor(drawing, chartedCols);
+            XSSFChart chart = drawing.createChart(anchor);
+            createChart(chart, sheet, chartedCols, 42.0);
+
+            try (FileOutputStream fos = new FileOutputStream("ExcelChartWithTargetLine.xlsx")) {
+                workbook.write(fos);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/FillsAndColors.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/FillsAndColors.java
new file mode 100644 (file)
index 0000000..baf462c
--- /dev/null
@@ -0,0 +1,65 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.IndexedColors;
+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.xssf.usermodel.XSSFRichTextString;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Fills and Colors
+ */
+public class FillsAndColors {
+    public static void main(String[] args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+            Sheet sheet = wb.createSheet("new sheet");
+
+            // Create a row and put some cells in it. Rows are 0 based.
+            Row row = sheet.createRow(1);
+
+            // Aqua background
+            CellStyle style = wb.createCellStyle();
+            style.setFillBackgroundColor(IndexedColors.AQUA.getIndex());
+            style.setFillPattern(FillPatternType.BIG_SPOTS);
+            Cell cell = row.createCell(1);
+            cell.setCellValue(new XSSFRichTextString("X"));
+            cell.setCellStyle(style);
+
+            // Orange "foreground", foreground being the fill foreground not the font color.
+            style = wb.createCellStyle();
+            style.setFillForegroundColor(IndexedColors.ORANGE.getIndex());
+            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+            cell = row.createCell(2);
+            cell.setCellValue(new XSSFRichTextString("X"));
+            cell.setCellStyle(style);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("fill_colors.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/FitSheetToOnePage.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/FitSheetToOnePage.java
new file mode 100644 (file)
index 0000000..389e87f
--- /dev/null
@@ -0,0 +1,46 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.PrintSetup;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+public class FitSheetToOnePage {
+
+    public static void main(String[]args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {  //or new HSSFWorkbook();
+            Sheet sheet = wb.createSheet("format sheet");
+            PrintSetup ps = sheet.getPrintSetup();
+
+            sheet.setAutobreaks(true);
+
+            ps.setFitHeight((short) 1);
+            ps.setFitWidth((short) 1);
+
+            // Create various cells and rows for spreadsheet.
+
+            try (FileOutputStream fileOut = new FileOutputStream("fitSheetToOnePage.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/HeadersAndFooters.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/HeadersAndFooters.java
new file mode 100644 (file)
index 0000000..946ae50
--- /dev/null
@@ -0,0 +1,84 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Footer;
+import org.apache.poi.ss.usermodel.Header;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+public class HeadersAndFooters {
+
+    public static void main(String[]args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+            Sheet sheet = wb.createSheet("first-header - format sheet");
+            sheet.createRow(0).createCell(0).setCellValue(123);
+
+            //set page numbers in the footer
+            Footer footer = sheet.getFooter();
+            //&P == current page number
+            //&N == page numbers
+            footer.setRight("Page &P of &N");
+
+
+            Header firstHeader = ((XSSFSheet) sheet).getFirstHeader();
+            //&F == workbook file name
+            firstHeader.setLeft("&F ......... first header");
+
+            for (int i = 0; i < 100; i = i + 10) {
+                sheet.createRow(i).createCell(0).setCellValue(123);
+            }
+
+
+            XSSFSheet sheet2 = (XSSFSheet) wb.createSheet("odd header-even footer");
+            Header oddHeader = sheet2.getOddHeader();
+            //&B == bold
+            //&E == double underline
+            //&D == date
+            oddHeader.setCenter("&B &E oddHeader     &D ");
+
+            Footer evenFooter = sheet2.getEvenFooter();
+            evenFooter.setRight("even footer &P");
+            sheet2.createRow(10).createCell(0).setCellValue("Second sheet with an oddHeader and an evenFooter");
+
+            for (int i = 0; i < 200; i = i + 10) {
+                sheet2.createRow(i).createCell(0).setCellValue(123);
+            }
+
+            XSSFSheet sheet3 = (XSSFSheet) wb.createSheet("odd header- odd footer");
+            sheet3.createRow(10).createCell(0).setCellValue("Third sheet with oddHeader and oddFooter");
+            Header oddH = sheet3.getOddHeader();
+            //&C == centered
+            oddH.setCenter("centered oddHeader");
+            oddH.setLeft("left ");
+            oddH.setRight("right ");
+
+            Footer oddF = sheet3.getOddFooter();
+            oddF.setLeft("Page &P");
+            oddF.setRight("Pages &N ");
+
+            try (FileOutputStream fileOut = new FileOutputStream("headerFooter.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/HyperlinkExample.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/HyperlinkExample.java
new file mode 100644 (file)
index 0000000..5196319
--- /dev/null
@@ -0,0 +1,96 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.common.usermodel.HyperlinkType;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.Hyperlink;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates how to create hyperlinks.
+ */
+public class HyperlinkExample {
+
+    public static void main(String[]args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+            CreationHelper createHelper = wb.getCreationHelper();
+
+            //cell style for hyperlinks
+            //by default hyperlinks are blue and underlined
+            CellStyle hlink_style = wb.createCellStyle();
+            Font hlink_font = wb.createFont();
+            hlink_font.setUnderline(Font.U_SINGLE);
+            hlink_font.setColor(IndexedColors.BLUE.getIndex());
+            hlink_style.setFont(hlink_font);
+
+            Cell cell;
+            Sheet sheet = wb.createSheet("Hyperlinks");
+            //URL
+            cell = sheet.createRow(0).createCell(0);
+            cell.setCellValue("URL Link");
+
+            Hyperlink link = createHelper.createHyperlink(HyperlinkType.URL);
+            link.setAddress("https://poi.apache.org/");
+            cell.setHyperlink(link);
+            cell.setCellStyle(hlink_style);
+
+            //link to a file in the current directory
+            cell = sheet.createRow(1).createCell(0);
+            cell.setCellValue("File Link");
+            link = createHelper.createHyperlink(HyperlinkType.FILE);
+            link.setAddress("link1.xls");
+            cell.setHyperlink(link);
+            cell.setCellStyle(hlink_style);
+
+            //e-mail link
+            cell = sheet.createRow(2).createCell(0);
+            cell.setCellValue("Email Link");
+            link = createHelper.createHyperlink(HyperlinkType.EMAIL);
+            //note, if subject contains white spaces, make sure they are url-encoded
+            link.setAddress("mailto:poi@apache.org?subject=Hyperlinks");
+            cell.setHyperlink(link);
+            cell.setCellStyle(hlink_style);
+
+            //link to a place in this workbook
+
+            //create a target sheet and cell
+            Sheet sheet2 = wb.createSheet("Target Sheet");
+            sheet2.createRow(0).createCell(0).setCellValue("Target Cell");
+
+            cell = sheet.createRow(3).createCell(0);
+            cell.setCellValue("Worksheet Link");
+            Hyperlink link2 = createHelper.createHyperlink(HyperlinkType.DOCUMENT);
+            link2.setAddress("'Target Sheet'!A1");
+            cell.setHyperlink(link2);
+            cell.setCellStyle(hlink_style);
+
+            try (FileOutputStream out = new FileOutputStream("hyperinks.xlsx")) {
+                wb.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/IterateCells.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/IterateCells.java
new file mode 100644 (file)
index 0000000..0b49927
--- /dev/null
@@ -0,0 +1,54 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+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.xssf.usermodel.XSSFWorkbook;
+
+/**
+ *  Iterate over rows and cells
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class IterateCells {
+
+    private IterateCells() {}
+
+    public static void main(String[] args) throws IOException {
+        try (
+                FileInputStream is = new FileInputStream(args[0]);
+                Workbook wb = new XSSFWorkbook(is)
+            ) {
+            for (int i = 0; i < wb.getNumberOfSheets(); i++) {
+                Sheet sheet = wb.getSheetAt(i);
+                System.out.println(wb.getSheetName(i));
+                for (Row row : sheet) {
+                    System.out.println("rownum: " + row.getRowNum());
+                    for (Cell cell : row) {
+                        System.out.println(cell);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/LineChart.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/LineChart.java
new file mode 100644 (file)
index 0000000..268d632
--- /dev/null
@@ -0,0 +1,128 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.PresetColor;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFLineProperties;
+import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.MarkerStyle;
+import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFLineChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xssf.usermodel.XSSFChart;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Line chart example.
+ */
+public final class LineChart {
+    private LineChart() {}
+
+    public static void main(String[] args) throws IOException {
+        try (XSSFWorkbook wb = new XSSFWorkbook()) {
+            XSSFSheet sheet = wb.createSheet("linechart");
+            final int NUM_OF_ROWS = 3;
+            final int NUM_OF_COLUMNS = 10;
+
+            // Create a row and put some cells in it. Rows are 0 based.
+            Row row;
+            Cell cell;
+            for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) {
+                row = sheet.createRow((short) rowIndex);
+                for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
+                    cell = row.createCell((short) colIndex);
+                    cell.setCellValue(colIndex * (rowIndex + 1.0));
+                }
+            }
+
+            XSSFDrawing drawing = sheet.createDrawingPatriarch();
+            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);
+
+            XSSFChart chart = drawing.createChart(anchor);
+            XDDFChartLegend legend = chart.getOrAddLegend();
+            legend.setPosition(LegendPosition.TOP_RIGHT);
+
+            // Use a category axis for the bottom axis.
+            XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
+            bottomAxis.setTitle("x"); // https://stackoverflow.com/questions/32010765
+            XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+            leftAxis.setTitle("f(x)");
+            leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
+
+            XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
+            XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1));
+            XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1));
+
+            XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
+            XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) data.addSeries(xs, ys1);
+            series1.setTitle("2x", null); // https://stackoverflow.com/questions/21855842
+            series1.setSmooth(false); // https://stackoverflow.com/questions/29014848
+            series1.setMarkerStyle(MarkerStyle.STAR); // https://stackoverflow.com/questions/39636138
+            XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) data.addSeries(xs, ys2);
+            series2.setTitle("3x", null);
+            series2.setSmooth(true);
+            series2.setMarkerSize((short) 6);
+            series2.setMarkerStyle(MarkerStyle.TRIANGLE); // https://stackoverflow.com/questions/39636138
+            chart.plot(data);
+
+            // if your series have missing values like https://stackoverflow.com/questions/29014848
+            // chart.displayBlanksAs(DisplayBlanks.GAP);
+
+            // https://stackoverflow.com/questions/24676460
+            solidLineSeries(data, 0, PresetColor.CHARTREUSE);
+            solidLineSeries(data, 1, PresetColor.TURQUOISE);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("ooxml-line-chart.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+
+    private static void solidLineSeries(XDDFChartData data, int index, PresetColor color) {
+        XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
+        XDDFLineProperties line = new XDDFLineProperties();
+        line.setFillProperties(fill);
+        XDDFChartData.Series series = data.getSeries().get(index);
+        XDDFShapeProperties properties = series.getShapeProperties();
+        if (properties == null) {
+            properties = new XDDFShapeProperties();
+        }
+        properties.setLineProperties(line);
+        series.setShapeProperties(properties);
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/LoadPasswordProtectedXlsx.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/LoadPasswordProtectedXlsx.java
new file mode 100644 (file)
index 0000000..6e376f0
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  ====================================================================
+ *    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.examples.xssf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+
+import org.apache.poi.examples.util.TempFileUtils;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.temp.AesZipFileZipEntrySource;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * An example that loads a password protected workbook and counts the sheets.
+ * <p><ul>
+ * <li>The example demonstrates that all temp files are removed.
+ * <li><code>AesZipFileZipEntrySource</code> is used to ensure that temp files are encrypted.
+ * </ul><p>
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class LoadPasswordProtectedXlsx {
+
+    private LoadPasswordProtectedXlsx() {}
+
+    public interface EncryptionHandler {
+        void handle(final InputStream inputStream) throws Exception;
+    }
+
+    public static void main(String[] args) throws Exception {
+        execute(args, LoadPasswordProtectedXlsx::printSheetCount);
+    }
+
+    public static void execute(String[] args, EncryptionHandler handler) throws Exception {
+        if(args.length != 2) {
+            throw new IllegalArgumentException("Expected 2 params: filename and password");
+        }
+        TempFileUtils.checkTempFiles();
+        String filename = args[0];
+        String password = args[1];
+        try (FileInputStream fis = new FileInputStream(filename);
+             POIFSFileSystem fs = new POIFSFileSystem(fis)) {
+            EncryptionInfo info = new EncryptionInfo(fs);
+            Decryptor d = Decryptor.getInstance(info);
+            if (!d.verifyPassword(password)) {
+                throw new RuntimeException("incorrect password");
+            }
+            try (InputStream unencryptedStream = d.getDataStream(fs)) {
+                handler.handle(unencryptedStream);
+            }
+        }
+        TempFileUtils.checkTempFiles();
+    }
+
+
+    private static void printSheetCount(final InputStream inputStream) throws Exception {
+        try (AesZipFileZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(inputStream);
+             OPCPackage pkg = OPCPackage.open(source);
+             XSSFWorkbook workbook = new XSSFWorkbook(pkg)) {
+            System.out.println("sheet count: " + workbook.getNumberOfSheets());
+        }
+    }
+
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/MergingCells.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/MergingCells.java
new file mode 100644 (file)
index 0000000..22695c5
--- /dev/null
@@ -0,0 +1,51 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+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.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * An example of how to merge regions of cells.
+ */
+public class MergingCells {
+    public static void main(String[] args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+            Sheet sheet = wb.createSheet("new sheet");
+
+            Row row = sheet.createRow((short) 1);
+            Cell cell = row.createCell((short) 1);
+            cell.setCellValue(new XSSFRichTextString("This is a test of merging"));
+
+            sheet.addMergedRegion(new CellRangeAddress(1, 1, 1, 2));
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("merging_cells.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/NewLinesInCells.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/NewLinesInCells.java
new file mode 100644 (file)
index 0000000..8064260
--- /dev/null
@@ -0,0 +1,58 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+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.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * How to use newlines in cells
+ */
+public class NewLinesInCells {
+
+    public static void main(String[]args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {   //or new HSSFWorkbook();
+            Sheet sheet = wb.createSheet();
+
+            Row row = sheet.createRow(2);
+            Cell cell = row.createCell(2);
+            cell.setCellValue("Use \n with word wrap on to create a new line");
+
+            //to enable newlines you need set a cell styles with wrap=true
+            CellStyle cs = wb.createCellStyle();
+            cs.setWrapText(true);
+            cell.setCellStyle(cs);
+
+            //increase row height to accommodate two lines of text
+            row.setHeightInPoints(2 * sheet.getDefaultRowHeightInPoints());
+
+            //adjust column width to fit the content
+            sheet.autoSizeColumn(2);
+
+            try (FileOutputStream fileOut = new FileOutputStream("ooxml-newlines.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/Outlining.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/Outlining.java
new file mode 100644 (file)
index 0000000..09f87cd
--- /dev/null
@@ -0,0 +1,78 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+public class Outlining {
+
+    public static void main(String[] args) throws IOException {
+        Outlining o=new Outlining();
+        o.groupRowColumn();
+        o.collapseExpandRowColumn();
+    }
+
+
+    private void groupRowColumn() throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {
+            Sheet sheet1 = wb.createSheet("new sheet");
+
+            sheet1.groupRow(5, 14);
+            sheet1.groupRow(7, 14);
+            sheet1.groupRow(16, 19);
+
+            sheet1.groupColumn((short) 4, (short) 7);
+            sheet1.groupColumn((short) 9, (short) 12);
+            sheet1.groupColumn((short) 10, (short) 11);
+
+            try (OutputStream fileOut = new FileOutputStream("outlining.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+
+    private void collapseExpandRowColumn() throws IOException {
+        try (Workbook wb2 = new XSSFWorkbook()) {
+            Sheet sheet2 = wb2.createSheet("new sheet");
+            sheet2.groupRow(5, 14);
+            sheet2.groupRow(7, 14);
+            sheet2.groupRow(16, 19);
+
+            sheet2.groupColumn((short) 4, (short) 7);
+            sheet2.groupColumn((short) 9, (short) 12);
+            sheet2.groupColumn((short) 10, (short) 11);
+
+
+            sheet2.setRowGroupCollapsed(7, true);
+            //sheet1.setRowGroupCollapsed(7,false);
+
+            sheet2.setColumnGroupCollapsed((short) 4, true);
+            sheet2.setColumnGroupCollapsed((short) 4, false);
+
+            try (OutputStream fileOut = new FileOutputStream("outlining_collapsed.xlsx")) {
+                wb2.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/ScatterChart.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/ScatterChart.java
new file mode 100644 (file)
index 0000000..6946126
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *  ====================================================================
+ *    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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.PresetColor;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFLineProperties;
+import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFScatterChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xssf.usermodel.XSSFChart;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Illustrates how to create a simple scatter chart.
+ */
+public final class ScatterChart {
+    private ScatterChart() {}
+
+    public static void main(String[] args) throws IOException {
+        try (XSSFWorkbook wb = new XSSFWorkbook()) {
+            XSSFSheet sheet = wb.createSheet("Sheet 1");
+            final int NUM_OF_ROWS = 3;
+            final int NUM_OF_COLUMNS = 10;
+
+            // Create a row and put some cells in it. Rows are 0 based.
+            Row row;
+            Cell cell;
+            for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) {
+                row = sheet.createRow((short) rowIndex);
+                for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
+                    cell = row.createCell((short) colIndex);
+                    cell.setCellValue(colIndex * (rowIndex + 1.0));
+                }
+            }
+
+            XSSFDrawing drawing = sheet.createDrawingPatriarch();
+            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);
+
+            XSSFChart chart = drawing.createChart(anchor);
+            XDDFChartLegend legend = chart.getOrAddLegend();
+            legend.setPosition(LegendPosition.TOP_RIGHT);
+
+            XDDFValueAxis bottomAxis = chart.createValueAxis(AxisPosition.BOTTOM);
+            bottomAxis.setTitle("x"); // https://stackoverflow.com/questions/32010765
+            XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+            leftAxis.setTitle("f(x)");
+            leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
+
+            XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
+            XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1));
+            XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1));
+
+
+            XDDFScatterChartData data = (XDDFScatterChartData) chart.createData(ChartTypes.SCATTER, bottomAxis, leftAxis);
+            XDDFScatterChartData.Series series1 = (XDDFScatterChartData.Series) data.addSeries(xs, ys1);
+            series1.setTitle("2x", null); // https://stackoverflow.com/questions/21855842
+            series1.setSmooth(false); // https://stackoverflow.com/questions/39636138
+            XDDFScatterChartData.Series series2 = (XDDFScatterChartData.Series) data.addSeries(xs, ys2);
+            series2.setTitle("3x", null);
+            chart.plot(data);
+
+            solidLineSeries(data, 0, PresetColor.CHARTREUSE);
+            solidLineSeries(data, 1, PresetColor.TURQUOISE);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("ooxml-scatter-chart.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+
+    private static void solidLineSeries(XDDFChartData data, int index, PresetColor color) {
+        XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
+        XDDFLineProperties line = new XDDFLineProperties();
+        line.setFillProperties(fill);
+        XDDFChartData.Series series = data.getSeries().get(index);
+        XDDFShapeProperties properties = series.getShapeProperties();
+        if (properties == null) {
+            properties = new XDDFShapeProperties();
+        }
+        properties.setLineProperties(line);
+        series.setShapeProperties(properties);
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/SelectedSheet.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/SelectedSheet.java
new file mode 100644 (file)
index 0000000..ef6d947
--- /dev/null
@@ -0,0 +1,45 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+public abstract class SelectedSheet {
+
+    public static void main(String[]args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+
+            wb.createSheet("row sheet");
+            wb.createSheet("another sheet");
+            Sheet sheet3 = wb.createSheet(" sheet 3 ");
+            sheet3.setSelected(true);
+            wb.setActiveSheet(2);
+
+            // Create various cells and rows for spreadsheet.
+
+            try (FileOutputStream fileOut = new FileOutputStream("selectedSheet.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/ShiftRows.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/ShiftRows.java
new file mode 100644 (file)
index 0000000..92d1f4c
--- /dev/null
@@ -0,0 +1,60 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+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.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * How to shift rows up or down
+ */
+public class ShiftRows {
+
+    public static void main(String[]args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {   //or new HSSFWorkbook();
+            Sheet sheet = wb.createSheet("Sheet1");
+
+            Row row1 = sheet.createRow(1);
+            row1.createCell(0).setCellValue(1);
+
+            Row row2 = sheet.createRow(4);
+            row2.createCell(1).setCellValue(2);
+
+            Row row3 = sheet.createRow(5);
+            row3.createCell(2).setCellValue(3);
+
+            Row row4 = sheet.createRow(6);
+            row4.createCell(3).setCellValue(4);
+
+            Row row5 = sheet.createRow(9);
+            row5.createCell(4).setCellValue(5);
+
+            // Shift rows 6 - 11 on the spreadsheet to the top (rows 0 - 5)
+            sheet.shiftRows(5, 10, -4);
+
+            try (FileOutputStream fileOut = new FileOutputStream("shiftRows.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/SplitAndFreezePanes.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/SplitAndFreezePanes.java
new file mode 100644 (file)
index 0000000..4a8afee
--- /dev/null
@@ -0,0 +1,52 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * How to set split and freeze panes
+ */
+public class SplitAndFreezePanes {
+    public static void main(String[]args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {
+            Sheet sheet1 = wb.createSheet("new sheet");
+            Sheet sheet2 = wb.createSheet("second sheet");
+            Sheet sheet3 = wb.createSheet("third sheet");
+            Sheet sheet4 = wb.createSheet("fourth sheet");
+
+            // Freeze just one row
+            sheet1.createFreezePane(0, 1, 0, 1);
+            // Freeze just one column
+            sheet2.createFreezePane(1, 0, 1, 0);
+            // Freeze the columns and rows (forget about scrolling position of the lower right quadrant).
+            sheet3.createFreezePane(2, 2);
+            // Create a split with the lower left side being the active quadrant
+            sheet4.createSplitPane(2000, 2000, 0, 0, Sheet.PANE_LOWER_LEFT);
+
+            try (FileOutputStream fileOut = new FileOutputStream("splitFreezePane.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkbookProperties.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkbookProperties.java
new file mode 100644 (file)
index 0000000..9bb43f9
--- /dev/null
@@ -0,0 +1,62 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ooxml.POIXMLProperties;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * How to set extended and custom properties
+ */
+public class WorkbookProperties {
+
+    public static void main(String[]args) throws IOException {
+        try (XSSFWorkbook workbook = new XSSFWorkbook()) {
+            workbook.createSheet("Workbook Properties");
+
+            POIXMLProperties props = workbook.getProperties();
+
+            /*
+             * Extended properties are a predefined set of metadata properties
+             * that are specifically applicable to Office Open XML documents.
+             * Extended properties consist of 24 simple properties and 3 complex properties stored in the
+             *  part targeted by the relationship of type
+             */
+            POIXMLProperties.ExtendedProperties ext = props.getExtendedProperties();
+            ext.getUnderlyingProperties().setCompany("Apache Software Foundation");
+            ext.getUnderlyingProperties().setTemplate("XSSF");
+
+            /*
+             * Custom properties enable users to define custom metadata properties.
+             */
+
+            POIXMLProperties.CustomProperties cust = props.getCustomProperties();
+            cust.addProperty("Author", "John Smith");
+            cust.addProperty("Year", 2009);
+            cust.addProperty("Price", 45.50);
+            cust.addProperty("Available", true);
+
+            try (FileOutputStream out = new FileOutputStream("workbook.xlsx")) {
+                workbook.write(out);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithBorders.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithBorders.java
new file mode 100644 (file)
index 0000000..5ffa54a
--- /dev/null
@@ -0,0 +1,65 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.IndexedColors;
+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.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Working with borders
+ */
+public class WorkingWithBorders {
+    public static void main(String[] args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {  //or new HSSFWorkbook();
+            Sheet sheet = wb.createSheet("borders");
+
+            // Create a row and put some cells in it. Rows are 0 based.
+            Row row = sheet.createRow((short) 1);
+
+            // Create a cell and put a value in it.
+            Cell cell = row.createCell((short) 1);
+            cell.setCellValue(4);
+
+            // Style the cell with borders all around.
+            CellStyle style = wb.createCellStyle();
+            style.setBorderBottom(BorderStyle.THIN);
+            style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
+            style.setBorderLeft(BorderStyle.THIN);
+            style.setLeftBorderColor(IndexedColors.GREEN.getIndex());
+            style.setBorderRight(BorderStyle.THIN);
+            style.setRightBorderColor(IndexedColors.BLUE.getIndex());
+            style.setBorderTop(BorderStyle.MEDIUM_DASHED);
+            style.setTopBorderColor(IndexedColors.BLACK.getIndex());
+            cell.setCellStyle(style);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("xssf-borders.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithFonts.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithFonts.java
new file mode 100644 (file)
index 0000000..a40ae57
--- /dev/null
@@ -0,0 +1,107 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Working with Fonts
+ */
+public class WorkingWithFonts {
+    public static void main(String[] args) throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {  //or new HSSFWorkbook();
+            Sheet sheet = wb.createSheet("Fonts");
+
+            Font font0 = wb.createFont();
+            font0.setColor(IndexedColors.BROWN.getIndex());
+            CellStyle style0 = wb.createCellStyle();
+            style0.setFont(font0);
+
+            Font font1 = wb.createFont();
+            font1.setFontHeightInPoints((short) 14);
+            font1.setFontName("Courier New");
+            font1.setColor(IndexedColors.RED.getIndex());
+            CellStyle style1 = wb.createCellStyle();
+            style1.setFont(font1);
+
+            Font font2 = wb.createFont();
+            font2.setFontHeightInPoints((short) 16);
+            font2.setFontName("Arial");
+            font2.setColor(IndexedColors.GREEN.getIndex());
+            CellStyle style2 = wb.createCellStyle();
+            style2.setFont(font2);
+
+            Font font3 = wb.createFont();
+            font3.setFontHeightInPoints((short) 18);
+            font3.setFontName("Times New Roman");
+            font3.setColor(IndexedColors.LAVENDER.getIndex());
+            CellStyle style3 = wb.createCellStyle();
+            style3.setFont(font3);
+
+            Font font4 = wb.createFont();
+            font4.setFontHeightInPoints((short) 18);
+            font4.setFontName("Wingdings");
+            font4.setColor(IndexedColors.GOLD.getIndex());
+            CellStyle style4 = wb.createCellStyle();
+            style4.setFont(font4);
+
+            Font font5 = wb.createFont();
+            font5.setFontName("Symbol");
+            CellStyle style5 = wb.createCellStyle();
+            style5.setFont(font5);
+
+            Cell cell0 = sheet.createRow(0).createCell(1);
+            cell0.setCellValue("Default");
+            cell0.setCellStyle(style0);
+
+            Cell cell1 = sheet.createRow(1).createCell(1);
+            cell1.setCellValue("Courier");
+            cell1.setCellStyle(style1);
+
+            Cell cell2 = sheet.createRow(2).createCell(1);
+            cell2.setCellValue("Arial");
+            cell2.setCellStyle(style2);
+
+            Cell cell3 = sheet.createRow(3).createCell(1);
+            cell3.setCellValue("Times New Roman");
+            cell3.setCellStyle(style3);
+
+            Cell cell4 = sheet.createRow(4).createCell(1);
+            cell4.setCellValue("Wingdings");
+            cell4.setCellStyle(style4);
+
+            Cell cell5 = sheet.createRow(5).createCell(1);
+            cell5.setCellValue("Symbol");
+            cell5.setCellStyle(style5);
+
+            // Write the output to a file
+            try (FileOutputStream fileOut = new FileOutputStream("xssf-fonts.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithPageSetup.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithPageSetup.java
new file mode 100644 (file)
index 0000000..a43c512
--- /dev/null
@@ -0,0 +1,82 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+
+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.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates various settings avaiable in the Page Setup dialog
+ */
+public class WorkingWithPageSetup {
+
+    public static void main(String[]args) throws Exception {
+        try (Workbook wb = new XSSFWorkbook()) {  //or new HSSFWorkbook();
+
+        /*
+         * It's possible to set up repeating rows and columns in your printouts by using the setRepeatingRowsAndColumns() function in the Workbook object.
+         *
+         * This function Contains 5 parameters:
+         * The first parameter is the index to the sheet (0 = first sheet).
+         * The second and third parameters specify the range for the columns to repreat.
+         * To stop the columns from repeating pass in -1 as the start and end column.
+         * The fourth and fifth parameters specify the range for the rows to repeat.
+         * To stop the columns from repeating pass in -1 as the start and end rows.
+         */
+            Sheet sheet1 = wb.createSheet("new sheet");
+            Sheet sheet2 = wb.createSheet("second sheet");
+
+            // Set the columns to repeat from column 0 to 2 on the first sheet
+            Row row1 = sheet1.createRow(0);
+            row1.createCell(0).setCellValue(1);
+            row1.createCell(1).setCellValue(2);
+            row1.createCell(2).setCellValue(3);
+            Row row2 = sheet1.createRow(1);
+            row2.createCell(1).setCellValue(4);
+            row2.createCell(2).setCellValue(5);
+
+
+            Row row3 = sheet2.createRow(1);
+            row3.createCell(0).setCellValue(2.1);
+            row3.createCell(4).setCellValue(2.2);
+            row3.createCell(5).setCellValue(2.3);
+            Row row4 = sheet2.createRow(2);
+            row4.createCell(4).setCellValue(2.4);
+            row4.createCell(5).setCellValue(2.5);
+
+            // Set the columns to repeat from column 0 to 2 on the first sheet
+            sheet1.setRepeatingColumns(CellRangeAddress.valueOf("A:C"));
+            // Set the the repeating rows and columns on the second sheet.
+            CellRangeAddress cra = CellRangeAddress.valueOf("E2:F3");
+            sheet2.setRepeatingColumns(cra);
+            sheet2.setRepeatingRows(cra);
+
+            //set the print area for the first sheet
+            wb.setPrintArea(0, 1, 2, 0, 3);
+
+
+            try (FileOutputStream fileOut = new FileOutputStream("xssf-printsetup.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithPictures.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithPictures.java
new file mode 100644 (file)
index 0000000..555bc51
--- /dev/null
@@ -0,0 +1,79 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.Picture;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates how to insert pictures in a SpreadsheetML document
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class WorkingWithPictures {
+    private WorkingWithPictures() {}
+
+    public static void main(String[] args) throws IOException {
+
+        //create a new workbook
+        try (Workbook wb = new XSSFWorkbook()) {
+            CreationHelper helper = wb.getCreationHelper();
+
+            //add a picture in this workbook.
+            InputStream is = new FileInputStream(args[0]);
+            byte[] bytes = IOUtils.toByteArray(is);
+            is.close();
+            int pictureIdx = wb.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);
+
+            //create sheet
+            Sheet sheet = wb.createSheet();
+
+            //create drawing
+            Drawing<?> drawing = sheet.createDrawingPatriarch();
+
+            //add a picture shape
+            ClientAnchor anchor = helper.createClientAnchor();
+            anchor.setCol1(1);
+            anchor.setRow1(1);
+            Picture pict = drawing.createPicture(anchor, pictureIdx);
+
+            //auto-size picture
+            pict.resize(2);
+
+            //save workbook
+            String file = "picture.xls";
+            if (wb instanceof XSSFWorkbook) {
+                file += "x"; // NOSONAR
+            }
+            try (OutputStream fileOut = new FileOutputStream(file)) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithRichText.java b/src/examples/src/org/apache/poi/examples/xssf/usermodel/WorkingWithRichText.java
new file mode 100644 (file)
index 0000000..43376fa
--- /dev/null
@@ -0,0 +1,70 @@
+/* ====================================================================
+   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.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates how to work with rich text
+ */
+public final class WorkingWithRichText {
+
+    private WorkingWithRichText() {}
+
+    public static void main(String[] args) throws Exception {
+        try (XSSFWorkbook wb = new XSSFWorkbook()) {
+            XSSFSheet sheet = wb.createSheet();
+            XSSFRow row = sheet.createRow(2);
+
+            XSSFCell cell = row.createCell(1);
+            XSSFRichTextString rt = new XSSFRichTextString("The quick brown fox");
+
+            XSSFFont font1 = wb.createFont();
+            font1.setBold(true);
+            font1.setColor(new XSSFColor(new java.awt.Color(255, 0, 0), wb.getStylesSource().getIndexedColors()));
+            rt.applyFont(0, 10, font1);
+
+            XSSFFont font2 = wb.createFont();
+            font2.setItalic(true);
+            font2.setUnderline(Font.U_DOUBLE);
+            font2.setColor(new XSSFColor(new java.awt.Color(0, 255, 0), wb.getStylesSource().getIndexedColors()));
+            rt.applyFont(10, 19, font2);
+
+            XSSFFont font3 = wb.createFont();
+            font3.setColor(new XSSFColor(new java.awt.Color(0, 0, 255), wb.getStylesSource().getIndexedColors()));
+            rt.append(" Jumped over the lazy dog", font3);
+
+            cell.setCellValue(rt);
+
+            // Write the output to a file
+            try (OutputStream fileOut = new FileOutputStream("xssf-richtext.xlsx")) {
+                wb.write(fileOut);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xwpf/usermodel/BarChartExample.java b/src/examples/src/org/apache/poi/examples/xwpf/usermodel/BarChartExample.java
new file mode 100644 (file)
index 0000000..89bd260
--- /dev/null
@@ -0,0 +1,143 @@
+
+/*
+ *  ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one or more
+ *    contributor license agreements.  See the NOTICE file distributed with
+ *    this work for additional information regarding copyright ownership.
+ *    The ASF licenses this file to You under the Apache License, Version 2.0
+ *    (the "License"); you may not use this file except in compliance with
+ *    the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xwpf.usermodel;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.chart.AxisOrientation;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xwpf.usermodel.XWPFChart;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+
+/**
+ * Build a bar chart from a template docx
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class BarChartExample {
+    private BarChartExample() {}
+
+    private static void usage(){
+        System.out.println("Usage: BarChartExample <bar-chart-template.docx> <bar-chart-data.txt>");
+        System.out.println("    bar-chart-template.docx     template with a bar chart");
+        System.out.println("    bar-chart-data.txt          the model to set. First line is chart title, " +
+                "then go pairs {axis-label value}");
+    }
+
+    public static void main(String[] args) throws Exception {
+        if(args.length < 2) {
+            usage();
+            return;
+        }
+
+        try (FileInputStream argIS = new FileInputStream(args[0]);
+                BufferedReader modelReader = new BufferedReader(new FileReader(args[1]))) {
+
+            String chartTitle = modelReader.readLine();  // first line is chart title
+            String[] series = modelReader.readLine().split(",");
+
+            // Category Axis Data
+            List<String> listLanguages = new ArrayList<>(10);
+
+            // Values
+            List<Double> listCountries = new ArrayList<>(10);
+            List<Double> listSpeakers = new ArrayList<>(10);
+
+            // set model
+            String ln;
+            while((ln = modelReader.readLine()) != null) {
+                String[] vals = ln.split(",");
+                listCountries.add(Double.valueOf(vals[0]));
+                listSpeakers.add(Double.valueOf(vals[1]));
+                listLanguages.add(vals[2]);
+            }
+            String[] categories = listLanguages.toArray(new String[0]);
+            Double[] values1 = listCountries.toArray(new Double[0]);
+            Double[] values2 = listSpeakers.toArray(new Double[0]);
+
+            try (XWPFDocument doc = new XWPFDocument(argIS)) {
+                XWPFChart chart = doc.getCharts().get(0);
+                setBarData(chart, chartTitle, series, categories, values1, values2);
+                chart = doc.getCharts().get(1);
+                setColumnData(chart, "Column variant");
+
+                // save the result
+                try (OutputStream out = new FileOutputStream("bar-chart-demo-output.docx")) {
+                    doc.write(out);
+                }
+            }
+        }
+        System.out.println("Done");
+    }
+
+    private static void setBarData(XWPFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
+        final List<XDDFChartData> data = chart.getChartSeries();
+        final XDDFBarChartData bar = (XDDFBarChartData) data.get(0);
+
+        final int numOfPoints = categories.length;
+        final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
+        final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
+        final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
+        final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
+        final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, 1);
+        values1[6] = 16.0; // if you ever want to change the underlying data
+        final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);
+
+        XDDFChartData.Series series1 = bar.getSeries(0);
+        series1.replaceData(categoriesData, valuesData);
+        series1.setTitle(series[0], chart.setSheetTitle(series[0], 0));
+        XDDFChartData.Series series2 = bar.addSeries(categoriesData, valuesData2);
+        series2.setTitle(series[1], chart.setSheetTitle(series[1], 1));
+
+        chart.plot(bar);
+        chart.setTitleText(chartTitle); // https://stackoverflow.com/questions/30532612
+        chart.setTitleOverlay(false);
+    }
+
+    private static void setColumnData(XWPFChart chart, String chartTitle) {
+        // Series Text
+        List<XDDFChartData> series = chart.getChartSeries();
+        XDDFBarChartData bar = (XDDFBarChartData) series.get(0);
+
+        // in order to transform a bar chart into a column chart, you just need to change the bar direction
+        bar.setBarDirection(BarDirection.COL);
+
+        // looking for "Stacked Bar Chart"? uncomment the following line
+        // bar.setBarGrouping(BarGrouping.STACKED);
+
+        // additionally, you can adjust the axes
+        bar.getCategoryAxis().setOrientation(AxisOrientation.MAX_MIN);
+        bar.getValueAxes().get(0).setPosition(AxisPosition.TOP);
+    }
+}
+
diff --git a/src/examples/src/org/apache/poi/examples/xwpf/usermodel/BetterHeaderFooterExample.java b/src/examples/src/org/apache/poi/examples/xwpf/usermodel/BetterHeaderFooterExample.java
new file mode 100644 (file)
index 0000000..39c9d08
--- /dev/null
@@ -0,0 +1,56 @@
+/* ====================================================================
+   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.examples.xwpf.usermodel;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.wp.usermodel.HeaderFooterType;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFFooter;
+import org.apache.poi.xwpf.usermodel.XWPFHeader;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+
+public class BetterHeaderFooterExample {
+
+    public static void main(String[] args) throws IOException {
+        try (XWPFDocument doc = new XWPFDocument()) {
+
+            XWPFParagraph p = doc.createParagraph();
+
+            XWPFRun r = p.createRun();
+            r.setText("Some Text");
+            r.setBold(true);
+            r = p.createRun();
+            r.setText("Goodbye");
+
+            // create header/footer functions insert an empty paragraph
+            XWPFHeader head = doc.createHeader(HeaderFooterType.DEFAULT);
+            head.createParagraph().createRun().setText("header");
+
+            XWPFFooter foot = doc.createFooter(HeaderFooterType.DEFAULT);
+            foot.createParagraph().createRun().setText("footer");
+
+            try (OutputStream os = new FileOutputStream(new File("header2.docx"))) {
+                doc.write(os);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xwpf/usermodel/ChartFromScratch.java b/src/examples/src/org/apache/poi/examples/xwpf/usermodel/ChartFromScratch.java
new file mode 100644 (file)
index 0000000..9eb0e2d
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ *  ====================================================================
+ *    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.examples.xwpf.usermodel;
+
+import java.io.BufferedReader;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.chart.AxisCrossBetween;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.AxisTickMark;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.BarGrouping;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChart;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xwpf.usermodel.XWPFChart;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+
+/**
+ * Build a chart without reading template file
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class ChartFromScratch {
+    private ChartFromScratch() {}
+
+    private static void usage(){
+        System.out.println("Usage: ChartFromScratch <bar-chart-data.txt>");
+        System.out.println("    bar-chart-data.txt          the model to set. First line is chart title, " +
+                "then go pairs {axis-label value}");
+    }
+
+    public static void main(String[] args) throws Exception {
+        if(args.length < 1) {
+            usage();
+            return;
+        }
+
+        try (BufferedReader modelReader = new BufferedReader(new FileReader(args[0]))) {
+
+            String chartTitle = modelReader.readLine();  // first line is chart title
+            String[] series = modelReader.readLine().split(",");
+
+            // Category Axis Data
+            List<String> listLanguages = new ArrayList<>(10);
+
+            // Values
+            List<Double> listCountries = new ArrayList<>(10);
+            List<Double> listSpeakers = new ArrayList<>(10);
+
+            // set model
+            String ln;
+            while((ln = modelReader.readLine()) != null) {
+                String[] vals = ln.split(",");
+                listCountries.add(Double.valueOf(vals[0]));
+                listSpeakers.add(Double.valueOf(vals[1]));
+                listLanguages.add(vals[2]);
+            }
+
+            String[] categories = listLanguages.toArray(new String[0]);
+            Double[] values1 = listCountries.toArray(new Double[0]);
+            Double[] values2 = listSpeakers.toArray(new Double[0]);
+
+            try (XWPFDocument doc = new XWPFDocument();
+                 OutputStream out = new FileOutputStream("chart-from-scratch.docx")) {
+                XWPFChart chart = doc.createChart(XDDFChart.DEFAULT_WIDTH * 10, XDDFChart.DEFAULT_HEIGHT * 15);
+                setBarData(chart, chartTitle, series, categories, values1, values2);
+                // save the result
+                doc.write(out);
+            }
+        }
+        System.out.println("Done");
+    }
+
+    private static void setBarData(XWPFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
+        // Use a category axis for the bottom axis.
+        XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
+        bottomAxis.setTitle(series[2]);
+        XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+        leftAxis.setTitle(series[0]+","+series[1]);
+        leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
+        leftAxis.setMajorTickMark(AxisTickMark.OUT);
+        leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
+
+        final int numOfPoints = categories.length;
+        final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_LANGUAGES, COLUMN_LANGUAGES));
+        final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_COUNTRIES, COLUMN_COUNTRIES));
+        final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_SPEAKERS, COLUMN_SPEAKERS));
+        final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, COLUMN_LANGUAGES);
+        final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, COLUMN_COUNTRIES);
+        valuesData.setFormatCode("General");
+        values1[6] = 16.0; // if you ever want to change the underlying data, it has to be done before building the data source
+        final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, COLUMN_SPEAKERS);
+        valuesData2.setFormatCode("General");
+
+
+        XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
+        bar.setBarGrouping(BarGrouping.CLUSTERED);
+
+        XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData);
+        series1.setTitle(series[0], chart.setSheetTitle(series[0], COLUMN_COUNTRIES));
+
+        XDDFBarChartData.Series series2 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData2);
+        series2.setTitle(series[1], chart.setSheetTitle(series[1], COLUMN_SPEAKERS));
+
+        bar.setVaryColors(true);
+        bar.setBarDirection(BarDirection.COL);
+        chart.plot(bar);
+
+        XDDFChartLegend legend = chart.getOrAddLegend();
+        legend.setPosition(LegendPosition.LEFT);
+        legend.setOverlay(false);
+
+        chart.setTitleText(chartTitle);
+        chart.setTitleOverlay(false);
+        chart.setAutoTitleDeleted(false);
+    }
+
+    private static final int COLUMN_LANGUAGES = 0;
+    private static final int COLUMN_COUNTRIES = 1;
+    private static final int COLUMN_SPEAKERS = 2;
+}
+
diff --git a/src/examples/src/org/apache/poi/examples/xwpf/usermodel/HeaderFooterTable.java b/src/examples/src/org/apache/poi/examples/xwpf/usermodel/HeaderFooterTable.java
new file mode 100644 (file)
index 0000000..70d2b7e
--- /dev/null
@@ -0,0 +1,105 @@
+/* ====================================================================
+   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.examples.xwpf.usermodel;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+import org.apache.poi.wp.usermodel.HeaderFooterType;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFFooter;
+import org.apache.poi.xwpf.usermodel.XWPFHeader;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.apache.poi.xwpf.usermodel.XWPFTable;
+import org.apache.poi.xwpf.usermodel.XWPFTableCell;
+import org.apache.poi.xwpf.usermodel.XWPFTableRow;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGridCol;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblLayoutType;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblLayoutType;
+
+public class HeaderFooterTable {
+
+    public static void main(String[] args) throws IOException {
+        try (XWPFDocument doc = new XWPFDocument()) {
+
+            // Create a header with a 1 row, 3 column table
+            // changes made for issue 57366 allow a new header or footer
+            // to be created empty. This is a change. You will have to add
+            // either a paragraph or a table to the header or footer for
+            // the document to be considered valid.
+            XWPFHeader hdr = doc.createHeader(HeaderFooterType.DEFAULT);
+            XWPFTable tbl = hdr.createTable(1, 3);
+
+            // Set the padding around text in the cells to 1/10th of an inch
+            int pad = (int) (.1 * 1440);
+            tbl.setCellMargins(pad, pad, pad, pad);
+
+            // Set table width to 6.5 inches in 1440ths of a point
+            tbl.setWidth((int) (6.5 * 1440));
+            // Can not yet set table or cell width properly, tables default to
+            // autofit layout, and this requires fixed layout
+            CTTbl ctTbl = tbl.getCTTbl();
+            CTTblPr ctTblPr = ctTbl.addNewTblPr();
+            CTTblLayoutType layoutType = ctTblPr.addNewTblLayout();
+            layoutType.setType(STTblLayoutType.FIXED);
+
+            // Now set up a grid for the table, cells will fit into the grid
+            // Each cell width is 3120 in 1440ths of an inch, or 1/3rd of 6.5"
+            BigInteger w = new BigInteger("3120");
+            CTTblGrid grid = ctTbl.addNewTblGrid();
+            for (int i = 0; i < 3; i++) {
+                CTTblGridCol gridCol = grid.addNewGridCol();
+                gridCol.setW(w);
+            }
+
+            // Add paragraphs to the cells
+            XWPFTableRow row = tbl.getRow(0);
+            XWPFTableCell cell = row.getCell(0);
+            XWPFParagraph p = cell.getParagraphArray(0);
+            XWPFRun r = p.createRun();
+            r.setText("header left cell");
+
+            cell = row.getCell(1);
+            p = cell.getParagraphArray(0);
+            r = p.createRun();
+            r.setText("header center cell");
+
+            cell = row.getCell(2);
+            p = cell.getParagraphArray(0);
+            r = p.createRun();
+            r.setText("header right cell");
+
+            // Create a footer with a Paragraph
+            XWPFFooter ftr = doc.createFooter(HeaderFooterType.DEFAULT);
+            p = ftr.createParagraph();
+
+            r = p.createRun();
+            r.setText("footer text");
+
+            try (OutputStream os = new FileOutputStream(new File("headertable.docx"))) {
+                doc.write(os);
+            }
+        }
+       }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xwpf/usermodel/SimpleDocument.java b/src/examples/src/org/apache/poi/examples/xwpf/usermodel/SimpleDocument.java
new file mode 100644 (file)
index 0000000..5751554
--- /dev/null
@@ -0,0 +1,136 @@
+/* ====================================================================
+   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.examples.xwpf.usermodel;
+
+import java.io.FileOutputStream;
+
+import org.apache.poi.xwpf.usermodel.Borders;
+import org.apache.poi.xwpf.usermodel.BreakClear;
+import org.apache.poi.xwpf.usermodel.BreakType;
+import org.apache.poi.xwpf.usermodel.LineSpacingRule;
+import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
+import org.apache.poi.xwpf.usermodel.TextAlignment;
+import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
+import org.apache.poi.xwpf.usermodel.VerticalAlign;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFHyperlinkRun;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+
+/**
+ * A simple WOrdprocessingML document created by POI XWPF API
+ */
+public class SimpleDocument {
+
+    public static void main(String[] args) throws Exception {
+        try (XWPFDocument doc = new XWPFDocument()) {
+
+            XWPFParagraph p1 = doc.createParagraph();
+            p1.setAlignment(ParagraphAlignment.CENTER);
+            p1.setBorderBottom(Borders.DOUBLE);
+            p1.setBorderTop(Borders.DOUBLE);
+
+            p1.setBorderRight(Borders.DOUBLE);
+            p1.setBorderLeft(Borders.DOUBLE);
+            p1.setBorderBetween(Borders.SINGLE);
+
+            p1.setVerticalAlignment(TextAlignment.TOP);
+
+            XWPFRun r1 = p1.createRun();
+            r1.setBold(true);
+            r1.setText("The quick brown fox");
+            r1.setBold(true);
+            r1.setFontFamily("Courier");
+            r1.setUnderline(UnderlinePatterns.DOT_DOT_DASH);
+            r1.setTextPosition(100);
+
+            XWPFParagraph p2 = doc.createParagraph();
+            p2.setAlignment(ParagraphAlignment.RIGHT);
+
+            //BORDERS
+            p2.setBorderBottom(Borders.DOUBLE);
+            p2.setBorderTop(Borders.DOUBLE);
+            p2.setBorderRight(Borders.DOUBLE);
+            p2.setBorderLeft(Borders.DOUBLE);
+            p2.setBorderBetween(Borders.SINGLE);
+
+            XWPFRun r2 = p2.createRun();
+            r2.setText("jumped over the lazy dog");
+            r2.setStrikeThrough(true);
+            r2.setFontSize(20);
+
+            XWPFRun r3 = p2.createRun();
+            r3.setText("and went away");
+            r3.setStrikeThrough(true);
+            r3.setFontSize(20);
+            r3.setSubscript(VerticalAlign.SUPERSCRIPT);
+
+            // hyperlink
+            XWPFHyperlinkRun hyperlink = p2.insertNewHyperlinkRun(0, "http://poi.apache.org/");
+            hyperlink.setUnderline(UnderlinePatterns.SINGLE);
+            hyperlink.setColor("0000ff");
+            hyperlink.setText("Apache POI");
+
+            XWPFParagraph p3 = doc.createParagraph();
+            p3.setWordWrapped(true);
+            p3.setPageBreak(true);
+
+            //p3.setAlignment(ParagraphAlignment.DISTRIBUTE);
+            p3.setAlignment(ParagraphAlignment.BOTH);
+            p3.setSpacingBetween(15, LineSpacingRule.EXACT);
+
+            p3.setIndentationFirstLine(600);
+
+
+            XWPFRun r4 = p3.createRun();
+            r4.setTextPosition(20);
+            r4.setText("To be, or not to be: that is the question: "
+                    + "Whether 'tis nobler in the mind to suffer "
+                    + "The slings and arrows of outrageous fortune, "
+                    + "Or to take arms against a sea of troubles, "
+                    + "And by opposing end them? To die: to sleep; ");
+            r4.addBreak(BreakType.PAGE);
+            r4.setText("No more; and by a sleep to say we end "
+                    + "The heart-ache and the thousand natural shocks "
+                    + "That flesh is heir to, 'tis a consummation "
+                    + "Devoutly to be wish'd. To die, to sleep; "
+                    + "To sleep: perchance to dream: ay, there's the rub; "
+                    + ".......");
+            r4.setItalic(true);
+//This would imply that this break shall be treated as a simple line break, and break the line after that word:
+
+            XWPFRun r5 = p3.createRun();
+            r5.setTextPosition(-10);
+            r5.setText("For in that sleep of death what dreams may come");
+            r5.addCarriageReturn();
+            r5.setText("When we have shuffled off this mortal coil, "
+                    + "Must give us pause: there's the respect "
+                    + "That makes calamity of so long life;");
+            r5.addBreak();
+            r5.setText("For who would bear the whips and scorns of time, "
+                    + "The oppressor's wrong, the proud man's contumely,");
+
+            r5.addBreak(BreakClear.ALL);
+            r5.setText("The pangs of despised love, the law's delay, "
+                    + "The insolence of office and the spurns " + ".......");
+
+            try (FileOutputStream out = new FileOutputStream("simple.docx")) {
+                doc.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xwpf/usermodel/SimpleDocumentWithHeader.java b/src/examples/src/org/apache/poi/examples/xwpf/usermodel/SimpleDocumentWithHeader.java
new file mode 100644 (file)
index 0000000..659f6b6
--- /dev/null
@@ -0,0 +1,70 @@
+/* ====================================================================
+   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.examples.xwpf.usermodel;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
+
+/**
+ *
+ * @author Richard Ngo
+ *
+ */
+public class SimpleDocumentWithHeader {
+
+       public static void main(String[] args) throws IOException {
+               try (XWPFDocument doc = new XWPFDocument()) {
+
+                       XWPFParagraph p = doc.createParagraph();
+
+                       XWPFRun r = p.createRun();
+                       r.setText("Some Text");
+                       r.setBold(true);
+                       r = p.createRun();
+                       r.setText("Goodbye");
+
+                       CTP ctP = CTP.Factory.newInstance();
+                       CTText t = ctP.addNewR().addNewT();
+                       t.setStringValue("header");
+                       XWPFParagraph[] pars = new XWPFParagraph[1];
+                       p = new XWPFParagraph(ctP, doc);
+                       pars[0] = p;
+
+                       XWPFHeaderFooterPolicy hfPolicy = doc.createHeaderFooterPolicy();
+                       hfPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT, pars);
+
+                       ctP = CTP.Factory.newInstance();
+                       t = ctP.addNewR().addNewT();
+                       t.setStringValue("My Footer");
+                       pars[0] = new XWPFParagraph(ctP, doc);
+                       hfPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT, pars);
+
+                       try (OutputStream os = new FileOutputStream(new File("header.docx"))) {
+                               doc.write(os);
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/examples/xwpf/usermodel/SimpleImages.java b/src/examples/src/org/apache/poi/examples/xwpf/usermodel/SimpleImages.java
new file mode 100644 (file)
index 0000000..1f996cf
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *  ====================================================================
+ *    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.examples.xwpf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.util.Units;
+import org.apache.poi.xwpf.usermodel.BreakType;
+import org.apache.poi.xwpf.usermodel.Document;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+
+/**
+ * Demonstrates how to add pictures in a .docx document
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class SimpleImages {
+
+    private SimpleImages() {}
+
+    public static void main(String[] args) throws IOException, InvalidFormatException {
+        try (XWPFDocument doc = new XWPFDocument()) {
+            XWPFParagraph p = doc.createParagraph();
+
+            XWPFRun r = p.createRun();
+
+            for (String imgFile : args) {
+                int format;
+
+                if (imgFile.endsWith(".emf")) {
+                    format = Document.PICTURE_TYPE_EMF;
+                } else if (imgFile.endsWith(".wmf")) {
+                    format = Document.PICTURE_TYPE_WMF;
+                } else if (imgFile.endsWith(".pict")) {
+                    format = Document.PICTURE_TYPE_PICT;
+                } else if (imgFile.endsWith(".jpeg") || imgFile.endsWith(".jpg")) {
+                    format = Document.PICTURE_TYPE_JPEG;
+                } else if (imgFile.endsWith(".png")) {
+                    format = Document.PICTURE_TYPE_PNG;
+                } else if (imgFile.endsWith(".dib")) {
+                    format = Document.PICTURE_TYPE_DIB;
+                } else if (imgFile.endsWith(".gif")) {
+                    format = Document.PICTURE_TYPE_GIF;
+                } else if (imgFile.endsWith(".tiff")) {
+                    format = Document.PICTURE_TYPE_TIFF;
+                } else if (imgFile.endsWith(".eps")) {
+                    format = Document.PICTURE_TYPE_EPS;
+                } else if (imgFile.endsWith(".bmp")) {
+                    format = Document.PICTURE_TYPE_BMP;
+                } else if (imgFile.endsWith(".wpg")) {
+                    format = Document.PICTURE_TYPE_WPG;
+                } else {
+                    System.err.println("Unsupported picture: " + imgFile +
+                            ". Expected emf|wmf|pict|jpeg|png|dib|gif|tiff|eps|bmp|wpg");
+                    continue;
+                }
+
+                r.setText(imgFile);
+                r.addBreak();
+                try (FileInputStream is = new FileInputStream(imgFile)) {
+                    r.addPicture(is, format, imgFile, Units.toEMU(200), Units.toEMU(200)); // 200x200 pixels
+                }
+                r.addBreak(BreakType.PAGE);
+            }
+
+            try (FileOutputStream out = new FileOutputStream("images.docx")) {
+                doc.write(out);
+            }
+        }
+    }
+
+
+}
diff --git a/src/examples/src/org/apache/poi/examples/xwpf/usermodel/SimpleTable.java b/src/examples/src/org/apache/poi/examples/xwpf/usermodel/SimpleTable.java
new file mode 100644 (file)
index 0000000..2a67f8f
--- /dev/null
@@ -0,0 +1,199 @@
+/* ====================================================================
+   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.examples.xwpf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.List;
+
+import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
+import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.apache.poi.xwpf.usermodel.XWPFTable;
+import org.apache.poi.xwpf.usermodel.XWPFTableCell;
+import org.apache.poi.xwpf.usermodel.XWPFTableRow;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHeight;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShd;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTrPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVerticalJc;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STShd;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
+
+/**
+ * This program creates a simple WordprocessingML table using POI XWPF API, and
+ * a more complex, styled table using both XWPF and ooxml-schema. It's possible
+ * that not all referenced wordprocessingml classes are defined in
+ * poi-ooxml-schemas-3.8-beta4. If this is the case, you'll need to use the full
+ * ooxml-schemas.jar library.
+ *
+ * @author gisella bronzetti (original)
+ * @author Gregg Morris (styled table)
+ */
+public class SimpleTable {
+
+    public static void main(String[] args) throws Exception {
+       try {
+               createSimpleTable();
+       }
+       catch(Exception e) {
+               System.out.println("Error trying to create simple table.");
+               throw(e);
+       }
+       try {
+               createStyledTable();
+       }
+       catch(Exception e) {
+               System.out.println("Error trying to create styled table.");
+               throw(e);
+       }
+    }
+
+    public static void createSimpleTable() throws Exception {
+        try (XWPFDocument doc = new XWPFDocument()) {
+            XWPFTable table = doc.createTable(3, 3);
+
+            table.getRow(1).getCell(1).setText("EXAMPLE OF TABLE");
+
+            // table cells have a list of paragraphs; there is an initial
+            // paragraph created when the cell is created. If you create a
+            // paragraph in the document to put in the cell, it will also
+            // appear in the document following the table, which is probably
+            // not the desired result.
+            XWPFParagraph p1 = table.getRow(0).getCell(0).getParagraphs().get(0);
+
+            XWPFRun r1 = p1.createRun();
+            r1.setBold(true);
+            r1.setText("The quick brown fox");
+            r1.setItalic(true);
+            r1.setFontFamily("Courier");
+            r1.setUnderline(UnderlinePatterns.DOT_DOT_DASH);
+            r1.setTextPosition(100);
+
+            table.getRow(2).getCell(2).setText("only text");
+
+            try (OutputStream out = new FileOutputStream("simpleTable.docx")) {
+                doc.write(out);
+            }
+        }
+    }
+
+    /**
+     * Create a table with some row and column styling. I "manually" add the
+     * style name to the table, but don't check to see if the style actually
+     * exists in the document. Since I'm creating it from scratch, it obviously
+     * won't exist. When opened in MS Word, the table style becomes "Normal".
+     * I manually set alternating row colors. This could be done using Themes,
+     * but that's left as an exercise for the reader. The cells in the last
+     * column of the table have 10pt. "Courier" font.
+     * I make no claims that this is the "right" way to do it, but it worked
+     * for me. Given the scarcity of XWPF examples, I thought this may prove
+     * instructive and give you ideas for your own solutions.
+     */
+    public static void createStyledTable() throws Exception {
+       // Create a new document from scratch
+
+        try (XWPFDocument doc = new XWPFDocument()) {
+            // -- OR --
+            // open an existing empty document with styles already defined
+            //XWPFDocument doc = new XWPFDocument(new FileInputStream("base_document.docx"));
+
+            // Create a new table with 6 rows and 3 columns
+            int nRows = 6;
+            int nCols = 3;
+            XWPFTable table = doc.createTable(nRows, nCols);
+
+            // Set the table style. If the style is not defined, the table style
+            // will become "Normal".
+            CTTblPr tblPr = table.getCTTbl().getTblPr();
+            CTString styleStr = tblPr.addNewTblStyle();
+            styleStr.setVal("StyledTable");
+
+            // Get a list of the rows in the table
+            List<XWPFTableRow> rows = table.getRows();
+            int rowCt = 0;
+            int colCt = 0;
+            for (XWPFTableRow row : rows) {
+                // get table row properties (trPr)
+                CTTrPr trPr = row.getCtRow().addNewTrPr();
+                // set row height; units = twentieth of a point, 360 = 0.25"
+                CTHeight ht = trPr.addNewTrHeight();
+                ht.setVal(BigInteger.valueOf(360));
+
+                // get the cells in this row
+                List<XWPFTableCell> cells = row.getTableCells();
+                // add content to each cell
+                for (XWPFTableCell cell : cells) {
+                    // get a table cell properties element (tcPr)
+                    CTTcPr tcpr = cell.getCTTc().addNewTcPr();
+                    // set vertical alignment to "center"
+                    CTVerticalJc va = tcpr.addNewVAlign();
+                    va.setVal(STVerticalJc.CENTER);
+
+                    // create cell color element
+                    CTShd ctshd = tcpr.addNewShd();
+                    ctshd.setColor("auto");
+                    ctshd.setVal(STShd.CLEAR);
+                    if (rowCt == 0) {
+                        // header row
+                        ctshd.setFill("A7BFDE");
+                    } else if (rowCt % 2 == 0) {
+                        // even row
+                        ctshd.setFill("D3DFEE");
+                    } else {
+                        // odd row
+                        ctshd.setFill("EDF2F8");
+                    }
+
+                    // get 1st paragraph in cell's paragraph list
+                    XWPFParagraph para = cell.getParagraphs().get(0);
+                    // create a run to contain the content
+                    XWPFRun rh = para.createRun();
+                    // style cell as desired
+                    if (colCt == nCols - 1) {
+                        // last column is 10pt Courier
+                        rh.setFontSize(10);
+                        rh.setFontFamily("Courier");
+                    }
+                    if (rowCt == 0) {
+                        // header row
+                        rh.setText("header row, col " + colCt);
+                        rh.setBold(true);
+                        para.setAlignment(ParagraphAlignment.CENTER);
+                    } else {
+                        // other rows
+                        rh.setText("row " + rowCt + ", col " + colCt);
+                        para.setAlignment(ParagraphAlignment.LEFT);
+                    }
+                    colCt++;
+                } // for cell
+                colCt = 0;
+                rowCt++;
+            } // for row
+
+            // write the file
+            try (OutputStream out = new FileOutputStream("styledTable.docx")) {
+                doc.write(out);
+            }
+        }
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xwpf/usermodel/UpdateEmbeddedDoc.java b/src/examples/src/org/apache/poi/examples/xwpf/usermodel/UpdateEmbeddedDoc.java
new file mode 100644 (file)
index 0000000..faf31b3
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ *  ====================================================================
+ *    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.examples.xwpf.usermodel;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.ss.usermodel.Cell;
+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.WorkbookFactory;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+
+/**
+ * Tests whether it is possible to successfully update an Excel workbook that is
+ * embedded into a WordprocessingML document. Note that the test has currently
+ * only been conducted with a binary Excel workbook and NOT yet with a
+ * SpreadsheetML workbook embedded into the document.<p>
+ *
+ * This code was successfully tested with the following file from the POI test collection:
+ * http://svn.apache.org/repos/asf/poi/trunk/test-data/document/EmbeddedDocument.docx
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public class UpdateEmbeddedDoc {
+
+    private XWPFDocument doc;
+    private File docFile;
+
+    private static final int SHEET_NUM = 0;
+    private static final int ROW_NUM = 0;
+    private static final int CELL_NUM = 0;
+    private static final double NEW_VALUE = 100.98D;
+    private static final String BINARY_EXTENSION = "xls";
+    private static final String OPENXML_EXTENSION = "xlsx";
+
+    /**
+     * Create a new instance of the UpdateEmbeddedDoc class using the following
+     * parameters;
+     *
+     * @param filename An instance of the String class that encapsulates the name
+     *                 of and path to a WordprocessingML Word document that contains an
+     *                 embedded binary Excel workbook.
+     * @throws java.io.FileNotFoundException Thrown if the file cannot be found
+     *                                       on the underlying file system.
+     * @throws java.io.IOException           Thrown if a problem occurs in the underlying
+     *                                       file system.
+     */
+    public UpdateEmbeddedDoc(String filename) throws FileNotFoundException, IOException {
+        this.docFile = new File(filename);
+        if (!this.docFile.exists()) {
+            throw new FileNotFoundException("The Word document " + filename + " does not exist.");
+        }
+        try (FileInputStream fis = new FileInputStream(this.docFile)) {
+            // Open the Word document file and instantiate the XWPFDocument class.
+            this.doc = new XWPFDocument(fis);
+        }
+    }
+
+    /**
+     * Called to update the embedded Excel workbook. As the format and structure
+     * of the workbook are known in advance, all this code attempts to do is
+     * write a new value into the first cell on the first row of the first
+     * worksheet. Prior to executing this method, that cell will contain the
+     * value 1.
+     *
+     * @throws org.apache.poi.openxml4j.exceptions.OpenXML4JException
+     *                             Rather
+     *                             than use the specific classes (HSSF/XSSF) to handle the embedded
+     *                             workbook this method uses those defined in the SS stream. As
+     *                             a result, it might be the case that a SpreadsheetML file is
+     *                             opened for processing, throwing this exception if that file is
+     *                             invalid.
+     * @throws java.io.IOException Thrown if a problem occurs in the underlying
+     *                             file system.
+     */
+    public void updateEmbeddedDoc() throws OpenXML4JException, IOException {
+        List<PackagePart> embeddedDocs = this.doc.getAllEmbeddedParts();
+        for (PackagePart pPart : embeddedDocs) {
+            String ext = pPart.getPartName().getExtension();
+            if (BINARY_EXTENSION.equals(ext) || OPENXML_EXTENSION.equals(ext)) {
+                // Get an InputStream from the package part and pass that
+                // to the create method of the WorkbookFactory class. Update
+                // the resulting Workbook and then stream that out again
+                // using an OutputStream obtained from the same PackagePart.
+                try (InputStream is = pPart.getInputStream();
+                     Workbook workbook = WorkbookFactory.create(is);
+                     OutputStream os = pPart.getOutputStream()) {
+                    Sheet sheet = workbook.getSheetAt(SHEET_NUM);
+                    Row row = sheet.getRow(ROW_NUM);
+                    Cell cell = row.getCell(CELL_NUM);
+                    cell.setCellValue(NEW_VALUE);
+                    workbook.write(os);
+                }
+            }
+        }
+
+        if (!embeddedDocs.isEmpty()) {
+            // Finally, write the newly modified Word document out to file.
+            try (FileOutputStream fos = new FileOutputStream(this.docFile)) {
+                this.doc.write(fos);
+            }
+        }
+    }
+
+    /**
+     * Called to test whether or not the embedded workbook was correctly
+     * updated. This method simply recovers the first cell from the first row
+     * of the first workbook and tests the value it contains.
+     * <p>
+     * Note that execution will not continue up to the assertion as the
+     * embedded workbook is now corrupted and causes an IllegalArgumentException
+     * with the following message
+     * <p>
+     * <em>java.lang.IllegalArgumentException: Your InputStream was neither an
+     * OLE2 stream, nor an OOXML stream</em>
+     * <p>
+     * to be thrown when the WorkbookFactory.createWorkbook(InputStream) method
+     * is executed.
+     *
+     * @throws org.apache.poi.openxml4j.exceptions.OpenXML4JException
+     *                             Rather
+     *                             than use the specific classes (HSSF/XSSF) to handle the embedded
+     *                             workbook this method uses those defined in the SS stream. As
+     *                             a result, it might be the case that a SpreadsheetML file is
+     *                             opened for processing, throwing this exception if that file is
+     *                             invalid.
+     * @throws java.io.IOException Thrown if a problem occurs in the underlying
+     *                             file system.
+     */
+    public void checkUpdatedDoc() throws OpenXML4JException, IOException {
+        for (PackagePart pPart : this.doc.getAllEmbeddedParts()) {
+            String ext = pPart.getPartName().getExtension();
+            if (BINARY_EXTENSION.equals(ext) || OPENXML_EXTENSION.equals(ext)) {
+                try (InputStream is = pPart.getInputStream();
+                     Workbook workbook = WorkbookFactory.create(is)) {
+                    Sheet sheet = workbook.getSheetAt(SHEET_NUM);
+                    Row row = sheet.getRow(ROW_NUM);
+                    Cell cell = row.getCell(CELL_NUM);
+                    if(cell.getNumericCellValue() != NEW_VALUE) {
+                        throw new IllegalStateException("Failed to validate document content.");
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Code to test updating of the embedded Excel workbook.
+     */
+    public static void main(String[] args) throws IOException, OpenXML4JException {
+        UpdateEmbeddedDoc ued = new UpdateEmbeddedDoc(args[0]);
+        ued.updateEmbeddedDoc();
+        ued.checkUpdatedDoc();
+    }
+}
diff --git a/src/examples/src/org/apache/poi/examples/xwpf/usermodel/bar-chart-data.txt b/src/examples/src/org/apache/poi/examples/xwpf/usermodel/bar-chart-data.txt
new file mode 100644 (file)
index 0000000..22c7b86
--- /dev/null
@@ -0,0 +1,12 @@
+10 languages with most speakers as first language\r
+countries,speakers,language\r
+58,315,العربية\r
+4,243,বাংলা\r
+38,1299,中文\r
+118,378,English\r
+4,260,हिन्दी\r
+2,128,日本語\r
+15,223,português\r
+6,119,ਪੰਜਾਬੀ\r
+18,154,Русский язык\r
+31,442,español\r
diff --git a/src/examples/src/org/apache/poi/examples/xwpf/usermodel/bar-chart-template.docx b/src/examples/src/org/apache/poi/examples/xwpf/usermodel/bar-chart-template.docx
new file mode 100644 (file)
index 0000000..ddd57ef
Binary files /dev/null and b/src/examples/src/org/apache/poi/examples/xwpf/usermodel/bar-chart-template.docx differ
diff --git a/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java b/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java
deleted file mode 100644 (file)
index 567323d..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hpsf.examples;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-
-import org.apache.poi.hpsf.DocumentSummaryInformation;
-import org.apache.poi.hpsf.HPSFException;
-import org.apache.poi.hpsf.HPSFRuntimeException;
-import org.apache.poi.hpsf.PropertySet;
-import org.apache.poi.hpsf.PropertySetFactory;
-import org.apache.poi.hpsf.SummaryInformation;
-import org.apache.poi.hpsf.WritingNotSupportedException;
-import org.apache.poi.poifs.eventfilesystem.POIFSReader;
-import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
-import org.apache.poi.poifs.filesystem.DirectoryEntry;
-import org.apache.poi.poifs.filesystem.DocumentInputStream;
-import org.apache.poi.poifs.filesystem.EntryUtils;
-import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.util.TempFile;
-
-/**
- * <p>This class copies a POI file system to a new file and compares the copy
- * with the original.</p>
- * <p>
- * <p>Property set streams are copied logically, i.e. the application
- * establishes a {@link org.apache.poi.hpsf.PropertySet} of an original property
- * set, creates a {@link org.apache.poi.hpsf.PropertySet} and writes the
- * {@link org.apache.poi.hpsf.PropertySet} to the destination POI file
- * system. - Streams which are no property set streams are copied bit by
- * bit.</p>
- * <p>
- * <p>The comparison of the POI file systems is done logically. That means that
- * the two disk files containing the POI file systems do not need to be
- * exactly identical. However, both POI file systems must contain the same
- * files, and most of these files must be bitwise identical. Property set
- * streams, however, are compared logically: they must have the same sections
- * with the same attributes, and the sections must contain the same properties.
- * Details like the ordering of the properties do not matter.</p>
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public final class CopyCompare {
-    private CopyCompare() {}
-
-    /**
-     * Runs the example program. The application expects one or two arguments:
-     *
-     * <ol>
-     * <li>The first argument is the disk file name of the POI filesystem to copy.</li>
-     * <li>The second argument is optional. If it is given, it is the name of
-     * a disk file the copy of the POI filesystem will be written to. If it is
-     * not given, the copy will be written to a temporary file which will be
-     * deleted at the end of the program.</li>
-     * </ol>
-     *
-     * @param args Command-line arguments.
-     * @throws IOException                  if any I/O exception occurs.
-     * @throws UnsupportedEncodingException if a character encoding is not
-     *                                      supported.
-     */
-    public static void main(final String[] args) throws IOException {
-        String originalFileName = null;
-        String copyFileName = null;
-
-        // Check the command-line arguments.
-        if (args.length == 1) {
-            originalFileName = args[0];
-            File f = TempFile.createTempFile("CopyOfPOIFileSystem-", ".ole2");
-            f.deleteOnExit();
-            copyFileName = f.getAbsolutePath();
-        } else if (args.length == 2) {
-            originalFileName = args[0];
-            copyFileName = args[1];
-        } else {
-            System.err.println("Usage: CopyCompare originPOIFS [copyPOIFS]");
-            System.exit(1);
-        }
-
-
-        // Read the origin POIFS using the eventing API.
-        final POIFSReader r = new POIFSReader();
-        try (final POIFSFileSystem poiFs = new POIFSFileSystem();
-             OutputStream fos = new FileOutputStream(copyFileName)) {
-            r.registerListener(e -> handleEvent(poiFs, e));
-            r.setNotifyEmptyDirectories(true);
-
-            r.read(new File(originalFileName));
-
-            // Write the new POIFS to disk.
-            poiFs.writeFilesystem(fos);
-        }
-
-        // Read all documents from the original POI file system and compare them with
-        // the equivalent document from the copy.
-        try (POIFSFileSystem opfs = new POIFSFileSystem(new File(originalFileName));
-             POIFSFileSystem cpfs = new POIFSFileSystem(new File(copyFileName))) {
-            final DirectoryEntry oRoot = opfs.getRoot();
-            final DirectoryEntry cRoot = cpfs.getRoot();
-            System.out.println(EntryUtils.areDirectoriesIdentical(oRoot, cRoot) ? "Equal" : "Not equal");
-        }
-    }
-
-    private interface InputStreamSupplier {
-        InputStream get() throws IOException, WritingNotSupportedException;
-    }
-
-    /**
-     * The method is called by POI's eventing API for each file in the origin POIFS.
-     */
-    public static void handleEvent(final POIFSFileSystem poiFs, final POIFSReaderEvent event) {
-        // The following declarations are shortcuts for accessing the "event" object.
-        final DocumentInputStream stream = event.getStream();
-
-        try {
-
-            // Find out whether the current document is a property set stream or not.
-            InputStreamSupplier su;
-            if (stream != null && PropertySet.isPropertySetStream(stream)) {
-                // Yes, the current document is a property set stream. Let's create
-                // a PropertySet instance from it.
-                PropertySet ps = PropertySetFactory.create(stream);
-
-                // Copy the property set to the destination POI file system.
-                final PropertySet mps;
-                if (ps instanceof DocumentSummaryInformation) {
-                    mps = new DocumentSummaryInformation(ps);
-                } else if (ps instanceof SummaryInformation) {
-                    mps = new SummaryInformation(ps);
-                } else {
-                    mps = new PropertySet(ps);
-                }
-                su = mps::toInputStream;
-            } else {
-                // No, the current document is not a property set stream.
-                // We copy it unmodified to the destination POIFS.
-                su = event::getStream;
-            }
-
-            try (InputStream is = su.get()) {
-                final POIFSDocumentPath path = event.getPath();
-
-                // Ensures that the directory hierarchy for a document in a POI fileystem is in place.
-                // Get the root directory. It does not have to be created since it always exists in a POIFS.
-                DirectoryEntry de = poiFs.getRoot();
-                if (File.separator.equals(path.toString())) {
-                    de.setStorageClsid(event.getStorageClassId());
-                }
-
-                for (int i=0; i<path.length(); i++) {
-                    String subDir = path.getComponent(i);
-                    if (de.hasEntry(subDir)) {
-                        de = (DirectoryEntry)de.getEntry(subDir);
-                    } else {
-                        de = de.createDirectory(subDir);
-                        if (i == path.length()-1) {
-                            de.setStorageClsid(event.getStorageClassId());
-                        }
-                    }
-                }
-
-                if (event.getName() != null) {
-                    de.createDocument(event.getName(), is);
-                }
-            }
-
-        } catch (HPSFException | IOException ex) {
-            // According to the definition of the processPOIFSReaderEvent method we cannot pass checked
-            // exceptions to the caller.
-            throw new HPSFRuntimeException("Could not read file " + event.getPath() + "/" + event.getName(), ex);
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hpsf/examples/ModifyDocumentSummaryInformation.java b/src/examples/src/org/apache/poi/hpsf/examples/ModifyDocumentSummaryInformation.java
deleted file mode 100644 (file)
index 4171106..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hpsf.examples;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.Date;
-
-import org.apache.poi.hpsf.CustomProperties;
-import org.apache.poi.hpsf.DocumentSummaryInformation;
-import org.apache.poi.hpsf.PropertySetFactory;
-import org.apache.poi.hpsf.SummaryInformation;
-import org.apache.poi.poifs.filesystem.DirectoryEntry;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-
-/**
- * <p>This is a sample application showing how to easily modify properties in
- * the summary information and in the document summary information. The
- * application reads the name of a POI filesystem from the command line and
- * performs the following actions:</p>
- *
- * <ul>
- *
- * <li><p>Open the POI filesystem.</p></li>
- *
- * <li><p>Read the summary information.</p></li>
- *
- * <li><p>Read and print the "author" property.</p></li>
- *
- * <li><p>Change the author to "Rainer Klute".</p></li>
- *
- * <li><p>Read the document summary information.</p></li>
- *
- * <li><p>Read and print the "category" property.</p></li>
- *
- * <li><p>Change the category to "POI example".</p></li>
- *
- * <li><p>Read the custom properties (if available).</p></li>
- *
- * <li><p>Insert a new custom property.</p></li>
- *
- * <li><p>Write the custom properties back to the document summary
- * information.</p></li>
- *
- * <li><p>Write the summary information to the POI filesystem.</p></li>
- *
- * <li><p>Write the document summary information to the POI filesystem.</p></li>
- *
- * <li><p>Write the POI filesystem back to the original file.</p></li>
- *
- * </ol>
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public final class ModifyDocumentSummaryInformation {
-
-    private ModifyDocumentSummaryInformation() {}
-
-    /**
-     * <p>Main method - see class description.</p>
-     *
-     * @param args The command-line parameters.
-     */
-    public static void main(final String[] args) throws Exception {
-        /* Read the name of the POI filesystem to modify from the command line.
-         * For brevity to boundary check is performed on the command-line
-         * arguments. */
-        File summaryFile = new File(args[0]);
-
-        /* Open the POI filesystem. */
-        try (POIFSFileSystem poifs = new POIFSFileSystem(summaryFile, false)) {
-
-            /* Read the summary information. */
-            DirectoryEntry dir = poifs.getRoot();
-            SummaryInformation si;
-            try {
-                si = (SummaryInformation) PropertySetFactory.create(
-                        dir, SummaryInformation.DEFAULT_STREAM_NAME);
-            } catch (FileNotFoundException ex) {
-                // There is no summary information yet. We have to create a new one
-                si = PropertySetFactory.newSummaryInformation();
-            }
-            assert(si != null);
-
-            /* Change the author to "Rainer Klute". Any former author value will
-             * be lost. If there has been no author yet, it will be created. */
-            si.setAuthor("Rainer Klute");
-            System.out.println("Author changed to " + si.getAuthor() + ".");
-
-
-            /* Handling the document summary information is analogous to handling
-             * the summary information. An additional feature, however, are the
-             * custom properties. */
-
-            /* Read the document summary information. */
-            DocumentSummaryInformation dsi;
-            try {
-                dsi = (DocumentSummaryInformation) PropertySetFactory.create(
-                        dir, DocumentSummaryInformation.DEFAULT_STREAM_NAME);
-            } catch (FileNotFoundException ex) {
-                /* There is no document summary information yet. We have to create a
-                 * new one. */
-                dsi = PropertySetFactory.newDocumentSummaryInformation();
-            }
-            assert(dsi != null);
-
-            /* Change the category to "POI example". Any former category value will
-             * be lost. If there has been no category yet, it will be created. */
-            dsi.setCategory("POI example");
-            System.out.println("Category changed to " + dsi.getCategory() + ".");
-
-            /* Read the custom properties. If there are no custom properties yet,
-             * the application has to create a new CustomProperties object. It will
-             * serve as a container for custom properties. */
-            CustomProperties customProperties = dsi.getCustomProperties();
-            if (customProperties == null)
-                customProperties = new CustomProperties();
-
-            /* Insert some custom properties into the container. */
-            customProperties.put("Key 1", "Value 1");
-            customProperties.put("Schl\u00fcssel 2", "Wert 2");
-            customProperties.put("Sample Number", 12345);
-            customProperties.put("Sample Boolean", Boolean.TRUE);
-            customProperties.put("Sample Date", new Date());
-
-            /* Read a custom property. */
-            Object value = customProperties.get("Sample Number");
-            System.out.println("Custom Sample Number is now " + value);
-
-            /* Write the custom properties back to the document summary
-             * information. */
-            dsi.setCustomProperties(customProperties);
-
-            /* Write the summary information and the document summary information
-             * to the POI filesystem. */
-            si.write(dir, SummaryInformation.DEFAULT_STREAM_NAME);
-            dsi.write(dir, DocumentSummaryInformation.DEFAULT_STREAM_NAME);
-
-            /* Write the POI filesystem back to the original file. Please note that
-             * in production code you should take care when write directly to the
-             * origin, to make sure you don't loose things on error */
-            poifs.writeFilesystem();
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hpsf/examples/ReadCustomPropertySets.java b/src/examples/src/org/apache/poi/hpsf/examples/ReadCustomPropertySets.java
deleted file mode 100644 (file)
index fc8751b..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hpsf.examples;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-
-import org.apache.poi.hpsf.HPSFRuntimeException;
-import org.apache.poi.hpsf.NoPropertySetStreamException;
-import org.apache.poi.hpsf.Property;
-import org.apache.poi.hpsf.PropertySet;
-import org.apache.poi.hpsf.PropertySetFactory;
-import org.apache.poi.hpsf.Section;
-import org.apache.poi.poifs.eventfilesystem.POIFSReader;
-import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
-
-/**
- * <p>Sample application showing how to read a document's custom property set.
- * Call it with the document's file name as command-line parameter.</p>
- *
- * <p>Explanations can be found in the HPSF HOW-TO.</p>
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public final class ReadCustomPropertySets {
-
-    private ReadCustomPropertySets() {}
-
-    /**
-     * <p>Runs the example program.</p>
-     *
-     * @param args Command-line arguments (unused).
-     * @throws IOException if any I/O exception occurs.
-     */
-    public static void main(final String[] args) throws IOException {
-        final String filename = args[0];
-        POIFSReader r = new POIFSReader();
-
-        /* Register a listener for *all* documents. */
-        r.registerListener(ReadCustomPropertySets::processPOIFSReaderEvent);
-        r.read(new File(filename));
-    }
-
-
-    public static void processPOIFSReaderEvent(final POIFSReaderEvent event) {
-        final String streamName = event.getPath() + event.getName();
-        PropertySet ps;
-        try {
-            ps = PropertySetFactory.create(event.getStream());
-        } catch (NoPropertySetStreamException ex) {
-            out("No property set stream: \"" + streamName + "\"");
-            return;
-        } catch (Exception ex) {
-            throw new HPSFRuntimeException("Property set stream \"" + streamName + "\": " + ex);
-        }
-
-        /* Print the name of the property set stream: */
-        out("Property set stream \"" + streamName + "\":");
-
-        /* Print the number of sections: */
-        final long sectionCount = ps.getSectionCount();
-        out("   No. of sections: " + sectionCount);
-
-        /* Print the list of sections: */
-        List<Section> sections = ps.getSections();
-        int nr = 0;
-        for (Section sec : sections) {
-            /* Print a single section: */
-            out("   Section " + nr++ + ":");
-            String s = sec.getFormatID().toString();
-            s = s.substring(0, s.length() - 1);
-            out("      Format ID: " + s);
-
-            /* Print the number of properties in this section. */
-            int propertyCount = sec.getPropertyCount();
-            out("      No. of properties: " + propertyCount);
-
-            /* Print the properties: */
-            Property[] properties = sec.getProperties();
-            for (Property p : properties) {
-                /* Print a single property: */
-                long id = p.getID();
-                long type = p.getType();
-                Object value = p.getValue();
-                out("      Property ID: " + id + ", type: " + type +
-                        ", value: " + value);
-            }
-        }
-    }
-
-    private static void out(final String msg) {
-        System.out.println(msg);
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hpsf/examples/ReadTitle.java b/src/examples/src/org/apache/poi/hpsf/examples/ReadTitle.java
deleted file mode 100644 (file)
index 1072064..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hpsf.examples;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.apache.poi.hpsf.PropertySetFactory;
-import org.apache.poi.hpsf.SummaryInformation;
-import org.apache.poi.poifs.eventfilesystem.POIFSReader;
-import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
-
-/**
- * <p>Sample application showing how to read a OLE 2 document's
- * title. Call it with the document's file name as command line
- * parameter.</p>
- *
- * <p>Explanations can be found in the HPSF HOW-TO.</p>
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public final class ReadTitle {
-    private ReadTitle() {}
-
-    /**
-     * <p>Runs the example program.</p>
-     *
-     * @param args Command-line arguments. The first command-line argument must
-     * be the name of a POI filesystem to read.
-     * @throws IOException if any I/O exception occurs.
-     */
-    public static void main(final String[] args) throws IOException {
-        final String filename = args[0];
-        POIFSReader r = new POIFSReader();
-        r.registerListener(ReadTitle::processPOIFSReaderEvent, SummaryInformation.DEFAULT_STREAM_NAME);
-        r.read(new File(filename));
-    }
-
-
-    private static void processPOIFSReaderEvent(final POIFSReaderEvent event) {
-        SummaryInformation si;
-        try {
-            si = (SummaryInformation) PropertySetFactory.create(event.getStream());
-        } catch (Exception ex) {
-            throw new RuntimeException("Property set stream \"" + event.getPath() + event.getName() + "\": " + ex);
-        }
-        final String title = si.getTitle();
-        System.out.println(title != null ? "Title: \"" + title + "\"" : "Document has no title.");
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java b/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java
deleted file mode 100644 (file)
index ce51773..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hpsf.examples;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.apache.poi.hpsf.HPSFRuntimeException;
-import org.apache.poi.hpsf.MarkUnsupportedException;
-import org.apache.poi.hpsf.NoPropertySetStreamException;
-import org.apache.poi.hpsf.PropertySet;
-import org.apache.poi.hpsf.PropertySetFactory;
-import org.apache.poi.hpsf.Section;
-import org.apache.poi.hpsf.SummaryInformation;
-import org.apache.poi.hpsf.Variant;
-import org.apache.poi.hpsf.WritingNotSupportedException;
-import org.apache.poi.hpsf.wellknown.PropertyIDMap;
-import org.apache.poi.poifs.eventfilesystem.POIFSReader;
-import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
-import org.apache.poi.poifs.filesystem.DirectoryEntry;
-import org.apache.poi.poifs.filesystem.DocumentInputStream;
-import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-
-/**
- * <p>This class is a sample application which shows how to write or modify the
- * author and title property of an OLE 2 document. This could be done in two
- * different ways:</p>
- *
- * <ul>
- *
- * <li><p>The first approach is to open the OLE 2 file as a POI filesystem
- * (see class {@link POIFSFileSystem}), read the summary information property
- * set (see classes {@link SummaryInformation} and {@link PropertySet}), write
- * the author and title properties into it and write the property set back into
- * the POI filesystem.</p></li>
- *
- * <li><p>The second approach does not modify the original POI filesystem, but
- * instead creates a new one. All documents from the original POIFS are copied
- * to the destination POIFS, except for the summary information stream. The
- * latter is modified by setting the author and title property before writing
- * it to the destination POIFS. It there are several summary information streams
- * in the original POIFS - e.g. in subordinate directories - they are modified
- * just the same.</p></li>
- *
- * </ul>
- *
- * <p>This sample application takes the second approach. It expects the name of
- * the existing POI filesystem's name as its first command-line parameter and
- * the name of the output POIFS as the second command-line argument. The
- * program then works as described above: It copies nearly all documents
- * unmodified from the input POI filesystem to the output POI filesystem. If it
- * encounters a summary information stream it reads its properties. Then it sets
- * the "author" and "title" properties to new values and writes the modified
- * summary information stream into the output file.</p>
- *
- * <p>Further explanations can be found in the HPSF HOW-TO.</p>
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public final class WriteAuthorAndTitle {
-    private WriteAuthorAndTitle() {}
-
-    /**
-     * <p>Runs the example program.</p>
-     *
-     * @param args Command-line arguments. The first command-line argument must
-     * be the name of a POI filesystem to read.
-     * @throws IOException if any I/O exception occurs.
-     */
-    public static void main(final String[] args) throws IOException {
-        /* Check whether we have exactly two command-line arguments. */
-        if (args.length != 2) {
-            System.err.println("Usage: WriteAuthorAndTitle originPOIFS destinationPOIFS");
-            System.exit(1);
-        }
-
-        /* Read the names of the origin and destination POI filesystems. */
-        final String srcName = args[0];
-        final String dstName = args[1];
-
-        /* Read the origin POIFS using the eventing API. The real work is done
-         * in the class ModifySICopyTheRest which is registered here as a
-         * POIFSReader. */
-        try (POIFSFileSystem poifs = new POIFSFileSystem();
-             OutputStream out = new FileOutputStream(dstName)) {
-            final POIFSReader r = new POIFSReader();
-            r.registerListener(e -> handleEvent(poifs, e));
-            r.read(new File(srcName));
-
-            /* Write the new POIFS to disk. */
-            poifs.writeFilesystem(out);
-        }
-    }
-
-    private interface InputStreamSupplier {
-        InputStream get() throws IOException, WritingNotSupportedException;
-    }
-
-    /**
-     * The method is called by POI's eventing API for each file in the origin POIFS.
-     */
-    private static void handleEvent(final POIFSFileSystem poiFs, final POIFSReaderEvent event) {
-        // The following declarations are shortcuts for accessing the "event" object.
-        final DocumentInputStream stream = event.getStream();
-
-        try {
-            final InputStreamSupplier isSup;
-
-            // Find out whether the current document is a property set stream or not.
-            if (PropertySet.isPropertySetStream(stream)) {
-                // Yes, the current document is a property set stream. Let's create a PropertySet instance from it.
-                PropertySet ps = PropertySetFactory.create(stream);
-
-                // Now we know that we really have a property set.
-                // The next step is to find out whether it is a summary information or not.
-                if (ps.isSummaryInformation()) {
-                    // Create a mutable property set as a copy of the original read-only property set.
-                    ps = new PropertySet(ps);
-
-                    // Retrieve the section containing the properties to modify.
-                    // A summary information property set contains exactly one section.
-                    final Section s = ps.getSections().get(0);
-
-                    // Set the properties.
-                    s.setProperty(PropertyIDMap.PID_AUTHOR, Variant.VT_LPSTR, "Rainer Klute");
-                    s.setProperty(PropertyIDMap.PID_TITLE, Variant.VT_LPWSTR, "Test");
-                }
-
-                isSup = ps::toInputStream;
-            } else {
-                // No, the current document is not a property set stream. We copy it unmodified to the destination POIFS.
-                isSup = event::getStream;
-            }
-
-            try (InputStream is = isSup.get()) {
-                final POIFSDocumentPath path = event.getPath();
-
-                // Ensures that the directory hierarchy for a document in a POI fileystem is in place.
-                // Get the root directory. It does not have to be created since it always exists in a POIFS.
-                DirectoryEntry de = poiFs.getRoot();
-
-                for (int i=0; i<path.length(); i++) {
-                    String subDir = path.getComponent(i);
-                    de = (de.hasEntry(subDir)) ? (DirectoryEntry)de.getEntry(subDir) : de.createDirectory(subDir);
-                }
-
-                de.createDocument(event.getName(), is);
-            }
-
-        } catch (MarkUnsupportedException | WritingNotSupportedException | IOException | NoPropertySetStreamException ex) {
-            // According to the definition of the processPOIFSReaderEvent method we cannot pass checked
-            // exceptions to the caller.
-            throw new HPSFRuntimeException("Could not read file " + event.getPath() + "/" + event.getName(), ex);
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hpsf/examples/WriteTitle.java b/src/examples/src/org/apache/poi/hpsf/examples/WriteTitle.java
deleted file mode 100644 (file)
index 8fd505f..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hpsf.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.poi.hpsf.Property;
-import org.apache.poi.hpsf.PropertySet;
-import org.apache.poi.hpsf.Section;
-import org.apache.poi.hpsf.SummaryInformation;
-import org.apache.poi.hpsf.Variant;
-import org.apache.poi.hpsf.WritingNotSupportedException;
-import org.apache.poi.hpsf.wellknown.PropertyIDMap;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-
-/**
- * <p>This class is a simple sample application showing how to create a property
- * set and write it to disk.</p>
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public final class WriteTitle {
-
-    private WriteTitle() {}
-
-    /**
-     * <p>Runs the example program.</p>
-     *
-     * @param args Command-line arguments. The first and only command-line
-     * argument is the name of the POI file system to create.
-     * @throws IOException if any I/O exception occurs.
-     * @throws WritingNotSupportedException if HPSF does not (yet) support
-     * writing a certain property type.
-     */
-    public static void main(final String[] args)
-    throws WritingNotSupportedException, IOException
-    {
-        /* Check whether we have exactly one command-line argument. */
-        if (args.length != 1)
-        {
-            System.err.println("Usage: " + WriteTitle.class.getName() + "destinationPOIFS");
-            System.exit(1);
-        }
-
-        final String fileName = args[0];
-
-        /* Create a mutable property set. Initially it contains a single section
-         * with no properties. */
-        final PropertySet mps = new PropertySet();
-
-        /* Retrieve the section the property set already contains. */
-        final Section ms = mps.getSections().get(0);
-
-        /* Turn the property set into a summary information property. This is
-         * done by setting the format ID of its first section to
-         * SectionIDMap.SUMMARY_INFORMATION_ID. */
-        ms.setFormatID(SummaryInformation.FORMAT_ID);
-
-        /* Create an empty property. */
-        final Property p = new Property();
-
-        /* Fill the property with appropriate settings so that it specifies the
-         * document's title. */
-        p.setID(PropertyIDMap.PID_TITLE);
-        p.setType(Variant.VT_LPWSTR);
-        p.setValue("Sample title");
-
-        /* Place the property into the section. */
-        ms.setProperty(p);
-
-        /* Create the POI file system the property set is to be written to.
-         * For writing the property set into a POI file system it has to be
-         * handed over to the POIFS.createDocument() method as an input stream
-         * which produces the bytes making out the property set stream. */
-        try (final POIFSFileSystem poiFs = new POIFSFileSystem();
-             final InputStream is = mps.toInputStream();
-             final FileOutputStream fos = new FileOutputStream(fileName)) {
-
-            /* Create the summary information property set in the POI file
-             * system. It is given the default name most (if not all) summary
-             * information property sets have. */
-            poiFs.createDocument(is, SummaryInformation.DEFAULT_STREAM_NAME);
-
-            /* Write the whole POI file system to a disk file. */
-            poiFs.writeFilesystem(fos);
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java b/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java
deleted file mode 100644 (file)
index 73871cb..0000000
+++ /dev/null
@@ -1,460 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hslf.examples;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.geom.Rectangle2D;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.List;
-
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.sl.draw.DrawTableShape;
-import org.apache.poi.sl.draw.SLGraphics;
-import org.apache.poi.sl.usermodel.AutoShape;
-import org.apache.poi.sl.usermodel.GroupShape;
-import org.apache.poi.sl.usermodel.ShapeType;
-import org.apache.poi.sl.usermodel.Slide;
-import org.apache.poi.sl.usermodel.SlideShow;
-import org.apache.poi.sl.usermodel.TableCell;
-import org.apache.poi.sl.usermodel.TableShape;
-import org.apache.poi.sl.usermodel.TextBox;
-import org.apache.poi.sl.usermodel.TextParagraph;
-import org.apache.poi.sl.usermodel.TextRun;
-import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
-import org.apache.poi.sl.usermodel.VerticalAlignment;
-
-/**
- * Presentation for Fast Feather Track on ApacheconEU 2008
- *
- * @author Yegor Kozlov
- */
-@SuppressWarnings("java:S1192")
-public final class ApacheconEU08 {
-
-    private ApacheconEU08() {}
-
-    public static void main(String[] args) throws IOException {
-        // use HSLFSlideShow or XMLSlideShow
-        try (SlideShow<?,?> ppt = new HSLFSlideShow()) {
-            ppt.setPageSize(new Dimension(720, 540));
-
-            slide1(ppt);
-            slide2(ppt);
-            slide3(ppt);
-            slide4(ppt);
-            slide5(ppt);
-            slide6(ppt);
-            slide7(ppt);
-            slide8(ppt);
-            slide9(ppt);
-            slide10(ppt);
-            slide11(ppt);
-            slide12(ppt);
-
-            String ext = ppt.getClass().getName().contains("HSLF") ? "ppt" : "pptx";
-            try (FileOutputStream out = new FileOutputStream("apachecon_eu_08." + ext)) {
-                ppt.write(out);
-            }
-        }
-    }
-
-    public static void slide1(SlideShow<?,?> ppt) throws IOException {
-        Slide<?,?> slide = ppt.createSlide();
-
-        TextBox<?,?> box1 = slide.createTextBox();
-        box1.setTextPlaceholder(TextPlaceholder.CENTER_TITLE);
-        box1.setText("POI-HSLF");
-        box1.setAnchor(new Rectangle(54, 78, 612, 115));
-
-        TextBox<?,?> box2 = slide.createTextBox();
-        box2.setTextPlaceholder(TextPlaceholder.CENTER_BODY);
-        box2.setText("Java API To Access Microsoft PowerPoint Format Files");
-        box2.setAnchor(new Rectangle(108, 204, 504, 138));
-
-        TextBox<?,?> box3 = slide.createTextBox();
-        box3.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(32d);
-        box3.setText(
-                "Yegor Kozlov\r" +
-                "yegor - apache - org");
-        box3.setHorizontalCentered(true);
-        box3.setAnchor(new Rectangle(206, 348, 310, 84));
-    }
-
-    public static void slide2(SlideShow<?,?> ppt) throws IOException {
-        Slide<?,?> slide = ppt.createSlide();
-
-        TextBox<?,?> box1 = slide.createTextBox();
-        box1.setTextPlaceholder(TextPlaceholder.TITLE);
-        box1.setText("What is HSLF?");
-        box1.setAnchor(new Rectangle(36, 21, 648, 90));
-
-        TextBox<?,?> box2 = slide.createTextBox();
-        box2.setTextPlaceholder(TextPlaceholder.BODY);
-        box2.setText("HorribleSLideshowFormat is the POI Project's pure Java implementation " +
-                "of the Powerpoint binary file format. \r" +
-                "POI sub-project since 2005\r" +
-                "Started by Nick Burch, Yegor Kozlov joined soon after");
-        box2.setAnchor(new Rectangle(36, 126, 648, 356));
-    }
-
-    public static void slide3(SlideShow<?,?> ppt) throws IOException {
-        Slide<?,?> slide = ppt.createSlide();
-
-        TextBox<?,?> box1 = slide.createTextBox();
-        box1.setTextPlaceholder(TextPlaceholder.TITLE);
-        box1.setText("HSLF in a Nutshell");
-        box1.setAnchor(new Rectangle(36, 15, 648, 65));
-
-        TextBox<?,?> box2 = slide.createTextBox();
-        box2.setTextPlaceholder(TextPlaceholder.BODY);
-        box2.setText(
-            "HSLF provides a way to read, create and modify MS PowerPoint presentations\r" +
-            "Pure Java API - you don't need PowerPoint to read and write *.ppt files\r" +
-            "Comprehensive support of PowerPoint objects\r" +
-                "Rich text\r" +
-                "Tables\r" +
-                "Shapes\r" +
-                "Pictures\r" +
-                "Master slides\r" +
-            "Access to low level data structures"
-        );
-
-        List<? extends TextParagraph<?,?,?>> tp = box2.getTextParagraphs();
-        for (int i : new byte[]{0,1,2,8}) {
-            tp.get(i).getTextRuns().get(0).setFontSize(28d);
-        }
-        for (int i : new byte[]{3,4,5,6,7}) {
-            tp.get(i).getTextRuns().get(0).setFontSize(24d);
-            tp.get(i).setIndentLevel(1);
-        }
-        box2.setAnchor(new Rectangle(36, 80, 648, 400));
-    }
-
-    public static void slide4(SlideShow<?,?> ppt) throws IOException {
-        Slide<?,?> slide = ppt.createSlide();
-
-        String[][] txt1 = {
-            {"Note"},
-            {"This presentation was created programmatically using POI HSLF"}
-        };
-        TableShape<?,?> table1 = slide.createTable(2, 1);
-        for (int i = 0; i < txt1.length; i++) {
-            for (int j = 0; j < txt1[i].length; j++) {
-                TableCell<?,?> cell = table1.getCell(i, j);
-                cell.setText(txt1[i][j]);
-                TextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
-                rt.setFontSize(10d);
-                rt.setFontFamily("Arial");
-                rt.setBold(true);
-                if(i == 0){
-                    rt.setFontSize(32d);
-                    rt.setFontColor(Color.white);
-                    cell.setFillColor(new Color(0, 153, 204));
-                } else {
-                    rt.setFontSize(28d);
-                    cell.setFillColor(new Color(235, 239, 241));
-                }
-                cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
-            }
-        }
-
-        DrawTableShape dts = new DrawTableShape(table1);
-        dts.setAllBorders(1.0, Color.black);
-        dts.setOutsideBorders(4.0);
-
-        table1.setColumnWidth(0, 450);
-        table1.setRowHeight(0, 50);
-        table1.setRowHeight(1, 80);
-
-        Dimension dim = ppt.getPageSize();
-        Rectangle2D oldAnchor = table1.getAnchor();
-        table1.setAnchor(new Rectangle2D.Double((dim.width-450)/2d, 100, oldAnchor.getWidth(), oldAnchor.getHeight()));
-
-        TextBox<?,?> box1 = slide.createTextBox();
-        box1.setHorizontalCentered(true);
-        box1.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(24d);
-        box1.setText("The source code is available at\r" +
-                "http://people.apache.org/~yegor/apachecon_eu08/");
-        box1.setAnchor(new Rectangle(80, 356, 553, 65));
-    }
-
-    public static void slide5(SlideShow<?,?> ppt) throws IOException {
-        Slide<?,?> slide = ppt.createSlide();
-
-        TextBox<?,?> box1 = slide.createTextBox();
-        box1.setTextPlaceholder(TextPlaceholder.TITLE);
-        box1.setText("HSLF in Action - 1\rData Extraction");
-        box1.setAnchor(new Rectangle(36, 21, 648, 100));
-
-        TextBox<?,?> box2 = slide.createTextBox();
-        box2.setTextPlaceholder(TextPlaceholder.BODY);
-        box2.setText(
-                "Text from slides and notes\r" +
-                "Images\r" +
-                "Shapes and their properties (type, position in the slide, color, font, etc.)");
-        box2.setAnchor(new Rectangle(36, 150, 648, 300));
-    }
-
-    public static void slide6(SlideShow<?,?> ppt) throws IOException {
-        Slide<?,?> slide = ppt.createSlide();
-
-        TextBox<?,?> box1 = slide.createTextBox();
-        box1.setTextPlaceholder(TextPlaceholder.TITLE);
-        box1.setText("HSLF in Action - 2");
-        box1.setAnchor(new Rectangle(36, 20, 648, 90));
-
-        TextBox<?,?> box2 = slide.createTextBox();
-        box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(18d);
-        box2.setText("Creating a simple presentation from scratch");
-        box2.setAnchor(new Rectangle(170, 100, 364, 30));
-
-        TextBox<?,?> box3 = slide.createTextBox();
-        TextRun rt3 = box3.getTextParagraphs().get(0).getTextRuns().get(0);
-        rt3.setFontFamily("Courier New");
-        rt3.setFontSize(8d);
-        box3.setText(
-                "SlideShow ppt = new SlideShow();\u000b" +
-                "Slide slide = ppt.createSlide();\u000b" +
-                "\u000b" +
-                "TextBox box2 = new TextBox();\u000b" +
-                "box2.setHorizontalAlignment(TextBox.AlignCenter);\u000b" +
-                "box2.setVerticalAlignment(TextBox.AnchorMiddle);\u000b" +
-                "box2.getTextRun().setText(\"Java Code\");\u000b" +
-                "box2.getFill().setForegroundColor(new Color(187, 224, 227));\u000b" +
-                "box2.setLineColor(Color.black);\u000b" +
-                "box2.setLineWidth(0.75);\u000b" +
-                "box2.setAnchor(new Rectangle(66, 243, 170, 170));\u000b" +
-                "slide.addShape(box2);\u000b" +
-                "\u000b" +
-                "TextBox box3 = new TextBox();\u000b" +
-                "box3.setHorizontalAlignment(TextBox.AlignCenter);\u000b" +
-                "box3.setVerticalAlignment(TextBox.AnchorMiddle);\u000b" +
-                "box3.getTextRun().setText(\"*.ppt file\");\u000b" +
-                "box3.setLineWidth(0.75);\u000b" +
-                "box3.setLineColor(Color.black);\u000b" +
-                "box3.getFill().setForegroundColor(new Color(187, 224, 227));\u000b" +
-                "box3.setAnchor(new Rectangle(473, 243, 170, 170));\u000b" +
-                "slide.addShape(box3);\u000b" +
-                "\u000b" +
-                "AutoShape box4 = new AutoShape(ShapeTypes.Arrow);\u000b" +
-                "box4.getFill().setForegroundColor(new Color(187, 224, 227));\u000b" +
-                "box4.setLineWidth(0.75);\u000b" +
-                "box4.setLineColor(Color.black);\u000b" +
-                "box4.setAnchor(new Rectangle(253, 288, 198, 85));\u000b" +
-                "slide.addShape(box4);\u000b" +
-                "\u000b" +
-                "FileOutputStream out = new FileOutputStream(\"hslf-demo.ppt\");\u000b" +
-                "ppt.write(out);\u000b" +
-                "out.close();");
-        box3.setAnchor(new Rectangle(30, 150, 618, 411));
-        box3.setHorizontalCentered(true);
-    }
-
-    public static void slide7(SlideShow<?,?> ppt) throws IOException {
-        Slide<?,?> slide = ppt.createSlide();
-
-        TextBox<?,?> box2 = slide.createTextBox();
-        box2.setHorizontalCentered(true);
-        box2.setVerticalAlignment(VerticalAlignment.MIDDLE);
-        box2.setText("Java Code");
-        box2.setFillColor(new Color(187, 224, 227));
-        box2.setStrokeStyle(0.75, Color.black);
-        box2.setAnchor(new Rectangle(66, 243, 170, 170));
-
-        TextBox<?,?> box3 = slide.createTextBox();
-        box3.setHorizontalCentered(true);
-        box3.setVerticalAlignment(VerticalAlignment.MIDDLE);
-        box3.setText("*.ppt file");
-        box3.setFillColor(new Color(187, 224, 227));
-        box3.setStrokeStyle(0.75, Color.black);
-        box3.setAnchor(new Rectangle(473, 243, 170, 170));
-
-        AutoShape<?,?> box4 = slide.createAutoShape();
-        box4.setShapeType(ShapeType.RIGHT_ARROW);
-        box4.setFillColor(new Color(187, 224, 227));
-        box4.setStrokeStyle(0.75, Color.black);
-        box4.setAnchor(new Rectangle(253, 288, 198, 85));
-    }
-
-    public static void slide8(SlideShow<?,?> ppt) throws IOException {
-        Slide<?,?> slide = ppt.createSlide();
-
-        TextBox<?,?> box1 = slide.createTextBox();
-        box1.setTextPlaceholder(TextPlaceholder.TITLE);
-        box1.setText("Wait, there is more!");
-        box1.setAnchor(new Rectangle(36, 21, 648, 90));
-
-        TextBox<?,?> box2 = slide.createTextBox();
-        box2.setTextPlaceholder(TextPlaceholder.BODY);
-        box2.setText(
-                "Rich text\r" +
-                "Tables\r" +
-                "Pictures (JPEG, PNG, BMP, WMF, PICT)\r" +
-                "Comprehensive formatting features");
-        box2.setAnchor(new Rectangle(36, 126, 648, 356));
-    }
-
-    public static void slide9(SlideShow<?,?> ppt) throws IOException {
-        Slide<?,?> slide = ppt.createSlide();
-
-        TextBox<?,?> box1 = slide.createTextBox();
-        box1.setTextPlaceholder(TextPlaceholder.TITLE);
-        box1.setText("HSLF in Action - 3");
-        box1.setAnchor(new Rectangle(36, 20, 648, 50));
-
-        TextBox<?,?> box2 = slide.createTextBox();
-        box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(18d);
-        box2.setText("PPGraphics2D: PowerPoint Graphics2D driver");
-        box2.setAnchor(new Rectangle(178, 70, 387, 30));
-
-        TextBox<?,?> box3 = slide.createTextBox();
-        TextRun rt3 = box3.getTextParagraphs().get(0).getTextRuns().get(0);
-        rt3.setFontFamily("Courier New");
-        rt3.setFontSize(8d);
-        box3.setText(
-                "//bar chart data. The first value is the bar color, the second is the width\u000b" +
-                "Object[] def = new Object[]{\u000b" +
-                "    Color.yellow, new Integer(100),\u000b" +
-                "    Color.green, new Integer(150),\u000b" +
-                "    Color.gray, new Integer(75),\u000b" +
-                "    Color.red, new Integer(200),\u000b" +
-                "};\u000b" +
-                "\u000b" +
-                "SlideShow ppt = new SlideShow();\u000b" +
-                "Slide slide = ppt.createSlide();\u000b" +
-                "\u000b" +
-                "ShapeGroup group = new ShapeGroup();\u000b" +
-                "//define position of the drawing in the slide\u000b" +
-                "Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);\u000b" +
-                "group.setAnchor(bounds);\u000b" +
-                "slide.addShape(group);\u000b" +
-                "Graphics2D graphics = new PPGraphics2D(group);\u000b" +
-                "\u000b" +
-                "//draw a simple bar graph\u000b" +
-                "int x = bounds.x + 50, y = bounds.y + 50;\u000b" +
-                "graphics.setFont(new Font(\"Arial\", Font.BOLD, 10));\u000b" +
-                "for (int i = 0, idx = 1; i < def.length; i+=2, idx++) {\u000b" +
-                "    graphics.setColor(Color.black);\u000b" +
-                "    int width = ((Integer)def[i+1]).intValue();\u000b" +
-                "    graphics.drawString(\"Q\" + idx, x-20, y+20);\u000b" +
-                "    graphics.drawString(width + \"%\", x + width + 10, y + 20);\u000b" +
-                "    graphics.setColor((Color)def[i]);\u000b" +
-                "    graphics.fill(new Rectangle(x, y, width, 30));\u000b" +
-                "    y += 40;\u000b" +
-                "}\u000b" +
-                "graphics.setColor(Color.black);\u000b" +
-                "graphics.setFont(new Font(\"Arial\", Font.BOLD, 14));\u000b" +
-                "graphics.draw(bounds);\u000b" +
-                "graphics.drawString(\"Performance\", x + 70, y + 40);\u000b" +
-                "\u000b" +
-                "FileOutputStream out = new FileOutputStream(\"hslf-demo.ppt\");\u000b" +
-                "ppt.write(out);\u000b" +
-                "out.close();");
-        box3.setAnchor(new Rectangle(96, 110, 499, 378));
-        box3.setHorizontalCentered(true);
-    }
-
-    public static void slide10(SlideShow<?,?> ppt) throws IOException {
-        //bar chart data. The first value is the bar color, the second is the width
-        Object[] def = new Object[]{
-            Color.yellow, 100,
-            Color.green, 150,
-            Color.gray, 75,
-            Color.red, 200,
-        };
-
-        Slide<?,?> slide = ppt.createSlide();
-
-        GroupShape<?,?> group = slide.createGroup();
-        //define position of the drawing in the slide
-        Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);
-        group.setAnchor(bounds);
-        Graphics2D graphics = new SLGraphics(group);
-
-        //draw a simple bar graph
-        int x = bounds.x + 50;
-        int y = bounds.y + 50;
-        graphics.setFont(new Font("Arial", Font.BOLD, 10));
-        for (int i = 0, idx = 1; i < def.length; i+=2, idx++) {
-            graphics.setColor(Color.black);
-            int width = (Integer) def[i + 1];
-            graphics.drawString("Q" + idx, x-20, y+20);
-            graphics.drawString(width + "%", x + width + 10, y + 20);
-            graphics.setColor((Color)def[i]);
-            graphics.fill(new Rectangle(x, y, width, 30));
-            y += 40;
-        }
-        graphics.setColor(Color.black);
-        graphics.setFont(new Font("Arial", Font.BOLD, 14));
-        graphics.draw(bounds);
-        graphics.drawString("Performance", x + 70, y + 40);
-
-    }
-
-    public static void slide11(SlideShow<?,?> ppt) throws IOException {
-        Slide<?,?> slide = ppt.createSlide();
-
-        TextBox<?,?> box1 = slide.createTextBox();
-        box1.setTextPlaceholder(TextPlaceholder.TITLE);
-        box1.setText("HSLF Development Plans");
-        box1.setAnchor(new Rectangle(36, 21, 648, 90));
-
-        TextBox<?,?> box2 = slide.createTextBox();
-        box2.setTextPlaceholder(TextPlaceholder.BODY);
-        box2.setText(
-            "Support for more PowerPoint functionality\r" +
-            "Rendering slides into java.awt.Graphics2D\r" +
-                "A way to export slides into images or other formats\r" +
-            "Integration with Apache FOP - Formatting Objects Processor\r" +
-                "Transformation of XSL-FO into PPT\r" +
-                "PPT2PDF transcoder"
-        );
-
-        List<? extends TextParagraph<?,?,?>> tp = box2.getTextParagraphs();
-        for (int i : new byte[]{0,1,3}) {
-            tp.get(i).getTextRuns().get(0).setFontSize(28d);
-        }
-        for (int i : new byte[]{2,4,5}) {
-            tp.get(i).getTextRuns().get(0).setFontSize(24d);
-            tp.get(i).setIndentLevel(1);
-        }
-
-        box2.setAnchor(new Rectangle(36, 126, 648, 400));
-    }
-
-    public static void slide12(SlideShow<?,?> ppt) throws IOException {
-        Slide<?,?> slide = ppt.createSlide();
-
-        TextBox<?,?> box1 = slide.createTextBox();
-        box1.setTextPlaceholder(TextPlaceholder.CENTER_TITLE);
-        box1.setText("Questions?");
-        box1.setAnchor(new Rectangle(54, 167, 612, 115));
-
-        TextBox<?,?> box2 = slide.createTextBox();
-        box2.setTextPlaceholder(TextPlaceholder.CENTER_BODY);
-        box2.setText(
-                "https://poi.apache.org/hslf/\r" +
-                "http://people.apache.org/~yegor");
-        box2.setAnchor(new Rectangle(108, 306, 504, 138));
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java b/src/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java
deleted file mode 100644 (file)
index dc814f3..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hslf.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hslf.usermodel.HSLFSlide;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.hslf.usermodel.HSLFTextBox;
-import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
-
-/**
- * How to create a single-level bulleted list
- * and change some of the bullet attributes
- */
-public final class BulletsDemo {
-
-    public static void main(String[] args) throws IOException {
-        try (HSLFSlideShow ppt = new HSLFSlideShow()) {
-            HSLFSlide slide = ppt.createSlide();
-
-            HSLFTextBox shape = new HSLFTextBox();
-            HSLFTextParagraph rt = shape.getTextParagraphs().get(0);
-            rt.getTextRuns().get(0).setFontSize(42d);
-            rt.setBullet(true);
-            rt.setIndent(0d);  //bullet offset
-            rt.setLeftMargin(50d);   //text offset (should be greater than bullet offset)
-            rt.setBulletChar('\u263A'); //bullet character
-            shape.setText(
-                    "January\r" +
-                            "February\r" +
-                            "March\r" +
-                            "April");
-            slide.addShape(shape);
-
-            shape.setAnchor(new java.awt.Rectangle(50, 50, 500, 300));  //position of the text box in the slide
-            slide.addShape(shape);
-
-            try (FileOutputStream out = new FileOutputStream("bullets.ppt")) {
-                ppt.write(out);
-            }
-        }
-   }
-}
diff --git a/src/examples/src/org/apache/poi/hslf/examples/CreateHyperlink.java b/src/examples/src/org/apache/poi/hslf/examples/CreateHyperlink.java
deleted file mode 100644 (file)
index 65fb0b9..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hslf.examples;
-
-import java.awt.Rectangle;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hslf.usermodel.HSLFHyperlink;
-import org.apache.poi.hslf.usermodel.HSLFSlide;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.hslf.usermodel.HSLFTextBox;
-
-/**
- * Demonstrates how to create hyperlinks in PowerPoint presentations
- */
-public final class CreateHyperlink {
-
-    private CreateHyperlink() {}
-
-    public static void main(String[] args) throws IOException {
-        try (HSLFSlideShow ppt = new HSLFSlideShow()) {
-            HSLFSlide slideA = ppt.createSlide();
-            ppt.createSlide();
-            HSLFSlide slideC = ppt.createSlide();
-
-            // link to a URL
-            HSLFTextBox textBox1 = slideA.createTextBox();
-            textBox1.setText("Apache POI");
-            textBox1.setAnchor(new Rectangle(100, 100, 200, 50));
-
-            HSLFHyperlink link1 = textBox1.getTextParagraphs().get(0).getTextRuns().get(0).createHyperlink();
-            link1.linkToUrl("http://www.apache.org");
-            link1.setLabel(textBox1.getText());
-
-            // link to another slide
-            HSLFTextBox textBox2 = slideA.createTextBox();
-            textBox2.setText("Go to slide #3");
-            textBox2.setAnchor(new Rectangle(100, 300, 200, 50));
-
-            HSLFHyperlink link2 = textBox2.getTextParagraphs().get(0).getTextRuns().get(0).createHyperlink();
-            link2.linkToSlide(slideC);
-
-            try (FileOutputStream out = new FileOutputStream("hyperlink.ppt")) {
-                ppt.write(out);
-            }
-        }
-   }
-}
diff --git a/src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java b/src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java
deleted file mode 100644 (file)
index e73b897..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hslf.examples;
-
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.poi.hslf.usermodel.HSLFObjectData;
-import org.apache.poi.hslf.usermodel.HSLFObjectShape;
-import org.apache.poi.hslf.usermodel.HSLFPictureData;
-import org.apache.poi.hslf.usermodel.HSLFPictureShape;
-import org.apache.poi.hslf.usermodel.HSLFShape;
-import org.apache.poi.hslf.usermodel.HSLFSlide;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.hslf.usermodel.HSLFSoundData;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hwpf.HWPFDocument;
-import org.apache.poi.hwpf.usermodel.Paragraph;
-import org.apache.poi.hwpf.usermodel.Range;
-import org.apache.poi.util.IOUtils;
-
-/**
- * Demonstrates how you can extract misc embedded data from a ppt file
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public final class DataExtraction {
-
-    private DataExtraction() {}
-
-    public static void main(String[] args) throws Exception {
-
-        if (args.length == 0) {
-            usage();
-            return;
-        }
-
-        try (FileInputStream fis = new FileInputStream(args[0]);
-            HSLFSlideShow ppt = new HSLFSlideShow(fis)) {
-
-            //extract all sound files embedded in this presentation
-            HSLFSoundData[] sound = ppt.getSoundData();
-            for (HSLFSoundData aSound : sound) {
-                handleSound(aSound);
-            }
-
-            int oleIdx = -1;
-            int picIdx = -1;
-            for (HSLFSlide slide : ppt.getSlides()) {
-                //extract embedded OLE documents
-                for (HSLFShape shape : slide.getShapes()) {
-                    if (shape instanceof HSLFObjectShape) {
-                        handleShape((HSLFObjectShape) shape, ++oleIdx);
-                    } else if (shape instanceof HSLFPictureShape) {
-                        handlePicture((HSLFPictureShape) shape, ++picIdx);
-                    }
-                }
-            }
-        }
-    }
-
-    private static void handleShape(HSLFObjectShape ole, int oleIdx) throws IOException {
-        HSLFObjectData data = ole.getObjectData();
-        String name = ole.getInstanceName();
-        switch (name == null ? "" : name) {
-            case "Worksheet":
-                //read xls
-                handleWorkbook(data, name, oleIdx);
-                break;
-            case "Document":
-                //read the word document
-                handleDocument(data, name, oleIdx);
-                break;
-            default:
-                handleUnknown(data, ole.getProgId(), oleIdx);
-                break;
-        }
-
-    }
-
-    private static void handleWorkbook(HSLFObjectData data, String name, int oleIdx) throws IOException {
-        try (InputStream is = data.getInputStream();
-             HSSFWorkbook wb = new HSSFWorkbook(is);
-             FileOutputStream out = new FileOutputStream(name + "-(" + (oleIdx) + ").xls")) {
-            wb.write(out);
-        }
-    }
-
-    private static void handleDocument(HSLFObjectData data, String name, int oleIdx) throws IOException {
-        try (InputStream is = data.getInputStream();
-             HWPFDocument doc = new HWPFDocument(is);
-             FileOutputStream out = new FileOutputStream(name + "-(" + (oleIdx) + ").doc")) {
-            Range r = doc.getRange();
-            for (int k = 0; k < r.numParagraphs(); k++) {
-                Paragraph p = r.getParagraph(k);
-                System.out.println(p.text());
-            }
-
-            //save on disk
-            doc.write(out);
-        }
-    }
-
-    private static void handleUnknown(HSLFObjectData data, String name, int oleIdx) throws IOException {
-        try (InputStream is = data.getInputStream();
-             FileOutputStream out = new FileOutputStream(name + "-" + (oleIdx + 1) + ".dat")) {
-            IOUtils.copy(is, out);
-        }
-    }
-
-    private static void handlePicture(HSLFPictureShape p, int picIdx) throws IOException {
-        HSLFPictureData data = p.getPictureData();
-        String ext = data.getType().extension;
-        try (FileOutputStream out = new FileOutputStream("pict-" + picIdx + ext)) {
-            out.write(data.getData());
-        }
-    }
-
-    private static void handleSound(HSLFSoundData aSound) throws IOException {
-        String type = aSound.getSoundType();  //*.wav
-        String name = aSound.getSoundName();  //typically file name
-
-        //save the sound  on disk
-        try (FileOutputStream out = new FileOutputStream(name + type)) {
-            out.write(aSound.getData());
-        }
-    }
-
-    private static void usage(){
-        System.out.println("Usage: DataExtraction  ppt");
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hslf/examples/Graphics2DDemo.java b/src/examples/src/org/apache/poi/hslf/examples/Graphics2DDemo.java
deleted file mode 100644 (file)
index 75ccf01..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hslf.examples;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.io.FileOutputStream;
-
-import org.apache.poi.hslf.usermodel.HSLFGroupShape;
-import org.apache.poi.hslf.usermodel.HSLFSlide;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.sl.draw.SLGraphics;
-
-/**
- * Demonstrates how to draw into a slide using the HSLF Graphics2D driver.
- */
-public final class Graphics2DDemo {
-
-    private Graphics2DDemo() {}
-
-    /**
-     * A simple bar chart demo
-     */
-    public static void main(String[] args) throws Exception {
-        try (HSLFSlideShow ppt = new HSLFSlideShow();
-             FileOutputStream out = new FileOutputStream("hslf-graphics.ppt")) {
-            //bar chart data. The first value is the bar color, the second is the width
-            Object[] def = {
-                    Color.yellow, 40,
-                    Color.green, 60,
-                    Color.gray, 30,
-                    Color.red, 80,
-            };
-
-            HSLFSlide slide = ppt.createSlide();
-
-            HSLFGroupShape group = new HSLFGroupShape();
-            //define position of the drawing in the slide
-            Rectangle bounds = new Rectangle(200, 100, 350, 300);
-            group.setAnchor(bounds);
-            group.setInteriorAnchor(new Rectangle(0, 0, 100, 100));
-            slide.addShape(group);
-            Graphics2D graphics = new SLGraphics(group);
-
-            //draw a simple bar graph
-            int x = 10, y = 10;
-            graphics.setFont(new Font("Arial", Font.BOLD, 10));
-            for (int i = 0, idx = 1; i < def.length; i += 2, idx++) {
-                graphics.setColor(Color.black);
-                int width = (Integer) def[i + 1];
-                graphics.drawString("Q" + idx, x - 5, y + 10);
-                graphics.drawString(width + "%", x + width + 3, y + 10);
-                graphics.setColor((Color) def[i]);
-                graphics.fill(new Rectangle(x, y, width, 10));
-                y += 15;
-            }
-            graphics.setColor(Color.black);
-            graphics.setFont(new Font("Arial", Font.BOLD, 14));
-            graphics.draw(group.getInteriorAnchor());
-            graphics.drawString("Performance", x + 30, y + 10);
-
-            ppt.write(out);
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hslf/examples/HeadersFootersDemo.java b/src/examples/src/org/apache/poi/hslf/examples/HeadersFootersDemo.java
deleted file mode 100644 (file)
index 28fc8b1..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.hslf.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hslf.model.HeadersFooters;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-
-/**
- * Demonstrates how to set headers / footers
- */
-public final class HeadersFootersDemo {
-    private HeadersFootersDemo() {}
-
-    public static void main(String[] args) throws IOException {
-        try (HSLFSlideShow ppt = new HSLFSlideShow()) {
-            HeadersFooters slideHeaders = ppt.getSlideHeadersFooters();
-            slideHeaders.setFootersText("Created by POI-HSLF");
-            slideHeaders.setSlideNumberVisible(true);
-            slideHeaders.setDateTimeText("custom date time");
-
-            HeadersFooters notesHeaders = ppt.getNotesHeadersFooters();
-            notesHeaders.setFootersText("My notes footers");
-            notesHeaders.setHeaderText("My notes header");
-
-            ppt.createSlide();
-
-            try (FileOutputStream out = new FileOutputStream("headers_footers.ppt")) {
-                ppt.write(out);
-            }
-        }
-    }
-
-}
diff --git a/src/examples/src/org/apache/poi/hslf/examples/Hyperlinks.java b/src/examples/src/org/apache/poi/hslf/examples/Hyperlinks.java
deleted file mode 100644 (file)
index f63afb4..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hslf.examples;
-
-import java.io.FileInputStream;
-import java.util.List;
-import java.util.Locale;
-
-import org.apache.poi.hslf.usermodel.HSLFHyperlink;
-import org.apache.poi.hslf.usermodel.HSLFSimpleShape;
-import org.apache.poi.hslf.usermodel.HSLFSlide;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
-import org.apache.poi.hslf.usermodel.HSLFTextRun;
-
-/**
- * Demonstrates how to read hyperlinks from  a presentation
- */
-@SuppressWarnings({"java:S106", "java:S4823"})
-public final class Hyperlinks {
-
-    private Hyperlinks() {}
-
-    public static void main(String[] args) throws Exception {
-        for (String arg : args) {
-            try (FileInputStream is = new FileInputStream(arg);
-                 HSLFSlideShow ppt = new HSLFSlideShow(is)) {
-
-                for (HSLFSlide slide : ppt.getSlides()) {
-                    System.out.println("\nslide " + slide.getSlideNumber());
-
-                    // read hyperlinks from the slide's text runs
-                    System.out.println("- reading hyperlinks from the text runs");
-                    slide.getTextParagraphs().stream().
-                        flatMap(List::stream).
-                        map(HSLFTextParagraph::getTextRuns).
-                        flatMap(List::stream).
-                        forEach(run -> out(run.getHyperlink(), run));
-
-                    // in PowerPoint you can assign a hyperlink to a shape without text,
-                    // for example to a Line object. The code below demonstrates how to
-                    // read such hyperlinks
-                    System.out.println("- reading hyperlinks from the slide's shapes");
-                    slide.getShapes().stream().
-                        filter(sh -> sh instanceof HSLFSimpleShape).
-                        forEach(sh -> out(((HSLFSimpleShape) sh).getHyperlink(), null));
-                }
-            }
-        }
-    }
-
-    private static void out(HSLFHyperlink link, HSLFTextRun run) {
-        if (link == null) {
-            return;
-        }
-        String rawText = run == null ? null : run.getRawText();
-        //in ppt end index is inclusive
-        String formatStr = "title: %1$s, address: %2$s" + (rawText == null ? "" : ", start: %3$s, end: %4$s, substring: %5$s");
-        String line = String.format(Locale.ROOT, formatStr, link.getLabel(), link.getAddress(), link.getStartIndex(), link.getEndIndex(), rawText);
-        System.out.println(line);
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hslf/examples/SoundFinder.java b/src/examples/src/org/apache/poi/hslf/examples/SoundFinder.java
deleted file mode 100644 (file)
index 49ca94b..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.hslf.examples;
-import java.io.FileInputStream;
-import java.io.IOException;
-
-import org.apache.poi.hslf.record.InteractiveInfoAtom;
-import org.apache.poi.hslf.record.RecordTypes;
-import org.apache.poi.hslf.usermodel.HSLFShape;
-import org.apache.poi.hslf.usermodel.HSLFSlide;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.hslf.usermodel.HSLFSoundData;
-
-/**
- * For each slide iterate over shapes and found associated sound data.
- */
-@SuppressWarnings({"java:S106", "java:S4823"})
-public final class SoundFinder {
-    private SoundFinder() {}
-
-    public static void main(String[] args) throws IOException {
-        try (FileInputStream fis = new FileInputStream(args[0])) {
-            try (HSLFSlideShow ppt = new HSLFSlideShow(fis)) {
-                HSLFSoundData[] sounds = ppt.getSoundData();
-
-                for (HSLFSlide slide : ppt.getSlides()) {
-                    for (HSLFShape shape : slide.getShapes()) {
-                        int soundRef = getSoundReference(shape);
-                        if (soundRef == -1) continue;
-
-
-                        System.out.println("Slide[" + slide.getSlideNumber() + "], shape[" + shape.getShapeId() + "], soundRef: " + soundRef);
-                        System.out.println("  " + sounds[soundRef].getSoundName());
-                        System.out.println("  " + sounds[soundRef].getSoundType());
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Check if a given shape is associated with a sound.
-     * @return 0-based reference to a sound in the sound collection
-     * or -1 if the shape is not associated with a sound
-     */
-    private static int getSoundReference(HSLFShape shape){
-        int soundRef = -1;
-        //dive into the shape container and search for InteractiveInfoAtom
-        InteractiveInfoAtom info = shape.getClientDataRecord(RecordTypes.InteractiveInfo.typeID);
-        if (info != null && info.getAction() == InteractiveInfoAtom.ACTION_MEDIA) {
-            soundRef = info.getSoundRef();
-        }
-        return soundRef;
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java b/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java
deleted file mode 100644 (file)
index da8464f..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hslf.examples;
-
-import java.awt.Color;
-import java.io.FileOutputStream;
-
-import org.apache.poi.hslf.usermodel.HSLFSlide;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.hslf.usermodel.HSLFTable;
-import org.apache.poi.hslf.usermodel.HSLFTableCell;
-import org.apache.poi.hslf.usermodel.HSLFTextRun;
-import org.apache.poi.sl.draw.DrawTableShape;
-import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
-import org.apache.poi.sl.usermodel.VerticalAlignment;
-
-/**
- * Demonstrates how to create tables
- */
-public final class TableDemo {
-
-    //test data for the first table
-    static final String[][] txt1 = {
-        {"INPUT FILE", "NUMBER OF RECORDS"},
-        {"Item File", "11,559"},
-        {"Vendor File", "502"},
-        {"Purchase History File - # of PO\u2019s\r(12/01/04 - 05/31/06)", "12,852"},
-        {"Purchase History File - # of PO Lines\r(12/01/04 - 05/31/06)", "53,523" },
-        {"Total PO History Spend", "$10,172,038"}
-    };
-
-    //test data for the second taable
-    static final String[][] txt2 = {
-        {"Data Source"},
-        {"CAS Internal Metrics - Item Master Summary\r" +
-         "CAS Internal Metrics - Vendor Summary\r" +
-         "CAS Internal Metrics - PO History Summary"}
-    };
-
-
-    public static void main(String[] args) throws Exception {
-        try (HSLFSlideShow ppt = new HSLFSlideShow()) {
-            HSLFSlide slide = ppt.createSlide();
-            create1stTable(slide);
-            create2ndTable(slide);
-
-            try (FileOutputStream out = new FileOutputStream("hslf-table.ppt")) {
-                ppt.write(out);
-            }
-        }
-    }
-    
-    static void create1stTable(HSLFSlide slide) {
-        //six rows, two columns
-        HSLFTable table1 = slide.createTable(6, 2);
-        for (int i = 0; i < txt1.length; i++) {
-            for (int j = 0; j < txt1[i].length; j++) {
-                HSLFTableCell cell = table1.getCell(i, j);
-                HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
-                rt.setFontFamily("Arial");
-                rt.setFontSize(10d);
-                if(i == 0){
-                    cell.getFill().setForegroundColor(new Color(227, 227, 227));
-                } else {
-                    rt.setBold(true);
-                }
-                cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
-                cell.setHorizontalCentered(true);
-                cell.setText(txt1[i][j]);
-            }
-        }
-
-        DrawTableShape dts1 = new DrawTableShape(table1);
-        dts1.setAllBorders(1.0, Color.black);
-
-        table1.setColumnWidth(0, 300);
-        table1.setColumnWidth(1, 150);
-
-        int pgWidth = slide.getSlideShow().getPageSize().width;
-        table1.moveTo((pgWidth - table1.getAnchor().getWidth())/2., 100.);
-    }
-
-    static void create2ndTable(HSLFSlide slide) {
-        //two rows, one column
-        HSLFTable table2 = slide.createTable(2, 1);
-        for (int i = 0; i < txt2.length; i++) {
-            for (int j = 0; j < txt2[i].length; j++) {
-                HSLFTableCell cell = table2.getCell(i, j);
-                HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
-                rt.setFontSize(10d);
-                rt.setFontFamily("Arial");
-                if(i == 0){
-                    cell.getFill().setForegroundColor(new Color(0, 51, 102));
-                    rt.setFontColor(Color.white);
-                    rt.setBold(true);
-                    rt.setFontSize(14d);
-                    cell.setHorizontalCentered(true);
-                } else {
-                    rt.getTextParagraph().setBullet(true);
-                    rt.setFontSize(12d);
-                    rt.getTextParagraph().setTextAlign(TextAlign.LEFT);
-                    cell.setHorizontalCentered(false);
-                }
-                cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
-                cell.setText(txt2[i][j]);
-            }
-        }
-        table2.setColumnWidth(0, 300);
-        table2.setRowHeight(0, 30);
-        table2.setRowHeight(1, 70);
-
-        DrawTableShape dts2 = new DrawTableShape(table2);
-        dts2.setOutsideBorders(Color.black, 1.0);
-
-        table2.moveTo(200, 400);
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hsmf/examples/Msg2txt.java b/src/examples/src/org/apache/poi/hsmf/examples/Msg2txt.java
deleted file mode 100644 (file)
index 010e711..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hsmf.examples;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-
-import org.apache.poi.hsmf.MAPIMessage;
-import org.apache.poi.hsmf.datatypes.AttachmentChunks;
-import org.apache.poi.hsmf.exceptions.ChunkNotFoundException;
-
-/**
- * Reads one or several Outlook MSG files and for each of them creates
- * a text file from available chunks and a directory that contains
- * attachments.
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public class Msg2txt {
-
-       /**
-        * The stem used to create file names for the text file and the directory
-        * that contains the attachments.
-        */
-       private String fileNameStem;
-
-       /**
-        * The Outlook MSG file being processed.
-        */
-       private MAPIMessage msg;
-
-       public Msg2txt(String fileName) throws IOException {
-               fileNameStem = fileName;
-               if(fileNameStem.endsWith(".msg") || fileNameStem.endsWith(".MSG")) {
-                       fileNameStem = fileNameStem.substring(0, fileNameStem.length() - 4);
-               }
-               msg = new MAPIMessage(fileName);
-       }
-
-       /**
-        * Processes the message.
-        *
-        * @throws IOException if an exception occurs while writing the message out
-        */
-       public void processMessage() throws IOException {
-               String txtFileName = fileNameStem + ".txt";
-               String attDirName = fileNameStem + "-att";
-        try (PrintWriter txtOut = new PrintWriter(txtFileName)) {
-            try {
-                String displayFrom = msg.getDisplayFrom();
-                txtOut.println("From: " + displayFrom);
-            } catch (ChunkNotFoundException e) {
-                // ignore
-            }
-            try {
-                String displayTo = msg.getDisplayTo();
-                txtOut.println("To: " + displayTo);
-            } catch (ChunkNotFoundException e) {
-                // ignore
-            }
-            try {
-                String displayCC = msg.getDisplayCC();
-                txtOut.println("CC: " + displayCC);
-            } catch (ChunkNotFoundException e) {
-                // ignore
-            }
-            try {
-                String displayBCC = msg.getDisplayBCC();
-                txtOut.println("BCC: " + displayBCC);
-            } catch (ChunkNotFoundException e) {
-                // ignore
-            }
-            try {
-                String subject = msg.getSubject();
-                txtOut.println("Subject: " + subject);
-            } catch (ChunkNotFoundException e) {
-                // ignore
-            }
-            try {
-                String body = msg.getTextBody();
-                txtOut.println(body);
-            } catch (ChunkNotFoundException e) {
-                System.err.println("No message body");
-            }
-
-            AttachmentChunks[] attachments = msg.getAttachmentFiles();
-            if (attachments.length > 0) {
-                File d = new File(attDirName);
-                if (d.mkdir()) {
-                    for (AttachmentChunks attachment : attachments) {
-                        processAttachment(attachment, d);
-                    }
-                } else {
-                    System.err.println("Can't create directory " + attDirName);
-                }
-            }
-        }
-       }
-
-       /**
-        * Processes a single attachment: reads it from the Outlook MSG file and
-        * writes it to disk as an individual file.
-        *
-        * @param attachment the chunk group describing the attachment
-        * @param dir the directory in which to write the attachment file
-        * @throws IOException when any of the file operations fails
-        */
-       public void processAttachment(AttachmentChunks attachment,
-             File dir) throws IOException {
-          String fileName = attachment.getAttachFileName().toString();
-          if(attachment.getAttachLongFileName() != null) {
-             fileName = attachment.getAttachLongFileName().toString();
-          }
-
-               File f = new File(dir, fileName);
-        try (OutputStream fileOut = new FileOutputStream(f)) {
-            fileOut.write(attachment.getAttachData().getValue());
-        }
-       }
-
-       /**
-        * Processes the list of arguments as a list of names of Outlook MSG files.
-        *
-        * @param args the list of MSG files to process
-        */
-       public static void main(String[] args) {
-               if(args.length <= 0) {
-                       System.err.println("No files names provided");
-               } else {
-                       for (String arg : args) {
-                               try {
-                                       Msg2txt processor = new Msg2txt(arg);
-                                       processor.processMessage();
-                               } catch (IOException e) {
-                                       System.err.println("Could not process " + arg + ": " + e);
-                               }
-                       }
-               }
-       }
-
-}
diff --git a/src/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java b/src/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java
deleted file mode 100644 (file)
index da06079..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.eventusermodel.examples;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener;
-import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
-import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
-import org.apache.poi.hssf.eventusermodel.HSSFListener;
-import org.apache.poi.hssf.eventusermodel.HSSFRequest;
-import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;
-import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
-import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
-import org.apache.poi.hssf.model.HSSFFormulaParser;
-import org.apache.poi.hssf.record.BOFRecord;
-import org.apache.poi.hssf.record.BlankRecord;
-import org.apache.poi.hssf.record.BoolErrRecord;
-import org.apache.poi.hssf.record.BoundSheetRecord;
-import org.apache.poi.hssf.record.FormulaRecord;
-import org.apache.poi.hssf.record.LabelRecord;
-import org.apache.poi.hssf.record.LabelSSTRecord;
-import org.apache.poi.hssf.record.NoteRecord;
-import org.apache.poi.hssf.record.NumberRecord;
-import org.apache.poi.hssf.record.RKRecord;
-import org.apache.poi.hssf.record.SSTRecord;
-import org.apache.poi.hssf.record.StringRecord;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-
-/**
- * A XLS -> CSV processor, that uses the MissingRecordAware
- *  EventModel code to ensure it outputs all columns and rows.
- * @author Nick Burch
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public class XLS2CSVmra implements HSSFListener {
-       private int minColumns;
-       private POIFSFileSystem fs;
-       private PrintStream output;
-
-       private int lastRowNumber;
-       private int lastColumnNumber;
-
-       /** Should we output the formula, or the value it has? */
-       private boolean outputFormulaValues = true;
-
-       /** For parsing Formulas */
-       private SheetRecordCollectingListener workbookBuildingListener;
-       private HSSFWorkbook stubWorkbook;
-
-       // Records we pick up as we process
-       private SSTRecord sstRecord;
-       private FormatTrackingHSSFListener formatListener;
-
-       /** So we known which sheet we're on */
-       private int sheetIndex = -1;
-       private BoundSheetRecord[] orderedBSRs;
-       private List<BoundSheetRecord> boundSheetRecords = new ArrayList<>();
-
-       // For handling formulas with string results
-       private int nextRow;
-       private int nextColumn;
-       private boolean outputNextStringRecord;
-
-       /**
-        * Creates a new XLS -> CSV converter
-        * @param fs The POIFSFileSystem to process
-        * @param output The PrintStream to output the CSV to
-        * @param minColumns The minimum number of columns to output, or -1 for no minimum
-        */
-       public XLS2CSVmra(POIFSFileSystem fs, PrintStream output, int minColumns) {
-               this.fs = fs;
-               this.output = output;
-               this.minColumns = minColumns;
-       }
-
-       /**
-        * Creates a new XLS -> CSV converter
-        * @param filename The file to process
-        * @param minColumns The minimum number of columns to output, or -1 for no minimum
-        */
-       public XLS2CSVmra(String filename, int minColumns) throws IOException, FileNotFoundException {
-               this(
-                               new POIFSFileSystem(new FileInputStream(filename)),
-                               System.out, minColumns
-               );
-       }
-
-       /**
-        * Initiates the processing of the XLS file to CSV
-        */
-       public void process() throws IOException {
-               MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
-               formatListener = new FormatTrackingHSSFListener(listener);
-
-               HSSFEventFactory factory = new HSSFEventFactory();
-               HSSFRequest request = new HSSFRequest();
-
-               if(outputFormulaValues) {
-                       request.addListenerForAllRecords(formatListener);
-               } else {
-                       workbookBuildingListener = new SheetRecordCollectingListener(formatListener);
-                       request.addListenerForAllRecords(workbookBuildingListener);
-               }
-
-               factory.processWorkbookEvents(request, fs);
-       }
-
-       /**
-        * Main HSSFListener method, processes events, and outputs the
-        *  CSV as the file is processed.
-        */
-       @Override
-    public void processRecord(org.apache.poi.hssf.record.Record record) {
-               int thisRow = -1;
-               int thisColumn = -1;
-               String thisStr = null;
-
-               switch (record.getSid())
-               {
-               case BoundSheetRecord.sid:
-                       boundSheetRecords.add((BoundSheetRecord)record);
-                       break;
-               case BOFRecord.sid:
-                       BOFRecord br = (BOFRecord)record;
-                       if(br.getType() == BOFRecord.TYPE_WORKSHEET) {
-                               // Create sub workbook if required
-                               if(workbookBuildingListener != null && stubWorkbook == null) {
-                                       stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
-                               }
-
-                               // Output the worksheet name
-                               // Works by ordering the BSRs by the location of
-                               //  their BOFRecords, and then knowing that we
-                               //  process BOFRecords in byte offset order
-                               sheetIndex++;
-                               if(orderedBSRs == null) {
-                                       orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
-                               }
-                               output.println();
-                               output.println(
-                                               orderedBSRs[sheetIndex].getSheetname() +
-                                               " [" + (sheetIndex+1) + "]:"
-                               );
-                       }
-                       break;
-
-               case SSTRecord.sid:
-                       sstRecord = (SSTRecord) record;
-                       break;
-
-               case BlankRecord.sid:
-                       BlankRecord brec = (BlankRecord) record;
-
-                       thisRow = brec.getRow();
-                       thisColumn = brec.getColumn();
-                       thisStr = "";
-                       break;
-               case BoolErrRecord.sid:
-                       BoolErrRecord berec = (BoolErrRecord) record;
-
-                       thisRow = berec.getRow();
-                       thisColumn = berec.getColumn();
-                       thisStr = "";
-                       break;
-
-               case FormulaRecord.sid:
-                       FormulaRecord frec = (FormulaRecord) record;
-
-                       thisRow = frec.getRow();
-                       thisColumn = frec.getColumn();
-
-                       if(outputFormulaValues) {
-                               if(Double.isNaN( frec.getValue() )) {
-                                       // Formula result is a string
-                                       // This is stored in the next record
-                                       outputNextStringRecord = true;
-                                       nextRow = frec.getRow();
-                                       nextColumn = frec.getColumn();
-                               } else {
-                                       thisStr = formatListener.formatNumberDateCell(frec);
-                               }
-                       } else {
-                               thisStr = '"' +
-                                       HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"';
-                       }
-                       break;
-               case StringRecord.sid:
-                       if(outputNextStringRecord) {
-                               // String for formula
-                               StringRecord srec = (StringRecord)record;
-                               thisStr = srec.getString();
-                               thisRow = nextRow;
-                               thisColumn = nextColumn;
-                               outputNextStringRecord = false;
-                       }
-                       break;
-
-               case LabelRecord.sid:
-                       LabelRecord lrec = (LabelRecord) record;
-
-                       thisRow = lrec.getRow();
-                       thisColumn = lrec.getColumn();
-                       thisStr = '"' + lrec.getValue() + '"';
-                       break;
-               case LabelSSTRecord.sid:
-                       LabelSSTRecord lsrec = (LabelSSTRecord) record;
-
-                       thisRow = lsrec.getRow();
-                       thisColumn = lsrec.getColumn();
-                       if(sstRecord == null) {
-                               thisStr = '"' + "(No SST Record, can't identify string)" + '"';
-                       } else {
-                               thisStr = '"' + sstRecord.getString(lsrec.getSSTIndex()).toString() + '"';
-                       }
-                       break;
-               case NoteRecord.sid:
-                       NoteRecord nrec = (NoteRecord) record;
-
-                       thisRow = nrec.getRow();
-                       thisColumn = nrec.getColumn();
-                       // TODO: Find object to match nrec.getShapeId()
-                       thisStr = '"' + "(TODO)" + '"';
-                       break;
-               case NumberRecord.sid:
-                       NumberRecord numrec = (NumberRecord) record;
-
-                       thisRow = numrec.getRow();
-                       thisColumn = numrec.getColumn();
-
-                       // Format
-                       thisStr = formatListener.formatNumberDateCell(numrec);
-                       break;
-               case RKRecord.sid:
-                       RKRecord rkrec = (RKRecord) record;
-
-                       thisRow = rkrec.getRow();
-                       thisColumn = rkrec.getColumn();
-                       thisStr = '"' + "(TODO)" + '"';
-                       break;
-               default:
-                       break;
-               }
-
-               // Handle new row
-               if(thisRow != -1 && thisRow != lastRowNumber) {
-                       lastColumnNumber = -1;
-               }
-
-               // Handle missing column
-               if(record instanceof MissingCellDummyRecord) {
-                       MissingCellDummyRecord mc = (MissingCellDummyRecord)record;
-                       thisRow = mc.getRow();
-                       thisColumn = mc.getColumn();
-                       thisStr = "";
-               }
-
-               // If we got something to print out, do so
-               if(thisStr != null) {
-                       if(thisColumn > 0) {
-                               output.print(',');
-                       }
-                       output.print(thisStr);
-               }
-
-               // Update column and row count
-               if(thisRow > -1)
-                       lastRowNumber = thisRow;
-               if(thisColumn > -1)
-                       lastColumnNumber = thisColumn;
-
-               // Handle end of row
-               if(record instanceof LastCellOfRowDummyRecord) {
-                       // Print out any missing commas if needed
-                       if(minColumns > 0) {
-                               // Columns are 0 based
-                               if(lastColumnNumber == -1) { lastColumnNumber = 0; }
-                               for(int i=lastColumnNumber; i<(minColumns); i++) {
-                                       output.print(',');
-                               }
-                       }
-
-                       // We're onto a new row
-                       lastColumnNumber = -1;
-
-                       // End the row
-                       output.println();
-               }
-       }
-
-       public static void main(String[] args) throws Exception {
-               if(args.length < 1) {
-                       System.err.println("Use:");
-                       System.err.println("  XLS2CSVmra <xls file> [min columns]");
-                       System.exit(1);
-               }
-
-               int minColumns = -1;
-               if(args.length >= 2) {
-                       minColumns = Integer.parseInt(args[1]);
-               }
-
-               XLS2CSVmra xls2csv = new XLS2CSVmra(args[0], minColumns);
-               xls2csv.process();
-       }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/AddDimensionedImage.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/AddDimensionedImage.java
deleted file mode 100644 (file)
index 38e2fe6..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-
-package org.apache.poi.hssf.usermodel.examples;
-
-/* Placeholder - this is now handled in the Common SS example **/
-public class AddDimensionedImage extends org.apache.poi.ss.examples.AddDimensionedImage {
-}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/Alignment.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/Alignment.java
deleted file mode 100644 (file)
index 57395b1..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-        
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFCellStyle;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-
-/**
- * Shows how various alignment options work.
- *
- * @author Glen Stampoultzis (glens at apache.org)
- */
-public class Alignment {
-    public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet = wb.createSheet("new sheet");
-            HSSFRow row = sheet.createRow(2);
-            createCell(wb, row, 0, HorizontalAlignment.CENTER);
-            createCell(wb, row, 1, HorizontalAlignment.CENTER_SELECTION);
-            createCell(wb, row, 2, HorizontalAlignment.FILL);
-            createCell(wb, row, 3, HorizontalAlignment.GENERAL);
-            createCell(wb, row, 4, HorizontalAlignment.JUSTIFY);
-            createCell(wb, row, 5, HorizontalAlignment.LEFT);
-            createCell(wb, row, 6, HorizontalAlignment.RIGHT);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-
-    /**
-     * Creates a cell and aligns it a certain way.
-     *
-     * @param wb        the workbook
-     * @param row       the row to create the cell in
-     * @param column    the column number to create the cell in
-     * @param align     the alignment for the cell.
-     */
-    private static void createCell(HSSFWorkbook wb, HSSFRow row, int column, HorizontalAlignment align) {
-        HSSFCell cell = row.createCell(column);
-        cell.setCellValue("Align It");
-        HSSFCellStyle cellStyle = wb.createCellStyle();
-        cellStyle.setAlignment(align);
-        cell.setCellStyle(cellStyle);
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/BigExample.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/BigExample.java
deleted file mode 100644 (file)
index ef1a06b..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFCellStyle;
-import org.apache.poi.hssf.usermodel.HSSFDataFormat;
-import org.apache.poi.hssf.usermodel.HSSFFont;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.FillPatternType;
-
-/**
- * Demonstrates many features of the user API at once.  Used in the HOW-TO guide.
- */
-public class BigExample {
-    public static void main(String[] args) throws IOException {
-        int rownum;
-
-        // create a new workbook
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            // create a new sheet
-            HSSFSheet s = wb.createSheet();
-            // declare a row object reference
-            HSSFRow r;
-            // declare a cell object reference
-            HSSFCell c;
-            // create 3 cell styles
-            HSSFCellStyle cs = wb.createCellStyle();
-            HSSFCellStyle cs2 = wb.createCellStyle();
-            HSSFCellStyle cs3 = wb.createCellStyle();
-            // create 2 fonts objects
-            HSSFFont f = wb.createFont();
-            HSSFFont f2 = wb.createFont();
-
-            //set font 1 to 12 point type
-            f.setFontHeightInPoints((short) 12);
-            //make it red
-            f.setColor(HSSFColorPredefined.RED.getIndex());
-            // make it bold
-            //arial is the default font
-            f.setBold(true);
-
-            //set font 2 to 10 point type
-            f2.setFontHeightInPoints((short) 10);
-            //make it the color at palette index 0xf (white)
-            f2.setColor(HSSFColorPredefined.WHITE.getIndex());
-            //make it bold
-            f2.setBold(true);
-
-            //set cell style
-            cs.setFont(f);
-            //set the cell format see HSSFDataFormat for a full list
-            cs.setDataFormat(HSSFDataFormat.getBuiltinFormat("($#,##0_);[Red]($#,##0)"));
-
-            //set a thin border
-            cs2.setBorderBottom(BorderStyle.THIN);
-            //fill w fg fill color
-            cs2.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-            // set foreground fill to red
-            cs2.setFillForegroundColor(HSSFColorPredefined.RED.getIndex());
-
-            // set the font
-            cs2.setFont(f2);
-
-            // set the sheet name to HSSF Test
-            wb.setSheetName(0, "HSSF Test");
-            // create a sheet with 300 rows (0-299)
-            for (rownum = 0; rownum < 300; rownum++) {
-                // create a row
-                r = s.createRow(rownum);
-                // on every other row
-                if ((rownum % 2) == 0) {
-                    // make the row height bigger  (in twips - 1/20 of a point)
-                    r.setHeight((short) 0x249);
-                }
-
-                // create 50 cells (0-49) (the += 2 becomes apparent later
-                for (int cellnum = 0; cellnum < 50; cellnum += 2) {
-                    // create a numeric cell
-                    c = r.createCell(cellnum);
-                    // do some goofy math to demonstrate decimals
-                    c.setCellValue((rownum * 10000.0) + cellnum
-                            + (rownum / 1000.0)
-                            + (cellnum / 10000.0));
-
-                    // on every other row
-                    if ((rownum % 2) == 0) {
-                        // set this cell to the first cell style we defined
-                        c.setCellStyle(cs);
-                    }
-
-                    // create a string cell (see why += 2 in the
-                    c = r.createCell(cellnum + 1);
-
-                    // set the cell's string value to "TEST"
-                    c.setCellValue("TEST");
-                    // make this column a bit wider
-                    s.setColumnWidth(cellnum + 1, (int) ((50 * 8) / ((double) 1 / 20)));
-
-                    // on every other row
-                    if ((rownum % 2) == 0) {
-                        // set this to the white on red cell style
-                        // we defined above
-                        c.setCellStyle(cs2);
-                    }
-
-                }
-            }
-
-            //draw a thick black border on the row at the bottom using BLANKS
-            // advance 2 rows
-            rownum++;
-            rownum++;
-
-            r = s.createRow(rownum);
-
-            // define the third style to be the default
-            // except with a thick black border at the bottom
-            cs3.setBorderBottom(BorderStyle.THICK);
-
-            //create 50 cells
-            for (int cellnum = 0; cellnum < 50; cellnum++) {
-                //create a blank type cell (no value)
-                c = r.createCell(cellnum);
-                // set it to the thick black border style
-                c.setCellStyle(cs3);
-            }
-
-            //end draw thick black border
-
-
-            // demonstrate adding/naming and deleting a sheet
-            // create a sheet, set its title then delete it
-            wb.createSheet();
-            wb.setSheetName(1, "DeletedSheet");
-            wb.removeSheetAt(1);
-            //end deleted sheet
-
-            // create a new file
-            try (FileOutputStream out = new FileOutputStream("workbook.xls")) {
-                // write the workbook to the output stream
-                // close our file (don't blow out our file handles
-                wb.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/Borders.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/Borders.java
deleted file mode 100644 (file)
index 9509619..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFCellStyle;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
-import org.apache.poi.ss.usermodel.BorderStyle;
-
-/**
- * Demonstrates how to create borders around cells.
- */
-public class Borders {
-    public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet = wb.createSheet("new sheet");
-
-            // Create a row and put some cells in it. Rows are 0 based.
-            HSSFRow row = sheet.createRow(1);
-
-            // Create a cell and put a value in it.
-            HSSFCell cell = row.createCell(1);
-            cell.setCellValue(4);
-
-            // Style the cell with borders all around.
-            HSSFCellStyle style = wb.createCellStyle();
-            style.setBorderBottom(BorderStyle.THIN);
-            style.setBottomBorderColor(HSSFColorPredefined.BLACK.getIndex());
-            style.setBorderLeft(BorderStyle.THIN);
-            style.setLeftBorderColor(HSSFColorPredefined.GREEN.getIndex());
-            style.setBorderRight(BorderStyle.THIN);
-            style.setRightBorderColor(HSSFColorPredefined.BLUE.getIndex());
-            style.setBorderTop(BorderStyle.MEDIUM_DASHED);
-            style.setTopBorderColor(HSSFColorPredefined.ORANGE.getIndex());
-            cell.setCellStyle(style);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/CellComments.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/CellComments.java
deleted file mode 100644 (file)
index 877708b..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import org.apache.poi.hssf.usermodel.HSSFComment;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.ClientAnchor;
-import org.apache.poi.ss.usermodel.Comment;
-import org.apache.poi.ss.usermodel.CreationHelper;
-import org.apache.poi.ss.usermodel.Drawing;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.usermodel.RichTextString;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Demonstrates how to work with excel cell comments.<p>
- *
- * Excel comment is a kind of a text shape,
- * so inserting a comment is very similar to placing a text box in a worksheet
- */
-public class CellComments {
-
-    public static void main(String[] args) throws IOException  {
-        createWorkbook(false, ".xls");
-        createWorkbook(true, ".xlsx");
-    }
-
-    private static void createWorkbook(boolean xssf, String extension) throws IOException {
-        try (Workbook wb = WorkbookFactory.create(xssf)) {
-            Sheet sheet = wb.createSheet("Cell comments in POI " + extension);
-            CreationHelper creationHelper = wb.getCreationHelper();
-
-            // Create the drawing patriarch. This is the top level container for all shapes including cell comments.
-            Drawing<?> patr = sheet.createDrawingPatriarch();
-
-            //create a cell in row 3
-            Cell cell1 = sheet.createRow(3).createCell(1);
-            cell1.setCellValue(creationHelper.createRichTextString("Hello, World"));
-
-            //anchor defines size and position of the comment in worksheet
-            ClientAnchor clientAnchor = creationHelper.createClientAnchor();
-            clientAnchor.setCol1(4);
-            clientAnchor.setRow1(2);
-            clientAnchor.setCol2(6);
-            clientAnchor.setRow2(5);
-            Comment comment1 = patr.createCellComment(clientAnchor);
-
-            // set text in the comment
-            comment1.setString(creationHelper.createRichTextString("We can set comments in POI"));
-
-            //set comment author.
-            //you can see it in the status bar when moving mouse over the commented cell
-            comment1.setAuthor("Apache Software Foundation");
-
-            // The first way to assign comment to a cell is via Cell.setCellComment method
-            cell1.setCellComment(comment1);
-
-            //create another cell in row 6
-            Cell cell2 = sheet.createRow(6).createCell(1);
-            cell2.setCellValue(36.6);
-
-
-            clientAnchor = creationHelper.createClientAnchor();
-            clientAnchor.setCol1(4);
-            clientAnchor.setRow1(8);
-            clientAnchor.setCol2(6);
-            clientAnchor.setRow2(11);
-            Comment comment2 = patr.createCellComment(clientAnchor);
-            //modify background color of the comment, only available in HSSF currently
-            if (wb instanceof HSSFWorkbook) {
-                ((HSSFComment) comment2).setFillColor(204, 236, 255);
-            }
-
-            RichTextString string = creationHelper.createRichTextString("Normal body temperature");
-
-            //apply custom font to the text in the comment
-            Font font = wb.createFont();
-            font.setFontName("Arial");
-            font.setFontHeightInPoints((short) 10);
-            font.setBold(true);
-            font.setColor(IndexedColors.RED.getIndex());
-            string.applyFont(font);
-
-            comment2.setString(string);
-            comment2.setVisible(true); //by default comments are hidden. This one is always visible.
-
-            comment2.setAuthor("Bill Gates");
-
-            /*
-             * The second way to assign comment to a cell is to implicitly specify its row and column.
-             * Note, it is possible to set row and column of a non-existing cell.
-             * It works, the comment is visible.
-             */
-            comment2.setRow(6);
-            comment2.setColumn(1);
-
-            try (FileOutputStream out = new FileOutputStream("poi_comment" + extension)) {
-                wb.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/CellTypes.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/CellTypes.java
deleted file mode 100644 (file)
index f589bc6..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Date;
-
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.FormulaError;
-
-public class CellTypes {
-    public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet = wb.createSheet("new sheet");
-            HSSFRow row = sheet.createRow(2);
-            row.createCell(0).setCellValue(1.1);
-            row.createCell(1).setCellValue(new Date());
-            row.createCell(2).setCellValue("a string");
-            row.createCell(3).setCellValue(true);
-            row.createCell(4).setCellErrorValue(FormulaError.NUM);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/CreateCells.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/CreateCells.java
deleted file mode 100644 (file)
index b2b803f..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFCell;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Illustrates how to create cell values.
- *
- * @author Glen Stampoultzis (glens at apache.org)
- */
-public class CreateCells {
-    public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet = wb.createSheet("new sheet");
-
-            // Create a row and put some cells in it. Rows are 0 based.
-            HSSFRow row = sheet.createRow(0);
-            // Create a cell and put a value in it.
-            HSSFCell cell = row.createCell(0);
-            cell.setCellValue(1);
-
-            // Or do it on one line.
-            row.createCell(1).setCellValue(1.2);
-            row.createCell(2).setCellValue("This is a string");
-            row.createCell(3).setCellValue(true);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/CreateDateCells.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/CreateDateCells.java
deleted file mode 100644 (file)
index 9fea613..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Date;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFCellStyle;
-import org.apache.poi.hssf.usermodel.HSSFDataFormat;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-
-/**
- * An example on how to cells with dates.  The important thing to note
- * about dates is that they are really normal numeric cells that are
- * formatted specially.
- */
-public class CreateDateCells {
-    public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet = wb.createSheet("new sheet");
-
-            // Create a row and put some cells in it. Rows are 0 based.
-            HSSFRow row = sheet.createRow(0);
-
-            // Create a cell and put a date value in it.  The first cell is not styled as a date.
-            HSSFCell cell = row.createCell(0);
-            cell.setCellValue(new Date());
-
-            // we style the second cell as a date (and time).  It is important to create a new cell style from the workbook
-            // otherwise you can end up modifying the built in style and effecting not only this cell but other cells.
-            HSSFCellStyle cellStyle = wb.createCellStyle();
-            cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("m/d/yy h:mm"));
-            cell = row.createCell(1);
-            cell.setCellValue(new Date());
-            cell.setCellStyle(cellStyle);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/EmbeddedObjects.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/EmbeddedObjects.java
deleted file mode 100644 (file)
index 9c9d0bc..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.Closeable;
-import java.io.FileInputStream;
-
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.hssf.usermodel.HSSFObjectData;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hwpf.HWPFDocument;
-import org.apache.poi.poifs.filesystem.DirectoryNode;
-import org.apache.poi.poifs.filesystem.Entry;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-
-/**
- * Demonstrates how you can extract embedded data from a .xls file
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class EmbeddedObjects {
-    private EmbeddedObjects() {}
-
-    @SuppressWarnings("unused")
-    public static void main(String[] args) throws Exception {
-        try (
-            FileInputStream fis = new FileInputStream(args[0]);
-            POIFSFileSystem fs = new POIFSFileSystem(fis);
-            HSSFWorkbook workbook = new HSSFWorkbook(fs)
-        ) {
-            for (HSSFObjectData obj : workbook.getAllEmbeddedObjects()) {
-                //the OLE2 Class Name of the object
-                String oleName = obj.getOLE2ClassName();
-                DirectoryNode dn = (obj.hasDirectoryEntry()) ? (DirectoryNode) obj.getDirectory() : null;
-                Closeable document = null;
-                switch (oleName) {
-                    case "Worksheet":
-                        document = new HSSFWorkbook(dn, fs, false);
-                        break;
-                    case "Document":
-                        document = new HWPFDocument(dn);
-                        break;
-                    case "Presentation":
-                        document = new HSLFSlideShow(dn);
-                        break;
-                    default:
-                        if (dn != null) {
-                            // The DirectoryEntry is a DocumentNode. Examine its entries to find out what it is
-                            for (Entry entry : dn) {
-                                String name = entry.getName();
-                            }
-                        } else {
-                            // There is no DirectoryEntry
-                            // Recover the object's data from the HSSFObjectData instance.
-                            byte[] objectData = obj.getObjectData();
-                        }
-                        break;
-                }
-                if (document != null) {
-                    document.close();
-                }
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/EventExample.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/EventExample.java
deleted file mode 100644 (file)
index 9d3ba51..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
-import org.apache.poi.hssf.eventusermodel.HSSFListener;
-import org.apache.poi.hssf.eventusermodel.HSSFRequest;
-import org.apache.poi.hssf.record.BOFRecord;
-import org.apache.poi.hssf.record.BoundSheetRecord;
-import org.apache.poi.hssf.record.LabelSSTRecord;
-import org.apache.poi.hssf.record.NumberRecord;
-import org.apache.poi.hssf.record.RowRecord;
-import org.apache.poi.hssf.record.SSTRecord;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-
-/**
- * This example shows how to use the event API for reading a file.
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public class EventExample implements HSSFListener {
-    private SSTRecord sstrec;
-
-    /**
-     * This method listens for incoming records and handles them as required.
-     * @param record    The record that was found while reading.
-     */
-    @Override
-    public void processRecord(org.apache.poi.hssf.record.Record record)
-    {
-        switch (record.getSid())
-        {
-            // the BOFRecord can represent either the beginning of a sheet or the workbook
-            case BOFRecord.sid:
-                BOFRecord bof = (BOFRecord) record;
-                if (bof.getType() == BOFRecord.TYPE_WORKBOOK)
-                {
-                    System.out.println("Encountered workbook");
-                    // assigned to the class level member
-                } else if (bof.getType() == BOFRecord.TYPE_WORKSHEET)
-                {
-                    System.out.println("Encountered sheet reference");
-                }
-                break;
-            case BoundSheetRecord.sid:
-                BoundSheetRecord bsr = (BoundSheetRecord) record;
-                System.out.println("New sheet named: " + bsr.getSheetname());
-                break;
-            case RowRecord.sid:
-                RowRecord rowrec = (RowRecord) record;
-                System.out.println("Row found, first column at "
-                        + rowrec.getFirstCol() + " last column at " + rowrec.getLastCol());
-                break;
-            case NumberRecord.sid:
-                NumberRecord numrec = (NumberRecord) record;
-                System.out.println("Cell found with value " + numrec.getValue()
-                        + " at row " + numrec.getRow() + " and column " + numrec.getColumn());
-                break;
-                // SSTRecords store a array of unique strings used in Excel.
-            case SSTRecord.sid:
-                sstrec = (SSTRecord) record;
-                for (int k = 0; k < sstrec.getNumUniqueStrings(); k++)
-                {
-                    System.out.println("String table value " + k + " = " + sstrec.getString(k));
-                }
-                break;
-            case LabelSSTRecord.sid:
-                LabelSSTRecord lrec = (LabelSSTRecord) record;
-                System.out.println("String cell found with value "
-                        + sstrec.getString(lrec.getSSTIndex()));
-                break;
-        }
-    }
-
-    /**
-     * Read an excel file and spit out what we find.
-     *
-     * @param args      Expect one argument that is the file to read.
-     * @throws IOException  When there is an error processing the file.
-     */
-    public static void main(String[] args) throws IOException
-    {
-        // create a new file input stream with the input file specified
-        // at the command line
-        try (FileInputStream fin = new FileInputStream(args[0])) {
-            // create a new org.apache.poi.poifs.filesystem.Filesystem
-            try (POIFSFileSystem poifs = new POIFSFileSystem(fin)) {
-                // get the Workbook (excel part) stream in a InputStream
-                try (InputStream din = poifs.createDocumentInputStream("Workbook")) {
-                    // construct out HSSFRequest object
-                    HSSFRequest req = new HSSFRequest();
-                    // lazy listen for ALL records with the listener shown above
-                    req.addListenerForAllRecords(new EventExample());
-                    // create our event factory
-                    HSSFEventFactory factory = new HSSFEventFactory();
-                    // process our events based on the document input stream
-                    factory.processEvents(req, din);
-                }
-            }
-        }
-        System.out.println("done.");
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/FrillsAndFills.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/FrillsAndFills.java
deleted file mode 100644 (file)
index 9627780..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFCellStyle;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
-import org.apache.poi.ss.usermodel.FillPatternType;
-
-/**
- * Shows how to use various fills.
- */
-public class FrillsAndFills {
-    public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet = wb.createSheet("new sheet");
-
-            // Create a row and put some cells in it. Rows are 0 based.
-            HSSFRow row = sheet.createRow(1);
-
-            // Aqua background
-            HSSFCellStyle style = wb.createCellStyle();
-            style.setFillBackgroundColor(HSSFColorPredefined.AQUA.getIndex());
-            style.setFillPattern(FillPatternType.BIG_SPOTS);
-            HSSFCell cell = row.createCell(1);
-            cell.setCellValue("X");
-            cell.setCellStyle(style);
-
-            // Orange "foreground", foreground being the fill foreground not the font color.
-            style = wb.createCellStyle();
-            style.setFillForegroundColor(HSSFColorPredefined.ORANGE.getIndex());
-            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-            cell = row.createCell(2);
-            cell.setCellValue("X");
-            cell.setCellStyle(style);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/HSSFReadWrite.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/HSSFReadWrite.java
deleted file mode 100644 (file)
index 52667d1..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFCellStyle;
-import org.apache.poi.hssf.usermodel.HSSFDataFormat;
-import org.apache.poi.hssf.usermodel.HSSFFont;
-import org.apache.poi.hssf.usermodel.HSSFRichTextString;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.ss.util.CellRangeAddress;
-
-/**
- * File for HSSF testing/examples
- *
- * THIS IS NOT THE MAIN HSSF FILE!! This is a utility for testing functionality.
- * It does contain sample API usage that may be educational to regular API
- * users.
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public final class HSSFReadWrite {
-
-       private HSSFReadWrite() {}
-
-       /**
-        * creates an {@link HSSFWorkbook} with the specified OS filename.
-        */
-       private static HSSFWorkbook readFile(String filename) throws IOException {
-               try (FileInputStream fis = new FileInputStream(filename)) {
-                       return new HSSFWorkbook(fis);        // NOSONAR - should not be closed here
-               }
-       }
-
-       /**
-        * given a filename this outputs a sample sheet with just a set of
-        * rows/cells.
-        */
-       private static void testCreateSampleSheet(String outputFilename) throws IOException {
-               try (HSSFWorkbook wb = new HSSFWorkbook();
-                        FileOutputStream out = new FileOutputStream(outputFilename)) {
-                       HSSFSheet s = wb.createSheet();
-                       HSSFCellStyle cs = wb.createCellStyle();
-                       HSSFCellStyle cs2 = wb.createCellStyle();
-                       HSSFCellStyle cs3 = wb.createCellStyle();
-                       HSSFFont f = wb.createFont();
-                       HSSFFont f2 = wb.createFont();
-
-                       f.setFontHeightInPoints((short) 12);
-                       f.setColor((short) 0xA);
-                       f.setBold(true);
-                       f2.setFontHeightInPoints((short) 10);
-                       f2.setColor((short) 0xf);
-                       f2.setBold(true);
-                       cs.setFont(f);
-                       cs.setDataFormat(HSSFDataFormat.getBuiltinFormat("($#,##0_);[Red]($#,##0)"));
-                       cs2.setBorderBottom(BorderStyle.THIN);
-                       cs2.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-                       cs2.setFillForegroundColor((short) 0xA);
-                       cs2.setFont(f2);
-                       wb.setSheetName(0, "HSSF Test");
-                       int rownum;
-                       for (rownum = 0; rownum < 300; rownum++) {
-                               HSSFRow r = s.createRow(rownum);
-                               if ((rownum % 2) == 0) {
-                                       r.setHeight((short) 0x249);
-                               }
-
-                               for (int cellnum = 0; cellnum < 50; cellnum += 2) {
-                                       HSSFCell c = r.createCell(cellnum);
-                                       c.setCellValue((rownum * 10000.0) + cellnum
-                                                       + (rownum / 1000.0) + (cellnum / 10000.0));
-                                       if ((rownum % 2) == 0) {
-                                               c.setCellStyle(cs);
-                                       }
-                                       c = r.createCell(cellnum + 1);
-                                       c.setCellValue(new HSSFRichTextString("TEST"));
-                                       // 50 characters divided by 1/20th of a point
-                                       s.setColumnWidth(cellnum + 1, (int) (50 * 8 / 0.05));
-                                       if ((rownum % 2) == 0) {
-                                               c.setCellStyle(cs2);
-                                       }
-                               }
-                       }
-
-                       // draw a thick black border on the row at the bottom using BLANKS
-                       rownum++;
-                       rownum++;
-                       HSSFRow r = s.createRow(rownum);
-                       cs3.setBorderBottom(BorderStyle.THICK);
-                       for (int cellnum = 0; cellnum < 50; cellnum++) {
-                               HSSFCell c = r.createCell(cellnum);
-                               c.setCellStyle(cs3);
-                       }
-                       s.addMergedRegion(new CellRangeAddress(0, 3, 0, 3));
-                       s.addMergedRegion(new CellRangeAddress(100, 110, 100, 110));
-
-                       // end draw thick black border
-                       // create a sheet, set its title then delete it
-                       wb.createSheet();
-                       wb.setSheetName(1, "DeletedSheet");
-                       wb.removeSheetAt(1);
-
-                       // end deleted sheet
-                       wb.write(out);
-               }
-       }
-
-       /**
-     * Method main
-     *
-     * Given 1 argument takes that as the filename, inputs it and dumps the
-     * cell values/types out to sys.out.<br>
-     *
-     * given 2 arguments where the second argument is the word "write" and the
-     * first is the filename - writes out a sample (test) spreadsheet
-     * see {@link HSSFReadWrite#testCreateSampleSheet(String)}.<br>
-     *
-     * given 2 arguments where the first is an input filename and the second
-     * an output filename (not write), attempts to fully read in the
-     * spreadsheet and fully write it out.<br>
-     *
-     * given 3 arguments where the first is an input filename and the second an
-     * output filename (not write) and the third is "modify1", attempts to read in the
-     * spreadsheet, deletes rows 0-24, 74-99.  Changes cell at row 39, col 3 to
-     * "MODIFIED CELL" then writes it out.  Hence this is "modify test 1".  If you
-     * take the output from the write test, you'll have a valid scenario.
-     */
-       public static void main(String[] args) throws Exception {
-               if (args.length < 1) {
-                       System.err.println("At least one argument expected");
-                       return;
-               }
-
-               String fileName = args[0];
-               if (args.length < 2) {
-
-                       try (HSSFWorkbook wb = HSSFReadWrite.readFile(fileName)) {
-                               System.out.println("Data dump:\n");
-
-                               for (int k = 0; k < wb.getNumberOfSheets(); k++) {
-                                       HSSFSheet sheet = wb.getSheetAt(k);
-                                       int rows = sheet.getPhysicalNumberOfRows();
-                                       System.out.println("Sheet " + k + " \"" + wb.getSheetName(k) + "\" has " + rows + " row(s).");
-                                       for (int r = 0; r < rows; r++) {
-                                               HSSFRow row = sheet.getRow(r);
-                                               if (row == null) {
-                                                       continue;
-                                               }
-
-                                               System.out.println("\nROW " + row.getRowNum() + " has " + row.getPhysicalNumberOfCells() + " cell(s).");
-                                               for (int c = 0; c < row.getLastCellNum(); c++) {
-                                                       HSSFCell cell = row.getCell(c);
-                                                       String value;
-
-                                                       if (cell != null) {
-                                                               switch (cell.getCellType()) {
-
-                                                                       case FORMULA:
-                                                                               value = "FORMULA value=" + cell.getCellFormula();
-                                                                               break;
-
-                                                                       case NUMERIC:
-                                                                               value = "NUMERIC value=" + cell.getNumericCellValue();
-                                                                               break;
-
-                                                                       case STRING:
-                                                                               value = "STRING value=" + cell.getStringCellValue();
-                                                                               break;
-
-                                                                       case BLANK:
-                                                                               value = "<BLANK>";
-                                                                               break;
-
-                                                                       case BOOLEAN:
-                                                                               value = "BOOLEAN value-" + cell.getBooleanCellValue();
-                                                                               break;
-
-                                                                       case ERROR:
-                                                                               value = "ERROR value=" + cell.getErrorCellValue();
-                                                                               break;
-
-                                                                       default:
-                                                                               value = "UNKNOWN value of type " + cell.getCellType();
-                                                               }
-                                                               System.out.println("CELL col=" + cell.getColumnIndex() + " VALUE=" + value);
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               } else if (args.length == 2) {
-                       if ("write".equalsIgnoreCase(args[1])) {
-                               System.out.println("Write mode");
-                               long time = System.currentTimeMillis();
-                               HSSFReadWrite.testCreateSampleSheet(fileName);
-
-                               System.out.println("" + (System.currentTimeMillis() - time) + " ms generation time");
-                       } else {
-                               System.out.println("readwrite test");
-                               try (HSSFWorkbook wb = HSSFReadWrite.readFile(fileName);
-                                        FileOutputStream stream = new FileOutputStream(args[1])) {
-                                       wb.write(stream);
-                               }
-                       }
-               } else if (args.length == 3 && "modify1".equalsIgnoreCase(args[2])) {
-                       // delete row 0-24, row 74 - 99 && change cell 3 on row 39 to string "MODIFIED CELL!!"
-
-                       try (HSSFWorkbook wb = HSSFReadWrite.readFile(fileName);
-                                FileOutputStream stream = new FileOutputStream(args[1])) {
-                               HSSFSheet sheet = wb.getSheetAt(0);
-
-                               for (int k = 0; k < 25; k++) {
-                                       HSSFRow row = sheet.getRow(k);
-                                       sheet.removeRow(row);
-                               }
-                               for (int k = 74; k < 100; k++) {
-                                       HSSFRow row = sheet.getRow(k);
-                                       sheet.removeRow(row);
-                               }
-                               HSSFRow row = sheet.getRow(39);
-                               HSSFCell cell = row.getCell(3);
-                               cell.setCellValue("MODIFIED CELL!!!!!");
-
-                               wb.write(stream);
-                       }
-               }
-       }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/HyperlinkFormula.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/HyperlinkFormula.java
deleted file mode 100644 (file)
index 5229436..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-
-/**
- * Test if hyperlink formula, with url that got more than 127 characters, works
- */
-public class HyperlinkFormula {
-    public static void main(String[] args) throws IOException {
-       try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet = wb.createSheet("new sheet");
-            HSSFRow row = sheet.createRow(0);
-
-            HSSFCell cell = row.createCell(0);
-            cell.setCellFormula("HYPERLINK(\"http://127.0.0.1:8080/toto/truc/index.html?test=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\", \"test\")");
-
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/Hyperlinks.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/Hyperlinks.java
deleted file mode 100644 (file)
index 9189f15..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.common.usermodel.HyperlinkType;
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFCellStyle;
-import org.apache.poi.hssf.usermodel.HSSFCreationHelper;
-import org.apache.poi.hssf.usermodel.HSSFFont;
-import org.apache.poi.hssf.usermodel.HSSFHyperlink;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
-import org.apache.poi.ss.usermodel.Font;
-
-/**
- * Demonstrates how to create hyperlinks.
- */
-public class Hyperlinks {
-
-    public static void main(String[] args) throws IOException  {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFCreationHelper helper = wb.getCreationHelper();
-
-            //cell style for hyperlinks
-            //by default hyperlinks are blue and underlined
-            HSSFCellStyle hlinkStyle = wb.createCellStyle();
-            HSSFFont hlinkFont = wb.createFont();
-            hlinkFont.setUnderline(Font.U_SINGLE);
-            hlinkFont.setColor(HSSFColorPredefined.BLUE.getIndex());
-            hlinkStyle.setFont(hlinkFont);
-
-            HSSFCell cell;
-            HSSFSheet sheet = wb.createSheet("Hyperlinks");
-
-            //URL
-            cell = sheet.createRow(0).createCell(0);
-            cell.setCellValue("URL Link");
-            HSSFHyperlink link = helper.createHyperlink(HyperlinkType.URL);
-            link.setAddress("https://poi.apache.org/");
-            cell.setHyperlink(link);
-            cell.setCellStyle(hlinkStyle);
-
-            //link to a file in the current directory
-            cell = sheet.createRow(1).createCell(0);
-            cell.setCellValue("File Link");
-            link = helper.createHyperlink(HyperlinkType.FILE);
-            link.setAddress("link1.xls");
-            cell.setHyperlink(link);
-            cell.setCellStyle(hlinkStyle);
-
-            //e-mail link
-            cell = sheet.createRow(2).createCell(0);
-            cell.setCellValue("Email Link");
-            link = helper.createHyperlink(HyperlinkType.EMAIL);
-            //note, if subject contains white spaces, make sure they are url-encoded
-            link.setAddress("mailto:poi@apache.org?subject=Hyperlinks");
-            cell.setHyperlink(link);
-            cell.setCellStyle(hlinkStyle);
-
-            //link to a place in this workbook
-
-            //create a target sheet and cell
-            HSSFSheet sheet2 = wb.createSheet("Target Sheet");
-            sheet2.createRow(0).createCell(0).setCellValue("Target Cell");
-
-            cell = sheet.createRow(3).createCell(0);
-            cell.setCellValue("Worksheet Link");
-            link = helper.createHyperlink(HyperlinkType.DOCUMENT);
-            link.setAddress("'Target Sheet'!A1");
-            cell.setHyperlink(link);
-            cell.setCellStyle(hlinkStyle);
-
-            try (FileOutputStream out = new FileOutputStream("hssf-links.xls")) {
-                wb.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/InCellLists.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/InCellLists.java
deleted file mode 100644 (file)
index b8d1903..0000000
+++ /dev/null
@@ -1,541 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFCellStyle;
-import org.apache.poi.hssf.usermodel.HSSFDataFormat;
-import org.apache.poi.hssf.usermodel.HSSFRichTextString;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-
-/**
- * This class contains code that demonstrates how to insert plain, numbered
- * and bulleted lists into an Excel spreadsheet cell.
- *
- * Look at the code contained in the demonstrateMethodCalls() method. It calls
- * other methods that create plain, numbered and bulleted single and
- * multi-level lists. The demonstrateMethodCalls() method appears at the top
- * of the class definition.
- *
- * Though different methods are provided to construct single and multi-level
- * plain, numbered and bulleted lists, close examination will reveal that they
- * are not strictly necessary. If the inputs to the listInCell() and
- * multilLevelListInCell() methods are constructed to include the bullet
- * character or the item numbers then these methods alone may be sufficient.
- *
- * @author Mark Beardsley [msb at apache.org]
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public class InCellLists {
-
-    // This character looks like a solid, black, loser case letter 'o'
-    // positioned up from the base line of the text.
-    private static final char BULLET_CHARACTER = '\u2022';
-
-    // The tab character - \t - cannot be used to create a tab space
-    // within a cell as it is rendered as a square. Therefore, four
-    // spaces are used to simulate that character.
-    private static final String TAB = "    ";
-
-    /**
-     * Call each of the list creation methods.
-     *
-     * @param outputFilename A String that encapsulates the name of and path to
-     *                       the Excel spreadsheet file this code will create.
-     */
-    public void demonstrateMethodCalls(String outputFilename) throws IOException {
-        try (HSSFWorkbook workbook = new HSSFWorkbook()) {
-            HSSFSheet sheet = workbook.createSheet("In Cell Lists");
-            HSSFRow row = sheet.createRow(0);
-
-            // Create a cell at A1 and insert a single, bulleted, item into
-            // that cell.
-            HSSFCell cell = row.createCell(0);
-            this.bulletedItemInCell(workbook, "List Item", cell);
-
-            // Create a cell at A2 and insert a plain list - that is one
-            // whose items are neither bulleted or numbered - into that cell.
-            row = sheet.createRow(1);
-            cell = row.createCell(0);
-            List<String> listItems = new ArrayList<>();
-            listItems.add("List Item One.");
-            listItems.add("List Item Two.");
-            listItems.add("List Item Three.");
-            listItems.add("List Item Four.");
-            this.listInCell(workbook, listItems, cell);
-            // The row height and cell width are set here to ensure that the
-            // list may be seen.
-            row.setHeight((short) 1100);
-            sheet.setColumnWidth(0, 9500);
-
-            // Create a cell at A3 and insert a numbered list into that cell.
-            // Note that a couple of items have been added to the listItems
-            // ArrayList
-            row = sheet.createRow(2);
-            cell = row.createCell(0);
-            listItems.add("List Item Five.");
-            listItems.add("List Item Six.");
-            this.numberedListInCell(workbook, listItems, cell, 1, 2);
-            row.setHeight((short) 1550);
-
-            // Create a cell at A4 and insert a numbered list into that cell.
-            // Note that a couple of items have been added to the listItems
-            // ArrayList
-            row = sheet.createRow(3);
-            cell = row.createCell(0);
-            listItems.add("List Item Seven.");
-            listItems.add("List Item Eight.");
-            listItems.add("List Item Nine.");
-            listItems.add("List Item Ten.");
-            this.bulletedListInCell(workbook, listItems, cell);
-            row.setHeight((short) 2550);
-
-            // Insert a plain, multi-level list into cell A5. Note that
-            // the major difference here is that the list items are passed as
-            // an ArrayList of MultiLevelListItems. Note that an ArrayList
-            // of instances of an inner class was used here in preference to
-            // a Hashtable or HashMap as the ArrayList will preserve the
-            // ordering of the items added to it; the first item added will
-            // be the first item recovered and the last item added, the last
-            // item recovered. Alternatively, a LinkedHashMap could be used
-            // to preserve order.
-            row = sheet.createRow(4);
-            cell = row.createCell(0);
-            List<MultiLevelListItem> multiLevelListItems = new ArrayList<>();
-            listItems = new ArrayList<>();
-            listItems.add("ML List Item One - Sub Item One.");
-            listItems.add("ML List Item One - Sub Item Two.");
-            listItems.add("ML List Item One - Sub Item Three.");
-            listItems.add("ML List Item One - Sub Item Four.");
-            multiLevelListItems.add(new MultiLevelListItem("List Item One.", listItems));
-            // Passing either null or an empty ArrayList will signal that
-            // there are no lower level items associated with the top level
-            // item
-            multiLevelListItems.add(new MultiLevelListItem("List Item Two.", null));
-            multiLevelListItems.add(new MultiLevelListItem("List Item Three.", null));
-            listItems = new ArrayList<>();
-            listItems.add("ML List Item Four - Sub Item One.");
-            listItems.add("ML List Item Four - Sub Item Two.");
-            listItems.add("ML List Item Four - Sub Item Three.");
-            multiLevelListItems.add(new MultiLevelListItem("List Item Four.", listItems));
-            this.multiLevelListInCell(workbook, multiLevelListItems, cell);
-            row.setHeight((short) 2800);
-
-            // Insert a numbered multi-level list into cell A6. Note that the
-            // same ArrayList as constructed for the above plain multi-level
-            // list example will be re-used
-            row = sheet.createRow(5);
-            cell = row.createCell(0);
-            this.multiLevelNumberedListInCell(workbook, multiLevelListItems,
-                    cell, 1, 1, 1, 2);
-            row.setHeight((short) 2800);
-
-            // Insert a numbered multi-level list into cell A7. Note that the
-            // same ArrayList as constructed for the plain multi-level list
-            // example will be re-used
-            row = sheet.createRow(6);
-            cell = row.createCell(0);
-            this.multiLevelBulletedListInCell(workbook, multiLevelListItems, cell);
-            row.setHeight((short) 2800);
-
-            // Save the completed workbook
-            try (FileOutputStream fos = new FileOutputStream(new File(outputFilename))) {
-                workbook.write(fos);
-            }
-        } catch (IOException ioEx) {
-            System.out.println("Caught a: " + ioEx.getClass().getName());
-            System.out.println("Message: " + ioEx.getMessage());
-            System.out.println("Stacktrace follows...........");
-            ioEx.printStackTrace(System.out);
-        }
-    }
-
-    /**
-     * Inserts a single bulleted item into a cell.
-     *
-     * @param workbook A reference to the HSSFWorkbook that 'contains' the
-     *                 cell.
-     * @param listItem An instance of the String class encapsulating the
-     *                 items text.
-     * @param cell An instance of the HSSFCell class that encapsulates a
-     *             reference to the spreadsheet cell into which the list item
-     *             will be written.
-     */
-    public void bulletedItemInCell(HSSFWorkbook workbook, String listItem, HSSFCell cell) {
-        // A format String must be built to ensure that the contents of the
-        // cell appear as a bulleted item.
-        HSSFDataFormat format = workbook.createDataFormat();
-        String formatString = InCellLists.BULLET_CHARACTER + " @";
-        int formatIndex = format.getFormat(formatString);
-
-        // Construct an HSSFCellStyle and set it's data formt to use the
-        // object created above.
-        HSSFCellStyle bulletStyle = workbook.createCellStyle();
-        bulletStyle.setDataFormat((short)formatIndex);
-
-        // Set the cells contents and style.
-        cell.setCellValue(new HSSFRichTextString(listItem));
-        cell.setCellStyle(bulletStyle);
-    }
-
-    /**
-     * Inserts a list of plain items - that is items that are neither
-     * numbered or bulleted - into a single cell.
-     *
-     * @param workbook A reference to the HSSFWorkbook that 'contains' the
-     *                 cell.
-     * @param listItems An ArrayList whose elements encapsulate the text for
-     *                  the list's items.
-     * @param cell An instance of the HSSFCell class that encapsulates a
-     *             reference to the spreadsheet cell into which the list
-     *             will be written.
-     */
-    public void listInCell(HSSFWorkbook workbook, List<String> listItems, HSSFCell cell) {
-        StringBuilder buffer = new StringBuilder();
-        HSSFCellStyle wrapStyle = workbook.createCellStyle();
-        wrapStyle.setWrapText(true);
-        for(String listItem : listItems) {
-            buffer.append(listItem);
-            buffer.append("\n");
-        }
-        // The StringBuilder's contents are the source for the contents
-        // of the cell.
-        cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
-        cell.setCellStyle(wrapStyle);
-    }
-
-    /**
-     * Inserts a numbered list into a single cell.
-     *
-     * @param workbook A reference to the HSSFWorkbook that 'contains' the
-     *                 cell.
-     * @param listItems An ArrayList whose elements encapsulate the text for
-     *                  the lists items.
-     * @param cell An instance of the HSSFCell class that encapsulates a
-     *             reference to the spreadsheet cell into which the list
-     *             will be written.
-     * @param startingValue A primitive int containing the number for the first
-     *                      item in the list.
-     * @param increment A primitive int containing the value that should be used
-     *                  to calculate subsequent item numbers.
-     */
-    public void numberedListInCell(HSSFWorkbook workbook,
-                                   List<String> listItems,
-                                   HSSFCell cell,
-                                   int startingValue,
-                                   int increment) {
-        StringBuilder buffer = new StringBuilder();
-        int itemNumber = startingValue;
-        // Note that again, an HSSFCellStye object is required and that
-        // it's wrap text property should be set to 'true'
-        HSSFCellStyle wrapStyle = workbook.createCellStyle();
-        wrapStyle.setWrapText(true);
-        // Note that the basic method is identical to the listInCell() method
-        // with one difference; a number prefixed to the items text.
-        for(String listItem : listItems) {
-            buffer.append(itemNumber).append(". ");
-            buffer.append(listItem);
-            buffer.append("\n");
-            itemNumber += increment;
-        }
-        // The StringBuilder's contents are the source for the contents
-        // of the cell.
-        cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
-        cell.setCellStyle(wrapStyle);
-    }
-
-    /**
-     * Insert a bulleted list into a cell.
-     *
-     * @param workbook A reference to the HSSFWorkbook that 'contains' the
-     *                 cell.
-     * @param listItems An ArrayList whose elements encapsulate the text for
-     *                  the lists items.
-     * @param cell An instance of the HSSFCell class that encapsulates a
-     *             reference to the spreadsheet cell into which the list
-     *             will be written.
-     */
-    public void bulletedListInCell(HSSFWorkbook workbook,
-                                   List<String> listItems,
-                                   HSSFCell cell) {
-        StringBuilder buffer = new StringBuilder();
-        // Note that again, an HSSFCellStye object is required and that
-        // it's wrap text property should be set to 'true'
-        HSSFCellStyle wrapStyle = workbook.createCellStyle();
-        wrapStyle.setWrapText(true);
-        // Note that the basic method is identical to the listInCell() method
-        // with one difference; the bullet character prefixed to the items text.
-        for(String listItem : listItems) {
-            buffer.append(InCellLists.BULLET_CHARACTER + " ");
-            buffer.append(listItem);
-            buffer.append("\n");
-        }
-        // The StringBuilder's contents are the source for the contents
-        // of the cell.
-        cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
-        cell.setCellStyle(wrapStyle);
-    }
-
-    /**
-     * Insert a multi-level list into a cell.
-     *
-     * @param workbook A reference to the HSSFWorkbook that 'contains' the
-     *                 cell.
-     * @param multiLevelListItems An ArrayList whose elements contain instances
-     *                            of the MultiLevelListItem class. Each element
-     *                            encapsulates the text for the high level item
-     *                            along with an ArrayList. Each element of this
-     *                            ArrayList encapsulates the text for a lower
-     *                            level item.
-     * @param cell An instance of the HSSFCell class that encapsulates a
-     *             reference to the spreadsheet cell into which the list
-     *             will be written.
-     */
-    public void multiLevelListInCell(HSSFWorkbook workbook,
-                                     List<MultiLevelListItem> multiLevelListItems,
-                                     HSSFCell cell) {
-        StringBuilder buffer = new StringBuilder();
-        // Note that again, an HSSFCellStye object is required and that
-        // it's wrap text property should be set to 'true'
-        HSSFCellStyle wrapStyle = workbook.createCellStyle();
-        wrapStyle.setWrapText(true);
-        // Step through the ArrayList of MultilLevelListItem instances.
-        for(MultiLevelListItem multiLevelListItem : multiLevelListItems) {
-            // For each element in the ArrayList, get the text for the high
-            // level list item......
-            buffer.append(multiLevelListItem.getItemText());
-            buffer.append("\n");
-            // and then an ArrayList whose elements encapsulate the text
-            // for the lower level list items.
-            List<String> lowerLevelItems = multiLevelListItem.getLowerLevelItems();
-            if (lowerLevelItems == null || lowerLevelItems.isEmpty()) {
-                continue;
-            }
-            for(String item : lowerLevelItems) {
-                buffer.append(InCellLists.TAB);
-                buffer.append(item);
-                buffer.append("\n");
-            }
-        }
-        // The StringBuilder's contents are the source for the contents
-        // of the cell.
-        cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
-        cell.setCellStyle(wrapStyle);
-    }
-
-    /**
-     * Insert a multi-level list into a cell.
-     *
-     * @param workbook A reference to the HSSFWorkbook that 'contains' the
-     *                 cell.
-     * @param multiLevelListItems An ArrayList whose elements contain instances
-     *                            of the MultiLevelListItem class. Each element
-     *                            encapsulates the text for the high level item
-     *                            along with an ArrayList. Each element of this
-     *                            ArrayList encapsulates the text for a lower
-     *                            level item.
-     * @param cell An instance of the HSSFCell class that encapsulates a
-     *             reference to the spreadsheet cell into which the list
-     *             will be written.
-     * @param highLevelStartingValue A primitive int containing the number
-     *                               for the first high level item in the list.
-     * @param highLevelIncrement A primitive int containing the value that
-     *                           should be used to calculate the number of
-     *                           subsequent high level item.
-     * @param lowLevelStartingValue A primitive int will containing the number
-     *                              for the first low level item associated
-     *                              with a high level item.
-     * @param lowLevelIncrement A primitive int containing the value that
-     *                          should be used to calculate the number of
-     *                          subsequent low level item.
-     */
-    public void multiLevelNumberedListInCell(HSSFWorkbook workbook,
-                                             List<MultiLevelListItem> multiLevelListItems,
-                                             HSSFCell cell,
-                                             int highLevelStartingValue,
-                                             int highLevelIncrement,
-                                             int lowLevelStartingValue,
-                                             int lowLevelIncrement) {
-        StringBuilder buffer = new StringBuilder();
-        int highLevelItemNumber = highLevelStartingValue;
-        // Note that again, an HSSFCellStye object is required and that
-        // it's wrap text property should be set to 'true'
-        HSSFCellStyle wrapStyle = workbook.createCellStyle();
-        wrapStyle.setWrapText(true);
-        // Step through the ArrayList of MultilLevelListItem instances.
-        for(MultiLevelListItem multiLevelListItem : multiLevelListItems) {
-            // For each element in the ArrayList, get the text for the high
-            // level list item......
-            buffer.append(highLevelItemNumber);
-            buffer.append(". ");
-            buffer.append(multiLevelListItem.getItemText());
-            buffer.append("\n");
-            // and then an ArrayList whose elements encapsulate the text
-            // for the lower level list items.
-            List<String> lowerLevelItems = multiLevelListItem.getLowerLevelItems();
-            if(lowerLevelItems != null && !lowerLevelItems.isEmpty()) {
-                int lowLevelItemNumber = lowLevelStartingValue;
-                for(String item : lowerLevelItems) {
-                    buffer.append(InCellLists.TAB);
-                    buffer.append(highLevelItemNumber);
-                    buffer.append(".");
-                    buffer.append(lowLevelItemNumber);
-                    buffer.append(" ");
-                    buffer.append(item);
-                    buffer.append("\n");
-                    lowLevelItemNumber += lowLevelIncrement;
-                }
-            }
-            highLevelItemNumber += highLevelIncrement;
-        }
-        // The StringBuilder's contents are the source for the contents
-        // of the cell.
-        cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
-        cell.setCellStyle(wrapStyle);
-    }
-
-    /**
-     * Insert a bulleted multi-level list into a cell.
-     *
-     * @param workbook A reference to the HSSFWorkbook that 'contains' the
-     *                 cell.
-     * @param multiLevelListItems An ArrayList whose elements contain instances
-     *                            of the MultiLevelListItem class. Each element
-     *                            encapsulates the text for the high level item
-     *                            along with an ArrayList. Each element of this
-     *                            ArrayList encapsulates the text for a lower
-     *                            level item.
-     * @param cell An instance of the HSSFCell class that encapsulates a
-     *             reference to the spreadsheet cell into which the list
-     *             will be written.
-     */
-    public void multiLevelBulletedListInCell(HSSFWorkbook workbook,
-                                             List<MultiLevelListItem> multiLevelListItems,
-                                             HSSFCell cell) {
-        StringBuilder buffer = new StringBuilder();
-        // Note that again, an HSSFCellStye object is required and that
-        // it's wrap text property should be set to 'true'
-        HSSFCellStyle wrapStyle = workbook.createCellStyle();
-        wrapStyle.setWrapText(true);
-        // Step through the ArrayList of MultilLevelListItem instances.
-        for(MultiLevelListItem multiLevelListItem : multiLevelListItems) {
-            // For each element in the ArrayList, get the text for the high
-            // level list item......
-            buffer.append(InCellLists.BULLET_CHARACTER);
-            buffer.append(" ");
-            buffer.append(multiLevelListItem.getItemText());
-            buffer.append("\n");
-            // and then an ArrayList whose elements encapsulate the text
-            // for the lower level list items.
-            List<String> lowerLevelItems = multiLevelListItem.getLowerLevelItems();
-            if(lowerLevelItems != null && !lowerLevelItems.isEmpty()) {
-                for(String item : lowerLevelItems) {
-                    buffer.append(InCellLists.TAB);
-                    buffer.append(InCellLists.BULLET_CHARACTER);
-                    buffer.append(" ");
-                    buffer.append(item);
-                    buffer.append("\n");
-                }
-            }
-        }
-        // The StringBuilder's contents are the source for the contents
-        // of the cell.
-        cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
-        cell.setCellStyle(wrapStyle);
-    }
-
-    /**
-     * The main entry point to the program. Demonstrates how to call the method
-     * that will create an Excel workbook containing many different sorts of
-     * lists.
-     *
-     * @param args the command line arguments.
-     */
-    public static void main(String[] args) throws IOException {
-        new InCellLists().demonstrateMethodCalls("Latest In Cell List.xls");
-    }
-
-    /**
-     * An instance of this inner class models an item or element in a
-     * multi-level list. Each multi-level list item consists of the text for the
-     * high level items and an ArrayList containing the text for each of the
-     * associated lower level items. When written into a cell, each multi-level
-     * list item will have this general appearance.
-     *
-     *     Item One
-     *         Sub Item One.
-     *         Sub Item Two.
-     *     Item Two
-     *         Sub Item One.
-     *         Sub Item Two.
-     *     etc.
-     *
-     * It would be quite possible to modify this class to model much more
-     * complex list structures descending through two, three or even more
-     * levels.
-     */
-    public final class MultiLevelListItem {
-
-        private String itemText;
-        private List<String> lowerLevelItems;
-
-        /**
-         * Create a new instance of the MultiLevelListItem class using the
-         * following parameters.
-         *
-         * @param itemText A String that encapsulates the text for the high
-         *                 level list item.
-         * @param lowerLevelItems An ArrayList whose elements encapsulate the
-         *                        text for the associated lower level list
-         *                        items.
-         */
-        public MultiLevelListItem(String itemText, List<String> lowerLevelItems) {
-            this.itemText = itemText;
-            this.lowerLevelItems = lowerLevelItems;
-        }
-
-        /**
-         * Get the text for the high level list item.
-         *
-         * @return A String that encapsulates the text for the high level list
-         *         item.
-         */
-        public String getItemText() {
-            return(this.itemText);
-        }
-
-        /**
-         * Get the text for the associated lower level list items.
-         *
-         * @return An ArrayList whose elements each encapsulate the text for a
-         *         single associated lower level list item.
-         */
-        public List<String> getLowerLevelItems() {
-            return lowerLevelItems;
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/MergedCells.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/MergedCells.java
deleted file mode 100644 (file)
index af1d8dd..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.util.CellRangeAddress;
-
-/**
- * An example of how to merge regions of cells.
- */
-public class MergedCells {
-   public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-             HSSFSheet sheet = wb.createSheet("new sheet");
-
-             HSSFRow row = sheet.createRow(1);
-             HSSFCell cell = row.createCell(1);
-             cell.setCellValue("This is a test of merging");
-
-             sheet.addMergedRegion(new CellRangeAddress(1, 1, 1, 2));
-
-             // Write the output to a file
-             try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                  wb.write(fileOut);
-             }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/NewLinesInCells.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/NewLinesInCells.java
deleted file mode 100644 (file)
index 2b7ce2d..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFCellStyle;
-import org.apache.poi.hssf.usermodel.HSSFFont;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-
-/**
- * Demonstrates how to use newlines in cells.
- */
-public class NewLinesInCells {
-    public static void main( String[] args ) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-                       HSSFSheet s = wb.createSheet();
-                       HSSFFont f2 = wb.createFont();
-
-                       HSSFCellStyle cs = wb.createCellStyle();
-
-                       cs.setFont(f2);
-                       // Word Wrap MUST be turned on
-                       cs.setWrapText(true);
-
-                       HSSFRow r = s.createRow(2);
-                       r.setHeight((short) 0x349);
-                       HSSFCell c = r.createCell(2);
-                       c.setCellValue("Use \n with word wrap on to create a new line");
-                       c.setCellStyle(cs);
-                       s.setColumnWidth(2, (int) ((50 * 8) / ((double) 1 / 20)));
-
-                       try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                               wb.write(fileOut);
-                       }
-               }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/NewSheet.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/NewSheet.java
deleted file mode 100644 (file)
index 2254254..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.util.WorkbookUtil;
-
-/**
- * Creates a new workbook with a sheet that's been explicitly defined.
- */
-public abstract class NewSheet {
-    public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            wb.createSheet("new sheet");
-            // create with default name
-            wb.createSheet();
-            final String name = "second sheet";
-            // setting sheet name later
-            wb.setSheetName(1, WorkbookUtil.createSafeSheetName(name));
-
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/NewWorkbook.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/NewWorkbook.java
deleted file mode 100644 (file)
index 3e61aaf..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-        
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-
-/**
- * This example creates a new blank workbook.  This workbook will contain a single blank sheet.
- */
-public class NewWorkbook {
-    public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/OfficeDrawing.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/OfficeDrawing.java
deleted file mode 100644 (file)
index 7e703c5..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFChildAnchor;
-import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
-import org.apache.poi.hssf.usermodel.HSSFFont;
-import org.apache.poi.hssf.usermodel.HSSFPatriarch;
-import org.apache.poi.hssf.usermodel.HSSFPicture;
-import org.apache.poi.hssf.usermodel.HSSFPolygon;
-import org.apache.poi.hssf.usermodel.HSSFRichTextString;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFShape;
-import org.apache.poi.hssf.usermodel.HSSFShapeGroup;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFSimpleShape;
-import org.apache.poi.hssf.usermodel.HSSFTextbox;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.Workbook;
-
-/**
- * Demonstrates how to use the office drawing capabilities of POI.
- */
-public final class OfficeDrawing {
-    private OfficeDrawing() {}
-
-    public static void main(String[] args) throws IOException {
-        // Create the workbook and sheets.
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet1 = wb.createSheet("new sheet");
-            HSSFSheet sheet2 = wb.createSheet("second sheet");
-            HSSFSheet sheet3 = wb.createSheet("third sheet");
-            HSSFSheet sheet4 = wb.createSheet("fourth sheet");
-            HSSFSheet sheet5 = wb.createSheet("fifth sheet");
-
-            // Draw stuff in them
-            drawSheet1(sheet1);
-            drawSheet2(sheet2);
-            drawSheet3(sheet3);
-            drawSheet4(sheet4, wb);
-            drawSheet5(sheet5, wb);
-
-            // Write the file out.
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-
-    private static void drawSheet1( HSSFSheet sheet1 )
-    {
-        // Create a row and size one of the cells reasonably large.
-        HSSFRow row = sheet1.createRow(2);
-        row.setHeight((short) 2800);
-        row.createCell(1);
-        sheet1.setColumnWidth(2, 9000);
-
-        // Create the drawing patriarch.  This is the top level container for
-        // all shapes.
-        HSSFPatriarch patriarch = sheet1.createDrawingPatriarch();
-
-        // Draw some lines and an oval.
-        drawLinesToCenter( patriarch );
-        drawManyLines( patriarch );
-        drawOval( patriarch );
-        drawPolygon( patriarch );
-
-        // Draw a rectangle.
-        HSSFSimpleShape rect = patriarch.createSimpleShape( new HSSFClientAnchor(100, 100, 900, 200, (short)0, 0, (short)0, 0) );
-        rect.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE);
-    }
-
-    private static void drawSheet2( HSSFSheet sheet2 )
-    {
-        // Create a row and size one of the cells reasonably large.
-        HSSFRow row = sheet2.createRow(2);
-        row.createCell(1);
-        row.setHeightInPoints(240);
-        sheet2.setColumnWidth(2, 9000);
-
-        // Create the drawing patriarch.  This is the top level container for
-        // all shapes. This will clear out any existing shapes for that sheet.
-        HSSFPatriarch patriarch = sheet2.createDrawingPatriarch();
-
-        // Draw a grid in one of the cells.
-        drawGrid( patriarch );
-    }
-
-    private static void drawSheet3( HSSFSheet sheet3 )
-    {
-        // Create a row and size one of the cells reasonably large
-        HSSFRow row = sheet3.createRow(2);
-        row.setHeightInPoints(140);
-        row.createCell(1);
-        sheet3.setColumnWidth(2, 9000);
-
-        // Create the drawing patriarch.  This is the top level container for
-        // all shapes. This will clear out any existing shapes for that sheet.
-        HSSFPatriarch patriarch = sheet3.createDrawingPatriarch();
-
-        // Create a shape group.
-        HSSFShapeGroup group = patriarch.createGroup(
-                new HSSFClientAnchor(0,0,900,200,(short)2,2,(short)2,2));
-
-        // Create a couple of lines in the group.
-        HSSFSimpleShape shape1 = group.createShape(new HSSFChildAnchor(3,3,500,500));
-        shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
-        ( (HSSFChildAnchor) shape1.getAnchor() ).setAnchor((short)3,3,500,500);
-        HSSFSimpleShape shape2 = group.createShape(new HSSFChildAnchor((short)1,200,400,600));
-        shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
-
-    }
-
-    private static void drawSheet4( HSSFSheet sheet4, HSSFWorkbook wb )
-    {
-        // Create the drawing patriarch.  This is the top level container for
-        // all shapes. This will clear out any existing shapes for that sheet.
-        HSSFPatriarch patriarch = sheet4.createDrawingPatriarch();
-
-        // Create a couple of textboxes
-        HSSFTextbox textbox1 = patriarch.createTextbox(
-                new HSSFClientAnchor(0,0,0,0,(short)1,1,(short)2,2));
-        textbox1.setString(new HSSFRichTextString("This is a test") );
-        HSSFTextbox textbox2 = patriarch.createTextbox(
-                new HSSFClientAnchor(0,0,900,100,(short)3,3,(short)3,4));
-        textbox2.setString(new HSSFRichTextString("Woo") );
-        textbox2.setFillColor(200,0,0);
-        textbox2.setLineStyle(HSSFShape.LINESTYLE_DOTGEL);
-
-        // Create third one with some fancy font styling.
-        HSSFTextbox textbox3 = patriarch.createTextbox(
-                new HSSFClientAnchor(0,0,900,100,(short)4,4,(short)5,4+1));
-        HSSFFont font = wb.createFont();
-        font.setItalic(true);
-        font.setUnderline(Font.U_DOUBLE);
-        HSSFRichTextString string = new HSSFRichTextString("Woo!!!");
-        string.applyFont(2,5,font);
-        textbox3.setString(string );
-        textbox3.setFillColor(0x08000030);
-        textbox3.setLineStyle(HSSFShape.LINESTYLE_NONE);  // no line around the textbox.
-        textbox3.setNoFill(true);    // make it transparent
-    }
-
-    private static void drawSheet5( HSSFSheet sheet5, HSSFWorkbook wb ) throws IOException
-    {
-
-        // Create the drawing patriarch.  This is the top level container for
-        // all shapes. This will clear out any existing shapes for that sheet.
-        HSSFPatriarch patriarch = sheet5.createDrawingPatriarch();
-
-        HSSFClientAnchor anchor;
-        anchor = new HSSFClientAnchor(0,0,0,255,(short)2,2,(short)4,7);
-        anchor.setAnchorType( AnchorType.MOVE_DONT_RESIZE );
-        patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4.png", wb ));
-
-        anchor = new HSSFClientAnchor(0,0,0,255,(short)4,2,(short)5,7);
-        anchor.setAnchorType( AnchorType.MOVE_DONT_RESIZE );
-        patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4edited.png", wb ));
-
-        anchor = new HSSFClientAnchor(0,0,1023,255,(short)6,2,(short)8,7);
-        anchor.setAnchorType( AnchorType.MOVE_DONT_RESIZE );
-        HSSFPicture picture = patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4s.png", wb ));
-        //Reset the image to the original size.
-        picture.resize();
-        picture.setLineStyle( HSSFShape.LINESTYLE_DASHDOTGEL );
-
-    }
-
-    private static int loadPicture( String path, HSSFWorkbook wb ) throws IOException
-    {
-        int pictureIndex;
-        try (FileInputStream fis = new FileInputStream(path);
-             ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
-            int c;
-            while ((c = fis.read()) != -1)
-                bos.write(c);
-            pictureIndex = wb.addPicture(bos.toByteArray(), Workbook.PICTURE_TYPE_PNG);
-        }
-        return pictureIndex;
-    }
-
-    private static void drawOval( HSSFPatriarch patriarch )
-    {
-        // Create an oval and style to taste.
-        HSSFClientAnchor a = new HSSFClientAnchor();
-        a.setAnchor((short)2, 2, 20, 20, (short) 2, 2, 190, 80);
-        HSSFSimpleShape s = patriarch.createSimpleShape(a);
-        s.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
-        s.setLineStyleColor(10,10,10);
-        s.setFillColor(90,10,200);
-        s.setLineWidth(HSSFShape.LINEWIDTH_ONE_PT * 3);
-        s.setLineStyle(HSSFShape.LINESTYLE_DOTSYS);
-    }
-
-    private static void drawPolygon( HSSFPatriarch patriarch )
-    {
-        //        HSSFClientAnchor a = new HSSFClientAnchor( 0, 0, 1023, 255, (short) 2, 2, (short) 3, 3 );
-        //        HSSFPolygon p = patriarch.createPolygon(a);
-        //        p.setPolygonDrawArea(100,100);
-        //        p.setPoints( new int[]{30, 90, 50}, new int[]{88, 5, 44} );
-
-
-        HSSFClientAnchor a = new HSSFClientAnchor();
-        a.setAnchor( (short) 2, 2, 0, 0, (short) 3, 3, 1023, 255 );
-        HSSFShapeGroup g = patriarch.createGroup( a );
-        g.setCoordinates(0,0,200,200);
-        HSSFPolygon p1 = g.createPolygon( new HSSFChildAnchor( 0, 0, 200, 200 ) );
-        p1.setPolygonDrawArea( 100, 100 );
-        p1.setPoints( new int[]{0, 90, 50}, new int[]{5, 5, 44} );
-        p1.setFillColor( 0, 255, 0 );
-        HSSFPolygon p2 = g.createPolygon( new HSSFChildAnchor( 20, 20, 200, 200 ) );
-        p2.setPolygonDrawArea( 200, 200 );
-        p2.setPoints( new int[]{120, 20, 150}, new int[]{105, 30, 195} );
-        p2.setFillColor( 255, 0, 0 );
-    }
-
-    private static void drawManyLines( HSSFPatriarch patriarch )
-    {
-        // Draw bunch of lines
-        int x1 = 100;
-        int y1 = 100;
-        int x2 = 800;
-        int y2 = 200;
-        int color = 0;
-        for (int i = 0; i < 10; i++)
-        {
-            HSSFClientAnchor a2 = new HSSFClientAnchor();
-            a2.setAnchor((short) 2, 2, x1, y1, (short) 2, 2, x2, y2);
-            HSSFSimpleShape shape2 = patriarch.createSimpleShape(a2);
-            shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
-            shape2.setLineStyleColor(color);
-            y1 -= 10;
-            y2 -= 10;
-            color += 30;
-        }
-    }
-
-    private static void drawGrid( HSSFPatriarch patriarch )
-    {
-        // This draws a grid of lines.  Since the coordinates space fixed at
-        // 1024 by 256 we use a ratio to get a reasonably square grids.
-
-        double xRatio = 3.22;
-        double yRatio = 0.6711;
-
-        int x1 = 0;
-        int y1 = 0;
-        int x2 = 0;
-        int y2 = 200;
-        for (int i = 0; i < 20; i++)
-        {
-            HSSFClientAnchor a2 = new HSSFClientAnchor();
-            a2.setAnchor((short) 2, 2, (int) ( x1 * xRatio ), (int) ( y1 * yRatio ),
-                    (short) 2, 2, (int) ( x2 * xRatio ), (int) ( y2 * yRatio ));
-            HSSFSimpleShape shape2 = patriarch.createSimpleShape(a2);
-            shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
-
-            x1 += 10;
-            x2 += 10;
-        }
-
-        x1 = 0;
-        y1 = 0;
-        x2 = 200;
-        y2 = 0;
-        for (int i = 0; i < 20; i++)
-        {
-            HSSFClientAnchor a2 = new HSSFClientAnchor();
-            a2.setAnchor((short) 2, 2, (int) ( x1 * xRatio ), (int) ( y1 * yRatio ),
-                    (short) 2, 2, (int) ( x2 * xRatio ), (int) ( y2 * yRatio ));
-            HSSFSimpleShape shape2 = patriarch.createSimpleShape(a2);
-            shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
-
-            y1 += 10;
-            y2 += 10;
-        }
-    }
-
-    private static void drawLinesToCenter( HSSFPatriarch patriarch )
-    {
-        // Draw some lines from and to the corners
-        {
-            HSSFClientAnchor a1 = new HSSFClientAnchor();
-            a1.setAnchor( (short)2, 2, 0, 0, (short) 2, 2, 512, 128);
-            HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
-            shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
-        }
-        {
-            HSSFClientAnchor a1 = new HSSFClientAnchor();
-            a1.setAnchor( (short)2, 2, 512, 128, (short) 2, 2, 1024, 0);
-            HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
-            shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
-        }
-        {
-            HSSFClientAnchor a1 = new HSSFClientAnchor();
-            a1.setAnchor( (short)1, 1, 0, 0, (short) 1, 1, 512, 100);
-            HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
-            shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
-        }
-        {
-            HSSFClientAnchor a1 = new HSSFClientAnchor();
-            a1.setAnchor( (short)1, 1, 512, 100, (short) 1, 1, 1024, 0);
-            HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
-            shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
-        }
-
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/OfficeDrawingWithGraphics.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/OfficeDrawingWithGraphics.java
deleted file mode 100644 (file)
index b437371..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import org.apache.poi.hssf.usermodel.*;
-
-import java.awt.*;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Demonstrates the use of the EscherGraphics2d library.
- *
- * @author Glen Stampoultzis (glens at apache.org)
- */
-public class OfficeDrawingWithGraphics {
-    public static void main( String[] args ) throws IOException {
-        // Create a workbook with one sheet and size the first three somewhat
-        // larger so we can fit the chemical structure diagram in.
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet = wb.createSheet("my drawing");
-            sheet.setColumnWidth(1, 256 * 27);
-            HSSFRow row1 = sheet.createRow(0);
-            row1.setHeightInPoints(10 * 15f);
-            HSSFRow row2 = sheet.createRow(1);
-            row2.setHeightInPoints(5 * 15f);
-            HSSFRow row3 = sheet.createRow(2);
-            row3.setHeightInPoints(10 * 15f);
-
-            // Add some cells so we can test that the anchoring works when we
-            // sort them.
-            row1.createCell(0).setCellValue("C");
-            row2.createCell(0).setCellValue("A");
-            row3.createCell(0).setCellValue("B");
-
-            // Create the top level drawing patriarch.
-            HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
-
-            HSSFClientAnchor a;
-            HSSFShapeGroup group;
-            EscherGraphics g;
-            EscherGraphics2d g2d;
-            // Anchor entirely within one cell.
-            a = new HSSFClientAnchor(0, 0, 1023, 255, (short) 1, 0, (short) 1, 0);
-            group = patriarch.createGroup(a);
-            group.setCoordinates(0, 0, 320, 276);
-            float verticalPointsPerPixel = a.getAnchorHeightInPoints(sheet) / Math.abs(group.getY2() - group.getY1());
-            g = new EscherGraphics(group, wb, Color.black, verticalPointsPerPixel);
-            g2d = new EscherGraphics2d(g);
-            drawStar(g2d);
-
-            a = new HSSFClientAnchor(0, 0, 1023, 255, (short) 1, 1, (short) 1, 1);
-            group = patriarch.createGroup(a);
-            group.setCoordinates(0, 0, 640, 276);
-            verticalPointsPerPixel = a.getAnchorHeightInPoints(sheet) / Math.abs(group.getY2() - group.getY1());
-//        verticalPixelsPerPoint = (float)Math.abs(group.getY2() - group.getY1()) / a.getAnchorHeightInPoints(sheet);
-            g = new EscherGraphics(group, wb, Color.black, verticalPointsPerPixel);
-            g2d = new EscherGraphics2d(g);
-            drawStar(g2d);
-
-            try (FileOutputStream out = new FileOutputStream("workbook.xls")) {
-                wb.write(out);
-            }
-        }
-    }
-
-    private static void drawStar( EscherGraphics2d g2d )
-    {
-        g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
-        for (double i = 0; i < Math.PI; i += 0.1)
-        {
-            g2d.setColor( new Color((int)(i * 5343062d) ) );
-            int x1 = (int) ( Math.cos(i) * 160.0 ) + 160;
-            int y1 = (int) ( Math.sin(i) * 138.0 ) + 138;
-            int x2 = (int) ( -Math.cos(i) * 160.0 ) + 160;
-            int y2 = (int) ( -Math.sin(i) * 138.0 ) + 138;
-            g2d.setStroke(new BasicStroke(2));
-            g2d.drawLine(x1,y1,x2,y2);
-        }
-        g2d.setFont(new Font("SansSerif",Font.BOLD | Font.ITALIC, 20));
-        g2d.drawString("EscherGraphics2d",70,100);
-        g2d.setColor(Color.yellow);
-        g2d.fillOval( 160-20,138-20,40,40);
-        g2d.setColor(Color.black);
-        g2d.fillPolygon(new int[] {-10+160,0+160,10+160,0+160}, new int[] {0+138,10+138,0+138,-10+138}, 4);
-        g2d.drawPolygon(new int[] {-160+160,0+160,160+160,0+160}, new int[] {0+138,138+138,0+138,-138+138}, 4);
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/Outlines.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/Outlines.java
deleted file mode 100644 (file)
index 9630957..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.Closeable;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
-
-/**
- * Creates outlines.
- */
-public class Outlines implements Closeable {
-    public static void main(String[] args)
-    throws IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
-        POILogger LOGGER = POILogFactory.getLogger(Outlines.class);
-        for (int i=1; i<=13; i++) {
-            try (Outlines o = new Outlines()) {
-                String log = (String) Outlines.class.getDeclaredMethod("test" + i).invoke(o);
-                String filename = "outline" + i + ".xls";
-                o.writeOut(filename);
-                LOGGER.log(POILogger.INFO, filename + " written. " + log);
-            }
-        }
-    }
-
-    private final HSSFWorkbook wb = new HSSFWorkbook();
-    private final HSSFSheet sheet1 = wb.createSheet("new sheet");
-
-    public void writeOut(String filename) throws IOException {
-        try (FileOutputStream fileOut = new FileOutputStream(filename)) {
-            wb.write(fileOut);
-        }
-    }
-    
-    @Override
-    public void close() throws IOException {
-        wb.close();
-    }
-
-    public String test1() {
-        sheet1.groupColumn(4, 7);
-
-        for (int row = 0; row < 200; row++) {
-            HSSFRow r = sheet1.createRow(row);
-            for (int column = 0; column < 200; column++) {
-                HSSFCell c = r.createCell(column);
-                c.setCellValue(column);
-            }
-        }
-        return "Two expanded groups.";
-    }
-
-    public String test2() {
-        sheet1.groupColumn(2, 10);
-        sheet1.groupColumn(4, 7);
-        sheet1.setColumnGroupCollapsed(4, true);
-        return "Two groups.  Inner group collapsed.";
-    }
-
-    public String test3() {
-        sheet1.groupColumn(2, 10);
-        sheet1.groupColumn(4, 7);
-        sheet1.setColumnGroupCollapsed(4, true);
-        sheet1.setColumnGroupCollapsed(2, true);
-        return "Two groups.  Both collapsed.";
-    }
-
-    public String test4() {
-        sheet1.groupColumn(2, 10);
-        sheet1.groupColumn(4, 7);
-        sheet1.setColumnGroupCollapsed(4, true);
-        sheet1.setColumnGroupCollapsed(2, true);
-
-        sheet1.setColumnGroupCollapsed(4, false);
-        return "Two groups.  Collapsed then inner group expanded.";
-    }
-
-    public String test5() {
-        sheet1.groupColumn(2, 10);
-        sheet1.groupColumn(4, 7);
-        sheet1.setColumnGroupCollapsed(4, true);
-        sheet1.setColumnGroupCollapsed(2, true);
-
-        sheet1.setColumnGroupCollapsed(4, false);
-        sheet1.setColumnGroupCollapsed(3, false);
-        return "Two groups.  Collapsed then reexpanded.";
-    }
-
-    public String test6() {
-        sheet1.groupColumn(2, 10);
-        sheet1.groupColumn(4, 10);
-        sheet1.setColumnGroupCollapsed(4, true);
-        sheet1.setColumnGroupCollapsed(2, true);
-
-        sheet1.setColumnGroupCollapsed(3, false);
-        return "Two groups with matching end points.  Second group collapsed.";
-    }
-
-    public String test7() {
-        sheet1.groupRow(5, 14);
-        sheet1.groupRow(7, 10);
-        return "Row outlines.";
-    }
-
-    public String test8() {
-        sheet1.groupRow(5, 14);
-        sheet1.groupRow(7, 10);
-        sheet1.setRowGroupCollapsed(7, true);
-        return "Row outlines.  Inner group collapsed.";
-    }
-
-    public String test9() {
-        sheet1.groupRow(5, 14);
-        sheet1.groupRow(7, 10);
-        sheet1.setRowGroupCollapsed(7, true);
-        sheet1.setRowGroupCollapsed(5, true);
-        return "Row outlines.  Both collapsed.";
-    }
-
-    public String test10() {
-        sheet1.groupRow(5, 14);
-        sheet1.groupRow(7, 10);
-        sheet1.setRowGroupCollapsed(7, true);
-        sheet1.setRowGroupCollapsed(5, true);
-        sheet1.setRowGroupCollapsed(8, false);
-        return "Row outlines.  Collapsed then inner group expanded.";
-    }
-
-    public String test11() {
-        sheet1.groupRow(5, 14);
-        sheet1.groupRow(7, 10);
-        sheet1.setRowGroupCollapsed(7, true);
-        sheet1.setRowGroupCollapsed(5, true);
-        sheet1.setRowGroupCollapsed(8, false);
-        sheet1.setRowGroupCollapsed(14, false);
-        return "Row outlines.  Collapsed then expanded.";
-    }
-
-    public String test12() {
-        sheet1.groupRow(5, 14);
-        sheet1.groupRow(7, 14);
-        sheet1.setRowGroupCollapsed(7, true);
-        sheet1.setRowGroupCollapsed(5, true);
-        sheet1.setRowGroupCollapsed(6, false);
-        return "Row outlines.  Two row groups with matching end points.  Second group collapsed.";
-    }
-
-    public String test13() {
-        sheet1.groupRow(5, 14);
-        sheet1.groupRow(7, 14);
-        sheet1.groupRow(16, 19);
-
-        sheet1.groupColumn(4, 7);
-        sheet1.groupColumn(9, 12);
-        sheet1.groupColumn(10, 11);
-        return "Mixed bag.";
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/ReadWriteWorkbook.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/ReadWriteWorkbook.java
deleted file mode 100644 (file)
index 9b856f9..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-
-/**
- * This example demonstrates opening a workbook, modifying it and writing
- * the results back out.
- *
- * @author Glen Stampoultzis (glens at apache.org)
- */
-public class ReadWriteWorkbook {
-    public static void main(String[] args) throws IOException {
-        try (FileInputStream fileIn = new FileInputStream("workbook.xls")) {
-            POIFSFileSystem fs = new POIFSFileSystem(fileIn);
-            HSSFWorkbook wb = new HSSFWorkbook(fs);
-            HSSFSheet sheet = wb.getSheetAt(0);
-            HSSFRow row = sheet.getRow(2);
-            if (row == null)
-                row = sheet.createRow(2);
-            HSSFCell cell = row.getCell(3);
-            if (cell == null)
-                cell = row.createCell(3);
-            cell.setCellValue("a test");
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("workbookout.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/RepeatingRowsAndColumns.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/RepeatingRowsAndColumns.java
deleted file mode 100644 (file)
index 5d6b4d5..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFCellStyle;
-import org.apache.poi.hssf.usermodel.HSSFFont;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.util.CellRangeAddress;
-
-public class RepeatingRowsAndColumns {
-    public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet1 = wb.createSheet("first sheet");
-            HSSFSheet sheet2 = wb.createSheet("second sheet");
-            HSSFSheet sheet3 = wb.createSheet("third sheet");
-
-            HSSFFont boldFont = wb.createFont();
-            boldFont.setFontHeightInPoints((short) 22);
-            boldFont.setBold(true);
-
-            HSSFCellStyle boldStyle = wb.createCellStyle();
-            boldStyle.setFont(boldFont);
-
-            HSSFRow row = sheet1.createRow(1);
-            HSSFCell cell = row.createCell(0);
-            cell.setCellValue("This quick brown fox");
-            cell.setCellStyle(boldStyle);
-
-            // Set the columns to repeat from column 0 to 2 on the first sheet
-            sheet1.setRepeatingColumns(CellRangeAddress.valueOf("A:C"));
-            // Set the rows to repeat from row 0 to 2 on the second sheet.
-            sheet2.setRepeatingRows(CellRangeAddress.valueOf("1:3"));
-            // Set the the repeating rows and columns on the third sheet.
-            CellRangeAddress cra = CellRangeAddress.valueOf("D1:E2");
-            sheet3.setRepeatingColumns(cra);
-            sheet3.setRepeatingRows(cra);
-
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/SplitAndFreezePanes.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/SplitAndFreezePanes.java
deleted file mode 100644 (file)
index a768640..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-        
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.Sheet;
-
-public class SplitAndFreezePanes {
-    public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet1 = wb.createSheet("new sheet");
-            HSSFSheet sheet2 = wb.createSheet("second sheet");
-            HSSFSheet sheet3 = wb.createSheet("third sheet");
-            HSSFSheet sheet4 = wb.createSheet("fourth sheet");
-
-            // Freeze just one row
-            sheet1.createFreezePane(0, 1, 0, 1);
-            // Freeze just one column
-            sheet2.createFreezePane(1, 0, 1, 0);
-            // Freeze the columns and rows (forget about scrolling position of the lower right quadrant).
-            sheet3.createFreezePane(2, 2);
-            // Create a split with the lower left side being the active quadrant
-            sheet4.createSplitPane(2000, 2000, 0, 0, Sheet.PANE_LOWER_LEFT);
-
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/WorkingWithFonts.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/WorkingWithFonts.java
deleted file mode 100644 (file)
index f0e114a..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFCellStyle;
-import org.apache.poi.hssf.usermodel.HSSFFont;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-
-/**
- * Demonstrates how to create and use fonts.
- */
-public class WorkingWithFonts {
-    public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet = wb.createSheet("new sheet");
-
-            // Create a row and put some cells in it. Rows are 0 based.
-            HSSFRow row = sheet.createRow(1);
-
-            // Create a new font and alter it.
-            HSSFFont font = wb.createFont();
-            font.setFontHeightInPoints((short) 24);
-            font.setFontName("Courier New");
-            font.setItalic(true);
-            font.setStrikeout(true);
-
-            // Fonts are set into a style so create a new one to use.
-            HSSFCellStyle style = wb.createCellStyle();
-            style.setFont(font);
-
-            // Create a cell and put a value in it.
-            HSSFCell cell = row.createCell(1);
-            cell.setCellValue("This is a test of fonts");
-            cell.setCellStyle(style);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/ZoomSheet.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/ZoomSheet.java
deleted file mode 100644 (file)
index 600041f..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-        
-
-package org.apache.poi.hssf.usermodel.examples;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-
-import java.io.IOException;
-import java.io.FileOutputStream;
-
-/**
- * Sets the zoom magnication for a sheet.
- *
- * @author Glen Stampoultzis (glens at apache.org)
- */
-public class ZoomSheet
-{
-    public static void main(String[] args) throws IOException {
-        try (HSSFWorkbook wb = new HSSFWorkbook()) {
-            HSSFSheet sheet1 = wb.createSheet("new sheet");
-            sheet1.setZoom(75);   // 75 percent magnification
-
-            try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/hwpf/Word2Forrest.java b/src/examples/src/org/apache/poi/hwpf/Word2Forrest.java
deleted file mode 100644 (file)
index b26f3c1..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hwpf;
-
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.nio.charset.StandardCharsets;
-
-import org.apache.poi.hwpf.model.StyleDescription;
-import org.apache.poi.hwpf.model.StyleSheet;
-import org.apache.poi.hwpf.usermodel.CharacterRun;
-import org.apache.poi.hwpf.usermodel.Paragraph;
-import org.apache.poi.hwpf.usermodel.Range;
-
-@SuppressWarnings({"java:S106","java:S4823"})
-public final class Word2Forrest
-{
-  Writer _out;
-  HWPFDocument _doc;
-
-  @SuppressWarnings("unused")
-  public Word2Forrest(HWPFDocument doc, OutputStream stream) throws IOException
-  {
-      _out = new OutputStreamWriter (stream, StandardCharsets.UTF_8);
-    _doc = doc;
-
-    init ();
-    openDocument ();
-    openBody ();
-
-    Range r = doc.getRange ();
-    StyleSheet styleSheet = doc.getStyleSheet ();
-
-    int sectionLevel = 0;
-    int lenParagraph = r.numParagraphs ();
-    boolean inCode = false;
-    for (int x = 0; x < lenParagraph; x++)
-    {
-      Paragraph p = r.getParagraph (x);
-      String text = p.text ();
-      if (text.trim ().length () == 0)
-      {
-        continue;
-      }
-      StyleDescription paragraphStyle = styleSheet.getStyleDescription (p.
-        getStyleIndex ());
-      String styleName = paragraphStyle.getName();
-      if (styleName.startsWith ("Heading"))
-      {
-        if (inCode)
-        {
-          closeSource();
-          inCode = false;
-        }
-
-        int headerLevel = Integer.parseInt (styleName.substring (8));
-        if (headerLevel > sectionLevel)
-        {
-          openSection ();
-        }
-        else
-        {
-          for (int y = 0; y < (sectionLevel - headerLevel) + 1; y++)
-          {
-            closeSection ();
-          }
-          openSection ();
-        }
-        sectionLevel = headerLevel;
-        openTitle ();
-        writePlainText (text);
-        closeTitle ();
-      }
-      else
-      {
-        int cruns = p.numCharacterRuns ();
-        CharacterRun run = p.getCharacterRun (0);
-        String fontName = run.getFontName();
-        if (fontName.startsWith ("Courier"))
-        {
-          if (!inCode)
-          {
-            openSource ();
-            inCode = true;
-          }
-          writePlainText (p.text());
-        }
-        else
-        {
-          if (inCode)
-          {
-            inCode = false;
-            closeSource();
-          }
-          openParagraph();
-          writePlainText(p.text());
-          closeParagraph();
-        }
-      }
-    }
-    for (int x = 0; x < sectionLevel; x++)
-    {
-      closeSection();
-    }
-    closeBody();
-    closeDocument();
-    _out.flush();
-
-  }
-
-    public void init ()
-      throws IOException
-    {
-      _out.write ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
-      _out.write ("<!DOCTYPE document PUBLIC \"-//APACHE//DTD Documentation V1.1//EN\" \"./dtd/document-v11.dtd\">\r\n");
-    }
-
-    public void openDocument ()
-      throws IOException
-    {
-      _out.write ("<document>\r\n");
-    }
-    public void closeDocument ()
-      throws IOException
-    {
-      _out.write ("</document>\r\n");
-    }
-
-
-    public void openBody ()
-      throws IOException
-    {
-      _out.write ("<body>\r\n");
-    }
-
-    public void closeBody ()
-      throws IOException
-    {
-      _out.write ("</body>\r\n");
-    }
-
-
-    public void openSection ()
-      throws IOException
-    {
-      _out.write ("<section>");
-
-    }
-
-    public void closeSection ()
-      throws IOException
-    {
-      _out.write ("</section>");
-
-    }
-
-    public void openTitle ()
-      throws IOException
-    {
-      _out.write ("<title>");
-    }
-
-    public void closeTitle ()
-      throws IOException
-    {
-      _out.write ("</title>");
-    }
-
-    public void writePlainText (String text)
-      throws IOException
-    {
-      _out.write (text);
-    }
-
-    public void openParagraph ()
-      throws IOException
-    {
-      _out.write ("<p>");
-    }
-
-    public void closeParagraph ()
-      throws IOException
-    {
-      _out.write ("</p>");
-    }
-
-    public void openSource ()
-      throws IOException
-    {
-      _out.write ("<source><![CDATA[");
-    }
-    public void closeSource ()
-      throws IOException
-    {
-      _out.write ("]]></source>");
-    }
-
-
-    public static void main(String[] args) throws IOException {
-      try (InputStream is = new FileInputStream(args[0]);
-           OutputStream out = new FileOutputStream("test.xml")) {
-        new Word2Forrest(new HWPFDocument(is), out);
-      }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/AddDimensionedImage.java b/src/examples/src/org/apache/poi/ss/examples/AddDimensionedImage.java
deleted file mode 100644 (file)
index 05a8a78..0000000
+++ /dev/null
@@ -1,1011 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-
-package org.apache.poi.ss.examples;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Locale;
-
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.ClientAnchor;
-import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;
-import org.apache.poi.ss.usermodel.Drawing;
-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.util.CellReference;
-import org.apache.poi.util.IOUtils;
-
-
-/**
- * Demonstrates how to add an image to a worksheet and set that images size
- * to a specific number of millimetres irrespective of the width of the columns
- * or height of the rows. Overridden methods are provided so that the location
- * of the image - the cells row and column coordinates that define the top
- * left hand corners of the image - can be identified either in the familiar
- * Excel manner - A1 for instance - or using POI's methodology of a column and
- * row index where 0, 0 would indicate cell A1.
- *
- * The best way to make use of these techniques is to delay adding the image to
- * the sheet until all other work has been completed. That way, the sizes of
- * all rows and columns will have been adjusted - assuming that step was
- * necessary. Even though the anchors type is set to prevent the image moving
- * or re-sizing, this setting does not have any effect until the sheet is being
- * viewed using the Excel application.
- *
- * The key to the process is the ClientAnchor class. It defines methods that allow
- * us to define the location of an image by specifying the following;
- *
- *      * How far - in terms of coordinate positions - the image should be inset
- *      from the left hand border of a cell.
- *      * How far - in terms of coordinate positions - the image should be inset
- *      from the from the top of the cell.
- *      * How far - in terms of coordinate positions - the right hand edge of
- *      the image should protrude into a cell (measured from the cells left hand
- *      edge to the images right hand edge).
- *      * How far - in terms of coordinate positions - the bottom edge of the
- *      image should protrude into a row (measured from the cells top edge to
- *      the images bottom edge).
- *      * The index of the column that contains the cell whose top left hand
- *      corner should be aligned with the top left hand corner of the image.
- *      * The index of the row that contains the cell whose top left hand corner
- *      should be aligned with the images top left hand corner.
- *      * The index of the column that contains the cell whose top left hand
- *      corner should be aligned with the images bottom right hand corner
- *      * The index number of the row that contains the cell whose top left
- *      hand corner should be aligned with the images bottom right hand corner.
- *
- * It can be used to add an image into cell A1, for example, in the following
- * manner;
- *
- *      ClientAnchor anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
- *
- *      anchor.setDx1(0);
- *      anchor.setDy1(0);
- *      anchor.setDx2(0);
- *      anchor.setDy2(0);
- *      anchor.setCol1(0);
- *      anchor.setRow1(0);
- *      anchor.setCol2(1);
- *      anchor.setRow2(1);
- *
- * Taken together, the first four methods define the locations of the top left
- * and bottom right hand corners of the image if you imagine that the image is
- * represented by a simple rectangle. The setDx1() and setDy1() methods locate
- * the top left hand corner of the image while setDx2() and and Dy2() locate the
- * bottom right hand corner of the image. An individual image can be inserted
- * into a single cell or is can lie across many cells and the latter four methods
- * are used to define just where the image should be positioned. They do this by
- * again by identifying where the top left and bottom right hand corners of the
- * image should be located but this time in terms of the indexes of the cells
- * in which those corners should be located. The setCol1() and setRow1() methods
- * together identify the cell that should contain the top left hand corner of
- * the image while setCol2() and setRow2() do the same for the images bottom
- * right hand corner.
- *
- * Knowing that, it is possible to look again at the example above and to see
- * that the top left hand corner of the image will be located in cell A1 (0, 0)
- * and it will be aligned with the very top left hand corner of the cell. Likewise,
- * the bottom right hand corner of the image will be located in cell B2 (1, 1) and
- * it will again be aligned with the top left hand corner of the cell. This has the
- * effect of making the image seem to occupy the whole of cell A1. Interestingly, it
- * also has an effect on the images resizing behaviour because testing has
- * demonstrated that if the image is wholly contained within one cell and is not
- * 'attached' for want of a better word, to a neighbouring cell, then that image
- * will not increase in size in response to the user dragging the column wider
- * or the cell higher.
- *
- * The following example demonstrates a slightly different way to insert an
- * image into cell A1 and to ensure that it occupies the whole of the cell. This
- * is accomplished by specifying the the images bottom right hand corner should be
- * aligned with the bottom right hand corner of the cell. It is also a case
- * where the image will not increase in size if the user increases the size of
- * the enclosing cell - irrespective of the anchors type - but it will reduce in
- * size if the cell is made smaller.
- *
- *      ClientAnchor anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
- *
- *      anchor.setDx1(0);
- *      anchor.setDy1(0);
- *      anchor.setDx2(1023);
- *      anchor.setDy2(255);
- *      anchor.setCol1(0);
- *      anchor.setRow1(0);
- *      anchor.setCol2(0);
- *      anchor.setRow2(0);
- *
- * Note that the final four method calls all pass the same value and seem to
- * indicate that the images top left hand corner is aligned with the top left
- * hand corner of cell A1 and that it's bottom right hand corner is also
- * aligned with the top left hand corner of cell A1. Yet, running this code
- * would see the image fully occupying cell A1. That is the result of the
- * values passed to parameters three and four; these I have referred to as
- * determining the images coordinates within the cell. They indicate that the
- * image should occupy - in order - the full width of the column and the full
- * height of the row.
- *
- * The co-ordinate values shown are the maxima; and they are independent of
- * row height/column width and of the font used. Passing 255 will always result
- * in the image occupying the full height of the row and passing 1023 will
- * always result in the image occupying the full width of the column. They help
- * in situations where an image is larger than a column/row and must overlap
- * into the next column/row. Using them does mean, however, that it is often
- * necessary to perform conversions between Excels characters units, points,
- * pixels and millimetres in order to establish how many rows/columns an image
- * should occupy and just what the various insets ought to be.
- *
- * Note that the setDx1(int) and setDy1(int) methods of the ClientAchor class
- * are not made use of in the code that follows. It would be fairly trivial
- * however to extend this example further and provide methods that would centre
- * an image within a cell or allow the user to specify that a plain border a
- * fixed number of millimetres wide should wrap around the image. Those first
- * two parameters would make this sort of functionality perfectly possible.
- *
- * Owing to the various conversions used, the actual size of the image may vary
- * from that required; testing has so far found this to be in the region of
- * plus or minus two millimetres. Most likely by modifying the way the
- * calculations are performed - possibly using double(s) throughout and
- * rounding the values at the correct point - it is likely that these errors
- * could be reduced or removed.
- *
- * A note concerning Excels image resizing behaviour. The ClientAnchor
- * class contains a method called setAnchorType(int) which can be used to
- * determine how Excel will resize an image in response to the user increasing
- * or decreasing the dimensions of the cell containing the image. There are
- * three values that can be passed to this method; 0 = To move and size the
- * image with the cell, 2 = To move but don't size the image with the cell,
- * 3 = To prevent the image from moving or being resized along with the cell. If
- * an image is inserted using this class and placed into a single cell then if
- * the setAnchorType(int) method is called and a value of either 0 or 2 passed
- * to it, the resultant resizing behaviour may be a surprise. The image will not
- * grow in size of the column is made wider or the row higher but it will shrink
- * if the columns width or rows height are reduced.
- *
- * @author Mark Beardsley [msb at apache.org] and Mark Southern [southern at scripps.edu]
- * @version 1.00 5th August 2009.
- *          2.00 26th February 2010.
- *               Ported to make use of the the SS usermodel classes.
- *               Ability to reuse the Drawing Patriarch so that multiple images
- *               can be inserted without unintentionally erasing earlier images.
- *               Check on image type added; i.e. jpg, jpeg or png.
- *               The String used to contain the files name is now converted
- *               into a URL.
- *          2.10 17th May 2012
- *               Corrected gross error that occurred when using the code with
- *               XSSF or SXSSF workbooks. In short, the code did not correctly
- *               calculate the size of the image(s) owing to the use of EMUs
- *               within the OOXML file format. That problem has largely been
- *               corrected although it should be mentioned that images are not
- *               sized with the same level of accuracy. Discrepancies of up to
- *               2mm have been noted in testing. Further investigation will
- *               continue to rectify this issue.
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public class AddDimensionedImage {
-
-    // Four constants that determine how - and indeed whether - the rows
-    // and columns an image may overlie should be expanded to accommodate that
-    // image.
-    // Passing EXPAND_ROW will result in the height of a row being increased
-    // to accommodate the image if it is not already larger. The image will
-    // be layed across one or more columns.
-    // Passing EXPAND_COLUMN will result in the width of the column being
-    // increased to accommodate the image if it is not already larger. The image
-    // will be layed across one or many rows.
-    // Passing EXPAND_ROW_AND_COLUMN will result in the height of the row
-    // bing increased along with the width of the column to accomdate the
-    // image if either is not already larger.
-    // Passing OVERLAY_ROW_AND_COLUMN will result in the image being layed
-    // over one or more rows and columns. No row or column will be resized,
-    // instead, code will determine how many rows and columns the image should
-    // overlie.
-    public static final int EXPAND_ROW = 1;
-    public static final int EXPAND_COLUMN = 2;
-    public static final int EXPAND_ROW_AND_COLUMN = 3;
-    public static final int OVERLAY_ROW_AND_COLUMN = 7;
-
-    // Modified to support EMU - English Metric Units - used within the OOXML
-    // workbooks, this multoplier is used to convert between measurements in
-    // millimetres and in EMUs
-    private static final int EMU_PER_MM = 36000;
-
-    /**
-     * Add an image to a worksheet.
-     *
-     * @param cellNumber A String that contains the location of the cell whose
-     *                   top left hand corner should be aligned with the top
-     *                   left hand corner of the image; for example "A1", "A2"
-     *                   etc. This is to support the familiar Excel syntax.
-     *                   Whilst images are are not actually inserted into cells
-     *                   this provides a convenient method of indicating where
-     *                   the image should be positioned on the sheet.
-     * @param sheet A reference to the sheet that contains the cell referenced
-     *              above.
-     * @param drawing An instance of the DrawingPatriarch class. This is now
-     *                passed into the method where it was, previously, recovered
-     *                from the sheet in order to allow multiple pictures be
-     *                inserted. If the patriarch was not 'cached in this manner
-     *                each time it was created any previously positioned images
-     *                would be simply over-written.
-     * @param imageFile An instance of the URL class that encapsulates the name
-     *                  of and path to the image that is to be 'inserted into'
-     *                  the sheet.
-     * @param reqImageWidthMM A primitive double that contains the required
-     *                        width of the image in millimetres.
-     * @param reqImageHeightMM A primitive double that contains the required
-     *                         height of the image in millimetres.
-     * @param resizeBehaviour A primitive int whose value will determine how
-     *                        the code should react if the image is larger than
-     *                        the cell referenced by the cellNumber parameter.
-     *                        Four constants are provided to determine what
-     *                        should happen;
-     *                          AddDimensionedImage.EXPAND_ROW
-     *                          AddDimensionedImage.EXPAND_COLUMN
-     *                          AddDimensionedImage.EXPAND_ROW_AND_COLUMN
-     *                          AddDimensionedImage.OVERLAY_ROW_AND_COLUMN
-     * @throws java.io.FileNotFoundException If the file containing the image
-     *                                       cannot be located.
-     * @throws java.io.IOException If a problem occurs whilst reading the file
-     *                             of image data.
-     * @throws java.lang.IllegalArgumentException If an invalid value is passed
-     *                                            to the resizeBehaviour
-     *                                            parameter.
-     */
-    public void addImageToSheet(String cellNumber, Sheet sheet, Drawing<?> drawing,
-            URL imageFile, double reqImageWidthMM, double reqImageHeightMM,
-            int resizeBehaviour) throws IOException, IllegalArgumentException {
-        // Convert the String into column and row indices then chain the
-        // call to the overridden addImageToSheet() method.
-        CellReference cellRef = new CellReference(cellNumber);
-        this.addImageToSheet(cellRef.getCol(), cellRef.getRow(), sheet, drawing,
-                imageFile, reqImageWidthMM, reqImageHeightMM,resizeBehaviour);
-    }
-
-    /**
-     * Add an image to a worksheet.
-     *
-     * @param colNumber A primitive int that contains the index number of a
-     *                  column on the worksheet; POI column indices are zero
-     *                  based. Together with the rowNumber parameter's value,
-     *                  this parameter identifies a cell on the worksheet. The
-     *                  images top left hand corner will be aligned with the
-     *                  top left hand corner of this cell.
-     * @param rowNumber A primitive int that contains the index number of a row
-     *                  on the worksheet; POI row indices are zero based.
-     *                  Together with the rowNumber parameter's value, this
-     *                  parameter identifies a cell on the worksheet. The
-     *                  images top left hand corner will be aligned with the
-     *                  top left hand corner of this cell.
-     * @param sheet A reference to the sheet that contains the cell identified
-     *              by the two parameters above.
-     * @param drawing An instance of the DrawingPatriarch class. This is now
-     *                passed into the method where it was, previously, recovered
-     *                from the sheet in order to allow multiple pictures be
-     *                inserted. If the patriarch was not 'cached in this manner
-     *                each time it was created any previously positioned images
-     *                would be simply over-written.
-     * @param imageFile An instance of the URL class that encapsulates the name
-     *                  of and path to the image that is to be 'inserted into'
-     *                  the sheet.
-     * @param reqImageWidthMM A primitive double that contains the required
-     *                        width of the image in millimetres.
-     * @param reqImageHeightMM A primitive double that contains the required
-     *                         height of the image in millimetres.
-     * @param resizeBehaviour A primitive int whose value will determine how
-     *                        the code should react if the image is larger than
-     *                        the cell referenced by the colNumber and
-     *                        rowNumber parameters. Four constants are provided
-     *                        to determine what should happen;
-     *                          AddDimensionedImage.EXPAND_ROW
-     *                          AddDimensionedImage.EXPAND_COLUMN
-     *                          AddDimensionedImage.EXPAND_ROW_AND_COLUMN
-     *                          AddDimensionedImage.OVERLAY_ROW_AND_COLUMN
-     * @throws java.io.FileNotFoundException If the file containing the image
-     *                                       cannot be located.
-     * @throws java.io.IOException If a problem occurs whilst reading the file
-     *                             of image data.
-     * @throws java.lang.IllegalArgumentException If an invalid value is passed
-     *                                            to the resizeBehaviour
-     *                                            parameter or if the extension
-     *                                            of the image file indicates that
-     *                                            it is of a type that cannot
-     *                                            currently be added to the worksheet.
-     */
-    public void addImageToSheet(int colNumber, int rowNumber, Sheet sheet, Drawing<?> drawing,
-            URL imageFile, double reqImageWidthMM, double reqImageHeightMM,
-            int resizeBehaviour) throws IOException,
-                                                     IllegalArgumentException {
-        ClientAnchor anchor;
-        ClientAnchorDetail rowClientAnchorDetail;
-        ClientAnchorDetail colClientAnchorDetail;
-        int imageType;
-
-        // Validate the resizeBehaviour parameter.
-        if((resizeBehaviour != AddDimensionedImage.EXPAND_COLUMN) &&
-           (resizeBehaviour != AddDimensionedImage.EXPAND_ROW) &&
-           (resizeBehaviour != AddDimensionedImage.EXPAND_ROW_AND_COLUMN) &&
-           (resizeBehaviour != AddDimensionedImage.OVERLAY_ROW_AND_COLUMN)) {
-            throw new IllegalArgumentException("Invalid value passed to the " +
-                    "resizeBehaviour parameter of AddDimensionedImage.addImageToSheet()");
-        }
-
-        // Call methods to calculate how the image and sheet should be
-        // manipulated to accommodate the image; columns and then rows.
-        colClientAnchorDetail = this.fitImageToColumns(sheet, colNumber,
-                reqImageWidthMM, resizeBehaviour);
-        rowClientAnchorDetail = this.fitImageToRows(sheet, rowNumber,
-                reqImageHeightMM, resizeBehaviour);
-
-        // Having determined if and how to resize the rows, columns and/or the
-        // image, create the ClientAnchor object to position the image on
-        // the worksheet. Note how the two ClientAnchorDetail records are
-        // interrogated to recover the row/column co-ordinates and any insets.
-        // The first two parameters are not used currently but could be if the
-        // need arose to extend the functionality of this code by adding the
-        // ability to specify that a clear 'border' be placed around the image.
-        anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
-
-        anchor.setDx1(0);
-        anchor.setDy1(0);
-        if (colClientAnchorDetail != null) {
-            anchor.setDx2(colClientAnchorDetail.getInset());
-            anchor.setCol1(colClientAnchorDetail.getFromIndex());
-            anchor.setCol2(colClientAnchorDetail.getToIndex());
-        }
-        if (rowClientAnchorDetail != null) {
-            anchor.setDy2(rowClientAnchorDetail.getInset());
-            anchor.setRow1(rowClientAnchorDetail.getFromIndex());
-            anchor.setRow2(rowClientAnchorDetail.getToIndex());
-        }
-
-        // For now, set the anchor type to do not move or resize the
-        // image as the size of the row/column is adjusted. This could easily
-        // become another parameter passed to the method. Please read the note
-        // above regarding the behaviour of image resizing.
-        anchor.setAnchorType(AnchorType.MOVE_AND_RESIZE);
-
-        // Now, add the picture to the workbook. Note that unlike the similar
-        // method in the HSSF Examples section, the image type is checked. First,
-        // the image files location is identified by interrogating the URL passed
-        // to the method, the images type is identified before it is added to the
-        // sheet.
-        String sURL = imageFile.toString().toLowerCase(Locale.ROOT);
-       if( sURL.endsWith(".png") ) {
-            imageType = Workbook.PICTURE_TYPE_PNG;
-       }
-       else if( sURL.endsWith(".jpg") || sURL.endsWith(".jpeg") ) {
-            imageType = Workbook.PICTURE_TYPE_JPEG;
-       }
-       else  {
-            throw new IllegalArgumentException("Invalid Image file : " +
-                sURL);
-       }
-        int index = sheet.getWorkbook().addPicture(
-            IOUtils.toByteArray(imageFile.openStream()), imageType);
-        drawing.createPicture(anchor, index);
-    }
-
-    /**
-     * Determines whether the sheets columns should be re-sized to accommodate
-     * the image, adjusts the columns width if necessary and creates then
-     * returns a ClientAnchorDetail object that facilitates construction of
-     * an ClientAnchor that will fix the image on the sheet and establish
-     * it's size.
-     *
-     * @param sheet A reference to the sheet that will 'contain' the image.
-     * @param colNumber A primitive int that contains the index number of a
-     *                  column on the sheet.
-     * @param reqImageWidthMM A primitive double that contains the required
-     *                        width of the image in millimetres
-     * @param resizeBehaviour A primitive int whose value will indicate how the
-     *                        width of the column should be adjusted if the
-     *                        required width of the image is greater than the
-     *                        width of the column.
-     * @return An instance of the ClientAnchorDetail class that will contain
-     *         the index number of the column containing the cell whose top
-     *         left hand corner also defines the top left hand corner of the
-     *         image, the index number column containing the cell whose top
-     *         left hand corner also defines the bottom right hand corner of
-     *         the image and an inset that determines how far the right hand
-     *         edge of the image can protrude into the next column - expressed
-     *         as a specific number of coordinate positions.
-     */
-    private ClientAnchorDetail fitImageToColumns(Sheet sheet, int colNumber,
-            double reqImageWidthMM, int resizeBehaviour) {
-
-        double colWidthMM;
-        double colCoordinatesPerMM;
-        int pictureWidthCoordinates;
-        ClientAnchorDetail colClientAnchorDetail = null;
-
-        // Get the colum's width in millimetres
-        colWidthMM = ConvertImageUnits.widthUnits2Millimetres(
-                (short)sheet.getColumnWidth(colNumber));
-
-        // Check that the column's width will accommodate the image at the
-        // required dimension. If the width of the column is LESS than the
-        // required width of the image, decide how the application should
-        // respond - resize the column or overlay the image across one or more
-        // columns.
-        if(colWidthMM < reqImageWidthMM) {
-
-            // Should the column's width simply be expanded?
-            if((resizeBehaviour == AddDimensionedImage.EXPAND_COLUMN) ||
-               (resizeBehaviour == AddDimensionedImage.EXPAND_ROW_AND_COLUMN)) {
-                // Set the width of the column by converting the required image
-                // width from millimetres into Excel's column width units.
-                sheet.setColumnWidth(colNumber,
-                        ConvertImageUnits.millimetres2WidthUnits(reqImageWidthMM));
-                // To make the image occupy the full width of the column, convert
-                // the required width of the image into co-ordinates. This value
-                // will become the inset for the ClientAnchorDetail class that
-                // is then instantiated.
-                if(sheet instanceof HSSFSheet) {
-                    colWidthMM = reqImageWidthMM;
-                    colCoordinatesPerMM = colWidthMM == 0 ? 0
-                        : ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS / colWidthMM;
-                    pictureWidthCoordinates = (int)(reqImageWidthMM * colCoordinatesPerMM);
-
-                }
-                else {
-                    pictureWidthCoordinates = (int)reqImageWidthMM * AddDimensionedImage.EMU_PER_MM;
-                }
-                colClientAnchorDetail = new ClientAnchorDetail(colNumber,
-                        colNumber, pictureWidthCoordinates);
-            }
-            // If the user has chosen to overlay both rows and columns or just
-            // to expand ONLY the size of the rows, then calculate how to lay
-            // the image out across one or more columns.
-            else if ((resizeBehaviour == AddDimensionedImage.OVERLAY_ROW_AND_COLUMN) ||
-                     (resizeBehaviour == AddDimensionedImage.EXPAND_ROW)) {
-                colClientAnchorDetail = this.calculateColumnLocation(sheet,
-                        colNumber, reqImageWidthMM);
-            }
-        }
-        // If the column is wider than the image.
-        else {
-            if(sheet instanceof HSSFSheet) {
-                // Mow many co-ordinate positions are there per millimetre?
-                colCoordinatesPerMM = ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS /
-                    colWidthMM;
-                // Given the width of the image, what should be it's co-ordinate?
-                pictureWidthCoordinates = (int)(reqImageWidthMM * colCoordinatesPerMM);
-            }
-            else {
-                pictureWidthCoordinates = (int)reqImageWidthMM *
-                        AddDimensionedImage.EMU_PER_MM;
-            }
-            colClientAnchorDetail = new ClientAnchorDetail(colNumber,
-                    colNumber, pictureWidthCoordinates);
-        }
-        return(colClientAnchorDetail);
-    }
-
-    /**
-     * Determines whether the sheets row should be re-sized to accommodate
-     * the image, adjusts the rows height if necessary and creates then
-     * returns a ClientAnchorDetail object that facilitates construction of
-     * a ClientAnchor that will fix the image on the sheet and establish
-     * it's size.
-     *
-     * @param sheet A reference to the sheet that will 'contain' the image.
-     * @param rowNumber A primitive int that contains the index number of a
-     *                  row on the sheet.
-     * @param reqImageHeightMM A primitive double that contains the required
-     *                         height of the image in millimetres
-     * @param resizeBehaviour A primitive int whose value will indicate how the
-     *                        height of the row should be adjusted if the
-     *                        required height of the image is greater than the
-     *                        height of the row.
-     * @return An instance of the ClientAnchorDetail class that will contain
-     *         the index number of the row containing the cell whose top
-     *         left hand corner also defines the top left hand corner of the
-     *         image, the index number of the row containing the cell whose
-     *         top left hand corner also defines the bottom right hand
-     *         corner of the image and an inset that determines how far the
-     *         bottom edge of the image can protrude into the next (lower)
-     *         row - expressed as a specific number of coordinate positions.
-     */
-    private ClientAnchorDetail fitImageToRows(Sheet sheet, int rowNumber,
-            double reqImageHeightMM, int resizeBehaviour) {
-        Row row;
-        double rowHeightMM;
-        double rowCoordinatesPerMM;
-        int pictureHeightCoordinates;
-        ClientAnchorDetail rowClientAnchorDetail = null;
-
-        // Get the row and it's height
-        row = sheet.getRow(rowNumber);
-        if(row == null) {
-            // Create row if it does not exist.
-            row = sheet.createRow(rowNumber);
-        }
-
-        // Get the row's height in millimetres
-        rowHeightMM = row.getHeightInPoints() / ConvertImageUnits.POINTS_PER_MILLIMETRE;
-
-        // Check that the row's height will accommodate the image at the required
-        // dimensions. If the height of the row is LESS than the required height
-        // of the image, decide how the application should respond - resize the
-        // row or overlay the image across a series of rows.
-        if(rowHeightMM < reqImageHeightMM) {
-            if((resizeBehaviour == AddDimensionedImage.EXPAND_ROW) ||
-               (resizeBehaviour == AddDimensionedImage.EXPAND_ROW_AND_COLUMN)) {
-                row.setHeightInPoints((float)(reqImageHeightMM *
-                        ConvertImageUnits.POINTS_PER_MILLIMETRE));
-                if(sheet instanceof HSSFSheet) {
-                    rowHeightMM = reqImageHeightMM;
-                    rowCoordinatesPerMM = rowHeightMM == 0 ? 0
-                        : ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS / rowHeightMM;
-                    pictureHeightCoordinates = (int)(reqImageHeightMM *
-                            rowCoordinatesPerMM);
-                }
-                else {
-                    pictureHeightCoordinates = (int)(reqImageHeightMM *
-                            AddDimensionedImage.EMU_PER_MM);
-                }
-                rowClientAnchorDetail = new ClientAnchorDetail(rowNumber,
-                        rowNumber, pictureHeightCoordinates);
-            }
-            // If the user has chosen to overlay both rows and columns or just
-            // to expand ONLY the size of the columns, then calculate how to lay
-            // the image out ver one or more rows.
-            else if((resizeBehaviour == AddDimensionedImage.OVERLAY_ROW_AND_COLUMN) ||
-                    (resizeBehaviour == AddDimensionedImage.EXPAND_COLUMN)) {
-                rowClientAnchorDetail = this.calculateRowLocation(sheet,
-                        rowNumber, reqImageHeightMM);
-            }
-        }
-        // Else, if the image is smaller than the space available
-        else {
-            if(sheet instanceof HSSFSheet) {
-                rowCoordinatesPerMM = ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS /
-                    rowHeightMM;
-                pictureHeightCoordinates = (int)(reqImageHeightMM * rowCoordinatesPerMM);
-            }
-            else {
-                pictureHeightCoordinates = (int)(reqImageHeightMM *
-                        AddDimensionedImage.EMU_PER_MM);
-            }
-            rowClientAnchorDetail = new ClientAnchorDetail(rowNumber,
-                        rowNumber, pictureHeightCoordinates);
-        }
-        return(rowClientAnchorDetail);
-    }
-
-    /**
-     * If the image is to overlie more than one column, calculations need to be
-     * performed to determine how many columns and whether the image will
-     * overlie just a part of one column in order to be presented at the
-     * required size.
-     *
-     * @param sheet The sheet that will 'contain' the image.
-     * @param startingColumn A primitive int whose value is the index of the
-     *                       column that contains the cell whose top left hand
-     *                       corner should be aligned with the top left hand
-     *                       corner of the image.
-     * @param reqImageWidthMM A primitive double whose value will indicate the
-     *                        required width of the image in millimetres.
-     * @return An instance of the ClientAnchorDetail class that will contain
-     *         the index number of the column containing the cell whose top
-     *         left hand corner also defines the top left hand corner of the
-     *         image, the index number column containing the cell whose top
-     *         left hand corner also defines the bottom right hand corner of
-     *         the image and an inset that determines how far the right hand
-     *         edge of the image can protrude into the next column - expressed
-     *         as a specific number of coordinate positions.
-     */
-    private ClientAnchorDetail calculateColumnLocation(Sheet sheet,
-                                                       int startingColumn,
-                                                       double reqImageWidthMM) {
-        ClientAnchorDetail anchorDetail;
-        double totalWidthMM = 0.0D;
-        double colWidthMM = 0.0D;
-        double overlapMM;
-        double coordinatePositionsPerMM;
-        int toColumn = startingColumn;
-        int inset;
-
-        // Calculate how many columns the image will have to
-        // span in order to be presented at the required size.
-        while(totalWidthMM < reqImageWidthMM) {
-            colWidthMM = ConvertImageUnits.widthUnits2Millimetres(
-                    (short)(sheet.getColumnWidth(toColumn)));
-            // Note use of the cell border width constant. Testing with an image
-            // declared to fit exactly into one column demonstrated that it's
-            // width was greater than the width of the column the POI returned.
-            // Further, this difference was a constant value that I am assuming
-            // related to the cell's borders. Either way, that difference needs
-            // to be allowed for in this calculation.
-            totalWidthMM += (colWidthMM + ConvertImageUnits.CELL_BORDER_WIDTH_MILLIMETRES);
-            toColumn++;
-        }
-        // De-crement by one the last column value.
-        toColumn--;
-        // Highly unlikely that this will be true but, if the width of a series
-        // of columns is exactly equal to the required width of the image, then
-        // simply build a ClientAnchorDetail object with an inset equal to the
-        // total number of co-ordinate positions available in a column, a
-        // from column co-ordinate (top left hand corner) equal to the value
-        // of the startingColumn parameter and a to column co-ordinate equal
-        // to the toColumn variable.
-        //
-        // Convert both values to ints to perform the test.
-        if((int)totalWidthMM == (int)reqImageWidthMM) {
-            // A problem could occur if the image is sized to fit into one or
-            // more columns. If that occurs, the value in the toColumn variable
-            // will be in error. To overcome this, there are two options, to
-            // ibcrement the toColumn variable's value by one or to pass the
-            // total number of co-ordinate positions to the third paramater
-            // of the ClientAnchorDetail constructor. For no sepcific reason,
-            // the latter option is used below.
-            if(sheet instanceof HSSFSheet) {
-                anchorDetail = new ClientAnchorDetail(startingColumn,
-                    toColumn, ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS);
-            }
-            else {
-                anchorDetail = new ClientAnchorDetail(startingColumn,
-                    toColumn, (int)reqImageWidthMM * AddDimensionedImage.EMU_PER_MM);
-            }
-        }
-        // In this case, the image will overlap part of another column and it is
-        // necessary to calculate just how much - this will become the inset
-        // for the ClientAnchorDetail object.
-        else {
-            // Firstly, claculate how much of the image should overlap into
-            // the next column.
-            overlapMM = reqImageWidthMM - (totalWidthMM - colWidthMM);
-
-            // When the required size is very close indded to the column size,
-            // the calcaulation above can produce a negative value. To prevent
-            // problems occuring in later caculations, this is simply removed
-            // be setting the overlapMM value to zero.
-            if(overlapMM < 0) {
-                overlapMM = 0.0D;
-            }
-
-            if(sheet instanceof HSSFSheet) {
-                // Next, from the columns width, calculate how many co-ordinate
-                // positons there are per millimetre
-                coordinatePositionsPerMM = (colWidthMM == 0) ? 0
-                    : ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS / colWidthMM;
-                // From this figure, determine how many co-ordinat positions to
-                // inset the left hand or bottom edge of the image.
-                inset = (int)(coordinatePositionsPerMM * overlapMM);
-            }
-            else {
-                inset = (int)overlapMM * AddDimensionedImage.EMU_PER_MM;
-            }
-
-            // Now create the ClientAnchorDetail object, setting the from and to
-            // columns and the inset.
-            anchorDetail = new ClientAnchorDetail(startingColumn, toColumn, inset);
-        }
-        return(anchorDetail);
-    }
-
-    /**
-     * If the image is to overlie more than one rows, calculations need to be
-     * performed to determine how many rows and whether the image will
-     * overlie just a part of one row in order to be presented at the
-     * required size.
-     *
-     * @param sheet The sheet that will 'contain' the image.
-     * @param startingRow A primitive int whose value is the index of the row
-     *                    that contains the cell whose top left hand corner
-     *                    should be aligned with the top left hand corner of
-     *                    the image.
-     * @param reqImageHeightMM A primitive double whose value will indicate the
-     *                         required height of the image in millimetres.
-     * @return An instance of the ClientAnchorDetail class that will contain
-     *         the index number of the row containing the cell whose top
-     *         left hand corner also defines the top left hand corner of the
-     *         image, the index number of the row containing the cell whose top
-     *         left hand corner also defines the bottom right hand corner of
-     *         the image and an inset that determines how far the bottom edge
-     *         can protrude into the next (lower) row - expressed as a specific
-     *         number of co-ordinate positions.
-     */
-    private ClientAnchorDetail calculateRowLocation(Sheet sheet,
-            int startingRow, double reqImageHeightMM) {
-        ClientAnchorDetail clientAnchorDetail;
-        Row row;
-        double rowHeightMM = 0.0D;
-        double totalRowHeightMM = 0.0D;
-        double overlapMM;
-        double rowCoordinatesPerMM;
-        int toRow = startingRow;
-        int inset;
-
-        // Step through the rows in the sheet and accumulate a total of their
-        // heights.
-        while(totalRowHeightMM < reqImageHeightMM) {
-            row = sheet.getRow(toRow);
-            // Note, if the row does not already exist on the sheet then create
-            // it here.
-            if(row == null) {
-                row = sheet.createRow(toRow);
-            }
-            // Get the row's height in millimetres and add to the running total.
-            rowHeightMM = row.getHeightInPoints() /
-                    ConvertImageUnits.POINTS_PER_MILLIMETRE;
-            totalRowHeightMM += rowHeightMM;
-            toRow++;
-        }
-        // Owing to the way the loop above works, the rowNumber will have been
-        // incremented one row too far. Undo that here.
-        toRow--;
-        // Check to see whether the image should occupy an exact number of
-        // rows. If so, build the ClientAnchorDetail record to point
-        // to those rows and with an inset of the total number of co-ordinate
-        // position in the row.
-        //
-        // To overcome problems that can occur with comparing double values for
-        // equality, cast both to int(s) to truncate the value; VERY crude and
-        // I do not really like it!!
-        if((int)totalRowHeightMM == (int)reqImageHeightMM) {
-            if(sheet instanceof HSSFSheet) {
-                clientAnchorDetail = new ClientAnchorDetail(startingRow, toRow,
-                    ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS);
-            }
-            else {
-                clientAnchorDetail = new ClientAnchorDetail(startingRow, toRow,
-                    (int)reqImageHeightMM * AddDimensionedImage.EMU_PER_MM);
-            }
-        }
-        else {
-            // Calculate how far the image will project into the next row. Note
-            // that the height of the last row assessed is subtracted from the
-            // total height of all rows assessed so far.
-            overlapMM = reqImageHeightMM - (totalRowHeightMM - rowHeightMM);
-
-            // To prevent an exception being thrown when the required width of
-            // the image is very close indeed to the column size.
-            if(overlapMM < 0) {
-                overlapMM = 0.0D;
-            }
-
-            if(sheet instanceof HSSFSheet) {
-                rowCoordinatesPerMM = (rowHeightMM == 0) ? 0
-                    : ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS / rowHeightMM;
-                inset = (int)(overlapMM * rowCoordinatesPerMM);
-            }
-            else {
-                inset = (int)overlapMM * AddDimensionedImage.EMU_PER_MM;
-            }
-            clientAnchorDetail = new ClientAnchorDetail(startingRow,
-                        toRow, inset);
-        }
-        return(clientAnchorDetail);
-    }
-
-    /**
-     * The main entry point to the program. It contains code that demonstrates
-     * one way to use the program.
-     *
-     * Note, the code is not restricted to use on new workbooks only. If an
-     * image is to be inserted into an existing workbook. just open that
-     * workbook, gat a reference to a sheet and pass that;
-     *
-     *      AddDimensionedImage addImage = new AddDimensionedImage();
-     *
-     *      File file = new File("....... Existing Workbook .......");
-     *      FileInputStream fis = new FileInputStream(file);
-     *      Workbook workbook = new HSSFWorkbook(fis);
-     *      HSSFSheet sheet = workbook.getSheetAt(0);
-     *      addImage.addImageToSheet("C3", sheet, "image.jpg", 30, 20,
-     *          AddDimensionedImage.EXPAND.ROW);
-     *
-     * @param args the command line arguments
-     */
-    public static void main(String[] args) throws IOException {
-        if(args.length < 2){
-               System.err.println("Usage: AddDimensionedImage imageFile outputFile");
-               return;
-       }
-
-        final String imageFile = args[0];
-        final String outputFile = args[1];
-
-        try (final Workbook workbook = new HSSFWorkbook();
-             final FileOutputStream fos = new FileOutputStream(outputFile)) {   // OR XSSFWorkbook
-            Sheet sheet = workbook.createSheet("Picture Test");
-            new AddDimensionedImage().addImageToSheet("B5", sheet, sheet.createDrawingPatriarch(),
-                    new File(imageFile).toURI().toURL(), 100, 40,
-                    AddDimensionedImage.EXPAND_ROW_AND_COLUMN);
-            workbook.write(fos);
-        }
-    }
-
-    /**
-     * The HSSFClientAnchor class accepts eight arguments. In order, these are;
-     *
-     *      * How far the left hand edge of the image is inset from the left hand
-     *      edge of the cell
-     *      * How far the top edge of the image is inset from the top of the cell
-     *      * How far the right hand edge of the image is inset from the left
-     *      hand edge of the cell
-     *      * How far the bottom edge of the image is inset from the top of the
-     *      cell.
-     *      * Together, arguments five and six determine the column and row
-     *      coordinates of the cell whose top left hand corner will be aligned
-     *      with the images top left hand corner.
-     *      * Together, arguments seven and eight determine the column and row
-     *      coordinates of the cell whose top left hand corner will be aligned
-     *      with the images bottom right hand corner.
-     *
-     * An instance of the ClientAnchorDetail class provides three of the eight
-     * parameters, one of the coordinates for the images top left hand corner,
-     * one of the coordinates for the images bottom right hand corner and
-     * either how far the image should be inset from the top or the left hand
-     * edge of the cell.
-     *
-     * @author Mark Beardsley [msb at apache.org]
-     * @version 1.00 5th August 2009.
-     */
-    public class ClientAnchorDetail {
-
-        private int fromIndex;
-        private int toIndex;
-        private int inset;
-
-        /**
-         * Create a new instance of the ClientAnchorDetail class using the
-         * following parameters.
-         *
-         * @param fromIndex A primitive int that contains one of the
-         *                  coordinates (row or column index) for the top left
-         *                  hand corner of the image.
-         * @param toIndex A primitive int that contains one of the
-         *                coordinates (row or column index) for the bottom
-         *                right hand corner of the image.
-         * @param inset A primitive int that contains a value which indicates
-         *              how far the image should be inset from the top or the
-         *              left hand edge of a cell.
-         */
-        public ClientAnchorDetail(int fromIndex, int toIndex, int inset) {
-            this.fromIndex = fromIndex;
-            this.toIndex = toIndex;
-            this.inset = inset;
-        }
-
-        /**
-         * Get one of the number of the column or row that contains the cell
-         * whose top left hand corner will be aligned with the top left hand
-         * corner of the image.
-         *
-         * @return The value - row or column index - for one of the coordinates
-         *         of the top left hand corner of the image.
-         */
-        public int getFromIndex() {
-            return(this.fromIndex);
-        }
-
-        /**
-         * Get one of the number of the column or row that contains the cell
-         * whose top left hand corner will be aligned with the bottom right hand
-         * corner of the image.
-         *
-         * @return The value - row or column index - for one of the coordinates
-         *         of the bottom right hand corner of the image.
-         */
-        public int getToIndex() {
-            return(this.toIndex);
-        }
-
-        /**
-         * Get the images offset from the edge of a cell.
-         *
-         * @return How far either the right hand or bottom edge of the image is
-         *         inset from the left hand or top edge of a cell.
-         */
-        public int getInset() {
-            return(this.inset);
-        }
-    }
-
-    /**
-     * Utility methods used to convert Excels character based column and row
-     * size measurements into pixels and/or millimetres. The class also contains
-     * various constants that are required in other calculations.
-     *
-     * @author xio[darjino@hotmail.com]
-     * @version 1.01 30th July 2009.
-     *      Added by Mark Beardsley [msb at apache.org].
-     *          Additional constants.
-     *          widthUnits2Millimetres() and millimetres2Units() methods.
-     */
-    public static class ConvertImageUnits {
-
-        // Each cell conatins a fixed number of co-ordinate points; this number
-        // does not vary with row height or column width or with font. These two
-        // constants are defined below.
-        public static final int TOTAL_COLUMN_COORDINATE_POSITIONS = 1023;
-        public static final int TOTAL_ROW_COORDINATE_POSITIONS = 255;
-        // The resoultion of an image can be expressed as a specific number
-        // of pixels per inch. Displays and printers differ but 96 pixels per
-        // inch is an acceptable standard to beging with.
-        public static final int PIXELS_PER_INCH = 96;
-        // Cnstants that defines how many pixels and points there are in a
-        // millimetre. These values are required for the conversion algorithm.
-        public static final double PIXELS_PER_MILLIMETRES = 3.78;
-        public static final double POINTS_PER_MILLIMETRE = 2.83;
-        // The column width returned by HSSF and the width of a picture when
-        // positioned to exactly cover one cell are different by almost exactly
-        // 2mm - give or take rounding errors. This constant allows that
-        // additional amount to be accounted for when calculating how many
-        // celles the image ought to overlie.
-        public static final double CELL_BORDER_WIDTH_MILLIMETRES = 2.0D;
-        public static final short EXCEL_COLUMN_WIDTH_FACTOR = 256;
-        public static final int UNIT_OFFSET_LENGTH = 7;
-        private static final int[] UNIT_OFFSET_MAP = { 0, 36, 73, 109, 146, 182, 219 };
-
-        /**
-        * pixel units to excel width units(units of 1/256th of a character width)
-        */
-        public static short pixel2WidthUnits(int pxs) {
-            short widthUnits = (short) (EXCEL_COLUMN_WIDTH_FACTOR *
-                    (pxs / UNIT_OFFSET_LENGTH));
-            widthUnits += UNIT_OFFSET_MAP[(pxs % UNIT_OFFSET_LENGTH)];
-            return widthUnits;
-        }
-
-        /**
-         * excel width units(units of 1/256th of a character width) to pixel
-         * units.
-         */
-        public static int widthUnits2Pixel(short widthUnits) {
-            int pixels = (widthUnits / EXCEL_COLUMN_WIDTH_FACTOR)
-                    * UNIT_OFFSET_LENGTH;
-            int offsetWidthUnits = widthUnits % EXCEL_COLUMN_WIDTH_FACTOR;
-            pixels += Math.round(offsetWidthUnits /
-                    ((float) EXCEL_COLUMN_WIDTH_FACTOR / UNIT_OFFSET_LENGTH));
-            return pixels;
-        }
-
-        /**
-         * Convert Excels width units into millimetres.
-         *
-         * @param widthUnits The width of the column or the height of the
-         *                   row in Excels units.
-         * @return A primitive double that contains the columns width or rows
-         *         height in millimetres.
-         */
-        public static double widthUnits2Millimetres(short widthUnits) {
-            return(ConvertImageUnits.widthUnits2Pixel(widthUnits) /
-                   ConvertImageUnits.PIXELS_PER_MILLIMETRES);
-        }
-
-        /**
-         * Convert into millimetres Excels width units..
-         *
-         * @param millimetres A primitive double that contains the columns
-         *                    width or rows height in millimetres.
-         * @return A primitive int that contains the columns width or rows
-         *         height in Excels units.
-         */
-        public static int millimetres2WidthUnits(double millimetres) {
-            return(ConvertImageUnits.pixel2WidthUnits((int)(millimetres *
-                    ConvertImageUnits.PIXELS_PER_MILLIMETRES)));
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/AligningCells.java b/src/examples/src/org/apache/poi/ss/examples/AligningCells.java
deleted file mode 100644 (file)
index cdd2bbc..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/* ====================================================================
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.poi.ss.usermodel.*;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Shows how various alignment options work.
- */
-public class AligningCells {
-
-    public static void main(String[] args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
-
-            Sheet sheet = wb.createSheet();
-            Row row = sheet.createRow(2);
-            row.setHeightInPoints(30);
-            for (int i = 0; i < 8; i++) {
-                //column width is set in units of 1/256th of a character width
-                sheet.setColumnWidth(i, 256 * 15);
-            }
-
-            createCell(wb, row, 0, HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
-            createCell(wb, row, 1, HorizontalAlignment.CENTER_SELECTION, VerticalAlignment.BOTTOM);
-            createCell(wb, row, 2, HorizontalAlignment.FILL, VerticalAlignment.CENTER);
-            createCell(wb, row, 3, HorizontalAlignment.GENERAL, VerticalAlignment.CENTER);
-            createCell(wb, row, 4, HorizontalAlignment.JUSTIFY, VerticalAlignment.JUSTIFY);
-            createCell(wb, row, 5, HorizontalAlignment.LEFT, VerticalAlignment.TOP);
-            createCell(wb, row, 6, HorizontalAlignment.RIGHT, VerticalAlignment.TOP);
-
-            // Write the output to a file
-            try (OutputStream fileOut = new FileOutputStream("ss-example-align.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-
-    /**
-     * Creates a cell and aligns it a certain way.
-     *
-     * @param wb     the workbook
-     * @param row    the row to create the cell in
-     * @param column the column number to create the cell in
-     * @param halign the horizontal alignment for the cell.
-     */
-    private static void createCell(Workbook wb, Row row, int column, HorizontalAlignment halign, VerticalAlignment valign) {
-        CreationHelper ch = wb.getCreationHelper();
-        Cell cell = row.createCell(column);
-        cell.setCellValue(ch.createRichTextString("Align It"));
-        CellStyle cellStyle = wb.createCellStyle();
-        cellStyle.setAlignment(halign);
-        cellStyle.setVerticalAlignment(valign);
-        cell.setCellStyle(cellStyle);
-    }
-}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/ss/examples/BusinessPlan.java b/src/examples/src/org/apache/poi/ss/examples/BusinessPlan.java
deleted file mode 100644 (file)
index 0e35509..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.examples;
-
-import java.io.FileOutputStream;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.DataFormat;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.usermodel.PrintSetup;
-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.xssf.usermodel.XSSFWorkbook;
-
-/**
- * A business plan demo
- * Usage:
- *  BusinessPlan -xls|xlsx
- *
- * @author Yegor Kozlov
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class BusinessPlan {
-
-    private static final String[] titles = {
-            "ID", "Project Name", "Owner", "Days", "Start", "End"};
-
-    //sample data to fill the sheet.
-    private static final String[][] data = {
-            {"1.0", "Marketing Research Tactical Plan", "J. Dow", "70", "9-Jul", null,
-                "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x"},
-            null,
-            {"1.1", "Scope Definition Phase", "J. Dow", "10", "9-Jul", null,
-                "x", "x", null, null,  null, null, null, null, null, null, null},
-            {"1.1.1", "Define research objectives", "J. Dow", "3", "9-Jul", null,
-                    "x", null, null, null,  null, null, null, null, null, null, null},
-            {"1.1.2", "Define research requirements", "S. Jones", "7", "10-Jul", null,
-                "x", "x", null, null,  null, null, null, null, null, null, null},
-            {"1.1.3", "Determine in-house resource or hire vendor", "J. Dow", "2", "15-Jul", null,
-                "x", "x", null, null,  null, null, null, null, null, null, null},
-            null,
-            {"1.2", "Vendor Selection Phase", "J. Dow", "19", "19-Jul", null,
-                null, "x", "x", "x",  "x", null, null, null, null, null, null},
-            {"1.2.1", "Define vendor selection criteria", "J. Dow", "3", "19-Jul", null,
-                null, "x", null, null,  null, null, null, null, null, null, null},
-            {"1.2.2", "Develop vendor selection questionnaire", "S. Jones, T. Wates", "2", "22-Jul", null,
-                null, "x", "x", null,  null, null, null, null, null, null, null},
-            {"1.2.3", "Develop Statement of Work", "S. Jones", "4", "26-Jul", null,
-                null, null, "x", "x",  null, null, null, null, null, null, null},
-            {"1.2.4", "Evaluate proposal", "J. Dow, S. Jones", "4", "2-Aug", null,
-                null, null, null, "x",  "x", null, null, null, null, null, null},
-            {"1.2.5", "Select vendor", "J. Dow", "1", "6-Aug", null,
-                null, null, null, null,  "x", null, null, null, null, null, null},
-            null,
-            {"1.3", "Research Phase", "G. Lee", "47", "9-Aug", null,
-                null, null, null, null,  "x", "x", "x", "x", "x", "x", "x"},
-            {"1.3.1", "Develop market research information needs questionnaire", "G. Lee", "2", "9-Aug", null,
-                null, null, null, null,  "x", null, null, null, null, null, null},
-            {"1.3.2", "Interview marketing group for market research needs", "G. Lee", "2", "11-Aug", null,
-                null, null, null, null,  "x", "x", null, null, null, null, null},
-            {"1.3.3", "Document information needs", "G. Lee, S. Jones", "1", "13-Aug", null,
-                null, null, null, null,  null, "x", null, null, null, null, null},
-    };
-
-    private BusinessPlan() {}
-
-    public static void main(String[] args) throws Exception {
-        Workbook wb;
-
-        if(args.length > 0 && args[0].equals("-xls")) wb = new HSSFWorkbook();
-        else wb = new XSSFWorkbook();
-
-        final SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM");
-
-        Map<String, CellStyle> styles = createStyles(wb);
-
-        Sheet sheet = wb.createSheet("Business Plan");
-
-        //turn off gridlines
-        sheet.setDisplayGridlines(false);
-        sheet.setPrintGridlines(false);
-        sheet.setFitToPage(true);
-        sheet.setHorizontallyCenter(true);
-        PrintSetup printSetup = sheet.getPrintSetup();
-        printSetup.setLandscape(true);
-
-        //the following three statements are required only for HSSF
-        sheet.setAutobreaks(true);
-        printSetup.setFitHeight((short)1);
-        printSetup.setFitWidth((short)1);
-
-        //the header row: centered text in 48pt font
-        Row headerRow = sheet.createRow(0);
-        headerRow.setHeightInPoints(12.75f);
-        for (int i = 0; i < titles.length; i++) {
-            Cell cell = headerRow.createCell(i);
-            cell.setCellValue(titles[i]);
-            cell.setCellStyle(styles.get("header"));
-        }
-        //columns for 11 weeks starting from 9-Jul
-        Calendar calendar = Calendar.getInstance();
-        int year = calendar.get(Calendar.YEAR);
-
-        calendar.setTime(fmt.parse("9-Jul"));
-        calendar.set(Calendar.YEAR, year);
-        for (int i = 0; i < 11; i++) {
-            Cell cell = headerRow.createCell(titles.length + i);
-            cell.setCellValue(calendar);
-            cell.setCellStyle(styles.get("header_date"));
-            calendar.roll(Calendar.WEEK_OF_YEAR, true);
-        }
-        //freeze the first row
-        sheet.createFreezePane(0, 1);
-
-        Row row;
-        Cell cell;
-        int rownum = 1;
-        for (int i = 0; i < data.length; i++, rownum++) {
-            row = sheet.createRow(rownum);
-            if(data[i] == null) continue;
-
-            for (int j = 0; j < data[i].length; j++) {
-                cell = row.createCell(j);
-                String styleName;
-                boolean isHeader = i == 0 || data[i-1] == null;
-                switch(j){
-                    case 0:
-                        if(isHeader) {
-                            styleName = "cell_b";
-                            cell.setCellValue(Double.parseDouble(data[i][j]));
-                        } else {
-                            styleName = "cell_normal";
-                            cell.setCellValue(data[i][j]);
-                        }
-                        break;
-                    case 1:
-                        if(isHeader) {
-                            styleName = i == 0 ? "cell_h" : "cell_bb";
-                        } else {
-                            styleName = "cell_indented";
-                        }
-                        cell.setCellValue(data[i][j]);
-                        break;
-                    case 2:
-                        styleName = isHeader ? "cell_b" : "cell_normal";
-                        cell.setCellValue(data[i][j]);
-                        break;
-                    case 3:
-                        styleName = isHeader ? "cell_b_centered" : "cell_normal_centered";
-                        cell.setCellValue(Integer.parseInt(data[i][j]));
-                        break;
-                    case 4: {
-                        calendar.setTime(fmt.parse(data[i][j]));
-                        calendar.set(Calendar.YEAR, year);
-                        cell.setCellValue(calendar);
-                        styleName = isHeader ? "cell_b_date" : "cell_normal_date";
-                        break;
-                    }
-                    case 5: {
-                        int r = rownum + 1;
-                        String fmla = "IF(AND(D"+r+",E"+r+"),E"+r+"+D"+r+",\"\")";
-                        cell.setCellFormula(fmla);
-                        styleName = isHeader ? "cell_bg" : "cell_g";
-                        break;
-                    }
-                    default:
-                        styleName = data[i][j] != null ? "cell_blue" : "cell_normal";
-                }
-
-                cell.setCellStyle(styles.get(styleName));
-            }
-        }
-
-        //group rows for each phase, row numbers are 0-based
-        sheet.groupRow(4, 6);
-        sheet.groupRow(9, 13);
-        sheet.groupRow(16, 18);
-
-        //set column widths, the width is measured in units of 1/256th of a character width
-        sheet.setColumnWidth(0, 256*6);
-        sheet.setColumnWidth(1, 256*33);
-        sheet.setColumnWidth(2, 256*20);
-        sheet.setZoom(75); //75% scale
-
-
-        // Write the output to a file
-        String file = "businessplan.xls";
-        if(wb instanceof XSSFWorkbook) file += "x";
-        FileOutputStream out = new FileOutputStream(file);
-        wb.write(out);
-        out.close();
-
-        wb.close();
-    }
-
-    /**
-     * create a library of cell styles
-     */
-    private static Map<String, CellStyle> createStyles(Workbook wb){
-        Map<String, CellStyle> styles = new HashMap<>();
-        DataFormat df = wb.createDataFormat();
-
-        CellStyle style;
-        Font headerFont = wb.createFont();
-        headerFont.setBold(true);
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setFont(headerFont);
-        styles.put("header", style);
-
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setFont(headerFont);
-        style.setDataFormat(df.getFormat("d-mmm"));
-        styles.put("header_date", style);
-
-        Font font1 = wb.createFont();
-        font1.setBold(true);
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.LEFT);
-        style.setFont(font1);
-        styles.put("cell_b", style);
-
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setFont(font1);
-        styles.put("cell_b_centered", style);
-
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.RIGHT);
-        style.setFont(font1);
-        style.setDataFormat(df.getFormat("d-mmm"));
-        styles.put("cell_b_date", style);
-
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.RIGHT);
-        style.setFont(font1);
-        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setDataFormat(df.getFormat("d-mmm"));
-        styles.put("cell_g", style);
-
-        Font font2 = wb.createFont();
-        font2.setColor(IndexedColors.BLUE.getIndex());
-        font2.setBold(true);
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.LEFT);
-        style.setFont(font2);
-        styles.put("cell_bb", style);
-
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.RIGHT);
-        style.setFont(font1);
-        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setDataFormat(df.getFormat("d-mmm"));
-        styles.put("cell_bg", style);
-
-        Font font3 = wb.createFont();
-        font3.setFontHeightInPoints((short)14);
-        font3.setColor(IndexedColors.DARK_BLUE.getIndex());
-        font3.setBold(true);
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.LEFT);
-        style.setFont(font3);
-        style.setWrapText(true);
-        styles.put("cell_h", style);
-
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.LEFT);
-        style.setWrapText(true);
-        styles.put("cell_normal", style);
-
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setWrapText(true);
-        styles.put("cell_normal_centered", style);
-
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.RIGHT);
-        style.setWrapText(true);
-        style.setDataFormat(df.getFormat("d-mmm"));
-        styles.put("cell_normal_date", style);
-
-        style = createBorderedStyle(wb);
-        style.setAlignment(HorizontalAlignment.LEFT);
-        style.setIndention((short)1);
-        style.setWrapText(true);
-        styles.put("cell_indented", style);
-
-        style = createBorderedStyle(wb);
-        style.setFillForegroundColor(IndexedColors.BLUE.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        styles.put("cell_blue", style);
-
-        return styles;
-    }
-
-    private static CellStyle createBorderedStyle(Workbook wb){
-        BorderStyle thin = BorderStyle.THIN;
-        short black = IndexedColors.BLACK.getIndex();
-
-        CellStyle style = wb.createCellStyle();
-        style.setBorderRight(thin);
-        style.setRightBorderColor(black);
-        style.setBorderBottom(thin);
-        style.setBottomBorderColor(black);
-        style.setBorderLeft(thin);
-        style.setLeftBorderColor(black);
-        style.setBorderTop(thin);
-        style.setTopBorderColor(black);
-        return style;
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/CalendarDemo.java b/src/examples/src/org/apache/poi/ss/examples/CalendarDemo.java
deleted file mode 100644 (file)
index 108cc25..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.examples;
-
-import java.io.FileOutputStream;
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.usermodel.PrintSetup;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.VerticalAlignment;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * A  monthly calendar created using Apache POI. Each month is on a separate sheet.
- * <pre>
- * Usage:
- * CalendarDemo -xls|xlsx <year>
- * </pre>
- *
- * @author Yegor Kozlov
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class CalendarDemo {
-
-    private static final String[] days = {
-            "Sunday", "Monday", "Tuesday",
-            "Wednesday", "Thursday", "Friday", "Saturday"};
-
-    private static final String[]  months = {
-            "January", "February", "March","April", "May", "June","July", "August",
-            "September","October", "November", "December"};
-
-    private CalendarDemo() {}
-
-    public static void main(String[] args) throws Exception {
-
-        Calendar calendar = Calendar.getInstance();
-        boolean xlsx = true;
-        for (String arg : args) {
-            if (arg.charAt(0) == '-') {
-                xlsx = arg.equals("-xlsx");
-            } else {
-                calendar.set(Calendar.YEAR, Integer.parseInt(arg));
-            }
-        }
-        int year = calendar.get(Calendar.YEAR);
-
-        try (Workbook wb = xlsx ? new XSSFWorkbook() : new HSSFWorkbook()) {
-
-            Map<String, CellStyle> styles = createStyles(wb);
-
-            for (int month = 0; month < 12; month++) {
-                calendar.set(Calendar.MONTH, month);
-                calendar.set(Calendar.DAY_OF_MONTH, 1);
-                //create a sheet for each month
-                Sheet sheet = wb.createSheet(months[month]);
-
-                //turn off gridlines
-                sheet.setDisplayGridlines(false);
-                sheet.setPrintGridlines(false);
-                sheet.setFitToPage(true);
-                sheet.setHorizontallyCenter(true);
-                PrintSetup printSetup = sheet.getPrintSetup();
-                printSetup.setLandscape(true);
-
-                //the following three statements are required only for HSSF
-                sheet.setAutobreaks(true);
-                printSetup.setFitHeight((short) 1);
-                printSetup.setFitWidth((short) 1);
-
-                //the header row: centered text in 48pt font
-                Row headerRow = sheet.createRow(0);
-                headerRow.setHeightInPoints(80);
-                Cell titleCell = headerRow.createCell(0);
-                titleCell.setCellValue(months[month] + " " + year);
-                titleCell.setCellStyle(styles.get("title"));
-                sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$N$1"));
-
-                //header with month titles
-                Row monthRow = sheet.createRow(1);
-                for (int i = 0; i < days.length; i++) {
-                    //set column widths, the width is measured in units of 1/256th of a character width
-                    sheet.setColumnWidth(i * 2, 5 * 256); //the column is 5 characters wide
-                    sheet.setColumnWidth(i * 2 + 1, 13 * 256); //the column is 13 characters wide
-                    sheet.addMergedRegion(new CellRangeAddress(1, 1, i * 2, i * 2 + 1));
-                    Cell monthCell = monthRow.createCell(i * 2);
-                    monthCell.setCellValue(days[i]);
-                    monthCell.setCellStyle(styles.get("month"));
-                }
-
-                int cnt = 1, day = 1;
-                int rownum = 2;
-                for (int j = 0; j < 6; j++) {
-                    Row row = sheet.createRow(rownum++);
-                    row.setHeightInPoints(100);
-                    for (int i = 0; i < days.length; i++) {
-                        Cell dayCell_1 = row.createCell(i * 2);
-                        Cell dayCell_2 = row.createCell(i * 2 + 1);
-
-                        int day_of_week = calendar.get(Calendar.DAY_OF_WEEK);
-                        if (cnt >= day_of_week && calendar.get(Calendar.MONTH) == month) {
-                            dayCell_1.setCellValue(day);
-                            calendar.set(Calendar.DAY_OF_MONTH, ++day);
-
-                            if (i == 0 || i == days.length - 1) {
-                                dayCell_1.setCellStyle(styles.get("weekend_left"));
-                                dayCell_2.setCellStyle(styles.get("weekend_right"));
-                            } else {
-                                dayCell_1.setCellStyle(styles.get("workday_left"));
-                                dayCell_2.setCellStyle(styles.get("workday_right"));
-                            }
-                        } else {
-                            dayCell_1.setCellStyle(styles.get("grey_left"));
-                            dayCell_2.setCellStyle(styles.get("grey_right"));
-                        }
-                        cnt++;
-                    }
-                    if (calendar.get(Calendar.MONTH) > month) break;
-                }
-            }
-
-            // Write the output to a file
-            String file = "calendar.xls";
-            if (wb instanceof XSSFWorkbook) file += "x";
-
-            try (FileOutputStream out = new FileOutputStream(file)) {
-                wb.write(out);
-            }
-        }
-    }
-
-    /**
-     * cell styles used for formatting calendar sheets
-     */
-    private static Map<String, CellStyle> createStyles(Workbook wb){
-        Map<String, CellStyle> styles = new HashMap<>();
-
-        short borderColor = IndexedColors.GREY_50_PERCENT.getIndex();
-
-        CellStyle style;
-        Font titleFont = wb.createFont();
-        titleFont.setFontHeightInPoints((short)48);
-        titleFont.setColor(IndexedColors.DARK_BLUE.getIndex());
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setFont(titleFont);
-        styles.put("title", style);
-
-        Font monthFont = wb.createFont();
-        monthFont.setFontHeightInPoints((short)12);
-        monthFont.setColor(IndexedColors.WHITE.getIndex());
-        monthFont.setBold(true);
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setFont(monthFont);
-        styles.put("month", style);
-
-        Font dayFont = wb.createFont();
-        dayFont.setFontHeightInPoints((short)14);
-        dayFont.setBold(true);
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.LEFT);
-        style.setVerticalAlignment(VerticalAlignment.TOP);
-        style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setBorderLeft(BorderStyle.THIN);
-        style.setLeftBorderColor(borderColor);
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(borderColor);
-        style.setFont(dayFont);
-        styles.put("weekend_left", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.TOP);
-        style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setBorderRight(BorderStyle.THIN);
-        style.setRightBorderColor(borderColor);
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(borderColor);
-        styles.put("weekend_right", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.LEFT);
-        style.setVerticalAlignment(VerticalAlignment.TOP);
-        style.setBorderLeft(BorderStyle.THIN);
-        style.setFillForegroundColor(IndexedColors.WHITE.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setLeftBorderColor(borderColor);
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(borderColor);
-        style.setFont(dayFont);
-        styles.put("workday_left", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.TOP);
-        style.setFillForegroundColor(IndexedColors.WHITE.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setBorderRight(BorderStyle.THIN);
-        style.setRightBorderColor(borderColor);
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(borderColor);
-        styles.put("workday_right", style);
-
-        style = wb.createCellStyle();
-        style.setBorderLeft(BorderStyle.THIN);
-        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(borderColor);
-        styles.put("grey_left", style);
-
-        style = wb.createCellStyle();
-        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setBorderRight(BorderStyle.THIN);
-        style.setRightBorderColor(borderColor);
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(borderColor);
-        styles.put("grey_right", style);
-
-        return styles;
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/CellStyleDetails.java b/src/examples/src/org/apache/poi/ss/examples/CellStyleDetails.java
deleted file mode 100644 (file)
index 4729c9f..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.examples;
-
-import java.io.File;
-
-import org.apache.poi.hssf.usermodel.HSSFFont;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.util.HSSFColor;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.Color;
-import org.apache.poi.ss.usermodel.DataFormatter;
-import org.apache.poi.ss.usermodel.Font;
-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.WorkbookFactory;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xssf.usermodel.XSSFColor;
-import org.apache.poi.xssf.usermodel.XSSFFont;
-
-/**
- * Demonstrates how to read excel styles for cells
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public final class CellStyleDetails {
-    private CellStyleDetails() {}
-
-    public static void main(String[] args) throws Exception {
-        if(args.length == 0) {
-           throw new IllegalArgumentException("Filename must be given");
-        }
-
-        try (Workbook wb = WorkbookFactory.create(new File(args[0]))) {
-            DataFormatter formatter = new DataFormatter();
-
-            for (int sn = 0; sn < wb.getNumberOfSheets(); sn++) {
-                Sheet sheet = wb.getSheetAt(sn);
-                System.out.println("Sheet #" + sn + " : " + sheet.getSheetName());
-
-                for (Row row : sheet) {
-                    System.out.println("  Row " + row.getRowNum());
-
-                    for (Cell cell : row) {
-                        CellReference ref = new CellReference(cell);
-                        System.out.print("    " + ref.formatAsString());
-                        System.out.print(" (" + cell.getColumnIndex() + ") ");
-
-                        CellStyle style = cell.getCellStyle();
-                        System.out.print("Format=" + style.getDataFormatString() + " ");
-                        System.out.print("FG=" + renderColor(style.getFillForegroundColorColor()) + " ");
-                        System.out.print("BG=" + renderColor(style.getFillBackgroundColorColor()) + " ");
-
-                        Font font = wb.getFontAt(style.getFontIndexAsInt());
-                        System.out.print("Font=" + font.getFontName() + " ");
-                        System.out.print("FontColor=");
-                        if (font instanceof HSSFFont) {
-                            System.out.print(renderColor(((HSSFFont) font).getHSSFColor((HSSFWorkbook) wb)));
-                        }
-                        if (font instanceof XSSFFont) {
-                            System.out.print(renderColor(((XSSFFont) font).getXSSFColor()));
-                        }
-
-                        System.out.println();
-                        System.out.println("        " + formatter.formatCellValue(cell));
-                    }
-                }
-
-                System.out.println();
-            }
-        }
-    }
-
-    private static String renderColor(Color color) {
-       if(color instanceof HSSFColor) {
-          return ((HSSFColor)color).getHexString();
-       } else if(color instanceof XSSFColor) {
-          return ((XSSFColor)color).getARGBHex();
-       } else {
-          return "(none)";
-       }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/ConditionalFormats.java b/src/examples/src/org/apache/poi/ss/examples/ConditionalFormats.java
deleted file mode 100644 (file)
index ff26f9d..0000000
+++ /dev/null
@@ -1,732 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.ss.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.List;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.formula.ConditionalFormattingEvaluator;
-import org.apache.poi.ss.formula.EvaluationConditionalFormatRule;
-import org.apache.poi.ss.formula.WorkbookEvaluatorProvider;
-import org.apache.poi.ss.usermodel.BuiltinFormats;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.ColorScaleFormatting;
-import org.apache.poi.ss.usermodel.ComparisonOperator;
-import org.apache.poi.ss.usermodel.ConditionalFormattingRule;
-import org.apache.poi.ss.usermodel.ConditionalFormattingThreshold.RangeType;
-import org.apache.poi.ss.usermodel.DataBarFormatting;
-import org.apache.poi.ss.usermodel.ExtendedColor;
-import org.apache.poi.ss.usermodel.FontFormatting;
-import org.apache.poi.ss.usermodel.IconMultiStateFormatting;
-import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.usermodel.PatternFormatting;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.SheetConditionalFormatting;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Excel Conditional Formatting -- Examples
- *
- * <p>
- *   Partly based on the code snippets from
- *   http://www.contextures.com/xlcondformat03.html
- * </p>
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class ConditionalFormats {
-
-    private ConditionalFormats() {}
-
-    /**
-     * generates a sample workbook with conditional formatting,
-     * and prints out a summary of applied formats for one sheet
-     * @param args pass "-xls" to generate an HSSF workbook, default is XSSF
-     */
-    public static void main(String[] args) throws IOException {
-        final boolean isHSSF = args.length > 0 && args[0].equals("-xls");
-        try (Workbook wb = isHSSF ? new HSSFWorkbook() : new XSSFWorkbook()) {
-
-            sameCell(wb.createSheet("Same Cell"));
-            multiCell(wb.createSheet("MultiCell"));
-            overlapping(wb.createSheet("Overlapping"));
-            errors(wb.createSheet("Errors"));
-            hideDupplicates(wb.createSheet("Hide Dups"));
-            formatDuplicates(wb.createSheet("Duplicates"));
-            inList(wb.createSheet("In List"));
-            expiry(wb.createSheet("Expiry"));
-            shadeAlt(wb.createSheet("Shade Alt"));
-            shadeBands(wb.createSheet("Shade Bands"));
-            iconSets(wb.createSheet("Icon Sets"));
-            colourScales(wb.createSheet("Colour Scales"));
-            dataBars(wb.createSheet("Data Bars"));
-
-            // print overlapping rule results
-            evaluateRules(wb, "Overlapping");
-
-            // Write the output to a file
-            String file = "cf-poi.xls";
-            if (wb instanceof XSSFWorkbook) {
-                file += "x";
-            }
-            try (FileOutputStream out = new FileOutputStream(file)) {
-                wb.write(out);
-            }
-            System.out.println("Generated: " + file);
-        }
-    }
-
-    /**
-     * Highlight cells based on their values
-     */
-    static void sameCell(Sheet sheet) {
-        sheet.createRow(0).createCell(0).setCellValue(84);
-        sheet.createRow(1).createCell(0).setCellValue(74);
-        sheet.createRow(2).createCell(0).setCellValue(50);
-        sheet.createRow(3).createCell(0).setCellValue(51);
-        sheet.createRow(4).createCell(0).setCellValue(49);
-        sheet.createRow(5).createCell(0).setCellValue(41);
-
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        // Condition 1: Cell Value Is   greater than  70   (Blue Fill)
-        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule(ComparisonOperator.GT, "70");
-        PatternFormatting fill1 = rule1.createPatternFormatting();
-        fill1.setFillBackgroundColor(IndexedColors.BLUE.index);
-        fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
-
-        // Condition 2: Cell Value Is  less than      50   (Green Fill)
-        ConditionalFormattingRule rule2 = sheetCF.createConditionalFormattingRule(ComparisonOperator.LT, "50");
-        PatternFormatting fill2 = rule2.createPatternFormatting();
-        fill2.setFillBackgroundColor(IndexedColors.GREEN.index);
-        fill2.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
-
-        CellRangeAddress[] regions = {
-                CellRangeAddress.valueOf("A1:A6")
-        };
-
-        sheetCF.addConditionalFormatting(regions, rule1, rule2);
-
-        sheet.getRow(0).createCell(2).setCellValue("<== Condition 1: Cell Value Is greater than 70 (Blue Fill)");
-        sheet.getRow(4).createCell(2).setCellValue("<== Condition 2: Cell Value Is less than 50 (Green Fill)");
-    }
-
-    /**
-     * Highlight multiple cells based on a formula
-     */
-    static void multiCell(Sheet sheet) {
-        // header row
-        Row row0 = sheet.createRow(0);
-        row0.createCell(0).setCellValue("Units");
-        row0.createCell(1).setCellValue("Cost");
-        row0.createCell(2).setCellValue("Total");
-
-        Row row1 = sheet.createRow(1);
-        row1.createCell(0).setCellValue(71);
-        row1.createCell(1).setCellValue(29);
-        row1.createCell(2).setCellValue(2059);
-
-        Row row2 = sheet.createRow(2);
-        row2.createCell(0).setCellValue(85);
-        row2.createCell(1).setCellValue(29);
-        row2.createCell(2).setCellValue(2059);
-
-        Row row3 = sheet.createRow(3);
-        row3.createCell(0).setCellValue(71);
-        row3.createCell(1).setCellValue(29);
-        row3.createCell(2).setCellValue(2059);
-
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        // Condition 1: Formula Is   =$B2>75   (Blue Fill)
-        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("$A2>75");
-        PatternFormatting fill1 = rule1.createPatternFormatting();
-        fill1.setFillBackgroundColor(IndexedColors.BLUE.index);
-        fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
-
-        CellRangeAddress[] regions = {
-                CellRangeAddress.valueOf("A2:C4")
-        };
-
-        sheetCF.addConditionalFormatting(regions, rule1);
-
-        sheet.getRow(2).createCell(4).setCellValue("<== Condition 1: Formula Is =$B2>75   (Blue Fill)");
-    }
-
-    /**
-     * Multiple conditional formatting rules can apply to
-     *  one cell, some combining, some beating others.
-     * Done in order of the rules added to the
-     *  SheetConditionalFormatting object
-     */
-    static void overlapping(Sheet sheet) {
-        for (int i=0; i<40; i++) {
-            int rn = i+1;
-            Row r = sheet.createRow(i);
-            r.createCell(0).setCellValue("This is row " + rn + " (" + i + ")");
-            String str = "";
-            if (rn%2 == 0) {
-                str = str + "even ";
-            }
-            if (rn%3 == 0) {
-                str = str + "x3 ";
-            }
-            if (rn%5 == 0) {
-                str = str + "x5 ";
-            }
-            if (rn%10 == 0) {
-                str = str + "x10 ";
-            }
-            if (str.length() == 0) {
-                str = "nothing special...";
-            }
-            r.createCell(1).setCellValue("It is " + str);
-        }
-        sheet.autoSizeColumn(0);
-        sheet.autoSizeColumn(1);
-
-        sheet.getRow(1).createCell(3).setCellValue("Even rows are blue");
-        sheet.getRow(2).createCell(3).setCellValue("Multiples of 3 have a grey background");
-        sheet.getRow(4).createCell(3).setCellValue("Multiples of 5 are bold");
-        sheet.getRow(9).createCell(3).setCellValue("Multiples of 10 are red (beats even)");
-
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        // Condition 1: Row divides by 10, red (will beat #1)
-        ConditionalFormattingRule rule1 =
-                sheetCF.createConditionalFormattingRule("MOD(ROW(),10)=0");
-        FontFormatting font1 = rule1.createFontFormatting();
-        font1.setFontColorIndex(IndexedColors.RED.index);
-
-        // Condition 2: Row is even, blue
-        ConditionalFormattingRule rule2 =
-                sheetCF.createConditionalFormattingRule("MOD(ROW(),2)=0");
-        FontFormatting font2 = rule2.createFontFormatting();
-        font2.setFontColorIndex(IndexedColors.BLUE.index);
-
-        // Condition 3: Row divides by 5, bold
-        ConditionalFormattingRule rule3 =
-                sheetCF.createConditionalFormattingRule("MOD(ROW(),5)=0");
-        FontFormatting font3 = rule3.createFontFormatting();
-        font3.setFontStyle(false, true);
-
-        // Condition 4: Row divides by 3, grey background
-        ConditionalFormattingRule rule4 =
-                sheetCF.createConditionalFormattingRule("MOD(ROW(),3)=0");
-        PatternFormatting fill4 = rule4.createPatternFormatting();
-        fill4.setFillBackgroundColor(IndexedColors.GREY_25_PERCENT.index);
-        fill4.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
-
-        // Apply
-        CellRangeAddress[] regions = {
-                CellRangeAddress.valueOf("A1:F41")
-        };
-
-        sheetCF.addConditionalFormatting(regions, rule1);
-        sheetCF.addConditionalFormatting(regions, rule2);
-        sheetCF.addConditionalFormatting(regions, rule3);
-        sheetCF.addConditionalFormatting(regions, rule4);
-    }
-
-    /**
-     *  Use Excel conditional formatting to check for errors,
-     *  and change the font colour to match the cell colour.
-     *  In this example, if formula result is  #DIV/0! then it will have white font colour.
-     */
-    static void errors(Sheet sheet) {
-        sheet.createRow(0).createCell(0).setCellValue(84);
-        sheet.createRow(1).createCell(0).setCellValue(0);
-        sheet.createRow(2).createCell(0).setCellFormula("ROUND(A1/A2,0)");
-        sheet.createRow(3).createCell(0).setCellValue(0);
-        sheet.createRow(4).createCell(0).setCellFormula("ROUND(A6/A4,0)");
-        sheet.createRow(5).createCell(0).setCellValue(41);
-
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        // Condition 1: Formula Is   =ISERROR(C2)   (White Font)
-        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("ISERROR(A1)");
-        FontFormatting font = rule1.createFontFormatting();
-        font.setFontColorIndex(IndexedColors.WHITE.index);
-
-        CellRangeAddress[] regions = {
-                CellRangeAddress.valueOf("A1:A6")
-        };
-
-        sheetCF.addConditionalFormatting(regions, rule1);
-
-        sheet.getRow(2).createCell(1).setCellValue("<== The error in this cell is hidden. Condition: Formula Is   =ISERROR(C2)   (White Font)");
-        sheet.getRow(4).createCell(1).setCellValue("<== The error in this cell is hidden. Condition: Formula Is   =ISERROR(C2)   (White Font)");
-    }
-
-    /**
-     * Use Excel conditional formatting to hide the duplicate values,
-     * and make the list easier to read. In this example, when the table is sorted by Region,
-     * the second (and subsequent) occurences of each region name will have white font colour.
-     */
-    static void hideDupplicates(Sheet sheet) {
-        sheet.createRow(0).createCell(0).setCellValue("City");
-        sheet.createRow(1).createCell(0).setCellValue("Boston");
-        sheet.createRow(2).createCell(0).setCellValue("Boston");
-        sheet.createRow(3).createCell(0).setCellValue("Chicago");
-        sheet.createRow(4).createCell(0).setCellValue("Chicago");
-        sheet.createRow(5).createCell(0).setCellValue("New York");
-
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        // Condition 1: Formula Is   =A2=A1   (White Font)
-        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("A2=A1");
-        FontFormatting font = rule1.createFontFormatting();
-        font.setFontColorIndex(IndexedColors.WHITE.index);
-
-        CellRangeAddress[] regions = {
-                CellRangeAddress.valueOf("A2:A6")
-        };
-
-        sheetCF.addConditionalFormatting(regions, rule1);
-
-        sheet.getRow(1).createCell(1).setCellValue("<== the second (and subsequent) " +
-                "occurences of each region name will have white font colour.  " +
-                "Condition: Formula Is   =A2=A1   (White Font)");
-    }
-
-    /**
-     * Use Excel conditional formatting to highlight duplicate entries in a column.
-     */
-    static void formatDuplicates(Sheet sheet) {
-        sheet.createRow(0).createCell(0).setCellValue("Code");
-        sheet.createRow(1).createCell(0).setCellValue(4);
-        sheet.createRow(2).createCell(0).setCellValue(3);
-        sheet.createRow(3).createCell(0).setCellValue(6);
-        sheet.createRow(4).createCell(0).setCellValue(3);
-        sheet.createRow(5).createCell(0).setCellValue(5);
-        sheet.createRow(6).createCell(0).setCellValue(8);
-        sheet.createRow(7).createCell(0).setCellValue(0);
-        sheet.createRow(8).createCell(0).setCellValue(2);
-        sheet.createRow(9).createCell(0).setCellValue(8);
-        sheet.createRow(10).createCell(0).setCellValue(6);
-
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        // Condition 1: Formula Is   =A2=A1   (White Font)
-        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("COUNTIF($A$2:$A$11,A2)>1");
-        FontFormatting font = rule1.createFontFormatting();
-        font.setFontStyle(false, true);
-        font.setFontColorIndex(IndexedColors.BLUE.index);
-
-        CellRangeAddress[] regions = {
-                CellRangeAddress.valueOf("A2:A11")
-        };
-
-        sheetCF.addConditionalFormatting(regions, rule1);
-
-        sheet.getRow(2).createCell(1).setCellValue("<== Duplicates numbers in the column are highlighted.  " +
-                "Condition: Formula Is =COUNTIF($A$2:$A$11,A2)>1   (Blue Font)");
-    }
-
-    /**
-     * Use Excel conditional formatting to highlight items that are in a list on the worksheet.
-     */
-    static void inList(Sheet sheet) {
-        sheet.createRow(0).createCell(0).setCellValue("Codes");
-        sheet.createRow(1).createCell(0).setCellValue("AA");
-        sheet.createRow(2).createCell(0).setCellValue("BB");
-        sheet.createRow(3).createCell(0).setCellValue("GG");
-        sheet.createRow(4).createCell(0).setCellValue("AA");
-        sheet.createRow(5).createCell(0).setCellValue("FF");
-        sheet.createRow(6).createCell(0).setCellValue("XX");
-        sheet.createRow(7).createCell(0).setCellValue("CC");
-
-        sheet.getRow(0).createCell(2).setCellValue("Valid");
-        sheet.getRow(1).createCell(2).setCellValue("AA");
-        sheet.getRow(2).createCell(2).setCellValue("BB");
-        sheet.getRow(3).createCell(2).setCellValue("CC");
-
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        // Condition 1: Formula Is   =A2=A1   (White Font)
-        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("COUNTIF($C$2:$C$4,A2)");
-        PatternFormatting fill1 = rule1.createPatternFormatting();
-        fill1.setFillBackgroundColor(IndexedColors.LIGHT_BLUE.index);
-        fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
-
-        CellRangeAddress[] regions = {
-                CellRangeAddress.valueOf("A2:A8")
-        };
-
-        sheetCF.addConditionalFormatting(regions, rule1);
-
-        sheet.getRow(2).createCell(3).setCellValue("<== Use Excel conditional formatting to highlight items that are in a list on the worksheet");
-    }
-
-    /**
-     *  Use Excel conditional formatting to highlight payments that are due in the next thirty days.
-     *  In this example, Due dates are entered in cells A2:A4.
-     */
-    static void expiry(Sheet sheet) {
-        CellStyle style = sheet.getWorkbook().createCellStyle();
-        style.setDataFormat((short)BuiltinFormats.getBuiltinFormat("d-mmm"));
-
-        sheet.createRow(0).createCell(0).setCellValue("Date");
-        sheet.createRow(1).createCell(0).setCellFormula("TODAY()+29");
-        sheet.createRow(2).createCell(0).setCellFormula("A2+1");
-        sheet.createRow(3).createCell(0).setCellFormula("A3+1");
-
-        for(int rownum = 1; rownum <= 3; rownum++) {
-            sheet.getRow(rownum).getCell(0).setCellStyle(style);
-        }
-
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        // Condition 1: Formula Is   =A2=A1   (White Font)
-        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("AND(A2-TODAY()>=0,A2-TODAY()<=30)");
-        FontFormatting font = rule1.createFontFormatting();
-        font.setFontStyle(false, true);
-        font.setFontColorIndex(IndexedColors.BLUE.index);
-
-        CellRangeAddress[] regions = {
-                CellRangeAddress.valueOf("A2:A4")
-        };
-
-        sheetCF.addConditionalFormatting(regions, rule1);
-
-        sheet.getRow(0).createCell(1).setCellValue("Dates within the next 30 days are highlighted");
-    }
-
-    /**
-     * Use Excel conditional formatting to shade alternating rows on the worksheet
-     */
-    static void shadeAlt(Sheet sheet) {
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        // Condition 1: Formula Is   =A2=A1   (White Font)
-        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("MOD(ROW(),2)");
-        PatternFormatting fill1 = rule1.createPatternFormatting();
-        fill1.setFillBackgroundColor(IndexedColors.LIGHT_GREEN.index);
-        fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
-
-        CellRangeAddress[] regions = {
-                CellRangeAddress.valueOf("A1:Z100")
-        };
-
-        sheetCF.addConditionalFormatting(regions, rule1);
-
-        sheet.createRow(0).createCell(1).setCellValue("Shade Alternating Rows");
-        sheet.createRow(1).createCell(1).setCellValue("Condition: Formula Is  =MOD(ROW(),2)   (Light Green Fill)");
-    }
-
-    /**
-     * You can use Excel conditional formatting to shade bands of rows on the worksheet.
-     * In this example, 3 rows are shaded light grey, and 3 are left with no shading.
-     * In the MOD function, the total number of rows in the set of banded rows (6) is entered.
-     */
-    static void shadeBands(Sheet sheet) {
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("MOD(ROW(),6)<3");
-        PatternFormatting fill1 = rule1.createPatternFormatting();
-        fill1.setFillBackgroundColor(IndexedColors.GREY_25_PERCENT.index);
-        fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
-
-        CellRangeAddress[] regions = {
-                CellRangeAddress.valueOf("A1:Z100")
-        };
-
-        sheetCF.addConditionalFormatting(regions, rule1);
-
-        sheet.createRow(0).createCell(1).setCellValue("Shade Bands of Rows");
-        sheet.createRow(1).createCell(1).setCellValue("Condition: Formula Is  =MOD(ROW(),6)<2   (Light Grey Fill)");
-    }
-
-    /**
-     * Icon Sets / Multi-States allow you to have icons shown which vary
-     *  based on the values, eg Red traffic light / Yellow traffic light /
-     *  Green traffic light
-     */
-    static void iconSets(Sheet sheet) {
-        sheet.createRow(0).createCell(0).setCellValue("Icon Sets");
-        Row r = sheet.createRow(1);
-        r.createCell(0).setCellValue("Reds");
-        r.createCell(1).setCellValue(0);
-        r.createCell(2).setCellValue(0);
-        r.createCell(3).setCellValue(0);
-        r = sheet.createRow(2);
-        r.createCell(0).setCellValue("Yellows");
-        r.createCell(1).setCellValue(5);
-        r.createCell(2).setCellValue(5);
-        r.createCell(3).setCellValue(5);
-        r = sheet.createRow(3);
-        r.createCell(0).setCellValue("Greens");
-        r.createCell(1).setCellValue(10);
-        r.createCell(2).setCellValue(10);
-        r.createCell(3).setCellValue(10);
-
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        CellRangeAddress[] regions = { CellRangeAddress.valueOf("B1:B4") };
-        ConditionalFormattingRule rule1 =
-                sheetCF.createConditionalFormattingRule(IconSet.GYR_3_TRAFFIC_LIGHTS);
-        IconMultiStateFormatting im1 = rule1.getMultiStateFormatting();
-        im1.getThresholds()[0].setRangeType(RangeType.MIN);
-        im1.getThresholds()[1].setRangeType(RangeType.PERCENT);
-        im1.getThresholds()[1].setValue(33d);
-        im1.getThresholds()[2].setRangeType(RangeType.MAX);
-        sheetCF.addConditionalFormatting(regions, rule1);
-
-        regions = new CellRangeAddress[] { CellRangeAddress.valueOf("C1:C4") };
-        ConditionalFormattingRule rule2 =
-                sheetCF.createConditionalFormattingRule(IconSet.GYR_3_FLAGS);
-        IconMultiStateFormatting im2 = rule1.getMultiStateFormatting();
-        im2.getThresholds()[0].setRangeType(RangeType.PERCENT);
-        im2.getThresholds()[0].setValue(0d);
-        im2.getThresholds()[1].setRangeType(RangeType.PERCENT);
-        im2.getThresholds()[1].setValue(33d);
-        im2.getThresholds()[2].setRangeType(RangeType.PERCENT);
-        im2.getThresholds()[2].setValue(67d);
-        sheetCF.addConditionalFormatting(regions, rule2);
-
-        regions = new CellRangeAddress[] { CellRangeAddress.valueOf("D1:D4") };
-        ConditionalFormattingRule rule3 =
-                sheetCF.createConditionalFormattingRule(IconSet.GYR_3_SYMBOLS_CIRCLE);
-        IconMultiStateFormatting im3 = rule1.getMultiStateFormatting();
-        im3.setIconOnly(true);
-        im3.getThresholds()[0].setRangeType(RangeType.MIN);
-        im3.getThresholds()[1].setRangeType(RangeType.NUMBER);
-        im3.getThresholds()[1].setValue(3d);
-        im3.getThresholds()[2].setRangeType(RangeType.NUMBER);
-        im3.getThresholds()[2].setValue(7d);
-        sheetCF.addConditionalFormatting(regions, rule3);
-    }
-
-    /**
-     * Color Scales / Colour Scales / Colour Gradients allow you shade the
-     *  background colour of the cell based on the values, eg from Red to
-     *  Yellow to Green.
-     */
-    static void colourScales(Sheet sheet) {
-        sheet.createRow(0).createCell(0).setCellValue("Colour Scales");
-        Row r = sheet.createRow(1);
-        r.createCell(0).setCellValue("Red-Yellow-Green");
-        for (int i=1; i<=7; i++) {
-            r.createCell(i).setCellValue((i-1)*5.0);
-        }
-        r = sheet.createRow(2);
-        r.createCell(0).setCellValue("Red-White-Blue");
-        for (int i=1; i<=9; i++) {
-            r.createCell(i).setCellValue((i-1)*5.0);
-        }
-        r = sheet.createRow(3);
-        r.createCell(0).setCellValue("Blue-Green");
-        for (int i=1; i<=16; i++) {
-            r.createCell(i).setCellValue((i-1));
-        }
-        sheet.setColumnWidth(0, 5000);
-
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        CellRangeAddress[] regions = { CellRangeAddress.valueOf("B2:H2") };
-        ConditionalFormattingRule rule1 =
-                sheetCF.createConditionalFormattingColorScaleRule();
-        ColorScaleFormatting cs1 = rule1.getColorScaleFormatting();
-        cs1.getThresholds()[0].setRangeType(RangeType.MIN);
-        cs1.getThresholds()[1].setRangeType(RangeType.PERCENTILE);
-        cs1.getThresholds()[1].setValue(50d);
-        cs1.getThresholds()[2].setRangeType(RangeType.MAX);
-        ((ExtendedColor)cs1.getColors()[0]).setARGBHex("FFF8696B");
-        ((ExtendedColor)cs1.getColors()[1]).setARGBHex("FFFFEB84");
-        ((ExtendedColor)cs1.getColors()[2]).setARGBHex("FF63BE7B");
-        sheetCF.addConditionalFormatting(regions, rule1);
-
-        regions = new CellRangeAddress[] { CellRangeAddress.valueOf("B3:J3") };
-        ConditionalFormattingRule rule2 =
-                sheetCF.createConditionalFormattingColorScaleRule();
-        ColorScaleFormatting cs2 = rule2.getColorScaleFormatting();
-        cs2.getThresholds()[0].setRangeType(RangeType.MIN);
-        cs2.getThresholds()[1].setRangeType(RangeType.PERCENTILE);
-        cs2.getThresholds()[1].setValue(50d);
-        cs2.getThresholds()[2].setRangeType(RangeType.MAX);
-        ((ExtendedColor)cs2.getColors()[0]).setARGBHex("FFF8696B");
-        ((ExtendedColor)cs2.getColors()[1]).setARGBHex("FFFCFCFF");
-        ((ExtendedColor)cs2.getColors()[2]).setARGBHex("FF5A8AC6");
-        sheetCF.addConditionalFormatting(regions, rule2);
-
-        regions = new CellRangeAddress[] { CellRangeAddress.valueOf("B4:Q4") };
-        ConditionalFormattingRule rule3=
-                sheetCF.createConditionalFormattingColorScaleRule();
-        ColorScaleFormatting cs3 = rule3.getColorScaleFormatting();
-        cs3.setNumControlPoints(2);
-        cs3.getThresholds()[0].setRangeType(RangeType.MIN);
-        cs3.getThresholds()[1].setRangeType(RangeType.MAX);
-        ((ExtendedColor)cs3.getColors()[0]).setARGBHex("FF5A8AC6");
-        ((ExtendedColor)cs3.getColors()[1]).setARGBHex("FF63BE7B");
-        sheetCF.addConditionalFormatting(regions, rule3);
-    }
-
-    /**
-     * DataBars / Data-Bars allow you to have bars shown vary
-     *  based on the values, from full to empty
-     */
-    static void dataBars(Sheet sheet) {
-        sheet.createRow(0).createCell(0).setCellValue("Data Bars");
-        Row r = sheet.createRow(1);
-        r.createCell(1).setCellValue("Green Positive");
-        r.createCell(2).setCellValue("Blue Mix");
-        r.createCell(3).setCellValue("Red Negative");
-        r = sheet.createRow(2);
-        r.createCell(1).setCellValue(0);
-        r.createCell(2).setCellValue(0);
-        r.createCell(3).setCellValue(0);
-        r = sheet.createRow(3);
-        r.createCell(1).setCellValue(5);
-        r.createCell(2).setCellValue(-5);
-        r.createCell(3).setCellValue(-5);
-        r = sheet.createRow(4);
-        r.createCell(1).setCellValue(10);
-        r.createCell(2).setCellValue(10);
-        r.createCell(3).setCellValue(-10);
-        r = sheet.createRow(5);
-        r.createCell(1).setCellValue(5);
-        r.createCell(2).setCellValue(5);
-        r.createCell(3).setCellValue(-5);
-        r = sheet.createRow(6);
-        r.createCell(1).setCellValue(20);
-        r.createCell(2).setCellValue(-10);
-        r.createCell(3).setCellValue(-20);
-        sheet.setColumnWidth(0, 3000);
-        sheet.setColumnWidth(1, 5000);
-        sheet.setColumnWidth(2, 5000);
-        sheet.setColumnWidth(3, 5000);
-
-        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
-
-        ExtendedColor color = sheet.getWorkbook().getCreationHelper().createExtendedColor();
-        color.setARGBHex("FF63BE7B");
-        CellRangeAddress[] regions = { CellRangeAddress.valueOf("B2:B7") };
-        ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule(color);
-        DataBarFormatting db1 = rule1.getDataBarFormatting();
-        db1.getMinThreshold().setRangeType(RangeType.MIN);
-        db1.getMaxThreshold().setRangeType(RangeType.MAX);
-        sheetCF.addConditionalFormatting(regions, rule1);
-
-        color = sheet.getWorkbook().getCreationHelper().createExtendedColor();
-        color.setARGBHex("FF5A8AC6");
-        regions = new CellRangeAddress[] { CellRangeAddress.valueOf("C2:C7") };
-        ConditionalFormattingRule rule2 = sheetCF.createConditionalFormattingRule(color);
-        DataBarFormatting db2 = rule2.getDataBarFormatting();
-        db2.getMinThreshold().setRangeType(RangeType.MIN);
-        db2.getMaxThreshold().setRangeType(RangeType.MAX);
-        sheetCF.addConditionalFormatting(regions, rule2);
-
-        color = sheet.getWorkbook().getCreationHelper().createExtendedColor();
-        color.setARGBHex("FFF8696B");
-        regions = new CellRangeAddress[] { CellRangeAddress.valueOf("D2:D7") };
-        ConditionalFormattingRule rule3 = sheetCF.createConditionalFormattingRule(color);
-        DataBarFormatting db3 = rule3.getDataBarFormatting();
-        db3.getMinThreshold().setRangeType(RangeType.MIN);
-        db3.getMaxThreshold().setRangeType(RangeType.MAX);
-        sheetCF.addConditionalFormatting(regions, rule3);
-    }
-
-    /**
-     * Print out a summary of the conditional formatting rules applied to cells on the given sheet.
-     * Only cells with a matching rule are printed, and for those, all matching rules are sumarized.
-     */
-    static void evaluateRules(Workbook wb, String sheetName) {
-        final WorkbookEvaluatorProvider wbEvalProv = (WorkbookEvaluatorProvider) wb.getCreationHelper().createFormulaEvaluator();
-        final ConditionalFormattingEvaluator cfEval = new ConditionalFormattingEvaluator(wb, wbEvalProv);
-        // if cell values have changed, clear cached format results
-        cfEval.clearAllCachedValues();
-
-        final Sheet sheet = wb.getSheet(sheetName);
-        for (Row r : sheet) {
-            for (Cell c : r) {
-                final List<EvaluationConditionalFormatRule> rules = cfEval.getConditionalFormattingForCell(c);
-                // check rules list for null, although current implementation will return an empty list, not null, then do what you want with results
-                if (rules == null || rules.isEmpty()) {
-                    continue;
-                }
-                final CellReference ref = ConditionalFormattingEvaluator.getRef(c);
-                if (rules.isEmpty()) {
-                    continue;
-                }
-
-                System.out.println("\n"
-                  + ref.formatAsString()
-                  + " has conditional formatting.");
-
-                for (EvaluationConditionalFormatRule rule : rules) {
-                    ConditionalFormattingRule cf = rule.getRule();
-
-                    StringBuilder b = new StringBuilder();
-                    b.append("\tRule ")
-                     .append(rule.getFormattingIndex())
-                     .append(": ");
-
-                    // check for color scale
-                    if (cf.getColorScaleFormatting() != null) {
-                        b.append("\n\t\tcolor scale (caller must calculate bucket)");
-                    }
-                    // check for data bar
-                    if (cf.getDataBarFormatting() != null) {
-                        b.append("\n\t\tdata bar (caller must calculate bucket)");
-                    }
-                    // check for icon set
-                    if (cf.getMultiStateFormatting() != null) {
-                        b.append("\n\t\ticon set (caller must calculate icon bucket)");
-                    }
-                    // check for fill
-                    if (cf.getPatternFormatting() != null) {
-                        final PatternFormatting fill = cf.getPatternFormatting();
-                        b.append("\n\t\tfill pattern ")
-                         .append(fill.getFillPattern())
-                         .append(" color index ")
-                         .append(fill.getFillBackgroundColor());
-                    }
-                    // font stuff
-                    if (cf.getFontFormatting() != null) {
-                        final FontFormatting ff = cf.getFontFormatting();
-                        b.append("\n\t\tfont format ")
-                         .append("color index ")
-                         .append(ff.getFontColorIndex());
-                        if (ff.isBold()) {
-                            b.append(" bold");
-                        }
-                        if (ff.isItalic()) {
-                            b.append(" italic");
-                        }
-                        if (ff.isStruckout()) {
-                            b.append(" strikeout");
-                        }
-                        b.append(" underline index ")
-                         .append(ff.getUnderlineType());
-                    }
-
-                    System.out.println(b);
-                }
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/DrawingBorders.java b/src/examples/src/org/apache/poi/ss/examples/DrawingBorders.java
deleted file mode 100644 (file)
index 8a4ad94..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.ss.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.BorderExtent;
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.IndexedColors;
-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.util.CellRangeAddress;
-import org.apache.poi.ss.util.PropertyTemplate;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Excel Border Drawing - examples
- *
- * <p>
- * Partly based on the code snippets from
- * org.apache.poi.ss.examples.ConditionalFormats
- * </p>
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public final class DrawingBorders {
-
-    private DrawingBorders() {}
-
-    public static void main(String[] args) throws IOException {
-        try (Workbook wb = (args.length > 0 && args[0].equals("-xls"))
-            ? new HSSFWorkbook() : new XSSFWorkbook()) {
-            // add a sheet, and put some values into it
-            Sheet sh1 = wb.createSheet("Sheet1");
-            Row r = sh1.createRow(0);
-            Cell c = r.createCell(1);
-            c.setCellValue("All Borders Medium Width");
-            r = sh1.createRow(4);
-            c = r.createCell(1);
-            c.setCellValue("Medium Outside / Thin Inside Borders");
-            r = sh1.createRow(8);
-            c = r.createCell(1);
-            c.setCellValue("Colored Borders");
-
-            // draw borders (three 3x3 grids)
-            PropertyTemplate pt = new PropertyTemplate();
-            // #1) these borders will all be medium in default color
-            pt.drawBorders(new CellRangeAddress(1, 3, 1, 3),
-                    BorderStyle.MEDIUM, BorderExtent.ALL);
-            // #2) these cells will have medium outside borders and thin inside borders
-            pt.drawBorders(new CellRangeAddress(5, 7, 1, 3),
-                    BorderStyle.MEDIUM, BorderExtent.OUTSIDE);
-            pt.drawBorders(new CellRangeAddress(5, 7, 1, 3), BorderStyle.THIN,
-                    BorderExtent.INSIDE);
-            // #3) these cells will all be medium weight with different colors for the
-            //     outside, inside horizontal, and inside vertical borders. The center
-            //     cell will have no borders.
-            pt.drawBorders(new CellRangeAddress(9, 11, 1, 3),
-                    BorderStyle.MEDIUM, IndexedColors.RED.getIndex(),
-                    BorderExtent.OUTSIDE);
-            pt.drawBorders(new CellRangeAddress(9, 11, 1, 3),
-                    BorderStyle.MEDIUM, IndexedColors.BLUE.getIndex(),
-                    BorderExtent.INSIDE_VERTICAL);
-            pt.drawBorders(new CellRangeAddress(9, 11, 1, 3),
-                    BorderStyle.MEDIUM, IndexedColors.GREEN.getIndex(),
-                    BorderExtent.INSIDE_HORIZONTAL);
-            pt.drawBorders(new CellRangeAddress(10, 10, 2, 2),
-                    BorderStyle.NONE,
-                    BorderExtent.ALL);
-
-            // apply borders to sheet
-            pt.applyBorders(sh1);
-
-            // add another sheet and apply the borders to it
-            Sheet sh2 = wb.createSheet("Sheet2");
-            pt.applyBorders(sh2);
-
-            // Write the output to a file
-            String file = "db-poi.xls" + (wb instanceof XSSFWorkbook ? "x" : "");
-            try (FileOutputStream out = new FileOutputStream(file)) {
-                wb.write(out);
-            }
-            System.out.println("Generated: " + file);
-        }
-    }
-
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/ExcelComparator.java b/src/examples/src/org/apache/poi/ss/examples/ExcelComparator.java
deleted file mode 100644 (file)
index f2cd249..0000000
+++ /dev/null
@@ -1,685 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.examples;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.Color;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-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.WorkbookFactory;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xssf.usermodel.XSSFCell;
-import org.apache.poi.xssf.usermodel.XSSFCellStyle;
-import org.apache.poi.xssf.usermodel.XSSFColor;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-
-/**
- * Utility to compare Excel File Contents cell by cell for all sheets.
- *
- * <p>This utility will be used to compare Excel File Contents cell by cell for all sheets programmatically.</p>
- *
- * <p>Below are the list of Attribute comparison supported in this version.</p>
- *
- * <ul>
- * <li>Cell Alignment</li>
- * <li>Cell Border Attributes</li>
- * <li>Cell Data</li>
- * <li>Cell Data-Type</li>
- * <li>Cell Fill Color</li>
- * <li>Cell Fill pattern</li>
- * <li>Cell Font Attributes</li>
- * <li>Cell Font Family</li>
- * <li>Cell Font Size</li>
- * <li>Cell Protection</li>
- * <li>Name of the sheets</li>
- * <li>Number of Columns</li>
- * <li>Number of Rows</li>
- * <li>Number of Sheet</li>
- * </ul>
- *
- * <p>(Some of the above attribute comparison only work for *.xlsx format currently. In future it can be enhanced.)</p>
- *
- * <p><b>Usage:</b></p>
- *
- * <pre>
- * {@code
- *  Workbook wb1 = WorkbookFactory.create(new File("workBook1.xls"));
- *  Workbook wb2 = WorkbookFactory.create(new File("workBook2.xls"));
- *  List<String> listOfDifferences = ExcelComparator.compare(wb1, wb2);
- *  for (String differences : listOfDifferences)
- *      System.out.println(differences);
- *  System.out.println("DifferenceFound = "+ excelFileDifference.isDifferenceFound);
- *  }
- * </pre>
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public class ExcelComparator {
-
-    private static final String CELL_DATA_DOES_NOT_MATCH = "Cell Data does not Match ::";
-    private static final String CELL_FONT_ATTRIBUTES_DOES_NOT_MATCH = "Cell Font Attributes does not Match ::";
-
-    private static class Locator {
-        Workbook workbook;
-        Sheet sheet;
-        Row row;
-        Cell cell;
-    }
-
-    List<String> listOfDifferences = new ArrayList<>();
-
-    public static void main(String[] args) throws Exception {
-        if (args.length != 2 || !(new File(args[0]).exists()) || !(new File(args[1]).exists())) {
-            System.err.println("java -cp <classpath> "+ExcelComparator.class.getCanonicalName()+" <workbook1.xls/x> <workbook2.xls/x");
-            System.exit(-1);
-        }
-
-        try (Workbook wb1 = WorkbookFactory.create(new File(args[0]), null, true)) {
-            try (Workbook wb2 = WorkbookFactory.create(new File(args[1]), null, true)) {
-                for (String d : ExcelComparator.compare(wb1, wb2)) {
-                    System.out.println(d);
-                }
-            }
-        }
-    }
-
-    /**
-     * Utility to compare Excel File Contents cell by cell for all sheets.
-     *
-     * @param wb1 the workbook1
-     * @param wb2 the workbook2
-     * @return the Excel file difference containing a flag and a list of differences
-     */
-    public static List<String> compare(Workbook wb1, Workbook wb2) {
-        Locator loc1 = new Locator();
-        Locator loc2 = new Locator();
-        loc1.workbook = wb1;
-        loc2.workbook = wb2;
-
-        ExcelComparator excelComparator = new ExcelComparator();
-        excelComparator.compareNumberOfSheets(loc1, loc2 );
-        excelComparator.compareSheetNames(loc1, loc2);
-        excelComparator.compareSheetData(loc1, loc2);
-
-        return excelComparator.listOfDifferences;
-    }
-
-    /**
-     * Compare data in all sheets.
-     */
-    private void compareDataInAllSheets(Locator loc1, Locator loc2) {
-        for (int i = 0; i < loc1.workbook.getNumberOfSheets(); i++) {
-            if (loc2.workbook.getNumberOfSheets() <= i) {
-                return;
-            }
-
-            loc1.sheet = loc1.workbook.getSheetAt(i);
-            loc2.sheet = loc2.workbook.getSheetAt(i);
-
-            compareDataInSheet(loc1, loc2);
-        }
-    }
-
-    private void compareDataInSheet(Locator loc1, Locator loc2) {
-        for (int j = 0; j <= loc1.sheet.getLastRowNum(); j++) {
-            if (loc2.sheet.getLastRowNum() <= j) {
-                return;
-            }
-
-            loc1.row = loc1.sheet.getRow(j);
-            loc2.row = loc2.sheet.getRow(j);
-
-            if ((loc1.row == null) || (loc2.row == null)) {
-                continue;
-            }
-
-            compareDataInRow(loc1, loc2);
-        }
-    }
-
-    private void compareDataInRow(Locator loc1, Locator loc2) {
-        for (int k = 0; k <= loc1.row.getLastCellNum(); k++) {
-            if (loc2.row.getLastCellNum() <= k) {
-                return;
-            }
-
-            loc1.cell = loc1.row.getCell(k);
-            loc2.cell = loc2.row.getCell(k);
-
-            if ((loc1.cell == null) || (loc2.cell == null)) {
-                continue;
-            }
-
-            compareDataInCell(loc1, loc2);
-        }
-    }
-
-    private void compareDataInCell(Locator loc1, Locator loc2) {
-        if (isCellTypeMatches(loc1, loc2)) {
-            final CellType loc1cellType = loc1.cell.getCellType();
-            switch(loc1cellType) {
-                case BLANK:
-                case STRING:
-                case ERROR:
-                    isCellContentMatches(loc1,loc2);
-                    break;
-                case BOOLEAN:
-                    isCellContentMatchesForBoolean(loc1,loc2);
-                    break;
-                case FORMULA:
-                    isCellContentMatchesForFormula(loc1,loc2);
-                    break;
-                case NUMERIC:
-                    if (DateUtil.isCellDateFormatted(loc1.cell)) {
-                        isCellContentMatchesForDate(loc1,loc2);
-                    } else {
-                        isCellContentMatchesForNumeric(loc1,loc2);
-                    }
-                    break;
-                default:
-                    throw new IllegalStateException("Unexpected cell type: " + loc1cellType);
-            }
-        }
-
-        isCellFillPatternMatches(loc1,loc2);
-        isCellAlignmentMatches(loc1,loc2);
-        isCellHiddenMatches(loc1,loc2);
-        isCellLockedMatches(loc1,loc2);
-        isCellFontFamilyMatches(loc1,loc2);
-        isCellFontSizeMatches(loc1,loc2);
-        isCellFontBoldMatches(loc1,loc2);
-        isCellUnderLineMatches(loc1,loc2);
-        isCellFontItalicsMatches(loc1,loc2);
-        isCellBorderMatches(loc1,loc2,'t');
-        isCellBorderMatches(loc1,loc2,'l');
-        isCellBorderMatches(loc1,loc2,'b');
-        isCellBorderMatches(loc1,loc2,'r');
-        isCellFillBackGroundMatches(loc1,loc2);
-    }
-
-    /**
-     * Compare number of columns in sheets.
-     */
-    private void compareNumberOfColumnsInSheets(Locator loc1, Locator loc2) {
-        for (int i = 0; i < loc1.workbook.getNumberOfSheets(); i++) {
-            if (loc2.workbook.getNumberOfSheets() <= i) {
-                return;
-            }
-
-            loc1.sheet = loc1.workbook.getSheetAt(i);
-            loc2.sheet = loc2.workbook.getSheetAt(i);
-
-            Iterator<Row> ri1 = loc1.sheet.rowIterator();
-            Iterator<Row> ri2 = loc2.sheet.rowIterator();
-
-            int num1 = (ri1.hasNext()) ? ri1.next().getPhysicalNumberOfCells() : 0;
-            int num2 = (ri2.hasNext()) ? ri2.next().getPhysicalNumberOfCells() : 0;
-
-            if (num1 != num2) {
-                String str = String.format(Locale.ROOT, "%s\nworkbook1 -> %s [%d] != workbook2 -> %s [%d]",
-                    "Number Of Columns does not Match ::",
-                    loc1.sheet.getSheetName(), num1,
-                    loc2.sheet.getSheetName(), num2
-                );
-                listOfDifferences.add(str);
-            }
-        }
-    }
-
-    /**
-     * Compare number of rows in sheets.
-     */
-    private void compareNumberOfRowsInSheets(Locator loc1, Locator loc2) {
-        for (int i = 0; i < loc1.workbook.getNumberOfSheets(); i++) {
-            if (loc2.workbook.getNumberOfSheets() <= i) {
-                return;
-            }
-
-            loc1.sheet = loc1.workbook.getSheetAt(i);
-            loc2.sheet = loc2.workbook.getSheetAt(i);
-
-            int num1 = loc1.sheet.getPhysicalNumberOfRows();
-            int num2 = loc2.sheet.getPhysicalNumberOfRows();
-
-            if (num1 != num2) {
-                String str = String.format(Locale.ROOT, "%s\nworkbook1 -> %s [%d] != workbook2 -> %s [%d]",
-                    "Number Of Rows does not Match ::",
-                    loc1.sheet.getSheetName(), num1,
-                    loc2.sheet.getSheetName(), num2
-                );
-                listOfDifferences.add(str);
-            }
-        }
-
-    }
-
-    /**
-     * Compare number of sheets.
-     */
-    private void compareNumberOfSheets(Locator loc1, Locator loc2) {
-        int num1 = loc1.workbook.getNumberOfSheets();
-        int num2 = loc2.workbook.getNumberOfSheets();
-        if (num1 != num2) {
-            String str = String.format(Locale.ROOT, "%s\nworkbook1 [%d] != workbook2 [%d]",
-                "Number of Sheets do not match ::",
-                num1, num2
-            );
-
-            listOfDifferences.add(str);
-
-        }
-    }
-
-    /**
-     * Compare sheet data.
-     */
-    private void compareSheetData(Locator loc1, Locator loc2) {
-        compareNumberOfRowsInSheets(loc1, loc2);
-        compareNumberOfColumnsInSheets(loc1, loc2);
-        compareDataInAllSheets(loc1, loc2);
-
-    }
-
-    /**
-     * Compare sheet names.
-     */
-    private void compareSheetNames(Locator loc1, Locator loc2) {
-        for (int i = 0; i < loc1.workbook.getNumberOfSheets(); i++) {
-            String name1 = loc1.workbook.getSheetName(i);
-            String name2 = (loc2.workbook.getNumberOfSheets() > i) ? loc2.workbook.getSheetName(i) : "";
-
-            if (!name1.equals(name2)) {
-                String str = String.format(Locale.ROOT, "%s\nworkbook1 -> %s [%d] != workbook2 -> %s [%d]",
-                    "Name of the sheets do not match ::", name1, i+1, name2, i+1
-                );
-                listOfDifferences.add(str);
-            }
-        }
-    }
-
-    /**
-     * Formats the message.
-     */
-    private void addMessage(Locator loc1, Locator loc2, String messageStart, String value1, String value2) {
-        String str =
-            String.format(Locale.ROOT, "%s\nworkbook1 -> %s -> %s [%s] != workbook2 -> %s -> %s [%s]",
-                messageStart,
-                loc1.sheet.getSheetName(), new CellReference(loc1.cell).formatAsString(), value1,
-                loc2.sheet.getSheetName(), new CellReference(loc2.cell).formatAsString(), value2
-            );
-        listOfDifferences.add(str);
-    }
-
-    /**
-     * Checks if cell alignment matches.
-     */
-    private void isCellAlignmentMatches(Locator loc1, Locator loc2) {
-        if(loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
-            return;
-        }
-
-        HorizontalAlignment align1 = loc1.cell.getCellStyle().getAlignment();
-        HorizontalAlignment align2 = loc2.cell.getCellStyle().getAlignment();
-        if (align1 != align2) {
-            addMessage(loc1, loc2,
-                "Cell Alignment does not Match ::",
-                align1.name(),
-                align2.name()
-            );
-        }
-    }
-
-    /**
-     * Checks if cell border bottom matches.
-     */
-    private void isCellBorderMatches(Locator loc1, Locator loc2, char borderSide) {
-        if (!(loc1.cell instanceof XSSFCell) ||
-                loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
-            return;
-        }
-
-        XSSFCellStyle style1 = ((XSSFCell)loc1.cell).getCellStyle();
-        XSSFCellStyle style2 = ((XSSFCell)loc2.cell).getCellStyle();
-        boolean b1, b2;
-        String borderName;
-        switch (borderSide) {
-            case 't': default:
-                b1 = style1.getBorderTop() == BorderStyle.THIN;
-                b2 = style2.getBorderTop() == BorderStyle.THIN;
-                borderName = "TOP";
-                break;
-            case 'b':
-                b1 = style1.getBorderBottom() == BorderStyle.THIN;
-                b2 = style2.getBorderBottom() == BorderStyle.THIN;
-                borderName = "BOTTOM";
-                break;
-            case 'l':
-                b1 = style1.getBorderLeft() == BorderStyle.THIN;
-                b2 = style2.getBorderLeft() == BorderStyle.THIN;
-                borderName = "LEFT";
-                break;
-            case 'r':
-                b1 = style1.getBorderRight() == BorderStyle.THIN;
-                b2 = style2.getBorderRight() == BorderStyle.THIN;
-                borderName = "RIGHT";
-                break;
-        }
-        if (b1 != b2) {
-            addMessage(loc1, loc2,
-                "Cell Border Attributes does not Match ::",
-                (b1 ? "" : "NOT ")+borderName+" BORDER",
-                (b2 ? "" : "NOT ")+borderName+" BORDER"
-            );
-        }
-    }
-
-    /**
-     * Checks if cell content matches.
-     */
-    private void isCellContentMatches(Locator loc1, Locator loc2) {
-        String str1 = loc1.cell.toString();
-        String str2 = loc2.cell.toString();
-        if (!str1.equals(str2)) {
-            addMessage(loc1,loc2,CELL_DATA_DOES_NOT_MATCH,str1,str2);
-        }
-    }
-
-    /**
-     * Checks if cell content matches for boolean.
-     */
-    private void isCellContentMatchesForBoolean(Locator loc1, Locator loc2) {
-        boolean b1 = loc1.cell.getBooleanCellValue();
-        boolean b2 = loc2.cell.getBooleanCellValue();
-        if (b1 != b2) {
-            addMessage(loc1,loc2,CELL_DATA_DOES_NOT_MATCH,Boolean.toString(b1),Boolean.toString(b2));
-        }
-    }
-
-    /**
-     * Checks if cell content matches for date.
-     */
-    private void isCellContentMatchesForDate(Locator loc1, Locator loc2) {
-        Date date1 = loc1.cell.getDateCellValue();
-        Date date2 = loc2.cell.getDateCellValue();
-        if (!date1.equals(date2)) {
-            addMessage(loc1, loc2, CELL_DATA_DOES_NOT_MATCH, date1.toString(), date2.toString());
-        }
-    }
-
-
-    /**
-     * Checks if cell content matches for formula.
-     */
-    private void isCellContentMatchesForFormula(Locator loc1, Locator loc2) {
-        // TODO: actually evaluate the formula / NPE checks
-        String form1 = loc1.cell.getCellFormula();
-        String form2 = loc2.cell.getCellFormula();
-        if (!form1.equals(form2)) {
-            addMessage(loc1, loc2, CELL_DATA_DOES_NOT_MATCH, form1, form2);
-        }
-    }
-
-    /**
-     * Checks if cell content matches for numeric.
-     */
-    private void isCellContentMatchesForNumeric(Locator loc1, Locator loc2) {
-        // TODO: Check for NaN
-        double num1 = loc1.cell.getNumericCellValue();
-        double num2 = loc2.cell.getNumericCellValue();
-        if (num1 != num2) {
-            addMessage(loc1, loc2, CELL_DATA_DOES_NOT_MATCH, Double.toString(num1), Double.toString(num2));
-        }
-    }
-
-    private String getCellFillBackground(Locator loc) {
-        Color col = loc.cell.getCellStyle().getFillForegroundColorColor();
-        return (col instanceof XSSFColor) ? ((XSSFColor)col).getARGBHex() : "NO COLOR";
-    }
-
-    /**
-     * Checks if cell file back ground matches.
-     */
-    private void isCellFillBackGroundMatches(Locator loc1, Locator loc2) {
-        if(loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
-            return;
-        }
-
-        String col1 = getCellFillBackground(loc1);
-        String col2 = getCellFillBackground(loc2);
-        if (!col1.equals(col2)) {
-            addMessage(loc1, loc2, "Cell Fill Color does not Match ::", col1, col2);
-        }
-    }
-    /**
-     * Checks if cell fill pattern matches.
-     */
-    private void isCellFillPatternMatches(Locator loc1, Locator loc2) {
-        if(loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
-            return;
-        }
-
-        FillPatternType fill1 = loc1.cell.getCellStyle().getFillPattern();
-        FillPatternType fill2 = loc2.cell.getCellStyle().getFillPattern();
-        if (fill1 != fill2) {
-            addMessage(loc1, loc2,
-                "Cell Fill pattern does not Match ::",
-                fill1.name(),
-                fill2.name()
-            );
-        }
-    }
-
-    /**
-     * Checks if cell font bold matches.
-     */
-    private void isCellFontBoldMatches(Locator loc1, Locator loc2) {
-        if (!(loc1.cell instanceof XSSFCell) ||
-                loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
-            return;
-        }
-
-        if(hasInvalidFontIndex(loc1, loc2)) {
-            return;
-        }
-
-        boolean b1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getBold();
-        boolean b2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getBold();
-        if (b1 != b2) {
-            addMessage(loc1, loc2,
-                CELL_FONT_ATTRIBUTES_DOES_NOT_MATCH,
-                (b1 ? "" : "NOT ")+"BOLD",
-                (b2 ? "" : "NOT ")+"BOLD"
-            );
-        }
-    }
-
-    /**
-     * Checks if cell font family matches.
-     */
-    private void isCellFontFamilyMatches(Locator loc1, Locator loc2) {
-        if (!(loc1.cell instanceof XSSFCell) ||
-                loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
-            return;
-        }
-
-        if(hasInvalidFontIndex(loc1, loc2)) {
-            return;
-        }
-
-        String family1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getFontName();
-        String family2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getFontName();
-        if (!family1.equals(family2)) {
-            addMessage(loc1, loc2, "Cell Font Family does not Match ::", family1, family2);
-        }
-    }
-
-    private boolean hasInvalidFontIndex(Locator loc1, Locator loc2) {
-        int fontIdx1 = loc1.cell.getCellStyle().getFontIndexAsInt();
-        int fontCount1 = ((XSSFWorkbook)loc1.workbook).getStylesSource().getFonts().size();
-        int fontIdx2 = loc2.cell.getCellStyle().getFontIndexAsInt();
-        int fontCount2 = ((XSSFWorkbook)loc2.workbook).getStylesSource().getFonts().size();
-
-        if(fontIdx1 >= fontCount1 || fontIdx2 >= fontCount2) {
-            addMessage(loc1, loc2, "Corrupted file, cell style references a font which is not defined", Integer.toString(fontIdx1), Integer.toString(fontIdx2));
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Checks if cell font italics matches.
-     */
-    private void isCellFontItalicsMatches(Locator loc1, Locator loc2) {
-        if (!(loc1.cell instanceof XSSFCell) ||
-                loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
-            return;
-        }
-
-        if(hasInvalidFontIndex(loc1, loc2)) {
-            return;
-        }
-
-        boolean b1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getItalic();
-        boolean b2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getItalic();
-        if (b1 != b2) {
-            addMessage(loc1, loc2,
-                CELL_FONT_ATTRIBUTES_DOES_NOT_MATCH,
-                (b1 ? "" : "NOT ")+"ITALICS",
-                (b2 ? "" : "NOT ")+"ITALICS"
-            );
-        }
-    }
-
-    /**
-     * Checks if cell font size matches.
-     */
-    private void isCellFontSizeMatches(Locator loc1, Locator loc2) {
-        if (!(loc1.cell instanceof XSSFCell) ||
-                loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
-            return;
-        }
-
-        if(hasInvalidFontIndex(loc1, loc2)) {
-            return;
-        }
-
-        short size1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getFontHeightInPoints();
-        short size2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getFontHeightInPoints();
-        if (size1 != size2) {
-            addMessage(loc1, loc2,
-                "Cell Font Size does not Match ::",
-                Short.toString(size1),
-                Short.toString(size2)
-            );
-        }
-    }
-
-    /**
-     * Checks if cell hidden matches.
-     */
-    private void isCellHiddenMatches(Locator loc1, Locator loc2) {
-        if (loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
-            return;
-        }
-
-        boolean b1 = loc1.cell.getCellStyle().getHidden();
-        boolean b2 = loc1.cell.getCellStyle().getHidden();
-        if (b1 != b2) {
-            addMessage(loc1, loc2,
-                "Cell Visibility does not Match ::",
-                (b1 ? "" : "NOT ")+"HIDDEN",
-                (b2 ? "" : "NOT ")+"HIDDEN"
-            );
-        }
-    }
-
-    /**
-     * Checks if cell locked matches.
-     */
-    private void isCellLockedMatches(Locator loc1, Locator loc2) {
-        if (loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
-            return;
-        }
-
-        boolean b1 = loc1.cell.getCellStyle().getLocked();
-        boolean b2 = loc1.cell.getCellStyle().getLocked();
-        if (b1 != b2) {
-            addMessage(loc1, loc2,
-                    "Cell Protection does not Match ::",
-                (b1 ? "" : "NOT ")+"LOCKED",
-                (b2 ? "" : "NOT ")+"LOCKED"
-            );
-        }
-    }
-
-    /**
-     * Checks if cell type matches.
-     */
-    private boolean isCellTypeMatches(Locator loc1, Locator loc2) {
-        CellType type1 = loc1.cell.getCellType();
-        CellType type2 = loc2.cell.getCellType();
-        if (type1 == type2) {
-            return true;
-        }
-
-        addMessage(loc1, loc2,
-            "Cell Data-Type does not Match in :: ",
-            type1.name(), type2.name()
-        );
-        return false;
-    }
-
-    /**
-     * Checks if cell under line matches.
-     */
-    private void isCellUnderLineMatches(Locator loc1, Locator loc2) {
-        // TODO: distinguish underline type
-
-        if (!(loc1.cell instanceof XSSFCell) ||
-                loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
-            return;
-        }
-
-        if(hasInvalidFontIndex(loc1, loc2)) {
-            return;
-        }
-
-        byte b1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getUnderline();
-        byte b2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getUnderline();
-        if (b1 != b2) {
-            addMessage(loc1, loc2,
-                CELL_FONT_ATTRIBUTES_DOES_NOT_MATCH,
-                (b1 == 1 ? "" : "NOT ")+"UNDERLINE",
-                (b2 == 1 ? "" : "NOT ")+"UNDERLINE"
-            );
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/ss/examples/LinkedDropDownLists.java b/src/examples/src/org/apache/poi/ss/examples/LinkedDropDownLists.java
deleted file mode 100644 (file)
index c98c87a..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-   /* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-   ==================================================================== */
-
-package org.apache.poi.ss.examples;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.DataValidation;
-import org.apache.poi.ss.usermodel.DataValidationConstraint;
-import org.apache.poi.ss.usermodel.DataValidationHelper;
-import org.apache.poi.ss.usermodel.Name;
-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.util.CellRangeAddressList;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Demonstrates one technique that may be used to create linked or dependent
- * drop down lists. This refers to a situation in which the selection made
- * in one drop down list affects the options that are displayed in the second
- * or subsequent drop down list(s). In this example, the value the user selects
- * from the down list in cell A1 will affect the values displayed in the linked
- * drop down list in cell B1. For the sake of simplicity, the data for the drop
- * down lists is included on the same worksheet but this does not have to be the
- * case; the data could appear on a separate sheet. If this were done, then the
- * names for the regions would have to be different, they would have to include
- * the name of the sheet.
- * 
- * There are two keys to this technique. The first is the use of named area or 
- * regions of cells to hold the data for the drop down lists and the second is
- * making use of the INDIRECT() function to convert a name into the addresses
- * of the cells it refers to.
- * 
- * Note that whilst this class builds just two linked drop down lists, there is
- * nothing to prevent more being created. Quite simply, use the value selected
- * by the user in one drop down list to determine what is shown in another and the
- * value selected in that drop down list to determine what is shown in a third,
- * and so on. Also, note that the data for the drop down lists is contained on
- * contained on the same sheet as the validations themselves. This is done simply
- * for simplicity and there is nothing to prevent a separate sheet being created
- * and used to hold the data. If this is done then problems may be encountered
- * if the sheet is opened with OpenOffice Calc. To prevent these problems, it is
- * better to include the name of the sheet when calling the setRefersToFormula()
- * method.
- *
- * @author Mark Beardsley [msb at apache.org]
- * @version 1.00 30th March 2012
- */
-public class LinkedDropDownLists {
-
-    LinkedDropDownLists(String workbookName) throws IOException {
-        // Using the ss.usermodel allows this class to support both binary
-        // and xml based workbooks. The choice of which one to create is
-        // made by checking the file extension.
-        try (Workbook workbook = workbookName.endsWith(".xlsx") ? new XSSFWorkbook() : new HSSFWorkbook()) {
-
-            // Build the sheet that will hold the data for the validations. This
-            // must be done first as it will create names that are referenced
-            // later.
-            Sheet sheet = workbook.createSheet("Linked Validations");
-            LinkedDropDownLists.buildDataSheet(sheet);
-
-            // Build the first data validation to occupy cell A1. Note
-            // that it retrieves it's data from the named area or region called
-            // CHOICES. Further information about this can be found in the
-            // static buildDataSheet() method below.
-            CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0);
-            DataValidationHelper dvHelper = sheet.getDataValidationHelper();
-            DataValidationConstraint dvConstraint = dvHelper.createFormulaListConstraint("CHOICES");
-            DataValidation validation = dvHelper.createValidation(dvConstraint, addressList);
-            sheet.addValidationData(validation);
-
-            // Now, build the linked or dependent drop down list that will
-            // occupy cell B1. The key to the whole process is the use of the
-            // INDIRECT() function. In the buildDataSheet(0 method, a series of
-            // named regions are created and the names of three of them mirror
-            // the options available to the user in the first drop down list
-            // (in cell A1). Using the INDIRECT() function makes it possible
-            // to convert the selection the user makes in that first drop down
-            // into the addresses of a named region of cells and then to use
-            // those cells to populate the second drop down list.
-            addressList = new CellRangeAddressList(0, 0, 1, 1);
-            dvConstraint = dvHelper.createFormulaListConstraint(
-                    "INDIRECT(UPPER($A$1))");
-            validation = dvHelper.createValidation(dvConstraint, addressList);
-            sheet.addValidationData(validation);
-
-            try (FileOutputStream fos = new FileOutputStream(workbookName)) {
-                workbook.write(fos);
-            }
-        }
-    }
-
-    /**
-     * Called to populate the named areas/regions. The contents of the cells on
-     * row one will be used to populate the first drop down list. The contents of
-     * the cells on rows two, three and four will be used to populate the second
-     * drop down list, just which row will be determined by the choice the user
-     * makes in the first drop down list.
-     * 
-     * In all cases, the approach is to create a row, create and populate cells
-     * with data and then specify a name that identifies those cells. With the
-     * exception of the first range, the names that are chosen for each range
-     * of cells are quite important. In short, each of the options the user 
-     * could select in the first drop down list is used as the name for another
-     * range of cells. Thus, in this example, the user can select either 
-     * 'Animal', 'Vegetable' or 'Mineral' in the first drop down and so the
-     * sheet contains ranges named 'ANIMAL', 'VEGETABLE' and 'MINERAL'.
-     * 
-     * @param dataSheet An instance of a class that implements the Sheet Sheet
-     *        interface (HSSFSheet or XSSFSheet).
-     */
-    private static void buildDataSheet(Sheet dataSheet) {
-        Row row = null;
-        Cell cell = null;
-        Name name = null;
-
-        // The first row will hold the data for the first validation.
-        row = dataSheet.createRow(10);
-        cell = row.createCell(0);
-        cell.setCellValue("Animal");
-        cell = row.createCell(1);
-        cell.setCellValue("Vegetable");
-        cell = row.createCell(2);
-        cell.setCellValue("Mineral");
-        name = dataSheet.getWorkbook().createName();
-        name.setRefersToFormula("$A$11:$C$11");
-        name.setNameName("CHOICES");
-
-        // The next three rows will hold the data that will be used to
-        // populate the second, or linked, drop down list.
-        row = dataSheet.createRow(11);
-        cell = row.createCell(0);
-        cell.setCellValue("Lion");
-        cell = row.createCell(1);
-        cell.setCellValue("Tiger");
-        cell = row.createCell(2);
-        cell.setCellValue("Leopard");
-        cell = row.createCell(3);
-        cell.setCellValue("Elephant");
-        cell = row.createCell(4);
-        cell.setCellValue("Eagle");
-        cell = row.createCell(5);
-        cell.setCellValue("Horse");
-        cell = row.createCell(6);
-        cell.setCellValue("Zebra");
-        name = dataSheet.getWorkbook().createName();
-        name.setRefersToFormula("$A$12:$G$12");
-        name.setNameName("ANIMAL");
-
-        row = dataSheet.createRow(12);
-        cell = row.createCell(0);
-        cell.setCellValue("Cabbage");
-        cell = row.createCell(1);
-        cell.setCellValue("Cauliflower");
-        cell = row.createCell(2);
-        cell.setCellValue("Potato");
-        cell = row.createCell(3);
-        cell.setCellValue("Onion");
-        cell = row.createCell(4);
-        cell.setCellValue("Beetroot");
-        cell = row.createCell(5);
-        cell.setCellValue("Asparagus");
-        cell = row.createCell(6);
-        cell.setCellValue("Spinach");
-        cell = row.createCell(7);
-        cell.setCellValue("Chard");
-        name = dataSheet.getWorkbook().createName();
-        name.setRefersToFormula("$A$13:$H$13");
-        name.setNameName("VEGETABLE");
-
-        row = dataSheet.createRow(13);
-        cell = row.createCell(0);
-        cell.setCellValue("Bauxite");
-        cell = row.createCell(1);
-        cell.setCellValue("Quartz");
-        cell = row.createCell(2);
-        cell.setCellValue("Feldspar");
-        cell = row.createCell(3);
-        cell.setCellValue("Shist");
-        cell = row.createCell(4);
-        cell.setCellValue("Shale");
-        cell = row.createCell(5);
-        cell.setCellValue("Mica");
-        name = dataSheet.getWorkbook().createName();
-        name.setRefersToFormula("$A$14:$F$14");
-        name.setNameName("MINERAL");
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/LoadEmbedded.java b/src/examples/src/org/apache/poi/ss/examples/LoadEmbedded.java
deleted file mode 100644 (file)
index 34313b0..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.examples;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.hssf.usermodel.HSSFObjectData;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hwpf.HWPFDocument;
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
-import org.apache.poi.openxml4j.opc.PackagePart;
-import org.apache.poi.poifs.filesystem.DirectoryNode;
-import org.apache.poi.poifs.filesystem.Entry;
-import org.apache.poi.sl.usermodel.SlideShow;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
-import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.xmlbeans.XmlException;
-
-/**
- * Loads embedded resources from Workbooks. Code taken from the website:
- *  https://poi.apache.org/spreadsheet/quick-guide.html#Embedded
- */
-@SuppressWarnings({"java:S106","java:S4823"})
-public final class LoadEmbedded {
-    private LoadEmbedded() {}
-
-    public static void main(String[] args) throws IOException, EncryptedDocumentException, OpenXML4JException, XmlException {
-       Workbook wb = WorkbookFactory.create(new File(args[0]));
-       loadEmbedded(wb);
-   }
-
-   public static void loadEmbedded(Workbook wb) throws IOException, InvalidFormatException, OpenXML4JException, XmlException {
-       if (wb instanceof HSSFWorkbook) {
-           loadEmbedded((HSSFWorkbook)wb);
-       }
-       else if (wb instanceof XSSFWorkbook) {
-           loadEmbedded((XSSFWorkbook)wb);
-       }
-       else {
-           throw new IllegalArgumentException(wb.getClass().getName());
-       }
-   }
-
-   public static void loadEmbedded(HSSFWorkbook workbook) throws IOException {
-       for (HSSFObjectData obj : workbook.getAllEmbeddedObjects()) {
-           //the OLE2 Class Name of the object
-           String oleName = obj.getOLE2ClassName();
-           if (oleName.equals("Worksheet")) {
-               DirectoryNode dn = (DirectoryNode) obj.getDirectory();
-               HSSFWorkbook embeddedWorkbook = new HSSFWorkbook(dn, false);
-               embeddedWorkbook.close();
-           } else if (oleName.equals("Document")) {
-               DirectoryNode dn = (DirectoryNode) obj.getDirectory();
-               HWPFDocument embeddedWordDocument = new HWPFDocument(dn);
-               embeddedWordDocument.close();
-           }  else if (oleName.equals("Presentation")) {
-               DirectoryNode dn = (DirectoryNode) obj.getDirectory();
-               SlideShow<?,?> embeddedSlieShow = new HSLFSlideShow(dn);
-               embeddedSlieShow.close();
-           } else {
-               if(obj.hasDirectoryEntry()){
-                   // The DirectoryEntry is a DocumentNode. Examine its entries to find out what it is
-                   DirectoryNode dn = (DirectoryNode) obj.getDirectory();
-                   for (Entry entry : dn) {
-                       //System.out.println(oleName + "." + entry.getName());
-                   }
-               } else {
-                   // There is no DirectoryEntry
-                   // Recover the object's data from the HSSFObjectData instance.
-                   byte[] objectData = obj.getObjectData();
-               }
-           }
-       }
-   }
-
-   public static void loadEmbedded(XSSFWorkbook workbook) throws IOException, InvalidFormatException, OpenXML4JException, XmlException {
-       for (PackagePart pPart : workbook.getAllEmbeddedParts()) {
-           String contentType = pPart.getContentType();
-           if (contentType.equals("application/vnd.ms-excel")) {
-               // Excel Workbook - either binary or OpenXML
-               HSSFWorkbook embeddedWorkbook = new HSSFWorkbook(pPart.getInputStream());
-               embeddedWorkbook.close();
-           } else if (contentType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
-               // Excel Workbook - OpenXML file format
-               XSSFWorkbook embeddedWorkbook = new XSSFWorkbook(pPart.getInputStream());
-               embeddedWorkbook.close();
-           } else if (contentType.equals("application/msword")) {
-               // Word Document - binary (OLE2CDF) file format
-               HWPFDocument document = new HWPFDocument(pPart.getInputStream());
-               document.close();
-           } else if (contentType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
-               // Word Document - OpenXML file format
-               XWPFDocument document = new XWPFDocument(pPart.getInputStream());
-               document.close();
-           } else if (contentType.equals("application/vnd.ms-powerpoint")) {
-               // PowerPoint Document - binary file format
-               HSLFSlideShow slideShow = new HSLFSlideShow(pPart.getInputStream());
-               slideShow.close();
-           } else if (contentType.equals("application/vnd.openxmlformats-officedocument.presentationml.presentation")) {
-               // PowerPoint Document - OpenXML file format
-               XMLSlideShow slideShow = new XMLSlideShow(pPart.getInputStream());
-               slideShow.close();
-           } else {
-               // Any other type of embedded object.
-               System.out.println("Unknown Embedded Document: " + contentType);
-               InputStream inputStream = pPart.getInputStream();
-               inputStream.close();
-           }
-       }
-   }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/LoanCalculator.java b/src/examples/src/org/apache/poi/ss/examples/LoanCalculator.java
deleted file mode 100644 (file)
index 079b782..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.examples;
-
-import java.io.FileOutputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.usermodel.Name;
-import org.apache.poi.ss.usermodel.PrintSetup;
-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.util.CellRangeAddress;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Simple Loan Calculator. Demonstrates advance usage of cell formulas and named ranges.
- *
- * Usage:
- *   LoanCalculator -xls|xlsx
- *
- * @author Yegor Kozlov
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class LoanCalculator {
-
-    private LoanCalculator() {}
-
-    public static void main(String[] args) throws Exception {
-        Workbook wb;
-
-        if(args.length > 0 && args[0].equals("-xls")) wb = new HSSFWorkbook();
-        else wb = new XSSFWorkbook();
-
-        Map<String, CellStyle> styles = createStyles(wb);
-        Sheet sheet = wb.createSheet("Loan Calculator");
-        sheet.setPrintGridlines(false);
-        sheet.setDisplayGridlines(false);
-
-        PrintSetup printSetup = sheet.getPrintSetup();
-        printSetup.setLandscape(true);
-        sheet.setFitToPage(true);
-        sheet.setHorizontallyCenter(true);
-
-        sheet.setColumnWidth(0, 3*256);
-        sheet.setColumnWidth(1, 3*256);
-        sheet.setColumnWidth(2, 11*256);
-        sheet.setColumnWidth(3, 14*256);
-        sheet.setColumnWidth(4, 14*256);
-        sheet.setColumnWidth(5, 14*256);
-        sheet.setColumnWidth(6, 14*256);
-
-        createNames(wb);
-
-        Row titleRow = sheet.createRow(0);
-        titleRow.setHeightInPoints(35);
-        for (int i = 1; i <= 7; i++) {
-            titleRow.createCell(i).setCellStyle(styles.get("title"));
-        }
-        Cell titleCell = titleRow.getCell(2);
-        titleCell.setCellValue("Simple Loan Calculator");
-        sheet.addMergedRegion(CellRangeAddress.valueOf("$C$1:$H$1"));
-
-        Row row = sheet.createRow(2);
-        Cell cell = row.createCell(4);
-        cell.setCellValue("Enter values");
-        cell.setCellStyle(styles.get("item_right"));
-
-        row = sheet.createRow(3);
-        cell = row.createCell(2);
-        cell.setCellValue("Loan amount");
-        cell.setCellStyle(styles.get("item_left"));
-        cell = row.createCell(4);
-        cell.setCellStyle(styles.get("input_$"));
-        cell.setAsActiveCell();
-
-        row = sheet.createRow(4);
-        cell = row.createCell(2);
-        cell.setCellValue("Annual interest rate");
-        cell.setCellStyle(styles.get("item_left"));
-        cell = row.createCell(4);
-        cell.setCellStyle(styles.get("input_%"));
-
-        row = sheet.createRow(5);
-        cell = row.createCell(2);
-        cell.setCellValue("Loan period in years");
-        cell.setCellStyle(styles.get("item_left"));
-        cell = row.createCell(4);
-        cell.setCellStyle(styles.get("input_i"));
-
-        row = sheet.createRow(6);
-        cell = row.createCell(2);
-        cell.setCellValue("Start date of loan");
-        cell.setCellStyle(styles.get("item_left"));
-        cell = row.createCell(4);
-        cell.setCellStyle(styles.get("input_d"));
-
-        row = sheet.createRow(8);
-        cell = row.createCell(2);
-        cell.setCellValue("Monthly payment");
-        cell.setCellStyle(styles.get("item_left"));
-        cell = row.createCell(4);
-        cell.setCellFormula("IF(Values_Entered,Monthly_Payment,\"\")");
-        cell.setCellStyle(styles.get("formula_$"));
-
-        row = sheet.createRow(9);
-        cell = row.createCell(2);
-        cell.setCellValue("Number of payments");
-        cell.setCellStyle(styles.get("item_left"));
-        cell = row.createCell(4);
-        cell.setCellFormula("IF(Values_Entered,Loan_Years*12,\"\")");
-        cell.setCellStyle(styles.get("formula_i"));
-
-        row = sheet.createRow(10);
-        cell = row.createCell(2);
-        cell.setCellValue("Total interest");
-        cell.setCellStyle(styles.get("item_left"));
-        cell = row.createCell(4);
-        cell.setCellFormula("IF(Values_Entered,Total_Cost-Loan_Amount,\"\")");
-        cell.setCellStyle(styles.get("formula_$"));
-
-        row = sheet.createRow(11);
-        cell = row.createCell(2);
-        cell.setCellValue("Total cost of loan");
-        cell.setCellStyle(styles.get("item_left"));
-        cell = row.createCell(4);
-        cell.setCellFormula("IF(Values_Entered,Monthly_Payment*Number_of_Payments,\"\")");
-        cell.setCellStyle(styles.get("formula_$"));
-
-
-        // Write the output to a file
-        String file = "loan-calculator.xls";
-        if(wb instanceof XSSFWorkbook) file += "x";
-        FileOutputStream out = new FileOutputStream(file);
-        wb.write(out);
-        out.close();
-    }
-
-    /**
-     * cell styles used for formatting calendar sheets
-     */
-    private static Map<String, CellStyle> createStyles(Workbook wb){
-        Map<String, CellStyle> styles = new HashMap<>();
-
-        CellStyle style;
-        Font titleFont = wb.createFont();
-        titleFont.setFontHeightInPoints((short)14);
-        titleFont.setFontName("Trebuchet MS");
-        style = wb.createCellStyle();
-        style.setFont(titleFont);
-        style.setBorderBottom(BorderStyle.DOTTED);
-        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        styles.put("title", style);
-
-        Font itemFont = wb.createFont();
-        itemFont.setFontHeightInPoints((short)9);
-        itemFont.setFontName("Trebuchet MS");
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.LEFT);
-        style.setFont(itemFont);
-        styles.put("item_left", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.RIGHT);
-        style.setFont(itemFont);
-        styles.put("item_right", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.RIGHT);
-        style.setFont(itemFont);
-        style.setBorderRight(BorderStyle.DOTTED);
-        style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderBottom(BorderStyle.DOTTED);
-        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderLeft(BorderStyle.DOTTED);
-        style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderTop(BorderStyle.DOTTED);
-        style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setDataFormat(wb.createDataFormat().getFormat("_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)"));
-        styles.put("input_$", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.RIGHT);
-        style.setFont(itemFont);
-        style.setBorderRight(BorderStyle.DOTTED);
-        style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderBottom(BorderStyle.DOTTED);
-        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderLeft(BorderStyle.DOTTED);
-        style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderTop(BorderStyle.DOTTED);
-        style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setDataFormat(wb.createDataFormat().getFormat("0.000%"));
-        styles.put("input_%", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.RIGHT);
-        style.setFont(itemFont);
-        style.setBorderRight(BorderStyle.DOTTED);
-        style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderBottom(BorderStyle.DOTTED);
-        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderLeft(BorderStyle.DOTTED);
-        style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderTop(BorderStyle.DOTTED);
-        style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setDataFormat(wb.createDataFormat().getFormat("0"));
-        styles.put("input_i", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setFont(itemFont);
-        style.setDataFormat(wb.createDataFormat().getFormat("m/d/yy"));
-        styles.put("input_d", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.RIGHT);
-        style.setFont(itemFont);
-        style.setBorderRight(BorderStyle.DOTTED);
-        style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderBottom(BorderStyle.DOTTED);
-        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderLeft(BorderStyle.DOTTED);
-        style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderTop(BorderStyle.DOTTED);
-        style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setDataFormat(wb.createDataFormat().getFormat("$##,##0.00"));
-        style.setBorderBottom(BorderStyle.DOTTED);
-        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        styles.put("formula_$", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.RIGHT);
-        style.setFont(itemFont);
-        style.setBorderRight(BorderStyle.DOTTED);
-        style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderBottom(BorderStyle.DOTTED);
-        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderLeft(BorderStyle.DOTTED);
-        style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setBorderTop(BorderStyle.DOTTED);
-        style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setDataFormat(wb.createDataFormat().getFormat("0"));
-        style.setBorderBottom(BorderStyle.DOTTED);
-        style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        styles.put("formula_i", style);
-
-        return styles;
-    }
-
-    //define named ranges for the inputs and formulas
-    public static void createNames(Workbook wb){
-        Name name;
-
-        name = wb.createName();
-        name.setNameName("Interest_Rate");
-        name.setRefersToFormula("'Loan Calculator'!$E$5");
-
-        name = wb.createName();
-        name.setNameName("Loan_Amount");
-        name.setRefersToFormula("'Loan Calculator'!$E$4");
-
-        name = wb.createName();
-        name.setNameName("Loan_Start");
-        name.setRefersToFormula("'Loan Calculator'!$E$7");
-
-        name = wb.createName();
-        name.setNameName("Loan_Years");
-        name.setRefersToFormula("'Loan Calculator'!$E$6");
-
-        name = wb.createName();
-        name.setNameName("Number_of_Payments");
-        name.setRefersToFormula("'Loan Calculator'!$E$10");
-
-        name = wb.createName();
-        name.setNameName("Monthly_Payment");
-        name.setRefersToFormula("-PMT(Interest_Rate/12,Number_of_Payments,Loan_Amount)");
-
-        name = wb.createName();
-        name.setNameName("Total_Cost");
-        name.setRefersToFormula("'Loan Calculator'!$E$12");
-
-        name = wb.createName();
-        name.setNameName("Total_Interest");
-        name.setRefersToFormula("'Loan Calculator'!$E$11");
-
-        name = wb.createName();
-        name.setNameName("Values_Entered");
-        name.setRefersToFormula("IF(Loan_Amount*Interest_Rate*Loan_Years*Loan_Start>0,1,0)");
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/SSPerformanceTest.java b/src/examples/src/org/apache/poi/ss/examples/SSPerformanceTest.java
deleted file mode 100644 (file)
index 05776be..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-package org.apache.poi.ss.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ooxml.POIXMLTypeLoader;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.VerticalAlignment;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xssf.streaming.SXSSFWorkbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class SSPerformanceTest {
-    private SSPerformanceTest() {}
-
-    public static void main(String[] args) throws IOException {
-        if (args.length < 4) {
-            usage("need at least four command arguments");
-        }
-
-        String type = args[0];
-        int rows = parseInt(args[1], "Failed to parse rows value as integer");
-        int cols = parseInt(args[2], "Failed to parse cols value as integer");
-        boolean saveFile = parseInt(args[3], "Failed to parse saveFile value as integer") != 0;
-
-        boolean warmup = false;
-        for(int arg = 4; arg < args.length;arg++) {
-            if(args[arg].equals("--unsynchronized-xmlbeans")) {
-                POIXMLTypeLoader.DEFAULT_XML_OPTIONS.setUnsynchronized();
-            }
-            if(args[arg].equals("--with-warmup-run")) {
-                warmup = true;
-            }
-        }
-
-        if(warmup) {
-            System.out.println("Performing a warmup run first");
-            runWithArgs(type, rows, cols, saveFile);
-        }
-
-        long timeStarted = System.currentTimeMillis();
-        runWithArgs(type, rows, cols, saveFile);
-        long timeFinished = System.currentTimeMillis();
-
-        System.out.printf("Elapsed %.2f seconds for arguments %s\n", ((double)timeFinished - timeStarted) / 1000, Arrays.toString(args));
-    }
-
-    private static void runWithArgs(String type, int rows, int cols, boolean saveFile) throws IOException {
-        try (Workbook workBook = createWorkbook(type)) {
-            boolean isHType = workBook instanceof HSSFWorkbook;
-            addContent(workBook, isHType, rows, cols);
-
-            if (saveFile) {
-                String fileName = type + "_" + rows + "_" + cols + "." + getFileSuffix(type);
-                saveFile(workBook, fileName);
-            }
-        }
-    }
-
-    private static void addContent(Workbook workBook, boolean isHType, int rows, int cols) {
-        Map<String, CellStyle> styles = createStyles(workBook);
-
-        Sheet sheet = workBook.createSheet("Main Sheet");
-
-        Cell headerCell = sheet.createRow(0).createCell(0);
-        headerCell.setCellValue("Header text is spanned across multiple cells");
-        headerCell.setCellStyle(styles.get("header"));
-        sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$F$1"));
-
-        int sheetNo = 0;
-        int rowIndexInSheet = 1;
-        double value = 0;
-        Calendar calendar = Calendar.getInstance();
-        for (int rowIndex = 0; rowIndex < rows; rowIndex++) {
-            if (isHType && sheetNo != rowIndex / 0x10000) {
-                sheet = workBook.createSheet("Spillover from sheet " + (++sheetNo));
-                headerCell.setCellValue("Header text is spanned across multiple cells");
-                headerCell.setCellStyle(styles.get("header"));
-                sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$F$1"));
-                rowIndexInSheet = 1;
-            }
-
-            Row row = sheet.createRow(rowIndexInSheet);
-            for (int colIndex = 0; colIndex < cols; colIndex++) {
-                value = populateCell(styles, value, calendar, rowIndex, row, colIndex);
-            }
-            rowIndexInSheet++;
-        }
-    }
-
-    private static double populateCell(Map<String, CellStyle> styles, double value, Calendar calendar, int rowIndex, Row row, int colIndex) {
-        Cell cell = row.createCell(colIndex);
-        String address = new CellReference(cell).formatAsString();
-        switch (colIndex){
-            case 0:
-                // column A: default number format
-                cell.setCellValue(value++);
-                break;
-            case 1:
-                // column B: #,##0
-                cell.setCellValue(value++);
-                cell.setCellStyle(styles.get("#,##0.00"));
-                break;
-            case 2:
-                // column C: $#,##0.00
-                cell.setCellValue(value++);
-                cell.setCellStyle(styles.get("$#,##0.00"));
-                break;
-            case 3:
-                // column D: red bold text on yellow background
-                cell.setCellValue(address);
-                cell.setCellStyle(styles.get("red-bold"));
-                break;
-            case 4:
-                // column E: boolean
-                // TODO booleans are shown as 1/0 instead of TRUE/FALSE
-                cell.setCellValue(rowIndex % 2 == 0);
-                break;
-            case 5:
-                // column F:  date / time
-                cell.setCellValue(calendar);
-                cell.setCellStyle(styles.get("m/d/yyyy"));
-                calendar.roll(Calendar.DAY_OF_YEAR, -1);
-                break;
-            case 6:
-                // column F: formula
-                // TODO formulas are not yet supported  in SXSSF
-                //cell.setCellFormula("SUM(A" + (rowIndex+1) + ":E" + (rowIndex+1)+ ")");
-                //break;
-            default:
-                cell.setCellValue(value++);
-                break;
-        }
-        return value;
-    }
-
-    private static void saveFile(Workbook workBook, String fileName) {
-        try {
-            FileOutputStream out = new FileOutputStream(fileName);
-            workBook.write(out);
-            out.close();
-        } catch (IOException ioe) {
-            System.err.println("Error: failed to write to file \"" + fileName + "\", reason=" + ioe.getMessage());
-        }
-    }
-
-    static Map<String, CellStyle> createStyles(Workbook wb) {
-        Map<String, CellStyle> styles = new HashMap<>();
-        CellStyle style;
-
-        Font headerFont = wb.createFont();
-        headerFont.setFontHeightInPoints((short) 14);
-        headerFont.setBold(true);
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setFont(headerFont);
-        style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        styles.put("header", style);
-
-        Font monthFont = wb.createFont();
-        monthFont.setFontHeightInPoints((short)12);
-        monthFont.setColor(IndexedColors.RED.getIndex());
-        monthFont.setBold(true);
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setFont(monthFont);
-        styles.put("red-bold", style);
-
-        String[] nfmt = {"#,##0.00", "$#,##0.00", "m/d/yyyy"};
-        for(String fmt : nfmt){
-            style = wb.createCellStyle();
-            style.setDataFormat(wb.createDataFormat().getFormat(fmt));
-            styles.put(fmt, style);
-        }
-
-        return styles;
-    }
-
-
-    static void usage(String message) {
-        System.err.println(message);
-        System.err.println("usage: java SSPerformanceTest HSSF|XSSF|SXSSF rows cols saveFile (0|1)? [--unsynchronized-xmlbeans] [--with-warmup-run]");
-        System.exit(1);
-    }
-
-    static Workbook createWorkbook(String type) {
-        if ("HSSF".equals(type))
-            return new HSSFWorkbook();
-        else if ("XSSF".equals(type))
-            return new XSSFWorkbook();
-        else if ("SXSSF".equals(type))
-            return new SXSSFWorkbook();
-
-        usage("Unknown type \"" + type + "\"");
-        throw new IllegalArgumentException("Should not reach this point");
-    }
-
-    static String getFileSuffix(String type) {
-        if ("HSSF".equals(type))
-            return "xls";
-        else if ("XSSF".equals(type))
-            return "xlsx";
-        else if ("SXSSF".equals(type))
-            return "xlsx";
-        return null;
-    }
-
-    static int parseInt(String value, String msg) {
-        try {
-            return Integer.parseInt(value);
-        } catch (NumberFormatException e) {
-            usage(msg);
-        }
-        return 0;
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/TimesheetDemo.java b/src/examples/src/org/apache/poi/ss/examples/TimesheetDemo.java
deleted file mode 100644 (file)
index 5829454..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.examples;
-
-import java.io.FileOutputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.usermodel.PrintSetup;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.VerticalAlignment;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * A weekly timesheet created using Apache POI.
- * Usage:
- *  TimesheetDemo -xls|xlsx
- *
- * @author Yegor Kozlov
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class TimesheetDemo {
-    private static final String[] titles = {
-            "Person",  "ID", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",
-            "Total\nHrs", "Overtime\nHrs", "Regular\nHrs"
-    };
-
-    private static final Object[][] sample_data = {
-            {"Yegor Kozlov", "YK", 5.0, 8.0, 10.0, 5.0, 5.0, 7.0, 6.0},
-            {"Gisella Bronzetti", "GB", 4.0, 3.0, 1.0, 3.5, null, null, 4.0},
-    };
-
-    private TimesheetDemo() {}
-
-    public static void main(String[] args) throws Exception {
-        Workbook wb;
-
-        if(args.length > 0 && args[0].equals("-xls")) wb = new HSSFWorkbook();
-        else wb = new XSSFWorkbook();
-
-        Map<String, CellStyle> styles = createStyles(wb);
-
-        Sheet sheet = wb.createSheet("Timesheet");
-        PrintSetup printSetup = sheet.getPrintSetup();
-        printSetup.setLandscape(true);
-        sheet.setFitToPage(true);
-        sheet.setHorizontallyCenter(true);
-
-        //title row
-        Row titleRow = sheet.createRow(0);
-        titleRow.setHeightInPoints(45);
-        Cell titleCell = titleRow.createCell(0);
-        titleCell.setCellValue("Weekly Timesheet");
-        titleCell.setCellStyle(styles.get("title"));
-        sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$L$1"));
-
-        //header row
-        Row headerRow = sheet.createRow(1);
-        headerRow.setHeightInPoints(40);
-        Cell headerCell;
-        for (int i = 0; i < titles.length; i++) {
-            headerCell = headerRow.createCell(i);
-            headerCell.setCellValue(titles[i]);
-            headerCell.setCellStyle(styles.get("header"));
-        }
-
-        int rownum = 2;
-        for (int i = 0; i < 10; i++) {
-            Row row = sheet.createRow(rownum++);
-            for (int j = 0; j < titles.length; j++) {
-                Cell cell = row.createCell(j);
-                if(j == 9){
-                    //the 10th cell contains sum over week days, e.g. SUM(C3:I3)
-                    String ref = "C" +rownum+ ":I" + rownum;
-                    cell.setCellFormula("SUM("+ref+")");
-                    cell.setCellStyle(styles.get("formula"));
-                } else if (j == 11){
-                    cell.setCellFormula("J" +rownum+ "-K" + rownum);
-                    cell.setCellStyle(styles.get("formula"));
-                } else {
-                    cell.setCellStyle(styles.get("cell"));
-                }
-            }
-        }
-
-        //row with totals below
-        Row sumRow = sheet.createRow(rownum++);
-        sumRow.setHeightInPoints(35);
-        Cell cell;
-        cell = sumRow.createCell(0);
-        cell.setCellStyle(styles.get("formula"));
-        cell = sumRow.createCell(1);
-        cell.setCellValue("Total Hrs:");
-        cell.setCellStyle(styles.get("formula"));
-
-        for (int j = 2; j < 12; j++) {
-            cell = sumRow.createCell(j);
-            String ref = (char)('A' + j) + "3:" + (char)('A' + j) + "12";
-            cell.setCellFormula("SUM(" + ref + ")");
-            if(j >= 9) cell.setCellStyle(styles.get("formula_2"));
-            else cell.setCellStyle(styles.get("formula"));
-        }
-        rownum++;
-        sumRow = sheet.createRow(rownum++);
-        sumRow.setHeightInPoints(25);
-        cell = sumRow.createCell(0);
-        cell.setCellValue("Total Regular Hours");
-        cell.setCellStyle(styles.get("formula"));
-        cell = sumRow.createCell(1);
-        cell.setCellFormula("L13");
-        cell.setCellStyle(styles.get("formula_2"));
-        sumRow = sheet.createRow(rownum++);
-        sumRow.setHeightInPoints(25);
-        cell = sumRow.createCell(0);
-        cell.setCellValue("Total Overtime Hours");
-        cell.setCellStyle(styles.get("formula"));
-        cell = sumRow.createCell(1);
-        cell.setCellFormula("K13");
-        cell.setCellStyle(styles.get("formula_2"));
-
-        //set sample data
-        for (int i = 0; i < sample_data.length; i++) {
-            Row row = sheet.getRow(2 + i);
-            for (int j = 0; j < sample_data[i].length; j++) {
-                if(sample_data[i][j] == null) continue;
-
-                if(sample_data[i][j] instanceof String) {
-                    row.getCell(j).setCellValue((String)sample_data[i][j]);
-                } else {
-                    row.getCell(j).setCellValue((Double)sample_data[i][j]);
-                }
-            }
-        }
-
-        //finally set column widths, the width is measured in units of 1/256th of a character width
-        sheet.setColumnWidth(0, 30*256); //30 characters wide
-        for (int i = 2; i < 9; i++) {
-            sheet.setColumnWidth(i, 6*256);  //6 characters wide
-        }
-        sheet.setColumnWidth(10, 10*256); //10 characters wide
-
-        // Write the output to a file
-        String file = "timesheet.xls";
-        if(wb instanceof XSSFWorkbook) file += "x";
-        FileOutputStream out = new FileOutputStream(file);
-        wb.write(out);
-        out.close();
-    }
-
-    /**
-     * Create a library of cell styles
-     */
-    private static Map<String, CellStyle> createStyles(Workbook wb){
-        Map<String, CellStyle> styles = new HashMap<>();
-        CellStyle style;
-        Font titleFont = wb.createFont();
-        titleFont.setFontHeightInPoints((short)18);
-        titleFont.setBold(true);
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setFont(titleFont);
-        styles.put("title", style);
-
-        Font monthFont = wb.createFont();
-        monthFont.setFontHeightInPoints((short)11);
-        monthFont.setColor(IndexedColors.WHITE.getIndex());
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setFont(monthFont);
-        style.setWrapText(true);
-        styles.put("header", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setWrapText(true);
-        style.setBorderRight(BorderStyle.THIN);
-        style.setRightBorderColor(IndexedColors.BLACK.getIndex());
-        style.setBorderLeft(BorderStyle.THIN);
-        style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
-        style.setBorderTop(BorderStyle.THIN);
-        style.setTopBorderColor(IndexedColors.BLACK.getIndex());
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
-        styles.put("cell", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setDataFormat(wb.createDataFormat().getFormat("0.00"));
-        styles.put("formula", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setDataFormat(wb.createDataFormat().getFormat("0.00"));
-        styles.put("formula_2", style);
-
-        return styles;
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/ToCSV.java b/src/examples/src/org/apache/poi/ss/examples/ToCSV.java
deleted file mode 100644 (file)
index a7a806d..0000000
+++ /dev/null
@@ -1,741 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.examples;
-
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.util.ArrayList;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.DataFormatter;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
-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.WorkbookFactory;
-
-/**
- * Demonstrates <em>one</em> way to convert an Excel spreadsheet into a CSV
- * file. This class makes the following assumptions;
- * <list>
- * <li>1. Where the Excel workbook contains more that one worksheet, then a single
- *    CSV file will contain the data from all of the worksheets.</li>
- * <li>2. The data matrix contained in the CSV file will be square. This means that
- *    the number of fields in each record of the CSV file will match the number
- *    of cells in the longest row found in the Excel workbook. Any short records
- *    will be 'padded' with empty fields - an empty field is represented in the
- *    the CSV file in this way - ,,.</li>
- * <li>3. Empty fields will represent missing cells.</li>
- * <li>4. A record consisting of empty fields will be used to represent an empty row
- *    in the Excel workbook.</li>
- * </list>
- * Therefore, if the worksheet looked like this;
- *
- * <pre>
- *  ___________________________________________
- *     |       |       |       |       |       |
- *     |   A   |   B   |   C   |   D   |   E   |
- *  ___|_______|_______|_______|_______|_______|
- *     |       |       |       |       |       |
- *   1 |   1   |   2   |   3   |   4   |   5   |
- *  ___|_______|_______|_______|_______|_______|
- *     |       |       |       |       |       |
- *   2 |       |       |       |       |       |
- *  ___|_______|_______|_______|_______|_______|
- *     |       |       |       |       |       |
- *   3 |       |   A   |       |   B   |       |
- *  ___|_______|_______|_______|_______|_______|
- *     |       |       |       |       |       |
- *   4 |       |       |       |       |   Z   |
- *  ___|_______|_______|_______|_______|_______|
- *     |       |       |       |       |       |
- *   5 | 1,400 |       |  250  |       |       |
- *  ___|_______|_______|_______|_______|_______|
- *
- * </pre>
- *
- * Then, the resulting CSV file will contain the following lines (records);
- * <pre>
- * 1,2,3,4,5
- * ,,,,
- * ,A,,B,
- * ,,,,Z
- * "1,400",,250,,
- * </pre><p>
- * Typically, the comma is used to separate each of the fields that, together,
- * constitute a single record or line within the CSV file. This is not however
- * a hard and fast rule and so this class allows the user to determine which
- * character is used as the field separator and assumes the comma if none other
- * is specified.
- * </p><p>
- * If a field contains the separator then it will be escaped. If the file should
- * obey Excel's CSV formatting rules, then the field will be surrounded with
- * speech marks whilst if it should obey UNIX conventions, each occurrence of
- * the separator will be preceded by the backslash character.
- * </p><p>
- * If a field contains an end of line (EOL) character then it too will be
- * escaped. If the file should obey Excel's CSV formatting rules then the field
- * will again be surrounded by speech marks. On the other hand, if the file
- * should follow UNIX conventions then a single backslash will precede the
- * EOL character. There is no single applicable standard for UNIX and some
- * appications replace the CR with \r and the LF with \n but this class will
- * not do so.
- * </p><p>
- * If the field contains double quotes then that character will be escaped. It
- * seems as though UNIX does not define a standard for this whilst Excel does.
- * Should the CSV file have to obey Excel's formmating rules then the speech
- * mark character will be escaped with a second set of speech marks. Finally, an
- * enclosing set of speah marks will also surround the entire field. Thus, if
- * the following line of text appeared in a cell - "Hello" he said - it would
- * look like this when converted into a field within a CSV file - """Hello"" he
- * said".
- * </p><p>
- * Finally, it is worth noting that talk of CSV 'standards' is really slightly
- * missleading as there is no such thing. It may well be that the code in this
- * class has to be modified to produce files to suit a specific application
- * or requirement.
- * </p>
- * @author Mark B
- * @version 1.00 9th April 2010
- *          1.10 13th April 2010 - Added support for processing all Excel
- *                                 workbooks in a folder along with the ability
- *                                 to specify a field separator character.
- *          2.00 14th April 2010 - Added support for embedded characters; the
- *                                 field separator, EOL and double quotes or
- *                                 speech marks. In addition, gave the client
- *                                 the ability to select how these are handled,
- *                                 either obeying Excel's or UNIX formatting
- *                                 conventions.
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public class ToCSV {
-
-    private Workbook workbook;
-    private ArrayList<ArrayList<String>> csvData;
-    private int maxRowWidth;
-    private int formattingConvention;
-    private DataFormatter formatter;
-    private FormulaEvaluator evaluator;
-    private String separator;
-
-    private static final String CSV_FILE_EXTENSION = ".csv";
-    private static final String DEFAULT_SEPARATOR = ",";
-
-    /**
-     * Identifies that the CSV file should obey Excel's formatting conventions
-     * with regard to escaping certain embedded characters - the field separator,
-     * speech mark and end of line (EOL) character
-     */
-    public static final int EXCEL_STYLE_ESCAPING = 0;
-
-    /**
-     * Identifies that the CSV file should obey UNIX formatting conventions
-     * with regard to escaping certain embedded characters - the field separator
-     * and end of line (EOL) character
-     */
-    public static final int UNIX_STYLE_ESCAPING = 1;
-
-    /**
-     * Process the contents of a folder, convert the contents of each Excel
-     * workbook into CSV format and save the resulting file to the specified
-     * folder using the same name as the original workbook with the .xls or
-     * .xlsx extension replaced by .csv. This method will ensure that the
-     * CSV file created contains the comma field separator and that embedded
-     * characters such as the field separator, the EOL and double quotes are
-     * escaped in accordance with Excel's convention.
-     *
-     * @param strSource An instance of the String class that encapsulates the
-     *        name of and path to either a folder containing those Excel
-     *        workbook(s) or the name of and path to an individual Excel workbook
-     *        that is/are to be converted.
-     * @param strDestination An instance of the String class encapsulating the
-     *        name of and path to a folder that will contain the resulting CSV
-     *        files.
-     * @throws java.io.FileNotFoundException Thrown if any file cannot be located
-     *         on the filesystem during processing.
-     * @throws java.io.IOException Thrown if the filesystem encounters any
-     *         problems during processing.
-     * @throws java.lang.IllegalArgumentException Thrown if the values passed
-     *         to the strSource parameter refers to a file or folder that does not
-     *         exist or if the value passed to the strDestination paramater refers
-     *         to a folder that does not exist or simply does not refer to a
-     *         folder.
-     */
-    public void convertExcelToCSV(String strSource, String strDestination)
-                       throws FileNotFoundException, IOException,
-                              IllegalArgumentException {
-
-        // Simply chain the call to the overloaded convertExcelToCSV(String,
-        // String, String, int) method, pass the default separator and ensure
-        // that certain embedded characters are escaped in accordance with
-        // Excel's formatting conventions
-        this.convertExcelToCSV(strSource, strDestination,
-                ToCSV.DEFAULT_SEPARATOR, ToCSV.EXCEL_STYLE_ESCAPING);
-    }
-
-    /**
-     * Process the contents of a folder, convert the contents of each Excel
-     * workbook into CSV format and save the resulting file to the specified
-     * folder using the same name as the original workbook with the .xls or
-     * .xlsx extension replaced by .csv. This method allows the client to
-     * define the field separator but will ensure that embedded characters such
-     * as the field separator, the EOL and double quotes are escaped in
-     * accordance with Excel's convention.
-     *
-     * @param strSource An instance of the String class that encapsulates the
-     *        name of and path to either a folder containing those Excel
-     *        workbook(s) or the name of and path to an individual Excel workbook
-     *        that is/are to be converted.
-     * @param strDestination An instance of the String class encapsulating the
-     *        name of and path to a folder that will contain the resulting CSV
-     *        files.
-     * @param separator An instance of the String class that encapsulates the
-     *        character or characters the client wishes to use as the field
-     *        separator.
-     * @throws java.io.FileNotFoundException Thrown if any file cannot be located
-     *         on the filesystem during processing.
-     * @throws java.io.IOException Thrown if the filesystem encounters any
-     *         problems during processing.
-     * @throws java.lang.IllegalArgumentException Thrown if the values passed
-     *         to the strSource parameter refers to a file or folder that does not
-     *         exist or if the value passed to the strDestination paramater refers
-     *         to a folder that does not exist or simply does not refer to a
-     *         folder.
-     */
-    public void convertExcelToCSV(String strSource, String strDestination,
-                                  String separator)
-                       throws FileNotFoundException, IOException,
-                              IllegalArgumentException {
-
-        // Simply chain the call to the overloaded convertExcelToCSV(String,
-        // String, String, int) method and ensure that certain embedded
-        // characters are escaped in accordance with Excel's formatting
-        // conventions
-        this.convertExcelToCSV(strSource, strDestination,
-                separator, ToCSV.EXCEL_STYLE_ESCAPING);
-    }
-
-    /**
-     * Process the contents of a folder, convert the contents of each Excel
-     * workbook into CSV format and save the resulting file to the specified
-     * folder using the same name as the original workbook with the .xls or
-     * .xlsx extension replaced by .csv
-     *
-     * @param strSource An instance of the String class that encapsulates the
-     *        name of and path to either a folder containing those Excel
-     *        workbook(s) or the name of and path to an individual Excel workbook
-     *        that is/are to be converted.
-     * @param strDestination An instance of the String class encapsulating the name
-     *        of and path to a folder that will contain the resulting CSV files.
-     * @param formattingConvention A primitive int whose value will determine
-     *        whether certain embedded characters should be escaped in accordance
-     *        with Excel's or UNIX formatting conventions. Two constants are
-     *        defined to support this option; ToCSV.EXCEL_STYLE_ESCAPING and
-     *        ToCSV.UNIX_STYLE_ESCAPING
-     * @param separator An instance of the String class encapsulating the
-     *        characters or characters that should be used to separate items
-     *        on a line within the CSV file.
-     * @throws java.io.FileNotFoundException Thrown if any file cannot be located
-     *         on the filesystem during processing.
-     * @throws java.io.IOException Thrown if the filesystem encounters any
-     *         problems during processing.
-     * @throws java.lang.IllegalArgumentException Thrown if the values passed
-     *         to the strSource parameter refers to a file or folder that does not
-     *         exist, if the value passed to the strDestination paramater refers
-     *         to a folder that does not exist,  if the value passed to the
-     *         strDestination parameter does not refer to a folder or if the
-     *         value passed to the formattingConvention parameter is other than
-     *         one of the values defined by the constants ToCSV.EXCEL_STYLE_ESCAPING
-     *         and ToCSV.UNIX_STYLE_ESCAPING.
-     */
-    public void convertExcelToCSV(String strSource, String strDestination,
-                                  String separator, int formattingConvention)
-                       throws FileNotFoundException, IOException,
-                              IllegalArgumentException {
-        // Check that the source file/folder exists.
-        File source = new File(strSource);
-        if(!source.exists()) {
-            throw new IllegalArgumentException("The source for the Excel " +
-                    "file(s) cannot be found at " + source);
-        }
-
-        // Ensure thaat the folder the user has chosen to save the CSV files
-        // away into firstly exists and secondly is a folder rather than, for
-        // instance, a data file.
-        File destination = new File(strDestination);
-        if(!destination.exists()) {
-            throw new IllegalArgumentException("The destination directory " + destination + " for the " +
-                    "converted CSV file(s) does not exist.");
-        }
-        if(!destination.isDirectory()) {
-            throw new IllegalArgumentException("The destination " + destination + " for the CSV " +
-                    "file(s) is not a directory/folder.");
-        }
-
-        // Ensure the value passed to the formattingConvention parameter is
-        // within range.
-        if(formattingConvention != ToCSV.EXCEL_STYLE_ESCAPING &&
-           formattingConvention != ToCSV.UNIX_STYLE_ESCAPING) {
-            throw new IllegalArgumentException("The value passed to the " +
-                    "formattingConvention parameter is out of range: " + formattingConvention + ", expecting one of " +
-                    ToCSV.EXCEL_STYLE_ESCAPING + " or " + ToCSV.UNIX_STYLE_ESCAPING);
-        }
-
-        // Copy the spearator character and formatting convention into local
-        // variables for use in other methods.
-        this.separator = separator;
-        this.formattingConvention = formattingConvention;
-
-        // Check to see if the sourceFolder variable holds a reference to
-        // a file or a folder full of files.
-        final File[] filesList;
-        if(source.isDirectory()) {
-            // Get a list of all of the Excel spreadsheet files (workbooks) in
-            // the source folder/directory
-            filesList = source.listFiles(new ExcelFilenameFilter());
-        }
-        else {
-            // Assume that it must be a file handle - although there are other
-            // options the code should perhaps check - and store the reference
-            // into the filesList variable.
-            filesList = new File[]{source};
-        }
-
-        // Step through each of the files in the source folder and for each
-        // open the workbook, convert it's contents to CSV format and then
-        // save the resulting file away into the folder specified by the
-        // contents of the destination variable. Note that the name of the
-        // csv file will be created by taking the name of the Excel file,
-        // removing the extension and replacing it with .csv. Note that there
-        // is one drawback with this approach; if the folder holding the files
-        // contains two workbooks whose names match but one is a binary file
-        // (.xls) and the other a SpreadsheetML file (.xlsx), then the names
-        // for both CSV files will be identical and one CSV file will,
-        // therefore, over-write the other.
-        if (filesList != null) {
-            for(File excelFile : filesList) {
-                // Open the workbook
-                this.openWorkbook(excelFile);
-
-                // Convert it's contents into a CSV file
-                this.convertToCSV();
-
-                // Build the name of the csv folder from that of the Excel workbook.
-                // Simply replace the .xls or .xlsx file extension with .csv
-                String destinationFilename = excelFile.getName();
-                destinationFilename = destinationFilename.substring(
-                        0, destinationFilename.lastIndexOf('.')) +
-                        ToCSV.CSV_FILE_EXTENSION;
-
-                // Save the CSV file away using the newly constricted file name
-                // and to the specified directory.
-                this.saveCSVFile(new File(destination, destinationFilename));
-            }
-        }
-    }
-
-    /**
-     * Open an Excel workbook ready for conversion.
-     *
-     * @param file An instance of the File class that encapsulates a handle
-     *        to a valid Excel workbook. Note that the workbook can be in
-     *        either binary (.xls) or SpreadsheetML (.xlsx) format.
-     * @throws java.io.FileNotFoundException Thrown if the file cannot be located.
-     * @throws java.io.IOException Thrown if a problem occurs in the file system.
-     */
-    private void openWorkbook(File file) throws FileNotFoundException,
-                                           IOException {
-        System.out.println("Opening workbook [" + file.getName() + "]");
-        try (FileInputStream fis = new FileInputStream(file)) {
-
-            // Open the workbook and then create the FormulaEvaluator and
-            // DataFormatter instances that will be needed to, respectively,
-            // force evaluation of forumlae found in cells and create a
-            // formatted String encapsulating the cells contents.
-            this.workbook = WorkbookFactory.create(fis);
-            this.evaluator = this.workbook.getCreationHelper().createFormulaEvaluator();
-            this.formatter = new DataFormatter(true);
-        }
-    }
-
-    /**
-     * Called to convert the contents of the currently opened workbook into
-     * a CSV file.
-     */
-    private void convertToCSV() {
-        Sheet sheet;
-        Row row;
-        int lastRowNum;
-        this.csvData = new ArrayList<>();
-
-        System.out.println("Converting files contents to CSV format.");
-
-        // Discover how many sheets there are in the workbook....
-        int numSheets = this.workbook.getNumberOfSheets();
-
-        // and then iterate through them.
-        for(int i = 0; i < numSheets; i++) {
-
-            // Get a reference to a sheet and check to see if it contains
-            // any rows.
-            sheet = this.workbook.getSheetAt(i);
-            if(sheet.getPhysicalNumberOfRows() > 0) {
-                // Note down the index number of the bottom-most row and
-                // then iterate through all of the rows on the sheet starting
-                // from the very first row - number 1 - even if it is missing.
-                // Recover a reference to the row and then call another method
-                // which will strip the data from the cells and build lines
-                // for inclusion in the resylting CSV file.
-                lastRowNum = sheet.getLastRowNum();
-                for(int j = 0; j <= lastRowNum; j++) {
-                    row = sheet.getRow(j);
-                    this.rowToCSV(row);
-                }
-            }
-        }
-    }
-
-    /**
-     * Called to actually save the data recovered from the Excel workbook
-     * as a CSV file.
-     *
-     * @param file An instance of the File class that encapsulates a handle
-     *             referring to the CSV file.
-     * @throws java.io.FileNotFoundException Thrown if the file cannot be found.
-     * @throws java.io.IOException Thrown to indicate and error occurred in the
-     *                             underylying file system.
-     */
-    private void saveCSVFile(File file) throws FileNotFoundException, IOException {
-        ArrayList<String> line;
-        StringBuilder buffer;
-        String csvLineElement;
-
-        // Open a writer onto the CSV file.
-        try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
-
-            System.out.println("Saving the CSV file [" + file.getName() + "]");
-
-            // Step through the elements of the ArrayList that was used to hold
-            // all of the data recovered from the Excel workbooks' sheets, rows
-            // and cells.
-            for(int i = 0; i < this.csvData.size(); i++) {
-                buffer = new StringBuilder();
-
-                // Get an element from the ArrayList that contains the data for
-                // the workbook. This element will itself be an ArrayList
-                // containing Strings and each String will hold the data recovered
-                // from a single cell. The for() loop is used to recover elements
-                // from this 'row' ArrayList one at a time and to write the Strings
-                // away to a StringBuilder thus assembling a single line for inclusion
-                // in the CSV file. If a row was empty or if it was short, then
-                // the ArrayList that contains it's data will also be shorter than
-                // some of the others. Therefore, it is necessary to check within
-                // the for loop to ensure that the ArrayList contains data to be
-                // processed. If it does, then an element will be recovered and
-                // appended to the StringBuilder.
-                line = this.csvData.get(i);
-                for(int j = 0; j < this.maxRowWidth; j++) {
-                    if(line.size() > j) {
-                        csvLineElement = line.get(j);
-                        if(csvLineElement != null) {
-                            buffer.append(this.escapeEmbeddedCharacters(
-                                    csvLineElement));
-                        }
-                    }
-                    if(j < (this.maxRowWidth - 1)) {
-                        buffer.append(this.separator);
-                    }
-                }
-
-                // Once the line is built, write it away to the CSV file.
-                bw.write(buffer.toString().trim());
-
-                // Condition the inclusion of new line characters so as to
-                // avoid an additional, superfluous, new line at the end of
-                // the file.
-                if(i < (this.csvData.size() - 1)) {
-                    bw.newLine();
-                }
-            }
-        }
-    }
-
-    /**
-     * Called to convert a row of cells into a line of data that can later be
-     * output to the CSV file.
-     *
-     * @param row An instance of either the HSSFRow or XSSFRow classes that
-     *            encapsulates information about a row of cells recovered from
-     *            an Excel workbook.
-     */
-    private void rowToCSV(Row row) {
-        Cell cell;
-        int lastCellNum;
-        ArrayList<String> csvLine = new ArrayList<>();
-
-        // Check to ensure that a row was recovered from the sheet as it is
-        // possible that one or more rows between other populated rows could be
-        // missing - blank. If the row does contain cells then...
-        if(row != null) {
-
-            // Get the index for the right most cell on the row and then
-            // step along the row from left to right recovering the contents
-            // of each cell, converting that into a formatted String and
-            // then storing the String into the csvLine ArrayList.
-            lastCellNum = row.getLastCellNum();
-            for(int i = 0; i <= lastCellNum; i++) {
-                cell = row.getCell(i);
-                if(cell == null) {
-                    csvLine.add("");
-                }
-                else {
-                    if(cell.getCellType() != CellType.FORMULA) {
-                        csvLine.add(this.formatter.formatCellValue(cell));
-                    }
-                    else {
-                        csvLine.add(this.formatter.formatCellValue(cell, this.evaluator));
-                    }
-                }
-            }
-            // Make a note of the index number of the right most cell. This value
-            // will later be used to ensure that the matrix of data in the CSV file
-            // is square.
-            if(lastCellNum > this.maxRowWidth) {
-                this.maxRowWidth = lastCellNum;
-            }
-        }
-        this.csvData.add(csvLine);
-    }
-
-    /**
-     * Checks to see whether the field - which consists of the formatted
-     * contents of an Excel worksheet cell encapsulated within a String - contains
-     * any embedded characters that must be escaped. The method is able to
-     * comply with either Excel's or UNIX formatting conventions in the
-     * following manner;
-     *
-     * With regard to UNIX conventions, if the field contains any embedded
-     * field separator or EOL characters they will each be escaped by prefixing
-     * a leading backspace character. These are the only changes that have yet
-     * emerged following some research as being required.
-     *
-     * Excel has other embedded character escaping requirements, some that emerged
-     * from empirical testing, other through research. Firstly, with regards to
-     * any embedded speech marks ("), each occurrence should be escaped with
-     * another speech mark and the whole field then surrounded with speech marks.
-     * Thus if a field holds <em>"Hello" he said</em> then it should be modified
-     * to appear as <em>"""Hello"" he said"</em>. Furthermore, if the field
-     * contains either embedded separator or EOL characters, it should also
-     * be surrounded with speech marks. As a result <em>1,400</em> would become
-     * <em>"1,400"</em> assuming that the comma is the required field separator.
-     * This has one consequence in, if a field contains embedded speech marks
-     * and embedded separator characters, checks for both are not required as the
-     * additional set of speech marks that should be placed around ay field
-     * containing embedded speech marks will also account for the embedded
-     * separator.
-     *
-     * It is worth making one further note with regard to embedded EOL
-     * characters. If the data in a worksheet is exported as a CSV file using
-     * Excel itself, then the field will be surounded with speech marks. If the
-     * resulting CSV file is then re-imports into another worksheet, the EOL
-     * character will result in the original simgle field occupying more than
-     * one cell. This same 'feature' is replicated in this classes behaviour.
-     *
-     * @param field An instance of the String class encapsulating the formatted
-     *        contents of a cell on an Excel worksheet.
-     * @return A String that encapsulates the formatted contents of that
-     *         Excel worksheet cell but with any embedded separator, EOL or
-     *         speech mark characters correctly escaped.
-     */
-    private String escapeEmbeddedCharacters(String field) {
-        StringBuilder buffer;
-
-        // If the fields contents should be formatted to confrom with Excel's
-        // convention....
-        if(this.formattingConvention == ToCSV.EXCEL_STYLE_ESCAPING) {
-
-            // Firstly, check if there are any speech marks (") in the field;
-            // each occurrence must be escaped with another set of spech marks
-            // and then the entire field should be enclosed within another
-            // set of speech marks. Thus, "Yes" he said would become
-            // """Yes"" he said"
-            if(field.contains("\"")) {
-                buffer = new StringBuilder(field.replaceAll("\"", "\\\"\\\""));
-                buffer.insert(0, "\"");
-                buffer.append("\"");
-            }
-            else {
-                // If the field contains either embedded separator or EOL
-                // characters, then escape the whole field by surrounding it
-                // with speech marks.
-                buffer = new StringBuilder(field);
-                if((buffer.indexOf(this.separator)) > -1 ||
-                         (buffer.indexOf("\n")) > -1) {
-                    buffer.insert(0, "\"");
-                    buffer.append("\"");
-                }
-            }
-            return(buffer.toString().trim());
-        }
-        // The only other formatting convention this class obeys is the UNIX one
-        // where any occurrence of the field separator or EOL character will
-        // be escaped by preceding it with a backslash.
-        else {
-            if(field.contains(this.separator)) {
-                field = field.replaceAll(this.separator, ("\\\\" + this.separator));
-            }
-            if(field.contains("\n")) {
-                field = field.replaceAll("\n", "\\\\\n");
-            }
-            return(field);
-        }
-    }
-
-    /**
-     * The main() method contains code that demonstrates how to use the class.
-     *
-     * @param args An array containing zero, one or more elements all of type
-     *        String. Each element will encapsulate an argument specified by the
-     *        user when running the program from the command prompt.
-     */
-    public static void main(String[] args) {
-        // Check the number of arguments passed to the main method. There
-        // must be two, three or four; the name of and path to either the folder
-        // containing the Excel files or an individual Excel workbook that is/are
-        // to be converted, the name of and path to the folder to which the CSV
-        // files should be written, - optionally - the separator character
-        // that should be used to separate individual items (fields) on the
-        // lines (records) of the CSV file and - again optionally - an integer
-        // that idicates whether the CSV file ought to obey Excel's or UNIX
-        // convnetions with regard to formatting fields that contain embedded
-        // separator, Speech mark or EOL character(s).
-        //
-        // Note that the names of the CSV files will be derived from those
-        // of the Excel file(s). Put simply the .xls or .xlsx extension will be
-        // replaced with .csv. Therefore, if the source folder contains files
-        // with matching names but different extensions - Test.xls and Test.xlsx
-        // for example - then the CSV file generated from one will overwrite
-        // that generated from the other.
-        ToCSV converter;
-        boolean converted = true;
-        long startTime = System.currentTimeMillis();
-        try {
-            converter = new ToCSV();
-            if(args.length == 2) {
-                // Just the Source File/Folder and Destination Folder were
-                // passed to the main method.
-                converter.convertExcelToCSV(args[0], args[1]);
-            }
-            else if(args.length == 3) {
-                // The Source File/Folder, Destination Folder and Separator
-                // were passed to the main method.
-                converter.convertExcelToCSV(args[0], args[1], args[2]);
-            }
-            else if(args.length == 4) {
-                // The Source File/Folder, Destination Folder, Separator and
-                // Formatting Convnetion were passed to the main method.
-                converter.convertExcelToCSV(args[0], args[1],
-                                            args[2], Integer.parseInt(args[3]));
-            }
-            else {
-                // None or more than four parameters were passed so display
-                //a Usage message.
-                System.out.println("Usage: java ToCSV [Source File/Folder] " +
-                    "[Destination Folder] [Separator] [Formatting Convention]\n" +
-                    "\tSource File/Folder\tThis argument should contain the name of and\n" +
-                    "\t\t\t\tpath to either a single Excel workbook or a\n" +
-                    "\t\t\t\tfolder containing one or more Excel workbooks.\n" +
-                    "\tDestination Folder\tThe name of and path to the folder that the\n" +
-                    "\t\t\t\tCSV files should be written out into. The\n" +
-                    "\t\t\t\tfolder must exist before running the ToCSV\n" +
-                    "\t\t\t\tcode as it will not check for or create it.\n" +
-                    "\tSeparator\t\tOptional. The character or characters that\n" +
-                    "\t\t\t\tshould be used to separate fields in the CSV\n" +
-                    "\t\t\t\trecord. If no value is passed then the comma\n" +
-                    "\t\t\t\twill be assumed.\n" +
-                    "\tFormatting Convention\tOptional. This argument can take one of two\n" +
-                    "\t\t\t\tvalues. Passing 0 (zero) will result in a CSV\n" +
-                    "\t\t\t\tfile that obeys Excel's formatting conventions\n" +
-                    "\t\t\t\twhilst passing 1 (one) will result in a file\n" +
-                    "\t\t\t\tthat obeys UNIX formatting conventions. If no\n" +
-                    "\t\t\t\tvalue is passed, then the CSV file produced\n" +
-                    "\t\t\t\twill obey Excel's formatting conventions.");
-                converted = false;
-            }
-        }
-        // It is not wise to have such a wide catch clause - Exception is very
-        // close to being at the top of the inheritance hierarchy - though it
-        // will suffice for this example as it is really not possible to recover
-        // easilly from an exceptional set of circumstances at this point in the
-        // program. It should however, ideally be replaced with one or more
-        // catch clauses optimised to handle more specific problems.
-        catch(Exception ex) {
-            System.out.println("Caught an: " + ex.getClass().getName());
-            System.out.println("Message: " + ex.getMessage());
-            System.out.println("Stacktrace follows:.....");
-            ex.printStackTrace(System.out);
-            converted = false;
-        }
-
-        if (converted) {
-            System.out.println("Conversion took " +
-                  ((System.currentTimeMillis() - startTime)/1000) + " seconds");
-        }
-    }
-
-    /**
-     * An instance of this class can be used to control the files returned
-     * be a call to the listFiles() method when made on an instance of the
-     * File class and that object refers to a folder/directory
-     */
-    static class ExcelFilenameFilter implements FilenameFilter {
-
-        /**
-         * Determine those files that will be returned by a call to the
-         * listFiles() method. In this case, the name of the file must end with
-         * either of the following two extension; '.xls' or '.xlsx'. For the
-         * future, it is very possible to parameterise this and allow the
-         * containing class to pass, for example, an array of Strings to this
-         * class on instantiation. Each element in that array could encapsulate
-         * a valid file extension - '.xls', '.xlsx', '.xlt', '.xlst', etc. These
-         * could then be used to control which files were returned by the call
-         * to the listFiles() method.
-         *
-         * @param file An instance of the File class that encapsulates a handle
-         *             referring to the folder/directory that contains the file.
-         * @param name An instance of the String class that encapsulates the
-         *             name of the file.
-         * @return A boolean value that indicates whether the file should be
-         *         included in the array retirned by the call to the listFiles()
-         *         method. In this case true will be returned if the name of the
-         *         file ends with either '.xls' or '.xlsx' and false will be
-         *         returned in all other instances.
-         */
-        @Override
-        public boolean accept(File file, String name) {
-            return(name.endsWith(".xls") || name.endsWith(".xlsx"));
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/formula/CalculateMortgage.java b/src/examples/src/org/apache/poi/ss/examples/formula/CalculateMortgage.java
deleted file mode 100644 (file)
index 678776c..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.examples.formula;
-
-import org.apache.poi.ss.formula.OperationEvaluationContext ;
-import org.apache.poi.ss.formula.eval.ErrorEval ;
-import org.apache.poi.ss.formula.eval.EvaluationException ;
-import org.apache.poi.ss.formula.eval.NumberEval ;
-import org.apache.poi.ss.formula.eval.OperandResolver ;
-import org.apache.poi.ss.formula.eval.ValueEval ;
-import org.apache.poi.ss.formula.functions.FreeRefFunction ;
-
-/**
- * A simple user-defined function to calculate principal and interest.
- * 
- * @author Jon Svede ( jon [at] loquatic [dot] com )
- * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
- *
- */
-public class CalculateMortgage implements FreeRefFunction {
-
-    @Override
-    public ValueEval evaluate( ValueEval[] args, OperationEvaluationContext ec ) {
-        
-        // verify that we have enough data
-        if (args.length != 3) {  
-            return ErrorEval.VALUE_INVALID;
-        }
-
-        // declare doubles for values
-        double principal, rate, years,  result;
-        try {
-            // extract values as ValueEval
-            ValueEval v1 = OperandResolver.getSingleValue( args[0], 
-                                                           ec.getRowIndex(), 
-                                                           ec.getColumnIndex() ) ;
-            ValueEval v2 = OperandResolver.getSingleValue( args[1], 
-                                                           ec.getRowIndex(), 
-                                                           ec.getColumnIndex() ) ;
-            ValueEval v3 = OperandResolver.getSingleValue( args[2], 
-                                                           ec.getRowIndex(), 
-                                                           ec.getColumnIndex() ) ;
-
-            // get data as doubles
-            principal  = OperandResolver.coerceValueToDouble( v1 ) ; 
-            rate  = OperandResolver.coerceValueToDouble( v2 ) ;
-            years = OperandResolver.coerceValueToDouble( v3 ) ;
-            
-            result = calculateMortgagePayment( principal, rate, years ) ;
-            System.out.println( "Result = " + result ) ;
-
-            checkValue(result);
-            
-        } catch (EvaluationException e) {
-            return e.getErrorEval();
-        }
-
-        return new NumberEval( result ) ;
-    }
-    
-    public double calculateMortgagePayment( double p, double r, double y ) {
-        double i = r / 12 ;
-        double n = y * 12 ;
-
-        return p * (( i * Math.pow((1 + i),n ) ) / ( Math.pow((1 + i),n) - 1));
-    }
-    /**
-     * Excel does not support infinities and NaNs, rather, it gives a #NUM! error in these cases
-     *
-     * @throws EvaluationException (#NUM!) if <tt>result</tt> is <tt>NaN</> or <tt>Infinity</tt>
-     */
-     private void checkValue(double result) throws EvaluationException {
-         if (Double.isNaN(result) || Double.isInfinite(result)) {
-             throw new EvaluationException(ErrorEval.NUM_ERROR);
-         }
-     }    
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/formula/CheckFunctionsSupported.java b/src/examples/src/org/apache/poi/ss/examples/formula/CheckFunctionsSupported.java
deleted file mode 100644 (file)
index d2291f0..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.examples.formula;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-import org.apache.poi.ss.formula.eval.NotImplementedException;
-import org.apache.poi.ss.formula.eval.NotImplementedFunctionException;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
-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.WorkbookFactory;
-import org.apache.poi.ss.util.CellReference;
-
-/**
- * Attempts to re-evaluate all the formulas in the workbook, and
- *  reports what (if any) formula functions used are not (currently)
- *  supported by Apache POI.
- *
- * <p>This provides examples of how to evaluate formulas in excel
- *  files using Apache POI, along with how to handle errors whilst
- *  doing so.
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public class CheckFunctionsSupported {
-    public static void main(String[] args) throws Exception {
-        if (args.length < 1) {
-            System.err.println("Use:");
-            System.err.println("  CheckFunctionsSupported <filename>");
-            return;
-        }
-
-        Workbook wb = WorkbookFactory.create(new File(args[0]));
-        CheckFunctionsSupported check = new CheckFunctionsSupported(wb);
-
-        // Fetch all the problems
-        List<FormulaEvaluationProblems> problems = new ArrayList<>();
-        for (int sn=0; sn<wb.getNumberOfSheets(); sn++) {
-            problems.add(check.getEvaluationProblems(sn));
-        }
-
-        // Produce an overall summary
-        Set<String> unsupportedFunctions = new TreeSet<>();
-        for (FormulaEvaluationProblems p : problems) {
-            unsupportedFunctions.addAll(p.unsupportedFunctions);
-        }
-        if (unsupportedFunctions.isEmpty()) {
-            System.out.println("There are no unsupported formula functions used");
-        } else {
-            System.out.println("Unsupported formula functions:");
-            for (String function : unsupportedFunctions) {
-                System.out.println("  " + function);
-            }
-            System.out.println("Total unsupported functions = " + unsupportedFunctions.size());
-        }
-
-        // Report sheet by sheet
-        for (int sn=0; sn<wb.getNumberOfSheets(); sn++) {
-            String sheetName = wb.getSheetName(sn);
-            FormulaEvaluationProblems probs = problems.get(sn);
-
-            System.out.println();
-            System.out.println("Sheet = " + sheetName);
-
-            if (probs.unevaluatableCells.isEmpty()) {
-                System.out.println(" All cells evaluated without error");
-            } else {
-                for (CellReference cr : probs.unevaluatableCells.keySet()) {
-                    System.out.println(" " + cr.formatAsString() + " - " +
-                            probs.unevaluatableCells.get(cr));
-                }
-            }
-        }
-    }
-
-    private final Workbook workbook;
-    private final FormulaEvaluator evaluator;
-    public CheckFunctionsSupported(Workbook workbook) {
-        this.workbook = workbook;
-        this.evaluator = workbook.getCreationHelper().createFormulaEvaluator();
-    }
-
-    public Set<String> getUnsupportedFunctions(String sheetName) {
-        return getUnsupportedFunctions(workbook.getSheet(sheetName));
-    }
-    public Set<String> getUnsupportedFunctions(int sheetIndex) {
-        return getUnsupportedFunctions(workbook.getSheetAt(sheetIndex));
-    }
-    public Set<String> getUnsupportedFunctions(Sheet sheet) {
-        FormulaEvaluationProblems problems = getEvaluationProblems(sheet);
-        return problems.unsupportedFunctions;
-    }
-
-    public FormulaEvaluationProblems getEvaluationProblems(String sheetName) {
-        return getEvaluationProblems(workbook.getSheet(sheetName));
-    }
-    public FormulaEvaluationProblems getEvaluationProblems(int sheetIndex) {
-        return getEvaluationProblems(workbook.getSheetAt(sheetIndex));
-    }
-    public FormulaEvaluationProblems getEvaluationProblems(Sheet sheet) {
-        Set<String> unsupportedFunctions = new HashSet<>();
-        Map<CellReference,Exception> unevaluatableCells = new HashMap<>();
-
-        for (Row r : sheet) {
-            for (Cell c : r) {
-                try {
-                    evaluator.evaluate(c);
-                } catch (Exception e) {
-                    if (e instanceof NotImplementedException && e.getCause() != null) {
-                        // Has been wrapped with cell details, but we know those
-                        e = (Exception)e.getCause();
-                    }
-
-                    if (e instanceof NotImplementedFunctionException) {
-                        NotImplementedFunctionException nie = (NotImplementedFunctionException)e;
-                        unsupportedFunctions.add(nie.getFunctionName());
-                    }
-                    unevaluatableCells.put(new CellReference(c), e);
-                }
-            }
-        }
-
-        return new FormulaEvaluationProblems(unsupportedFunctions, unevaluatableCells);
-    }
-
-    public static class FormulaEvaluationProblems {
-        /** Which used functions are unsupported by POI at this time */
-        private final Set<String> unsupportedFunctions;
-        /** Which cells had unevaluatable formulas, and why? */
-        private final Map<CellReference,Exception> unevaluatableCells;
-
-        protected FormulaEvaluationProblems(Set<String> unsupportedFunctions,
-                             Map<CellReference, Exception> unevaluatableCells) {
-            this.unsupportedFunctions = Collections.unmodifiableSet(unsupportedFunctions);
-            this.unevaluatableCells = Collections.unmodifiableMap(unevaluatableCells);
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/formula/SettingExternalFunction.java b/src/examples/src/org/apache/poi/ss/examples/formula/SettingExternalFunction.java
deleted file mode 100644 (file)
index 992d0f0..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.ss.examples.formula;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-import org.apache.poi.ss.formula.OperationEvaluationContext;
-import org.apache.poi.ss.formula.eval.ErrorEval;
-import org.apache.poi.ss.formula.eval.ValueEval;
-import org.apache.poi.ss.formula.functions.FreeRefFunction;
-import org.apache.poi.ss.formula.udf.UDFFinder;
-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.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Demonstrates how to use functions provided by third-party add-ins, e.g. Bloomberg Excel Add-in.
- *
- * There can be situations when you are not interested in formula evaluation,
- * you just need to set the formula  and the workbook will be evaluation by the client.
- */
-public class SettingExternalFunction {
-
-    /**
-     * wrap external functions in a plugin
-     */
-    public static class BloombergAddIn implements UDFFinder {
-        private final Map<String, FreeRefFunction> _functionsByName;
-
-        public BloombergAddIn() {
-            // dummy function that returns NA
-            // don't care about the implementation, we are not interested in evaluation
-            // and this method will never be called
-            FreeRefFunction NA = new FreeRefFunction() {
-                @Override
-                public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
-                    return ErrorEval.NA;
-                }
-            };
-            _functionsByName = new HashMap<>();
-            _functionsByName.put("BDP", NA);
-            _functionsByName.put("BDH", NA);
-            _functionsByName.put("BDS", NA);
-        }
-
-        @Override
-        public FreeRefFunction findFunction(String name) {
-            return _functionsByName.get(name.toUpperCase(Locale.ROOT));
-        }
-
-    }
-
-    public static void main( String[] args ) throws IOException {
-
-        try (Workbook wb = new XSSFWorkbook()) {  // or new HSSFWorkbook()
-
-            // register the add-in
-            wb.addToolPack(new BloombergAddIn());
-
-            Sheet sheet = wb.createSheet();
-            Row row = sheet.createRow(0);
-            row.createCell(0).setCellFormula("BDP(\"GOOG Equity\",\"CHG_PCT_YTD\")/100");
-            row.createCell(1).setCellFormula("BDH(\"goog us equity\",\"EBIT\",\"1/1/2005\",\"12/31/2009\",\"per=cy\",\"curr=USD\") ");
-            row.createCell(2).setCellFormula("BDS(\"goog us equity\",\"top_20_holders_public_filings\") ");
-
-            try (FileOutputStream out = new FileOutputStream("bloomberg-demo.xlsx")) {
-                wb.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/formula/UserDefinedFunctionExample.java b/src/examples/src/org/apache/poi/ss/examples/formula/UserDefinedFunctionExample.java
deleted file mode 100644 (file)
index 7f5922b..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.examples.formula;
-
-import java.io.File;
-
-import org.apache.poi.ss.formula.functions.FreeRefFunction;
-import org.apache.poi.ss.formula.udf.DefaultUDFFinder;
-import org.apache.poi.ss.formula.udf.UDFFinder;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellValue;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
-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.WorkbookFactory;
-import org.apache.poi.ss.util.CellReference;
-
-
-/**
- * An example class of how to invoke a User Defined Function for a given
- * XLS instance using POI's UDFFinder implementation.
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class UserDefinedFunctionExample {
-
-    private UserDefinedFunctionExample() {}
-
-    public static void main(String[] args ) throws Exception {
-
-        if(  args.length != 2 ) {
-            // e.g. src/examples/src/org/apache/poi/ss/examples/formula/mortgage-calculation.xls Sheet1!B4
-            System.out.println( "usage: UserDefinedFunctionExample fileName cellId" ) ;
-            return;
-        }
-
-        System.out.println( "fileName: " + args[0] ) ;
-        System.out.println( "cell: " + args[1] ) ;
-
-        File workbookFile = new File( args[0] ) ;
-
-        try (Workbook workbook = WorkbookFactory.create(workbookFile, null, true)) {
-            String[] functionNames = {"calculatePayment"};
-            FreeRefFunction[] functionImpls = {new CalculateMortgage()};
-
-            UDFFinder udfToolpack = new DefaultUDFFinder(functionNames, functionImpls);
-
-            // register the user-defined function in the workbook
-            workbook.addToolPack(udfToolpack);
-
-            FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
-
-            CellReference cr = new CellReference(args[1]);
-            String sheetName = cr.getSheetName();
-            Sheet sheet = workbook.getSheet(sheetName);
-            int rowIdx = cr.getRow();
-            int colIdx = cr.getCol();
-            Row row = sheet.getRow(rowIdx);
-            Cell cell = row.getCell(colIdx);
-
-            CellValue value = evaluator.evaluate(cell);
-
-            System.out.println("returns value: " + value);
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/formula/mortgage-calculation.xls b/src/examples/src/org/apache/poi/ss/examples/formula/mortgage-calculation.xls
deleted file mode 100644 (file)
index 4e71ba8..0000000
Binary files a/src/examples/src/org/apache/poi/ss/examples/formula/mortgage-calculation.xls and /dev/null differ
diff --git a/src/examples/src/org/apache/poi/ss/examples/html/HSSFHtmlHelper.java b/src/examples/src/org/apache/poi/ss/examples/html/HSSFHtmlHelper.java
deleted file mode 100644 (file)
index e7c4ea6..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.examples.html;
-
-import java.util.Formatter;
-
-import org.apache.poi.hssf.usermodel.HSSFCellStyle;
-import org.apache.poi.hssf.usermodel.HSSFPalette;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.util.HSSFColor;
-import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
-import org.apache.poi.ss.usermodel.CellStyle;
-
-/**
- * Implementation of {@link HtmlHelper} for HSSF files.
- */
-public class HSSFHtmlHelper implements HtmlHelper {
-    private final HSSFWorkbook wb;
-    private final HSSFPalette colors;
-
-    private static final HSSFColor HSSF_AUTO = HSSFColorPredefined.AUTOMATIC.getColor();
-
-    public HSSFHtmlHelper(HSSFWorkbook wb) {
-        this.wb = wb;
-        // If there is no custom palette, then this creates a new one that is
-        // a copy of the default
-        colors = wb.getCustomPalette();
-    }
-
-    @Override
-    public void colorStyles(CellStyle style, Formatter out) {
-        HSSFCellStyle cs = (HSSFCellStyle) style;
-        out.format("  /* fill pattern = %d */%n", cs.getFillPattern().getCode());
-        styleColor(out, "background-color", cs.getFillForegroundColor());
-        styleColor(out, "color", cs.getFont(wb).getColor());
-        styleColor(out, "border-left-color", cs.getLeftBorderColor());
-        styleColor(out, "border-right-color", cs.getRightBorderColor());
-        styleColor(out, "border-top-color", cs.getTopBorderColor());
-        styleColor(out, "border-bottom-color", cs.getBottomBorderColor());
-    }
-
-    private void styleColor(Formatter out, String attr, short index) {
-        HSSFColor color = colors.getColor(index);
-        if (index == HSSF_AUTO.getIndex() || color == null) {
-            out.format("  /* %s: index = %d */%n", attr, index);
-        } else {
-            short[] rgb = color.getTriplet();
-            out.format("  %s: #%02x%02x%02x; /* index = %d */%n", attr, rgb[0],
-                    rgb[1], rgb[2], index);
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/ss/examples/html/HtmlHelper.java b/src/examples/src/org/apache/poi/ss/examples/html/HtmlHelper.java
deleted file mode 100644 (file)
index 2cb1a91..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.examples.html;
-
-import org.apache.poi.ss.usermodel.CellStyle;
-
-import java.util.Formatter;
-
-/**
- * This interface is used where code wants to be independent of the workbook
- * formats.  If you are writing such code, you can add a method to this
- * interface, and then implement it for both HSSF and XSSF workbooks, letting
- * the driving code stay independent of format.
- *
- * @author Ken Arnold, Industrious Media LLC
- */
-public interface HtmlHelper {
-    /**
-     * Outputs the appropriate CSS style for the given cell style.
-     *
-     * @param style The cell style.
-     * @param out   The place to write the output.
-     */
-    void colorStyles(CellStyle style, Formatter out);
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/html/ToHtml.java b/src/examples/src/org/apache/poi/ss/examples/html/ToHtml.java
deleted file mode 100644 (file)
index 15fdc2a..0000000
+++ /dev/null
@@ -1,508 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.examples.html;
-
-import java.io.BufferedReader;
-import java.io.Closeable;
-import java.io.FileInputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.util.Formatter;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.format.CellFormat;
-import org.apache.poi.ss.format.CellFormatResult;
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.VerticalAlignment;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * This example shows how to display a spreadsheet in HTML using the classes for
- * spreadsheet display.
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class ToHtml {
-    private final Workbook wb;
-    private final Appendable output;
-    private boolean completeHTML;
-    private Formatter out;
-    private boolean gotBounds;
-    private int firstColumn;
-    private int endColumn;
-    private HtmlHelper helper;
-
-    private static final String DEFAULTS_CLASS = "excelDefaults";
-    private static final String COL_HEAD_CLASS = "colHeader";
-    private static final String ROW_HEAD_CLASS = "rowHeader";
-
-    private static final Map<HorizontalAlignment, String> HALIGN = mapFor(
-            HorizontalAlignment.LEFT, "left",
-            HorizontalAlignment.CENTER, "center",
-            HorizontalAlignment.RIGHT, "right",
-            HorizontalAlignment.FILL, "left",
-            HorizontalAlignment.JUSTIFY, "left",
-            HorizontalAlignment.CENTER_SELECTION, "center");
-
-    private static final Map<VerticalAlignment, String> VALIGN = mapFor(
-            VerticalAlignment.BOTTOM, "bottom",
-            VerticalAlignment.CENTER, "middle",
-            VerticalAlignment.TOP, "top");
-
-    private static final Map<BorderStyle, String> BORDER = mapFor(
-            BorderStyle.DASH_DOT, "dashed 1pt",
-            BorderStyle.DASH_DOT_DOT, "dashed 1pt",
-            BorderStyle.DASHED, "dashed 1pt",
-            BorderStyle.DOTTED, "dotted 1pt",
-            BorderStyle.DOUBLE, "double 3pt",
-            BorderStyle.HAIR, "solid 1px",
-            BorderStyle.MEDIUM, "solid 2pt",
-            BorderStyle.MEDIUM_DASH_DOT, "dashed 2pt",
-            BorderStyle.MEDIUM_DASH_DOT_DOT, "dashed 2pt",
-            BorderStyle.MEDIUM_DASHED, "dashed 2pt",
-            BorderStyle.NONE, "none",
-            BorderStyle.SLANTED_DASH_DOT, "dashed 2pt",
-            BorderStyle.THICK, "solid 3pt",
-            BorderStyle.THIN, "dashed 1pt");
-
-    private static final int IDX_TABLE_WIDTH = -2;
-    private static final int IDX_HEADER_COL_WIDTH = -1;
-
-
-    @SuppressWarnings({"unchecked"})
-    private static <K, V> Map<K, V> mapFor(Object... mapping) {
-        Map<K, V> map = new HashMap<>();
-        for (int i = 0; i < mapping.length; i += 2) {
-            map.put((K) mapping[i], (V) mapping[i + 1]);
-        }
-        return map;
-    }
-
-    /**
-     * Creates a new examples to HTML for the given workbook.
-     *
-     * @param wb     The workbook.
-     * @param output Where the HTML output will be written.
-     *
-     * @return An object for converting the workbook to HTML.
-     */
-    public static ToHtml create(Workbook wb, Appendable output) {
-        return new ToHtml(wb, output);
-    }
-
-    /**
-     * Creates a new examples to HTML for the given workbook.  If the path ends
-     * with "<tt>.xlsx</tt>" an {@link XSSFWorkbook} will be used; otherwise
-     * this will use an {@link HSSFWorkbook}.
-     *
-     * @param path   The file that has the workbook.
-     * @param output Where the HTML output will be written.
-     *
-     * @return An object for converting the workbook to HTML.
-     */
-    public static ToHtml create(String path, Appendable output)
-            throws IOException {
-        return create(new FileInputStream(path), output);
-    }
-
-    /**
-     * Creates a new examples to HTML for the given workbook.  This attempts to
-     * detect whether the input is XML (so it should create an {@link
-     * XSSFWorkbook} or not (so it should create an {@link HSSFWorkbook}).
-     *
-     * @param in     The input stream that has the workbook.
-     * @param output Where the HTML output will be written.
-     *
-     * @return An object for converting the workbook to HTML.
-     */
-    public static ToHtml create(InputStream in, Appendable output)
-            throws IOException {
-        Workbook wb = WorkbookFactory.create(in);
-        return create(wb, output);
-    }
-
-    private ToHtml(Workbook wb, Appendable output) {
-        if (wb == null) {
-            throw new NullPointerException("wb");
-        }
-        if (output == null) {
-            throw new NullPointerException("output");
-        }
-        this.wb = wb;
-        this.output = output;
-        setupColorMap();
-    }
-
-    private void setupColorMap() {
-        if (wb instanceof HSSFWorkbook) {
-            helper = new HSSFHtmlHelper((HSSFWorkbook) wb);
-        } else if (wb instanceof XSSFWorkbook) {
-            helper = new XSSFHtmlHelper();
-        } else {
-            throw new IllegalArgumentException(
-                    "unknown workbook type: " + wb.getClass().getSimpleName());
-        }
-    }
-
-    /**
-     * Run this class as a program
-     *
-     * @param args The command line arguments.
-     *
-     * @throws Exception Exception we don't recover from.
-     */
-    public static void main(String[] args) throws Exception {
-        if(args.length < 2){
-            System.err.println("usage: ToHtml inputWorkbook outputHtmlFile");
-            return;
-        }
-
-        try (
-                FileWriter fw = new FileWriter(args[1]);
-                PrintWriter pw = new PrintWriter(fw)
-            ) {
-            ToHtml toHtml = create(args[0], pw);
-            toHtml.setCompleteHTML(true);
-            toHtml.printPage();
-        }
-    }
-
-    public void setCompleteHTML(boolean completeHTML) {
-        this.completeHTML = completeHTML;
-    }
-
-    public void printPage() throws IOException {
-        try {
-            ensureOut();
-            if (completeHTML) {
-                out.format(
-                        "<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>%n");
-                out.format("<html>%n");
-                out.format("<head>%n");
-                out.format("</head>%n");
-                out.format("<body>%n");
-            }
-
-            print();
-
-            if (completeHTML) {
-                out.format("</body>%n");
-                out.format("</html>%n");
-            }
-        } finally {
-            IOUtils.closeQuietly(out);
-            if (output instanceof Closeable) {
-                IOUtils.closeQuietly((Closeable) output);
-            }
-        }
-    }
-
-    public void print() {
-        printInlineStyle();
-        printSheets();
-    }
-
-    private void printInlineStyle() {
-        //out.format("<link href=\"excelStyle.css\" rel=\"stylesheet\" type=\"text/css\">%n");
-        out.format("<style type=\"text/css\">%n");
-        printStyles();
-        out.format("</style>%n");
-    }
-
-    private void ensureOut() {
-        if (out == null) {
-            out = new Formatter(output);
-        }
-    }
-
-    public void printStyles() {
-        ensureOut();
-
-        // First, copy the base css
-        try (BufferedReader in = new BufferedReader(new InputStreamReader(
-                getClass().getResourceAsStream("excelStyle.css")))){
-            String line;
-            while ((line = in.readLine()) != null) {
-                out.format("%s%n", line);
-            }
-        } catch (IOException e) {
-            throw new IllegalStateException("Reading standard css", e);
-        }
-
-        // now add css for each used style
-        Set<CellStyle> seen = new HashSet<>();
-        for (int i = 0; i < wb.getNumberOfSheets(); i++) {
-            Sheet sheet = wb.getSheetAt(i);
-            Iterator<Row> rows = sheet.rowIterator();
-            while (rows.hasNext()) {
-                Row row = rows.next();
-                for (Cell cell : row) {
-                    CellStyle style = cell.getCellStyle();
-                    if (!seen.contains(style)) {
-                        printStyle(style);
-                        seen.add(style);
-                    }
-                }
-            }
-        }
-    }
-
-    private void printStyle(CellStyle style) {
-        out.format(".%s .%s {%n", DEFAULTS_CLASS, styleName(style));
-        styleContents(style);
-        out.format("}%n");
-    }
-
-    private void styleContents(CellStyle style) {
-        styleOut("text-align", style.getAlignment(), HALIGN);
-        styleOut("vertical-align", style.getVerticalAlignment(), VALIGN);
-        fontStyle(style);
-        borderStyles(style);
-        helper.colorStyles(style, out);
-    }
-
-    private void borderStyles(CellStyle style) {
-        styleOut("border-left", style.getBorderLeft(), BORDER);
-        styleOut("border-right", style.getBorderRight(), BORDER);
-        styleOut("border-top", style.getBorderTop(), BORDER);
-        styleOut("border-bottom", style.getBorderBottom(), BORDER);
-    }
-
-    private void fontStyle(CellStyle style) {
-        Font font = wb.getFontAt(style.getFontIndexAsInt());
-
-        if (font.getBold()) {
-            out.format("  font-weight: bold;%n");
-        }
-        if (font.getItalic()) {
-            out.format("  font-style: italic;%n");
-        }
-
-        int fontheight = font.getFontHeightInPoints();
-        if (fontheight == 9) {
-            //fix for stupid ol Windows
-            fontheight = 10;
-        }
-        out.format("  font-size: %dpt;%n", fontheight);
-
-        // Font color is handled with the other colors
-    }
-
-    private String styleName(CellStyle style) {
-        if (style == null) {
-            style = wb.getCellStyleAt((short) 0);
-        }
-        StringBuilder sb = new StringBuilder();
-        try (Formatter fmt = new Formatter(sb)) {
-            fmt.format("style_%02x", style.getIndex());
-            return fmt.toString();
-        }
-    }
-
-    private <K> void styleOut(String attr, K key, Map<K, String> mapping) {
-        String value = mapping.get(key);
-        if (value != null) {
-            out.format("  %s: %s;%n", attr, value);
-        }
-    }
-
-    private static CellType ultimateCellType(Cell c) {
-        CellType type = c.getCellType();
-        if (type == CellType.FORMULA) {
-            type = c.getCachedFormulaResultType();
-        }
-        return type;
-    }
-
-    private void printSheets() {
-        ensureOut();
-        Sheet sheet = wb.getSheetAt(0);
-        printSheet(sheet);
-    }
-
-    public void printSheet(Sheet sheet) {
-        ensureOut();
-        Map<Integer, Integer> widths = computeWidths(sheet);
-        int tableWidth = widths.get(IDX_TABLE_WIDTH);
-        out.format("<table class=%s style=\"width:%dpx;\">%n", DEFAULTS_CLASS, tableWidth);
-        printCols(widths);
-        printSheetContent(sheet);
-        out.format("</table>%n");
-    }
-
-    /**
-     * computes the column widths, defined by the sheet.
-     *
-     * @param sheet The sheet for which to compute widths
-     * @return Map with key: column index; value: column width in pixels
-     *     <br>special keys:
-     *     <br>{@link #IDX_HEADER_COL_WIDTH} - width of the header column
-     *     <br>{@link #IDX_TABLE_WIDTH} - width of the entire table
-     */
-    private Map<Integer, Integer> computeWidths(Sheet sheet) {
-        Map<Integer, Integer> ret = new TreeMap<>();
-        int tableWidth = 0;
-
-        ensureColumnBounds(sheet);
-
-        // compute width of the header column
-        int lastRowNum = sheet.getLastRowNum();
-        int headerCharCount = String.valueOf(lastRowNum).length();
-        int headerColWidth = widthToPixels((headerCharCount + 1) * 256.0);
-        ret.put(IDX_HEADER_COL_WIDTH, headerColWidth);
-        tableWidth += headerColWidth;
-
-        for (int i = firstColumn; i < endColumn; i++) {
-            int colWidth = widthToPixels(sheet.getColumnWidth(i));
-            ret.put(i, colWidth);
-            tableWidth += colWidth;
-        }
-
-        ret.put(IDX_TABLE_WIDTH, tableWidth);
-        return ret ;
-    }
-
-    /**
-     * Probably platform-specific, but appears to be a close approximation on some systems
-     * @param widthUnits POI's native width unit (twips)
-     * @return the approximate number of pixels for a typical display
-     */
-    protected int widthToPixels(final double widthUnits) {
-        return Math.toIntExact(Math.round(widthUnits * 9 / 256));
-    }
-
-    private void printCols(Map<Integer, Integer> widths) {
-        int headerColWidth = widths.get(IDX_HEADER_COL_WIDTH);
-        out.format("<col style=\"width:%dpx\"/>%n", headerColWidth);
-        for (int i = firstColumn; i < endColumn; i++) {
-            int colWidth = widths.get(i);
-            out.format("<col style=\"width:%dpx;\"/>%n", colWidth);
-        }
-    }
-
-    private void ensureColumnBounds(Sheet sheet) {
-        if (gotBounds) {
-            return;
-        }
-
-        Iterator<Row> iter = sheet.rowIterator();
-        firstColumn = (iter.hasNext() ? Integer.MAX_VALUE : 0);
-        endColumn = 0;
-        while (iter.hasNext()) {
-            Row row = iter.next();
-            short firstCell = row.getFirstCellNum();
-            if (firstCell >= 0) {
-                firstColumn = Math.min(firstColumn, firstCell);
-                endColumn = Math.max(endColumn, row.getLastCellNum());
-            }
-        }
-        gotBounds = true;
-    }
-
-    private void printColumnHeads() {
-        out.format("<thead>%n");
-        out.format("  <tr class=%s>%n", COL_HEAD_CLASS);
-        out.format("    <th class=%s>&#x25CA;</th>%n", COL_HEAD_CLASS);
-        //noinspection UnusedDeclaration
-        StringBuilder colName = new StringBuilder();
-        for (int i = firstColumn; i < endColumn; i++) {
-            colName.setLength(0);
-            int cnum = i;
-            do {
-                colName.insert(0, (char) ('A' + cnum % 26));
-                cnum /= 26;
-            } while (cnum > 0);
-            out.format("    <th class=%s>%s</th>%n", COL_HEAD_CLASS, colName);
-        }
-        out.format("  </tr>%n");
-        out.format("</thead>%n");
-    }
-
-    private void printSheetContent(Sheet sheet) {
-        printColumnHeads();
-
-        out.format("<tbody>%n");
-        Iterator<Row> rows = sheet.rowIterator();
-        while (rows.hasNext()) {
-            Row row = rows.next();
-
-            out.format("  <tr>%n");
-            out.format("    <td class=%s>%d</td>%n", ROW_HEAD_CLASS,
-                    row.getRowNum() + 1);
-            for (int i = firstColumn; i < endColumn; i++) {
-                String content = "&nbsp;";
-                String attrs = "";
-                CellStyle style = null;
-                if (i >= row.getFirstCellNum() && i < row.getLastCellNum()) {
-                    Cell cell = row.getCell(i);
-                    if (cell != null) {
-                        style = cell.getCellStyle();
-                        attrs = tagStyle(cell, style);
-                        //Set the value that is rendered for the cell
-                        //also applies the format
-                        CellFormat cf = CellFormat.getInstance(
-                                style.getDataFormatString());
-                        CellFormatResult result = cf.apply(cell);
-                        content = result.text; //never null
-                        if (content.isEmpty()) {
-                            content = "&nbsp;";
-                        }
-                    }
-                }
-                out.format("    <td class=%s %s>%s</td>%n", styleName(style),
-                        attrs, content);
-            }
-            out.format("  </tr>%n");
-        }
-        out.format("</tbody>%n");
-    }
-
-    private String tagStyle(Cell cell, CellStyle style) {
-        if (style.getAlignment() == HorizontalAlignment.GENERAL) {
-            switch (ultimateCellType(cell)) {
-            case STRING:
-                return "style=\"text-align: left;\"";
-            case BOOLEAN:
-            case ERROR:
-                return "style=\"text-align: center;\"";
-            case NUMERIC:
-            default:
-                // "right" is the default
-                break;
-            }
-        }
-        return "";
-    }
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/html/XSSFHtmlHelper.java b/src/examples/src/org/apache/poi/ss/examples/html/XSSFHtmlHelper.java
deleted file mode 100644 (file)
index 20a30ed..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.examples.html;
-
-import java.util.Formatter;
-
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.xssf.usermodel.XSSFCellStyle;
-import org.apache.poi.xssf.usermodel.XSSFColor;
-
-/**
- * Implementation of {@link HtmlHelper} for XSSF files.
- *
- * @author Ken Arnold, Industrious Media LLC
- */
-public class XSSFHtmlHelper implements HtmlHelper {
-    @Override
-    public void colorStyles(CellStyle style, Formatter out) {
-        XSSFCellStyle cs = (XSSFCellStyle) style;
-        styleColor(out, "background-color", cs.getFillForegroundXSSFColor());
-        styleColor(out, "text-color", cs.getFont().getXSSFColor());
-    }
-
-    private void styleColor(Formatter out, String attr, XSSFColor color) {
-        if (color == null || color.isAuto()) {
-            return;
-        }
-
-        byte[] rgb = color.getRGB();
-        if (rgb == null) {
-            return;
-        }
-
-        // This is done twice -- rgba is new with CSS 3, and browser that don't
-        // support it will ignore the rgba specification and stick with the
-        // solid color, which is declared first
-        out.format("  %s: #%02x%02x%02x;%n", attr, rgb[0], rgb[1], rgb[2]);
-        byte[] argb = color.getARGB();
-        if (argb == null) {
-            return;
-        }
-        out.format("  %s: rgba(0x%02x, 0x%02x, 0x%02x, 0x%02x);%n", attr,
-                argb[3], argb[0], argb[1], argb[2]);
-    }
-}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/ss/examples/html/excelStyle.css b/src/examples/src/org/apache/poi/ss/examples/html/excelStyle.css
deleted file mode 100644 (file)
index f056123..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
-   ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-   ====================================================================
- */
-/*
- * This is the default style sheet for html generated by ToHtml
- *
- * @author Ken Arnold, Industrious Media LLC
- */
-.excelDefaults {
-       background-color: white;
-       color: black;
-       text-decoration: none;
-       direction: ltr;
-       text-transform: none;
-       text-indent: 0;
-       letter-spacing: 0;
-       word-spacing: 0;
-       white-space: pre-wrap;
-       unicode-bidi: normal;
-       background-image: none;
-       text-shadow: none;
-       list-style-image: none;
-       list-style-type: none;
-       padding: 0;
-       margin: 0;
-       border-collapse: collapse;
-       vertical-align: bottom;
-       font-style: normal;
-       font-family: sans-serif;
-       font-variant: normal;
-       font-weight: normal;
-       font-size: 10pt;
-       text-align: right;
-       table-layout: fixed;
-       word-wrap: break-word;
-       overflow-wrap: break-word;
-}
-
-.excelDefaults td {
-       padding: 1px 5px;
-       border: 1px solid silver;
-}
-
-.excelDefaults .colHeader {
-       background-color: silver;
-       font-weight: bold;
-       border: 1px solid black;
-       text-align: center;
-       padding: 1px 5px;
-}
-
-.excelDefaults .rowHeader {
-       background-color: silver;
-       font-weight: bold;
-       border: 1px solid black;
-       text-align: right;
-       padding: 1px 5px;
-}
diff --git a/src/examples/src/org/apache/poi/ss/examples/html/package-info.java b/src/examples/src/org/apache/poi/ss/examples/html/package-info.java
deleted file mode 100644 (file)
index 11b5fd5..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-/**
- * This package contains an example that uses POI to convert a workbook into
- * an HTML representation of the data.  It can use both XSSF and HSSF workbooks.
- */
-package org.apache.poi.ss.examples.html;
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/AddVideoToPptx.java.txt b/src/examples/src/org/apache/poi/xslf/usermodel/AddVideoToPptx.java.txt
deleted file mode 100644 (file)
index 2d32c4d..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/*\r
- *  ====================================================================\r
- *    Licensed to the Apache Software Foundation (ASF) under one or more\r
- *    contributor license agreements.  See the NOTICE file distributed with\r
- *    this work for additional information regarding copyright ownership.\r
- *    The ASF licenses this file to You under the Apache License, Version 2.0\r
- *    (the "License"); you may not use this file except in compliance with\r
- *    the License.  You may obtain a copy of the License at\r
- *\r
- *        http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- *    Unless required by applicable law or agreed to in writing, software\r
- *    distributed under the License is distributed on an "AS IS" BASIS,\r
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- *    See the License for the specific language governing permissions and\r
- *    limitations under the License.\r
- * ==================================================================== \r
- */\r
-\r
-package org.apache.poi.xslf.usermodel;\r
-\r
-import java.awt.Rectangle;\r
-import java.awt.image.BufferedImage;\r
-import java.io.ByteArrayOutputStream;\r
-import java.io.FileOutputStream;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.io.OutputStream;\r
-import java.net.URL;\r
-import java.text.DecimalFormat;\r
-\r
-import javax.imageio.ImageIO;\r
-import javax.xml.namespace.QName;\r
-\r
-import org.apache.poi.openxml4j.opc.PackagePart;\r
-import org.apache.poi.openxml4j.opc.PackagePartName;\r
-import org.apache.poi.openxml4j.opc.PackageRelationship;\r
-import org.apache.poi.openxml4j.opc.PackagingURIHelper;\r
-import org.apache.poi.openxml4j.opc.TargetMode;\r
-import org.apache.poi.sl.usermodel.PictureData.PictureType;\r
-import org.apache.xmlbeans.XmlCursor;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;\r
-import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.CTExtension;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.CTTLCommonMediaNodeData;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.CTTLCommonTimeNodeData;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.CTTimeNodeList;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeIndefinite;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeFillType;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeRestartType;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeType;\r
-\r
-import com.xuggle.mediatool.IMediaReader;\r
-import com.xuggle.mediatool.MediaListenerAdapter;\r
-import com.xuggle.mediatool.ToolFactory;\r
-import com.xuggle.mediatool.event.IVideoPictureEvent;\r
-import com.xuggle.xuggler.Global;\r
-import com.xuggle.xuggler.IContainer;\r
-import com.xuggle.xuggler.io.InputOutputStreamHandler;\r
-\r
-/**\r
- * Adding multiple videos to a slide\r
- * \r
- * need the Xuggler 5.4 jars:\r
- *  &lt;repositories&gt;\r
- *  &lt;repository&gt;\r
- *  &lt;id&gt;xuggle repo&lt;/id&gt;\r
- *  &lt;url&gt;http://xuggle.googlecode.com/svn/trunk/repo/share/java/&lt;/url&gt;\r
- *  &lt;/repository&gt;\r
- *  &lt;/repositories&gt;\r
- *  ...\r
- *  &lt;dependency&gt;\r
- *  &lt;groupId&gt;xuggle&lt;/groupId&gt;\r
- *  &lt;artifactId&gt;xuggle-xuggler&lt;/artifactId&gt;\r
- *  &lt;version&gt;5.4&lt;/version&gt;\r
- *  &lt;/dependency&gt;\r
- * \r
- * @see <a href="http://stackoverflow.com/questions/15197300/apache-poi-xslf-adding-movie-to-the-slide">Apache POI XSLF Adding movie to the slide</a>\r
- * @see <a href="http://apache-poi.1045710.n5.nabble.com/Question-about-embedded-video-in-PPTX-files-tt5718461.html">Question about embedded video in PPTX files</a>\r
- */\r
-public class AddVideoToPptx {\r
-    static DecimalFormat df_time = new DecimalFormat("0.####");\r
-\r
-    public static void main(String[] args) throws Exception {\r
-        URL video = new URL("http://archive.org/download/test-mpeg/test-mpeg.mpg");\r
-        // URL video = new URL("file:test-mpeg.mpg");\r
-\r
-        XMLSlideShow pptx = new XMLSlideShow();\r
-\r
-        // add video file\r
-        String videoFileName = video.getPath().substring(video.getPath().lastIndexOf('/')+1);\r
-        PackagePartName partName = PackagingURIHelper.createPartName("/ppt/media/"+videoFileName);\r
-        PackagePart part = pptx.getPackage().createPart(partName, "video/mpeg");\r
-        OutputStream partOs = part.getOutputStream();\r
-        InputStream fis = video.openStream();\r
-        byte buf[] = new byte[1024];\r
-        for (int readBytes; (readBytes = fis.read(buf)) != -1; partOs.write(buf, 0, readBytes));\r
-        fis.close();\r
-        partOs.close();\r
-\r
-        XSLFSlide slide1 = pptx.createSlide();\r
-        XSLFPictureShape pv1 = addPreview(pptx, slide1, part, 5, 50, 50);\r
-        addVideo(pptx, slide1, part, pv1, 5);\r
-        addTimingInfo(slide1, pv1);\r
-        XSLFPictureShape pv2 = addPreview(pptx, slide1, part, 9, 50, 250);\r
-        addVideo(pptx, slide1, part, pv2, 9);\r
-        addTimingInfo(slide1, pv2);\r
-\r
-        FileOutputStream fos = new FileOutputStream("pptx-with-video.pptx");\r
-        pptx.write(fos);\r
-        fos.close();\r
-        \r
-        pptx.close();\r
-    }\r
-\r
-    static XSLFPictureShape addPreview(XMLSlideShow pptx, XSLFSlide slide1, PackagePart videoPart, double seconds, int x, int y) throws IOException {\r
-        // get preview after 5 sec.\r
-        IContainer ic = IContainer.make();\r
-        InputOutputStreamHandler iosh = new InputOutputStreamHandler(videoPart.getInputStream());\r
-        if (ic.open(iosh, IContainer.Type.READ, null) < 0) return null;\r
-\r
-        IMediaReader mediaReader = ToolFactory.makeReader(ic);\r
-\r
-        // stipulate that we want BufferedImages created in BGR 24bit color space\r
-        mediaReader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);\r
-\r
-        ImageSnapListener isl = new ImageSnapListener(seconds);\r
-        mediaReader.addListener(isl);\r
-\r
-        // read out the contents of the media file and\r
-        // dispatch events to the attached listener\r
-        while (!isl.hasFired && mediaReader.readPacket() == null) ;\r
-\r
-        mediaReader.close();\r
-        ic.close();\r
-\r
-        // add snapshot\r
-        BufferedImage image1 = isl.image;\r
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();\r
-        ImageIO.write(image1, "jpeg", bos);\r
-        XSLFPictureData snap = pptx.addPicture(bos.toByteArray(), PictureType.JPEG);\r
-        XSLFPictureShape pic1 = slide1.createPicture(snap);\r
-        pic1.setAnchor(new Rectangle(x, y, image1.getWidth(), image1.getHeight()));\r
-        return pic1;\r
-    }\r
-\r
-    static void addVideo(XMLSlideShow pptx, XSLFSlide slide1, PackagePart videoPart, XSLFPictureShape pic1, double seconds) throws IOException {\r
-\r
-        // add video shape\r
-        PackagePartName partName = videoPart.getPartName();\r
-        PackageRelationship prsEmbed1 = slide1.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, "http://schemas.microsoft.com/office/2007/relationships/media");\r
-        PackageRelationship prsExec1 = slide1.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/video");\r
-        CTPicture xpic1 = (CTPicture)pic1.getXmlObject();\r
-        CTHyperlink link1 = xpic1.getNvPicPr().getCNvPr().addNewHlinkClick();\r
-        link1.setId("");\r
-        link1.setAction("ppaction://media");\r
-\r
-        // add video relation\r
-        CTApplicationNonVisualDrawingProps nvPr = xpic1.getNvPicPr().getNvPr();\r
-        nvPr.addNewVideoFile().setLink(prsExec1.getId());\r
-        CTExtension ext = nvPr.addNewExtLst().addNewExt();\r
-        // see http://msdn.microsoft.com/en-us/library/dd950140(v=office.12).aspx\r
-        ext.setUri("{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}");\r
-        String p14Ns = "http://schemas.microsoft.com/office/powerpoint/2010/main";\r
-        XmlCursor cur = ext.newCursor();\r
-        cur.toEndToken();\r
-        cur.beginElement(new QName(p14Ns, "media", "p14"));\r
-        cur.insertNamespace("p14", p14Ns);\r
-        cur.insertAttributeWithValue(new QName(STRelationshipId.type.getName().getNamespaceURI(), "embed"), prsEmbed1.getId());\r
-        cur.beginElement(new QName(p14Ns, "trim", "p14"));\r
-        cur.insertAttributeWithValue("st", df_time.format(seconds*1000.0));\r
-        cur.dispose();\r
-\r
-    }\r
-\r
-    static void addTimingInfo(XSLFSlide slide1, XSLFPictureShape pic1) {\r
-        // add slide timing information, so video can be controlled\r
-        CTSlide xslide = slide1.getXmlObject();\r
-        CTTimeNodeList ctnl;\r
-        if (!xslide.isSetTiming()) {\r
-            CTTLCommonTimeNodeData ctn = xslide.addNewTiming().addNewTnLst().addNewPar().addNewCTn();\r
-            ctn.setDur(STTLTimeIndefinite.INDEFINITE);\r
-            ctn.setRestart(STTLTimeNodeRestartType.NEVER);\r
-            ctn.setNodeType(STTLTimeNodeType.TM_ROOT);\r
-            ctnl = ctn.addNewChildTnLst();\r
-        } else {\r
-            ctnl = xslide.getTiming().getTnLst().getParArray(0).getCTn().getChildTnLst();\r
-        }\r
-\r
-        CTTLCommonMediaNodeData cmedia = ctnl.addNewVideo().addNewCMediaNode();\r
-        cmedia.setVol(80000);\r
-        CTTLCommonTimeNodeData ctn = cmedia.addNewCTn();\r
-        ctn.setFill(STTLTimeNodeFillType.HOLD);\r
-        ctn.setDisplay(false);\r
-        ctn.addNewStCondLst().addNewCond().setDelay(STTLTimeIndefinite.INDEFINITE);\r
-        cmedia.addNewTgtEl().addNewSpTgt().setSpid(""+pic1.getShapeId());\r
-    }\r
-\r
-\r
-    static class ImageSnapListener extends MediaListenerAdapter {\r
-        final double SECONDS_BETWEEN_FRAMES;\r
-        final long MICRO_SECONDS_BETWEEN_FRAMES;\r
-        boolean hasFired = false;\r
-        BufferedImage image = null;\r
-\r
-        // The video stream index, used to ensure we display frames from one and\r
-        // only one video stream from the media container.\r
-        int mVideoStreamIndex = -1;\r
-\r
-        // Time of last frame write\r
-        long mLastPtsWrite = Global.NO_PTS;\r
-\r
-        public ImageSnapListener(double seconds) {\r
-            SECONDS_BETWEEN_FRAMES = seconds;\r
-            MICRO_SECONDS_BETWEEN_FRAMES =\r
-                    (long)(Global.DEFAULT_PTS_PER_SECOND * SECONDS_BETWEEN_FRAMES);\r
-        }\r
-\r
-\r
-        @Override\r
-        public void onVideoPicture(IVideoPictureEvent event) {\r
-\r
-            if (event.getStreamIndex() != mVideoStreamIndex) {\r
-                // if the selected video stream id is not yet set, go ahead an\r
-                // select this lucky video stream\r
-                if (mVideoStreamIndex != -1) return;\r
-                mVideoStreamIndex = event.getStreamIndex();\r
-            }\r
-\r
-            long evtTS = event.getTimeStamp();\r
-\r
-            // if uninitialized, back date mLastPtsWrite to get the very first frame\r
-            if (mLastPtsWrite == Global.NO_PTS)\r
-                mLastPtsWrite = Math.max(0, evtTS - MICRO_SECONDS_BETWEEN_FRAMES);\r
-\r
-            // if it's time to write the next frame\r
-            if (evtTS - mLastPtsWrite >= MICRO_SECONDS_BETWEEN_FRAMES) {\r
-                if (!hasFired) {\r
-                    image = event.getImage();\r
-                    hasFired = true;\r
-                }\r
-                // update last write time\r
-                mLastPtsWrite += MICRO_SECONDS_BETWEEN_FRAMES;\r
-            }\r
-        }\r
-    }\r
-\r
-}\r
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/BarChartDemo.java b/src/examples/src/org/apache/poi/xslf/usermodel/BarChartDemo.java
deleted file mode 100644 (file)
index d717e37..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.poi.ooxml.POIXMLDocumentPart;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.xddf.usermodel.chart.AxisOrientation;
-import org.apache.poi.xddf.usermodel.chart.AxisPosition;
-import org.apache.poi.xddf.usermodel.chart.BarDirection;
-import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
-import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
-
-/**
- * Build a bar chart from a template pptx
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class BarChartDemo {
-    private BarChartDemo() {}
-
-    private static void usage(){
-        System.out.println("Usage: BarChartDemo <bar-chart-template.pptx> <bar-chart-data.txt>");
-        System.out.println("    bar-chart-template.pptx     template with a bar chart");
-        System.out.println("    bar-chart-data.txt          the model to set. First line is chart title, " +
-                "then go pairs {axis-label value}");
-    }
-
-    public static void main(String[] args) throws Exception {
-        if(args.length < 2) {
-            usage();
-            return;
-        }
-
-        try (FileInputStream argIS = new FileInputStream(args[0]);
-            BufferedReader modelReader = new BufferedReader(new FileReader(args[1]))) {
-
-            String chartTitle = modelReader.readLine();  // first line is chart title
-            String[] series = modelReader.readLine().split(",");
-
-            // Category Axis Data
-            List<String> listLanguages = new ArrayList<>(10);
-
-            // Values
-            List<Double> listCountries = new ArrayList<>(10);
-            List<Double> listSpeakers = new ArrayList<>(10);
-
-            // set model
-            String ln;
-            while((ln = modelReader.readLine()) != null) {
-                String[] vals = ln.split(",");
-                listCountries.add(Double.valueOf(vals[0]));
-                listSpeakers.add(Double.valueOf(vals[1]));
-                listLanguages.add(vals[2]);
-            }
-            String[] categories = listLanguages.toArray(new String[0]);
-            Double[] values1 = listCountries.toArray(new Double[0]);
-            Double[] values2 = listSpeakers.toArray(new Double[0]);
-
-            try (XMLSlideShow pptx = new XMLSlideShow(argIS)) {
-                XSLFSlide slide = pptx.getSlides().get(0);
-                setBarData(findChart(slide), chartTitle, series, categories, values1, values2);
-
-                XSLFChart chart = findChart(pptx.createSlide().importContent(slide));
-                setColumnData(chart, "Column variant");
-
-                // save the result
-                try (OutputStream out = new FileOutputStream("bar-chart-demo-output.pptx")) {
-                    pptx.write(out);
-                }
-            }
-        }
-    }
-
-    private static void setBarData(XSLFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
-        final List<XDDFChartData> data = chart.getChartSeries();
-        final XDDFBarChartData bar = (XDDFBarChartData) data.get(0);
-
-        final int numOfPoints = categories.length;
-        final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_LANGUAGES, COLUMN_LANGUAGES));
-        final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_COUNTRIES, COLUMN_COUNTRIES));
-        final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_SPEAKERS, COLUMN_SPEAKERS));
-        final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, COLUMN_LANGUAGES);
-        final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, COLUMN_COUNTRIES);
-        values1[6] = 16.0; // if you ever want to change the underlying data, it has to be done before building the data source
-        final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, COLUMN_SPEAKERS);
-
-        XDDFChartData.Series series1 = bar.getSeries(0);
-        series1.replaceData(categoriesData, valuesData);
-        series1.setTitle(series[0], chart.setSheetTitle(series[0], COLUMN_COUNTRIES));
-        XDDFChartData.Series series2 = bar.addSeries(categoriesData, valuesData2);
-        series2.setTitle(series[1], chart.setSheetTitle(series[1], COLUMN_SPEAKERS));
-
-        chart.plot(bar);
-        chart.setTitleText(chartTitle); // https://stackoverflow.com/questions/30532612
-        // chart.setTitleOverlay(overlay);
-
-        // adjust font size for readability
-        bar.getCategoryAxis().getOrAddTextProperties().setFontSize(11.5);
-        chart.getTitle().getOrAddTextProperties().setFontSize(18.2);
-    }
-
-    private static void setColumnData(XSLFChart chart, String chartTitle) {
-        // Series Text
-        List<XDDFChartData> series = chart.getChartSeries();
-        XDDFBarChartData bar = (XDDFBarChartData) series.get(0);
-
-        // in order to transform a bar chart into a column chart, you just need to change the bar direction
-        bar.setBarDirection(BarDirection.COL);
-
-        // looking for "Stacked Bar Chart"? uncomment the following line
-        // bar.setBarGrouping(BarGrouping.STACKED);
-
-        // additionally, you can adjust the axes
-        bar.getCategoryAxis().setOrientation(AxisOrientation.MAX_MIN);
-        bar.getValueAxes().get(0).setPosition(AxisPosition.TOP);
-    }
-
-    private static XSLFChart findChart(XSLFSlide slide) {
-        // find chart in the slide
-        XSLFChart chart = null;
-        for(POIXMLDocumentPart part : slide.getRelations()){
-            if(part instanceof XSLFChart){
-                chart = (XSLFChart) part;
-                break;
-            }
-        }
-
-        if(chart == null) {
-            throw new IllegalStateException("chart not found in the template");
-        }
-        return chart;
-    }
-
-    private static final int COLUMN_LANGUAGES = 0;
-    private static final int COLUMN_COUNTRIES = 1;
-    private static final int COLUMN_SPEAKERS = 2;
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/ChartFromScratch.java b/src/examples/src/org/apache/poi/xslf/usermodel/ChartFromScratch.java
deleted file mode 100644 (file)
index eb007fc..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import java.awt.geom.Rectangle2D;
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.util.Units;
-import org.apache.poi.xddf.usermodel.chart.AxisCrossBetween;
-import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
-import org.apache.poi.xddf.usermodel.chart.AxisPosition;
-import org.apache.poi.xddf.usermodel.chart.AxisTickMark;
-import org.apache.poi.xddf.usermodel.chart.BarDirection;
-import org.apache.poi.xddf.usermodel.chart.BarGrouping;
-import org.apache.poi.xddf.usermodel.chart.ChartTypes;
-import org.apache.poi.xddf.usermodel.chart.LegendPosition;
-import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartAxis;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
-import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
-
-/**
- * Build a chart without reading template file
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class ChartFromScratch {
-    private ChartFromScratch() {}
-
-    private static void usage(){
-        System.out.println("Usage: ChartFromScratch <bar-chart-data.txt>");
-        System.out.println("    bar-chart-data.txt          the model to set. First line is chart title, " +
-                "then go pairs {axis-label value}");
-    }
-
-    public static void main(String[] args) throws Exception {
-        if(args.length < 1) {
-            usage();
-            return;
-        }
-
-        try (BufferedReader modelReader = new BufferedReader(new FileReader(args[0]))) {
-
-            String chartTitle = modelReader.readLine();  // first line is chart title
-            String[] series = modelReader.readLine().split(",");
-
-            // Category Axis Data
-            List<String> listLanguages = new ArrayList<>(10);
-
-            // Values
-            List<Double> listCountries = new ArrayList<>(10);
-            List<Double> listSpeakers = new ArrayList<>(10);
-
-            // set model
-            String ln;
-            while((ln = modelReader.readLine()) != null) {
-                String[] vals = ln.split(",");
-                listCountries.add(Double.valueOf(vals[0]));
-                listSpeakers.add(Double.valueOf(vals[1]));
-                listLanguages.add(vals[2]);
-            }
-
-            String[] categories = listLanguages.toArray(new String[0]);
-            Double[] values1 = listCountries.toArray(new Double[0]);
-            Double[] values2 = listSpeakers.toArray(new Double[0]);
-
-            try (XMLSlideShow ppt = new XMLSlideShow()) {
-                createSlideWithChart(ppt, chartTitle, series, categories, values1, values2);
-                createSlideWithChart(ppt, chartTitle, series, categories, values1, values2);
-                createSlideWithChart(ppt, chartTitle, series, categories, values1, values2);
-                // save the result
-                try (OutputStream out = new FileOutputStream("chart-from-scratch.pptx")) {
-                    ppt.write(out);
-                }
-            }
-            try (FileInputStream is = new FileInputStream("chart-from-scratch.pptx")) {
-                try (XMLSlideShow ppt = new XMLSlideShow(is)) {
-                    for (XSLFSlide slide : ppt.getSlides()) {
-                        for (XSLFShape shape : slide.getShapes()) {
-                            if (shape instanceof XSLFGraphicFrame) {
-                                XSLFGraphicFrame frame = (XSLFGraphicFrame) shape;
-                                if (frame.hasChart()) {
-                                    System.out.println(frame.getChart().getTitleShape().getText());
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        System.out.println("Done");
-    }
-
-    private static void createSlideWithChart(XMLSlideShow ppt, String chartTitle, String[] series, String[] categories,
-            Double[] values1, Double[] values2) {
-        XSLFSlide slide = ppt.createSlide();
-        XSLFChart chart = ppt.createChart();
-        Rectangle2D rect2D = new java.awt.Rectangle(fromCM(1.5), fromCM(4), fromCM(22), fromCM(14));
-        slide.addChart(chart, rect2D);
-        setBarData(chart, chartTitle, series, categories, values1, values2);
-    }
-
-    private static int fromCM(double cm) {
-        return (int) (Math.rint(cm * Units.EMU_PER_CENTIMETER));
-    }
-
-    private static void setBarData(XSLFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
-        // Use a category axis for the bottom axis.
-        XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
-        bottomAxis.setTitle(series[2]);
-        XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
-        leftAxis.setTitle(series[0]+","+series[1]);
-        leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
-        leftAxis.setMajorTickMark(AxisTickMark.OUT);
-        leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
-
-        final int numOfPoints = categories.length;
-        final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_LANGUAGES, COLUMN_LANGUAGES));
-        final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_COUNTRIES, COLUMN_COUNTRIES));
-        final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_SPEAKERS, COLUMN_SPEAKERS));
-        final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, COLUMN_LANGUAGES);
-        final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, COLUMN_COUNTRIES);
-        valuesData.setFormatCode("General");
-        values1[6] = 16.0; // if you ever want to change the underlying data, it has to be done before building the data source
-        final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, COLUMN_SPEAKERS);
-        valuesData2.setFormatCode("General");
-
-
-        XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
-        bar.setBarGrouping(BarGrouping.CLUSTERED);
-
-        XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData);
-        series1.setTitle(series[0], chart.setSheetTitle(series[0], COLUMN_COUNTRIES));
-
-        XDDFBarChartData.Series series2 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData2);
-        series2.setTitle(series[1], chart.setSheetTitle(series[1], COLUMN_SPEAKERS));
-
-        bar.setVaryColors(true);
-        bar.setBarDirection(BarDirection.COL);
-        chart.plot(bar);
-
-        XDDFChartLegend legend = chart.getOrAddLegend();
-        legend.setPosition(LegendPosition.LEFT);
-        legend.setOverlay(false);
-
-        chart.setTitleText(chartTitle);
-        chart.setTitleOverlay(false);
-        chart.setAutoTitleDeleted(false);
-    }
-
-    private static final int COLUMN_LANGUAGES = 0;
-    private static final int COLUMN_COUNTRIES = 1;
-    private static final int COLUMN_SPEAKERS = 2;
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/DataExtraction.java b/src/examples/src/org/apache/poi/xslf/usermodel/DataExtraction.java
deleted file mode 100644 (file)
index 543726a..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import java.awt.Dimension;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintStream;
-
-import org.apache.poi.openxml4j.opc.PackagePart;
-
-/**
- * Demonstrates how you can extract data from a .pptx file
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class DataExtraction {
-    private DataExtraction() {}
-
-    public static void main(String[] args) throws IOException {
-
-        PrintStream out = System.out;
-
-        if (args.length == 0) {
-           out.println("Input file is required");
-           return;
-        }
-
-        FileInputStream is = new FileInputStream(args[0]);
-        try (XMLSlideShow ppt = new XMLSlideShow(is)) {
-            is.close();
-
-            // Get the document's embedded files.
-            for (PackagePart p : ppt.getAllEmbeddedParts()) {
-                String type = p.getContentType();
-                // typically file name
-                String name = p.getPartName().getName();
-                out.println("Embedded file (" + type + "): " + name);
-
-                InputStream pIs = p.getInputStream();
-                // make sense of the part data
-                pIs.close();
-
-            }
-
-            // Get the document's embedded files.
-            for (XSLFPictureData data : ppt.getPictureData()) {
-                String type = data.getContentType();
-                String name = data.getFileName();
-                out.println("Picture (" + type + "): " + name);
-
-                InputStream pIs = data.getInputStream();
-                // make sense of the image data
-                pIs.close();
-            }
-
-            // size of the canvas in points
-            Dimension pageSize = ppt.getPageSize();
-            out.println("Pagesize: " + pageSize);
-
-            for (XSLFSlide slide : ppt.getSlides()) {
-                for (XSLFShape shape : slide) {
-                    if (shape instanceof XSLFTextShape) {
-                        XSLFTextShape txShape = (XSLFTextShape) shape;
-                        out.println(txShape.getText());
-                    } else if (shape instanceof XSLFPictureShape) {
-                        XSLFPictureShape pShape = (XSLFPictureShape) shape;
-                        XSLFPictureData pData = pShape.getPictureData();
-                        out.println(pData.getFileName());
-                    } else {
-                        out.println("Process me: " + shape.getClass());
-                    }
-                }
-            }
-        }
-    }
-
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/MergePresentations.java b/src/examples/src/org/apache/poi/xslf/usermodel/MergePresentations.java
deleted file mode 100644 (file)
index e295ffd..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-
-/**
- * Merge multiple pptx presentations together
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class MergePresentations {
-    private MergePresentations() {}
-
-    public static void main(String[] args) throws Exception {
-        try (XMLSlideShow ppt = new XMLSlideShow()) {
-            for (String arg : args) {
-                try (FileInputStream is = new FileInputStream(arg);
-                     XMLSlideShow src = new XMLSlideShow(is)) {
-                    for (XSLFSlide srcSlide : src.getSlides()) {
-                        ppt.createSlide().importContent(srcSlide);
-                    }
-                }
-            }
-
-            try (FileOutputStream out = new FileOutputStream("merged.pptx")) {
-                ppt.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/PPTX2SVG.txt b/src/examples/src/org/apache/poi/xslf/usermodel/PPTX2SVG.txt
deleted file mode 100644 (file)
index dbe089a..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import org.apache.batik.dom.svg.SVGDOMImplementation;
-import org.apache.batik.svggen.SVGGraphics2D;
-import org.apache.batik.transcoder.wmf.tosvg.WMFPainter;
-import org.apache.batik.transcoder.wmf.tosvg.WMFRecordStore;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.openxml4j.opc.PackagePart;
-import org.w3c.dom.DOMImplementation;
-import org.w3c.dom.Document;
-
-import javax.imageio.ImageIO;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import java.awt.Dimension;
-import java.awt.Graphics2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.io.DataInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-
-/**
- * Convert each slide of a .pptx presentation into SVG
- *
- * @author Yegor Kozlov
- */
-public class PPTX2SVG {
-
-    static void usage() {
-        System.out.println("Usage: PPTX2SVG  <pptx file>");
-    }
-
-    public static void main(String[] args) throws Exception {
-        if (args.length == 0) {
-            usage();
-            return;
-        }
-
-        String file = args[0];
-
-        System.out.println("Processing " + file);
-
-        // read the .pptx file
-        XMLSlideShow ppt = new XMLSlideShow(OPCPackage.open(file));
-
-        Dimension pgsize = ppt.getPageSize();
-
-        // convert each slide into a .svg file
-        XSLFSlide[] slide = ppt.getSlides();
-        for (int i = 0; i < slide.length; i++) {
-            // Create initial SVG DOM
-            DOMImplementation domImpl = SVGDOMImplementation.getDOMImplementation();
-            Document doc = domImpl.createDocument("http://www.w3.org/2000/svg", "svg", null);
-            //Use Batik SVG Graphics2D driver
-            SVGGraphics2D graphics = new SVGGraphics2D(doc);
-            graphics.setRenderingHint(XSLFRenderingHint.IMAGE_RENDERER, new WMFImageRender());
-            graphics.setSVGCanvasSize(pgsize);
-
-            String title = slide[i].getTitle();
-            System.out.println("Rendering slide " + (i + 1) + (title == null ? "" : ": " + title));
-
-            // draw stuff. All the heavy-lifting happens here
-            slide[i].draw(graphics);
-
-            // save the result.
-            int sep = file.lastIndexOf(".");
-            String fname = file.substring(0, sep == -1 ? file.length() : sep) + "-" + (i + 1) + ".svg";
-            OutputStreamWriter out =
-                    new OutputStreamWriter(new FileOutputStream(fname), "UTF-8");
-            DOMSource domSource = new DOMSource(graphics.getRoot());
-            StreamResult streamResult = new StreamResult(out);
-            TransformerFactory tf = TransformerFactory.newInstance();
-            Transformer serializer = tf.newTransformer();
-            serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
-            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
-            serializer.transform(domSource, streamResult);
-            out.flush();
-            out.close();
-        }
-        System.out.println("Done");
-    }
-
-    /**
-     * Image renderer with support for .wmf images
-     */
-    static class WMFImageRender extends XSLFImageRendener {
-
-        /**
-         * Use Apache Batik to render WMF,
-         * delegate all other types of images to the javax.imageio framework
-       */
-        @Override
-        public boolean drawImage(Graphics2D graphics, XSLFPictureData data,
-                                 Rectangle2D anchor) {
-            try {
-                // see what type of image we are
-                PackagePart part = data.getPackagePart();
-                String contentType = part.getContentType();
-                if (contentType.equals("image/x-wmf")) {
-                    WMFRecordStore currentStore = new WMFRecordStore();
-                    currentStore.read(new DataInputStream(part.getInputStream()));
-                    int wmfwidth = currentStore.getWidthPixels();
-                    float conv = (float) anchor.getWidth() / wmfwidth;
-
-                    // Build a painter for the RecordStore
-                    WMFPainter painter = new WMFPainter(currentStore,
-                            (int) anchor.getX(), (int) anchor.getY(), conv);
-                    painter.paint(graphics);
-                } else {
-                    BufferedImage img = ImageIO.read(data.getPackagePart().getInputStream());
-                    graphics.drawImage(img,
-                            (int) anchor.getX(), (int) anchor.getY(),
-                            (int) anchor.getWidth(), (int) anchor.getHeight(), null);
-                }
-            } catch (Exception e) {
-                return false;
-            }
-            return true;
-        }
-
-        /**
-         * Convert data form the supplied package part into a BufferedImage.
-         * This method is used to create texture paint.
-         */
-        @Override
-        public BufferedImage readImage(PackagePart packagePart) throws IOException {
-            String contentType = packagePart.getContentType();
-            if (contentType.equals("image/x-wmf")) {
-                try {
-                    WMFRecordStore currentStore = new WMFRecordStore();
-                    currentStore.read(new DataInputStream(packagePart.getInputStream()));
-                    int wmfwidth = currentStore.getWidthPixels();
-                    int wmfheight = currentStore.getHeightPixels();
-
-                    BufferedImage img = new BufferedImage(wmfwidth, wmfheight, BufferedImage.TYPE_INT_RGB);
-                    Graphics2D graphics = img.createGraphics();
-
-                    // Build a painter for the RecordStore
-                    WMFPainter painter = new WMFPainter(currentStore, 0, 0, 1.0f);
-                    painter.paint(graphics);
-
-                    return img;
-                } catch (IOException e) {
-                    return null;
-                }
-            } else {
-                return ImageIO.read(packagePart.getInputStream());
-            }
-        }
-
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/PieChartDemo.java b/src/examples/src/org/apache/poi/xslf/usermodel/PieChartDemo.java
deleted file mode 100644 (file)
index 15036a8..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.poi.ooxml.POIXMLDocumentPart;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
-import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
-
-/**
- * Build a pie chart from a template pptx
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class PieChartDemo {
-    private PieChartDemo() {}
-
-    private static void usage(){
-        System.out.println("Usage: PieChartDemo <pie-chart-template.pptx> <pie-chart-data.txt>");
-        System.out.println("    pie-chart-template.pptx     template with a pie chart");
-        System.out.println("    pie-chart-data.txt          the model to set. First line is chart title, " +
-                "then go pairs {axis-label value}");
-    }
-
-    public static void main(String[] args) throws Exception {
-        if(args.length < 2) {
-            usage();
-            return;
-        }
-
-        try (FileInputStream argIS = new FileInputStream(args[0]);
-            BufferedReader modelReader = new BufferedReader(new FileReader(args[1]))) {
-            String chartTitle = modelReader.readLine();  // first line is chart title
-
-            try (XMLSlideShow pptx = new XMLSlideShow(argIS)) {
-                XSLFSlide slide = pptx.getSlides().get(0);
-
-                // find chart in the slide
-                XSLFChart chart = null;
-                for (POIXMLDocumentPart part : slide.getRelations()) {
-                    if (part instanceof XSLFChart) {
-                        chart = (XSLFChart) part;
-                        break;
-                    }
-                }
-
-                   if(chart == null) {
-                       throw new IllegalStateException("chart not found in the template");
-                   }
-
-                   // Series Text
-                   List<XDDFChartData> series = chart.getChartSeries();
-                   XDDFPieChartData pie = (XDDFPieChartData) series.get(0);
-
-                   // Category Axis Data
-                   List<String> listCategories = new ArrayList<>(3);
-
-                   // Values
-                   List<Double> listValues = new ArrayList<>(3);
-
-                   // set model
-                   String ln;
-                   while((ln = modelReader.readLine()) != null){
-                       String[] vals = ln.split("\\s+");
-                       listCategories.add(vals[0]);
-                       listValues.add(Double.valueOf(vals[1]));
-                   }
-                   String[] categories = listCategories.toArray(new String[0]);
-                   Double[] values = listValues.toArray(new Double[0]);
-
-                   final int numOfPoints = categories.length;
-                   final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
-                   final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
-                   final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange);
-                   final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values, valuesDataRange);
-
-                   XDDFPieChartData.Series firstSeries = (XDDFPieChartData.Series) pie.getSeries(0);
-                   firstSeries.replaceData(categoriesData, valuesData);
-                   firstSeries.setTitle(chartTitle, chart.setSheetTitle(chartTitle, 0));
-                   firstSeries.setExplosion(25L);
-                   chart.plot(pie);
-
-                // save the result
-                try (OutputStream out = new FileOutputStream("pie-chart-demo-output.pptx")) {
-                    pptx.write(out);
-                }
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial1.java b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial1.java
deleted file mode 100644 (file)
index 34a33f7..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ==================================================================== 
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Demonstrates how to create slides with predefined layout
- * and fill the placeholder shapes
- */
-public final class Tutorial1 {
-    private Tutorial1() {}
-
-    public static void main(String[] args) throws IOException{
-        try (XMLSlideShow ppt = new XMLSlideShow()) {
-            // XSLFSlide#createSlide() with no arguments creates a blank slide
-            /*XSLFSlide blankSlide =*/
-            ppt.createSlide();
-
-
-            XSLFSlideMaster master = ppt.getSlideMasters().get(0);
-
-            XSLFSlideLayout layout1 = master.getLayout(SlideLayout.TITLE);
-            XSLFSlide slide1 = ppt.createSlide(layout1);
-            XSLFTextShape[] ph1 = slide1.getPlaceholders();
-            XSLFTextShape titlePlaceholder1 = ph1[0];
-            titlePlaceholder1.setText("This is a title");
-            XSLFTextShape subtitlePlaceholder1 = ph1[1];
-            subtitlePlaceholder1.setText("this is a subtitle");
-
-            XSLFSlideLayout layout2 = master.getLayout(SlideLayout.TITLE_AND_CONTENT);
-            XSLFSlide slide2 = ppt.createSlide(layout2);
-            XSLFTextShape[] ph2 = slide2.getPlaceholders();
-            XSLFTextShape titlePlaceholder2 = ph2[0];
-            titlePlaceholder2.setText("This is a title");
-            XSLFTextShape bodyPlaceholder = ph2[1];
-            // we are going to add text by paragraphs. Clear the default placehoder text before that
-            bodyPlaceholder.clearText();
-            XSLFTextParagraph p1 = bodyPlaceholder.addNewTextParagraph();
-            p1.setIndentLevel(0);
-            p1.addNewTextRun().setText("Level1 text");
-            XSLFTextParagraph p2 = bodyPlaceholder.addNewTextParagraph();
-            p2.setIndentLevel(1);
-            p2.addNewTextRun().setText("Level2 text");
-            XSLFTextParagraph p3 = bodyPlaceholder.addNewTextParagraph();
-            p3.setIndentLevel(2);
-            p3.addNewTextRun().setText("Level3 text");
-
-            try (FileOutputStream out = new FileOutputStream("slides.pptx")) {
-                ppt.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial2.java b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial2.java
deleted file mode 100644 (file)
index b1c1e1e..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ==================================================================== 
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import java.awt.Color;
-import java.awt.Rectangle;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Basic paragraph and text formatting
- */
-public final class Tutorial2 {
-    private Tutorial2() {}
-
-    public static void main(String[] args) throws IOException{
-        try (XMLSlideShow ppt = new XMLSlideShow()) {
-            XSLFSlide slide1 = ppt.createSlide();
-            XSLFTextBox shape1 = slide1.createTextBox();
-            // initial height of the text box is 100 pt but
-            Rectangle anchor = new Rectangle(10, 100, 300, 100);
-            shape1.setAnchor(anchor);
-
-            XSLFTextParagraph p1 = shape1.addNewTextParagraph();
-            XSLFTextRun r1 = p1.addNewTextRun();
-            r1.setText("Paragraph Formatting");
-            r1.setFontSize(24d);
-            r1.setFontColor(new Color(85, 142, 213));
-
-            XSLFTextParagraph p2 = shape1.addNewTextParagraph();
-            // If spaceBefore >= 0, then space is a percentage of normal line height.
-            // If spaceBefore < 0, the absolute value of linespacing is the spacing in points
-            p2.setSpaceBefore(-20d); // 20 pt from the previous paragraph
-            p2.setSpaceAfter(300d); // 3 lines after the paragraph
-            XSLFTextRun r2 = p2.addNewTextRun();
-            r2.setText("Paragraph  properties apply to all text residing within the corresponding paragraph.");
-            r2.setFontSize(16d);
-
-            XSLFTextParagraph p3 = shape1.addNewTextParagraph();
-
-            XSLFTextRun r3 = p3.addNewTextRun();
-            r3.setText("Run Formatting");
-            r3.setFontSize(24d);
-            r3.setFontColor(new Color(85, 142, 213));
-
-            XSLFTextParagraph p4 = shape1.addNewTextParagraph();
-            p4.setSpaceBefore(-20d); // 20 pt from the previous paragraph
-            p4.setSpaceAfter(300d); // 3 lines after the paragraph
-            XSLFTextRun r4 = p4.addNewTextRun();
-            r4.setFontSize(16d);
-            r4.setText(
-                    "Run level formatting is the most granular property level and allows " +
-                            "for the specifying of all low level text properties. The text run is " +
-                            "what all paragraphs are derived from and thus specifying various " +
-                            "properties per run will allow for a diversely formatted text paragraph.");
-
-            // resize the shape to fit text
-            shape1.resizeToFitText();
-
-            try (FileOutputStream out = new FileOutputStream("text.pptx")) {
-                ppt.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial3.java b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial3.java
deleted file mode 100644 (file)
index 15b8660..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ==================================================================== 
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import java.awt.Rectangle;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.sl.usermodel.Placeholder;
-
-/**
- * How to set slide title
- */
-public final class Tutorial3 {
-    private Tutorial3() {}
-
-    public static void main(String[] args) throws IOException{
-        try (XMLSlideShow ppt = new XMLSlideShow()) {
-            XSLFSlide slide = ppt.createSlide();
-
-            XSLFTextShape titleShape = slide.createTextBox();
-            titleShape.setPlaceholder(Placeholder.TITLE);
-            titleShape.setText("This is a slide title");
-            titleShape.setAnchor(new Rectangle(50, 50, 400, 100));
-
-            try (FileOutputStream out = new FileOutputStream("title.pptx")) {
-                ppt.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial4.java b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial4.java
deleted file mode 100644 (file)
index 68648ab..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ==================================================================== 
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import java.awt.Color;
-import java.awt.Rectangle;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.sl.usermodel.TableCell.BorderEdge;
-import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
-
-/**
- * PPTX Tables
- */
-public final class Tutorial4 {
-    private Tutorial4() {}
-
-    public static void main(String[] args) throws IOException{
-        try (XMLSlideShow ppt = new XMLSlideShow()) {
-            // XSLFSlide#createSlide() with no arguments creates a blank slide
-            XSLFSlide slide = ppt.createSlide();
-
-            XSLFTable tbl = slide.createTable();
-            tbl.setAnchor(new Rectangle(50, 50, 450, 300));
-
-            int numColumns = 3;
-            int numRows = 5;
-            XSLFTableRow headerRow = tbl.addRow();
-            headerRow.setHeight(50);
-            // header
-            for (int i = 0; i < numColumns; i++) {
-                XSLFTableCell th = headerRow.addCell();
-                XSLFTextParagraph p = th.addNewTextParagraph();
-                p.setTextAlign(TextAlign.CENTER);
-                XSLFTextRun r = p.addNewTextRun();
-                r.setText("Header " + (i + 1));
-                r.setBold(true);
-                r.setFontColor(Color.white);
-                th.setFillColor(new Color(79, 129, 189));
-                th.setBorderWidth(BorderEdge.bottom, 2.0);
-                th.setBorderColor(BorderEdge.bottom, Color.white);
-
-                tbl.setColumnWidth(i, 150);  // all columns are equally sized
-            }
-
-            // rows
-
-            for (int rownum = 0; rownum < numRows; rownum++) {
-                XSLFTableRow tr = tbl.addRow();
-                tr.setHeight(50);
-                // header
-                for (int i = 0; i < numColumns; i++) {
-                    XSLFTableCell cell = tr.addCell();
-                    XSLFTextParagraph p = cell.addNewTextParagraph();
-                    XSLFTextRun r = p.addNewTextRun();
-
-                    r.setText("Cell " + (i + 1));
-                    if (rownum % 2 == 0)
-                        cell.setFillColor(new Color(208, 216, 232));
-                    else
-                        cell.setFillColor(new Color(233, 247, 244));
-
-                }
-            }
-
-            try (FileOutputStream out = new FileOutputStream("table.pptx")) {
-                ppt.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial5.java b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial5.java
deleted file mode 100644 (file)
index 4230cc2..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ==================================================================== 
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.sl.usermodel.PictureData.PictureType;
-
-/**
- * Images
- */
-public final class Tutorial5 {
-    private Tutorial5() {}
-
-    public static void main(String[] args) throws IOException{
-        try (XMLSlideShow ppt = new XMLSlideShow()) {
-            XSLFSlide slide = ppt.createSlide();
-
-            File img = new File(System.getProperty("POI.testdata.path", "test-data"), "slideshow/clock.jpg");
-            XSLFPictureData pictureData = ppt.addPicture(img, PictureType.PNG);
-
-            /*XSLFPictureShape shape =*/
-            slide.createPicture(pictureData);
-
-            try (FileOutputStream out = new FileOutputStream("images.pptx")) {
-                ppt.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial6.java b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial6.java
deleted file mode 100644 (file)
index 8ddd6ce..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import java.awt.Rectangle;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Hyperlinks
- */
-public final class Tutorial6 {
-    private Tutorial6() {}
-
-    public static void main(String[] args) throws IOException{
-        try (XMLSlideShow ppt = new XMLSlideShow()) {
-            XSLFSlide slide1 = ppt.createSlide();
-            XSLFSlide slide2 = ppt.createSlide();
-
-            XSLFTextBox shape1 = slide1.createTextBox();
-            shape1.setAnchor(new Rectangle(50, 50, 200, 50));
-            XSLFTextRun r1 = shape1.addNewTextParagraph().addNewTextRun();
-            XSLFHyperlink link1 = r1.createHyperlink();
-            r1.setText("https://poi.apache.org"); // visible text
-            link1.setAddress("https://poi.apache.org");  // link address
-
-            XSLFTextBox shape2 = slide1.createTextBox();
-            shape2.setAnchor(new Rectangle(300, 50, 200, 50));
-            XSLFTextRun r2 = shape2.addNewTextParagraph().addNewTextRun();
-            XSLFHyperlink link2 = r2.createHyperlink();
-            r2.setText("Go to the second slide"); // visible text
-            link2.linkToSlide(slide2);  // link address
-
-
-            try (FileOutputStream out = new FileOutputStream("hyperlinks.pptx")) {
-                ppt.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial7.java b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial7.java
deleted file mode 100644 (file)
index 2fcd9c3..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ==================================================================== 
- */
-
-package org.apache.poi.xslf.usermodel;
-
-import java.awt.Color;
-import java.awt.Rectangle;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.sl.usermodel.AutoNumberingScheme;
-
-/**
- * Bullets and numbering
- */
-public final class Tutorial7 {
-    private Tutorial7() {}
-
-    public static void main(String[] args) throws IOException {
-        try (XMLSlideShow ppt = new XMLSlideShow()) {
-            XSLFSlide slide = ppt.createSlide();
-            XSLFTextBox shape = slide.createTextBox();
-            shape.setAnchor(new Rectangle(50, 50, 400, 200));
-
-            XSLFTextParagraph p1 = shape.addNewTextParagraph();
-            p1.setIndentLevel(0);
-            p1.setBullet(true);
-            XSLFTextRun r1 = p1.addNewTextRun();
-            r1.setText("Bullet1");
-
-            XSLFTextParagraph p2 = shape.addNewTextParagraph();
-            // indentation before text
-            p2.setLeftMargin(60d);
-            // the bullet is set 40 pt before the text
-            p2.setIndent(-40d);
-            p2.setBullet(true);
-            // customize bullets
-            p2.setBulletFontColor(Color.red);
-            p2.setBulletFont("Wingdings");
-            p2.setBulletCharacter("\u0075");
-            p2.setIndentLevel(1);
-            XSLFTextRun r2 = p2.addNewTextRun();
-            r2.setText("Bullet2");
-
-            // the next three paragraphs form an auto-numbered list
-            XSLFTextParagraph p3 = shape.addNewTextParagraph();
-            p3.setBulletAutoNumber(AutoNumberingScheme.alphaLcParenRight, 1);
-            p3.setIndentLevel(2);
-            XSLFTextRun r3 = p3.addNewTextRun();
-            r3.setText("Numbered List Item - 1");
-
-            XSLFTextParagraph p4 = shape.addNewTextParagraph();
-            p4.setBulletAutoNumber(AutoNumberingScheme.alphaLcParenRight, 2);
-            p4.setIndentLevel(2);
-            XSLFTextRun r4 = p4.addNewTextRun();
-            r4.setText("Numbered List Item - 2");
-
-            XSLFTextParagraph p5 = shape.addNewTextParagraph();
-            p5.setBulletAutoNumber(AutoNumberingScheme.alphaLcParenRight, 3);
-            p5.setIndentLevel(2);
-            XSLFTextRun r5 = p5.addNewTextRun();
-            r5.setText("Numbered List Item - 3");
-
-            shape.resizeToFitText();
-
-            try (FileOutputStream out = new FileOutputStream("list.pptx")) {
-                ppt.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/bar-chart-data.txt b/src/examples/src/org/apache/poi/xslf/usermodel/bar-chart-data.txt
deleted file mode 100644 (file)
index 22c7b86..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-10 languages with most speakers as first language\r
-countries,speakers,language\r
-58,315,العربية\r
-4,243,বাংলা\r
-38,1299,中文\r
-118,378,English\r
-4,260,हिन्दी\r
-2,128,日本語\r
-15,223,português\r
-6,119,ਪੰਜਾਬੀ\r
-18,154,Русский язык\r
-31,442,español\r
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/bar-chart-template.pptx b/src/examples/src/org/apache/poi/xslf/usermodel/bar-chart-template.pptx
deleted file mode 100644 (file)
index e4d2613..0000000
Binary files a/src/examples/src/org/apache/poi/xslf/usermodel/bar-chart-template.pptx and /dev/null differ
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/pie-chart-data.txt b/src/examples/src/org/apache/poi/xslf/usermodel/pie-chart-data.txt
deleted file mode 100644 (file)
index 40b6959..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-My Chart\r
-First 1.0\r
-Second 3.0\r
-Third 4.0
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/pie-chart-template.pptx b/src/examples/src/org/apache/poi/xslf/usermodel/pie-chart-template.pptx
deleted file mode 100644 (file)
index 33d28e1..0000000
Binary files a/src/examples/src/org/apache/poi/xslf/usermodel/pie-chart-template.pptx and /dev/null differ
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step1.java b/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step1.java
deleted file mode 100644 (file)
index 6651bcc..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xslf.usermodel.tutorial;
-
-import java.io.FileInputStream;
-
-import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.apache.poi.xslf.usermodel.XSLFShape;
-import org.apache.poi.xslf.usermodel.XSLFSlide;
-import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
-import org.apache.poi.xslf.usermodel.XSLFTextRun;
-import org.apache.poi.xslf.usermodel.XSLFTextShape;
-
-/**
- * Reading a .pptx presentation and printing basic shape properties
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class Step1 {
-    private Step1() {}
-
-    public static void main(String[] args) throws Exception {
-        if(args.length == 0)  {
-            System.out.println("Input file is required");
-            return;
-        }
-
-        FileInputStream fis = new FileInputStream(args[0]);
-        try (XMLSlideShow ppt = new XMLSlideShow(fis)) {
-            fis.close();
-
-            for (XSLFSlide slide : ppt.getSlides()) {
-                System.out.println("Title: " + slide.getTitle());
-
-                for (XSLFShape shape : slide.getShapes()) {
-                    if (shape instanceof XSLFTextShape) {
-                        XSLFTextShape tsh = (XSLFTextShape) shape;
-                        for (XSLFTextParagraph p : tsh) {
-                            System.out.println("Paragraph level: " + p.getIndentLevel());
-                            for (XSLFTextRun r : p) {
-                                System.out.println(r.getRawText());
-                                System.out.println("  bold: " + r.isBold());
-                                System.out.println("  italic: " + r.isItalic());
-                                System.out.println("  underline: " + r.isUnderlined());
-                                System.out.println("  font.family: " + r.getFontFamily());
-                                System.out.println("  font.size: " + r.getFontSize());
-                                System.out.println("  font.color: " + r.getFontColor());
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step2.java b/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step2.java
deleted file mode 100644 (file)
index 03fd4f6..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xslf.usermodel.tutorial;
-
-import org.apache.poi.xslf.usermodel.SlideLayout;
-import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.apache.poi.xslf.usermodel.XSLFSlide;
-import org.apache.poi.xslf.usermodel.XSLFSlideLayout;
-import org.apache.poi.xslf.usermodel.XSLFSlideMaster;
-import org.apache.poi.xslf.usermodel.XSLFTextShape;
-
-import java.io.FileOutputStream;
-
-/**
- * Create slides from pre-defined slide layouts
- */
-public final class Step2 {
-    private Step2() {}
-
-    public static void main(String[] args) throws Exception{
-        try (XMLSlideShow ppt = new XMLSlideShow()) {
-
-            // first see what slide layouts are available by default
-            System.out.println("Available slide layouts:");
-            for (XSLFSlideMaster master : ppt.getSlideMasters()) {
-                for (XSLFSlideLayout layout : master.getSlideLayouts()) {
-                    System.out.println(layout.getType());
-                }
-            }
-
-            // blank slide
-        /*XSLFSlide blankSlide =*/
-            ppt.createSlide();
-
-            XSLFSlideMaster defaultMaster = ppt.getSlideMasters().get(0);
-
-            // title slide
-            XSLFSlideLayout titleLayout = defaultMaster.getLayout(SlideLayout.TITLE);
-            XSLFSlide slide1 = ppt.createSlide(titleLayout);
-            XSLFTextShape title1 = slide1.getPlaceholder(0);
-            title1.setText("First Title");
-
-            // title and content
-            XSLFSlideLayout titleBodyLayout = defaultMaster.getLayout(SlideLayout.TITLE_AND_CONTENT);
-            XSLFSlide slide2 = ppt.createSlide(titleBodyLayout);
-
-            XSLFTextShape title2 = slide2.getPlaceholder(0);
-            title2.setText("Second Title");
-
-            XSLFTextShape body2 = slide2.getPlaceholder(1);
-            body2.clearText(); // unset any existing text
-            body2.addNewTextParagraph().addNewTextRun().setText("First paragraph");
-            body2.addNewTextParagraph().addNewTextRun().setText("Second paragraph");
-            body2.addNewTextParagraph().addNewTextRun().setText("Third paragraph");
-
-
-            try (FileOutputStream out = new FileOutputStream("step2.pptx")) {
-                ppt.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/eventusermodel/XLSX2CSV.java b/src/examples/src/org/apache/poi/xssf/eventusermodel/XLSX2CSV.java
deleted file mode 100644 (file)
index 5b9a519..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.eventusermodel;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintStream;
-
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.openxml4j.opc.PackageAccess;
-import org.apache.poi.ss.usermodel.DataFormatter;
-import org.apache.poi.ss.util.CellAddress;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.util.XMLHelper;
-import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
-import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor;
-import org.apache.poi.xssf.model.SharedStrings;
-import org.apache.poi.xssf.model.Styles;
-import org.apache.poi.xssf.model.StylesTable;
-import org.apache.poi.xssf.usermodel.XSSFComment;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-
-/**
- * A rudimentary XLSX -> CSV processor modeled on the
- * POI sample program XLS2CSVmra from the package
- * org.apache.poi.hssf.eventusermodel.examples.
- * As with the HSSF version, this tries to spot missing
- *  rows and cells, and output empty entries for them.
- * <p>
- * Data sheets are read using a SAX parser to keep the
- * memory footprint relatively small, so this should be
- * able to read enormous workbooks.  The styles table and
- * the shared-string table must be kept in memory.  The
- * standard POI styles table class is used, but a custom
- * (read-only) class is used for the shared string table
- * because the standard POI SharedStringsTable grows very
- * quickly with the number of unique strings.
- * <p>
- * For a more advanced implementation of SAX event parsing
- * of XLSX files, see {@link XSSFEventBasedExcelExtractor}
- * and {@link XSSFSheetXMLHandler}. Note that for many cases,
- * it may be possible to simply use those with a custom
- * {@link SheetContentsHandler} and no SAX code needed of
- * your own!
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public class XLSX2CSV {
-    /**
-     * Uses the XSSF Event SAX helpers to do most of the work
-     *  of parsing the Sheet XML, and outputs the contents
-     *  as a (basic) CSV.
-     */
-    private class SheetToCSV implements SheetContentsHandler {
-        private boolean firstCellOfRow;
-        private int currentRow = -1;
-        private int currentCol = -1;
-
-        private void outputMissingRows(int number) {
-            for (int i=0; i<number; i++) {
-                for (int j=0; j<minColumns; j++) {
-                    output.append(',');
-                }
-                output.append('\n');
-            }
-        }
-
-        @Override
-        public void startRow(int rowNum) {
-            // If there were gaps, output the missing rows
-            outputMissingRows(rowNum-currentRow-1);
-            // Prepare for this row
-            firstCellOfRow = true;
-            currentRow = rowNum;
-            currentCol = -1;
-        }
-
-        @Override
-        public void endRow(int rowNum) {
-            // Ensure the minimum number of columns
-            for (int i=currentCol; i<minColumns; i++) {
-                output.append(',');
-            }
-            output.append('\n');
-        }
-
-        @Override
-        public void cell(String cellReference, String formattedValue,
-                XSSFComment comment) {
-            if (firstCellOfRow) {
-                firstCellOfRow = false;
-            } else {
-                output.append(',');
-            }
-
-            // gracefully handle missing CellRef here in a similar way as XSSFCell does
-            if(cellReference == null) {
-                cellReference = new CellAddress(currentRow, currentCol).formatAsString();
-            }
-
-            // Did we miss any cells?
-            int thisCol = (new CellReference(cellReference)).getCol();
-            int missedCols = thisCol - currentCol - 1;
-            for (int i=0; i<missedCols; i++) {
-                output.append(',');
-            }
-            currentCol = thisCol;
-
-            // Number or string?
-            try {
-                //noinspection ResultOfMethodCallIgnored
-                Double.parseDouble(formattedValue);
-                output.append(formattedValue);
-            } catch (Exception e) {
-                output.append('"');
-                output.append(formattedValue);
-                output.append('"');
-            }
-        }
-    }
-
-
-    ///////////////////////////////////////
-
-    private final OPCPackage xlsxPackage;
-
-    /**
-     * Number of columns to read starting with leftmost
-     */
-    private final int minColumns;
-
-    /**
-     * Destination for data
-     */
-    private final PrintStream output;
-
-    /**
-     * Creates a new XLSX -> CSV examples
-     *
-     * @param pkg        The XLSX package to process
-     * @param output     The PrintStream to output the CSV to
-     * @param minColumns The minimum number of columns to output, or -1 for no minimum
-     */
-    public XLSX2CSV(OPCPackage pkg, PrintStream output, int minColumns) {
-        this.xlsxPackage = pkg;
-        this.output = output;
-        this.minColumns = minColumns;
-    }
-
-    /**
-     * Parses and shows the content of one sheet
-     * using the specified styles and shared-strings tables.
-     *
-     * @param styles The table of styles that may be referenced by cells in the sheet
-     * @param strings The table of strings that may be referenced by cells in the sheet
-     * @param sheetInputStream The stream to read the sheet-data from.
-
-     * @exception java.io.IOException An IO exception from the parser,
-     *            possibly from a byte stream or character stream
-     *            supplied by the application.
-     * @throws SAXException if parsing the XML data fails.
-     */
-    public void processSheet(
-            Styles styles,
-            SharedStrings strings,
-            SheetContentsHandler sheetHandler,
-            InputStream sheetInputStream) throws IOException, SAXException {
-        DataFormatter formatter = new DataFormatter();
-        InputSource sheetSource = new InputSource(sheetInputStream);
-        try {
-            XMLReader sheetParser = XMLHelper.newXMLReader();
-            ContentHandler handler = new XSSFSheetXMLHandler(
-                  styles, null, strings, sheetHandler, formatter, false);
-            sheetParser.setContentHandler(handler);
-            sheetParser.parse(sheetSource);
-         } catch(ParserConfigurationException e) {
-            throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage());
-         }
-    }
-
-    /**
-     * Initiates the processing of the XLS workbook file to CSV.
-     *
-     * @throws IOException If reading the data from the package fails.
-     * @throws SAXException if parsing the XML data fails.
-     */
-    public void process() throws IOException, OpenXML4JException, SAXException {
-        ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(this.xlsxPackage);
-        XSSFReader xssfReader = new XSSFReader(this.xlsxPackage);
-        StylesTable styles = xssfReader.getStylesTable();
-        XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
-        int index = 0;
-        while (iter.hasNext()) {
-            try (InputStream stream = iter.next()) {
-                String sheetName = iter.getSheetName();
-                this.output.println();
-                this.output.println(sheetName + " [index=" + index + "]:");
-                processSheet(styles, strings, new SheetToCSV(), stream);
-            }
-            ++index;
-        }
-    }
-
-    public static void main(String[] args) throws Exception {
-        if (args.length < 1) {
-            System.err.println("Use:");
-            System.err.println("  XLSX2CSV <xlsx file> [min columns]");
-            return;
-        }
-
-        File xlsxFile = new File(args[0]);
-        if (!xlsxFile.exists()) {
-            System.err.println("Not found or not a file: " + xlsxFile.getPath());
-            return;
-        }
-
-        int minColumns = -1;
-        if (args.length >= 2)
-            minColumns = Integer.parseInt(args[1]);
-
-        // The package open is instantaneous, as it should be.
-        try (OPCPackage p = OPCPackage.open(xlsxFile.getPath(), PackageAccess.READ)) {
-            XLSX2CSV xlsx2csv = new XLSX2CSV(p, System.out, minColumns);
-            xlsx2csv.process();
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java b/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java
deleted file mode 100644 (file)
index 3c79e1c..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.eventusermodel.examples;
-
-import java.io.InputStream;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.openxml4j.opc.PackageAccess;
-import org.apache.poi.util.XMLHelper;
-import org.apache.poi.xssf.eventusermodel.XLSX2CSV;
-import org.apache.poi.xssf.eventusermodel.XSSFReader;
-import org.apache.poi.xssf.model.SharedStringsTable;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.DefaultHandler;
-
-/**
- * XSSF and SAX (Event API) basic example.
- * See {@link XLSX2CSV} for a fuller example of doing
- *  XSLX processing with the XSSF Event code.
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public class FromHowTo {
-    public void processFirstSheet(String filename) throws Exception {
-        try (OPCPackage pkg = OPCPackage.open(filename, PackageAccess.READ)) {
-            XSSFReader r = new XSSFReader(pkg);
-            SharedStringsTable sst = r.getSharedStringsTable();
-
-            XMLReader parser = fetchSheetParser(sst);
-
-            // process the first sheet
-            try (InputStream sheet = r.getSheetsData().next()) {
-                               InputSource sheetSource = new InputSource(sheet);
-                               parser.parse(sheetSource);
-                       }
-        }
-    }
-
-    public void processAllSheets(String filename) throws Exception {
-        try (OPCPackage pkg = OPCPackage.open(filename, PackageAccess.READ)) {
-            XSSFReader r = new XSSFReader(pkg);
-            SharedStringsTable sst = r.getSharedStringsTable();
-
-            XMLReader parser = fetchSheetParser(sst);
-
-            Iterator<InputStream> sheets = r.getSheetsData();
-            while (sheets.hasNext()) {
-                System.out.println("Processing new sheet:\n");
-                try (InputStream sheet = sheets.next()) {
-                                       InputSource sheetSource = new InputSource(sheet);
-                                       parser.parse(sheetSource);
-                               }
-                System.out.println();
-            }
-        }
-    }
-
-    public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException, ParserConfigurationException {
-        XMLReader parser = XMLHelper.newXMLReader();
-        ContentHandler handler = new SheetHandler(sst);
-        parser.setContentHandler(handler);
-        return parser;
-    }
-
-    /**
-     * See org.xml.sax.helpers.DefaultHandler javadocs
-     */
-    private static class SheetHandler extends DefaultHandler {
-        private final SharedStringsTable sst;
-        private String lastContents;
-        private boolean nextIsString;
-        private boolean inlineStr;
-        private final LruCache<Integer,String> lruCache = new LruCache<>(50);
-
-        private static class LruCache<A,B> extends LinkedHashMap<A, B> {
-            private final int maxEntries;
-
-            public LruCache(final int maxEntries) {
-                super(maxEntries + 1, 1.0f, true);
-                this.maxEntries = maxEntries;
-            }
-
-            @Override
-            protected boolean removeEldestEntry(final Map.Entry<A, B> eldest) {
-                return super.size() > maxEntries;
-            }
-        }
-
-        private SheetHandler(SharedStringsTable sst) {
-            this.sst = sst;
-        }
-
-        @Override
-        public void startElement(String uri, String localName, String name,
-                                 Attributes attributes) throws SAXException {
-            // c => cell
-            if(name.equals("c")) {
-                // Print the cell reference
-                System.out.print(attributes.getValue("r") + " - ");
-                // Figure out if the value is an index in the SST
-                String cellType = attributes.getValue("t");
-                nextIsString = cellType != null && cellType.equals("s");
-                inlineStr = cellType != null && cellType.equals("inlineStr");
-            }
-            // Clear contents cache
-            lastContents = "";
-        }
-
-        @Override
-        public void endElement(String uri, String localName, String name)
-                throws SAXException {
-            // Process the last contents as required.
-            // Do now, as characters() may be called more than once
-            if(nextIsString && !lastContents.trim().isEmpty()) {
-                Integer idx = Integer.valueOf(lastContents);
-                lastContents = lruCache.get(idx);
-                if (lastContents == null && !lruCache.containsKey(idx)) {
-                    lastContents = sst.getItemAt(idx).toString();
-                    lruCache.put(idx, lastContents);
-                }
-                nextIsString = false;
-            }
-
-            // v => contents of a cell
-            // Output after we've seen the string contents
-            if(name.equals("v") || (inlineStr && name.equals("c"))) {
-                System.out.println(lastContents);
-            }
-        }
-
-        @Override
-        public void characters(char[] ch, int start, int length) throws SAXException { // NOSONAR
-            lastContents += new String(ch, start, length);
-        }
-    }
-
-    public static void main(String[] args) throws Exception {
-        FromHowTo howto = new FromHowTo();
-        howto.processFirstSheet(args[0]);
-        howto.processAllSheets(args[0]);
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/LoadPasswordProtectedXlsxStreaming.java b/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/LoadPasswordProtectedXlsxStreaming.java
deleted file mode 100644 (file)
index 7a3ad6b..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xssf.eventusermodel.examples;
-
-import java.io.InputStream;
-
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.poifs.crypt.temp.AesZipFileZipEntrySource;
-import org.apache.poi.xssf.eventusermodel.XSSFReader;
-import org.apache.poi.xssf.eventusermodel.XSSFReader.SheetIterator;
-import org.apache.poi.xssf.usermodel.examples.LoadPasswordProtectedXlsx;
-
-/**
- * An example that loads a password protected workbook and counts the sheets.
- * The example highlights how to do this in streaming way.
- * <p><ul>
- * <li>The example demonstrates that all temp files are removed.
- * <li><code>AesZipFileZipEntrySource</code> is used to ensure that temp files are encrypted.
- * </ul><p>
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class LoadPasswordProtectedXlsxStreaming {
-
-    private LoadPasswordProtectedXlsxStreaming() {}
-
-    public static void main(String[] args) throws Exception {
-        LoadPasswordProtectedXlsx.execute(args, LoadPasswordProtectedXlsxStreaming::printSheetCount);
-    }
-
-    private static void printSheetCount(final InputStream inputStream) throws Exception {
-        try (AesZipFileZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(inputStream);
-             OPCPackage pkg = OPCPackage.open(source)) {
-            XSSFReader reader = new XSSFReader(pkg);
-            SheetIterator iter = (SheetIterator)reader.getSheetsData();
-            int count = 0;
-            while(iter.hasNext()) {
-                iter.next();
-                count++;
-            }
-            System.out.println("sheet count: " + count);
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/streaming/examples/DeferredGeneration.java b/src/examples/src/org/apache/poi/xssf/streaming/examples/DeferredGeneration.java
deleted file mode 100644 (file)
index ce1db09..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xssf.streaming.examples;
-
-import org.apache.poi.xssf.streaming.DeferredSXSSFSheet;
-import org.apache.poi.xssf.streaming.DeferredSXSSFWorkbook;
-import org.apache.poi.xssf.streaming.SXSSFCell;
-import org.apache.poi.xssf.streaming.SXSSFRow;
-
-import java.io.FileOutputStream;
-
-/**
- * An example that outputs a simple generated workbook that uses deferred creation of the rows in the sheets.
- * When the workbook is written to an output stream, the output data is streamed immediately.
- * There is no collation of the data in temp files prior to writing the overall file.
- * This depends on how efficient the row generating functions are.
- */
-public final class DeferredGeneration {
-
-    private DeferredGeneration() {}
-
-    public static void main(String[] args) throws Exception {
-        String filename;
-        if(args.length == 0) {
-            filename = "deferred-generation.xlsx";
-        } else {
-            filename = args[0];
-        }
-        try (DeferredSXSSFWorkbook wb = new DeferredSXSSFWorkbook()){
-            for(int i = 0; i < 10; i++) {
-                DeferredSXSSFSheet sheet = wb.createSheet("Sheet" + i);
-                sheet.setRowGenerator((sh) -> {
-                    for (int r = 0; r < 1000; r++) {
-                        SXSSFRow row = sheet.createRow(r);
-                        for (int c = 0; c < 100; c++) {
-                            SXSSFCell cell = row.createCell(c);
-                            cell.setCellValue("abcd");
-                        }
-                    }
-                });
-            }
-            wb.write(new FileOutputStream(filename));
-            System.out.println("wrote " + filename);
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/streaming/examples/HybridStreaming.java b/src/examples/src/org/apache/poi/xssf/streaming/examples/HybridStreaming.java
deleted file mode 100644 (file)
index 2092475..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.streaming.examples;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
-import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
-import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
-import org.apache.poi.xssf.usermodel.XSSFComment;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
-import org.xml.sax.SAXException;
-
-/**
- * This demonstrates how a hybrid approach to workbook read can be taken, using 
- * a mix of traditional XSSF and streaming one particular worksheet (perhaps one
- * which is too big for the ordinary DOM parse).
- */
-public class HybridStreaming {
-    
-    private static final String SHEET_TO_STREAM = "large sheet";
-
-    public static void main(String[] args) throws IOException, SAXException {
-        try (InputStream sourceBytes = new FileInputStream("workbook.xlsx")) {
-            XSSFWorkbook workbook = new XSSFWorkbook(sourceBytes) {
-                /**
-                 * Avoid DOM parse of large sheet
-                 */
-                @Override
-                public void parseSheet(java.util.Map<String, XSSFSheet> shIdMap, CTSheet ctSheet) {
-                    if (!SHEET_TO_STREAM.equals(ctSheet.getName())) {
-                        super.parseSheet(shIdMap, ctSheet);
-                    }
-                }
-            };
-
-            // Having avoided a DOM-based parse of the sheet, we can stream it instead.
-            ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(workbook.getPackage());
-            new XSSFSheetXMLHandler(workbook.getStylesSource(), strings, createSheetContentsHandler(), false);
-            workbook.close();
-        }
-    }
-
-    private static SheetContentsHandler createSheetContentsHandler() {
-        return new SheetContentsHandler() {
-            
-            @Override
-            public void startRow(int rowNum) {
-            }
-            
-            @Override
-            public void endRow(int rowNum) {
-            }
-            
-            @Override
-            public void cell(String cellReference, String formattedValue, XSSFComment comment) {
-            }
-        };
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/streaming/examples/Outlining.java b/src/examples/src/org/apache/poi/xssf/streaming/examples/Outlining.java
deleted file mode 100644 (file)
index 7c892a8..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.streaming.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.xssf.streaming.SXSSFSheet;
-import org.apache.poi.xssf.streaming.SXSSFWorkbook;
-
-public class Outlining {
-
-       public static void main(String[] args) throws IOException {
-               Outlining o = new Outlining();
-               o.collapseRow();
-       }
-
-       private void collapseRow() throws IOException {
-               try (SXSSFWorkbook wb2 = new SXSSFWorkbook(100)) {
-                       SXSSFSheet sheet2 = wb2.createSheet("new sheet");
-
-                       int rowCount = 20;
-                       for (int i = 0; i < rowCount; i++) {
-                               sheet2.createRow(i);
-                       }
-
-                       sheet2.groupRow(4, 9);
-                       sheet2.groupRow(11, 19);
-
-                       sheet2.setRowGroupCollapsed(4, true);
-
-                       try (FileOutputStream fileOut = new FileOutputStream("outlining_collapsed.xlsx")) {
-                               wb2.write(fileOut);
-                       } finally {
-                               wb2.dispose();
-                       }
-               }
-       }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/streaming/examples/SavePasswordProtectedXlsx.java b/src/examples/src/org/apache/poi/xssf/streaming/examples/SavePasswordProtectedXlsx.java
deleted file mode 100644 (file)
index a20c87e..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xssf.streaming.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.GeneralSecurityException;
-
-import org.apache.poi.examples.util.TempFileUtils;
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.poifs.crypt.EncryptionInfo;
-import org.apache.poi.poifs.crypt.EncryptionMode;
-import org.apache.poi.poifs.crypt.Encryptor;
-import org.apache.poi.poifs.crypt.temp.EncryptedTempData;
-import org.apache.poi.poifs.crypt.temp.SXSSFWorkbookWithCustomZipEntrySource;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.xssf.streaming.SXSSFCell;
-import org.apache.poi.xssf.streaming.SXSSFRow;
-import org.apache.poi.xssf.streaming.SXSSFSheet;
-
-/**
- * An example that outputs a simple generated workbook that is password protected.
- * The example highlights how to do this in streaming way.
- * <p><ul>
- * <li>The example demonstrates that all temp files are removed.
- * <li><code>SXSSFWorkbookWithCustomZipEntrySource</code> extends SXSSFWorkbook to ensure temp files are encrypted.
- * </ul><p>
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class SavePasswordProtectedXlsx {
-
-    private SavePasswordProtectedXlsx() {}
-
-    public static void main(String[] args) throws Exception {
-        if(args.length != 2) {
-            throw new IllegalArgumentException("Expected 2 params: filename and password");
-        }
-        TempFileUtils.checkTempFiles();
-        String filename = args[0];
-        String password = args[1];
-        SXSSFWorkbookWithCustomZipEntrySource wb = new SXSSFWorkbookWithCustomZipEntrySource();
-        try {
-            for(int i = 0; i < 10; i++) {
-                SXSSFSheet sheet = wb.createSheet("Sheet" + i);
-                for(int r = 0; r < 1000; r++) {
-                    SXSSFRow row = sheet.createRow(r);
-                    for(int c = 0; c < 100; c++) {
-                        SXSSFCell cell = row.createCell(c);
-                        cell.setCellValue("abcd");
-                    }
-                }
-            }
-            EncryptedTempData tempData = new EncryptedTempData();
-            try {
-                wb.write(tempData.getOutputStream());
-                save(tempData.getInputStream(), filename, password);
-                System.out.println("Saved " + filename);
-            } finally {
-                tempData.dispose();
-            }
-        } finally {
-            wb.close();
-            wb.dispose();
-        }
-        TempFileUtils.checkTempFiles();
-    }
-
-    public static void save(final InputStream inputStream, final String filename, final String pwd)
-            throws InvalidFormatException, IOException, GeneralSecurityException {
-
-        try (POIFSFileSystem fs = new POIFSFileSystem();
-             OPCPackage opc = OPCPackage.open(inputStream);
-             FileOutputStream fos = new FileOutputStream(filename)) {
-            EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
-            Encryptor enc = Encryptor.getInstance(info);
-            enc.confirmPassword(pwd);
-            opc.save(enc.getDataStream(fs));
-            fs.writeFilesystem(fos);
-        } finally {
-            IOUtils.closeQuietly(inputStream);
-        }
-    }
-
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/AligningCells.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/AligningCells.java
deleted file mode 100644 (file)
index bee89d1..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/* ====================================================================
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.CreationHelper;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-import org.apache.poi.ss.usermodel.VerticalAlignment;
-import org.apache.poi.xssf.usermodel.XSSFCell;
-import org.apache.poi.xssf.usermodel.XSSFCellStyle;
-import org.apache.poi.xssf.usermodel.XSSFRow;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTRowImpl;
-
-/**
- * Shows how various alignment options work.
- *
- * Modified by Cristian Petrula, Romania on May 26, 2010
- * New method was added centerAcrossSelection to center a column content over 
- * one selection using {@link HorizontalAlignment#CENTER_SELECTION}
- * To create this method example was change for XSSF only and the previous
- * AligningCells.java example has been moved into the SS examples folder.
- */
-public class AligningCells {
-
-    public static void main(String[] args) throws IOException {
-        try (XSSFWorkbook wb = new XSSFWorkbook()) {
-
-            XSSFSheet sheet = wb.createSheet();
-            XSSFRow row = sheet.createRow(2);
-            row.setHeightInPoints(30);
-            for (int i = 0; i < 8; i++) {
-                //column width is set in units of 1/256th of a character width
-                sheet.setColumnWidth(i, 256 * 15);
-            }
-
-            createCell(wb, row, 0, HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
-            createCell(wb, row, 1, HorizontalAlignment.CENTER_SELECTION, VerticalAlignment.BOTTOM);
-            createCell(wb, row, 2, HorizontalAlignment.FILL, VerticalAlignment.CENTER);
-            createCell(wb, row, 3, HorizontalAlignment.GENERAL, VerticalAlignment.CENTER);
-            createCell(wb, row, 4, HorizontalAlignment.JUSTIFY, VerticalAlignment.JUSTIFY);
-            createCell(wb, row, 5, HorizontalAlignment.LEFT, VerticalAlignment.TOP);
-            createCell(wb, row, 6, HorizontalAlignment.RIGHT, VerticalAlignment.TOP);
-
-            //center text over B4, C4, D4
-            row = sheet.createRow(3);
-            centerAcrossSelection(wb, row, 1, 3, VerticalAlignment.CENTER);
-
-            // Write the output to a file
-            try (OutputStream fileOut = new FileOutputStream("xssf-align.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-
-    /**
-     * Creates a cell and aligns it a certain way.
-     *
-     * @param wb     the workbook
-     * @param row    the row to create the cell in
-     * @param column the column number to create the cell in
-     * @param halign the horizontal alignment for the cell.
-     */
-    private static void createCell(XSSFWorkbook wb, XSSFRow row, int column,
-                                   HorizontalAlignment halign, VerticalAlignment valign) {
-        CreationHelper ch = wb.getCreationHelper();
-        XSSFCell cell = row.createCell(column);
-        cell.setCellValue(ch.createRichTextString("Align It"));
-        CellStyle cellStyle = wb.createCellStyle();
-        cellStyle.setAlignment(halign);
-        cellStyle.setVerticalAlignment(valign);
-        cell.setCellStyle(cellStyle);
-    }
-
-    /**
-     * Center a text over multiple columns using ALIGN_CENTER_SELECTION
-     *
-     * @param wb the workbook
-     * @param row the row to create the cell in
-     * @param start_column  the column number to create the cell in and where the selection starts
-     * @param end_column    the column number where the selection ends
-     * @param valign the horizontal alignment for the cell.
-     */
-    private static void centerAcrossSelection(XSSFWorkbook wb, XSSFRow row,
-            int start_column, int end_column, VerticalAlignment valign) {
-        CreationHelper ch = wb.getCreationHelper();
-
-        // Create cell style with ALIGN_CENTER_SELECTION
-        XSSFCellStyle cellStyle = wb.createCellStyle();
-        cellStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);
-        cellStyle.setVerticalAlignment(valign);
-
-        // Create cells over the selected area
-        for (int i = start_column; i <= end_column; i++) {
-            XSSFCell cell = row.createCell(i);
-            cell.setCellStyle(cellStyle);
-        }
-
-        // Set value to the first cell
-        XSSFCell cell = row.getCell(start_column);
-        cell.setCellValue(ch.createRichTextString("Align It"));
-
-        // Make the selection
-        CTRowImpl ctRow = (CTRowImpl) row.getCTRow();
-
-        // Add object with format start_coll:end_coll. For example 1:3 will span from
-        // cell 1 to cell 3, where the column index starts with 0
-        //
-        // You can add multiple spans for one row
-        Object span = start_column + ":" + end_column;
-
-        List<Object> spanList = new ArrayList<>();
-        spanList.add(span);
-
-        //add spns to the row
-        ctRow.setSpans(spanList);
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/BarAndLineChart.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/BarAndLineChart.java
deleted file mode 100644 (file)
index 2ad12a3..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.util.Random;
-
-import org.apache.poi.common.usermodel.fonts.FontGroup;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xddf.usermodel.PresetColor;
-import org.apache.poi.xddf.usermodel.XDDFColor;
-import org.apache.poi.xddf.usermodel.XDDFFillProperties;
-import org.apache.poi.xddf.usermodel.XDDFLineProperties;
-import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
-import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
-import org.apache.poi.xddf.usermodel.chart.AxisPosition;
-import org.apache.poi.xddf.usermodel.chart.BarDirection;
-import org.apache.poi.xddf.usermodel.chart.ChartTypes;
-import org.apache.poi.xddf.usermodel.chart.LayoutMode;
-import org.apache.poi.xddf.usermodel.chart.LegendPosition;
-import org.apache.poi.xddf.usermodel.chart.MarkerStyle;
-import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
-import org.apache.poi.xddf.usermodel.chart.XDDFCategoryDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
-import org.apache.poi.xddf.usermodel.chart.XDDFLineChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFManualLayout;
-import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
-import org.apache.poi.xddf.usermodel.text.UnderlineType;
-import org.apache.poi.xddf.usermodel.text.XDDFFont;
-import org.apache.poi.xddf.usermodel.text.XDDFRunProperties;
-import org.apache.poi.xddf.usermodel.text.XDDFTextParagraph;
-import org.apache.poi.xssf.usermodel.XSSFCell;
-import org.apache.poi.xssf.usermodel.XSSFChart;
-import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
-import org.apache.poi.xssf.usermodel.XSSFDrawing;
-import org.apache.poi.xssf.usermodel.XSSFRow;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-// original contributions by Axel Richter on https://stackoverflow.com/questions/47065690
-// additional title formatting from https://stackoverflow.com/questions/50418856
-// and legend positioning from https://stackoverflow.com/questions/49615379
-// this would probably be an answer for https://stackoverflow.com/questions/36447925 too
-public final class BarAndLineChart {
-
-    private static final int NUM_OF_ROWS = 7;
-    private static final Random RNG = new Random();
-
-    private BarAndLineChart() {}
-
-    public static void main(String[] args) throws Exception {
-        try (XSSFWorkbook wb = new XSSFWorkbook()) {
-            XSSFSheet sheet = wb.createSheet("Sheet1");
-
-            XSSFRow row = sheet.createRow(0);
-            row.createCell(0);
-            row.createCell(1).setCellValue("Bars");
-            row.createCell(2).setCellValue("Lines");
-
-            XSSFCell cell;
-            for (int r = 1; r < NUM_OF_ROWS; r++) {
-                row = sheet.createRow(r);
-                cell = row.createCell(0);
-                cell.setCellValue("C" + r);
-                cell = row.createCell(1);
-                cell.setCellValue(RNG.nextDouble());
-                cell = row.createCell(2);
-                cell.setCellValue(RNG.nextDouble() * 10);
-            }
-
-            XSSFDrawing drawing = sheet.createDrawingPatriarch();
-            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 4, 0, 11, 15);
-
-            XSSFChart chart = drawing.createChart(anchor);
-            chart.setTitleText("This is my title");
-            chart.setTitleOverlay(true);
-            XDDFRunProperties properties = new XDDFRunProperties();
-            properties.setBold(true);
-            properties.setItalic(true);
-            properties.setUnderline(UnderlineType.DOT_DOT_DASH_HEAVY);
-            properties.setFontSize(22.5);
-            XDDFFont[] fonts = new XDDFFont[] {
-                    new XDDFFont(FontGroup.LATIN, "Calibri", null, null, null),
-                    new XDDFFont(FontGroup.COMPLEX_SCRIPT, "Liberation Sans", null, null, null)
-                    };
-            properties.setFonts(fonts);
-            properties.setLineProperties(new XDDFLineProperties(
-                    new XDDFSolidFillProperties(XDDFColor.from(PresetColor.SIENNA))));
-            XDDFTextParagraph paragraph = chart.getTitle().getBody().getParagraph(0);
-            paragraph.setDefaultRunProperties(properties);
-
-            // the data sources
-            XDDFCategoryDataSource xs = XDDFDataSourcesFactory.fromStringCellRange(sheet,
-                    new CellRangeAddress(1, NUM_OF_ROWS - 1, 0, 0));
-            XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
-                    new CellRangeAddress(1, NUM_OF_ROWS - 1, 1, 1));
-            XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
-                    new CellRangeAddress(1, NUM_OF_ROWS - 1, 2, 2));
-
-            // cat axis 1 (bars)
-            XDDFCategoryAxis barCategories = chart.createCategoryAxis(AxisPosition.BOTTOM);
-
-            // val axis 1 (left)
-            XDDFValueAxis leftValues = chart.createValueAxis(AxisPosition.LEFT);
-            leftValues.crossAxis(barCategories);
-            barCategories.crossAxis(leftValues);
-
-            // cat axis 2 (lines)
-            XDDFCategoryAxis lineCategories = chart.createCategoryAxis(AxisPosition.BOTTOM);
-            lineCategories.setVisible(false); // this cat axis is deleted
-
-            // val axis 2 (right)
-            XDDFValueAxis rightValues = chart.createValueAxis(AxisPosition.RIGHT);
-            // this value axis crosses its category axis at max value
-            rightValues.setCrosses(AxisCrosses.MAX);
-            rightValues.crossAxis(lineCategories);
-            lineCategories.crossAxis(rightValues);
-
-            // the bar chart
-            XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, barCategories, leftValues);
-            XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(xs, ys1);
-            series1.setTitle(null, new CellReference(sheet.getSheetName(), 0, 1, true,true));
-            bar.setVaryColors(true);
-            bar.setBarDirection(BarDirection.COL);
-            chart.plot(bar);
-
-            // the line chart on secondary axis
-            XDDFLineChartData lines = (XDDFLineChartData) chart.createData(ChartTypes.LINE, lineCategories,
-                    rightValues);
-
-            //uncomment below line if only primary axis required and comment above line
-            // the line chart on primary axis
-            /*XDDFLineChartData lines = (XDDFLineChartData) chart.createData(ChartTypes.LINE, lineCategories,
-                    leftValues);*/
-
-
-            XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) lines.addSeries(xs, ys2);
-            series2.setTitle(null, new CellReference(sheet.getSheetName(), 0, 2, true, true));
-            series2.setSmooth(false);
-            series2.setMarkerStyle(MarkerStyle.DIAMOND);
-            series2.setMarkerSize((short)14);
-            lines.setVaryColors(true);
-            chart.plot(lines);
-
-            // some colors
-            XDDFFillProperties solidChartreuse = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.CHARTREUSE));
-            XDDFFillProperties solidTurquoise = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.TURQUOISE));
-            XDDFLineProperties solidLines = new XDDFLineProperties(solidTurquoise);
-            series1.setFillProperties(solidChartreuse);
-            series1.setLineProperties(solidLines); // bar border color different from fill
-            series2.setLineProperties(solidLines);
-
-            // legend
-            XDDFChartLegend legend = chart.getOrAddLegend();
-            legend.setPosition(LegendPosition.LEFT);
-            legend.setOverlay(false);
-            XDDFManualLayout layout = legend.getOrAddManualLayout();
-            layout.setXMode(LayoutMode.EDGE);
-            layout.setYMode(LayoutMode.EDGE);
-            layout.setX(0.00); //left edge of the chart
-            layout.setY(0.25); //25% of chart's height from top edge of the chart
-
-            try (FileOutputStream fileOut = new FileOutputStream("BarAndLineChart.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/BarChart.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/BarChart.java
deleted file mode 100644 (file)
index 0cd57fc..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.xddf.usermodel.PresetColor;
-import org.apache.poi.xddf.usermodel.XDDFColor;
-import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
-import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
-import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
-import org.apache.poi.xddf.usermodel.chart.AxisPosition;
-import org.apache.poi.xddf.usermodel.chart.BarDirection;
-import org.apache.poi.xddf.usermodel.chart.ChartTypes;
-import org.apache.poi.xddf.usermodel.chart.LegendPosition;
-import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
-import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
-import org.apache.poi.xssf.usermodel.XSSFChart;
-import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
-import org.apache.poi.xssf.usermodel.XSSFDrawing;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Line chart example.
- */
-public final class BarChart {
-    private BarChart() {}
-
-    public static void main(String[] args) throws IOException {
-        try (XSSFWorkbook wb = new XSSFWorkbook()) {
-            XSSFSheet sheet = wb.createSheet("barchart");
-            final int NUM_OF_ROWS = 3;
-            final int NUM_OF_COLUMNS = 10;
-
-            // Create a row and put some cells in it. Rows are 0 based.
-            Row row;
-            Cell cell;
-            for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) {
-                row = sheet.createRow((short) rowIndex);
-                for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
-                    cell = row.createCell((short) colIndex);
-                    cell.setCellValue(colIndex * (rowIndex + 1.0));
-                }
-            }
-
-            XSSFDrawing drawing = sheet.createDrawingPatriarch();
-            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);
-
-            XSSFChart chart = drawing.createChart(anchor);
-            chart.setTitleText("x = 2x and x = 3x");
-            chart.setTitleOverlay(false);
-            XDDFChartLegend legend = chart.getOrAddLegend();
-            legend.setPosition(LegendPosition.TOP_RIGHT);
-
-            // Use a category axis for the bottom axis.
-            XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
-            bottomAxis.setTitle("x"); // https://stackoverflow.com/questions/32010765
-            XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
-            leftAxis.setTitle("f(x)");
-            leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
-
-            XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
-            XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1));
-            XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1));
-
-            XDDFChartData data = chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
-            XDDFChartData.Series series1 = data.addSeries(xs, ys1);
-            series1.setTitle("2x", null); // https://stackoverflow.com/questions/21855842
-            XDDFChartData.Series series2 = data.addSeries(xs, ys2);
-            series2.setTitle("3x", null);
-            chart.plot(data);
-
-            // in order to transform a bar chart into a column chart, you just need to change the bar direction
-            XDDFBarChartData bar = (XDDFBarChartData) data;
-            bar.setBarDirection(BarDirection.COL);
-            // looking for "Stacked Bar Chart"? uncomment the following line
-            // bar.setBarGrouping(BarGrouping.STACKED);
-
-            solidFillSeries(data, 0, PresetColor.CHARTREUSE);
-            solidFillSeries(data, 1, PresetColor.TURQUOISE);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("ooxml-bar-chart.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-
-    private static void solidFillSeries(XDDFChartData data, int index, PresetColor color) {
-        XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
-        XDDFChartData.Series series = data.getSeries().get(index);
-        XDDFShapeProperties properties = series.getShapeProperties();
-        if (properties == null) {
-            properties = new XDDFShapeProperties();
-        }
-        properties.setFillProperties(fill);
-        series.setShapeProperties(properties);
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/BigGridDemo.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/BigGridDemo.java
deleted file mode 100644 (file)
index 8aaecb4..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.util.Calendar;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-
-import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
-import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
-import org.apache.commons.compress.archivers.zip.ZipFile;
-import org.apache.poi.openxml4j.opc.internal.ZipHelper;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xssf.usermodel.XSSFCellStyle;
-import org.apache.poi.xssf.usermodel.XSSFDataFormat;
-import org.apache.poi.xssf.usermodel.XSSFFont;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Demonstrates a workaround you can use to generate large workbooks and avoid OutOfMemory exception.
- *
- * Note - You probably <em>don't want to use this approach any more</em>! POI
- *  now includes the SXSSF which handles all of this for you, you should
- *  be using that instead! This code remains mostly for historical interest.
- * <p>
- * See <a "https://poi.apache.org/spreadsheet/how-to.html#sxssf">
- *     https://poi.apache.org/spreadsheet/how-to.html#sxssf</a>.
- * <p>
- * If you really want to use this approach, which is also the one that SXSSF
- * does for you, it works as follows:
- *
- * 1. create a template workbook, create sheets and global objects such as cell styles, number formats, etc.
- * 2. create an application that streams data in a text file
- * 3. Substitute the sheet in the template with the generated data
- *
- * <p>
- *  Since 3.8 POI provides a low-memory footprint SXSSF API, which implements
- *  ths "BigGridDemo" strategy. SXSSF is an API-compatible streaming extension
- *  of XSSF to be used when very large spreadsheets have to be produced, and
- *  heap space is limited. SXSSF achieves its low memory footprint by limiting
- *  access to the rows that are within a sliding window, while XSSF gives access
- *  to all rows in the document. Older rows that are no longer in the window
- *  become inaccessible, as they are written to the disk.
- * </p>
- * See <a "https://poi.apache.org/spreadsheet/how-to.html#sxssf">
- *     https://poi.apache.org/spreadsheet/how-to.html#sxssf</a>.
- */
-public final class BigGridDemo {
-    private static final String XML_ENCODING = "UTF-8";
-
-    private static final Random rnd = new Random();
-
-    private BigGridDemo() {}
-
-    public static void main(String[] args) throws Exception {
-
-        // Step 1. Create a template file. Setup sheets and workbook-level objects such as
-        // cell styles, number formats, etc.
-
-        try (XSSFWorkbook wb = new XSSFWorkbook()) {
-            XSSFSheet sheet = wb.createSheet("Big Grid");
-
-            Map<String, XSSFCellStyle> styles = createStyles(wb);
-            //name of the zip entry holding sheet data, e.g. /xl/worksheets/sheet1.xml
-            String sheetRef = sheet.getPackagePart().getPartName().getName();
-
-            //save the template
-            try (FileOutputStream os = new FileOutputStream("template.xlsx")) {
-                wb.write(os);
-            }
-
-            //Step 2. Generate XML file.
-            File tmp = File.createTempFile("sheet", ".xml");
-            try (
-                    FileOutputStream stream = new FileOutputStream(tmp);
-                    Writer fw = new OutputStreamWriter(stream, XML_ENCODING)
-                ) {
-                generate(fw, styles);
-            }
-
-            //Step 3. Substitute the template entry with the generated data
-            try (FileOutputStream out = new FileOutputStream("big-grid.xlsx")) {
-                substitute(new File("template.xlsx"), tmp, sheetRef.substring(1), out);
-            }
-        }
-    }
-
-    /**
-     * Create a library of cell styles.
-     */
-    private static Map<String, XSSFCellStyle> createStyles(XSSFWorkbook wb){
-        Map<String, XSSFCellStyle> styles = new HashMap<>();
-        XSSFDataFormat fmt = wb.createDataFormat();
-
-        XSSFCellStyle style1 = wb.createCellStyle();
-        style1.setAlignment(HorizontalAlignment.RIGHT);
-        style1.setDataFormat(fmt.getFormat("0.0%"));
-        styles.put("percent", style1);
-
-        XSSFCellStyle style2 = wb.createCellStyle();
-        style2.setAlignment(HorizontalAlignment.CENTER);
-        style2.setDataFormat(fmt.getFormat("0.0X"));
-        styles.put("coeff", style2);
-
-        XSSFCellStyle style3 = wb.createCellStyle();
-        style3.setAlignment(HorizontalAlignment.RIGHT);
-        style3.setDataFormat(fmt.getFormat("$#,##0.00"));
-        styles.put("currency", style3);
-
-        XSSFCellStyle style4 = wb.createCellStyle();
-        style4.setAlignment(HorizontalAlignment.RIGHT);
-        style4.setDataFormat(fmt.getFormat("mmm dd"));
-        styles.put("date", style4);
-
-        XSSFCellStyle style5 = wb.createCellStyle();
-        XSSFFont headerFont = wb.createFont();
-        headerFont.setBold(true);
-        style5.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
-        style5.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style5.setFont(headerFont);
-        styles.put("header", style5);
-
-        return styles;
-    }
-
-    private static void generate(Writer out, Map<String, XSSFCellStyle> styles) throws Exception {
-
-        Calendar calendar = Calendar.getInstance();
-
-        SpreadsheetWriter sw = new SpreadsheetWriter(out);
-        sw.beginSheet();
-
-        //insert header row
-        sw.insertRow(0);
-        int styleIndex = styles.get("header").getIndex();
-        sw.createCell(0, "Title", styleIndex);
-        sw.createCell(1, "% Change", styleIndex);
-        sw.createCell(2, "Ratio", styleIndex);
-        sw.createCell(3, "Expenses", styleIndex);
-        sw.createCell(4, "Date", styleIndex);
-
-        sw.endRow();
-
-        //write data rows
-        for (int rownum = 1; rownum < 100000; rownum++) {
-            sw.insertRow(rownum);
-
-            sw.createCell(0, "Hello, " + rownum + "!");
-            sw.createCell(1, (double)rnd.nextInt(100)/100, styles.get("percent").getIndex());
-            sw.createCell(2, (double)rnd.nextInt(10)/10, styles.get("coeff").getIndex());
-            sw.createCell(3, rnd.nextInt(10000), styles.get("currency").getIndex());
-            sw.createCell(4, calendar, styles.get("date").getIndex());
-
-            sw.endRow();
-
-            calendar.roll(Calendar.DAY_OF_YEAR, 1);
-        }
-        sw.endSheet();
-    }
-
-    /**
-     *
-     * @param zipfile the template file
-     * @param tmpfile the XML file with the sheet data
-     * @param entry the name of the sheet entry to substitute, e.g. xl/worksheets/sheet1.xml
-     * @param out the stream to write the result to
-     */
-    private static void substitute(File zipfile, File tmpfile, String entry, OutputStream out) throws IOException {
-        try (ZipFile zip = ZipHelper.openZipFile(zipfile)) {
-            try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(out)) {
-                Enumeration<? extends ZipArchiveEntry> en = zip.getEntries();
-                while (en.hasMoreElements()) {
-                    ZipArchiveEntry ze = en.nextElement();
-                    if (!ze.getName().equals(entry)) {
-                        zos.putArchiveEntry(new ZipArchiveEntry(ze.getName()));
-                        try (InputStream is = zip.getInputStream(ze)) {
-                            copyStream(is, zos);
-                        }
-                        zos.closeArchiveEntry();
-                    }
-                }
-                zos.putArchiveEntry(new ZipArchiveEntry(entry));
-                try (InputStream is = new FileInputStream(tmpfile)) {
-                    copyStream(is, zos);
-                }
-                zos.closeArchiveEntry();
-            }
-        }
-    }
-
-    private static void copyStream(InputStream in, OutputStream out) throws IOException {
-        byte[] chunk = new byte[1024];
-        int count;
-        while ((count = in.read(chunk)) >=0 ) {
-          out.write(chunk,0,count);
-        }
-    }
-
-    /**
-     * Writes spreadsheet data in a Writer.
-     * (YK: in future it may evolve in a full-featured API for streaming data in Excel)
-     */
-    public static class SpreadsheetWriter {
-        private final Writer _out;
-        private int _rownum;
-
-        SpreadsheetWriter(Writer out){
-            _out = out;
-        }
-
-        void beginSheet() throws IOException {
-            _out.write("<?xml version=\"1.0\" encoding=\""+XML_ENCODING+"\"?>" +
-                    "<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">" );
-            _out.write("<sheetData>\n");
-        }
-
-        void endSheet() throws IOException {
-            _out.write("</sheetData>");
-            _out.write("</worksheet>");
-        }
-
-        /**
-         * Insert a new row
-         *
-         * @param rownum 0-based row number
-         */
-        void insertRow(int rownum) throws IOException {
-            _out.write("<row r=\""+(rownum+1)+"\">\n");
-            this._rownum = rownum;
-        }
-
-        /**
-         * Insert row end marker
-         */
-        void endRow() throws IOException {
-            _out.write("</row>\n");
-        }
-
-        public void createCell(int columnIndex, String value, int styleIndex) throws IOException {
-            String ref = new CellReference(_rownum, columnIndex).formatAsString();
-            _out.write("<c r=\""+ref+"\" t=\"inlineStr\"");
-            if(styleIndex != -1) {
-                _out.write(" s=\""+styleIndex+"\"");
-            }
-            _out.write(">");
-            _out.write("<is><t>"+value+"</t></is>");
-            _out.write("</c>");
-        }
-
-        public void createCell(int columnIndex, String value) throws IOException {
-            createCell(columnIndex, value, -1);
-        }
-
-        public void createCell(int columnIndex, double value, int styleIndex) throws IOException {
-            String ref = new CellReference(_rownum, columnIndex).formatAsString();
-            _out.write("<c r=\""+ref+"\" t=\"n\"");
-            if(styleIndex != -1) {
-                _out.write(" s=\""+styleIndex+"\"");
-            }
-            _out.write(">");
-            _out.write("<v>"+value+"</v>");
-            _out.write("</c>");
-        }
-
-        public void createCell(int columnIndex, double value) throws IOException {
-            createCell(columnIndex, value, -1);
-        }
-
-        public void createCell(int columnIndex, Calendar value, int styleIndex) throws IOException {
-            createCell(columnIndex, DateUtil.getExcelDate(value, false), styleIndex);
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/CalendarDemo.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/CalendarDemo.java
deleted file mode 100644 (file)
index 11ffafc..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import org.apache.poi.xssf.usermodel.*;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.usermodel.*;
-
-import java.io.FileOutputStream;
-import java.util.Calendar;
-import java.util.Map;
-import java.util.HashMap;
-
-/**
- * A  monthly calendar created using Apache POI. Each month is on a separate sheet.
- * This is a version of org.apache.poi.ss.examples.CalendarDemo that demonstrates
- * some XSSF features not avaiable when using common HSSF-XSSF interfaces.
- *
- * <pre>
- * Usage:
- * CalendarDemo <year>
- * </pre>
- *
- * @author Yegor Kozlov
- */
-public class CalendarDemo {
-
-    private static final String[] days = {
-            "Sunday", "Monday", "Tuesday",
-            "Wednesday", "Thursday", "Friday", "Saturday"};
-
-    private static final String[]  months = {
-            "January", "February", "March","April", "May", "June","July", "August",
-            "September","October", "November", "December"};
-
-    public static void main(String[] args) throws Exception {
-
-        Calendar calendar = Calendar.getInstance();
-        if(args.length > 0) calendar.set(Calendar.YEAR, Integer.parseInt(args[0]));
-
-        int year = calendar.get(Calendar.YEAR);
-
-        try (XSSFWorkbook wb = new XSSFWorkbook()) {
-            Map<String, XSSFCellStyle> styles = createStyles(wb);
-
-            for (int month = 0; month < 12; month++) {
-                calendar.set(Calendar.MONTH, month);
-                calendar.set(Calendar.DAY_OF_MONTH, 1);
-                //create a sheet for each month
-                XSSFSheet sheet = wb.createSheet(months[month]);
-
-                //turn off gridlines
-                sheet.setDisplayGridlines(false);
-                sheet.setPrintGridlines(false);
-                XSSFPrintSetup printSetup = sheet.getPrintSetup();
-                printSetup.setOrientation(PrintOrientation.LANDSCAPE);
-                sheet.setFitToPage(true);
-                sheet.setHorizontallyCenter(true);
-
-                //the header row: centered text in 48pt font
-                XSSFRow headerRow = sheet.createRow(0);
-                headerRow.setHeightInPoints(80);
-                XSSFCell titleCell = headerRow.createCell(0);
-                titleCell.setCellValue(months[month] + " " + year);
-                titleCell.setCellStyle(styles.get("title"));
-                sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$N$1"));
-
-                //header with month titles
-                XSSFRow monthRow = sheet.createRow(1);
-                for (int i = 0; i < days.length; i++) {
-                    //for compatibility with HSSF we have to set column width in units of 1/256th of a character width
-                    sheet.setColumnWidth(i * 2, 5 * 256); //the column is 5 characters wide
-                    sheet.setColumnWidth(i * 2 + 1, 13 * 256); //the column is 13 characters wide
-                    sheet.addMergedRegion(new CellRangeAddress(1, 1, i * 2, i * 2 + 1));
-                    XSSFCell monthCell = monthRow.createCell(i * 2);
-                    monthCell.setCellValue(days[i]);
-                    monthCell.setCellStyle(styles.get("month"));
-                }
-
-                int cnt = 1, day = 1;
-                int rownum = 2;
-                for (int j = 0; j < 6; j++) {
-                    XSSFRow row = sheet.createRow(rownum++);
-                    row.setHeightInPoints(100);
-                    for (int i = 0; i < days.length; i++) {
-                        XSSFCell dayCell_1 = row.createCell(i * 2);
-                        XSSFCell dayCell_2 = row.createCell(i * 2 + 1);
-
-                        int day_of_week = calendar.get(Calendar.DAY_OF_WEEK);
-                        if (cnt >= day_of_week && calendar.get(Calendar.MONTH) == month) {
-                            dayCell_1.setCellValue(day);
-                            calendar.set(Calendar.DAY_OF_MONTH, ++day);
-
-                            if (i == 0 || i == days.length - 1) {
-                                dayCell_1.setCellStyle(styles.get("weekend_left"));
-                                dayCell_2.setCellStyle(styles.get("weekend_right"));
-                            } else {
-                                dayCell_1.setCellStyle(styles.get("workday_left"));
-                                dayCell_2.setCellStyle(styles.get("workday_right"));
-                            }
-                        } else {
-                            dayCell_1.setCellStyle(styles.get("grey_left"));
-                            dayCell_2.setCellStyle(styles.get("grey_right"));
-                        }
-                        cnt++;
-                    }
-                    if (calendar.get(Calendar.MONTH) > month) break;
-                }
-            }
-
-            // Write the output to a file
-            try (FileOutputStream out = new FileOutputStream("calendar-" + year + ".xlsx")) {
-                wb.write(out);
-            }
-
-        }
-    }
-
-    /**
-     * cell styles used for formatting calendar sheets
-     */
-    private static Map<String, XSSFCellStyle> createStyles(XSSFWorkbook wb){
-        Map<String, XSSFCellStyle> styles = new HashMap<>();
-
-        XSSFCellStyle style;
-        XSSFFont titleFont = wb.createFont();
-        titleFont.setFontHeightInPoints((short)48);
-        titleFont.setColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setFont(titleFont);
-        styles.put("title", style);
-
-        XSSFFont monthFont = wb.createFont();
-        monthFont.setFontHeightInPoints((short)12);
-        monthFont.setColor(new XSSFColor(new java.awt.Color(255, 255, 255), wb.getStylesSource().getIndexedColors()));
-        monthFont.setBold(true);
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setFont(monthFont);
-        styles.put("month", style);
-
-        XSSFFont dayFont = wb.createFont();
-        dayFont.setFontHeightInPoints((short)14);
-        dayFont.setBold(true);
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.LEFT);
-        style.setVerticalAlignment(VerticalAlignment.TOP);
-        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(228, 232, 243), wb.getStylesSource().getIndexedColors()));
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setBorderLeft(BorderStyle.THIN);
-        style.setLeftBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        style.setFont(dayFont);
-        styles.put("weekend_left", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.TOP);
-        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(228, 232, 243), wb.getStylesSource().getIndexedColors()));
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setBorderRight(BorderStyle.THIN);
-        style.setRightBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        styles.put("weekend_right", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.LEFT);
-        style.setVerticalAlignment(VerticalAlignment.TOP);
-        style.setBorderLeft(BorderStyle.THIN);
-        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(255, 255, 255), wb.getStylesSource().getIndexedColors()));
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setLeftBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        style.setFont(dayFont);
-        styles.put("workday_left", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.TOP);
-        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(255, 255, 255), wb.getStylesSource().getIndexedColors()));
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setBorderRight(BorderStyle.THIN);
-        style.setRightBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        styles.put("workday_right", style);
-
-        style = wb.createCellStyle();
-        style.setBorderLeft(BorderStyle.THIN);
-        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(234, 234, 234), wb.getStylesSource().getIndexedColors()));
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        styles.put("grey_left", style);
-
-        style = wb.createCellStyle();
-        style.setFillForegroundColor(new XSSFColor(new java.awt.Color(234, 234, 234), wb.getStylesSource().getIndexedColors()));
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        style.setBorderRight(BorderStyle.THIN);
-        style.setRightBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
-        styles.put("grey_right", style);
-
-        return styles;
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/CellComments.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/CellComments.java
deleted file mode 100644 (file)
index 40f4905..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.ClientAnchor;
-import org.apache.poi.ss.usermodel.Comment;
-import org.apache.poi.ss.usermodel.CreationHelper;
-import org.apache.poi.ss.usermodel.Drawing;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.usermodel.RichTextString;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.util.CellAddress;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Demonstrates how to work with excel cell comments.
- *
- * <p>
- * Excel comment is a kind of a text shape,
- * so inserting a comment is very similar to placing a text box in a worksheet
- * </p>
- *
- * @author Yegor Kozlov
- */
-public class CellComments {
-    public static void main(String[] args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {
-
-            CreationHelper factory = wb.getCreationHelper();
-
-            Sheet sheet = wb.createSheet();
-
-            Cell cell1 = sheet.createRow(3).createCell(5);
-            cell1.setCellValue("F4");
-
-            Drawing<?> drawing = sheet.createDrawingPatriarch();
-
-            ClientAnchor anchor = factory.createClientAnchor();
-
-            Comment comment1 = drawing.createCellComment(anchor);
-            RichTextString str1 = factory.createRichTextString("Hello, World!");
-            comment1.setString(str1);
-            comment1.setAuthor("Apache POI");
-            cell1.setCellComment(comment1);
-
-            Cell cell2 = sheet.createRow(2).createCell(2);
-            cell2.setCellValue("C3");
-
-            Comment comment2 = drawing.createCellComment(anchor);
-            RichTextString str2 = factory.createRichTextString("XSSF can set cell comments");
-            //apply custom font to the text in the comment
-            Font font = wb.createFont();
-            font.setFontName("Arial");
-            font.setFontHeightInPoints((short) 14);
-            font.setBold(true);
-            font.setColor(IndexedColors.RED.getIndex());
-            str2.applyFont(font);
-
-            comment2.setString(str2);
-            comment2.setAuthor("Apache POI");
-            comment2.setAddress(new CellAddress("C3"));
-
-            try (FileOutputStream out = new FileOutputStream("comments.xlsx")) {
-                wb.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/CreateCell.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/CreateCell.java
deleted file mode 100644 (file)
index 27bc060..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Date;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.CreationHelper;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.RichTextString;
-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.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Illustrates how to create cell and set values of different types.
- */
-public class CreateCell {
-
-    public static void main(String[] args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
-            CreationHelper creationHelper = wb.getCreationHelper();
-            Sheet sheet = wb.createSheet("new sheet");
-
-            // Create a row and put some cells in it. Rows are 0 based.
-            Row row = sheet.createRow((short) 0);
-            // Create a cell and put a value in it.
-            Cell cell = row.createCell((short) 0);
-            cell.setCellValue(1);
-
-            //numeric value
-            row.createCell(1).setCellValue(1.2);
-
-            //plain string value
-            row.createCell(2).setCellValue("This is a string cell");
-
-            //rich text string
-            RichTextString str = creationHelper.createRichTextString("Apache");
-            Font font = wb.createFont();
-            font.setItalic(true);
-            font.setUnderline(Font.U_SINGLE);
-            str.applyFont(font);
-            row.createCell(3).setCellValue(str);
-
-            //boolean value
-            row.createCell(4).setCellValue(true);
-
-            //formula
-            row.createCell(5).setCellFormula("SUM(A1:B1)");
-
-            //date
-            CellStyle style = wb.createCellStyle();
-            style.setDataFormat(creationHelper.createDataFormat().getFormat("m/d/yy h:mm"));
-            cell = row.createCell(6);
-            cell.setCellValue(new Date());
-            cell.setCellStyle(style);
-
-            //hyperlink
-            row.createCell(7).setCellFormula("SUM(A1:B1)");
-            cell.setCellFormula("HYPERLINK(\"http://google.com\",\"Google\")");
-
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("ooxml-cell.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/CreatePivotTable.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/CreatePivotTable.java
deleted file mode 100644 (file)
index a048ae4..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements.  See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License.  You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.ss.SpreadsheetVersion;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.DataConsolidateFunction;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.util.AreaReference;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xssf.usermodel.XSSFPivotTable;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-public class CreatePivotTable {
-
-    public static void main(String[] args) throws FileNotFoundException, IOException, InvalidFormatException {
-        try (XSSFWorkbook wb = new XSSFWorkbook()) {
-            XSSFSheet sheet = wb.createSheet();
-
-            //Create some data to build the pivot table on
-            setCellData(sheet);
-
-            AreaReference source = new AreaReference("A1:D4", SpreadsheetVersion.EXCEL2007);
-            CellReference position = new CellReference("H5");
-            // Create a pivot table on this sheet, with H5 as the top-left cell..
-            // The pivot table's data source is on the same sheet in A1:D4
-            XSSFPivotTable pivotTable = sheet.createPivotTable(source, position);
-            //Configure the pivot table
-            //Use first column as row label
-            pivotTable.addRowLabel(0);
-            //Sum up the second column
-            pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1);
-            //Set the third column as filter
-            pivotTable.addColumnLabel(DataConsolidateFunction.AVERAGE, 2);
-            //Add filter on forth column
-            pivotTable.addReportFilter(3);
-
-            try (FileOutputStream fileOut = new FileOutputStream("ooxml-pivottable.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-
-    public static void setCellData(XSSFSheet sheet){
-        Row row1 = sheet.createRow(0);
-        // Create a cell and put a value in it.
-        Cell cell11 = row1.createCell(0);
-        cell11.setCellValue("Names");
-        Cell cell12 = row1.createCell(1);
-        cell12.setCellValue("#");
-        Cell cell13 = row1.createCell(2);
-        cell13.setCellValue("%");
-        Cell cell14 = row1.createCell(3);
-        cell14.setCellValue("Human");
-
-        Row row2 = sheet.createRow(1);
-        Cell cell21 = row2.createCell(0);
-        cell21.setCellValue("Jane");
-        Cell cell22 = row2.createCell(1);
-        cell22.setCellValue(10);
-        Cell cell23 = row2.createCell(2);
-        cell23.setCellValue(100);
-        Cell cell24 = row2.createCell(3);
-        cell24.setCellValue("Yes");
-
-        Row row3 = sheet.createRow(2);
-        Cell cell31 = row3.createCell(0);
-        cell31.setCellValue("Tarzan");
-        Cell cell32 = row3.createCell(1);
-        cell32.setCellValue(5);
-        Cell cell33 = row3.createCell(2);
-        cell33.setCellValue(90);
-        Cell cell34 = row3.createCell(3);
-        cell34.setCellValue("Yes");
-
-        Row row4 = sheet.createRow(3);
-        Cell cell41 = row4.createCell(0);
-        cell41.setCellValue("Terk");
-        Cell cell42 = row4.createCell(1);
-        cell42.setCellValue(10);
-        Cell cell43 = row4.createCell(2);
-        cell43.setCellValue(90);
-        Cell cell44 = row4.createCell(3);
-        cell44.setCellValue("No");
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/CreatePivotTable2.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/CreatePivotTable2.java
deleted file mode 100644 (file)
index 27ff990..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements.  See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License.  You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Date;
-import java.util.Calendar;
-
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.ss.SpreadsheetVersion;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.DataConsolidateFunction;
-import org.apache.poi.ss.usermodel.DataFormat;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.util.AreaReference;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xssf.usermodel.XSSFPivotTable;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-public class CreatePivotTable2 {
-
-    public static void main(String[] args) throws FileNotFoundException, IOException, InvalidFormatException {
-        try (XSSFWorkbook wb = new XSSFWorkbook()) {
-            XSSFSheet sheet = wb.createSheet();
-
-            //Create some data to build the pivot table on
-            setCellData(sheet);
-
-            AreaReference source = new AreaReference("A1:E7", SpreadsheetVersion.EXCEL2007);
-            CellReference position = new CellReference("H1");
-            // Create a pivot table on this sheet, with H1 as the top-left cell..
-            // The pivot table's data source is on the same sheet in A1:E7
-            XSSFPivotTable pivotTable = sheet.createPivotTable(source, position);
-            //Configure the pivot table
-            //Use first column as row label
-            pivotTable.addRowLabel(0);
-            //Sum up the second column with column title and data format
-            pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1, "Values", "#,##0.00");
-            //Use third column (month) as columns (side by side)
-            pivotTable.addColLabel(3, "DD.MM.YYYY");
-
-            //Add filter on forth column
-            pivotTable.addReportFilter(4);
-
-            try (FileOutputStream fileOut = new FileOutputStream("ooxml-pivottable2.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-
-    public static void setCellData(XSSFSheet sheet){
-        Calendar cal1 = Calendar.getInstance();
-        cal1.set(2017, 0, 1, 0, 0, 0);
-        Calendar cal2 = Calendar.getInstance();
-        cal2.set(2017, 1, 1, 0, 0, 0);
-        Row row1 = sheet.createRow(0);
-        // Create a cell and put a value in it.
-        // first row are column titles
-        Cell cell11 = row1.createCell(0);
-        cell11.setCellValue("Names");
-        Cell cell12 = row1.createCell(1);
-        cell12.setCellValue("Values");
-        Cell cell13 = row1.createCell(2);
-        cell13.setCellValue("%");
-        Cell cell14 = row1.createCell(3);
-        cell14.setCellValue("Month");
-        Cell cell15 = row1.createCell(4);
-        cell15.setCellValue("No");
-
-        CellStyle csDbl = sheet.getWorkbook().createCellStyle();
-        DataFormat dfDbl = sheet.getWorkbook().createDataFormat();
-        csDbl.setDataFormat(dfDbl.getFormat("#,##0.00"));
-
-        CellStyle csDt = sheet.getWorkbook().createCellStyle();
-        DataFormat dfDt = sheet.getWorkbook().createDataFormat();
-        csDt.setDataFormat(dfDt.getFormat("dd/MM/yyyy"));
-        // data
-        setDataRow(sheet, 1, "Jane", 1120.5, 100, cal1.getTime(), 1, csDbl, csDt);
-        setDataRow(sheet, 2, "Jane", 1453.2, 95, cal2.getTime(), 2, csDbl, csDt);
-
-        setDataRow(sheet, 3, "Tarzan", 1869.8, 88, cal1.getTime(), 1, csDbl, csDt);
-        setDataRow(sheet, 4, "Tarzan", 1536.2, 92, cal2.getTime(), 2, csDbl, csDt);
-
-        setDataRow(sheet, 5, "Terk", 1624.1, 75, cal1.getTime(), 1, csDbl, csDt);
-        setDataRow(sheet, 6, "Terk", 1569.3, 82, cal2.getTime(), 2, csDbl, csDt);
-        sheet.autoSizeColumn(3);
-    }
-
-    public static void setDataRow(XSSFSheet sheet, int rowNum, String name, double v1, int v2, Date dt, int no, CellStyle csDbl, CellStyle csDt){
-        Row row = sheet.createRow(rowNum);
-        // set the values for one row
-        Cell c1 = row.createCell(0);
-        c1.setCellValue(name);
-        Cell c2 = row.createCell(1);
-        c2.setCellValue(v1);
-        c2.setCellStyle(csDbl);
-        Cell c3 = row.createCell(2);
-        c3.setCellValue(v2);
-        Cell c4 = row.createCell(3);
-        c4.setCellValue(dt);
-        c4.setCellStyle(csDt);
-        Cell c5 = row.createCell(4);
-        c5.setCellValue(no);
-    }
-
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/CreateTable.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/CreateTable.java
deleted file mode 100644 (file)
index ad2b6ad..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.util.AreaReference;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xssf.usermodel.XSSFCell;
-import org.apache.poi.xssf.usermodel.XSSFRow;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFTable;
-import org.apache.poi.xssf.usermodel.XSSFTableStyleInfo;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Demonstrates how to create a simple table using Apache POI.
- */
-public class CreateTable {
-
-    public static void main(String[] args) throws IOException {
-
-        try (XSSFWorkbook wb = new XSSFWorkbook()) {
-            XSSFSheet sheet = wb.createSheet();
-
-            // Set which area the table should be placed in
-            AreaReference reference = wb.getCreationHelper().createAreaReference(
-                    new CellReference(0, 0), new CellReference(2, 2));
-
-            // Create
-            XSSFTable table = sheet.createTable(reference);
-            table.setName("Test");
-            table.setDisplayName("Test_Table");
-
-            // For now, create the initial style in a low-level way
-            table.getCTTable().addNewTableStyleInfo();
-            table.getCTTable().getTableStyleInfo().setName("TableStyleMedium2");
-
-            // Style the table
-            XSSFTableStyleInfo style = (XSSFTableStyleInfo) table.getStyle();
-            style.setName("TableStyleMedium2");
-            style.setShowColumnStripes(false);
-            style.setShowRowStripes(true);
-            style.setFirstColumn(false);
-            style.setLastColumn(false);
-            style.setShowRowStripes(true);
-            style.setShowColumnStripes(true);
-
-            // Set the values for the table
-            XSSFRow row;
-            XSSFCell cell;
-            for (int i = 0; i < 3; i++) {
-                // Create row
-                row = sheet.createRow(i);
-                for (int j = 0; j < 3; j++) {
-                    // Create cell
-                    cell = row.createCell(j);
-                    if (i == 0) {
-                        cell.setCellValue("Column" + (j + 1));
-                    } else {
-                        cell.setCellValue((i + 1.0) * (j + 1.0));
-                    }
-                }
-            }
-
-            // Save
-            try (FileOutputStream fileOut = new FileOutputStream("ooxml-table.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/CreateUserDefinedDataFormats.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/CreateUserDefinedDataFormats.java
deleted file mode 100644 (file)
index 134560b..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.DataFormat;
-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.xssf.usermodel.XSSFWorkbook;
-
-/**
- * How to set user-defined date formats
- */
-public class CreateUserDefinedDataFormats {
-
-
-    public static void main(String[]args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {  //or new HSSFWorkbook();
-            Sheet sheet = wb.createSheet("format sheet");
-            CellStyle style;
-            DataFormat format = wb.createDataFormat();
-            Row row;
-            Cell cell;
-            short rowNum = 0;
-            short colNum = 0;
-
-            row = sheet.createRow(rowNum);
-            cell = row.createCell(colNum);
-            cell.setCellValue(11111.25);
-            style = wb.createCellStyle();
-            style.setDataFormat(format.getFormat("0.0"));
-            cell.setCellStyle(style);
-
-            row = sheet.createRow(++rowNum);
-            cell = row.createCell(colNum);
-            cell.setCellValue(11111.25);
-            style = wb.createCellStyle();
-            style.setDataFormat(format.getFormat("#,##0.0000"));
-            cell.setCellStyle(style);
-
-            try (FileOutputStream fileOut = new FileOutputStream("ooxml_dataFormat.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/CustomXMLMapping.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/CustomXMLMapping.java
deleted file mode 100644 (file)
index 9f2ab3d..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.ByteArrayOutputStream;
-
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.xssf.extractor.XSSFExportToXml;
-import org.apache.poi.xssf.usermodel.XSSFMap;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Print all custom XML mappings registered in the given workbook
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class CustomXMLMapping {
-
-    private CustomXMLMapping() {}
-
-    public static void main(String[] args) throws Exception {
-        try (OPCPackage pkg = OPCPackage.open(args[0]);
-             XSSFWorkbook wb = new XSSFWorkbook(pkg)) {
-            for (XSSFMap map : wb.getCustomXMLMappings()) {
-                XSSFExportToXml exporter = new XSSFExportToXml(map);
-
-                ByteArrayOutputStream os = new ByteArrayOutputStream();
-                exporter.exportToXML(os, true);
-                String xml = os.toString("UTF-8");
-                System.out.println(xml);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/EmbeddedObjects.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/EmbeddedObjects.java
deleted file mode 100644 (file)
index 1931af7..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.Closeable;
-import java.io.InputStream;
-
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hwpf.HWPFDocument;
-import org.apache.poi.openxml4j.opc.PackagePart;
-import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-
-/**
- * Demonstrates how you can extract embedded data from a .xlsx file
- */
-public class EmbeddedObjects {
-    public static void main(String[] args) throws Exception {
-        try (XSSFWorkbook workbook = new XSSFWorkbook(args[0])) {
-            for (PackagePart pPart : workbook.getAllEmbeddedParts()) {
-                String contentType = pPart.getContentType();
-                try (InputStream is = pPart.getInputStream()) {
-                    Closeable document;
-                    if (contentType.equals("application/vnd.ms-excel")) {
-                        // Excel Workbook - either binary or OpenXML
-                        document = new HSSFWorkbook(is);
-                    } else if (contentType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
-                        // Excel Workbook - OpenXML file format
-                        document = new XSSFWorkbook(is);
-                    } else if (contentType.equals("application/msword")) {
-                        // Word Document - binary (OLE2CDF) file format
-                        document = new HWPFDocument(is);
-                    } else if (contentType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
-                        // Word Document - OpenXML file format
-                        document = new XWPFDocument(is);
-                    } else if (contentType.equals("application/vnd.ms-powerpoint")) {
-                        // PowerPoint Document - binary file format
-                        document = new HSLFSlideShow(is);
-                    } else if (contentType.equals("application/vnd.openxmlformats-officedocument.presentationml.presentation")) {
-                        // PowerPoint Document - OpenXML file format
-                        document = new XMLSlideShow(is);
-                    } else {
-                        // Any other type of embedded object.
-                        document = is;
-                    }
-                    document.close();
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/ExcelChartWithTargetLine.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/ExcelChartWithTargetLine.java
deleted file mode 100644 (file)
index c5a4f8d..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xddf.usermodel.PresetColor;
-import org.apache.poi.xddf.usermodel.XDDFColor;
-import org.apache.poi.xddf.usermodel.XDDFFillProperties;
-import org.apache.poi.xddf.usermodel.XDDFLineProperties;
-import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
-import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
-import org.apache.poi.xddf.usermodel.chart.AxisPosition;
-import org.apache.poi.xddf.usermodel.chart.AxisTickLabelPosition;
-import org.apache.poi.xddf.usermodel.chart.BarDirection;
-import org.apache.poi.xddf.usermodel.chart.ChartTypes;
-import org.apache.poi.xddf.usermodel.chart.LegendPosition;
-import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
-import org.apache.poi.xddf.usermodel.chart.XDDFCategoryDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
-import org.apache.poi.xddf.usermodel.chart.XDDFLegendEntry;
-import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFScatterChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
-import org.apache.poi.xddf.usermodel.text.XDDFRunProperties;
-import org.apache.poi.xssf.usermodel.XSSFCell;
-import org.apache.poi.xssf.usermodel.XSSFChart;
-import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
-import org.apache.poi.xssf.usermodel.XSSFDrawing;
-import org.apache.poi.xssf.usermodel.XSSFRow;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * This example is based on original contributions by Axel Richter on StackOverflow.
- *
- * <em>Note from original author</em>:
- * This only works for Excel since OpenOffice or LibreOffice Calc is not able having series having literal numeric values set.
- *
- * @see <a href="https://stackoverflow.com/questions/50772989/">Create target marker in a bar chart with openxmlformats</a>
- * @see <a href="https://stackoverflow.com/questions/50873700/">Change axis color and font of the chart in openxmlformats</a>
- * @see <a href="https://stackoverflow.com/questions/51530552/">Change colors of line chart Apache POI</a>
- */
-public final class ExcelChartWithTargetLine {
-    private ExcelChartWithTargetLine() {}
-
-    private static final int NUM_OF_ROWS = 6;
-
-    private static void createChart(XSSFChart chart, XSSFSheet sheet, int[] chartedCols, double target) {
-        // some colors
-        XDDFFillProperties[] fills = new XDDFFillProperties[] {
-            new XDDFSolidFillProperties(XDDFColor.from(PresetColor.TURQUOISE)),
-            new XDDFSolidFillProperties(XDDFColor.from(PresetColor.CHARTREUSE)),
-            new XDDFSolidFillProperties(XDDFColor.from(PresetColor.LAVENDER)),
-            new XDDFSolidFillProperties(XDDFColor.from(PresetColor.CHOCOLATE)),
-            new XDDFSolidFillProperties(XDDFColor.from(PresetColor.TOMATO)),
-            new XDDFSolidFillProperties(XDDFColor.from(PresetColor.PLUM))
-        };
-        XDDFLineProperties solidTurquoise = new XDDFLineProperties(fills[0]);
-        XDDFLineProperties solidTomato = new XDDFLineProperties(fills[4]);
-        XDDFLineProperties solidPlum = new XDDFLineProperties(fills[5]);
-        XDDFSolidFillProperties solidAlmond = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.BLANCHED_ALMOND));
-        XDDFSolidFillProperties solidGray = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.DARK_SLATE_GRAY));
-
-
-        // the bar chart
-
-        XDDFCategoryAxis barCategories = chart.createCategoryAxis(AxisPosition.BOTTOM);
-        XDDFValueAxis leftValues = chart.createValueAxis(AxisPosition.LEFT);
-        leftValues.crossAxis(barCategories);
-        barCategories.crossAxis(leftValues);
-
-        // from https://stackoverflow.com/questions/50873700/
-        // colored major grid lines
-        leftValues.getOrAddMajorGridProperties().setLineProperties(solidTomato);
-        //colored axis line
-        leftValues.getOrAddShapeProperties().setLineProperties(solidPlum);
-        // axis font
-        XDDFRunProperties props = leftValues.getOrAddTextProperties();
-        props.setFontSize(14.0);
-        props.setFillProperties(fills[5]);
-
-        XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, barCategories, leftValues);
-        bar.setVaryColors(true);
-        bar.setBarDirection(chartedCols.length > 1 ? BarDirection.COL : BarDirection.BAR);
-
-        for (int c : chartedCols) {
-            // the data sources
-            XDDFCategoryDataSource xs = XDDFDataSourcesFactory.fromStringCellRange(sheet,
-                    new CellRangeAddress(1, NUM_OF_ROWS, 0, 0));
-            XDDFNumericalDataSource<Double> ys = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
-                    new CellRangeAddress(1, NUM_OF_ROWS, c, c));
-            XDDFBarChartData.Series series = (XDDFBarChartData.Series) bar.addSeries(xs, ys);
-            series.setTitle(null, new CellReference(sheet.getSheetName(), 0, c, true, true));
-            series.setFillProperties(fills[c]);
-            series.setLineProperties(solidTurquoise); // bar border color different from fill
-        }
-        chart.plot(bar);
-
-
-        // target line
-        // line of a scatter chart from 0 (min) to 1 (max) having value of target
-
-        XDDFValueAxis scatterX = chart.createValueAxis(AxisPosition.TOP);
-        scatterX.setVisible(false);
-        scatterX.setTickLabelPosition(AxisTickLabelPosition.NONE);
-        XDDFValueAxis scatterY = chart.createValueAxis(AxisPosition.RIGHT);
-        scatterY.setVisible(false);
-        scatterY.setTickLabelPosition(AxisTickLabelPosition.NONE);
-        scatterX.crossAxis(scatterY);
-        scatterY.crossAxis(scatterX);
-        if (chartedCols.length > 1) {
-            scatterX.setMaximum(1.0);
-        } else {
-            scatterY.setMaximum(1.0);
-        }
-
-        XDDFScatterChartData scatter = (XDDFScatterChartData) chart.createData(ChartTypes.SCATTER, scatterX, scatterY);
-        scatter.setVaryColors(true);
-
-        //  This only works for Excel since OpenOffice or LibreOffice Calc does not support literal numeric data series.
-        XDDFNumericalDataSource<Double> targetDS = XDDFDataSourcesFactory.fromArray(new Double[] { target, target });
-        XDDFNumericalDataSource<Double> zeroOneDS = XDDFDataSourcesFactory.fromArray(new Double[] { 0.0, 1.0 });
-
-        if (chartedCols.length > 1) {
-            // BarDirection.COL then X axis is from 0 to 1 and Y axis is target axis
-            scatter.addSeries(zeroOneDS, targetDS).setLineProperties(solidTurquoise);
-        } else {
-            // BarDirection.BAR then X axis is target axis and Y axis is from 0 to 1
-            scatter.addSeries(targetDS, zeroOneDS).setLineProperties(solidTurquoise);
-        }
-
-        chart.plot(scatter);
-
-
-        // legend
-        if (chartedCols.length > 1) {
-            XDDFChartLegend legend = chart.getOrAddLegend();
-            legend.setPosition(LegendPosition.LEFT);
-            legend.setOverlay(false);
-
-            // delete additional target line series legend entry
-            XDDFLegendEntry entry = legend.addEntry();
-            entry.setIndex(0);
-            entry.setDelete(true);
-        }
-
-
-        // from https://stackoverflow.com/questions/51530552/
-        // customize the chart
-
-        // do not auto delete the title
-        chart.setAutoTitleDeleted(false);
-
-        // plot area background and border line
-        XDDFShapeProperties chartProps = chart.getOrAddShapeProperties();
-        chartProps.setFillProperties(solidAlmond);
-        chartProps.setLineProperties(new XDDFLineProperties(solidGray));
-
-        // line style of cat axis
-        XDDFLineProperties categoriesProps = new XDDFLineProperties(solidGray);
-        categoriesProps.setWidth(2.1);
-        barCategories.getOrAddShapeProperties().setLineProperties(categoriesProps);
-    }
-
-    private static XSSFClientAnchor createAnchor(XSSFDrawing drawing, int[] chartedCols) {
-        if (chartedCols.length > 1) {
-            return drawing.createAnchor(0, 0, 0, 0, 0, 8, 10, 23);
-        } else {
-            return drawing.createAnchor(0, 0, 0, 0, 0, 8, 5, 23);
-        }
-    }
-
-    public static void main(String[] args) throws Exception {
-        try (XSSFWorkbook workbook = new XSSFWorkbook()) {
-            XSSFSheet sheet = workbook.createSheet("targetline");
-            final int NUM_OF_COLUMNS = 4;
-
-            // create some data
-            XSSFRow row;
-            XSSFCell cell;
-            String[] headings = new String[] { "Year", "Male", "Female", "Other" };
-            int rowIndex = 0;
-            row = sheet.createRow(rowIndex);
-            for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
-                cell = row.createCell(colIndex);
-                cell.setCellValue(headings[colIndex]);
-            }
-            double[][] values = new double[][] { new double[] { 1980, 56.0, 44.1, 12.2 },
-                    new double[] { 1985, 34.5, 41.0, 4 }, new double[] { 1990, 65.0, 68.5, 9.1 },
-                    new double[] { 1995, 34.7, 47.6, 4.9 }, new double[] { 2000, 23.0, 64.5, 11.1 },
-                    new double[] { 2005, 56.3, 69.8, 9.5 } };
-            for (; rowIndex < NUM_OF_ROWS; rowIndex++) {
-                row = sheet.createRow(rowIndex + 1);
-                for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
-                    cell = row.createCell(colIndex);
-                    cell.setCellValue(values[rowIndex][colIndex]);
-                }
-            }
-
-            int[] chartedCols = new int[] {  1,  2  , 3  };
-
-            XSSFDrawing drawing = sheet.createDrawingPatriarch();
-            XSSFClientAnchor anchor = createAnchor(drawing, chartedCols);
-            XSSFChart chart = drawing.createChart(anchor);
-            createChart(chart, sheet, chartedCols, 42.0);
-
-            try (FileOutputStream fos = new FileOutputStream("ExcelChartWithTargetLine.xlsx")) {
-                workbook.write(fos);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/FillsAndColors.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/FillsAndColors.java
deleted file mode 100644 (file)
index f7ffcf5..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.ss.usermodel.IndexedColors;
-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.xssf.usermodel.XSSFRichTextString;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Fills and Colors
- */
-public class FillsAndColors {
-    public static void main(String[] args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
-            Sheet sheet = wb.createSheet("new sheet");
-
-            // Create a row and put some cells in it. Rows are 0 based.
-            Row row = sheet.createRow(1);
-
-            // Aqua background
-            CellStyle style = wb.createCellStyle();
-            style.setFillBackgroundColor(IndexedColors.AQUA.getIndex());
-            style.setFillPattern(FillPatternType.BIG_SPOTS);
-            Cell cell = row.createCell(1);
-            cell.setCellValue(new XSSFRichTextString("X"));
-            cell.setCellStyle(style);
-
-            // Orange "foreground", foreground being the fill foreground not the font color.
-            style = wb.createCellStyle();
-            style.setFillForegroundColor(IndexedColors.ORANGE.getIndex());
-            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-            cell = row.createCell(2);
-            cell.setCellValue(new XSSFRichTextString("X"));
-            cell.setCellStyle(style);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("fill_colors.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/FitSheetToOnePage.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/FitSheetToOnePage.java
deleted file mode 100644 (file)
index 398b8de..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.PrintSetup;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-public class FitSheetToOnePage {
-
-    public static void main(String[]args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {  //or new HSSFWorkbook();
-            Sheet sheet = wb.createSheet("format sheet");
-            PrintSetup ps = sheet.getPrintSetup();
-
-            sheet.setAutobreaks(true);
-
-            ps.setFitHeight((short) 1);
-            ps.setFitWidth((short) 1);
-
-            // Create various cells and rows for spreadsheet.
-
-            try (FileOutputStream fileOut = new FileOutputStream("fitSheetToOnePage.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/HeadersAndFooters.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/HeadersAndFooters.java
deleted file mode 100644 (file)
index fc9860d..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Footer;
-import org.apache.poi.ss.usermodel.Header;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-public class HeadersAndFooters {
-
-    public static void main(String[]args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
-            Sheet sheet = wb.createSheet("first-header - format sheet");
-            sheet.createRow(0).createCell(0).setCellValue(123);
-
-            //set page numbers in the footer
-            Footer footer = sheet.getFooter();
-            //&P == current page number
-            //&N == page numbers
-            footer.setRight("Page &P of &N");
-
-
-            Header firstHeader = ((XSSFSheet) sheet).getFirstHeader();
-            //&F == workbook file name
-            firstHeader.setLeft("&F ......... first header");
-
-            for (int i = 0; i < 100; i = i + 10) {
-                sheet.createRow(i).createCell(0).setCellValue(123);
-            }
-
-
-            XSSFSheet sheet2 = (XSSFSheet) wb.createSheet("odd header-even footer");
-            Header oddHeader = sheet2.getOddHeader();
-            //&B == bold
-            //&E == double underline
-            //&D == date
-            oddHeader.setCenter("&B &E oddHeader     &D ");
-
-            Footer evenFooter = sheet2.getEvenFooter();
-            evenFooter.setRight("even footer &P");
-            sheet2.createRow(10).createCell(0).setCellValue("Second sheet with an oddHeader and an evenFooter");
-
-            for (int i = 0; i < 200; i = i + 10) {
-                sheet2.createRow(i).createCell(0).setCellValue(123);
-            }
-
-            XSSFSheet sheet3 = (XSSFSheet) wb.createSheet("odd header- odd footer");
-            sheet3.createRow(10).createCell(0).setCellValue("Third sheet with oddHeader and oddFooter");
-            Header oddH = sheet3.getOddHeader();
-            //&C == centered
-            oddH.setCenter("centered oddHeader");
-            oddH.setLeft("left ");
-            oddH.setRight("right ");
-
-            Footer oddF = sheet3.getOddFooter();
-            oddF.setLeft("Page &P");
-            oddF.setRight("Pages &N ");
-
-            try (FileOutputStream fileOut = new FileOutputStream("headerFooter.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/HyperlinkExample.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/HyperlinkExample.java
deleted file mode 100644 (file)
index e5663ec..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.common.usermodel.HyperlinkType;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.CreationHelper;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.Hyperlink;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Demonstrates how to create hyperlinks.
- */
-public class HyperlinkExample {
-
-    public static void main(String[]args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
-            CreationHelper createHelper = wb.getCreationHelper();
-
-            //cell style for hyperlinks
-            //by default hyperlinks are blue and underlined
-            CellStyle hlink_style = wb.createCellStyle();
-            Font hlink_font = wb.createFont();
-            hlink_font.setUnderline(Font.U_SINGLE);
-            hlink_font.setColor(IndexedColors.BLUE.getIndex());
-            hlink_style.setFont(hlink_font);
-
-            Cell cell;
-            Sheet sheet = wb.createSheet("Hyperlinks");
-            //URL
-            cell = sheet.createRow(0).createCell(0);
-            cell.setCellValue("URL Link");
-
-            Hyperlink link = createHelper.createHyperlink(HyperlinkType.URL);
-            link.setAddress("https://poi.apache.org/");
-            cell.setHyperlink(link);
-            cell.setCellStyle(hlink_style);
-
-            //link to a file in the current directory
-            cell = sheet.createRow(1).createCell(0);
-            cell.setCellValue("File Link");
-            link = createHelper.createHyperlink(HyperlinkType.FILE);
-            link.setAddress("link1.xls");
-            cell.setHyperlink(link);
-            cell.setCellStyle(hlink_style);
-
-            //e-mail link
-            cell = sheet.createRow(2).createCell(0);
-            cell.setCellValue("Email Link");
-            link = createHelper.createHyperlink(HyperlinkType.EMAIL);
-            //note, if subject contains white spaces, make sure they are url-encoded
-            link.setAddress("mailto:poi@apache.org?subject=Hyperlinks");
-            cell.setHyperlink(link);
-            cell.setCellStyle(hlink_style);
-
-            //link to a place in this workbook
-
-            //create a target sheet and cell
-            Sheet sheet2 = wb.createSheet("Target Sheet");
-            sheet2.createRow(0).createCell(0).setCellValue("Target Cell");
-
-            cell = sheet.createRow(3).createCell(0);
-            cell.setCellValue("Worksheet Link");
-            Hyperlink link2 = createHelper.createHyperlink(HyperlinkType.DOCUMENT);
-            link2.setAddress("'Target Sheet'!A1");
-            cell.setHyperlink(link2);
-            cell.setCellStyle(hlink_style);
-
-            try (FileOutputStream out = new FileOutputStream("hyperinks.xlsx")) {
-                wb.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/IterateCells.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/IterateCells.java
deleted file mode 100644 (file)
index b7f2930..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Cell;
-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.xssf.usermodel.XSSFWorkbook;
-
-/**
- *  Iterate over rows and cells
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class IterateCells {
-
-    private IterateCells() {}
-
-    public static void main(String[] args) throws IOException {
-        try (
-                FileInputStream is = new FileInputStream(args[0]);
-                Workbook wb = new XSSFWorkbook(is)
-            ) {
-            for (int i = 0; i < wb.getNumberOfSheets(); i++) {
-                Sheet sheet = wb.getSheetAt(i);
-                System.out.println(wb.getSheetName(i));
-                for (Row row : sheet) {
-                    System.out.println("rownum: " + row.getRowNum());
-                    for (Cell cell : row) {
-                        System.out.println(cell);
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/LineChart.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/LineChart.java
deleted file mode 100644 (file)
index 0141e17..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.xddf.usermodel.PresetColor;
-import org.apache.poi.xddf.usermodel.XDDFColor;
-import org.apache.poi.xddf.usermodel.XDDFLineProperties;
-import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
-import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
-import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
-import org.apache.poi.xddf.usermodel.chart.AxisPosition;
-import org.apache.poi.xddf.usermodel.chart.ChartTypes;
-import org.apache.poi.xddf.usermodel.chart.LegendPosition;
-import org.apache.poi.xddf.usermodel.chart.MarkerStyle;
-import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
-import org.apache.poi.xddf.usermodel.chart.XDDFLineChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
-import org.apache.poi.xssf.usermodel.XSSFChart;
-import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
-import org.apache.poi.xssf.usermodel.XSSFDrawing;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Line chart example.
- */
-public final class LineChart {
-    private LineChart() {}
-
-    public static void main(String[] args) throws IOException {
-        try (XSSFWorkbook wb = new XSSFWorkbook()) {
-            XSSFSheet sheet = wb.createSheet("linechart");
-            final int NUM_OF_ROWS = 3;
-            final int NUM_OF_COLUMNS = 10;
-
-            // Create a row and put some cells in it. Rows are 0 based.
-            Row row;
-            Cell cell;
-            for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) {
-                row = sheet.createRow((short) rowIndex);
-                for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
-                    cell = row.createCell((short) colIndex);
-                    cell.setCellValue(colIndex * (rowIndex + 1.0));
-                }
-            }
-
-            XSSFDrawing drawing = sheet.createDrawingPatriarch();
-            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);
-
-            XSSFChart chart = drawing.createChart(anchor);
-            XDDFChartLegend legend = chart.getOrAddLegend();
-            legend.setPosition(LegendPosition.TOP_RIGHT);
-
-            // Use a category axis for the bottom axis.
-            XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
-            bottomAxis.setTitle("x"); // https://stackoverflow.com/questions/32010765
-            XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
-            leftAxis.setTitle("f(x)");
-            leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
-
-            XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
-            XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1));
-            XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1));
-
-            XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
-            XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) data.addSeries(xs, ys1);
-            series1.setTitle("2x", null); // https://stackoverflow.com/questions/21855842
-            series1.setSmooth(false); // https://stackoverflow.com/questions/29014848
-            series1.setMarkerStyle(MarkerStyle.STAR); // https://stackoverflow.com/questions/39636138
-            XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) data.addSeries(xs, ys2);
-            series2.setTitle("3x", null);
-            series2.setSmooth(true);
-            series2.setMarkerSize((short) 6);
-            series2.setMarkerStyle(MarkerStyle.TRIANGLE); // https://stackoverflow.com/questions/39636138
-            chart.plot(data);
-
-            // if your series have missing values like https://stackoverflow.com/questions/29014848
-            // chart.displayBlanksAs(DisplayBlanks.GAP);
-
-            // https://stackoverflow.com/questions/24676460
-            solidLineSeries(data, 0, PresetColor.CHARTREUSE);
-            solidLineSeries(data, 1, PresetColor.TURQUOISE);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("ooxml-line-chart.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-
-    private static void solidLineSeries(XDDFChartData data, int index, PresetColor color) {
-        XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
-        XDDFLineProperties line = new XDDFLineProperties();
-        line.setFillProperties(fill);
-        XDDFChartData.Series series = data.getSeries().get(index);
-        XDDFShapeProperties properties = series.getShapeProperties();
-        if (properties == null) {
-            properties = new XDDFShapeProperties();
-        }
-        properties.setLineProperties(line);
-        series.setShapeProperties(properties);
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/LoadPasswordProtectedXlsx.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/LoadPasswordProtectedXlsx.java
deleted file mode 100644 (file)
index 7afe88f..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileInputStream;
-import java.io.InputStream;
-
-import org.apache.poi.examples.util.TempFileUtils;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.poifs.crypt.Decryptor;
-import org.apache.poi.poifs.crypt.EncryptionInfo;
-import org.apache.poi.poifs.crypt.temp.AesZipFileZipEntrySource;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * An example that loads a password protected workbook and counts the sheets.
- * <p><ul>
- * <li>The example demonstrates that all temp files are removed.
- * <li><code>AesZipFileZipEntrySource</code> is used to ensure that temp files are encrypted.
- * </ul><p>
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class LoadPasswordProtectedXlsx {
-
-    private LoadPasswordProtectedXlsx() {}
-
-    public interface EncryptionHandler {
-        void handle(final InputStream inputStream) throws Exception;
-    }
-
-    public static void main(String[] args) throws Exception {
-        execute(args, LoadPasswordProtectedXlsx::printSheetCount);
-    }
-
-    public static void execute(String[] args, EncryptionHandler handler) throws Exception {
-        if(args.length != 2) {
-            throw new IllegalArgumentException("Expected 2 params: filename and password");
-        }
-        TempFileUtils.checkTempFiles();
-        String filename = args[0];
-        String password = args[1];
-        try (FileInputStream fis = new FileInputStream(filename);
-             POIFSFileSystem fs = new POIFSFileSystem(fis)) {
-            EncryptionInfo info = new EncryptionInfo(fs);
-            Decryptor d = Decryptor.getInstance(info);
-            if (!d.verifyPassword(password)) {
-                throw new RuntimeException("incorrect password");
-            }
-            try (InputStream unencryptedStream = d.getDataStream(fs)) {
-                handler.handle(unencryptedStream);
-            }
-        }
-        TempFileUtils.checkTempFiles();
-    }
-
-
-    private static void printSheetCount(final InputStream inputStream) throws Exception {
-        try (AesZipFileZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(inputStream);
-             OPCPackage pkg = OPCPackage.open(source);
-             XSSFWorkbook workbook = new XSSFWorkbook(pkg)) {
-            System.out.println("sheet count: " + workbook.getNumberOfSheets());
-        }
-    }
-
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/MergingCells.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/MergingCells.java
deleted file mode 100644 (file)
index f9abb80..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Cell;
-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.util.CellRangeAddress;
-import org.apache.poi.xssf.usermodel.XSSFRichTextString;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * An example of how to merge regions of cells.
- */
-public class MergingCells {
-    public static void main(String[] args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
-            Sheet sheet = wb.createSheet("new sheet");
-
-            Row row = sheet.createRow((short) 1);
-            Cell cell = row.createCell((short) 1);
-            cell.setCellValue(new XSSFRichTextString("This is a test of merging"));
-
-            sheet.addMergedRegion(new CellRangeAddress(1, 1, 1, 2));
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("merging_cells.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/NewLinesInCells.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/NewLinesInCells.java
deleted file mode 100644 (file)
index c3b4c1c..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-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.xssf.usermodel.XSSFWorkbook;
-
-/**
- * How to use newlines in cells
- */
-public class NewLinesInCells {
-
-    public static void main(String[]args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {   //or new HSSFWorkbook();
-            Sheet sheet = wb.createSheet();
-
-            Row row = sheet.createRow(2);
-            Cell cell = row.createCell(2);
-            cell.setCellValue("Use \n with word wrap on to create a new line");
-
-            //to enable newlines you need set a cell styles with wrap=true
-            CellStyle cs = wb.createCellStyle();
-            cs.setWrapText(true);
-            cell.setCellStyle(cs);
-
-            //increase row height to accommodate two lines of text
-            row.setHeightInPoints(2 * sheet.getDefaultRowHeightInPoints());
-
-            //adjust column width to fit the content
-            sheet.autoSizeColumn(2);
-
-            try (FileOutputStream fileOut = new FileOutputStream("ooxml-newlines.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/Outlining.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/Outlining.java
deleted file mode 100644 (file)
index b00b59a..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-public class Outlining {
-
-    public static void main(String[] args) throws IOException {
-        Outlining o=new Outlining();
-        o.groupRowColumn();
-        o.collapseExpandRowColumn();
-    }
-
-
-    private void groupRowColumn() throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {
-            Sheet sheet1 = wb.createSheet("new sheet");
-
-            sheet1.groupRow(5, 14);
-            sheet1.groupRow(7, 14);
-            sheet1.groupRow(16, 19);
-
-            sheet1.groupColumn((short) 4, (short) 7);
-            sheet1.groupColumn((short) 9, (short) 12);
-            sheet1.groupColumn((short) 10, (short) 11);
-
-            try (OutputStream fileOut = new FileOutputStream("outlining.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-
-    private void collapseExpandRowColumn() throws IOException {
-        try (Workbook wb2 = new XSSFWorkbook()) {
-            Sheet sheet2 = wb2.createSheet("new sheet");
-            sheet2.groupRow(5, 14);
-            sheet2.groupRow(7, 14);
-            sheet2.groupRow(16, 19);
-
-            sheet2.groupColumn((short) 4, (short) 7);
-            sheet2.groupColumn((short) 9, (short) 12);
-            sheet2.groupColumn((short) 10, (short) 11);
-
-
-            sheet2.setRowGroupCollapsed(7, true);
-            //sheet1.setRowGroupCollapsed(7,false);
-
-            sheet2.setColumnGroupCollapsed((short) 4, true);
-            sheet2.setColumnGroupCollapsed((short) 4, false);
-
-            try (OutputStream fileOut = new FileOutputStream("outlining_collapsed.xlsx")) {
-                wb2.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/ScatterChart.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/ScatterChart.java
deleted file mode 100644 (file)
index 5e10db8..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.xddf.usermodel.PresetColor;
-import org.apache.poi.xddf.usermodel.XDDFColor;
-import org.apache.poi.xddf.usermodel.XDDFLineProperties;
-import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
-import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
-import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
-import org.apache.poi.xddf.usermodel.chart.AxisPosition;
-import org.apache.poi.xddf.usermodel.chart.ChartTypes;
-import org.apache.poi.xddf.usermodel.chart.LegendPosition;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
-import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFScatterChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
-import org.apache.poi.xssf.usermodel.XSSFChart;
-import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
-import org.apache.poi.xssf.usermodel.XSSFDrawing;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Illustrates how to create a simple scatter chart.
- */
-public final class ScatterChart {
-    private ScatterChart() {}
-
-    public static void main(String[] args) throws IOException {
-        try (XSSFWorkbook wb = new XSSFWorkbook()) {
-            XSSFSheet sheet = wb.createSheet("Sheet 1");
-            final int NUM_OF_ROWS = 3;
-            final int NUM_OF_COLUMNS = 10;
-
-            // Create a row and put some cells in it. Rows are 0 based.
-            Row row;
-            Cell cell;
-            for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) {
-                row = sheet.createRow((short) rowIndex);
-                for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
-                    cell = row.createCell((short) colIndex);
-                    cell.setCellValue(colIndex * (rowIndex + 1.0));
-                }
-            }
-
-            XSSFDrawing drawing = sheet.createDrawingPatriarch();
-            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);
-
-            XSSFChart chart = drawing.createChart(anchor);
-            XDDFChartLegend legend = chart.getOrAddLegend();
-            legend.setPosition(LegendPosition.TOP_RIGHT);
-
-            XDDFValueAxis bottomAxis = chart.createValueAxis(AxisPosition.BOTTOM);
-            bottomAxis.setTitle("x"); // https://stackoverflow.com/questions/32010765
-            XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
-            leftAxis.setTitle("f(x)");
-            leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
-
-            XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
-            XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1));
-            XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1));
-
-
-            XDDFScatterChartData data = (XDDFScatterChartData) chart.createData(ChartTypes.SCATTER, bottomAxis, leftAxis);
-            XDDFScatterChartData.Series series1 = (XDDFScatterChartData.Series) data.addSeries(xs, ys1);
-            series1.setTitle("2x", null); // https://stackoverflow.com/questions/21855842
-            series1.setSmooth(false); // https://stackoverflow.com/questions/39636138
-            XDDFScatterChartData.Series series2 = (XDDFScatterChartData.Series) data.addSeries(xs, ys2);
-            series2.setTitle("3x", null);
-            chart.plot(data);
-
-            solidLineSeries(data, 0, PresetColor.CHARTREUSE);
-            solidLineSeries(data, 1, PresetColor.TURQUOISE);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("ooxml-scatter-chart.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-
-    private static void solidLineSeries(XDDFChartData data, int index, PresetColor color) {
-        XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
-        XDDFLineProperties line = new XDDFLineProperties();
-        line.setFillProperties(fill);
-        XDDFChartData.Series series = data.getSeries().get(index);
-        XDDFShapeProperties properties = series.getShapeProperties();
-        if (properties == null) {
-            properties = new XDDFShapeProperties();
-        }
-        properties.setLineProperties(line);
-        series.setShapeProperties(properties);
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/SelectedSheet.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/SelectedSheet.java
deleted file mode 100644 (file)
index ffe384f..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-public abstract class SelectedSheet {
-    
-    public static void main(String[]args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
-
-            wb.createSheet("row sheet");
-            wb.createSheet("another sheet");
-            Sheet sheet3 = wb.createSheet(" sheet 3 ");
-            sheet3.setSelected(true);
-            wb.setActiveSheet(2);
-
-            // Create various cells and rows for spreadsheet.
-
-            try (FileOutputStream fileOut = new FileOutputStream("selectedSheet.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/ShiftRows.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/ShiftRows.java
deleted file mode 100644 (file)
index 48ab3bf..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-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.xssf.usermodel.XSSFWorkbook;
-
-/**
- * How to shift rows up or down 
- */
-public class ShiftRows {
-
-    public static void main(String[]args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {   //or new HSSFWorkbook();
-            Sheet sheet = wb.createSheet("Sheet1");
-
-            Row row1 = sheet.createRow(1);
-            row1.createCell(0).setCellValue(1);
-
-            Row row2 = sheet.createRow(4);
-            row2.createCell(1).setCellValue(2);
-
-            Row row3 = sheet.createRow(5);
-            row3.createCell(2).setCellValue(3);
-
-            Row row4 = sheet.createRow(6);
-            row4.createCell(3).setCellValue(4);
-
-            Row row5 = sheet.createRow(9);
-            row5.createCell(4).setCellValue(5);
-
-            // Shift rows 6 - 11 on the spreadsheet to the top (rows 0 - 5)
-            sheet.shiftRows(5, 10, -4);
-
-            try (FileOutputStream fileOut = new FileOutputStream("shiftRows.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/SplitAndFreezePanes.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/SplitAndFreezePanes.java
deleted file mode 100644 (file)
index dfee247..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * How to set split and freeze panes
- */
-public class SplitAndFreezePanes {
-    public static void main(String[]args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {
-            Sheet sheet1 = wb.createSheet("new sheet");
-            Sheet sheet2 = wb.createSheet("second sheet");
-            Sheet sheet3 = wb.createSheet("third sheet");
-            Sheet sheet4 = wb.createSheet("fourth sheet");
-
-            // Freeze just one row
-            sheet1.createFreezePane(0, 1, 0, 1);
-            // Freeze just one column
-            sheet2.createFreezePane(1, 0, 1, 0);
-            // Freeze the columns and rows (forget about scrolling position of the lower right quadrant).
-            sheet3.createFreezePane(2, 2);
-            // Create a split with the lower left side being the active quadrant
-            sheet4.createSplitPane(2000, 2000, 0, 0, Sheet.PANE_LOWER_LEFT);
-
-            try (FileOutputStream fileOut = new FileOutputStream("splitFreezePane.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkbookProperties.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkbookProperties.java
deleted file mode 100644 (file)
index 4e28e9d..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ooxml.POIXMLProperties;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * How to set extended and custom properties
- */
-public class WorkbookProperties {
-
-    public static void main(String[]args) throws IOException {
-        try (XSSFWorkbook workbook = new XSSFWorkbook()) {
-            workbook.createSheet("Workbook Properties");
-
-            POIXMLProperties props = workbook.getProperties();
-
-            /*
-             * Extended properties are a predefined set of metadata properties
-             * that are specifically applicable to Office Open XML documents.
-             * Extended properties consist of 24 simple properties and 3 complex properties stored in the
-             *  part targeted by the relationship of type
-             */
-            POIXMLProperties.ExtendedProperties ext = props.getExtendedProperties();
-            ext.getUnderlyingProperties().setCompany("Apache Software Foundation");
-            ext.getUnderlyingProperties().setTemplate("XSSF");
-
-            /*
-             * Custom properties enable users to define custom metadata properties.
-             */
-
-            POIXMLProperties.CustomProperties cust = props.getCustomProperties();
-            cust.addProperty("Author", "John Smith");
-            cust.addProperty("Year", 2009);
-            cust.addProperty("Price", 45.50);
-            cust.addProperty("Available", true);
-
-            try (FileOutputStream out = new FileOutputStream("workbook.xlsx")) {
-                workbook.write(out);
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithBorders.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithBorders.java
deleted file mode 100644 (file)
index bdf856f..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.IndexedColors;
-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.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Working with borders
- */
-public class WorkingWithBorders {
-    public static void main(String[] args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {  //or new HSSFWorkbook();
-            Sheet sheet = wb.createSheet("borders");
-
-            // Create a row and put some cells in it. Rows are 0 based.
-            Row row = sheet.createRow((short) 1);
-
-            // Create a cell and put a value in it.
-            Cell cell = row.createCell((short) 1);
-            cell.setCellValue(4);
-
-            // Style the cell with borders all around.
-            CellStyle style = wb.createCellStyle();
-            style.setBorderBottom(BorderStyle.THIN);
-            style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
-            style.setBorderLeft(BorderStyle.THIN);
-            style.setLeftBorderColor(IndexedColors.GREEN.getIndex());
-            style.setBorderRight(BorderStyle.THIN);
-            style.setRightBorderColor(IndexedColors.BLUE.getIndex());
-            style.setBorderTop(BorderStyle.MEDIUM_DASHED);
-            style.setTopBorderColor(IndexedColors.BLACK.getIndex());
-            cell.setCellStyle(style);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("xssf-borders.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithFonts.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithFonts.java
deleted file mode 100644 (file)
index b2fa599..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Working with Fonts
- */
-public class WorkingWithFonts {
-    public static void main(String[] args) throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {  //or new HSSFWorkbook();
-            Sheet sheet = wb.createSheet("Fonts");
-
-            Font font0 = wb.createFont();
-            font0.setColor(IndexedColors.BROWN.getIndex());
-            CellStyle style0 = wb.createCellStyle();
-            style0.setFont(font0);
-
-            Font font1 = wb.createFont();
-            font1.setFontHeightInPoints((short) 14);
-            font1.setFontName("Courier New");
-            font1.setColor(IndexedColors.RED.getIndex());
-            CellStyle style1 = wb.createCellStyle();
-            style1.setFont(font1);
-
-            Font font2 = wb.createFont();
-            font2.setFontHeightInPoints((short) 16);
-            font2.setFontName("Arial");
-            font2.setColor(IndexedColors.GREEN.getIndex());
-            CellStyle style2 = wb.createCellStyle();
-            style2.setFont(font2);
-
-            Font font3 = wb.createFont();
-            font3.setFontHeightInPoints((short) 18);
-            font3.setFontName("Times New Roman");
-            font3.setColor(IndexedColors.LAVENDER.getIndex());
-            CellStyle style3 = wb.createCellStyle();
-            style3.setFont(font3);
-
-            Font font4 = wb.createFont();
-            font4.setFontHeightInPoints((short) 18);
-            font4.setFontName("Wingdings");
-            font4.setColor(IndexedColors.GOLD.getIndex());
-            CellStyle style4 = wb.createCellStyle();
-            style4.setFont(font4);
-
-            Font font5 = wb.createFont();
-            font5.setFontName("Symbol");
-            CellStyle style5 = wb.createCellStyle();
-            style5.setFont(font5);
-
-            Cell cell0 = sheet.createRow(0).createCell(1);
-            cell0.setCellValue("Default");
-            cell0.setCellStyle(style0);
-
-            Cell cell1 = sheet.createRow(1).createCell(1);
-            cell1.setCellValue("Courier");
-            cell1.setCellStyle(style1);
-
-            Cell cell2 = sheet.createRow(2).createCell(1);
-            cell2.setCellValue("Arial");
-            cell2.setCellStyle(style2);
-
-            Cell cell3 = sheet.createRow(3).createCell(1);
-            cell3.setCellValue("Times New Roman");
-            cell3.setCellStyle(style3);
-
-            Cell cell4 = sheet.createRow(4).createCell(1);
-            cell4.setCellValue("Wingdings");
-            cell4.setCellStyle(style4);
-
-            Cell cell5 = sheet.createRow(5).createCell(1);
-            cell5.setCellValue("Symbol");
-            cell5.setCellStyle(style5);
-
-            // Write the output to a file
-            try (FileOutputStream fileOut = new FileOutputStream("xssf-fonts.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithPageSetup.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithPageSetup.java
deleted file mode 100644 (file)
index 7da2d53..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Demonstrates various settings avaiable in the Page Setup dialog
- */
-public class WorkingWithPageSetup {
-
-    public static void main(String[]args) throws Exception {
-        try (Workbook wb = new XSSFWorkbook()) {  //or new HSSFWorkbook();
-
-        /*
-         * It's possible to set up repeating rows and columns in your printouts by using the setRepeatingRowsAndColumns() function in the Workbook object.
-         *
-         * This function Contains 5 parameters:
-         * The first parameter is the index to the sheet (0 = first sheet).
-         * The second and third parameters specify the range for the columns to repreat.
-         * To stop the columns from repeating pass in -1 as the start and end column.
-         * The fourth and fifth parameters specify the range for the rows to repeat.
-         * To stop the columns from repeating pass in -1 as the start and end rows.
-         */
-            Sheet sheet1 = wb.createSheet("new sheet");
-            Sheet sheet2 = wb.createSheet("second sheet");
-
-            // Set the columns to repeat from column 0 to 2 on the first sheet
-            Row row1 = sheet1.createRow(0);
-            row1.createCell(0).setCellValue(1);
-            row1.createCell(1).setCellValue(2);
-            row1.createCell(2).setCellValue(3);
-            Row row2 = sheet1.createRow(1);
-            row2.createCell(1).setCellValue(4);
-            row2.createCell(2).setCellValue(5);
-
-
-            Row row3 = sheet2.createRow(1);
-            row3.createCell(0).setCellValue(2.1);
-            row3.createCell(4).setCellValue(2.2);
-            row3.createCell(5).setCellValue(2.3);
-            Row row4 = sheet2.createRow(2);
-            row4.createCell(4).setCellValue(2.4);
-            row4.createCell(5).setCellValue(2.5);
-
-            // Set the columns to repeat from column 0 to 2 on the first sheet
-            sheet1.setRepeatingColumns(CellRangeAddress.valueOf("A:C"));
-            // Set the the repeating rows and columns on the second sheet.
-            CellRangeAddress cra = CellRangeAddress.valueOf("E2:F3");
-            sheet2.setRepeatingColumns(cra);
-            sheet2.setRepeatingRows(cra);
-
-            //set the print area for the first sheet
-            wb.setPrintArea(0, 1, 2, 0, 3);
-
-
-            try (FileOutputStream fileOut = new FileOutputStream("xssf-printsetup.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithPictures.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithPictures.java
deleted file mode 100644 (file)
index 0bee5e7..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.apache.poi.ss.usermodel.ClientAnchor;
-import org.apache.poi.ss.usermodel.CreationHelper;
-import org.apache.poi.ss.usermodel.Drawing;
-import org.apache.poi.ss.usermodel.Picture;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Demonstrates how to insert pictures in a SpreadsheetML document
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class WorkingWithPictures {
-    private WorkingWithPictures() {}
-
-    public static void main(String[] args) throws IOException {
-
-        //create a new workbook
-        try (Workbook wb = new XSSFWorkbook()) {
-            CreationHelper helper = wb.getCreationHelper();
-
-            //add a picture in this workbook.
-            InputStream is = new FileInputStream(args[0]);
-            byte[] bytes = IOUtils.toByteArray(is);
-            is.close();
-            int pictureIdx = wb.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);
-
-            //create sheet
-            Sheet sheet = wb.createSheet();
-
-            //create drawing
-            Drawing<?> drawing = sheet.createDrawingPatriarch();
-
-            //add a picture shape
-            ClientAnchor anchor = helper.createClientAnchor();
-            anchor.setCol1(1);
-            anchor.setRow1(1);
-            Picture pict = drawing.createPicture(anchor, pictureIdx);
-
-            //auto-size picture
-            pict.resize(2);
-
-            //save workbook
-            String file = "picture.xls";
-            if (wb instanceof XSSFWorkbook) {
-                file += "x"; // NOSONAR
-            }
-            try (OutputStream fileOut = new FileOutputStream(file)) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithRichText.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithRichText.java
deleted file mode 100644 (file)
index 9fdda45..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.xssf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.xssf.usermodel.XSSFCell;
-import org.apache.poi.xssf.usermodel.XSSFColor;
-import org.apache.poi.xssf.usermodel.XSSFFont;
-import org.apache.poi.xssf.usermodel.XSSFRichTextString;
-import org.apache.poi.xssf.usermodel.XSSFRow;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Demonstrates how to work with rich text
- */
-public final class WorkingWithRichText {
-
-    private WorkingWithRichText() {}
-
-    public static void main(String[] args) throws Exception {
-        try (XSSFWorkbook wb = new XSSFWorkbook()) {
-            XSSFSheet sheet = wb.createSheet();
-            XSSFRow row = sheet.createRow(2);
-
-            XSSFCell cell = row.createCell(1);
-            XSSFRichTextString rt = new XSSFRichTextString("The quick brown fox");
-
-            XSSFFont font1 = wb.createFont();
-            font1.setBold(true);
-            font1.setColor(new XSSFColor(new java.awt.Color(255, 0, 0), wb.getStylesSource().getIndexedColors()));
-            rt.applyFont(0, 10, font1);
-
-            XSSFFont font2 = wb.createFont();
-            font2.setItalic(true);
-            font2.setUnderline(Font.U_DOUBLE);
-            font2.setColor(new XSSFColor(new java.awt.Color(0, 255, 0), wb.getStylesSource().getIndexedColors()));
-            rt.applyFont(10, 19, font2);
-
-            XSSFFont font3 = wb.createFont();
-            font3.setColor(new XSSFColor(new java.awt.Color(0, 0, 255), wb.getStylesSource().getIndexedColors()));
-            rt.append(" Jumped over the lazy dog", font3);
-
-            cell.setCellValue(rt);
-
-            // Write the output to a file
-            try (OutputStream fileOut = new FileOutputStream("xssf-richtext.xlsx")) {
-                wb.write(fileOut);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/BarChartExample.java b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/BarChartExample.java
deleted file mode 100644 (file)
index 2301687..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xwpf.usermodel.examples;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.xddf.usermodel.chart.AxisOrientation;
-import org.apache.poi.xddf.usermodel.chart.AxisPosition;
-import org.apache.poi.xddf.usermodel.chart.BarDirection;
-import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
-import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
-import org.apache.poi.xwpf.usermodel.XWPFChart;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-
-/**
- * Build a bar chart from a template docx
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class BarChartExample {
-    private BarChartExample() {}
-
-    private static void usage(){
-        System.out.println("Usage: BarChartExample <bar-chart-template.docx> <bar-chart-data.txt>");
-        System.out.println("    bar-chart-template.docx     template with a bar chart");
-        System.out.println("    bar-chart-data.txt          the model to set. First line is chart title, " +
-                "then go pairs {axis-label value}");
-    }
-
-    public static void main(String[] args) throws Exception {
-        if(args.length < 2) {
-            usage();
-            return;
-        }
-
-        try (FileInputStream argIS = new FileInputStream(args[0]);
-                BufferedReader modelReader = new BufferedReader(new FileReader(args[1]))) {
-
-            String chartTitle = modelReader.readLine();  // first line is chart title
-            String[] series = modelReader.readLine().split(",");
-
-            // Category Axis Data
-            List<String> listLanguages = new ArrayList<>(10);
-
-            // Values
-            List<Double> listCountries = new ArrayList<>(10);
-            List<Double> listSpeakers = new ArrayList<>(10);
-
-            // set model
-            String ln;
-            while((ln = modelReader.readLine()) != null) {
-                String[] vals = ln.split(",");
-                listCountries.add(Double.valueOf(vals[0]));
-                listSpeakers.add(Double.valueOf(vals[1]));
-                listLanguages.add(vals[2]);
-            }
-            String[] categories = listLanguages.toArray(new String[0]);
-            Double[] values1 = listCountries.toArray(new Double[0]);
-            Double[] values2 = listSpeakers.toArray(new Double[0]);
-
-            try (XWPFDocument doc = new XWPFDocument(argIS)) {
-                XWPFChart chart = doc.getCharts().get(0);
-                setBarData(chart, chartTitle, series, categories, values1, values2);
-                chart = doc.getCharts().get(1);
-                setColumnData(chart, "Column variant");
-
-                // save the result
-                try (OutputStream out = new FileOutputStream("bar-chart-demo-output.docx")) {
-                    doc.write(out);
-                }
-            }
-        }
-        System.out.println("Done");
-    }
-
-    private static void setBarData(XWPFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
-        final List<XDDFChartData> data = chart.getChartSeries();
-        final XDDFBarChartData bar = (XDDFBarChartData) data.get(0);
-
-        final int numOfPoints = categories.length;
-        final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
-        final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
-        final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
-        final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
-        final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, 1);
-        values1[6] = 16.0; // if you ever want to change the underlying data
-        final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);
-
-        XDDFChartData.Series series1 = bar.getSeries(0);
-        series1.replaceData(categoriesData, valuesData);
-        series1.setTitle(series[0], chart.setSheetTitle(series[0], 0));
-        XDDFChartData.Series series2 = bar.addSeries(categoriesData, valuesData2);
-        series2.setTitle(series[1], chart.setSheetTitle(series[1], 1));
-
-        chart.plot(bar);
-        chart.setTitleText(chartTitle); // https://stackoverflow.com/questions/30532612
-        chart.setTitleOverlay(false);
-    }
-
-    private static void setColumnData(XWPFChart chart, String chartTitle) {
-        // Series Text
-        List<XDDFChartData> series = chart.getChartSeries();
-        XDDFBarChartData bar = (XDDFBarChartData) series.get(0);
-
-        // in order to transform a bar chart into a column chart, you just need to change the bar direction
-        bar.setBarDirection(BarDirection.COL);
-
-        // looking for "Stacked Bar Chart"? uncomment the following line
-        // bar.setBarGrouping(BarGrouping.STACKED);
-
-        // additionally, you can adjust the axes
-        bar.getCategoryAxis().setOrientation(AxisOrientation.MAX_MIN);
-        bar.getValueAxes().get(0).setPosition(AxisPosition.TOP);
-    }
-}
-
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/BetterHeaderFooterExample.java b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/BetterHeaderFooterExample.java
deleted file mode 100644 (file)
index 6cd7cfa..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xwpf.usermodel.examples;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.poi.wp.usermodel.HeaderFooterType;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.poi.xwpf.usermodel.XWPFFooter;
-import org.apache.poi.xwpf.usermodel.XWPFHeader;
-import org.apache.poi.xwpf.usermodel.XWPFParagraph;
-import org.apache.poi.xwpf.usermodel.XWPFRun;
-
-public class BetterHeaderFooterExample {
-
-    public static void main(String[] args) throws IOException {
-        try (XWPFDocument doc = new XWPFDocument()) {
-
-            XWPFParagraph p = doc.createParagraph();
-
-            XWPFRun r = p.createRun();
-            r.setText("Some Text");
-            r.setBold(true);
-            r = p.createRun();
-            r.setText("Goodbye");
-
-            // create header/footer functions insert an empty paragraph
-            XWPFHeader head = doc.createHeader(HeaderFooterType.DEFAULT);
-            head.createParagraph().createRun().setText("header");
-
-            XWPFFooter foot = doc.createFooter(HeaderFooterType.DEFAULT);
-            foot.createParagraph().createRun().setText("footer");
-
-            try (OutputStream os = new FileOutputStream(new File("header2.docx"))) {
-                doc.write(os);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/ChartFromScratch.java b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/ChartFromScratch.java
deleted file mode 100644 (file)
index 266466c..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xwpf.usermodel.examples;
-
-import java.io.BufferedReader;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.xddf.usermodel.chart.AxisCrossBetween;
-import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
-import org.apache.poi.xddf.usermodel.chart.AxisPosition;
-import org.apache.poi.xddf.usermodel.chart.AxisTickMark;
-import org.apache.poi.xddf.usermodel.chart.BarDirection;
-import org.apache.poi.xddf.usermodel.chart.BarGrouping;
-import org.apache.poi.xddf.usermodel.chart.ChartTypes;
-import org.apache.poi.xddf.usermodel.chart.LegendPosition;
-import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
-import org.apache.poi.xddf.usermodel.chart.XDDFChart;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartAxis;
-import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
-import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
-import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
-import org.apache.poi.xwpf.usermodel.XWPFChart;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-
-/**
- * Build a chart without reading template file
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class ChartFromScratch {
-    private ChartFromScratch() {}
-
-    private static void usage(){
-        System.out.println("Usage: ChartFromScratch <bar-chart-data.txt>");
-        System.out.println("    bar-chart-data.txt          the model to set. First line is chart title, " +
-                "then go pairs {axis-label value}");
-    }
-
-    public static void main(String[] args) throws Exception {
-        if(args.length < 1) {
-            usage();
-            return;
-        }
-
-        try (BufferedReader modelReader = new BufferedReader(new FileReader(args[0]))) {
-
-            String chartTitle = modelReader.readLine();  // first line is chart title
-            String[] series = modelReader.readLine().split(",");
-
-            // Category Axis Data
-            List<String> listLanguages = new ArrayList<>(10);
-
-            // Values
-            List<Double> listCountries = new ArrayList<>(10);
-            List<Double> listSpeakers = new ArrayList<>(10);
-
-            // set model
-            String ln;
-            while((ln = modelReader.readLine()) != null) {
-                String[] vals = ln.split(",");
-                listCountries.add(Double.valueOf(vals[0]));
-                listSpeakers.add(Double.valueOf(vals[1]));
-                listLanguages.add(vals[2]);
-            }
-
-            String[] categories = listLanguages.toArray(new String[0]);
-            Double[] values1 = listCountries.toArray(new Double[0]);
-            Double[] values2 = listSpeakers.toArray(new Double[0]);
-
-            try (XWPFDocument doc = new XWPFDocument();
-                 OutputStream out = new FileOutputStream("chart-from-scratch.docx")) {
-                XWPFChart chart = doc.createChart(XDDFChart.DEFAULT_WIDTH * 10, XDDFChart.DEFAULT_HEIGHT * 15);
-                setBarData(chart, chartTitle, series, categories, values1, values2);
-                // save the result
-                doc.write(out);
-            }
-        }
-        System.out.println("Done");
-    }
-
-    private static void setBarData(XWPFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
-        // Use a category axis for the bottom axis.
-        XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
-        bottomAxis.setTitle(series[2]);
-        XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
-        leftAxis.setTitle(series[0]+","+series[1]);
-        leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
-        leftAxis.setMajorTickMark(AxisTickMark.OUT);
-        leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
-
-        final int numOfPoints = categories.length;
-        final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_LANGUAGES, COLUMN_LANGUAGES));
-        final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_COUNTRIES, COLUMN_COUNTRIES));
-        final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_SPEAKERS, COLUMN_SPEAKERS));
-        final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, COLUMN_LANGUAGES);
-        final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, COLUMN_COUNTRIES);
-        valuesData.setFormatCode("General");
-        values1[6] = 16.0; // if you ever want to change the underlying data, it has to be done before building the data source
-        final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, COLUMN_SPEAKERS);
-        valuesData2.setFormatCode("General");
-
-
-        XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
-        bar.setBarGrouping(BarGrouping.CLUSTERED);
-
-        XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData);
-        series1.setTitle(series[0], chart.setSheetTitle(series[0], COLUMN_COUNTRIES));
-
-        XDDFBarChartData.Series series2 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData2);
-        series2.setTitle(series[1], chart.setSheetTitle(series[1], COLUMN_SPEAKERS));
-
-        bar.setVaryColors(true);
-        bar.setBarDirection(BarDirection.COL);
-        chart.plot(bar);
-
-        XDDFChartLegend legend = chart.getOrAddLegend();
-        legend.setPosition(LegendPosition.LEFT);
-        legend.setOverlay(false);
-
-        chart.setTitleText(chartTitle);
-        chart.setTitleOverlay(false);
-        chart.setAutoTitleDeleted(false);
-    }
-
-    private static final int COLUMN_LANGUAGES = 0;
-    private static final int COLUMN_COUNTRIES = 1;
-    private static final int COLUMN_SPEAKERS = 2;
-}
-
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/HeaderFooterTable.java b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/HeaderFooterTable.java
deleted file mode 100644 (file)
index bc40c4d..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xwpf.usermodel.examples;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.math.BigInteger;
-
-import org.apache.poi.wp.usermodel.HeaderFooterType;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.poi.xwpf.usermodel.XWPFFooter;
-import org.apache.poi.xwpf.usermodel.XWPFHeader;
-import org.apache.poi.xwpf.usermodel.XWPFParagraph;
-import org.apache.poi.xwpf.usermodel.XWPFRun;
-import org.apache.poi.xwpf.usermodel.XWPFTable;
-import org.apache.poi.xwpf.usermodel.XWPFTableCell;
-import org.apache.poi.xwpf.usermodel.XWPFTableRow;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGridCol;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblLayoutType;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblLayoutType;
-
-public class HeaderFooterTable {
-
-    public static void main(String[] args) throws IOException {
-        try (XWPFDocument doc = new XWPFDocument()) {
-
-            // Create a header with a 1 row, 3 column table
-            // changes made for issue 57366 allow a new header or footer
-            // to be created empty. This is a change. You will have to add
-            // either a paragraph or a table to the header or footer for
-            // the document to be considered valid.
-            XWPFHeader hdr = doc.createHeader(HeaderFooterType.DEFAULT);
-            XWPFTable tbl = hdr.createTable(1, 3);
-
-            // Set the padding around text in the cells to 1/10th of an inch
-            int pad = (int) (.1 * 1440);
-            tbl.setCellMargins(pad, pad, pad, pad);
-
-            // Set table width to 6.5 inches in 1440ths of a point
-            tbl.setWidth((int) (6.5 * 1440));
-            // Can not yet set table or cell width properly, tables default to
-            // autofit layout, and this requires fixed layout
-            CTTbl ctTbl = tbl.getCTTbl();
-            CTTblPr ctTblPr = ctTbl.addNewTblPr();
-            CTTblLayoutType layoutType = ctTblPr.addNewTblLayout();
-            layoutType.setType(STTblLayoutType.FIXED);
-
-            // Now set up a grid for the table, cells will fit into the grid
-            // Each cell width is 3120 in 1440ths of an inch, or 1/3rd of 6.5"
-            BigInteger w = BigInteger.valueOf(3120);
-            CTTblGrid grid = ctTbl.addNewTblGrid();
-            for (int i = 0; i < 3; i++) {
-                CTTblGridCol gridCol = grid.addNewGridCol();
-                gridCol.setW(w);
-            }
-
-            // Add paragraphs to the cells
-            XWPFTableRow row = tbl.getRow(0);
-            XWPFTableCell cell = row.getCell(0);
-            XWPFParagraph p = cell.getParagraphArray(0);
-            XWPFRun r = p.createRun();
-            r.setText("header left cell");
-
-            cell = row.getCell(1);
-            p = cell.getParagraphArray(0);
-            r = p.createRun();
-            r.setText("header center cell");
-
-            cell = row.getCell(2);
-            p = cell.getParagraphArray(0);
-            r = p.createRun();
-            r.setText("header right cell");
-
-            // Create a footer with a Paragraph
-            XWPFFooter ftr = doc.createFooter(HeaderFooterType.DEFAULT);
-            p = ftr.createParagraph();
-
-            r = p.createRun();
-            r.setText("footer text");
-
-            try (OutputStream os = new FileOutputStream(new File("headertable.docx"))) {
-                doc.write(os);
-            }
-        }
-       }
-}
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleDocument.java b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleDocument.java
deleted file mode 100644 (file)
index 2699015..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xwpf.usermodel.examples;
-
-import java.io.FileOutputStream;
-
-import org.apache.poi.xwpf.usermodel.Borders;
-import org.apache.poi.xwpf.usermodel.BreakClear;
-import org.apache.poi.xwpf.usermodel.BreakType;
-import org.apache.poi.xwpf.usermodel.LineSpacingRule;
-import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
-import org.apache.poi.xwpf.usermodel.TextAlignment;
-import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
-import org.apache.poi.xwpf.usermodel.VerticalAlign;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.poi.xwpf.usermodel.XWPFHyperlinkRun;
-import org.apache.poi.xwpf.usermodel.XWPFParagraph;
-import org.apache.poi.xwpf.usermodel.XWPFRun;
-
-/**
- * A simple WOrdprocessingML document created by POI XWPF API
- */
-public class SimpleDocument {
-
-    public static void main(String[] args) throws Exception {
-        try (XWPFDocument doc = new XWPFDocument()) {
-
-            XWPFParagraph p1 = doc.createParagraph();
-            p1.setAlignment(ParagraphAlignment.CENTER);
-            p1.setBorderBottom(Borders.DOUBLE);
-            p1.setBorderTop(Borders.DOUBLE);
-
-            p1.setBorderRight(Borders.DOUBLE);
-            p1.setBorderLeft(Borders.DOUBLE);
-            p1.setBorderBetween(Borders.SINGLE);
-
-            p1.setVerticalAlignment(TextAlignment.TOP);
-
-            XWPFRun r1 = p1.createRun();
-            r1.setBold(true);
-            r1.setText("The quick brown fox");
-            r1.setBold(true);
-            r1.setFontFamily("Courier");
-            r1.setUnderline(UnderlinePatterns.DOT_DOT_DASH);
-            r1.setTextPosition(100);
-
-            XWPFParagraph p2 = doc.createParagraph();
-            p2.setAlignment(ParagraphAlignment.RIGHT);
-
-            //BORDERS
-            p2.setBorderBottom(Borders.DOUBLE);
-            p2.setBorderTop(Borders.DOUBLE);
-            p2.setBorderRight(Borders.DOUBLE);
-            p2.setBorderLeft(Borders.DOUBLE);
-            p2.setBorderBetween(Borders.SINGLE);
-
-            XWPFRun r2 = p2.createRun();
-            r2.setText("jumped over the lazy dog");
-            r2.setStrikeThrough(true);
-            r2.setFontSize(20);
-
-            XWPFRun r3 = p2.createRun();
-            r3.setText("and went away");
-            r3.setStrikeThrough(true);
-            r3.setFontSize(20);
-            r3.setSubscript(VerticalAlign.SUPERSCRIPT);
-
-            // hyperlink
-            XWPFHyperlinkRun hyperlink = p2.insertNewHyperlinkRun(0, "http://poi.apache.org/");
-            hyperlink.setUnderline(UnderlinePatterns.SINGLE);
-            hyperlink.setColor("0000ff");
-            hyperlink.setText("Apache POI");
-
-            XWPFParagraph p3 = doc.createParagraph();
-            p3.setWordWrapped(true);
-            p3.setPageBreak(true);
-
-            //p3.setAlignment(ParagraphAlignment.DISTRIBUTE);
-            p3.setAlignment(ParagraphAlignment.BOTH);
-            p3.setSpacingBetween(15, LineSpacingRule.EXACT);
-
-            p3.setIndentationFirstLine(600);
-
-
-            XWPFRun r4 = p3.createRun();
-            r4.setTextPosition(20);
-            r4.setText("To be, or not to be: that is the question: "
-                    + "Whether 'tis nobler in the mind to suffer "
-                    + "The slings and arrows of outrageous fortune, "
-                    + "Or to take arms against a sea of troubles, "
-                    + "And by opposing end them? To die: to sleep; ");
-            r4.addBreak(BreakType.PAGE);
-            r4.setText("No more; and by a sleep to say we end "
-                    + "The heart-ache and the thousand natural shocks "
-                    + "That flesh is heir to, 'tis a consummation "
-                    + "Devoutly to be wish'd. To die, to sleep; "
-                    + "To sleep: perchance to dream: ay, there's the rub; "
-                    + ".......");
-            r4.setItalic(true);
-//This would imply that this break shall be treated as a simple line break, and break the line after that word:
-
-            XWPFRun r5 = p3.createRun();
-            r5.setTextPosition(-10);
-            r5.setText("For in that sleep of death what dreams may come");
-            r5.addCarriageReturn();
-            r5.setText("When we have shuffled off this mortal coil, "
-                    + "Must give us pause: there's the respect "
-                    + "That makes calamity of so long life;");
-            r5.addBreak();
-            r5.setText("For who would bear the whips and scorns of time, "
-                    + "The oppressor's wrong, the proud man's contumely,");
-
-            r5.addBreak(BreakClear.ALL);
-            r5.setText("The pangs of despised love, the law's delay, "
-                    + "The insolence of office and the spurns " + ".......");
-
-            try (FileOutputStream out = new FileOutputStream("simple.docx")) {
-                doc.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleDocumentWithHeader.java b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleDocumentWithHeader.java
deleted file mode 100644 (file)
index 7927e91..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xwpf.usermodel.examples;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.poi.xwpf.usermodel.XWPFParagraph;
-import org.apache.poi.xwpf.usermodel.XWPFRun;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
-
-/**
- * 
- * @author Richard Ngo
- *
- */
-public class SimpleDocumentWithHeader {
-
-       public static void main(String[] args) throws IOException {
-               try (XWPFDocument doc = new XWPFDocument()) {
-
-                       XWPFParagraph p = doc.createParagraph();
-
-                       XWPFRun r = p.createRun();
-                       r.setText("Some Text");
-                       r.setBold(true);
-                       r = p.createRun();
-                       r.setText("Goodbye");
-
-                       CTP ctP = CTP.Factory.newInstance();
-                       CTText t = ctP.addNewR().addNewT();
-                       t.setStringValue("header");
-                       XWPFParagraph[] pars = new XWPFParagraph[1];
-                       p = new XWPFParagraph(ctP, doc);
-                       pars[0] = p;
-
-                       XWPFHeaderFooterPolicy hfPolicy = doc.createHeaderFooterPolicy();
-                       hfPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT, pars);
-
-                       ctP = CTP.Factory.newInstance();
-                       t = ctP.addNewR().addNewT();
-                       t.setStringValue("My Footer");
-                       pars[0] = new XWPFParagraph(ctP, doc);
-                       hfPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT, pars);
-
-                       try (OutputStream os = new FileOutputStream(new File("header.docx"))) {
-                               doc.write(os);
-                       }
-               }
-       }
-}
\ No newline at end of file
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleImages.java b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleImages.java
deleted file mode 100644 (file)
index 9e37995..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-package org.apache.poi.xwpf.usermodel.examples;
-
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.util.Units;
-import org.apache.poi.xwpf.usermodel.BreakType;
-import org.apache.poi.xwpf.usermodel.Document;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.poi.xwpf.usermodel.XWPFParagraph;
-import org.apache.poi.xwpf.usermodel.XWPFRun;
-
-/**
- * Demonstrates how to add pictures in a .docx document
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public final class SimpleImages {
-
-    private SimpleImages() {}
-
-    public static void main(String[] args) throws IOException, InvalidFormatException {
-        try (XWPFDocument doc = new XWPFDocument()) {
-            XWPFParagraph p = doc.createParagraph();
-
-            XWPFRun r = p.createRun();
-
-            for (String imgFile : args) {
-                int format;
-
-                if (imgFile.endsWith(".emf")) {
-                    format = Document.PICTURE_TYPE_EMF;
-                } else if (imgFile.endsWith(".wmf")) {
-                    format = Document.PICTURE_TYPE_WMF;
-                } else if (imgFile.endsWith(".pict")) {
-                    format = Document.PICTURE_TYPE_PICT;
-                } else if (imgFile.endsWith(".jpeg") || imgFile.endsWith(".jpg")) {
-                    format = Document.PICTURE_TYPE_JPEG;
-                } else if (imgFile.endsWith(".png")) {
-                    format = Document.PICTURE_TYPE_PNG;
-                } else if (imgFile.endsWith(".dib")) {
-                    format = Document.PICTURE_TYPE_DIB;
-                } else if (imgFile.endsWith(".gif")) {
-                    format = Document.PICTURE_TYPE_GIF;
-                } else if (imgFile.endsWith(".tiff")) {
-                    format = Document.PICTURE_TYPE_TIFF;
-                } else if (imgFile.endsWith(".eps")) {
-                    format = Document.PICTURE_TYPE_EPS;
-                } else if (imgFile.endsWith(".bmp")) {
-                    format = Document.PICTURE_TYPE_BMP;
-                } else if (imgFile.endsWith(".wpg")) {
-                    format = Document.PICTURE_TYPE_WPG;
-                } else {
-                    System.err.println("Unsupported picture: " + imgFile +
-                            ". Expected emf|wmf|pict|jpeg|png|dib|gif|tiff|eps|bmp|wpg");
-                    continue;
-                }
-
-                r.setText(imgFile);
-                r.addBreak();
-                try (FileInputStream is = new FileInputStream(imgFile)) {
-                    r.addPicture(is, format, imgFile, Units.toEMU(200), Units.toEMU(200)); // 200x200 pixels
-                }
-                r.addBreak(BreakType.PAGE);
-            }
-
-            try (FileOutputStream out = new FileOutputStream("images.docx")) {
-                doc.write(out);
-            }
-        }
-    }
-
-
-}
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleTable.java b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleTable.java
deleted file mode 100644 (file)
index b09e00b..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.xwpf.usermodel.examples;
-
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.math.BigInteger;
-import java.util.List;
-
-import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
-import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.poi.xwpf.usermodel.XWPFParagraph;
-import org.apache.poi.xwpf.usermodel.XWPFRun;
-import org.apache.poi.xwpf.usermodel.XWPFTable;
-import org.apache.poi.xwpf.usermodel.XWPFTableCell;
-import org.apache.poi.xwpf.usermodel.XWPFTableRow;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHeight;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShd;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTrPr;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVerticalJc;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.STShd;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
-
-/**
- * This program creates a simple WordprocessingML table using POI XWPF API, and
- * a more complex, styled table using both XWPF and ooxml-schema. It's possible
- * that not all referenced wordprocessingml classes are defined in
- * poi-ooxml-schemas-3.8-beta4. If this is the case, you'll need to use the full
- * ooxml-schemas.jar library.
- *
- * @author gisella bronzetti (original)
- * @author Gregg Morris (styled table)
- */
-public class SimpleTable {
-
-    public static void main(String[] args) throws Exception {
-       try {
-               createSimpleTable();
-       }
-       catch(Exception e) {
-               System.out.println("Error trying to create simple table.");
-               throw(e);
-       }
-       try {
-               createStyledTable();
-       }
-       catch(Exception e) {
-               System.out.println("Error trying to create styled table.");
-               throw(e);
-       }
-    }
-
-    public static void createSimpleTable() throws Exception {
-        try (XWPFDocument doc = new XWPFDocument()) {
-            XWPFTable table = doc.createTable(3, 3);
-
-            table.getRow(1).getCell(1).setText("EXAMPLE OF TABLE");
-
-            // table cells have a list of paragraphs; there is an initial
-            // paragraph created when the cell is created. If you create a
-            // paragraph in the document to put in the cell, it will also
-            // appear in the document following the table, which is probably
-            // not the desired result.
-            XWPFParagraph p1 = table.getRow(0).getCell(0).getParagraphs().get(0);
-
-            XWPFRun r1 = p1.createRun();
-            r1.setBold(true);
-            r1.setText("The quick brown fox");
-            r1.setItalic(true);
-            r1.setFontFamily("Courier");
-            r1.setUnderline(UnderlinePatterns.DOT_DOT_DASH);
-            r1.setTextPosition(100);
-
-            table.getRow(2).getCell(2).setText("only text");
-
-            try (OutputStream out = new FileOutputStream("simpleTable.docx")) {
-                doc.write(out);
-            }
-        }
-    }
-
-    /**
-     * Create a table with some row and column styling. I "manually" add the
-     * style name to the table, but don't check to see if the style actually
-     * exists in the document. Since I'm creating it from scratch, it obviously
-     * won't exist. When opened in MS Word, the table style becomes "Normal".
-     * I manually set alternating row colors. This could be done using Themes,
-     * but that's left as an exercise for the reader. The cells in the last
-     * column of the table have 10pt. "Courier" font.
-     * I make no claims that this is the "right" way to do it, but it worked
-     * for me. Given the scarcity of XWPF examples, I thought this may prove
-     * instructive and give you ideas for your own solutions.
-     */
-    public static void createStyledTable() throws Exception {
-       // Create a new document from scratch
-
-        try (XWPFDocument doc = new XWPFDocument()) {
-            // -- OR --
-            // open an existing empty document with styles already defined
-            //XWPFDocument doc = new XWPFDocument(new FileInputStream("base_document.docx"));
-
-            // Create a new table with 6 rows and 3 columns
-            int nRows = 6;
-            int nCols = 3;
-            XWPFTable table = doc.createTable(nRows, nCols);
-
-            // Set the table style. If the style is not defined, the table style
-            // will become "Normal".
-            CTTblPr tblPr = table.getCTTbl().getTblPr();
-            CTString styleStr = tblPr.addNewTblStyle();
-            styleStr.setVal("StyledTable");
-
-            // Get a list of the rows in the table
-            List<XWPFTableRow> rows = table.getRows();
-            int rowCt = 0;
-            int colCt = 0;
-            for (XWPFTableRow row : rows) {
-                // get table row properties (trPr)
-                CTTrPr trPr = row.getCtRow().addNewTrPr();
-                // set row height; units = twentieth of a point, 360 = 0.25"
-                CTHeight ht = trPr.addNewTrHeight();
-                ht.setVal(BigInteger.valueOf(360));
-
-                // get the cells in this row
-                List<XWPFTableCell> cells = row.getTableCells();
-                // add content to each cell
-                for (XWPFTableCell cell : cells) {
-                    // get a table cell properties element (tcPr)
-                    CTTcPr tcpr = cell.getCTTc().addNewTcPr();
-                    // set vertical alignment to "center"
-                    CTVerticalJc va = tcpr.addNewVAlign();
-                    va.setVal(STVerticalJc.CENTER);
-
-                    // create cell color element
-                    CTShd ctshd = tcpr.addNewShd();
-                    ctshd.setColor("auto");
-                    ctshd.setVal(STShd.CLEAR);
-                    if (rowCt == 0) {
-                        // header row
-                        ctshd.setFill("A7BFDE");
-                    } else if (rowCt % 2 == 0) {
-                        // even row
-                        ctshd.setFill("D3DFEE");
-                    } else {
-                        // odd row
-                        ctshd.setFill("EDF2F8");
-                    }
-
-                    // get 1st paragraph in cell's paragraph list
-                    XWPFParagraph para = cell.getParagraphs().get(0);
-                    // create a run to contain the content
-                    XWPFRun rh = para.createRun();
-                    // style cell as desired
-                    if (colCt == nCols - 1) {
-                        // last column is 10pt Courier
-                        rh.setFontSize(10);
-                        rh.setFontFamily("Courier");
-                    }
-                    if (rowCt == 0) {
-                        // header row
-                        rh.setText("header row, col " + colCt);
-                        rh.setBold(true);
-                        para.setAlignment(ParagraphAlignment.CENTER);
-                    } else {
-                        // other rows
-                        rh.setText("row " + rowCt + ", col " + colCt);
-                        para.setAlignment(ParagraphAlignment.LEFT);
-                    }
-                    colCt++;
-                } // for cell
-                colCt = 0;
-                rowCt++;
-            } // for row
-
-            // write the file
-            try (OutputStream out = new FileOutputStream("styledTable.docx")) {
-                doc.write(out);
-            }
-        }
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/UpdateEmbeddedDoc.java b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/UpdateEmbeddedDoc.java
deleted file mode 100644 (file)
index af0eefd..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.xwpf.usermodel.examples;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.List;
-
-import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
-import org.apache.poi.openxml4j.opc.PackagePart;
-import org.apache.poi.ss.usermodel.Cell;
-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.WorkbookFactory;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-
-/**
- * Tests whether it is possible to successfully update an Excel workbook that is
- * embedded into a WordprocessingML document. Note that the test has currently
- * only been conducted with a binary Excel workbook and NOT yet with a
- * SpreadsheetML workbook embedded into the document.<p>
- *
- * This code was successfully tested with the following file from the POI test collection:
- * http://svn.apache.org/repos/asf/poi/trunk/test-data/document/EmbeddedDocument.docx
- */
-@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
-public class UpdateEmbeddedDoc {
-
-    private XWPFDocument doc;
-    private File docFile;
-
-    private static final int SHEET_NUM = 0;
-    private static final int ROW_NUM = 0;
-    private static final int CELL_NUM = 0;
-    private static final double NEW_VALUE = 100.98D;
-    private static final String BINARY_EXTENSION = "xls";
-    private static final String OPENXML_EXTENSION = "xlsx";
-
-    /**
-     * Create a new instance of the UpdateEmbeddedDoc class using the following
-     * parameters;
-     *
-     * @param filename An instance of the String class that encapsulates the name
-     *                 of and path to a WordprocessingML Word document that contains an
-     *                 embedded binary Excel workbook.
-     * @throws java.io.FileNotFoundException Thrown if the file cannot be found
-     *                                       on the underlying file system.
-     * @throws java.io.IOException           Thrown if a problem occurs in the underlying
-     *                                       file system.
-     */
-    public UpdateEmbeddedDoc(String filename) throws FileNotFoundException, IOException {
-        this.docFile = new File(filename);
-        if (!this.docFile.exists()) {
-            throw new FileNotFoundException("The Word document " + filename + " does not exist.");
-        }
-        try (FileInputStream fis = new FileInputStream(this.docFile)) {
-            // Open the Word document file and instantiate the XWPFDocument class.
-            this.doc = new XWPFDocument(fis);
-        }
-    }
-
-    /**
-     * Called to update the embedded Excel workbook. As the format and structure
-     * of the workbook are known in advance, all this code attempts to do is
-     * write a new value into the first cell on the first row of the first
-     * worksheet. Prior to executing this method, that cell will contain the
-     * value 1.
-     *
-     * @throws org.apache.poi.openxml4j.exceptions.OpenXML4JException
-     *                             Rather
-     *                             than use the specific classes (HSSF/XSSF) to handle the embedded
-     *                             workbook this method uses those defined in the SS stream. As
-     *                             a result, it might be the case that a SpreadsheetML file is
-     *                             opened for processing, throwing this exception if that file is
-     *                             invalid.
-     * @throws java.io.IOException Thrown if a problem occurs in the underlying
-     *                             file system.
-     */
-    public void updateEmbeddedDoc() throws OpenXML4JException, IOException {
-        List<PackagePart> embeddedDocs = this.doc.getAllEmbeddedParts();
-        for (PackagePart pPart : embeddedDocs) {
-            String ext = pPart.getPartName().getExtension();
-            if (BINARY_EXTENSION.equals(ext) || OPENXML_EXTENSION.equals(ext)) {
-                // Get an InputStream from the package part and pass that
-                // to the create method of the WorkbookFactory class. Update
-                // the resulting Workbook and then stream that out again
-                // using an OutputStream obtained from the same PackagePart.
-                try (InputStream is = pPart.getInputStream();
-                     Workbook workbook = WorkbookFactory.create(is);
-                     OutputStream os = pPart.getOutputStream()) {
-                    Sheet sheet = workbook.getSheetAt(SHEET_NUM);
-                    Row row = sheet.getRow(ROW_NUM);
-                    Cell cell = row.getCell(CELL_NUM);
-                    cell.setCellValue(NEW_VALUE);
-                    workbook.write(os);
-                }
-            }
-        }
-
-        if (!embeddedDocs.isEmpty()) {
-            // Finally, write the newly modified Word document out to file.
-            try (FileOutputStream fos = new FileOutputStream(this.docFile)) {
-                this.doc.write(fos);
-            }
-        }
-    }
-
-    /**
-     * Called to test whether or not the embedded workbook was correctly
-     * updated. This method simply recovers the first cell from the first row
-     * of the first workbook and tests the value it contains.
-     * <p>
-     * Note that execution will not continue up to the assertion as the
-     * embedded workbook is now corrupted and causes an IllegalArgumentException
-     * with the following message
-     * <p>
-     * <em>java.lang.IllegalArgumentException: Your InputStream was neither an
-     * OLE2 stream, nor an OOXML stream</em>
-     * <p>
-     * to be thrown when the WorkbookFactory.createWorkbook(InputStream) method
-     * is executed.
-     *
-     * @throws org.apache.poi.openxml4j.exceptions.OpenXML4JException
-     *                             Rather
-     *                             than use the specific classes (HSSF/XSSF) to handle the embedded
-     *                             workbook this method uses those defined in the SS stream. As
-     *                             a result, it might be the case that a SpreadsheetML file is
-     *                             opened for processing, throwing this exception if that file is
-     *                             invalid.
-     * @throws java.io.IOException Thrown if a problem occurs in the underlying
-     *                             file system.
-     */
-    public void checkUpdatedDoc() throws OpenXML4JException, IOException {
-        for (PackagePart pPart : this.doc.getAllEmbeddedParts()) {
-            String ext = pPart.getPartName().getExtension();
-            if (BINARY_EXTENSION.equals(ext) || OPENXML_EXTENSION.equals(ext)) {
-                try (InputStream is = pPart.getInputStream();
-                     Workbook workbook = WorkbookFactory.create(is)) {
-                    Sheet sheet = workbook.getSheetAt(SHEET_NUM);
-                    Row row = sheet.getRow(ROW_NUM);
-                    Cell cell = row.getCell(CELL_NUM);
-                    if(cell.getNumericCellValue() != NEW_VALUE) {
-                        throw new IllegalStateException("Failed to validate document content.");
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Code to test updating of the embedded Excel workbook.
-     */
-    public static void main(String[] args) throws IOException, OpenXML4JException {
-        UpdateEmbeddedDoc ued = new UpdateEmbeddedDoc(args[0]);
-        ued.updateEmbeddedDoc();
-        ued.checkUpdatedDoc();
-    }
-}
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-data.txt b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-data.txt
deleted file mode 100644 (file)
index 22c7b86..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-10 languages with most speakers as first language\r
-countries,speakers,language\r
-58,315,العربية\r
-4,243,বাংলা\r
-38,1299,中文\r
-118,378,English\r
-4,260,हिन्दी\r
-2,128,日本語\r
-15,223,português\r
-6,119,ਪੰਜਾਬੀ\r
-18,154,Русский язык\r
-31,442,español\r
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-template.docx b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-template.docx
deleted file mode 100644 (file)
index ddd57ef..0000000
Binary files a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-template.docx and /dev/null differ
diff --git a/src/excelant/testcases/org/apache/poi/ss/examples/formula/CalculateMortgageFunction.java b/src/excelant/testcases/org/apache/poi/ss/examples/formula/CalculateMortgageFunction.java
deleted file mode 100644 (file)
index 2e2e62b..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.examples.formula;
-
-import org.apache.poi.ss.formula.OperationEvaluationContext ;
-import org.apache.poi.ss.formula.eval.ErrorEval ;
-import org.apache.poi.ss.formula.eval.EvaluationException ;
-import org.apache.poi.ss.formula.eval.NumberEval ;
-import org.apache.poi.ss.formula.eval.OperandResolver ;
-import org.apache.poi.ss.formula.eval.ValueEval ;
-import org.apache.poi.ss.formula.functions.FreeRefFunction ;
-
-/**
- * A simple user-defined function to calculate principal and interest.
- *
- * Used by {@link org.apache.poi.ss.excelant.util.TestExcelAntWorkbookUtil}.
- * 
- * @author Jon Svede ( jon [at] loquatic [dot] com )
- * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
- *
- */
-public class CalculateMortgageFunction implements FreeRefFunction {
-
-    @Override
-    public ValueEval evaluate( ValueEval[] args, OperationEvaluationContext ec ) {
-        
-        // verify that we have enough data
-        if (args.length != 3) {  
-            return ErrorEval.VALUE_INVALID;
-        }
-
-        // declare doubles for values
-        double principal, rate, years,  result;
-        try {
-            // extract values as ValueEval
-            ValueEval v1 = OperandResolver.getSingleValue( args[0], 
-                                                           ec.getRowIndex(), 
-                                                           ec.getColumnIndex() ) ;
-            ValueEval v2 = OperandResolver.getSingleValue( args[1], 
-                                                           ec.getRowIndex(), 
-                                                           ec.getColumnIndex() ) ;
-            ValueEval v3 = OperandResolver.getSingleValue( args[2], 
-                                                           ec.getRowIndex(), 
-                                                           ec.getColumnIndex() ) ;
-
-            // get data as doubles
-            principal  = OperandResolver.coerceValueToDouble( v1 ) ; 
-            rate  = OperandResolver.coerceValueToDouble( v2 ) ;
-            years = OperandResolver.coerceValueToDouble( v3 ) ;
-            
-            result = calculateMortgagePayment( principal, rate, years ) ;
-            System.out.println( "Result = " + result ) ;
-
-            checkValue(result);
-            
-        } catch (EvaluationException e) {
-            return e.getErrorEval();
-        }
-
-        return new NumberEval( result ) ;
-    }
-    
-    public double calculateMortgagePayment( double p, double r, double y ) {
-        double i = r / 12 ;
-        double n = y * 12 ;
-
-        return p * (( i * Math.pow((1 + i),n ) ) / ( Math.pow((1 + i),n) - 1));
-    }
-    /**
-     * Excel does not support infinities and NaNs, rather, it gives a #NUM! error in these cases
-     *
-     * @throws EvaluationException (#NUM!) if <tt>result</tt> is <tt>NaN</> or <tt>Infinity</tt>
-     */
-     private void checkValue(double result) throws EvaluationException {
-         if (Double.isNaN(result) || Double.isInfinite(result)) {
-             throw new EvaluationException(ErrorEval.NUM_ERROR);
-         }
-     }    
-}
diff --git a/src/excelant/testcases/org/apache/poi/ss/examples/formula/ExcelAntUserDefinedFunctionTestHelper.java b/src/excelant/testcases/org/apache/poi/ss/examples/formula/ExcelAntUserDefinedFunctionTestHelper.java
deleted file mode 100644 (file)
index 68e4b69..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.examples.formula;
-
-import org.apache.poi.ss.excelant.ExcelAntUserDefinedFunction;
-
-public class ExcelAntUserDefinedFunctionTestHelper extends
-               ExcelAntUserDefinedFunction {
-
-       @Override
-       protected String getFunctionAlias() {
-               // TODO Auto-generated method stub
-               return super.getFunctionAlias();
-       }
-
-       @Override
-       protected String getClassName() {
-               // TODO Auto-generated method stub
-               return super.getClassName();
-       }
-
-}
diff --git a/src/excelant/testcases/org/apache/poi/ss/examples/formula/TestExcelAntUserDefinedFunction.java b/src/excelant/testcases/org/apache/poi/ss/examples/formula/TestExcelAntUserDefinedFunction.java
deleted file mode 100644 (file)
index 0606a8b..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.examples.formula;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class TestExcelAntUserDefinedFunction {
-
-       private ExcelAntUserDefinedFunctionTestHelper fixture ;
-
-       @Before
-       public void setUp() {
-               fixture = new ExcelAntUserDefinedFunctionTestHelper() ;
-       }
-
-       @Test
-       public void testSetClassName() {
-               String className = "simple.class.name" ;
-
-               fixture.setClassName( className ) ;
-               String value = fixture.getClassName() ;
-
-               assertNotNull( value ) ;
-               assertEquals( className, value ) ;
-       }
-
-       @Test
-       public void testSetFunction() {
-               String functionAlias = "alias" ;
-
-               fixture.setFunctionAlias( functionAlias ) ;
-
-               String alias = fixture.getFunctionAlias() ;
-
-               assertNotNull( alias ) ;
-               assertEquals( functionAlias, alias ) ;
-       }
-
-}
diff --git a/src/excelant/testcases/org/apache/poi/ss/excelant/CalculateMortgageFunction.java b/src/excelant/testcases/org/apache/poi/ss/excelant/CalculateMortgageFunction.java
new file mode 100644 (file)
index 0000000..73eb984
--- /dev/null
@@ -0,0 +1,93 @@
+/* ====================================================================
+   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.ss.excelant;
+
+import org.apache.poi.ss.formula.OperationEvaluationContext;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.EvaluationException;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.OperandResolver;
+import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
+
+/**
+ * A simple user-defined function to calculate principal and interest.
+ *
+ * Used by {@link org.apache.poi.ss.excelant.util.TestExcelAntWorkbookUtil}.
+ *
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ *
+ */
+public class CalculateMortgageFunction implements FreeRefFunction {
+
+    @Override
+    public ValueEval evaluate( ValueEval[] args, OperationEvaluationContext ec ) {
+
+        // verify that we have enough data
+        if (args.length != 3) {
+            return ErrorEval.VALUE_INVALID;
+        }
+
+        // declare doubles for values
+        double principal, rate, years,  result;
+        try {
+            // extract values as ValueEval
+            ValueEval v1 = OperandResolver.getSingleValue( args[0],
+                                                           ec.getRowIndex(),
+                                                           ec.getColumnIndex() ) ;
+            ValueEval v2 = OperandResolver.getSingleValue( args[1],
+                                                           ec.getRowIndex(),
+                                                           ec.getColumnIndex() ) ;
+            ValueEval v3 = OperandResolver.getSingleValue( args[2],
+                                                           ec.getRowIndex(),
+                                                           ec.getColumnIndex() ) ;
+
+            // get data as doubles
+            principal  = OperandResolver.coerceValueToDouble( v1 ) ;
+            rate  = OperandResolver.coerceValueToDouble( v2 ) ;
+            years = OperandResolver.coerceValueToDouble( v3 ) ;
+
+            result = calculateMortgagePayment( principal, rate, years ) ;
+            System.out.println( "Result = " + result ) ;
+
+            checkValue(result);
+
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+
+        return new NumberEval( result ) ;
+    }
+
+    public double calculateMortgagePayment( double p, double r, double y ) {
+        double i = r / 12 ;
+        double n = y * 12 ;
+
+        return p * (( i * Math.pow((1 + i),n ) ) / ( Math.pow((1 + i),n) - 1));
+    }
+    /**
+     * Excel does not support infinities and NaNs, rather, it gives a #NUM! error in these cases
+     *
+     * @throws EvaluationException (#NUM!) if <tt>result</tt> is <tt>NaN</> or <tt>Infinity</tt>
+     */
+     private void checkValue(double result) throws EvaluationException {
+         if (Double.isNaN(result) || Double.isInfinite(result)) {
+             throw new EvaluationException(ErrorEval.NUM_ERROR);
+         }
+     }
+}
diff --git a/src/excelant/testcases/org/apache/poi/ss/excelant/ExcelAntUserDefinedFunctionTestHelper.java b/src/excelant/testcases/org/apache/poi/ss/excelant/ExcelAntUserDefinedFunctionTestHelper.java
new file mode 100644 (file)
index 0000000..48086fc
--- /dev/null
@@ -0,0 +1,34 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.ss.excelant;
+
+public class ExcelAntUserDefinedFunctionTestHelper extends
+               ExcelAntUserDefinedFunction {
+
+       @Override
+       protected String getFunctionAlias() {
+               // TODO Auto-generated method stub
+               return super.getFunctionAlias();
+       }
+
+       @Override
+       protected String getClassName() {
+               // TODO Auto-generated method stub
+               return super.getClassName();
+       }
+
+}
diff --git a/src/excelant/testcases/org/apache/poi/ss/excelant/TestExcelAntUserDefinedFunction.java b/src/excelant/testcases/org/apache/poi/ss/excelant/TestExcelAntUserDefinedFunction.java
new file mode 100644 (file)
index 0000000..73b1080
--- /dev/null
@@ -0,0 +1,57 @@
+/* ====================================================================
+   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.ss.excelant;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestExcelAntUserDefinedFunction {
+
+       private ExcelAntUserDefinedFunctionTestHelper fixture ;
+
+       @Before
+       public void setUp() {
+               fixture = new ExcelAntUserDefinedFunctionTestHelper() ;
+       }
+
+       @Test
+       public void testSetClassName() {
+               String className = "simple.class.name" ;
+
+               fixture.setClassName( className ) ;
+               String value = fixture.getClassName() ;
+
+               assertNotNull( value ) ;
+               assertEquals( className, value ) ;
+       }
+
+       @Test
+       public void testSetFunction() {
+               String functionAlias = "alias" ;
+
+               fixture.setFunctionAlias( functionAlias ) ;
+
+               String alias = fixture.getFunctionAlias() ;
+
+               assertNotNull( alias ) ;
+               assertEquals( functionAlias, alias ) ;
+       }
+
+}
index d387aab365d70bd6b1aae8f879603482879d7e3f..0882195551a8a4585cca4fb4be6f9e77c21fd0cd 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!-- 
+<!--
 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
@@ -164,7 +164,7 @@ under the License.
     <target name="test-udf">
         <poi:excelant fileName="${data.dir.name}/spreadsheet/excelant.xls">
             <poi:udf functionAlias="calculatePayment"
-                     className="org.apache.poi.ss.examples.formula.CalculateMortgageFunction"/>
+                     className="org.apache.poi.ss.excelant.CalculateMortgageFunction"/>
             <poi:test>
                 <poi:setDouble cell="'MortageCalculatorFunction'!$B$1" value="240000"/>
                 <poi:setDouble cell="'MortageCalculatorFunction'!$B$2" value ="0.11"/>
index 3771405cb6282ff102b2c25a7f2e783b472369cd..b6c7df7a291b3555ddc21f72ce0370e0786c57b2 100644 (file)
@@ -29,7 +29,7 @@ import java.io.IOException;
 import java.util.Date;
 import java.util.List;
 
-import org.apache.poi.ss.examples.formula.CalculateMortgageFunction;
+import org.apache.poi.ss.excelant.CalculateMortgageFunction;
 import org.apache.poi.ss.excelant.TestBuildFile;
 import org.apache.poi.ss.formula.udf.UDFFinder;
 import org.apache.poi.ss.usermodel.DateUtil;
diff --git a/src/integrationtest/org/apache/poi/BaseIntegrationTest.java b/src/integrationtest/org/apache/poi/BaseIntegrationTest.java
deleted file mode 100644 (file)
index 10c534e..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi;
-
-import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
-import org.apache.poi.stress.FileHandler;
-import org.apache.poi.stress.HSLFFileHandler;
-import org.apache.poi.stress.HSSFFileHandler;
-import org.apache.poi.stress.HWPFFileHandler;
-import org.apache.poi.stress.XSLFFileHandler;
-import org.apache.poi.stress.XSSFFileHandler;
-import org.apache.poi.stress.XWPFFileHandler;
-import org.junit.Assume;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.zip.ZipException;
-
-import static org.junit.Assert.assertNotNull;
-
-/**
- * This class is used for mass-regression testing via a
- * separate project, this class provides functionality to
- * run integration tests on one file and handle some
- * types of files/exceptions, e.g. old file formats.
- *
- */
-public class BaseIntegrationTest {
-       private final File rootDir;
-       private String file;
-       private FileHandler handler;
-
-       public BaseIntegrationTest(File rootDir, String file, FileHandler handler) {
-               this.rootDir = rootDir;
-               this.file = file;
-               this.handler = handler;
-       }
-
-       public void test() throws Exception {
-        assertNotNull("Unknown file extension for file: " + file + ": " + TestAllFiles.getExtension(file), handler);
-               testOneFile(new File(rootDir, file));
-       }
-
-       protected void testOneFile(File inputFile) throws Exception {
-               try {
-                       handleFile(inputFile);
-               } catch (OfficeXmlFileException e) {
-                       // switch XWPF and HWPF and so forth depending on the error message
-                       handleWrongOLE2XMLExtension(inputFile, e);
-               } catch (OldFileFormatException e) {
-                       // Not even text extraction is supported for these: handler.handleExtracting(inputFile);
-                       Assume.assumeFalse("File " + file + " excluded because it is unsupported old Excel format", true);
-               } catch (EncryptedDocumentException e) {
-                       // Do not try to read encrypted files
-                       Assume.assumeFalse("File " + file + " excluded because it is password-encrypted", true);
-               } catch (ZipException e) {
-                       // some files are corrupted
-                       if (e.getMessage().equals("unexpected EOF") || e.getMessage().equals("Truncated ZIP file")) {
-                               Assume.assumeFalse("File " + file + " excluded because the Zip file is incomplete", true);
-                       }
-
-                       throw e;
-               } catch (IOException e) {
-                       // ignore some other ways of corrupted files
-                       String message = e.getMessage();
-                       if(message != null && message.contains("Truncated ZIP file")) {
-                               Assume.assumeFalse("File " + file + " excluded because the Zip file is incomplete", true);
-                       }
-
-                       // sometimes binary format has XML-format-extension...
-                       if(message != null && message.contains("rong file format or file extension for OO XML file")) {
-                               handleWrongOLE2XMLExtension(inputFile, e);
-                               return;
-                       }
-
-                       throw e;
-               } catch (IllegalArgumentException e) {
-                       // ignore errors for documents with incorrect extension
-                       String message = e.getMessage();
-                       if(message != null && (message.equals("The document is really a RTF file") ||
-                                       message.equals("The document is really a PDF file") ||
-                                       message.equals("The document is really a HTML file"))) {
-                               Assume.assumeFalse("File " + file + " excluded because it is actually a PDF/RTF/HTML file", true);
-                       }
-
-                       if(message != null && message.equals("The document is really a OOXML file")) {
-                               handleWrongOLE2XMLExtension(inputFile, e);
-                               return;
-                       }
-
-                       throw e;
-               }
-
-               try {
-                       handler.handleExtracting(inputFile);
-               } catch (EncryptedDocumentException e) {
-                       // Do not try to read encrypted files
-                       Assume.assumeFalse("File " + file + " excluded because it is password-encrypted", true);
-               }
-       }
-
-    void handleWrongOLE2XMLExtension(File inputFile, Exception e) throws Exception {
-               // we sometimes have wrong extensions, so for some exceptions we try to handle it
-               // with the correct FileHandler instead
-               String message = e.getMessage();
-
-               // ignore some file-types that we do not want to handle here
-               Assume.assumeFalse("File " + file + " excluded because it is actually a PDF/RTF/HTML file",
-                               message != null && (message.equals("The document is really a RTF file") ||
-                                       message.equals("The document is really a PDF file") ||
-                                       message.equals("The document is really a HTML file")));
-
-               if(message != null && (message.equals("The document is really a XLS file"))) {
-                       handler = TestAllFiles.HANDLERS.get(".xls");
-                       handleFile(inputFile);
-               } else if(message != null && (message.equals("The document is really a PPT file"))) {
-                       handler = TestAllFiles.HANDLERS.get(".ppt");
-                       handleFile(inputFile);
-               } else if(message != null && (message.equals("The document is really a DOC file"))) {
-                       handler = TestAllFiles.HANDLERS.get(".doc");
-                       handleFile(inputFile);
-               } else if(message != null && (message.equals("The document is really a VSD file"))) {
-                       handler = TestAllFiles.HANDLERS.get(".vsd");
-                       handleFile(inputFile);
-
-               // use XWPF instead of HWPF and XSSF instead of HSSF as the file seems to have the wrong extension
-               } else if (handler instanceof HWPFFileHandler) {
-            handler = TestAllFiles.HANDLERS.get(".docx");
-            handleFile(inputFile);
-        } else if (handler instanceof HSSFFileHandler) {
-            handler = TestAllFiles.HANDLERS.get(".xlsx");
-            handleFile(inputFile);
-        } else if (handler instanceof HSLFFileHandler) {
-                       handler = TestAllFiles.HANDLERS.get(".pptx");
-                       handleFile(inputFile);
-
-               // and the other way around, use HWPF instead of XWPF and so forth
-               } else if(handler instanceof XWPFFileHandler) {
-                       handler = TestAllFiles.HANDLERS.get(".doc");
-                       handleFile(inputFile);
-               } else if(handler instanceof XSSFFileHandler) {
-                       handler = TestAllFiles.HANDLERS.get(".xls");
-                       handleFile(inputFile);
-               } else if(handler instanceof XSLFFileHandler) {
-                       handler = TestAllFiles.HANDLERS.get(".ppt");
-                       handleFile(inputFile);
-        } else {
-                       // nothing matched => throw the exception to the outside
-            throw e;
-        }
-       }
-
-       private void handleFile(File inputFile) throws Exception {
-               try (InputStream newStream = new BufferedInputStream(new FileInputStream(inputFile), 64*1024)) {
-                       handler.handleFile(newStream, inputFile.getAbsolutePath());
-               }
-       }
-}
diff --git a/src/integrationtest/org/apache/poi/HeapDump.java b/src/integrationtest/org/apache/poi/HeapDump.java
deleted file mode 100644 (file)
index 625527d..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi;
-
-import com.sun.management.HotSpotDiagnosticMXBean;
-
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-
-public class HeapDump {
-    // This is the name of the HotSpot Diagnostic MBean
-    private static final String HOTSPOT_BEAN_NAME =
-            "com.sun.management:type=HotSpotDiagnostic";
-
-    // field to store the hotspot diagnostic MBean
-    private static volatile HotSpotDiagnosticMXBean hotspotMBean;
-
-    /**
-     * Call this method from your application whenever you
-     * want to dump the heap snapshot into a file.
-     *
-     * @param fileName name of the heap dump file
-     * @param live flag that tells whether to dump
-     *             only the live objects
-     */
-    public static void dumpHeap(String fileName, boolean live) throws IOException {
-        // initialize hotspot diagnostic MBean
-        initHotspotMBean();
-        hotspotMBean.dumpHeap(fileName, live);
-    }
-
-    // initialize the hotspot diagnostic MBean field
-    private static void initHotspotMBean() throws IOException {
-        if (hotspotMBean == null) {
-            synchronized (HeapDump.class) {
-                if (hotspotMBean == null) {
-                    hotspotMBean = getHotspotMBean();
-                }
-            }
-        }
-    }
-
-    // get the hotspot diagnostic MBean from the platform MBean server
-    private static HotSpotDiagnosticMXBean getHotspotMBean() throws IOException {
-        return ManagementFactory.newPlatformMXBeanProxy(ManagementFactory.getPlatformMBeanServer(),
-                        HOTSPOT_BEAN_NAME, HotSpotDiagnosticMXBean.class);
-    }
-}
diff --git a/src/integrationtest/org/apache/poi/POIFileScanner.java b/src/integrationtest/org/apache/poi/POIFileScanner.java
deleted file mode 100644 (file)
index 4e8c002..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hwpf.HWPFDocument;
-import org.apache.poi.poifs.filesystem.FileMagic;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
-import org.apache.poi.stress.FileHandler;
-import org.apache.poi.stress.XSSFFileHandler;
-import org.apache.poi.util.SuppressForbidden;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.tools.ant.DirectoryScanner;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.AbstractMap;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Helper class to scan a folder for files and return a collection of
- * found files together with the matching {@link FileHandler}.
- *
- * Can also be used to get the appropriate FileHandler for a single file.
- */
-public class POIFileScanner {
-    private final static File ROOT_DIR;
-    static {
-        // when running in Gradle, current directory might be "build/integrationtest"
-        if(new File("../../test-data").exists()) {
-            ROOT_DIR = new File("../../test-data");
-        } else {
-            ROOT_DIR = new File("test-data");
-        }
-    }
-
-    /**
-     * Scan a folder for files and return a collection of
-     * found files together with the matching {@link FileHandler}.
-     *
-     * Note: unknown files will be assigned to {@link org.apache.poi.TestAllFiles.NullFileHandler}
-     *
-     * @param rootDir The directory to scan
-     * @return A collection with file-FileHandler pairs which can be used for running tests on that file
-     * @throws IOException If determining the file-type fails
-     */
-    public static Collection<Map.Entry<String, FileHandler>> scan(File rootDir) throws IOException {
-        DirectoryScanner scanner = new DirectoryScanner();
-        scanner.setBasedir(rootDir);
-
-        scanner.setExcludes(TestAllFiles.SCAN_EXCLUDES);
-
-        System.out.println("Scanning for files in " + rootDir);
-
-        scanner.scan();
-
-        String[] includedFiles = scanner.getIncludedFiles();
-        System.out.println("Handling " + includedFiles.length + " files");
-
-        List<Map.Entry<String, FileHandler>> files = new ArrayList<>();
-        for(String file : includedFiles) {
-            // breaks files with slash in their name on Linux:
-            // file = file.replace('\\', '/'); // ... failures/handlers lookup doesn't work on windows otherwise
-
-            FileHandler fileHandler = getFileHandler(rootDir, file);
-
-            files.add(new AbstractMap.SimpleImmutableEntry<>(file, fileHandler));
-
-            if(files.size() % 100 == 0) {
-                System.out.print(".");
-                if(files.size() % 100_000 == 0) {
-                    System.out.println(file);
-                }
-            }
-        }
-        System.out.println();
-
-        return files;
-    }
-
-    /**
-     * Get the FileHandler for a single file
-     *
-     * @param rootDir The directory where the file resides
-     * @param file The name of the file without directory
-     * @return The matching {@link FileHandler}, A {@link org.apache.poi.TestAllFiles.NullFileHandler}
-     *          is returned if no match is found
-     * @throws IOException If determining the file-type fails
-     */
-    protected static FileHandler getFileHandler(File rootDir, String file) throws IOException {
-        FileHandler fileHandler = TestAllFiles.HANDLERS.get(TestAllFiles.getExtension(file));
-        if(fileHandler == null) {
-            // we could not detect a type of file based on the extension, so we
-            // need to take a close look at the file
-            fileHandler = detectUnnamedFile(rootDir, file);
-        }
-        return fileHandler;
-    }
-
-    private static FileHandler detectUnnamedFile(File rootDir, String file) throws IOException {
-        File testFile = new File(rootDir, file);
-
-        // find out if it looks like OLE2 (HSSF, HSLF, HWPF, ...) or OOXML (XSSF, XSLF, XWPF, ...)
-        // and then determine the file type accordingly
-        FileMagic magic = FileMagic.valueOf(testFile);
-        switch (magic) {
-            case OLE2: {
-                try {
-                    try (POIFSFileSystem fs = new POIFSFileSystem(testFile, true)) {
-                        HSSFWorkbook.getWorkbookDirEntryName(fs.getRoot());
-                    }
-
-                    // we did not get an exception, so it seems this is a HSSFWorkbook
-                    return TestAllFiles.HANDLERS.get(".xls");
-                } catch (IOException | RuntimeException e) {
-                    try {
-                        try (FileInputStream istream = new FileInputStream(testFile)) {
-                            try (HWPFDocument ignored = new HWPFDocument(istream)) {
-                                // seems to be a valid document
-                                return TestAllFiles.HANDLERS.get(".doc");
-                            }
-                        }
-                    } catch (IOException | RuntimeException e2) {
-                        System.out.println("Could not open POIFSFileSystem for OLE2 file " + testFile + ": " + e + " and " + e2);
-                        return TestAllFiles.NullFileHandler.instance;
-                    }
-                }
-            }
-            case OOXML: {
-                try {
-                    try (Workbook ignored = WorkbookFactory.create(testFile, null, true)) {
-                        // seems to be a valid workbook
-                        return TestAllFiles.HANDLERS.get(".xlsx");
-                    }
-                } catch (IOException | RuntimeException e) {
-                    try {
-                        try (FileInputStream is = new FileInputStream(testFile)) {
-                            try (XWPFDocument ignored = new XWPFDocument(is)) {
-                                // seems to be a valid document
-                                return TestAllFiles.HANDLERS.get(".docx");
-                            }
-                        }
-                    } catch (IOException | RuntimeException e2) {
-                        System.out.println("Could not open POIFSFileSystem for OOXML file " + testFile + ": " + e + " and " + e2);
-                        return TestAllFiles.NullFileHandler.instance;
-                    }
-                }
-            }
-
-            // do not warn about a few detected file types
-            case RTF:
-            case PDF:
-            case HTML:
-            case XML:
-            case JPEG:
-            case GIF:
-            case TIFF:
-            case WMF:
-            case EMF:
-            case BMP:
-                return TestAllFiles.NullFileHandler.instance;
-        }
-
-        System.out.println("Did not get a handler for extension " + TestAllFiles.getExtension(file) +
-                " of file " + file + ": " + magic);
-        return TestAllFiles.NullFileHandler.instance;
-    }
-
-    @Ignore
-    @Test
-    @SuppressForbidden("Just an ignored test")
-    public void testInvalidFile() throws IOException, InterruptedException {
-        FileHandler fileHandler = POIFileScanner.getFileHandler(new File("/usbc/CommonCrawl"),
-                "www.bgs.ac.uk_downloads_directdownload.cfm_id=2362&noexcl=true&t=west_20sussex_20-_20building_20stone_20quarries");
-
-        assertEquals(XSSFFileHandler.class, fileHandler.getClass());
-
-        // to show the output from ZipFile() from commons-compress
-        // although I did not find out yet why the ZipFile is not closed here
-        System.gc();
-        Thread.sleep(1000);
-        System.gc();
-        Thread.sleep(1000);
-    }
-
-    @Test
-    public void testDetectUnnamedFile() throws IOException {
-        POIFileScanner.detectUnnamedFile(new File(ROOT_DIR, "spreadsheet"), "49156.xlsx");
-    }
-
-    @Test
-    public void test() throws IOException {
-        POIFileScanner.scan(ROOT_DIR);
-    }
-}
diff --git a/src/integrationtest/org/apache/poi/TestAllFiles.java b/src/integrationtest/org/apache/poi/TestAllFiles.java
deleted file mode 100644 (file)
index 6a54ba2..0000000
+++ /dev/null
@@ -1,501 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi;
-
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
-import org.apache.poi.poifs.crypt.Decryptor;
-import org.apache.poi.stress.AbstractFileHandler;
-import org.apache.poi.stress.FileHandler;
-import org.apache.poi.stress.HDGFFileHandler;
-import org.apache.poi.stress.HMEFFileHandler;
-import org.apache.poi.stress.HPBFFileHandler;
-import org.apache.poi.stress.HPSFFileHandler;
-import org.apache.poi.stress.HSLFFileHandler;
-import org.apache.poi.stress.HSMFFileHandler;
-import org.apache.poi.stress.HSSFFileHandler;
-import org.apache.poi.stress.HWPFFileHandler;
-import org.apache.poi.stress.OPCFileHandler;
-import org.apache.poi.stress.POIFSFileHandler;
-import org.apache.poi.stress.XDGFFileHandler;
-import org.apache.poi.stress.XSLFFileHandler;
-import org.apache.poi.stress.XSSFBFileHandler;
-import org.apache.poi.stress.XSSFFileHandler;
-import org.apache.poi.stress.XWPFFileHandler;
-import org.apache.tools.ant.DirectoryScanner;
-import org.junit.AssumptionViolatedException;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-/**
- *  This is an integration test which performs various actions on all stored test-files and tries
- *  to reveal problems which are introduced, but not covered (yet) by unit tests.
- *
- *  This test looks for any file under the test-data directory and tries to do some useful
- *  processing with it based on it's type.
- *
- *  The test is implemented as a junit {@link Parameterized} test, which leads
- *  to one test-method call for each file (currently around 950 files are handled).
- *
- *  There is a a mapping of extension to implementations of the interface
- *  {@link FileHandler} which defines how the file is loaded and which actions are
- *  tried with the file.
- *
- *  The test can be expanded by adding more actions to the FileHandlers, this automatically
- *  applies the action to any such file in our test-data repository.
- *
- *  There is also a list of files that should actually fail.
- *
- *  Note: It is also a test-failure if a file that is expected to fail now actually works,
- *  i.e. if a bug was fixed in POI itself, the file should be removed from the expected-failures
- *  here as well! This is to ensure that files that should not work really do not work, e.g.
- *  that we do not remove expected sanity checks.
- */
-@RunWith(Parameterized.class)
-public class TestAllFiles {
-    private static final File ROOT_DIR = new File("test-data");
-    private static final boolean IGNORE_SCRATCHPAD = Boolean.getBoolean("scratchpad.ignore");
-
-    public static final String[] SCAN_EXCLUDES = new String[] { "**/.svn/**", "lost+found", "**/.git/**" };
-
-    private static final Map<String,String> FILE_PASSWORD;
-
-
-    // map file extensions to the actual mappers
-    public static final Map<String, FileHandler> HANDLERS = new HashMap<>();
-
-    static {
-        // Excel
-        HANDLERS.put(".xls", new HSSFFileHandler());
-        HANDLERS.put(".xlsx", new XSSFFileHandler());
-        HANDLERS.put(".xlsm", new XSSFFileHandler());
-        HANDLERS.put(".xltx", new XSSFFileHandler());
-        HANDLERS.put(".xlsb", new XSSFBFileHandler());
-
-        // Word
-        HANDLERS.put(".doc", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HWPFFileHandler());
-        HANDLERS.put(".docx", new XWPFFileHandler());
-        HANDLERS.put(".dotx", new XWPFFileHandler());
-        HANDLERS.put(".docm", new XWPFFileHandler());
-
-        // OpenXML4J files
-        HANDLERS.put(".ooxml", new OPCFileHandler());
-        HANDLERS.put(".zip", new OPCFileHandler());
-
-        // Powerpoint
-        HANDLERS.put(".ppt", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HSLFFileHandler());
-        HANDLERS.put(".pot", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HSLFFileHandler());
-        HANDLERS.put(".pptx", new XSLFFileHandler());
-        HANDLERS.put(".pptm", new XSLFFileHandler());
-        HANDLERS.put(".ppsm", new XSLFFileHandler());
-        HANDLERS.put(".ppsx", new XSLFFileHandler());
-        HANDLERS.put(".thmx", new XSLFFileHandler());
-        HANDLERS.put(".potx", new XSLFFileHandler());
-
-        // Outlook
-        HANDLERS.put(".msg", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HSMFFileHandler());
-
-        // Publisher
-        HANDLERS.put(".pub", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HPBFFileHandler());
-
-        // Visio - binary
-        HANDLERS.put(".vsd", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HDGFFileHandler());
-
-        // Visio - ooxml
-        HANDLERS.put(".vsdm", new XDGFFileHandler());
-        HANDLERS.put(".vsdx", new XDGFFileHandler());
-        HANDLERS.put(".vssm", new XDGFFileHandler());
-        HANDLERS.put(".vssx", new XDGFFileHandler());
-        HANDLERS.put(".vstm", new XDGFFileHandler());
-        HANDLERS.put(".vstx", new XDGFFileHandler());
-
-        // Visio - not handled yet
-        HANDLERS.put(".vst", NullFileHandler.instance);
-        HANDLERS.put(".vss", NullFileHandler.instance);
-
-        // POIFS
-        HANDLERS.put(".ole2", new POIFSFileHandler());
-
-        // Microsoft Admin Template?
-        HANDLERS.put(".adm", new HPSFFileHandler());
-
-        // Microsoft TNEF
-        HANDLERS.put(".dat", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HMEFFileHandler());
-
-        // TODO: are these readable by some of the formats?
-        HANDLERS.put(".wri", NullFileHandler.instance);
-        HANDLERS.put(".shw", NullFileHandler.instance);
-        HANDLERS.put(".zvi", NullFileHandler.instance);
-        HANDLERS.put(".mpp", NullFileHandler.instance);
-        HANDLERS.put(".qwp", NullFileHandler.instance);
-        HANDLERS.put(".wps", NullFileHandler.instance);
-        HANDLERS.put(".bin", NullFileHandler.instance);
-        HANDLERS.put(".xps", NullFileHandler.instance);
-        HANDLERS.put(".sldprt", NullFileHandler.instance);
-        HANDLERS.put(".mdb", NullFileHandler.instance);
-        HANDLERS.put(".vml", NullFileHandler.instance);
-
-        // ignore some file types, images, other formats, ...
-        HANDLERS.put(".txt", NullFileHandler.instance);
-        HANDLERS.put(".pdf", NullFileHandler.instance);
-        HANDLERS.put(".rtf", NullFileHandler.instance);
-        HANDLERS.put(".gif", NullFileHandler.instance);
-        HANDLERS.put(".html", NullFileHandler.instance);
-        HANDLERS.put(".png", NullFileHandler.instance);
-        HANDLERS.put(".wmf", NullFileHandler.instance);
-        HANDLERS.put(".emf", NullFileHandler.instance);
-        HANDLERS.put(".dib", NullFileHandler.instance);
-        HANDLERS.put(".svg", NullFileHandler.instance);
-        HANDLERS.put(".pict", NullFileHandler.instance);
-        HANDLERS.put(".jpg", NullFileHandler.instance);
-        HANDLERS.put(".jpeg", NullFileHandler.instance);
-        HANDLERS.put(".tif", NullFileHandler.instance);
-        HANDLERS.put(".tiff", NullFileHandler.instance);
-        HANDLERS.put(".wav", NullFileHandler.instance);
-        HANDLERS.put(".xml", NullFileHandler.instance);
-        HANDLERS.put(".csv", NullFileHandler.instance);
-        HANDLERS.put(".ods", NullFileHandler.instance);
-        HANDLERS.put(".ttf", NullFileHandler.instance);
-        HANDLERS.put(".fntdata", NullFileHandler.instance);
-        // VBA source files
-        HANDLERS.put(".vba", NullFileHandler.instance);
-        HANDLERS.put(".bas", NullFileHandler.instance);
-        HANDLERS.put(".frm", NullFileHandler.instance);
-        HANDLERS.put(".frx", NullFileHandler.instance); //binary
-        HANDLERS.put(".cls", NullFileHandler.instance);
-
-        // map some files without extension
-        HANDLERS.put("spreadsheet/BigSSTRecord", NullFileHandler.instance);
-        HANDLERS.put("spreadsheet/BigSSTRecord2", NullFileHandler.instance);
-        HANDLERS.put("spreadsheet/BigSSTRecord2CR1", NullFileHandler.instance);
-        HANDLERS.put("spreadsheet/BigSSTRecord2CR2", NullFileHandler.instance);
-        HANDLERS.put("spreadsheet/BigSSTRecord2CR3", NullFileHandler.instance);
-        HANDLERS.put("spreadsheet/BigSSTRecord2CR4", NullFileHandler.instance);
-        HANDLERS.put("spreadsheet/BigSSTRecord2CR5", NullFileHandler.instance);
-        HANDLERS.put("spreadsheet/BigSSTRecord2CR6", NullFileHandler.instance);
-        HANDLERS.put("spreadsheet/BigSSTRecord2CR7", NullFileHandler.instance);
-        HANDLERS.put("spreadsheet/BigSSTRecordCR", NullFileHandler.instance);
-        HANDLERS.put("spreadsheet/test_properties1", NullFileHandler.instance);
-
-        // keystore files
-        HANDLERS.put(".pfx", NullFileHandler.instance);
-        HANDLERS.put(".pem", NullFileHandler.instance);
-        HANDLERS.put(".jks", NullFileHandler.instance);
-        HANDLERS.put(".pkcs12", NullFileHandler.instance);
-
-        Map<String,String> passmap = new HashMap<>();
-        passmap.put("slideshow/Password_Protected-hello.ppt", "hello");
-        passmap.put("slideshow/Password_Protected-56-hello.ppt", "hello");
-        passmap.put("slideshow/Password_Protected-np-hello.ppt", "hello");
-        passmap.put("slideshow/cryptoapi-proc2356.ppt", "crypto");
-        passmap.put("spreadsheet/xor-encryption-abc.xls", "abc");
-        passmap.put("spreadsheet/35897-type4.xls", "freedom");
-        passmap.put("spreadsheet/58616.xlsx", Decryptor.DEFAULT_PASSWORD);
-        passmap.put("spreadsheet/password.xls", "password");
-        passmap.put("spreadsheet/protected_passtika.xlsx", "tika");
-        passmap.put("document/bug53475-password-is-pass.docx", "pass");
-        passmap.put("document/bug53475-password-is-solrcell.docx", "solrcell");
-        passmap.put("document/password_password_cryptoapi.doc", "password");
-        passmap.put("document/password_tika_binaryrc4.doc", "tika");
-        passmap.put("poifs/protect.xlsx", Decryptor.DEFAULT_PASSWORD);
-        passmap.put("poifs/extenxls_pwd123.xlsx", "pwd123");
-        passmap.put("poifs/protected_agile.docx", Decryptor.DEFAULT_PASSWORD);
-        passmap.put("poifs/60320-protected.xlsx", "Test001!!");
-        passmap.put("poifs/protected_sha512.xlsx", "this is a test");
-
-        FILE_PASSWORD = Collections.unmodifiableMap(passmap);
-    }
-
-    private static Set<String> unmodifiableHashSet(String... a) {
-        return Collections.unmodifiableSet(hashSet(a));
-    }
-    private static Set<String> hashSet(String... a) {
-        return new HashSet<>(Arrays.asList(a));
-    }
-
-    // Old Word Documents where we can at least extract some text
-    private static final Set<String> OLD_FILES_HWPF = unmodifiableHashSet(
-        "document/Bug49933.doc",
-        "document/Bug51944.doc",
-        "document/Word6.doc",
-        "document/Word6_sections.doc",
-        "document/Word6_sections2.doc",
-        "document/Word95.doc",
-        "document/word95err.doc",
-        "document/Bug60936.doc",
-        "document/Bug60942.doc",
-        "document/Bug60942b.doc",
-        "document/cn.orthodox.www_divenbog_APRIL_30-APRIL.DOC",
-        "hpsf/TestMickey.doc",
-        "document/52117.doc",
-        "hpsf/TestInvertedClassID.doc",
-        "hpsf/TestBug52117.doc"
-    );
-
-    private static final Set<String> EXPECTED_FAILURES = unmodifiableHashSet(
-        // password protected files without known password
-        "spreadsheet/51832.xls",
-        "document/PasswordProtected.doc",
-
-        // TODO: fails XMLExportTest, is this ok?
-        "spreadsheet/CustomXMLMapping-singleattributenamespace.xlsx",
-        "spreadsheet/55864.xlsx",
-        "spreadsheet/57890.xlsx",
-        "spreadsheet/xxe_in_schema.xlsx",
-
-        // TODO: these fail now with some NPE/file read error because we now try to compute every value via Cell.toString()!
-        "spreadsheet/44958.xls",
-        "spreadsheet/44958_1.xls",
-        "spreadsheet/testArraysAndTables.xls",
-
-        // TODO: good to ignore?
-        "spreadsheet/sample-beta.xlsx",
-        "document/cpansearch.perl.org_src_tobyink_acme-rundoc-0.001_word-lib_hello_world.docm",
-
-        // This is actually a spreadsheet!
-        "hpsf/TestRobert_Flaherty.doc",
-
-        // some files that are broken, eg Word 95, ...
-        "spreadsheet/43493.xls",
-        "spreadsheet/46904.xls",
-        "document/Bug50955.doc",
-        "document/57843.doc",
-        "slideshow/PPT95.ppt",
-        "slideshow/pp40only.ppt",
-        "slideshow/Divino_Revelado.pptx",
-        "openxml4j/OPCCompliance_CoreProperties_DCTermsNamespaceLimitedUseFAIL.docx",
-        "openxml4j/OPCCompliance_CoreProperties_DoNotUseCompatibilityMarkupFAIL.docx",
-        "openxml4j/OPCCompliance_CoreProperties_LimitedXSITypeAttribute_NotPresentFAIL.docx",
-        "openxml4j/OPCCompliance_CoreProperties_LimitedXSITypeAttribute_PresentWithUnauthorizedValueFAIL.docx",
-        "openxml4j/OPCCompliance_CoreProperties_OnlyOneCorePropertiesPartFAIL.docx",
-        "openxml4j/OPCCompliance_CoreProperties_UnauthorizedXMLLangAttributeFAIL.docx",
-        "openxml4j/OPCCompliance_DerivedPartNameFAIL.docx",
-        "openxml4j/invalid.xlsx",
-        "openxml4j/62592.thmx",
-        "spreadsheet/54764-2.xlsx",   // see TestXSSFBugs.bug54764()
-        "spreadsheet/54764.xlsx",     // see TestXSSFBugs.bug54764()
-        "poifs/unknown_properties.msg", // POIFS properties corrupted
-        (IGNORE_SCRATCHPAD ? "" : "poifs/only-zero-byte-streams.ole2"), // No actual contents
-        "spreadsheet/poc-xmlbomb.xlsx",  // contains xml-entity-expansion
-        "spreadsheet/poc-xmlbomb-empty.xlsx",  // contains xml-entity-expansion
-        "spreadsheet/poc-shared-strings.xlsx",  // contains shared-string-entity-expansion
-        "document/61612a.docx",
-        "document/word2.doc",
-        "spreadsheet/xlsx-corrupted.xlsx",
-
-        // old Excel files, which we only support simple text extraction of
-        "spreadsheet/testEXCEL_2.xls",
-        "spreadsheet/testEXCEL_3.xls",
-        "spreadsheet/testEXCEL_4.xls",
-        "spreadsheet/testEXCEL_5.xls",
-        "spreadsheet/testEXCEL_95.xls",
-        "spreadsheet/59074.xls",
-        "spreadsheet/60284.xls",
-        "spreadsheet/64130.xls",
-
-        // OOXML Strict is not yet supported, see bug #57699
-        "spreadsheet/SampleSS.strict.xlsx",
-        "spreadsheet/SimpleStrict.xlsx",
-        "spreadsheet/sample.strict.xlsx",
-        "spreadsheet/57914.xlsx",
-
-        // files with XML entities
-        "openxml4j/ContentTypeHasEntities.ooxml",
-
-        // non-TNEF files
-        "ddf/Container.dat",
-        "ddf/47143.dat",
-
-        // sheet cloning errors
-        "spreadsheet/56450.xls",
-        // "spreadsheet/OddStyleRecord.xls",
-
-        // msg files with non-standard encodings
-        "hsmf/ASCII_CP1251_LCID1049.msg",
-        "hsmf/ASCII_UTF-8_CP1252_LCID1031.msg",
-        "hsmf/ASCII_UTF-8_CP1252_LCID1031_HTML.msg",
-        "hsmf/HTMLBodyBinary_CP1251.msg",
-        "hsmf/HTMLBodyBinary_UTF-8.msg"
-    );
-
-    private static final Set<String> IGNORED = unmodifiableHashSet(
-        // OPC handler works / XSSF handler fails
-        "spreadsheet/57181.xlsm",
-        "spreadsheet/61300.xls"//intentionally fuzzed -- used to cause infinite loop
-    );
-
-    @Parameters(name="{index}: {0} using {1}")
-    public static Iterable<Object[]> files() {
-        DirectoryScanner scanner = new DirectoryScanner();
-        scanner.setBasedir(ROOT_DIR);
-        scanner.setExcludes(SCAN_EXCLUDES);
-
-        scanner.scan();
-
-        System.out.println("Handling " + scanner.getIncludedFiles().length + " files");
-
-        List<Object[]> files = new ArrayList<>();
-        for(String file : scanner.getIncludedFiles()) {
-            file = file.replace('\\', '/'); // ... failures/handlers lookup doesn't work on windows otherwise
-            if (IGNORED.contains(file)) {
-                System.out.println("Ignoring " + file);
-                continue;
-            }
-            FileHandler handler = HANDLERS.get(getExtension(file));
-            files.add(new Object[] { file, handler });
-
-            // for some file-types also run OPCFileHandler
-            if(handler instanceof XSSFFileHandler ||
-                handler instanceof XWPFFileHandler ||
-                handler instanceof XSLFFileHandler ||
-                handler instanceof XDGFFileHandler) {
-                files.add(new Object[] { file, new OPCFileHandler() });
-            }
-
-            if (handler instanceof HSSFFileHandler ||
-                handler instanceof HSLFFileHandler ||
-                handler instanceof HWPFFileHandler ||
-                handler instanceof HDGFFileHandler) {
-                files.add(new Object[] { file, new HPSFFileHandler() });
-            }
-        }
-
-        return files;
-    }
-
-    @SuppressWarnings("DefaultAnnotationParam")
-    @Parameter(value=0)
-    public String file;
-
-    @Parameter(value=1)
-    public FileHandler handler;
-
-    @Before
-    public void setPassword() {
-        // this also removes the password for non encrypted files
-        String pass = TestAllFiles.FILE_PASSWORD.get(file);
-        Biff8EncryptionKey.setCurrentUserPassword(pass);
-    }
-
-    @Test
-    public void testAllFiles() throws Exception {
-        if(handler == null) {
-            fail("Did not find a handler for file " + file);
-        }
-
-        System.out.println("Reading " + file + " with " + handler.getClass().getSimpleName());
-        assertNotNull("Unknown file extension for file: " + file + ": " + getExtension(file), handler);
-        File inputFile = new File(ROOT_DIR, file);
-
-        // special cases where docx-handling breaks, but OPCPackage handling works
-        boolean ignoredOPC = (file.endsWith(".docx") || file.endsWith(".xlsx") ||
-                    file.endsWith(".xlsb") || file.endsWith(".pptx")) &&
-                handler instanceof OPCFileHandler;
-        boolean ignoreHPSF = (handler instanceof HPSFFileHandler);
-
-        try {
-            try (InputStream stream = new BufferedInputStream(new FileInputStream(inputFile), 64 * 1024)) {
-                handler.handleFile(stream, file);
-                assertFalse("Expected to fail for file " + file + " and handler " + handler + ", but did not fail!",
-                        OLD_FILES_HWPF.contains(file) && !ignoreHPSF);
-            }
-
-            handler.handleExtracting(inputFile);
-
-            assertFalse("Expected to fail for file " + file + " and handler " + handler + ", but did not fail!",
-                EXPECTED_FAILURES.contains(file) && !ignoredOPC && !ignoreHPSF);
-        } catch (OldFileFormatException e) {
-            // for old word files we should still support extracting text
-            if(OLD_FILES_HWPF.contains(file)) {
-                handler.handleExtracting(inputFile);
-            } else {
-                // check if we expect failure for this file
-                if(!EXPECTED_FAILURES.contains(file) && !AbstractFileHandler.EXPECTED_EXTRACTOR_FAILURES.contains(file)) {
-                    System.out.println("Failed: " + file);
-                    throw new Exception("While handling " + file, e);
-                }
-            }
-        } catch (AssumptionViolatedException e) {
-            // file handler ignored this file
-        } catch (Exception e) {
-            // check if we expect failure for this file
-            if(!EXPECTED_FAILURES.contains(file) && !AbstractFileHandler.EXPECTED_EXTRACTOR_FAILURES.contains(file)) {
-                System.out.println("Failed: " + file);
-                throw new Exception("While handling " + file, e);
-            }
-        }
-
-        try {
-            // let some file handlers do additional stuff
-            handler.handleAdditional(inputFile);
-        } catch (AssumptionViolatedException e) {
-            // file handler ignored this file
-        } catch (Exception e) {
-            if(!EXPECTED_FAILURES.contains(file) && !AbstractFileHandler.EXPECTED_EXTRACTOR_FAILURES.contains(file)) {
-                System.out.println("Failed: " + file);
-                throw new Exception("While handling " + file, e);
-            }
-        }
-    }
-
-    public static String getExtension(String file) {
-        int pos = file.lastIndexOf('.');
-        if(pos == -1 || pos == file.length()-1) {
-            return file;
-        }
-
-        return file.substring(pos).toLowerCase(Locale.ROOT);
-    }
-
-    public static class NullFileHandler implements FileHandler {
-        public static final FileHandler instance = new NullFileHandler();
-
-        @Override
-        public void handleFile(InputStream stream, String path) {
-        }
-
-        @Override
-        public void handleExtracting(File file) {
-        }
-
-        @Override
-        public void handleAdditional(File file) {
-        }
-    }
-}
diff --git a/src/integrationtest/org/apache/poi/hssf/usermodel/RecordsStresser.java b/src/integrationtest/org/apache/poi/hssf/usermodel/RecordsStresser.java
deleted file mode 100644 (file)
index d277d40..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.hssf.usermodel;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.List;
-
-import org.apache.poi.hssf.record.Record;
-import org.junit.Test;
-
-/**
- * Needs to be implemented in this package to have access to
- * HSSFWorkbook.getWorkbook()
- */
-public class RecordsStresser {
-    public static void handleWorkbook(HSSFWorkbook wb) {
-        List<org.apache.poi.hssf.record.Record> records = wb.getWorkbook().getRecords();
-        for(org.apache.poi.hssf.record.Record record : records) {
-            // some Records do not implement clone ?!
-            // equals instead of instanceof is on purpose here to only skip exactly this class and not any derived ones
-//            if(record.getClass().equals(InterfaceHdrRecord.class) ||
-//                    record.getClass().equals(MMSRecord.class) ||
-//                    record.getClass().equals(InterfaceEndRecord.class) ||
-//                    record.getClass().equals(WriteAccessRecord.class) ||
-//                    record.getClass().equals(CodepageRecord.class) ||
-//                    record.getClass().equals(DSFRecord.class)) {
-//                continue;
-//            }
-            try {
-                Record newRecord = record.copy();
-
-                assertEquals("Expecting the same class back from clone(), but had Record of type " + record.getClass() + " and got back a " + newRecord.getClass() + " from clone()",
-                        record.getClass(), newRecord.getClass());
-
-                byte[] origBytes = record.serialize();
-                byte[] newBytes = newRecord.serialize();
-
-                assertArrayEquals("Record of type " + record.getClass() + " should return the same byte array via the clone() method, but did return a different array",
-                        origBytes, newBytes);
-            } catch (RuntimeException e) {
-                // some Records do not implement clone, ignore those for now
-                assertTrue(e.getMessage().contains("needs to define a clone method"));
-            }
-        }
-    }
-
-    // a test-case to test this locally without executing the full TestAllFiles
-    @Test
-    public void test() throws Exception {
-        try (InputStream stream = new FileInputStream("test-data/spreadsheet/15556.xls")) {
-            HSSFWorkbook wb = new HSSFWorkbook(stream);
-            handleWorkbook(wb);
-            wb.close();
-        }
-    }
-}
diff --git a/src/integrationtest/org/apache/poi/stress/BaseIntegrationTest.java b/src/integrationtest/org/apache/poi/stress/BaseIntegrationTest.java
new file mode 100644 (file)
index 0000000..8abe9fc
--- /dev/null
@@ -0,0 +1,170 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.stress;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipException;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.OldFileFormatException;
+import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
+import org.junit.Assume;
+
+/**
+ * This class is used for mass-regression testing via a
+ * separate project, this class provides functionality to
+ * run integration tests on one file and handle some
+ * types of files/exceptions, e.g. old file formats.
+ *
+ */
+public class BaseIntegrationTest {
+       private final File rootDir;
+       private String file;
+       private FileHandler handler;
+
+       public BaseIntegrationTest(File rootDir, String file, FileHandler handler) {
+               this.rootDir = rootDir;
+               this.file = file;
+               this.handler = handler;
+       }
+
+       public void test() throws Exception {
+        assertNotNull("Unknown file extension for file: " + file + ": " + TestAllFiles.getExtension(file), handler);
+               testOneFile(new File(rootDir, file));
+       }
+
+       protected void testOneFile(File inputFile) throws Exception {
+               try {
+                       handleFile(inputFile);
+               } catch (OfficeXmlFileException e) {
+                       // switch XWPF and HWPF and so forth depending on the error message
+                       handleWrongOLE2XMLExtension(inputFile, e);
+               } catch (OldFileFormatException e) {
+                       // Not even text extraction is supported for these: handler.handleExtracting(inputFile);
+                       Assume.assumeFalse("File " + file + " excluded because it is unsupported old Excel format", true);
+               } catch (EncryptedDocumentException e) {
+                       // Do not try to read encrypted files
+                       Assume.assumeFalse("File " + file + " excluded because it is password-encrypted", true);
+               } catch (ZipException e) {
+                       // some files are corrupted
+                       if (e.getMessage().equals("unexpected EOF") || e.getMessage().equals("Truncated ZIP file")) {
+                               Assume.assumeFalse("File " + file + " excluded because the Zip file is incomplete", true);
+                       }
+
+                       throw e;
+               } catch (IOException e) {
+                       // ignore some other ways of corrupted files
+                       String message = e.getMessage();
+                       if(message != null && message.contains("Truncated ZIP file")) {
+                               Assume.assumeFalse("File " + file + " excluded because the Zip file is incomplete", true);
+                       }
+
+                       // sometimes binary format has XML-format-extension...
+                       if(message != null && message.contains("rong file format or file extension for OO XML file")) {
+                               handleWrongOLE2XMLExtension(inputFile, e);
+                               return;
+                       }
+
+                       throw e;
+               } catch (IllegalArgumentException e) {
+                       // ignore errors for documents with incorrect extension
+                       String message = e.getMessage();
+                       if(message != null && (message.equals("The document is really a RTF file") ||
+                                       message.equals("The document is really a PDF file") ||
+                                       message.equals("The document is really a HTML file"))) {
+                               Assume.assumeFalse("File " + file + " excluded because it is actually a PDF/RTF/HTML file", true);
+                       }
+
+                       if(message != null && message.equals("The document is really a OOXML file")) {
+                               handleWrongOLE2XMLExtension(inputFile, e);
+                               return;
+                       }
+
+                       throw e;
+               }
+
+               try {
+                       handler.handleExtracting(inputFile);
+               } catch (EncryptedDocumentException e) {
+                       // Do not try to read encrypted files
+                       Assume.assumeFalse("File " + file + " excluded because it is password-encrypted", true);
+               }
+       }
+
+    void handleWrongOLE2XMLExtension(File inputFile, Exception e) throws Exception {
+               // we sometimes have wrong extensions, so for some exceptions we try to handle it
+               // with the correct FileHandler instead
+               String message = e.getMessage();
+
+               // ignore some file-types that we do not want to handle here
+               Assume.assumeFalse("File " + file + " excluded because it is actually a PDF/RTF/HTML file",
+                               message != null && (message.equals("The document is really a RTF file") ||
+                                       message.equals("The document is really a PDF file") ||
+                                       message.equals("The document is really a HTML file")));
+
+               if(message != null && (message.equals("The document is really a XLS file"))) {
+                       handler = TestAllFiles.HANDLERS.get(".xls");
+                       handleFile(inputFile);
+               } else if(message != null && (message.equals("The document is really a PPT file"))) {
+                       handler = TestAllFiles.HANDLERS.get(".ppt");
+                       handleFile(inputFile);
+               } else if(message != null && (message.equals("The document is really a DOC file"))) {
+                       handler = TestAllFiles.HANDLERS.get(".doc");
+                       handleFile(inputFile);
+               } else if(message != null && (message.equals("The document is really a VSD file"))) {
+                       handler = TestAllFiles.HANDLERS.get(".vsd");
+                       handleFile(inputFile);
+
+               // use XWPF instead of HWPF and XSSF instead of HSSF as the file seems to have the wrong extension
+               } else if (handler instanceof HWPFFileHandler) {
+            handler = TestAllFiles.HANDLERS.get(".docx");
+            handleFile(inputFile);
+        } else if (handler instanceof HSSFFileHandler) {
+            handler = TestAllFiles.HANDLERS.get(".xlsx");
+            handleFile(inputFile);
+        } else if (handler instanceof HSLFFileHandler) {
+                       handler = TestAllFiles.HANDLERS.get(".pptx");
+                       handleFile(inputFile);
+
+               // and the other way around, use HWPF instead of XWPF and so forth
+               } else if(handler instanceof XWPFFileHandler) {
+                       handler = TestAllFiles.HANDLERS.get(".doc");
+                       handleFile(inputFile);
+               } else if(handler instanceof XSSFFileHandler) {
+                       handler = TestAllFiles.HANDLERS.get(".xls");
+                       handleFile(inputFile);
+               } else if(handler instanceof XSLFFileHandler) {
+                       handler = TestAllFiles.HANDLERS.get(".ppt");
+                       handleFile(inputFile);
+        } else {
+                       // nothing matched => throw the exception to the outside
+            throw e;
+        }
+       }
+
+       private void handleFile(File inputFile) throws Exception {
+               try (InputStream newStream = new BufferedInputStream(new FileInputStream(inputFile), 64*1024)) {
+                       handler.handleFile(newStream, inputFile.getAbsolutePath());
+               }
+       }
+}
index ba2e1bc617793a2a82d7d733754dcf6d89d7e4ee..2c125db1c076ec46edafd376730e4b864aa84139 100644 (file)
@@ -30,12 +30,12 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
+import org.apache.poi.examples.hpsf.CopyCompare;
 import org.apache.poi.hpsf.DocumentSummaryInformation;
 import org.apache.poi.hpsf.HPSFPropertiesOnlyDocument;
 import org.apache.poi.hpsf.MarkUnsupportedException;
 import org.apache.poi.hpsf.PropertySet;
 import org.apache.poi.hpsf.SummaryInformation;
-import org.apache.poi.hpsf.examples.CopyCompare;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
 import org.apache.poi.poifs.filesystem.DocumentInputStream;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
diff --git a/src/integrationtest/org/apache/poi/stress/HSSFRecordsStresser.java b/src/integrationtest/org/apache/poi/stress/HSSFRecordsStresser.java
new file mode 100644 (file)
index 0000000..932fd39
--- /dev/null
@@ -0,0 +1,76 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.stress;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.junit.Test;
+
+/**
+ * Needs to be implemented in this package to have access to
+ * HSSFWorkbook.getWorkbook()
+ */
+public class HSSFRecordsStresser {
+    public static void handleWorkbook(HSSFWorkbook wb) {
+        List<org.apache.poi.hssf.record.Record> records = wb.getWorkbook().getRecords();
+        for(org.apache.poi.hssf.record.Record record : records) {
+            // some Records do not implement clone ?!
+            // equals instead of instanceof is on purpose here to only skip exactly this class and not any derived ones
+//            if(record.getClass().equals(InterfaceHdrRecord.class) ||
+//                    record.getClass().equals(MMSRecord.class) ||
+//                    record.getClass().equals(InterfaceEndRecord.class) ||
+//                    record.getClass().equals(WriteAccessRecord.class) ||
+//                    record.getClass().equals(CodepageRecord.class) ||
+//                    record.getClass().equals(DSFRecord.class)) {
+//                continue;
+//            }
+            try {
+                Record newRecord = record.copy();
+
+                assertEquals("Expecting the same class back from clone(), but had Record of type " + record.getClass() + " and got back a " + newRecord.getClass() + " from clone()",
+                        record.getClass(), newRecord.getClass());
+
+                byte[] origBytes = record.serialize();
+                byte[] newBytes = newRecord.serialize();
+
+                assertArrayEquals("Record of type " + record.getClass() + " should return the same byte array via the clone() method, but did return a different array",
+                        origBytes, newBytes);
+            } catch (RuntimeException e) {
+                // some Records do not implement clone, ignore those for now
+                assertTrue(e.getMessage().contains("needs to define a clone method"));
+            }
+        }
+    }
+
+    // a test-case to test this locally without executing the full TestAllFiles
+    @Test
+    public void test() throws Exception {
+        try (InputStream stream = new FileInputStream("test-data/spreadsheet/15556.xls")) {
+            HSSFWorkbook wb = new HSSFWorkbook(stream);
+            handleWorkbook(wb);
+            wb.close();
+        }
+    }
+}
diff --git a/src/integrationtest/org/apache/poi/stress/HeapDump.java b/src/integrationtest/org/apache/poi/stress/HeapDump.java
new file mode 100644 (file)
index 0000000..59a3832
--- /dev/null
@@ -0,0 +1,62 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.stress;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+
+public class HeapDump {
+    // This is the name of the HotSpot Diagnostic MBean
+    private static final String HOTSPOT_BEAN_NAME =
+            "com.sun.management:type=HotSpotDiagnostic";
+
+    // field to store the hotspot diagnostic MBean
+    private static volatile HotSpotDiagnosticMXBean hotspotMBean;
+
+    /**
+     * Call this method from your application whenever you
+     * want to dump the heap snapshot into a file.
+     *
+     * @param fileName name of the heap dump file
+     * @param live flag that tells whether to dump
+     *             only the live objects
+     */
+    public static void dumpHeap(String fileName, boolean live) throws IOException {
+        // initialize hotspot diagnostic MBean
+        initHotspotMBean();
+        hotspotMBean.dumpHeap(fileName, live);
+    }
+
+    // initialize the hotspot diagnostic MBean field
+    private static void initHotspotMBean() throws IOException {
+        if (hotspotMBean == null) {
+            synchronized (HeapDump.class) {
+                if (hotspotMBean == null) {
+                    hotspotMBean = getHotspotMBean();
+                }
+            }
+        }
+    }
+
+    // get the hotspot diagnostic MBean from the platform MBean server
+    private static HotSpotDiagnosticMXBean getHotspotMBean() throws IOException {
+        return ManagementFactory.newPlatformMXBeanProxy(ManagementFactory.getPlatformMBeanServer(),
+                        HOTSPOT_BEAN_NAME, HotSpotDiagnosticMXBean.class);
+    }
+}
diff --git a/src/integrationtest/org/apache/poi/stress/POIFileScanner.java b/src/integrationtest/org/apache/poi/stress/POIFileScanner.java
new file mode 100644 (file)
index 0000000..947e709
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ *  ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one or more
+ *    contributor license agreements.  See the NOTICE file distributed with
+ *    this work for additional information regarding copyright ownership.
+ *    The ASF licenses this file to You under the Apache License, Version 2.0
+ *    (the "License"); you may not use this file except in compliance with
+ *    the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.stress;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.util.SuppressForbidden;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.tools.ant.DirectoryScanner;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Helper class to scan a folder for files and return a collection of
+ * found files together with the matching {@link FileHandler}.
+ *
+ * Can also be used to get the appropriate FileHandler for a single file.
+ */
+public class POIFileScanner {
+    private final static File ROOT_DIR;
+    static {
+        // when running in Gradle, current directory might be "build/integrationtest"
+        if(new File("../../test-data").exists()) {
+            ROOT_DIR = new File("../../test-data");
+        } else {
+            ROOT_DIR = new File("test-data");
+        }
+    }
+
+    /**
+     * Scan a folder for files and return a collection of
+     * found files together with the matching {@link FileHandler}.
+     *
+     * Note: unknown files will be assigned to {@link TestAllFiles.NullFileHandler}
+     *
+     * @param rootDir The directory to scan
+     * @return A collection with file-FileHandler pairs which can be used for running tests on that file
+     * @throws IOException If determining the file-type fails
+     */
+    public static Collection<Map.Entry<String, FileHandler>> scan(File rootDir) throws IOException {
+        DirectoryScanner scanner = new DirectoryScanner();
+        scanner.setBasedir(rootDir);
+
+        scanner.setExcludes(TestAllFiles.SCAN_EXCLUDES);
+
+        System.out.println("Scanning for files in " + rootDir);
+
+        scanner.scan();
+
+        String[] includedFiles = scanner.getIncludedFiles();
+        System.out.println("Handling " + includedFiles.length + " files");
+
+        List<Map.Entry<String, FileHandler>> files = new ArrayList<>();
+        for(String file : includedFiles) {
+            // breaks files with slash in their name on Linux:
+            // file = file.replace('\\', '/'); // ... failures/handlers lookup doesn't work on windows otherwise
+
+            FileHandler fileHandler = getFileHandler(rootDir, file);
+
+            files.add(new AbstractMap.SimpleImmutableEntry<>(file, fileHandler));
+
+            if(files.size() % 100 == 0) {
+                System.out.print(".");
+                if(files.size() % 100_000 == 0) {
+                    System.out.println(file);
+                }
+            }
+        }
+        System.out.println();
+
+        return files;
+    }
+
+    /**
+     * Get the FileHandler for a single file
+     *
+     * @param rootDir The directory where the file resides
+     * @param file The name of the file without directory
+     * @return The matching {@link FileHandler}, A {@link TestAllFiles.NullFileHandler}
+     *          is returned if no match is found
+     * @throws IOException If determining the file-type fails
+     */
+    protected static FileHandler getFileHandler(File rootDir, String file) throws IOException {
+        FileHandler fileHandler = TestAllFiles.HANDLERS.get(TestAllFiles.getExtension(file));
+        if(fileHandler == null) {
+            // we could not detect a type of file based on the extension, so we
+            // need to take a close look at the file
+            fileHandler = detectUnnamedFile(rootDir, file);
+        }
+        return fileHandler;
+    }
+
+    private static FileHandler detectUnnamedFile(File rootDir, String file) throws IOException {
+        File testFile = new File(rootDir, file);
+
+        // find out if it looks like OLE2 (HSSF, HSLF, HWPF, ...) or OOXML (XSSF, XSLF, XWPF, ...)
+        // and then determine the file type accordingly
+        FileMagic magic = FileMagic.valueOf(testFile);
+        switch (magic) {
+            case OLE2: {
+                try {
+                    try (POIFSFileSystem fs = new POIFSFileSystem(testFile, true)) {
+                        HSSFWorkbook.getWorkbookDirEntryName(fs.getRoot());
+                    }
+
+                    // we did not get an exception, so it seems this is a HSSFWorkbook
+                    return TestAllFiles.HANDLERS.get(".xls");
+                } catch (IOException | RuntimeException e) {
+                    try {
+                        try (FileInputStream istream = new FileInputStream(testFile)) {
+                            try (HWPFDocument ignored = new HWPFDocument(istream)) {
+                                // seems to be a valid document
+                                return TestAllFiles.HANDLERS.get(".doc");
+                            }
+                        }
+                    } catch (IOException | RuntimeException e2) {
+                        System.out.println("Could not open POIFSFileSystem for OLE2 file " + testFile + ": " + e + " and " + e2);
+                        return TestAllFiles.NullFileHandler.instance;
+                    }
+                }
+            }
+            case OOXML: {
+                try {
+                    try (Workbook ignored = WorkbookFactory.create(testFile, null, true)) {
+                        // seems to be a valid workbook
+                        return TestAllFiles.HANDLERS.get(".xlsx");
+                    }
+                } catch (IOException | RuntimeException e) {
+                    try {
+                        try (FileInputStream is = new FileInputStream(testFile)) {
+                            try (XWPFDocument ignored = new XWPFDocument(is)) {
+                                // seems to be a valid document
+                                return TestAllFiles.HANDLERS.get(".docx");
+                            }
+                        }
+                    } catch (IOException | RuntimeException e2) {
+                        System.out.println("Could not open POIFSFileSystem for OOXML file " + testFile + ": " + e + " and " + e2);
+                        return TestAllFiles.NullFileHandler.instance;
+                    }
+                }
+            }
+
+            // do not warn about a few detected file types
+            case RTF:
+            case PDF:
+            case HTML:
+            case XML:
+            case JPEG:
+            case GIF:
+            case TIFF:
+            case WMF:
+            case EMF:
+            case BMP:
+                return TestAllFiles.NullFileHandler.instance;
+        }
+
+        System.out.println("Did not get a handler for extension " + TestAllFiles.getExtension(file) +
+                " of file " + file + ": " + magic);
+        return TestAllFiles.NullFileHandler.instance;
+    }
+
+    @Ignore
+    @Test
+    @SuppressForbidden("Just an ignored test")
+    public void testInvalidFile() throws IOException, InterruptedException {
+        FileHandler fileHandler = POIFileScanner.getFileHandler(new File("/usbc/CommonCrawl"),
+                "www.bgs.ac.uk_downloads_directdownload.cfm_id=2362&noexcl=true&t=west_20sussex_20-_20building_20stone_20quarries");
+
+        assertEquals(XSSFFileHandler.class, fileHandler.getClass());
+
+        // to show the output from ZipFile() from commons-compress
+        // although I did not find out yet why the ZipFile is not closed here
+        System.gc();
+        Thread.sleep(1000);
+        System.gc();
+        Thread.sleep(1000);
+    }
+
+    @Test
+    public void testDetectUnnamedFile() throws IOException {
+        POIFileScanner.detectUnnamedFile(new File(ROOT_DIR, "spreadsheet"), "49156.xlsx");
+    }
+
+    @Test
+    public void test() throws IOException {
+        POIFileScanner.scan(ROOT_DIR);
+    }
+}
diff --git a/src/integrationtest/org/apache/poi/stress/TestAllFiles.java b/src/integrationtest/org/apache/poi/stress/TestAllFiles.java
new file mode 100644 (file)
index 0000000..d95b156
--- /dev/null
@@ -0,0 +1,485 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.stress;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.poi.OldFileFormatException;
+import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.tools.ant.DirectoryScanner;
+import org.junit.AssumptionViolatedException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ *  This is an integration test which performs various actions on all stored test-files and tries
+ *  to reveal problems which are introduced, but not covered (yet) by unit tests.
+ *
+ *  This test looks for any file under the test-data directory and tries to do some useful
+ *  processing with it based on it's type.
+ *
+ *  The test is implemented as a junit {@link Parameterized} test, which leads
+ *  to one test-method call for each file (currently around 950 files are handled).
+ *
+ *  There is a a mapping of extension to implementations of the interface
+ *  {@link FileHandler} which defines how the file is loaded and which actions are
+ *  tried with the file.
+ *
+ *  The test can be expanded by adding more actions to the FileHandlers, this automatically
+ *  applies the action to any such file in our test-data repository.
+ *
+ *  There is also a list of files that should actually fail.
+ *
+ *  Note: It is also a test-failure if a file that is expected to fail now actually works,
+ *  i.e. if a bug was fixed in POI itself, the file should be removed from the expected-failures
+ *  here as well! This is to ensure that files that should not work really do not work, e.g.
+ *  that we do not remove expected sanity checks.
+ */
+@RunWith(Parameterized.class)
+public class TestAllFiles {
+    private static final File ROOT_DIR = new File("test-data");
+    private static final boolean IGNORE_SCRATCHPAD = Boolean.getBoolean("scratchpad.ignore");
+
+    public static final String[] SCAN_EXCLUDES = new String[] { "**/.svn/**", "lost+found", "**/.git/**" };
+
+    private static final Map<String,String> FILE_PASSWORD;
+
+
+    // map file extensions to the actual mappers
+    public static final Map<String, FileHandler> HANDLERS = new HashMap<>();
+
+    static {
+        // Excel
+        HANDLERS.put(".xls", new HSSFFileHandler());
+        HANDLERS.put(".xlsx", new XSSFFileHandler());
+        HANDLERS.put(".xlsm", new XSSFFileHandler());
+        HANDLERS.put(".xltx", new XSSFFileHandler());
+        HANDLERS.put(".xlsb", new XSSFBFileHandler());
+
+        // Word
+        HANDLERS.put(".doc", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HWPFFileHandler());
+        HANDLERS.put(".docx", new XWPFFileHandler());
+        HANDLERS.put(".dotx", new XWPFFileHandler());
+        HANDLERS.put(".docm", new XWPFFileHandler());
+
+        // OpenXML4J files
+        HANDLERS.put(".ooxml", new OPCFileHandler());
+        HANDLERS.put(".zip", new OPCFileHandler());
+
+        // Powerpoint
+        HANDLERS.put(".ppt", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HSLFFileHandler());
+        HANDLERS.put(".pot", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HSLFFileHandler());
+        HANDLERS.put(".pptx", new XSLFFileHandler());
+        HANDLERS.put(".pptm", new XSLFFileHandler());
+        HANDLERS.put(".ppsm", new XSLFFileHandler());
+        HANDLERS.put(".ppsx", new XSLFFileHandler());
+        HANDLERS.put(".thmx", new XSLFFileHandler());
+        HANDLERS.put(".potx", new XSLFFileHandler());
+
+        // Outlook
+        HANDLERS.put(".msg", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HSMFFileHandler());
+
+        // Publisher
+        HANDLERS.put(".pub", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HPBFFileHandler());
+
+        // Visio - binary
+        HANDLERS.put(".vsd", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HDGFFileHandler());
+
+        // Visio - ooxml
+        HANDLERS.put(".vsdm", new XDGFFileHandler());
+        HANDLERS.put(".vsdx", new XDGFFileHandler());
+        HANDLERS.put(".vssm", new XDGFFileHandler());
+        HANDLERS.put(".vssx", new XDGFFileHandler());
+        HANDLERS.put(".vstm", new XDGFFileHandler());
+        HANDLERS.put(".vstx", new XDGFFileHandler());
+
+        // Visio - not handled yet
+        HANDLERS.put(".vst", NullFileHandler.instance);
+        HANDLERS.put(".vss", NullFileHandler.instance);
+
+        // POIFS
+        HANDLERS.put(".ole2", new POIFSFileHandler());
+
+        // Microsoft Admin Template?
+        HANDLERS.put(".adm", new HPSFFileHandler());
+
+        // Microsoft TNEF
+        HANDLERS.put(".dat", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HMEFFileHandler());
+
+        // TODO: are these readable by some of the formats?
+        HANDLERS.put(".wri", NullFileHandler.instance);
+        HANDLERS.put(".shw", NullFileHandler.instance);
+        HANDLERS.put(".zvi", NullFileHandler.instance);
+        HANDLERS.put(".mpp", NullFileHandler.instance);
+        HANDLERS.put(".qwp", NullFileHandler.instance);
+        HANDLERS.put(".wps", NullFileHandler.instance);
+        HANDLERS.put(".bin", NullFileHandler.instance);
+        HANDLERS.put(".xps", NullFileHandler.instance);
+        HANDLERS.put(".sldprt", NullFileHandler.instance);
+        HANDLERS.put(".mdb", NullFileHandler.instance);
+        HANDLERS.put(".vml", NullFileHandler.instance);
+
+        // ignore some file types, images, other formats, ...
+        HANDLERS.put(".txt", NullFileHandler.instance);
+        HANDLERS.put(".pdf", NullFileHandler.instance);
+        HANDLERS.put(".rtf", NullFileHandler.instance);
+        HANDLERS.put(".gif", NullFileHandler.instance);
+        HANDLERS.put(".html", NullFileHandler.instance);
+        HANDLERS.put(".png", NullFileHandler.instance);
+        HANDLERS.put(".wmf", NullFileHandler.instance);
+        HANDLERS.put(".emf", NullFileHandler.instance);
+        HANDLERS.put(".dib", NullFileHandler.instance);
+        HANDLERS.put(".svg", NullFileHandler.instance);
+        HANDLERS.put(".pict", NullFileHandler.instance);
+        HANDLERS.put(".jpg", NullFileHandler.instance);
+        HANDLERS.put(".jpeg", NullFileHandler.instance);
+        HANDLERS.put(".tif", NullFileHandler.instance);
+        HANDLERS.put(".tiff", NullFileHandler.instance);
+        HANDLERS.put(".wav", NullFileHandler.instance);
+        HANDLERS.put(".xml", NullFileHandler.instance);
+        HANDLERS.put(".csv", NullFileHandler.instance);
+        HANDLERS.put(".ods", NullFileHandler.instance);
+        HANDLERS.put(".ttf", NullFileHandler.instance);
+        HANDLERS.put(".fntdata", NullFileHandler.instance);
+        // VBA source files
+        HANDLERS.put(".vba", NullFileHandler.instance);
+        HANDLERS.put(".bas", NullFileHandler.instance);
+        HANDLERS.put(".frm", NullFileHandler.instance);
+        HANDLERS.put(".frx", NullFileHandler.instance); //binary
+        HANDLERS.put(".cls", NullFileHandler.instance);
+
+        // map some files without extension
+        HANDLERS.put("spreadsheet/BigSSTRecord", NullFileHandler.instance);
+        HANDLERS.put("spreadsheet/BigSSTRecord2", NullFileHandler.instance);
+        HANDLERS.put("spreadsheet/BigSSTRecord2CR1", NullFileHandler.instance);
+        HANDLERS.put("spreadsheet/BigSSTRecord2CR2", NullFileHandler.instance);
+        HANDLERS.put("spreadsheet/BigSSTRecord2CR3", NullFileHandler.instance);
+        HANDLERS.put("spreadsheet/BigSSTRecord2CR4", NullFileHandler.instance);
+        HANDLERS.put("spreadsheet/BigSSTRecord2CR5", NullFileHandler.instance);
+        HANDLERS.put("spreadsheet/BigSSTRecord2CR6", NullFileHandler.instance);
+        HANDLERS.put("spreadsheet/BigSSTRecord2CR7", NullFileHandler.instance);
+        HANDLERS.put("spreadsheet/BigSSTRecordCR", NullFileHandler.instance);
+        HANDLERS.put("spreadsheet/test_properties1", NullFileHandler.instance);
+
+        // keystore files
+        HANDLERS.put(".pfx", NullFileHandler.instance);
+        HANDLERS.put(".pem", NullFileHandler.instance);
+        HANDLERS.put(".jks", NullFileHandler.instance);
+        HANDLERS.put(".pkcs12", NullFileHandler.instance);
+
+        Map<String,String> passmap = new HashMap<>();
+        passmap.put("slideshow/Password_Protected-hello.ppt", "hello");
+        passmap.put("slideshow/Password_Protected-56-hello.ppt", "hello");
+        passmap.put("slideshow/Password_Protected-np-hello.ppt", "hello");
+        passmap.put("slideshow/cryptoapi-proc2356.ppt", "crypto");
+        passmap.put("spreadsheet/xor-encryption-abc.xls", "abc");
+        passmap.put("spreadsheet/35897-type4.xls", "freedom");
+        passmap.put("spreadsheet/58616.xlsx", Decryptor.DEFAULT_PASSWORD);
+        passmap.put("spreadsheet/password.xls", "password");
+        passmap.put("spreadsheet/protected_passtika.xlsx", "tika");
+        passmap.put("document/bug53475-password-is-pass.docx", "pass");
+        passmap.put("document/bug53475-password-is-solrcell.docx", "solrcell");
+        passmap.put("document/password_password_cryptoapi.doc", "password");
+        passmap.put("document/password_tika_binaryrc4.doc", "tika");
+        passmap.put("poifs/protect.xlsx", Decryptor.DEFAULT_PASSWORD);
+        passmap.put("poifs/extenxls_pwd123.xlsx", "pwd123");
+        passmap.put("poifs/protected_agile.docx", Decryptor.DEFAULT_PASSWORD);
+        passmap.put("poifs/60320-protected.xlsx", "Test001!!");
+        passmap.put("poifs/protected_sha512.xlsx", "this is a test");
+
+        FILE_PASSWORD = Collections.unmodifiableMap(passmap);
+    }
+
+    private static Set<String> unmodifiableHashSet(String... a) {
+        return Collections.unmodifiableSet(hashSet(a));
+    }
+    private static Set<String> hashSet(String... a) {
+        return new HashSet<>(Arrays.asList(a));
+    }
+
+    // Old Word Documents where we can at least extract some text
+    private static final Set<String> OLD_FILES_HWPF = unmodifiableHashSet(
+        "document/Bug49933.doc",
+        "document/Bug51944.doc",
+        "document/Word6.doc",
+        "document/Word6_sections.doc",
+        "document/Word6_sections2.doc",
+        "document/Word95.doc",
+        "document/word95err.doc",
+        "document/Bug60936.doc",
+        "document/Bug60942.doc",
+        "document/Bug60942b.doc",
+        "document/cn.orthodox.www_divenbog_APRIL_30-APRIL.DOC",
+        "hpsf/TestMickey.doc",
+        "document/52117.doc",
+        "hpsf/TestInvertedClassID.doc",
+        "hpsf/TestBug52117.doc"
+    );
+
+    private static final Set<String> EXPECTED_FAILURES = unmodifiableHashSet(
+        // password protected files without known password
+        "spreadsheet/51832.xls",
+        "document/PasswordProtected.doc",
+
+        // TODO: fails XMLExportTest, is this ok?
+        "spreadsheet/CustomXMLMapping-singleattributenamespace.xlsx",
+        "spreadsheet/55864.xlsx",
+        "spreadsheet/57890.xlsx",
+        "spreadsheet/xxe_in_schema.xlsx",
+
+        // TODO: these fail now with some NPE/file read error because we now try to compute every value via Cell.toString()!
+        "spreadsheet/44958.xls",
+        "spreadsheet/44958_1.xls",
+        "spreadsheet/testArraysAndTables.xls",
+
+        // TODO: good to ignore?
+        "spreadsheet/sample-beta.xlsx",
+        "document/cpansearch.perl.org_src_tobyink_acme-rundoc-0.001_word-lib_hello_world.docm",
+
+        // This is actually a spreadsheet!
+        "hpsf/TestRobert_Flaherty.doc",
+
+        // some files that are broken, eg Word 95, ...
+        "spreadsheet/43493.xls",
+        "spreadsheet/46904.xls",
+        "document/Bug50955.doc",
+        "document/57843.doc",
+        "slideshow/PPT95.ppt",
+        "slideshow/pp40only.ppt",
+        "slideshow/Divino_Revelado.pptx",
+        "openxml4j/OPCCompliance_CoreProperties_DCTermsNamespaceLimitedUseFAIL.docx",
+        "openxml4j/OPCCompliance_CoreProperties_DoNotUseCompatibilityMarkupFAIL.docx",
+        "openxml4j/OPCCompliance_CoreProperties_LimitedXSITypeAttribute_NotPresentFAIL.docx",
+        "openxml4j/OPCCompliance_CoreProperties_LimitedXSITypeAttribute_PresentWithUnauthorizedValueFAIL.docx",
+        "openxml4j/OPCCompliance_CoreProperties_OnlyOneCorePropertiesPartFAIL.docx",
+        "openxml4j/OPCCompliance_CoreProperties_UnauthorizedXMLLangAttributeFAIL.docx",
+        "openxml4j/OPCCompliance_DerivedPartNameFAIL.docx",
+        "openxml4j/invalid.xlsx",
+        "openxml4j/62592.thmx",
+        "spreadsheet/54764-2.xlsx",   // see TestXSSFBugs.bug54764()
+        "spreadsheet/54764.xlsx",     // see TestXSSFBugs.bug54764()
+        "poifs/unknown_properties.msg", // POIFS properties corrupted
+        (IGNORE_SCRATCHPAD ? "" : "poifs/only-zero-byte-streams.ole2"), // No actual contents
+        "spreadsheet/poc-xmlbomb.xlsx",  // contains xml-entity-expansion
+        "spreadsheet/poc-xmlbomb-empty.xlsx",  // contains xml-entity-expansion
+        "spreadsheet/poc-shared-strings.xlsx",  // contains shared-string-entity-expansion
+        "document/61612a.docx",
+        "document/word2.doc",
+        "spreadsheet/xlsx-corrupted.xlsx",
+
+        // old Excel files, which we only support simple text extraction of
+        "spreadsheet/testEXCEL_2.xls",
+        "spreadsheet/testEXCEL_3.xls",
+        "spreadsheet/testEXCEL_4.xls",
+        "spreadsheet/testEXCEL_5.xls",
+        "spreadsheet/testEXCEL_95.xls",
+        "spreadsheet/59074.xls",
+        "spreadsheet/60284.xls",
+        "spreadsheet/64130.xls",
+
+        // OOXML Strict is not yet supported, see bug #57699
+        "spreadsheet/SampleSS.strict.xlsx",
+        "spreadsheet/SimpleStrict.xlsx",
+        "spreadsheet/sample.strict.xlsx",
+        "spreadsheet/57914.xlsx",
+
+        // files with XML entities
+        "openxml4j/ContentTypeHasEntities.ooxml",
+
+        // non-TNEF files
+        "ddf/Container.dat",
+        "ddf/47143.dat",
+
+        // sheet cloning errors
+        "spreadsheet/56450.xls",
+        // "spreadsheet/OddStyleRecord.xls",
+
+        // msg files with non-standard encodings
+        "hsmf/ASCII_CP1251_LCID1049.msg",
+        "hsmf/ASCII_UTF-8_CP1252_LCID1031.msg",
+        "hsmf/ASCII_UTF-8_CP1252_LCID1031_HTML.msg",
+        "hsmf/HTMLBodyBinary_CP1251.msg",
+        "hsmf/HTMLBodyBinary_UTF-8.msg"
+    );
+
+    private static final Set<String> IGNORED = unmodifiableHashSet(
+        // OPC handler works / XSSF handler fails
+        "spreadsheet/57181.xlsm",
+        "spreadsheet/61300.xls"//intentionally fuzzed -- used to cause infinite loop
+    );
+
+    @Parameters(name="{index}: {0} using {1}")
+    public static Iterable<Object[]> files() {
+        DirectoryScanner scanner = new DirectoryScanner();
+        scanner.setBasedir(ROOT_DIR);
+        scanner.setExcludes(SCAN_EXCLUDES);
+
+        scanner.scan();
+
+        System.out.println("Handling " + scanner.getIncludedFiles().length + " files");
+
+        List<Object[]> files = new ArrayList<>();
+        for(String file : scanner.getIncludedFiles()) {
+            file = file.replace('\\', '/'); // ... failures/handlers lookup doesn't work on windows otherwise
+            if (IGNORED.contains(file)) {
+                System.out.println("Ignoring " + file);
+                continue;
+            }
+            FileHandler handler = HANDLERS.get(getExtension(file));
+            files.add(new Object[] { file, handler });
+
+            // for some file-types also run OPCFileHandler
+            if(handler instanceof XSSFFileHandler ||
+                handler instanceof XWPFFileHandler ||
+                handler instanceof XSLFFileHandler ||
+                handler instanceof XDGFFileHandler) {
+                files.add(new Object[] { file, new OPCFileHandler() });
+            }
+
+            if (handler instanceof HSSFFileHandler ||
+                handler instanceof HSLFFileHandler ||
+                handler instanceof HWPFFileHandler ||
+                handler instanceof HDGFFileHandler) {
+                files.add(new Object[] { file, new HPSFFileHandler() });
+            }
+        }
+
+        return files;
+    }
+
+    @SuppressWarnings("DefaultAnnotationParam")
+    @Parameter(value=0)
+    public String file;
+
+    @Parameter(value=1)
+    public FileHandler handler;
+
+    @Before
+    public void setPassword() {
+        // this also removes the password for non encrypted files
+        String pass = TestAllFiles.FILE_PASSWORD.get(file);
+        Biff8EncryptionKey.setCurrentUserPassword(pass);
+    }
+
+    @Test
+    public void testAllFiles() throws Exception {
+        if(handler == null) {
+            fail("Did not find a handler for file " + file);
+        }
+
+        System.out.println("Reading " + file + " with " + handler.getClass().getSimpleName());
+        assertNotNull("Unknown file extension for file: " + file + ": " + getExtension(file), handler);
+        File inputFile = new File(ROOT_DIR, file);
+
+        // special cases where docx-handling breaks, but OPCPackage handling works
+        boolean ignoredOPC = (file.endsWith(".docx") || file.endsWith(".xlsx") ||
+                    file.endsWith(".xlsb") || file.endsWith(".pptx")) &&
+                handler instanceof OPCFileHandler;
+        boolean ignoreHPSF = (handler instanceof HPSFFileHandler);
+
+        try {
+            try (InputStream stream = new BufferedInputStream(new FileInputStream(inputFile), 64 * 1024)) {
+                handler.handleFile(stream, file);
+                assertFalse("Expected to fail for file " + file + " and handler " + handler + ", but did not fail!",
+                        OLD_FILES_HWPF.contains(file) && !ignoreHPSF);
+            }
+
+            handler.handleExtracting(inputFile);
+
+            assertFalse("Expected to fail for file " + file + " and handler " + handler + ", but did not fail!",
+                EXPECTED_FAILURES.contains(file) && !ignoredOPC && !ignoreHPSF);
+        } catch (OldFileFormatException e) {
+            // for old word files we should still support extracting text
+            if(OLD_FILES_HWPF.contains(file)) {
+                handler.handleExtracting(inputFile);
+            } else {
+                // check if we expect failure for this file
+                if(!EXPECTED_FAILURES.contains(file) && !AbstractFileHandler.EXPECTED_EXTRACTOR_FAILURES.contains(file)) {
+                    System.out.println("Failed: " + file);
+                    throw new Exception("While handling " + file, e);
+                }
+            }
+        } catch (AssumptionViolatedException e) {
+            // file handler ignored this file
+        } catch (Exception e) {
+            // check if we expect failure for this file
+            if(!EXPECTED_FAILURES.contains(file) && !AbstractFileHandler.EXPECTED_EXTRACTOR_FAILURES.contains(file)) {
+                System.out.println("Failed: " + file);
+                throw new Exception("While handling " + file, e);
+            }
+        }
+
+        try {
+            // let some file handlers do additional stuff
+            handler.handleAdditional(inputFile);
+        } catch (AssumptionViolatedException e) {
+            // file handler ignored this file
+        } catch (Exception e) {
+            if(!EXPECTED_FAILURES.contains(file) && !AbstractFileHandler.EXPECTED_EXTRACTOR_FAILURES.contains(file)) {
+                System.out.println("Failed: " + file);
+                throw new Exception("While handling " + file, e);
+            }
+        }
+    }
+
+    public static String getExtension(String file) {
+        int pos = file.lastIndexOf('.');
+        if(pos == -1 || pos == file.length()-1) {
+            return file;
+        }
+
+        return file.substring(pos).toLowerCase(Locale.ROOT);
+    }
+
+    public static class NullFileHandler implements FileHandler {
+        public static final FileHandler instance = new NullFileHandler();
+
+        @Override
+        public void handleFile(InputStream stream, String path) {
+        }
+
+        @Override
+        public void handleExtracting(File file) {
+        }
+
+        @Override
+        public void handleAdditional(File file) {
+        }
+    }
+}
index 0505d72df962ef5b3710f0821592a30b80deb6f0..c0f88768b86985404796a204b7f423e6128b174e 100644 (file)
@@ -38,8 +38,11 @@ import java.util.Set;
 import javax.xml.transform.TransformerException;
 
 import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.ooxml.POIXMLException;
+import org.apache.poi.examples.ss.ExcelComparator;
+import org.apache.poi.examples.xssf.eventusermodel.FromHowTo;
+import org.apache.poi.examples.xssf.eventusermodel.XLSX2CSV;
 import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
+import org.apache.poi.ooxml.POIXMLException;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.OLE2NotOfficeXmlFileException;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
@@ -47,11 +50,8 @@ import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.poifs.crypt.Decryptor;
 import org.apache.poi.poifs.crypt.EncryptionInfo;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.ss.examples.ExcelComparator;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.xssf.eventusermodel.XLSX2CSV;
 import org.apache.poi.xssf.eventusermodel.XSSFReader;
-import org.apache.poi.xssf.eventusermodel.examples.FromHowTo;
 import org.apache.poi.xssf.extractor.XSSFExportToXml;
 import org.apache.poi.xssf.usermodel.XSSFMap;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
@@ -99,27 +99,27 @@ public class XSSFFileHandler extends SpreadsheetHandler {
 
         // use the combined handler for HSSF/XSSF
         handleWorkbook(wb);
-        
+
         // TODO: some documents fail currently...
         //XSSFFormulaEvaluator evaluator = new XSSFFormulaEvaluator(wb);
         //evaluator.evaluateAll();
 
         // also verify general POIFS-stuff
         new POIXMLDocumentHandler().handlePOIXMLDocument(wb);
-        
+
         // and finally ensure that exporting to XML works
         exportToXML(wb);
 
         // this allows to trigger a heap-dump at this point to see which memory is still allocated
         //HeapDump.dumpHeap("/tmp/poi.hprof", false);
-        
+
         wb.close();
     }
 
 
     private void checkXSSFReader(OPCPackage p) throws IOException, OpenXML4JException {
         XSSFReader reader = new XSSFReader(p);
-        
+
         // these can be null...
         InputStream sharedStringsData = reader.getSharedStringsData();
         if(sharedStringsData != null) {
@@ -132,21 +132,21 @@ public class XSSFFileHandler extends SpreadsheetHandler {
             stylesData.close();
         }
         reader.getStylesTable();
-        
+
         InputStream themesData = reader.getThemesData();
         if(themesData != null) {
             themesData.close();
         }
 
         assertNotNull(reader.getWorkbookData());
-        
+
         Iterator<InputStream> sheetsData = reader.getSheetsData();
         while(sheetsData.hasNext()) {
             InputStream str = sheetsData.next();
             str.close();
         }
     }
-    
+
     private void exportToXML(XSSFWorkbook wb) throws SAXException,
             TransformerException {
         for (XSSFMap map : wb.getCustomXMLMappings()) {
@@ -221,8 +221,8 @@ public class XSSFFileHandler extends SpreadsheetHandler {
     public void testAdditional() throws Exception {
         handleAdditional(new File("test-data/spreadsheet/poc-xmlbomb.xlsx"));
     }
-    
-    // need to override all methods to omit calls to UTF-handling methods 
+
+    // need to override all methods to omit calls to UTF-handling methods
     static class NullPrintStream extends PrintStream {
         @SuppressWarnings("resource")
         NullPrintStream() {
index e7d8afa8d7ddb08f263da9d5496f196a866cf4f6..06a76a952b0a366f84da13f59713aa47a46f8540 100644 (file)
@@ -49,7 +49,7 @@ import org.apache.poi.util.POILogger;
 /**
  * This holds the common functionality for all POI
  *  Document classes.
- * Currently, this relates to Document Information Properties 
+ * Currently, this relates to Document Information Properties
  */
 public abstract class POIDocument implements Closeable {
     /** Holds metadata on our document */
@@ -76,7 +76,7 @@ public abstract class POIDocument implements Closeable {
 
     /**
      * Constructs from the default POIFS
-     * 
+     *
      * @param fs the filesystem the document is read from
      */
     protected POIDocument(POIFSFileSystem fs) {
@@ -85,8 +85,8 @@ public abstract class POIDocument implements Closeable {
 
     /**
      * Fetch the Document Summary Information of the document
-     * 
-     * @return The Document Summary Information or null 
+     *
+     * @return The Document Summary Information or null
      *      if it could not be read for this document.
      */
     public DocumentSummaryInformation getDocumentSummaryInformation() {
@@ -96,9 +96,9 @@ public abstract class POIDocument implements Closeable {
         return dsInf;
     }
 
-    /** 
+    /**
      * Fetch the Summary Information of the document
-     * 
+     *
      * @return The Summary information for the document or null
      *      if it could not be read for this document.
      */
@@ -108,7 +108,7 @@ public abstract class POIDocument implements Closeable {
         }
         return sInf;
     }
-       
+
     /**
      * Will create whichever of SummaryInformation
      *  and DocumentSummaryInformation (HPSF) properties
@@ -136,7 +136,8 @@ public abstract class POIDocument implements Closeable {
      * If a given property set is missing or corrupt,
      *  it will remain null;
      */
-    protected void readProperties() {
+    @Internal
+    public void readProperties() {
         if (initialized) {
             return;
         }
@@ -170,11 +171,11 @@ public abstract class POIDocument implements Closeable {
         }
         return null;
     }
-    
-    /** 
+
+    /**
      * For a given named property entry, either return it or null if
      *  if it wasn't found
-     *  
+     *
      *  @param setName The property to read
      *  @return The value of the given property or null if it wasn't found.
      *
@@ -184,11 +185,11 @@ public abstract class POIDocument implements Closeable {
     protected PropertySet getPropertySet(String setName) throws IOException {
         return getPropertySet(setName, getEncryptionInfo());
     }
-    
-    /** 
+
+    /**
      * For a given named property entry, either return it or null if
      *  if it wasn't found
-     *  
+     *
      *  @param setName The property to read
      *  @param encryptionInfo the encryption descriptor in case of cryptoAPI encryption
      *  @return The value of the given property or null if it wasn't found.
@@ -198,7 +199,7 @@ public abstract class POIDocument implements Closeable {
     @SuppressWarnings("WeakerAccess")
     protected PropertySet getPropertySet(String setName, EncryptionInfo encryptionInfo) throws IOException {
         DirectoryNode dirNode = directory;
-        
+
         POIFSFileSystem encPoifs = null;
         String step = "getting";
         try {
@@ -212,12 +213,12 @@ public abstract class POIDocument implements Closeable {
                 encPoifs = dec.getSummaryEntries(dirNode, encryptedStream);
                 dirNode = encPoifs.getRoot();
             }
-            
+
             //directory can be null when creating new documents
             if (dirNode == null || !dirNode.hasEntry(setName)) {
                 return null;
             }
-    
+
             // Find the entry, and get an input stream for it
             step = "getting";
             try (DocumentInputStream dis = dirNode.createDocumentInputStream(dirNode.getEntry(setName))) {
@@ -233,11 +234,11 @@ public abstract class POIDocument implements Closeable {
             IOUtils.closeQuietly(encPoifs);
         }
     }
-    
+
     /**
      * Writes out the updated standard Document Information Properties (HPSF)
      *  into the currently open POIFSFileSystem
-     * 
+     *
      * @throws IOException if an error when writing to the open
      *      {@link POIFSFileSystem} occurs
      */
@@ -249,19 +250,20 @@ public abstract class POIDocument implements Closeable {
     /**
      * Writes out the standard Document Information Properties (HPSF)
      * @param outFS the POIFSFileSystem to write the properties into
-     * 
-     * @throws IOException if an error when writing to the 
+     *
+     * @throws IOException if an error when writing to the
      *      {@link POIFSFileSystem} occurs
      */
-    protected void writeProperties(POIFSFileSystem outFS) throws IOException {
+    @Internal
+    public void writeProperties(POIFSFileSystem outFS) throws IOException {
         writeProperties(outFS, null);
     }
     /**
      * Writes out the standard Document Information Properties (HPSF)
      * @param outFS the {@link POIFSFileSystem} to write the properties into
      * @param writtenEntries a list of POIFS entries to add the property names too
-     * 
-     * @throws IOException if an error when writing to the 
+     *
+     * @throws IOException if an error when writing to the
      *      {@link POIFSFileSystem} occurs
      */
     protected void writeProperties(POIFSFileSystem outFS, List<String> writtenEntries) throws IOException {
@@ -308,15 +310,15 @@ public abstract class POIDocument implements Closeable {
             writtenEntries.add(name);
         }
     }
-       
+
     /**
      * Writes out a given PropertySet
      *
      * @param name the (POIFS Level) name of the property to write
-     * @param set the PropertySet to write out 
+     * @param set the PropertySet to write out
      * @param outFS the {@link POIFSFileSystem} to write the property into
-     * 
-     * @throws IOException if an error when writing to the 
+     *
+     * @throws IOException if an error when writing to the
      *      {@link POIFSFileSystem} occurs
      */
     private void writePropertySet(String name, PropertySet set, POIFSFileSystem outFS) throws IOException {
@@ -341,7 +343,7 @@ public abstract class POIDocument implements Closeable {
      * Called during a {@link #write()} to ensure that the Document (and
      *  associated {@link POIFSFileSystem}) was opened in a way compatible
      *  with an in-place write.
-     * 
+     *
      * @throws IllegalStateException if the document was opened suitably
      */
     protected void validateInPlaceWritePossible() throws IllegalStateException {
@@ -356,32 +358,32 @@ public abstract class POIDocument implements Closeable {
             throw new IllegalStateException("Opened read-only or via an InputStream, a Writeable File is required");
         }
     }
-    
+
     /**
      * Writes the document out to the currently open {@link File}, via the
      *  writeable {@link POIFSFileSystem} it was opened from.
-     *  
+     *
      * <p>This will fail (with an {@link IllegalStateException} if the
      *  document was opened read-only, opened from an {@link InputStream}
-     *   instead of a File, or if this is not the root document. For those cases, 
-     *   you must use {@link #write(OutputStream)} or {@link #write(File)} to 
+     *   instead of a File, or if this is not the root document. For those cases,
+     *   you must use {@link #write(OutputStream)} or {@link #write(File)} to
      *   write to a brand new document.
-     *   
+     *
      * @since POI 3.15 beta 3
-     * 
+     *
      * @throws IOException thrown on errors writing to the file
      * @throws IllegalStateException if this isn't from a writable File
      */
     public abstract void write() throws IOException;
 
     /**
-     * Writes the document out to the specified new {@link File}. If the file 
+     * Writes the document out to the specified new {@link File}. If the file
      * exists, it will be replaced, otherwise a new one will be created
      *
      * @since POI 3.15 beta 3
-     * 
+     *
      * @param newFile The new File to write to.
-     * 
+     *
      * @throws IOException thrown on errors writing to the file
      */
     public abstract void write(File newFile) throws IOException;
@@ -389,20 +391,20 @@ public abstract class POIDocument implements Closeable {
     /**
      * Writes the document out to the specified output stream. The
      * stream is not closed as part of this operation.
-     * 
+     *
      * Note - if the Document was opened from a {@link File} rather
      *  than an {@link InputStream}, you <b>must</b> write out using
      *  {@link #write()} or to a different File. Overwriting the currently
      *  open file via an OutputStream isn't possible.
-     *  
+     *
      * If {@code stream} is a {@link java.io.FileOutputStream} on a networked drive
      * or has a high cost/latency associated with each written byte,
      * consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream}
      * to improve write performance, or use {@link #write()} / {@link #write(File)}
      * if possible.
-     * 
+     *
      * @param out The stream to write to.
-     * 
+     *
      * @throws IOException thrown on errors writing to the stream
      */
     public abstract void write(OutputStream out) throws IOException;
@@ -429,7 +431,7 @@ public abstract class POIDocument implements Closeable {
     public DirectoryNode getDirectory() {
         return directory;
     }
-    
+
     /**
      * Clear/unlink the attached directory entry
      */
@@ -437,11 +439,11 @@ public abstract class POIDocument implements Closeable {
     protected void clearDirectory() {
         directory = null;
     }
-    
+
     /**
      * check if we were created by POIFS otherwise create a new dummy POIFS
      * for storing the package data
-     * 
+     *
      * @return {@code true} if dummy directory was created, {@code false} otherwise
      */
     @SuppressWarnings("resource")
@@ -453,7 +455,7 @@ public abstract class POIDocument implements Closeable {
         }
         return false;
     }
-    
+
     /**
      * Replaces the attached directory, e.g. if this document is written
      * to a new POIFSFileSystem
index db4fa77a0e2d535d03720d02a6f38b06d5a7fe12..6ce74d1206ee0a74da5333b803bb361774d38dd9 100644 (file)
@@ -1546,7 +1546,8 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
         }
     }
 
-    /*package*/ InternalWorkbook getWorkbook() {
+    @Internal
+    public InternalWorkbook getWorkbook() {
         return workbook;
     }
 
index 1d826e4c10a52108ff70f964a13cfc57b3d0fcbf..0c4c98a7c2e84952d73a08831d3c644d2fd8818c 100644 (file)
 
 package org.apache.poi.hssf.usermodel;
 
+import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 
+import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.FileMagic;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.ss.usermodel.WorkbookProvider;
 import org.apache.poi.util.Internal;
 
 /**
@@ -30,15 +36,11 @@ import org.apache.poi.util.Internal;
  */
 @SuppressWarnings("unused")
 @Internal
-public class HSSFWorkbookFactory extends WorkbookFactory {
+public class HSSFWorkbookFactory implements WorkbookProvider {
 
-    static {
-        init();
-    }
-
-    public static void init() {
-        WorkbookFactory.createHssfFromScratch = HSSFWorkbookFactory::createWorkbook;
-        WorkbookFactory.createHssfByNode = HSSFWorkbookFactory::createWorkbook;
+    @Override
+    public boolean accepts(FileMagic fm) {
+        return FileMagic.OLE2 == fm;
     }
 
     /**
@@ -46,7 +48,7 @@ public class HSSFWorkbookFactory extends WorkbookFactory {
      *
      * @return The created workbook
      */
-    public static HSSFWorkbook createWorkbook() {
+    public HSSFWorkbook create() {
         return new HSSFWorkbook();
     }
 
@@ -64,7 +66,45 @@ public class HSSFWorkbookFactory extends WorkbookFactory {
      * Note that in order to properly release resources the
      * Workbook should be closed after use.
      */
-    public static HSSFWorkbook createWorkbook(final DirectoryNode root) throws IOException {
-        return new HSSFWorkbook(root, true);
+    public HSSFWorkbook create(final DirectoryNode root, String password) throws IOException {
+        boolean passwordSet = false;
+        if (password != null) {
+            Biff8EncryptionKey.setCurrentUserPassword(password);
+            passwordSet = true;
+        }
+        try {
+            return new HSSFWorkbook(root, true);
+        } finally {
+            if (passwordSet) {
+                Biff8EncryptionKey.setCurrentUserPassword(null);
+            }
+        }
+    }
+
+    @Override
+    public Workbook create(InputStream inp) throws IOException {
+        return create(inp, null);
+    }
+
+    @Override
+    public Workbook create(InputStream inp, String password) throws IOException {
+        POIFSFileSystem fs = new POIFSFileSystem(inp);
+        return create(fs.getRoot(), password);
+    }
+
+    @Override
+    public Workbook create(File file, String password, boolean readOnly) throws IOException {
+        boolean passwordSet = false;
+        if (password != null) {
+            Biff8EncryptionKey.setCurrentUserPassword(password);
+            passwordSet = true;
+        }
+        try {
+            return new HSSFWorkbook(new POIFSFileSystem(file, readOnly), true);
+        } finally {
+            if (passwordSet) {
+                Biff8EncryptionKey.setCurrentUserPassword(null);
+            }
+        }
     }
 }
index 88c2c8493cd0ce299e1a72d1f925b2558f9428e4..f32910e1ab4d806dda977fcc0813995a52acdb61 100644 (file)
@@ -19,15 +19,27 @@ package org.apache.poi.poifs.crypt;
 
 public enum ChainingMode {
     // ecb - only for standard encryption
-    ecb("ECB", 1),
-    cbc("CBC", 2),
+    ecb("ECB", 1, null),
+    cbc("CBC", 2, "ChainingModeCBC"),
     /* Cipher feedback chaining (CFB), with an 8-bit window */
-    cfb("CFB8", 3);
+    cfb("CFB8", 3, "ChainingModeCFB");
 
     public final String jceId;
     public final int ecmaId;
-    ChainingMode(String jceId, int ecmaId) {
+    public final String xmlId;
+
+    ChainingMode(String jceId, int ecmaId, String xmlId) {
         this.jceId = jceId;
         this.ecmaId = ecmaId;
+        this.xmlId = xmlId;
+    }
+
+    public static ChainingMode fromXmlId(String xmlId) {
+        for (ChainingMode cm : values()) {
+            if (cm.xmlId != null && cm.xmlId.equals(xmlId)) {
+                return cm;
+            }
+        }
+        return null;
     }
 }
\ No newline at end of file
index 38f666e15e4c6f8243b6bf647ae5f7cde705cc45..f10dda09bd2c1468ed617716c433fdac8f0e5427 100644 (file)
@@ -86,7 +86,7 @@ public abstract class EncryptionHeader implements GenericRecord, Duplicatable {
         return flags;
     }
 
-    protected void setFlags(int flags) {
+    public void setFlags(int flags) {
         this.flags = flags;
     }
 
@@ -94,7 +94,7 @@ public abstract class EncryptionHeader implements GenericRecord, Duplicatable {
         return sizeExtra;
     }
 
-    protected void setSizeExtra(int sizeExtra) {
+    public void setSizeExtra(int sizeExtra) {
         this.sizeExtra = sizeExtra;
     }
 
@@ -102,7 +102,7 @@ public abstract class EncryptionHeader implements GenericRecord, Duplicatable {
         return cipherAlgorithm;
     }
 
-    protected void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) {
+    public void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) {
         this.cipherAlgorithm = cipherAlgorithm;
         if (cipherAlgorithm.allowedKeySize.length == 1) {
             setKeySize(cipherAlgorithm.defaultKeySize);
@@ -113,7 +113,7 @@ public abstract class EncryptionHeader implements GenericRecord, Duplicatable {
         return hashAlgorithm;
     }
 
-    protected void setHashAlgorithm(HashAlgorithm hashAlgorithm) {
+    public void setHashAlgorithm(HashAlgorithm hashAlgorithm) {
         this.hashAlgorithm = hashAlgorithm;
     }
 
@@ -128,7 +128,7 @@ public abstract class EncryptionHeader implements GenericRecord, Duplicatable {
      *
      * @param keyBits
      */
-    protected void setKeySize(int keyBits) {
+    public void setKeySize(int keyBits) {
         this.keyBits = keyBits;
         for (int allowedBits : getCipherAlgorithm().allowedKeySize) {
             if (allowedBits == keyBits) {
@@ -142,7 +142,7 @@ public abstract class EncryptionHeader implements GenericRecord, Duplicatable {
        return blockSize;
     }
 
-    protected void setBlockSize(int blockSize) {
+    public void setBlockSize(int blockSize) {
         this.blockSize = blockSize;
     }
 
@@ -150,7 +150,7 @@ public abstract class EncryptionHeader implements GenericRecord, Duplicatable {
         return keySalt;
     }
 
-    protected void setKeySalt(byte[] salt) {
+    public void setKeySalt(byte[] salt) {
         this.keySalt = (salt == null) ? null : salt.clone();
     }
 
@@ -158,7 +158,7 @@ public abstract class EncryptionHeader implements GenericRecord, Duplicatable {
         return providerType;
     }
 
-    protected void setCipherProvider(CipherProvider providerType) {
+    public void setCipherProvider(CipherProvider providerType) {
         this.providerType = providerType;
     }
 
@@ -166,7 +166,7 @@ public abstract class EncryptionHeader implements GenericRecord, Duplicatable {
         return cspName;
     }
 
-    protected void setCspName(String cspName) {
+    public void setCspName(String cspName) {
         this.cspName = cspName;
     }
 
index 81aca4e417ffe3562b3b561828d7894c6b159b42..17a9136fe42808ed5dd1b27df9892646004d1972 100644 (file)
@@ -43,6 +43,12 @@ import org.apache.poi.util.LittleEndianInput;
  * @see #getBuilder(EncryptionMode)
  */
 public class EncryptionInfo implements GenericRecord {
+
+    /**
+     * Document entry name for encryption info xml descriptor
+     */
+    public static final String ENCRYPTION_INFO_ENTRY = "EncryptionInfo";
+
     /**
      * A flag that specifies whether CryptoAPI RC4 or ECMA-376 encryption
      * ECMA-376 is used. It MUST be 1 unless flagExternal is 1. If flagExternal is 1, it MUST be 0.
@@ -110,25 +116,16 @@ public class EncryptionInfo implements GenericRecord {
             versionMinor = dis.readUShort();
         }
 
-        if (   versionMajor == xor.versionMajor
-            && versionMinor == xor.versionMinor) {
+        if (versionMajor == xor.versionMajor && versionMinor == xor.versionMinor) {
             encryptionMode = xor;
             encryptionFlags = -1;
-        } else if (   versionMajor == binaryRC4.versionMajor
-            && versionMinor == binaryRC4.versionMinor) {
+        } else if (versionMajor == binaryRC4.versionMajor && versionMinor == binaryRC4.versionMinor) {
             encryptionMode = binaryRC4;
             encryptionFlags = -1;
-        } else if (
-               2 <= versionMajor && versionMajor <= 4
-            && versionMinor == 2) {
+        } else if (2 <= versionMajor && versionMajor <= 4 && versionMinor == 2) {
             encryptionFlags = dis.readInt();
-            encryptionMode = (
-                preferredEncryptionMode == cryptoAPI
-                || !flagAES.isSet(encryptionFlags))
-                ? cryptoAPI : standard;
-        } else if (
-               versionMajor == agile.versionMajor
-            && versionMinor == agile.versionMinor){
+            encryptionMode = (preferredEncryptionMode == cryptoAPI || !flagAES.isSet(encryptionFlags)) ? cryptoAPI : standard;
+        } else if (versionMajor == agile.versionMajor && versionMinor == agile.versionMinor){
             encryptionMode = agile;
             encryptionFlags = dis.readInt();
         } else {
index d45fb28c272273273b3c8c3a386e67c9fa93754f..2d3f0fe64a895d4d397e80f9ccb0de871c06466b 100644 (file)
@@ -83,35 +83,35 @@ public abstract class EncryptionVerifier implements GenericRecord, Duplicatable
         return chainingMode;
     }
 
-    protected void setSalt(byte[] salt) {
+    public void setSalt(byte[] salt) {
         this.salt = (salt == null) ? null : salt.clone();
     }
 
-    protected void setEncryptedVerifier(byte[] encryptedVerifier) {
+    public void setEncryptedVerifier(byte[] encryptedVerifier) {
         this.encryptedVerifier = (encryptedVerifier == null) ? null : encryptedVerifier.clone();
     }
 
-    protected void setEncryptedVerifierHash(byte[] encryptedVerifierHash) {
+    public void setEncryptedVerifierHash(byte[] encryptedVerifierHash) {
         this.encryptedVerifierHash = (encryptedVerifierHash == null) ? null : encryptedVerifierHash.clone();
     }
 
-    protected void setEncryptedKey(byte[] encryptedKey) {
+    public void setEncryptedKey(byte[] encryptedKey) {
         this.encryptedKey = (encryptedKey == null) ? null : encryptedKey.clone();
     }
 
-    protected void setSpinCount(int spinCount) {
+    public void setSpinCount(int spinCount) {
         this.spinCount = spinCount;
     }
 
-    protected void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) {
+    public void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) {
         this.cipherAlgorithm = cipherAlgorithm;
     }
 
-    protected void setChainingMode(ChainingMode chainingMode) {
+    public void setChainingMode(ChainingMode chainingMode) {
         this.chainingMode = chainingMode;
     }
 
-    protected void setHashAlgorithm(HashAlgorithm hashAlgorithm) {
+    public void setHashAlgorithm(HashAlgorithm hashAlgorithm) {
         this.hashAlgorithm = hashAlgorithm;
     }
 
diff --git a/src/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java b/src/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java
new file mode 100644 (file)
index 0000000..f8efe0d
--- /dev/null
@@ -0,0 +1,283 @@
+/* ====================================================================
+   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.poifs.crypt.agile;
+
+import static org.apache.poi.poifs.crypt.CryptoFunctions.generateIv;
+import static org.apache.poi.poifs.crypt.CryptoFunctions.generateKey;
+import static org.apache.poi.poifs.crypt.CryptoFunctions.getBlock0;
+import static org.apache.poi.poifs.crypt.CryptoFunctions.getCipher;
+import static org.apache.poi.poifs.crypt.CryptoFunctions.getMessageDigest;
+import static org.apache.poi.poifs.crypt.CryptoFunctions.hashPassword;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.poifs.crypt.ChainingMode;
+import org.apache.poi.poifs.crypt.ChunkedCipherInputStream;
+import org.apache.poi.poifs.crypt.CipherAlgorithm;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionHeader;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.DocumentInputStream;
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * Decryptor implementation for Agile Encryption
+ */
+public class AgileDecryptor extends Decryptor {
+    static final byte[] kVerifierInputBlock = longToBytes(0xfea7d2763b4b9e79L);
+    static final byte[] kHashedVerifierBlock = longToBytes(0xd7aa0f6d3061344eL);
+    static final byte[] kCryptoKeyBlock = longToBytes(0x146e0be7abacd0d6L);
+    static final byte[] kIntegrityKeyBlock = longToBytes(0x5fb2ad010cb9e1f6L);
+    static final byte[] kIntegrityValueBlock = longToBytes(0xa0677f02b22c8433L);
+
+    private long _length = -1;
+
+    protected AgileDecryptor() {
+    }
+
+    protected AgileDecryptor(AgileDecryptor other) {
+        super(other);
+        _length = other._length;
+    }
+
+    private static byte[] longToBytes(long l) {
+        return ByteBuffer.allocate(Long.BYTES).putLong(l).array();
+    }
+
+    /**
+     * set decryption password
+     */
+    @Override
+    public boolean verifyPassword(String password) throws GeneralSecurityException {
+        AgileEncryptionVerifier ver = (AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
+        AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
+
+        int blockSize = header.getBlockSize();
+
+        byte[] pwHash = hashPassword(password, ver.getHashAlgorithm(), ver.getSalt(), ver.getSpinCount());
+
+        /*
+         * encryptedVerifierHashInput: This attribute MUST be generated by using the following steps:
+         * 1. Generate a random array of bytes with the number of bytes used specified by the saltSize
+         *    attribute.
+         * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password,
+         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
+         *    consisting of the following bytes: 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, and 0x79.
+         * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue
+         *    attribute as an initialization vector as specified in section 2.3.4.12. If the array of bytes is not an
+         *    integral multiple of blockSize bytes, pad the array with 0x00 to the next integral multiple of
+         *    blockSize bytes.
+         * 4. Use base64 to encode the result of step 3.
+         */
+        byte[] verfierInputEnc = hashInput(ver, pwHash, kVerifierInputBlock, ver.getEncryptedVerifier(), Cipher.DECRYPT_MODE);
+        setVerifier(verfierInputEnc);
+        MessageDigest hashMD = getMessageDigest(ver.getHashAlgorithm());
+        byte[] verifierHash = hashMD.digest(verfierInputEnc);
+
+        /*
+         * encryptedVerifierHashValue: This attribute MUST be generated by using the following steps:
+         * 1. Obtain the hash value of the random array of bytes generated in step 1 of the steps for
+         *    encryptedVerifierHashInput.
+         * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password,
+         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
+         *    consisting of the following bytes: 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, and 0x4e.
+         * 3. Encrypt the hash value obtained in step 1 by using the binary form of the saltValue attribute as
+         *    an initialization vector as specified in section 2.3.4.12. If hashSize is not an integral multiple of
+         *    blockSize bytes, pad the hash value with 0x00 to an integral multiple of blockSize bytes.
+         * 4. Use base64 to encode the result of step 3.
+         */
+        byte[] verifierHashDec = hashInput(ver, pwHash, kHashedVerifierBlock, ver.getEncryptedVerifierHash(), Cipher.DECRYPT_MODE);
+        verifierHashDec = getBlock0(verifierHashDec, ver.getHashAlgorithm().hashSize);
+
+        /*
+         * encryptedKeyValue: This attribute MUST be generated by using the following steps:
+         * 1. Generate a random array of bytes that is the same size as specified by the
+         *    Encryptor.KeyData.keyBits attribute of the parent element.
+         * 2. Generate an encryption key as specified in section 2.3.4.11, using the user-supplied password,
+         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
+         *    consisting of the following bytes: 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, and 0xd6.
+         * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue
+         *    attribute as an initialization vector as specified in section 2.3.4.12. If the array of bytes is not an
+         *    integral multiple of blockSize bytes, pad the array with 0x00 to an integral multiple of
+         *    blockSize bytes.
+         * 4. Use base64 to encode the result of step 3.
+         */
+        byte[] keyspec = hashInput(ver, pwHash, kCryptoKeyBlock, ver.getEncryptedKey(), Cipher.DECRYPT_MODE);
+        keyspec = getBlock0(keyspec, header.getKeySize()/8);
+        SecretKeySpec secretKey = new SecretKeySpec(keyspec, header.getCipherAlgorithm().jceId);
+
+        /*
+         * 1. Obtain the intermediate key by decrypting the encryptedKeyValue from a KeyEncryptor
+         *    contained within the KeyEncryptors sequence. Use this key for encryption operations in the
+         *    remaining steps of this section.
+         * 2. Generate a random array of bytes, known as Salt, of the same length as the value of the
+         *    KeyData.hashSize attribute.
+         * 3. Encrypt the random array of bytes generated in step 2 by using the binary form of the
+         *    KeyData.saltValue attribute and a blockKey byte array consisting of the following bytes: 0x5f,
+         *    0xb2, 0xad, 0x01, 0x0c, 0xb9, 0xe1, and 0xf6 used to form an initialization vector as specified in
+         *    section 2.3.4.12. If the array of bytes is not an integral multiple of blockSize bytes, pad the
+         *    array with 0x00 to the next integral multiple of blockSize bytes.
+         * 4. Assign the encryptedHmacKey attribute to the base64-encoded form of the result of step 3.
+         */
+        byte[] vec = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityKeyBlock, blockSize);
+        CipherAlgorithm cipherAlgo = header.getCipherAlgorithm();
+        Cipher cipher = getCipher(secretKey, cipherAlgo, header.getChainingMode(), vec, Cipher.DECRYPT_MODE);
+        byte[] hmacKey = cipher.doFinal(header.getEncryptedHmacKey());
+        hmacKey = getBlock0(hmacKey, header.getHashAlgorithm().hashSize);
+
+        /*
+         * 5. Generate an HMAC, as specified in [RFC2104], of the encrypted form of the data (message),
+         *    which the DataIntegrity element will verify by using the Salt generated in step 2 as the key.
+         *    Note that the entire EncryptedPackage stream (1), including the StreamSize field, MUST be
+         *    used as the message.
+         * 6. Encrypt the HMAC as in step 3 by using a blockKey byte array consisting of the following bytes:
+         *    0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, and 0x33.
+         * 7. Assign the encryptedHmacValue attribute to the base64-encoded form of the result of step 6.
+         */
+        vec = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityValueBlock, blockSize);
+        cipher = getCipher(secretKey, cipherAlgo, ver.getChainingMode(), vec, Cipher.DECRYPT_MODE);
+        byte[] hmacValue = cipher.doFinal(header.getEncryptedHmacValue());
+        hmacValue = getBlock0(hmacValue, header.getHashAlgorithm().hashSize);
+
+        if (Arrays.equals(verifierHashDec, verifierHash)) {
+            setSecretKey(secretKey);
+            setIntegrityHmacKey(hmacKey);
+            setIntegrityHmacValue(hmacValue);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    protected static int getNextBlockSize(int inputLen, int blockSize) {
+        return (int)Math.ceil(inputLen / (double)blockSize) * blockSize;
+    }
+
+    /* package */ static byte[] hashInput(AgileEncryptionVerifier ver, byte[] pwHash, byte[] blockKey, byte[] inputKey, int cipherMode) {
+        CipherAlgorithm cipherAlgo = ver.getCipherAlgorithm();
+        ChainingMode chainMode = ver.getChainingMode();
+        int keySize = ver.getKeySize()/8;
+        int blockSize = ver.getBlockSize();
+        HashAlgorithm hashAlgo = ver.getHashAlgorithm();
+
+        byte[] intermedKey = generateKey(pwHash, hashAlgo, blockKey, keySize);
+        SecretKey skey = new SecretKeySpec(intermedKey, cipherAlgo.jceId);
+        byte[] iv = generateIv(hashAlgo, ver.getSalt(), null, blockSize);
+        Cipher cipher = getCipher(skey, cipherAlgo, chainMode, iv, cipherMode);
+        byte[] hashFinal;
+
+        try {
+            inputKey = getBlock0(inputKey, getNextBlockSize(inputKey.length, blockSize));
+            hashFinal = cipher.doFinal(inputKey);
+            return hashFinal;
+        } catch (GeneralSecurityException e) {
+            throw new EncryptedDocumentException(e);
+        }
+    }
+
+    @Override
+    public InputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException {
+        DocumentInputStream dis = dir.createDocumentInputStream(DEFAULT_POIFS_ENTRY);
+        _length = dis.readLong();
+        return new AgileCipherInputStream(dis, _length);
+    }
+
+    @Override
+    public long getLength(){
+        if(_length == -1) {
+            throw new IllegalStateException("EcmaDecryptor.getDataStream() was not called");
+        }
+        return _length;
+    }
+
+
+    protected static Cipher initCipherForBlock(Cipher existing, int block, boolean lastChunk, EncryptionInfo encryptionInfo, SecretKey skey, int encryptionMode)
+    throws GeneralSecurityException {
+        EncryptionHeader header = encryptionInfo.getHeader();
+        String padding = (lastChunk ? "PKCS5Padding" : "NoPadding");
+        if (existing == null || !existing.getAlgorithm().endsWith(padding)) {
+            existing = getCipher(skey, header.getCipherAlgorithm(), header.getChainingMode(), header.getKeySalt(), encryptionMode, padding);
+        }
+
+        byte[] blockKey = new byte[4];
+        LittleEndian.putInt(blockKey, 0, block);
+        byte[] iv = generateIv(header.getHashAlgorithm(), header.getKeySalt(), blockKey, header.getBlockSize());
+
+        AlgorithmParameterSpec aps;
+        if (header.getCipherAlgorithm() == CipherAlgorithm.rc2) {
+            aps = new RC2ParameterSpec(skey.getEncoded().length*8, iv);
+        } else {
+            aps = new IvParameterSpec(iv);
+        }
+
+        existing.init(encryptionMode, skey, aps);
+
+        return existing;
+    }
+
+    /**
+     * 2.3.4.15 Data Encryption (Agile Encryption)
+     *
+     * The EncryptedPackage stream (1) MUST be encrypted in 4096-byte segments to facilitate nearly
+     * random access while allowing CBC modes to be used in the encryption process.
+     * The initialization vector for the encryption process MUST be obtained by using the zero-based
+     * segment number as a blockKey and the binary form of the KeyData.saltValue as specified in
+     * section 2.3.4.12. The block number MUST be represented as a 32-bit unsigned integer.
+     * Data blocks MUST then be encrypted by using the initialization vector and the intermediate key
+     * obtained by decrypting the encryptedKeyValue from a KeyEncryptor contained within the
+     * KeyEncryptors sequence as specified in section 2.3.4.10. The final data block MUST be padded to
+     * the next integral multiple of the KeyData.blockSize value. Any padding bytes can be used. Note
+     * that the StreamSize field of the EncryptedPackage field specifies the number of bytes of
+     * unencrypted data as specified in section 2.3.4.4.
+     */
+    private class AgileCipherInputStream extends ChunkedCipherInputStream {
+        public AgileCipherInputStream(DocumentInputStream stream, long size)
+        throws GeneralSecurityException {
+            super(stream, size, 4096);
+        }
+
+        // TODO: calculate integrity hmac while reading the stream
+        // for a post-validation of the data
+
+        @Override
+        protected Cipher initCipherForBlock(Cipher cipher, int block)
+        throws GeneralSecurityException {
+            return AgileDecryptor.initCipherForBlock(cipher, block, false, getEncryptionInfo(), getSecretKey(), Cipher.DECRYPT_MODE);
+        }
+    }
+
+    @Override
+    public AgileDecryptor copy() {
+        return new AgileDecryptor(this);
+    }
+}
diff --git a/src/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java b/src/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java
new file mode 100644 (file)
index 0000000..78c289f
--- /dev/null
@@ -0,0 +1,140 @@
+/* ====================================================================
+   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.poifs.crypt.agile;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.poifs.crypt.ChainingMode;
+import org.apache.poi.poifs.crypt.CipherAlgorithm;
+import org.apache.poi.poifs.crypt.EncryptionHeader;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.util.GenericRecordUtil;
+
+public class AgileEncryptionHeader extends EncryptionHeader {
+    private byte[] encryptedHmacKey;
+    private byte[] encryptedHmacValue;
+
+    public AgileEncryptionHeader(String descriptor) {
+        this(AgileEncryptionInfoBuilder.parseDescriptor(descriptor));
+    }
+
+    public AgileEncryptionHeader(AgileEncryptionHeader other) {
+        super(other);
+        encryptedHmacKey = (other.encryptedHmacKey == null) ? null : other.encryptedHmacKey.clone();
+        encryptedHmacValue = (other.encryptedHmacValue == null) ? null : other.encryptedHmacValue.clone();
+    }
+
+    protected AgileEncryptionHeader(EncryptionDocument ed) {
+        KeyData keyData;
+        try {
+            keyData = ed.getKeyData();
+            if (keyData == null) {
+                throw new NullPointerException("keyData not set");
+            }
+        } catch (Exception e) {
+            throw new EncryptedDocumentException("Unable to parse keyData");
+        }
+
+        int keyBits = keyData.getKeyBits();
+
+        CipherAlgorithm ca = keyData.getCipherAlgorithm();
+        setCipherAlgorithm(ca);
+        setCipherProvider(ca.provider);
+
+        setKeySize(keyBits);
+        setFlags(0);
+        setSizeExtra(0);
+        setCspName(null);
+        setBlockSize(keyData.getBlockSize());
+
+        setChainingMode(keyData.getCipherChaining());
+
+        if (getChainingMode() != ChainingMode.cbc && getChainingMode() != ChainingMode.cfb) {
+            throw new EncryptedDocumentException("Unsupported chaining mode - "+ keyData.getCipherChaining());
+        }
+
+        int hashSize = keyData.getHashSize();
+
+        HashAlgorithm ha = keyData.getHashAlgorithm();
+        setHashAlgorithm(ha);
+
+        if (getHashAlgorithm().hashSize != hashSize) {
+            throw new EncryptedDocumentException("Unsupported hash algorithm: " +
+                    keyData.getHashAlgorithm() + " @ " + hashSize + " bytes");
+        }
+
+        int saltLength = keyData.getSaltSize();
+        setKeySalt(keyData.getSaltValue());
+        if (getKeySalt().length != saltLength) {
+            throw new EncryptedDocumentException("Invalid salt length");
+        }
+
+        DataIntegrity di = ed.getDataIntegrity();
+        setEncryptedHmacKey(di.getEncryptedHmacKey());
+        setEncryptedHmacValue(di.getEncryptedHmacValue());
+    }
+
+
+    public AgileEncryptionHeader(CipherAlgorithm algorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode chainingMode) {
+        setCipherAlgorithm(algorithm);
+        setHashAlgorithm(hashAlgorithm);
+        setKeySize(keyBits);
+        setBlockSize(blockSize);
+        setChainingMode(chainingMode);
+    }
+
+    // make method visible for this package
+    @Override
+    public void setKeySalt(byte[] salt) {
+        if (salt == null || salt.length != getBlockSize()) {
+            throw new EncryptedDocumentException("invalid verifier salt");
+        }
+        super.setKeySalt(salt);
+    }
+
+    public byte[] getEncryptedHmacKey() {
+        return encryptedHmacKey;
+    }
+
+    protected void setEncryptedHmacKey(byte[] encryptedHmacKey) {
+        this.encryptedHmacKey = (encryptedHmacKey == null) ? null : encryptedHmacKey.clone();
+    }
+
+    public byte[] getEncryptedHmacValue() {
+        return encryptedHmacValue;
+    }
+
+    protected void setEncryptedHmacValue(byte[] encryptedHmacValue) {
+        this.encryptedHmacValue = (encryptedHmacValue == null) ? null : encryptedHmacValue.clone();
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "base", super::getGenericProperties,
+            "encryptedHmacKey", this::getEncryptedHmacKey,
+            "encryptedHmacValue", this::getEncryptedHmacValue
+        );
+    }
+
+    @Override
+    public AgileEncryptionHeader copy() {
+        return new AgileEncryptionHeader(this);
+    }
+}
diff --git a/src/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionInfoBuilder.java b/src/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionInfoBuilder.java
new file mode 100644 (file)
index 0000000..0674305
--- /dev/null
@@ -0,0 +1,111 @@
+/* ====================================================================
+   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.poifs.crypt.agile;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.poifs.crypt.ChainingMode;
+import org.apache.poi.poifs.crypt.CipherAlgorithm;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.EncryptionInfoBuilder;
+import org.apache.poi.poifs.crypt.EncryptionMode;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.XMLHelper;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {
+
+    @Override
+    public void initialize(EncryptionInfo info, LittleEndianInput dis) throws IOException {
+        EncryptionDocument ed = parseDescriptor((InputStream)dis);
+        info.setHeader(new AgileEncryptionHeader(ed));
+        info.setVerifier(new AgileEncryptionVerifier(ed));
+        if (info.getVersionMajor() == EncryptionMode.agile.versionMajor
+            && info.getVersionMinor() == EncryptionMode.agile.versionMinor) {
+            AgileDecryptor dec = new AgileDecryptor();
+            dec.setEncryptionInfo(info);
+            info.setDecryptor(dec);
+            AgileEncryptor enc = new AgileEncryptor();
+            enc.setEncryptionInfo(info);
+            info.setEncryptor(enc);
+        }
+    }
+
+    @Override
+    public void initialize(EncryptionInfo info, CipherAlgorithm cipherAlgorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode chainingMode) {
+        if (cipherAlgorithm == null) {
+            cipherAlgorithm = CipherAlgorithm.aes128;
+        }
+        if (cipherAlgorithm == CipherAlgorithm.rc4) {
+            throw new EncryptedDocumentException("RC4 must not be used with agile encryption.");
+        }
+        if (hashAlgorithm == null) {
+            hashAlgorithm = HashAlgorithm.sha1;
+        }
+        if (chainingMode == null) {
+            chainingMode = ChainingMode.cbc;
+        }
+        if (!(chainingMode == ChainingMode.cbc || chainingMode == ChainingMode.cfb)) {
+            throw new EncryptedDocumentException("Agile encryption only supports CBC/CFB chaining.");
+        }
+        if (keyBits == -1) {
+            keyBits = cipherAlgorithm.defaultKeySize;
+        }
+        if (blockSize == -1) {
+            blockSize = cipherAlgorithm.blockSize;
+        }
+        boolean found = false;
+        for (int ks : cipherAlgorithm.allowedKeySize) {
+            found |= (ks == keyBits);
+        }
+        if (!found) {
+            throw new EncryptedDocumentException("KeySize "+keyBits+" not allowed for Cipher "+ cipherAlgorithm);
+        }
+        info.setHeader(new AgileEncryptionHeader(cipherAlgorithm, hashAlgorithm, keyBits, blockSize, chainingMode));
+        info.setVerifier(new AgileEncryptionVerifier(cipherAlgorithm, hashAlgorithm, keyBits, blockSize, chainingMode));
+        AgileDecryptor dec = new AgileDecryptor();
+        dec.setEncryptionInfo(info);
+        info.setDecryptor(dec);
+        AgileEncryptor enc = new AgileEncryptor();
+        enc.setEncryptionInfo(info);
+        info.setEncryptor(enc);
+    }
+
+    protected static EncryptionDocument parseDescriptor(String descriptor) {
+        return parseDescriptor(new InputSource(descriptor));
+    }
+
+    protected static EncryptionDocument parseDescriptor(InputStream descriptor) {
+        return parseDescriptor(new InputSource(descriptor));
+    }
+
+    private static EncryptionDocument parseDescriptor(InputSource descriptor) {
+        try {
+            Document doc = XMLHelper.newDocumentBuilder().parse(descriptor);
+            EncryptionDocument ed = new EncryptionDocument();
+            ed.parse(doc);
+            return ed;
+        } catch (SAXException|IOException e) {
+            throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);
+        }
+    }
+}
diff --git a/src/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java b/src/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java
new file mode 100644 (file)
index 0000000..6699b54
--- /dev/null
@@ -0,0 +1,185 @@
+/* ====================================================================
+   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.poifs.crypt.agile;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.poifs.crypt.ChainingMode;
+import org.apache.poi.poifs.crypt.CipherAlgorithm;
+import org.apache.poi.poifs.crypt.EncryptionVerifier;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+
+/**
+ * Used when checking if a key is valid for a document
+ */
+public class AgileEncryptionVerifier extends EncryptionVerifier {
+
+    private int keyBits = -1;
+    private int blockSize = -1;
+
+    @SuppressWarnings("unused")
+    public AgileEncryptionVerifier(String descriptor) {
+        this(AgileEncryptionInfoBuilder.parseDescriptor(descriptor));
+    }
+
+    protected AgileEncryptionVerifier(EncryptionDocument ed) {
+        PasswordKeyEncryptor keyData = null;
+        for (KeyEncryptor ke : ed.getKeyEncryptors()) {
+            keyData = ke.getPasswordKeyEncryptor();
+            if (keyData != null) {
+                break;
+            }
+        }
+
+        if (keyData == null) {
+            throw new NullPointerException("encryptedKey not set");
+        }
+
+        setCipherAlgorithm(keyData.getCipherAlgorithm());
+        setKeySize(keyData.getKeyBits());
+
+        int blockSize = keyData.getBlockSize();
+        setBlockSize(blockSize);
+
+        int hashSize = keyData.getHashSize();
+
+        HashAlgorithm ha = keyData.getHashAlgorithm();
+        setHashAlgorithm(ha);
+
+        if (getHashAlgorithm().hashSize != hashSize) {
+            throw new EncryptedDocumentException("Unsupported hash algorithm: " +
+                    keyData.getHashAlgorithm() + " @ " + hashSize + " bytes");
+        }
+
+        setSpinCount(keyData.getSpinCount());
+        setEncryptedVerifier(keyData.getEncryptedVerifierHashInput());
+        setSalt(keyData.getSaltValue());
+        setEncryptedKey(keyData.getEncryptedKeyValue());
+        setEncryptedVerifierHash(keyData.getEncryptedVerifierHashValue());
+
+        int saltSize = keyData.getSaltSize();
+        if (saltSize != getSalt().length) {
+            throw new EncryptedDocumentException("Invalid salt size");
+        }
+
+        setChainingMode(keyData.getCipherChaining());
+        if (keyData.getCipherChaining() != ChainingMode.cbc && keyData.getCipherChaining() != ChainingMode.cfb) {
+            throw new EncryptedDocumentException("Unsupported chaining mode - "+ keyData.getCipherChaining());
+        }
+    }
+
+    public AgileEncryptionVerifier(CipherAlgorithm cipherAlgorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode chainingMode) {
+        setCipherAlgorithm(cipherAlgorithm);
+        setHashAlgorithm(hashAlgorithm);
+        setChainingMode(chainingMode);
+        setKeySize(keyBits);
+        setBlockSize(blockSize);
+        setSpinCount(100000); // TODO: use parameter
+    }
+
+    public AgileEncryptionVerifier(AgileEncryptionVerifier other) {
+        super(other);
+        keyBits = other.keyBits;
+        blockSize = other.blockSize;
+    }
+
+    @Override
+    public void setSalt(byte[] salt) {
+        if (salt == null || salt.length != getCipherAlgorithm().blockSize) {
+            throw new EncryptedDocumentException("invalid verifier salt");
+        }
+        super.setSalt(salt);
+    }
+
+    // make method visible for this package
+    @Override
+    public void setEncryptedVerifier(byte[] encryptedVerifier) {
+        super.setEncryptedVerifier(encryptedVerifier);
+    }
+
+    // make method visible for this package
+    @Override
+    public void setEncryptedVerifierHash(byte[] encryptedVerifierHash) {
+        super.setEncryptedVerifierHash(encryptedVerifierHash);
+    }
+
+    // make method visible for this package
+    @Override
+    public void setEncryptedKey(byte[] encryptedKey) {
+        super.setEncryptedKey(encryptedKey);
+    }
+
+    @Override
+    public AgileEncryptionVerifier copy() {
+        return new AgileEncryptionVerifier(this);
+    }
+
+
+    /**
+     * The keysize (in bits) of the verifier data. This usually equals the keysize of the header,
+     * but only on a few exceptions, like files generated by Office for Mac, can be
+     * different.
+     *
+     * @return the keysize (in bits) of the verifier.
+     */
+    public int getKeySize() {
+        return keyBits;
+    }
+
+
+    /**
+     * The blockSize (in bytes) of the verifier data.
+     * This usually equals the blocksize of the header.
+     *
+     * @return the blockSize (in bytes) of the verifier,
+     */
+    public int getBlockSize() {
+        return blockSize;
+    }
+
+    /**
+     * Sets the keysize (in bits) of the verifier
+     *
+     * @param keyBits the keysize (in bits)
+     */
+    public void setKeySize(int keyBits) {
+        this.keyBits = keyBits;
+        for (int allowedBits : getCipherAlgorithm().allowedKeySize) {
+            if (allowedBits == keyBits) {
+                return;
+            }
+        }
+        throw new EncryptedDocumentException("KeySize "+keyBits+" not allowed for cipher "+getCipherAlgorithm());
+    }
+
+
+    /**
+     * Sets the blockSize (in bytes) of the verifier
+     *
+     * @param blockSize the blockSize (in bytes)
+     */
+    public void setBlockSize(int blockSize) {
+        this.blockSize = blockSize;
+    }
+
+    @Override
+    public final void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) {
+        super.setCipherAlgorithm(cipherAlgorithm);
+        if (cipherAlgorithm.allowedKeySize.length == 1) {
+            setKeySize(cipherAlgorithm.defaultKeySize);
+        }
+    }
+}
diff --git a/src/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java b/src/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java
new file mode 100644 (file)
index 0000000..9200fb3
--- /dev/null
@@ -0,0 +1,388 @@
+/* ====================================================================
+   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.poifs.crypt.agile;
+
+import static org.apache.poi.poifs.crypt.CryptoFunctions.getBlock0;
+import static org.apache.poi.poifs.crypt.CryptoFunctions.getCipher;
+import static org.apache.poi.poifs.crypt.CryptoFunctions.getMessageDigest;
+import static org.apache.poi.poifs.crypt.CryptoFunctions.hashPassword;
+import static org.apache.poi.poifs.crypt.DataSpaceMapUtils.createEncryptionEntry;
+import static org.apache.poi.poifs.crypt.EncryptionInfo.ENCRYPTION_INFO_ENTRY;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.getNextBlockSize;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.hashInput;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kCryptoKeyBlock;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kHashedVerifierBlock;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kIntegrityKeyBlock;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kIntegrityValueBlock;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kVerifierInputBlock;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+import java.util.Random;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.poifs.crypt.ChunkedCipherOutputStream;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
+import org.apache.poi.poifs.crypt.DataSpaceMapUtils;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.Encryptor;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.util.XMLHelper;
+import org.w3c.dom.Document;
+
+public class AgileEncryptor extends Encryptor {
+
+    //arbitrarily selected; may need to increase
+    private static final int MAX_RECORD_LENGTH = 1_000_000;
+
+    private byte[] integritySalt;
+    private byte[] pwHash;
+
+       protected AgileEncryptor() {}
+
+    protected AgileEncryptor(AgileEncryptor other) {
+           super(other);
+           integritySalt = (other.integritySalt == null) ? null : other.integritySalt.clone();
+           pwHash = (other.pwHash == null) ? null : other.pwHash.clone();
+    }
+
+    @Override
+    public void confirmPassword(String password) {
+        // see [MS-OFFCRYPTO] - 2.3.3 EncryptionVerifier
+        Random r = new SecureRandom();
+        AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
+        int blockSize = header.getBlockSize();
+        int keySize = header.getKeySize()/8;
+        int hashSize = header.getHashAlgorithm().hashSize;
+
+        byte[] newVerifierSalt = IOUtils.safelyAllocate(blockSize, MAX_RECORD_LENGTH)
+             , newVerifier = IOUtils.safelyAllocate(blockSize, MAX_RECORD_LENGTH)
+             , newKeySalt = IOUtils.safelyAllocate(blockSize, MAX_RECORD_LENGTH)
+             , newKeySpec = IOUtils.safelyAllocate(keySize, MAX_RECORD_LENGTH)
+             , newIntegritySalt = IOUtils.safelyAllocate(hashSize, MAX_RECORD_LENGTH);
+        r.nextBytes(newVerifierSalt); // blocksize
+        r.nextBytes(newVerifier); // blocksize
+        r.nextBytes(newKeySalt); // blocksize
+        r.nextBytes(newKeySpec); // keysize
+        r.nextBytes(newIntegritySalt); // hashsize
+
+        confirmPassword(password, newKeySpec, newKeySalt, newVerifierSalt, newVerifier, newIntegritySalt);
+    }
+
+       @Override
+    public void confirmPassword(String password, byte[] keySpec, byte[] keySalt, byte[] verifier, byte[] verifierSalt, byte[] integritySalt) {
+        AgileEncryptionVerifier ver = (AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
+        AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
+
+        ver.setSalt(verifierSalt);
+        header.setKeySalt(keySalt);
+
+        int blockSize = header.getBlockSize();
+
+        pwHash = hashPassword(password, ver.getHashAlgorithm(), verifierSalt, ver.getSpinCount());
+
+        /*
+         * encryptedVerifierHashInput: This attribute MUST be generated by using the following steps:
+         * 1. Generate a random array of bytes with the number of bytes used specified by the saltSize
+         *    attribute.
+         * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password,
+         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
+         *    consisting of the following bytes: 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, and 0x79.
+         * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue
+         *    attribute as an initialization vector as specified in section 2.3.4.12. If the array of bytes is not an
+         *    integral multiple of blockSize bytes, pad the array with 0x00 to the next integral multiple of
+         *    blockSize bytes.
+         * 4. Use base64 to encode the result of step 3.
+         */
+        byte[] encryptedVerifier = hashInput(ver, pwHash, kVerifierInputBlock, verifier, Cipher.ENCRYPT_MODE);
+        ver.setEncryptedVerifier(encryptedVerifier);
+
+
+        /*
+         * encryptedVerifierHashValue: This attribute MUST be generated by using the following steps:
+         * 1. Obtain the hash value of the random array of bytes generated in step 1 of the steps for
+         *    encryptedVerifierHashInput.
+         * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password,
+         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
+         *    consisting of the following bytes: 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, and 0x4e.
+         * 3. Encrypt the hash value obtained in step 1 by using the binary form of the saltValue attribute as
+         *    an initialization vector as specified in section 2.3.4.12. If hashSize is not an integral multiple of
+         *    blockSize bytes, pad the hash value with 0x00 to an integral multiple of blockSize bytes.
+         * 4. Use base64 to encode the result of step 3.
+         */
+        MessageDigest hashMD = getMessageDigest(ver.getHashAlgorithm());
+        byte[] hashedVerifier = hashMD.digest(verifier);
+        byte[] encryptedVerifierHash = hashInput(ver, pwHash, kHashedVerifierBlock, hashedVerifier, Cipher.ENCRYPT_MODE);
+        ver.setEncryptedVerifierHash(encryptedVerifierHash);
+
+        /*
+         * encryptedKeyValue: This attribute MUST be generated by using the following steps:
+         * 1. Generate a random array of bytes that is the same size as specified by the
+         *    Encryptor.KeyData.keyBits attribute of the parent element.
+         * 2. Generate an encryption key as specified in section 2.3.4.11, using the user-supplied password,
+         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
+         *    consisting of the following bytes: 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, and 0xd6.
+         * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue
+         *    attribute as an initialization vector as specified in section 2.3.4.12. If the array of bytes is not an
+         *    integral multiple of blockSize bytes, pad the array with 0x00 to an integral multiple of
+         *    blockSize bytes.
+         * 4. Use base64 to encode the result of step 3.
+         */
+        byte[] encryptedKey = hashInput(ver, pwHash, kCryptoKeyBlock, keySpec, Cipher.ENCRYPT_MODE);
+        ver.setEncryptedKey(encryptedKey);
+
+        SecretKey secretKey = new SecretKeySpec(keySpec, header.getCipherAlgorithm().jceId);
+        setSecretKey(secretKey);
+
+        /*
+         * 2.3.4.14 DataIntegrity Generation (Agile Encryption)
+         *
+         * The DataIntegrity element contained within an Encryption element MUST be generated by using
+         * the following steps:
+         * 1. Obtain the intermediate key by decrypting the encryptedKeyValue from a KeyEncryptor
+         *    contained within the KeyEncryptors sequence. Use this key for encryption operations in the
+         *    remaining steps of this section.
+         * 2. Generate a random array of bytes, known as Salt, of the same length as the value of the
+         *    KeyData.hashSize attribute.
+         * 3. Encrypt the random array of bytes generated in step 2 by using the binary form of the
+         *    KeyData.saltValue attribute and a blockKey byte array consisting of the following bytes:
+         *    0x5f, 0xb2, 0xad, 0x01, 0x0c, 0xb9, 0xe1, and 0xf6 used to form an initialization vector as
+         *    specified in section 2.3.4.12. If the array of bytes is not an integral multiple of blockSize
+         *    bytes, pad the array with 0x00 to the next integral multiple of blockSize bytes.
+         * 4. Assign the encryptedHmacKey attribute to the base64-encoded form of the result of step 3.
+         * 5. Generate an HMAC, as specified in [RFC2104], of the encrypted form of the data (message),
+         *    which the DataIntegrity element will verify by using the Salt generated in step 2 as the key.
+         *    Note that the entire EncryptedPackage stream (1), including the StreamSize field, MUST be
+         *    used as the message.
+         * 6. Encrypt the HMAC as in step 3 by using a blockKey byte array consisting of the following bytes:
+         *    0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, and 0x33.
+         * 7.  Assign the encryptedHmacValue attribute to the base64-encoded form of the result of step 6.
+         */
+        this.integritySalt = integritySalt.clone();
+
+        try {
+            byte[] vec = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityKeyBlock, header.getBlockSize());
+            Cipher cipher = getCipher(secretKey, header.getCipherAlgorithm(), header.getChainingMode(), vec, Cipher.ENCRYPT_MODE);
+            byte[] hmacKey = getBlock0(this.integritySalt, getNextBlockSize(this.integritySalt.length, blockSize));
+            byte[] encryptedHmacKey = cipher.doFinal(hmacKey);
+            header.setEncryptedHmacKey(encryptedHmacKey);
+        } catch (GeneralSecurityException e) {
+            throw new EncryptedDocumentException(e);
+        }
+       }
+
+    @Override
+    public OutputStream getDataStream(DirectoryNode dir)
+            throws IOException, GeneralSecurityException {
+        // TODO: initialize headers
+        return new AgileCipherOutputStream(dir);
+    }
+
+    /**
+     * Generate an HMAC, as specified in [RFC2104], of the encrypted form of the data (message),
+     * which the DataIntegrity element will verify by using the Salt generated in step 2 as the key.
+     * Note that the entire EncryptedPackage stream (1), including the StreamSize field, MUST be
+     * used as the message.
+     *
+     * Encrypt the HMAC as in step 3 by using a blockKey byte array consisting of the following bytes:
+     * 0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, and 0x33.
+     **/
+    protected void updateIntegrityHMAC(File tmpFile, int oleStreamSize) throws GeneralSecurityException, IOException {
+        // as the integrity hmac needs to contain the StreamSize,
+        // it's not possible to calculate it on-the-fly while buffering
+        // TODO: add stream size parameter to getDataStream()
+        AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
+        int blockSize = header.getBlockSize();
+        HashAlgorithm hashAlgo = header.getHashAlgorithm();
+        Mac integrityMD = CryptoFunctions.getMac(hashAlgo);
+        byte[] hmacKey = getBlock0(this.integritySalt, getNextBlockSize(this.integritySalt.length, blockSize));
+        integrityMD.init(new SecretKeySpec(hmacKey, hashAlgo.jceHmacId));
+
+        byte[] buf = new byte[1024];
+        LittleEndian.putLong(buf, 0, oleStreamSize);
+        integrityMD.update(buf, 0, LittleEndianConsts.LONG_SIZE);
+
+        try (InputStream fis = new FileInputStream(tmpFile)) {
+            int readBytes;
+            while ((readBytes = fis.read(buf)) != -1) {
+                integrityMD.update(buf, 0, readBytes);
+            }
+        }
+
+        byte[] hmacValue = integrityMD.doFinal();
+        byte[] hmacValueFilled = getBlock0(hmacValue, getNextBlockSize(hmacValue.length, blockSize));
+
+        byte[] iv = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityValueBlock, blockSize);
+        Cipher cipher = CryptoFunctions.getCipher(getSecretKey(), header.getCipherAlgorithm(), header.getChainingMode(), iv, Cipher.ENCRYPT_MODE);
+        byte[] encryptedHmacValue = cipher.doFinal(hmacValueFilled);
+
+        header.setEncryptedHmacValue(encryptedHmacValue);
+    }
+
+    protected EncryptionDocument createEncryptionDocument() {
+        AgileEncryptionVerifier ver = (AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
+        AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
+
+        EncryptionDocument ed = new EncryptionDocument();
+        KeyData keyData = new KeyData();
+        ed.setKeyData(keyData);
+
+        KeyEncryptor keyEnc = new KeyEncryptor();
+        ed.getKeyEncryptors().add(keyEnc);
+
+        PasswordKeyEncryptor keyPass = new PasswordKeyEncryptor();
+        keyEnc.setPasswordKeyEncryptor(keyPass);
+
+        keyPass.setSpinCount(ver.getSpinCount());
+
+        keyData.setSaltSize(header.getBlockSize());
+        keyPass.setSaltSize(ver.getBlockSize());
+
+        keyData.setBlockSize(header.getBlockSize());
+        keyPass.setBlockSize(ver.getBlockSize());
+
+        keyData.setKeyBits(header.getKeySize());
+        keyPass.setKeyBits(ver.getKeySize());
+
+        keyData.setHashSize(header.getHashAlgorithm().hashSize);
+        keyPass.setHashSize(ver.getHashAlgorithm().hashSize);
+
+        // header and verifier have to have the same cipher algorithm
+        if (!header.getCipherAlgorithm().xmlId.equals(ver.getCipherAlgorithm().xmlId)) {
+            throw new EncryptedDocumentException("Cipher algorithm of header and verifier have to match");
+        }
+
+        keyData.setCipherAlgorithm(header.getCipherAlgorithm());
+        keyPass.setCipherAlgorithm(header.getCipherAlgorithm());
+
+        keyData.setCipherChaining(header.getChainingMode());
+        keyPass.setCipherChaining(header.getChainingMode());
+
+        keyData.setHashAlgorithm(header.getHashAlgorithm());
+        keyPass.setHashAlgorithm(ver.getHashAlgorithm());
+
+        keyData.setSaltValue(header.getKeySalt());
+        keyPass.setSaltValue(ver.getSalt());
+        keyPass.setEncryptedVerifierHashInput(ver.getEncryptedVerifier());
+        keyPass.setEncryptedVerifierHashValue(ver.getEncryptedVerifierHash());
+        keyPass.setEncryptedKeyValue(ver.getEncryptedKey());
+
+        DataIntegrity hmacData = new DataIntegrity();
+        ed.setDataIntegrity(hmacData);
+        hmacData.setEncryptedHmacKey(header.getEncryptedHmacKey());
+        hmacData.setEncryptedHmacValue(header.getEncryptedHmacValue());
+
+        return ed;
+    }
+
+    protected void marshallEncryptionDocument(EncryptionDocument ed, LittleEndianByteArrayOutputStream os) {
+        Document doc = XMLHelper.newDocumentBuilder().newDocument();
+        ed.write(doc);
+
+        try {
+            Transformer trans = XMLHelper.newTransformer();
+            trans.setOutputProperty(OutputKeys.METHOD, "xml");
+            trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+            trans.setOutputProperty(OutputKeys.INDENT, "no");
+            trans.setOutputProperty(OutputKeys.STANDALONE, "yes");
+            trans.transform(new DOMSource(doc), new StreamResult(os));
+        } catch (TransformerException e) {
+            throw new EncryptedDocumentException("error marshalling encryption info document", e);
+        }
+    }
+
+    /**
+     * 2.3.4.15 Data Encryption (Agile Encryption)
+     *
+     * The EncryptedPackage stream (1) MUST be encrypted in 4096-byte segments to facilitate nearly
+     * random access while allowing CBC modes to be used in the encryption process.
+     * The initialization vector for the encryption process MUST be obtained by using the zero-based
+     * segment number as a blockKey and the binary form of the KeyData.saltValue as specified in
+     * section 2.3.4.12. The block number MUST be represented as a 32-bit unsigned integer.
+     * Data blocks MUST then be encrypted by using the initialization vector and the intermediate key
+     * obtained by decrypting the encryptedKeyValue from a KeyEncryptor contained within the
+     * KeyEncryptors sequence as specified in section 2.3.4.10. The final data block MUST be padded to
+     * the next integral multiple of the KeyData.blockSize value. Any padding bytes can be used. Note
+     * that the StreamSize field of the EncryptedPackage field specifies the number of bytes of
+     * unencrypted data as specified in section 2.3.4.4.
+     */
+    private class AgileCipherOutputStream extends ChunkedCipherOutputStream {
+        public AgileCipherOutputStream(DirectoryNode dir) throws IOException, GeneralSecurityException {
+            super(dir, 4096);
+        }
+
+        @Override
+        protected Cipher initCipherForBlock(Cipher existing, int block, boolean lastChunk)
+        throws GeneralSecurityException {
+            return AgileDecryptor.initCipherForBlock(existing, block, lastChunk, getEncryptionInfo(), getSecretKey(), Cipher.ENCRYPT_MODE);
+        }
+
+        @Override
+        protected void calculateChecksum(File fileOut, int oleStreamSize)
+        throws GeneralSecurityException, IOException {
+            // integrityHMAC needs to be updated before the encryption document is created
+            updateIntegrityHMAC(fileOut, oleStreamSize);
+        }
+
+        @Override
+        protected void createEncryptionInfoEntry(DirectoryNode dir, File tmpFile)
+        throws IOException {
+            DataSpaceMapUtils.addDefaultDataSpace(dir);
+            createEncryptionEntry(dir, ENCRYPTION_INFO_ENTRY, this::marshallEncryptionRecord);
+        }
+
+        private void marshallEncryptionRecord(LittleEndianByteArrayOutputStream bos) {
+            final EncryptionInfo info = getEncryptionInfo();
+
+            // EncryptionVersionInfo (4 bytes): A Version structure (section 2.1.4), where
+            // Version.vMajor MUST be 0x0004 and Version.vMinor MUST be 0x0004
+            bos.writeShort(info.getVersionMajor());
+            bos.writeShort(info.getVersionMinor());
+            // Reserved (4 bytes): A value that MUST be 0x00000040
+            bos.writeInt(info.getEncryptionFlags());
+
+            EncryptionDocument ed = createEncryptionDocument();
+            marshallEncryptionDocument(ed, bos);
+        }
+    }
+
+    @Override
+    public AgileEncryptor copy() {
+        return new AgileEncryptor(this);
+    }
+}
diff --git a/src/java/org/apache/poi/poifs/crypt/agile/CertificateKeyEncryptor.java b/src/java/org/apache/poi/poifs/crypt/agile/CertificateKeyEncryptor.java
new file mode 100644 (file)
index 0000000..938b04f
--- /dev/null
@@ -0,0 +1,95 @@
+/* ====================================================================
+   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.poifs.crypt.agile;
+
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.getBinAttr;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.setBinAttr;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class CertificateKeyEncryptor {
+
+    /**
+     * A base64-encoded value that specifies the encrypted form of the intermediate key,
+     * which is encrypted with the public key contained within the X509Certificate attribute.
+     */
+    private byte[] encryptedKeyValue;
+
+    /**
+     * A base64-encoded value that specifies a DER-encoded X.509 certificate (1) used to encrypt the intermediate key.
+     * The certificate (1) MUST contain only the public portion of the public-private key pair.
+     */
+    private byte[] x509Certificate;
+
+    /**
+     * A base64-encoded value that specifies the HMAC of the binary data obtained by base64-decoding the X509Certificate
+     * attribute. The hashing algorithm used to derive the HMAC MUST be the hashing algorithm specified for the
+     * Encryption.keyData element. The secret key used to derive the HMAC MUST be the intermediate key. If the
+     * intermediate key is reset, any CertificateKeyEncryptor elements are also reset to contain the new intermediate
+     * key, except that the certVerifier attribute MUST match the value calculated using the current intermediate key,
+     * to verify that the CertificateKeyEncryptor element actually encrypted the current intermediate key. If a
+     * CertificateKeyEncryptor element does not have a correct certVerifier attribute, it MUST be discarded.
+     */
+    private byte[] certVerifier;
+
+    public CertificateKeyEncryptor(Element certificateKey) {
+        if (certificateKey == null) {
+            throw new EncryptedDocumentException("Unable to parse encryption descriptor");
+        }
+        encryptedKeyValue = getBinAttr(certificateKey, "encryptedKeyValue");
+        x509Certificate = getBinAttr(certificateKey, "X509Certificate");
+        certVerifier = getBinAttr(certificateKey, "certVerifier");
+    }
+
+    void write(Element encryption) {
+        Document doc = encryption.getOwnerDocument();
+        Element keyEncryptor = (Element) encryption.appendChild(doc.createElement("keyEncryptor"));
+        keyEncryptor.setAttribute("uri", KeyEncryptor.CERT_NS);
+        Element encryptedKey = (Element) keyEncryptor.appendChild(doc.createElement("c:encryptedKey"));
+
+        setBinAttr(encryptedKey, "encryptedKeyValue", encryptedKeyValue);
+        setBinAttr(encryptedKey, "x509Certificate", x509Certificate);
+        setBinAttr(encryptedKey, "certVerifier", certVerifier);
+    }
+
+    public byte[] getEncryptedKeyValue() {
+        return encryptedKeyValue;
+    }
+
+    public void setEncryptedKeyValue(byte[] encryptedKeyValue) {
+        this.encryptedKeyValue = encryptedKeyValue;
+    }
+
+    public byte[] getX509Certificate() {
+        return x509Certificate;
+    }
+
+    public void setX509Certificate(byte[] x509Certificate) {
+        this.x509Certificate = x509Certificate;
+    }
+
+    public byte[] getCertVerifier() {
+        return certVerifier;
+    }
+
+    public void setCertVerifier(byte[] certVerifier) {
+        this.certVerifier = certVerifier;
+    }
+}
diff --git a/src/java/org/apache/poi/poifs/crypt/agile/DataIntegrity.java b/src/java/org/apache/poi/poifs/crypt/agile/DataIntegrity.java
new file mode 100644 (file)
index 0000000..5d067b0
--- /dev/null
@@ -0,0 +1,82 @@
+/* ====================================================================
+   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.poifs.crypt.agile;
+
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.ENC_NS;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.getBinAttr;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.getTag;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.setBinAttr;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+
+/**
+ * A complex type that specifies data used to verify whether the encrypted data passes an integrity check.
+ * It MUST be generated using the method specified in section 2.3.4.14
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/dd924068(v=office.12).aspx">DataIntegrity Generation</a>
+ */
+public class DataIntegrity {
+    /**
+     * A base64-encoded value that specifies an encrypted key used in calculating the encryptedHmacValue.
+     */
+    private byte[] encryptedHmacKey;
+
+    /**
+     * A base64-encoded value that specifies an HMAC derived from encryptedHmacKey and the encrypted data.
+     */
+    private byte[] encryptedHmacValue;
+
+    public DataIntegrity() {
+
+    }
+
+    public DataIntegrity(Element parent) {
+        Element dataIntegrity = getTag(parent, ENC_NS, "dataIntegrity");
+        if (dataIntegrity == null) {
+            throw new EncryptedDocumentException("Unable to parse encryption descriptor");
+        }
+        encryptedHmacKey = getBinAttr(dataIntegrity, "encryptedHmacKey");
+        encryptedHmacValue = getBinAttr(dataIntegrity, "encryptedHmacValue");
+    }
+
+    void write(Element encryption) {
+        Document doc = encryption.getOwnerDocument();
+        Element dataIntegrity = (Element)encryption.appendChild(doc.createElement("dataIntegrity"));
+        setBinAttr(dataIntegrity, "encryptedHmacKey", encryptedHmacKey);
+        setBinAttr(dataIntegrity, "encryptedHmacValue", encryptedHmacValue);
+    }
+
+    public byte[] getEncryptedHmacKey() {
+        return encryptedHmacKey;
+    }
+
+    public void setEncryptedHmacKey(byte[] encryptedHmacKey) {
+        this.encryptedHmacKey = encryptedHmacKey;
+    }
+
+    public byte[] getEncryptedHmacValue() {
+        return encryptedHmacValue;
+    }
+
+    public void setEncryptedHmacValue(byte[] encryptedHmacValue) {
+        this.encryptedHmacValue = encryptedHmacValue;
+    }
+}
diff --git a/src/java/org/apache/poi/poifs/crypt/agile/EncryptionDocument.java b/src/java/org/apache/poi/poifs/crypt/agile/EncryptionDocument.java
new file mode 100644 (file)
index 0000000..07004d0
--- /dev/null
@@ -0,0 +1,150 @@
+/* ====================================================================
+   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.poifs.crypt.agile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.XMLConstants;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.poi.EncryptedDocumentException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class EncryptionDocument {
+    static final String ENC_NS = "http://schemas.microsoft.com/office/2006/encryption";
+
+    private KeyData keyData;
+
+    /**
+     * All ECMA-376 documents [ECMA-376] encrypted by Microsoft Office using agile encryption will have a DataIntegrity
+     * element present. The schema allows for a DataIntegrity element to not be present because the encryption schema
+     * can be used by applications that do not create ECMA-376 documents [ECMA-376].
+     */
+    private DataIntegrity dataIntegrity;
+
+    private final List<KeyEncryptor> keyEncryptors = new ArrayList<>();
+
+    public EncryptionDocument() {
+
+    }
+
+    public void parse(Document doc) {
+        Element encryption = doc.getDocumentElement();
+        if (!ENC_NS.equals(encryption.getNamespaceURI()) || !"encryption".equals(encryption.getLocalName())) {
+            throw new EncryptedDocumentException("Unable to parse encryption descriptor");
+        }
+        keyData = new KeyData(encryption);
+        dataIntegrity = new DataIntegrity(encryption);
+
+        // The KeyEncryptor element, which MUST be used when encrypting password-protected agile encryption documents,
+        // is either a PasswordKeyEncryptor or a CertificateKeyEncryptor. Exactly one PasswordKeyEncryptor MUST be
+        // present. Zero or more CertificateKeyEncryptor elements are contained within the KeyEncryptors element.
+        Element keyEncryptors = getTag(encryption, ENC_NS, "keyEncryptors");
+        if (keyEncryptors == null) {
+            throw new EncryptedDocumentException("Unable to parse encryption descriptor");
+        }
+        NodeList ke = keyEncryptors.getElementsByTagNameNS(ENC_NS, "keyEncryptor");
+        for (int i=0; i<ke.getLength(); i++) {
+            this.keyEncryptors.add(new KeyEncryptor((Element)ke.item(i)));
+        }
+    }
+
+    public void write(Document doc) {
+        doc.setXmlStandalone(true);
+        Element encryption = (Element)doc.appendChild(doc.createElementNS(ENC_NS, "encryption"));
+        if (keyData != null) {
+            keyData.write(encryption);
+        }
+        if (dataIntegrity != null) {
+            dataIntegrity.write(encryption);
+        }
+        Element keyEncryptors = (Element)encryption.appendChild(doc.createElement("keyEncryptors"));
+        boolean hasPass = false;
+        boolean hasCert = false;
+        for (KeyEncryptor ke : this.keyEncryptors) {
+            ke.write(keyEncryptors);
+            hasPass |= ke.getPasswordKeyEncryptor() != null;
+            hasCert |= ke.getCertificateKeyEncryptor() != null;
+        }
+        if (hasPass) {
+            encryption.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns:p", KeyEncryptor.PASS_NS);
+        }
+        if (hasCert) {
+            encryption.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns:c", KeyEncryptor.CERT_NS);
+        }
+
+    }
+
+
+    public KeyData getKeyData() {
+        return keyData;
+    }
+
+    public void setKeyData(KeyData keyData) {
+        this.keyData = keyData;
+    }
+
+    public DataIntegrity getDataIntegrity() {
+        return dataIntegrity;
+    }
+
+    public void setDataIntegrity(DataIntegrity dataIntegrity) {
+        this.dataIntegrity = dataIntegrity;
+    }
+
+    public List<KeyEncryptor> getKeyEncryptors() {
+        return keyEncryptors;
+    }
+
+    static Element getTag(Element el, String ns, String name) {
+        if (el == null) {
+            return null;
+        }
+        NodeList nl = el.getElementsByTagNameNS(ns, name);
+        return (nl.getLength() > 0) ? (Element)nl.item(0) : null;
+    }
+
+    static Integer getIntAttr(Element el, String name) {
+        String at = el.getAttribute(name);
+        return (at.isEmpty()) ? null : Integer.valueOf(at);
+    }
+
+    static byte[] getBinAttr(Element el, String name) {
+        String at = el.getAttribute(name);
+        return (at.isEmpty()) ? null : Base64.decodeBase64(at);
+    }
+
+    static void setIntAttr(Element el, String name, Integer val) {
+        setAttr(el, name, val == null ? null : val.toString());
+    }
+
+    static void setAttr(Element el, String name, String val) {
+        if (val != null) {
+            el.setAttribute(name, val);
+        }
+    }
+
+    static void setBinAttr(Element el, String name, byte[] val) {
+        if (val != null) {
+            setAttr(el, name, Base64.encodeBase64String(val));
+        }
+    }
+}
diff --git a/src/java/org/apache/poi/poifs/crypt/agile/KeyData.java b/src/java/org/apache/poi/poifs/crypt/agile/KeyData.java
new file mode 100644 (file)
index 0000000..fba57eb
--- /dev/null
@@ -0,0 +1,148 @@
+/* ====================================================================
+   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.poifs.crypt.agile;
+
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.ENC_NS;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.getBinAttr;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.getIntAttr;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.getTag;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.setAttr;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.setBinAttr;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.setIntAttr;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.poifs.crypt.ChainingMode;
+import org.apache.poi.poifs.crypt.CipherAlgorithm;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * A complex type that specifies the encryption used within this element. The saltValue attribute is a base64-encoded
+ * binary value that is randomly generated. The number of bytes required to decode the saltValue attribute MUST be equal
+ * to the value of the saltSize attribute.
+ */
+public class KeyData {
+    private Integer saltSize;
+    private Integer blockSize;
+    private Integer keyBits;
+    private Integer hashSize;
+    private CipherAlgorithm cipherAlgorithm;
+    private ChainingMode cipherChaining;
+    private HashAlgorithm hashAlgorithm;
+    private byte[] saltValue;
+
+    public KeyData() {
+
+    }
+
+    public KeyData(Element parent) {
+        Element keyData = getTag(parent, ENC_NS, "keyData");
+        if (keyData == null) {
+            throw new EncryptedDocumentException("Unable to parse encryption descriptor");
+        }
+        saltSize = getIntAttr(keyData, "saltSize");
+        blockSize = getIntAttr(keyData, "blockSize");
+        keyBits = getIntAttr(keyData, "keyBits");
+        hashSize = getIntAttr(keyData, "hashSize");
+        cipherAlgorithm = CipherAlgorithm.fromXmlId(keyData.getAttribute("cipherAlgorithm"), keyBits);
+        cipherChaining = ChainingMode.fromXmlId(keyData.getAttribute("cipherChaining"));
+        hashAlgorithm = HashAlgorithm.fromEcmaId(keyData.getAttribute("hashAlgorithm"));
+        if (cipherAlgorithm == null || cipherChaining == null || hashAlgorithm == null) {
+            throw new EncryptedDocumentException("Cipher algorithm, chaining mode or hash algorithm was null");
+        }
+        saltValue = getBinAttr(keyData, "saltValue");
+    }
+
+    void write(Element encryption) {
+        Document doc = encryption.getOwnerDocument();
+        Element keyData = (Element)encryption.appendChild(doc.createElement("keyData"));
+        setIntAttr(keyData, "saltSize", saltSize);
+        setIntAttr(keyData, "blockSize", blockSize);
+        setIntAttr(keyData, "keyBits", keyBits);
+        setIntAttr(keyData, "hashSize", hashSize);
+        setAttr(keyData, "cipherAlgorithm", cipherAlgorithm == null ? null : cipherAlgorithm.xmlId);
+        setAttr(keyData, "cipherChaining", cipherChaining == null ? null : cipherChaining.xmlId);
+        setAttr(keyData, "hashAlgorithm", hashAlgorithm == null ? null : hashAlgorithm.ecmaString);
+        setBinAttr(keyData, "saltValue", saltValue);
+    }
+
+    public Integer getSaltSize() {
+        return saltSize;
+    }
+
+    public void setSaltSize(Integer saltSize) {
+        this.saltSize = saltSize;
+    }
+
+    public Integer getBlockSize() {
+        return blockSize;
+    }
+
+    public void setBlockSize(Integer blockSize) {
+        this.blockSize = blockSize;
+    }
+
+    public Integer getKeyBits() {
+        return keyBits;
+    }
+
+    public void setKeyBits(Integer keyBits) {
+        this.keyBits = keyBits;
+    }
+
+    public Integer getHashSize() {
+        return hashSize;
+    }
+
+    public void setHashSize(Integer hashSize) {
+        this.hashSize = hashSize;
+    }
+
+    public CipherAlgorithm getCipherAlgorithm() {
+        return cipherAlgorithm;
+    }
+
+    public void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) {
+        this.cipherAlgorithm = cipherAlgorithm;
+    }
+
+    public ChainingMode getCipherChaining() {
+        return cipherChaining;
+    }
+
+    public void setCipherChaining(ChainingMode cipherChaining) {
+        this.cipherChaining = cipherChaining;
+    }
+
+    public HashAlgorithm getHashAlgorithm() {
+        return hashAlgorithm;
+    }
+
+    public void setHashAlgorithm(HashAlgorithm hashAlgorithm) {
+        this.hashAlgorithm = hashAlgorithm;
+    }
+
+    public byte[] getSaltValue() {
+        return saltValue;
+    }
+
+    public void setSaltValue(byte[] saltValue) {
+        this.saltValue = (saltValue == null) ? null : saltValue.clone();
+    }
+}
diff --git a/src/java/org/apache/poi/poifs/crypt/agile/KeyEncryptor.java b/src/java/org/apache/poi/poifs/crypt/agile/KeyEncryptor.java
new file mode 100644 (file)
index 0000000..c7e591d
--- /dev/null
@@ -0,0 +1,81 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.poifs.crypt.agile;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * A sequence of KeyEncryptor elements. Exactly one KeyEncryptors element MUST be present, and the KeyEncryptors element
+ * MUST contain at least one KeyEncryptor.
+ */
+public class KeyEncryptor {
+    static final String PASS_NS = "http://schemas.microsoft.com/office/2006/keyEncryptor/password";
+    static final String CERT_NS = "http://schemas.microsoft.com/office/2006/keyEncryptor/certificate";
+
+    private PasswordKeyEncryptor passwordKeyEncryptor;
+    private CertificateKeyEncryptor certificateKeyEncryptor;
+
+    public KeyEncryptor() {
+
+    }
+
+    public KeyEncryptor(Element keyEncryptor) {
+        if (keyEncryptor == null) {
+            throw new EncryptedDocumentException("Unable to parse encryption descriptor");
+        }
+        NodeList nl = keyEncryptor.getElementsByTagNameNS("*", "encryptedKey");
+        // usually only one encryptor is set, so iterate and overwrite the encryptor members
+        for (int i=0; i<nl.getLength(); i++) {
+            Element el = (Element)nl.item(i);
+            String nsUri = el.getNamespaceURI();
+            if (PASS_NS.equals(nsUri)) {
+                passwordKeyEncryptor = new PasswordKeyEncryptor(el);
+            } else if (CERT_NS.equals(nsUri)) {
+                certificateKeyEncryptor = new CertificateKeyEncryptor(el);
+            }
+        }
+    }
+
+    void write(Element keyEncryptors) {
+        if (passwordKeyEncryptor != null) {
+            passwordKeyEncryptor.write(keyEncryptors);
+        } else if (certificateKeyEncryptor != null) {
+            certificateKeyEncryptor.write(keyEncryptors);
+        }
+    }
+
+
+
+    public PasswordKeyEncryptor getPasswordKeyEncryptor() {
+        return passwordKeyEncryptor;
+    }
+
+    public void setPasswordKeyEncryptor(PasswordKeyEncryptor passwordKeyEncryptor) {
+        this.passwordKeyEncryptor = passwordKeyEncryptor;
+    }
+
+    public CertificateKeyEncryptor getCertificateKeyEncryptor() {
+        return certificateKeyEncryptor;
+    }
+
+    public void setCertificateKeyEncryptor(CertificateKeyEncryptor certificateKeyEncryptor) {
+        this.certificateKeyEncryptor = certificateKeyEncryptor;
+    }
+}
diff --git a/src/java/org/apache/poi/poifs/crypt/agile/PasswordKeyEncryptor.java b/src/java/org/apache/poi/poifs/crypt/agile/PasswordKeyEncryptor.java
new file mode 100644 (file)
index 0000000..1e3f864
--- /dev/null
@@ -0,0 +1,241 @@
+/* ====================================================================
+   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.poifs.crypt.agile;
+
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.getBinAttr;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.getIntAttr;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.setAttr;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.setBinAttr;
+import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.setIntAttr;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.poifs.crypt.ChainingMode;
+import org.apache.poi.poifs.crypt.CipherAlgorithm;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class PasswordKeyEncryptor {
+
+    /**
+     * An unsigned integer that specifies the number of bytes used by a salt. It MUST be at least 1 and no greater than 65,536.
+     */
+    private Integer saltSize;
+
+    /**
+     * An unsigned integer that specifies the number of bytes used to encrypt one block of data.
+     * It MUST be at least 2, no greater than 4096, and a multiple of 2.
+     */
+    private Integer blockSize;
+
+    /**
+     * An unsigned integer that specifies the number of bits used by an encryption algorithm.
+     * It MUST be at least 8 and a multiple of 8.
+     */
+    private Integer keyBits;
+
+    /**
+     * An unsigned integer that specifies the number of bytes used by a hash value.
+     * It MUST be at least 1, no greater than 65,536, and the same number of bytes as the hash algorithm emits.
+     */
+    private Integer hashSize;
+
+    /**
+     * A CipherAlgorithm that specifies the cipher algorithm for a PasswordKeyEncryptor.
+     * The cipher algorithm specified MUST be the same as the cipher algorithm specified for the Encryption.keyData element.
+     */
+    private CipherAlgorithm cipherAlgorithm;
+
+    /**
+     * A CipherChaining that specifies the cipher chaining mode for a PasswordKeyEncryptor.
+     */
+    private ChainingMode cipherChaining;
+
+    /**
+     * A HashAlgorithm that specifies the hashing algorithm for a PasswordKeyEncryptor.
+     * The hashing algorithm specified MUST be the same as the hashing algorithm specified for the Encryption.keyData element.
+     */
+    private HashAlgorithm hashAlgorithm;
+
+    /**
+     * A base64-encoded binary byte array that specifies the salt value for a PasswordKeyEncryptor.
+     * The number of bytes required by the decoded form of this element MUST be saltSize.
+     */
+    private byte[] saltValue;
+
+    /**
+     * A SpinCount that specifies the spin count for a PasswordKeyEncryptor.
+     */
+    private Integer spinCount;
+
+    /**
+     * A base64-encoded value that specifies the encrypted verifier hash input for a
+     * PasswordKeyEncryptor used in password verification.
+     */
+    private byte[] encryptedVerifierHashInput;
+
+    /**
+     * A base64-encoded value that specifies the encrypted verifier hash value for a
+     * PasswordKeyEncryptor used in password verification.
+     */
+    private byte[] encryptedVerifierHashValue;
+
+    /**
+     * A base64-encoded value that specifies the encrypted form of the intermediate key.
+     */
+    private byte[] encryptedKeyValue;
+
+    public PasswordKeyEncryptor() {
+
+    }
+
+    public PasswordKeyEncryptor(Element passwordKey) {
+        if (passwordKey == null) {
+            throw new EncryptedDocumentException("Unable to parse encryption descriptor");
+        }
+        saltSize = getIntAttr(passwordKey, "saltSize");
+        blockSize = getIntAttr(passwordKey, "blockSize");
+        keyBits = getIntAttr(passwordKey, "keyBits");
+        hashSize = getIntAttr(passwordKey, "hashSize");
+        cipherAlgorithm = CipherAlgorithm.fromXmlId(passwordKey.getAttribute("cipherAlgorithm"), keyBits);
+        cipherChaining = ChainingMode.fromXmlId(passwordKey.getAttribute("cipherChaining"));
+        hashAlgorithm = HashAlgorithm.fromEcmaId(passwordKey.getAttribute("hashAlgorithm"));
+        saltValue = getBinAttr(passwordKey, "saltValue");
+        spinCount = getIntAttr(passwordKey, "spinCount");
+        encryptedVerifierHashInput = getBinAttr(passwordKey, "encryptedVerifierHashInput");
+        encryptedVerifierHashValue = getBinAttr(passwordKey, "encryptedVerifierHashValue");
+        encryptedKeyValue = getBinAttr(passwordKey, "encryptedKeyValue");
+    }
+
+    void write(Element encryption) {
+        Document doc = encryption.getOwnerDocument();
+        Element keyEncryptor = (Element) encryption.appendChild(doc.createElement("keyEncryptor"));
+        keyEncryptor.setAttribute("uri", KeyEncryptor.PASS_NS);
+        Element encryptedKey = (Element) keyEncryptor.appendChild(doc.createElement("p:encryptedKey"));
+
+        setIntAttr(encryptedKey, "saltSize", saltSize);
+        setIntAttr(encryptedKey, "blockSize", blockSize);
+        setIntAttr(encryptedKey, "keyBits", keyBits);
+        setIntAttr(encryptedKey, "hashSize", hashSize);
+        setAttr(encryptedKey, "cipherAlgorithm", cipherAlgorithm == null ? null : cipherAlgorithm.xmlId);
+        setAttr(encryptedKey, "cipherChaining", cipherChaining == null ? null : cipherChaining.xmlId);
+        setAttr(encryptedKey, "hashAlgorithm", hashAlgorithm == null ? null : hashAlgorithm.ecmaString);
+        setBinAttr(encryptedKey, "saltValue", saltValue);
+        setIntAttr(encryptedKey, "spinCount", spinCount);
+        setBinAttr(encryptedKey, "encryptedVerifierHashInput", encryptedVerifierHashInput);
+        setBinAttr(encryptedKey, "encryptedVerifierHashValue", encryptedVerifierHashValue);
+        setBinAttr(encryptedKey, "encryptedKeyValue", encryptedKeyValue);
+
+    }
+
+    public Integer getSaltSize() {
+        return saltSize;
+    }
+
+    public void setSaltSize(Integer saltSize) {
+        this.saltSize = saltSize;
+    }
+
+    public Integer getBlockSize() {
+        return blockSize;
+    }
+
+    public void setBlockSize(Integer blockSize) {
+        this.blockSize = blockSize;
+    }
+
+    public Integer getKeyBits() {
+        return keyBits;
+    }
+
+    public void setKeyBits(Integer keyBits) {
+        this.keyBits = keyBits;
+    }
+
+    public Integer getHashSize() {
+        return hashSize;
+    }
+
+    public void setHashSize(Integer hashSize) {
+        this.hashSize = hashSize;
+    }
+
+    public CipherAlgorithm getCipherAlgorithm() {
+        return cipherAlgorithm;
+    }
+
+    public void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) {
+        this.cipherAlgorithm = cipherAlgorithm;
+    }
+
+    public ChainingMode getCipherChaining() {
+        return cipherChaining;
+    }
+
+    public void setCipherChaining(ChainingMode cipherChaining) {
+        this.cipherChaining = cipherChaining;
+    }
+
+    public HashAlgorithm getHashAlgorithm() {
+        return hashAlgorithm;
+    }
+
+    public void setHashAlgorithm(HashAlgorithm hashAlgorithm) {
+        this.hashAlgorithm = hashAlgorithm;
+    }
+
+    public byte[] getSaltValue() {
+        return saltValue;
+    }
+
+    public void setSaltValue(byte[] saltValue) {
+        this.saltValue = saltValue;
+    }
+
+    public Integer getSpinCount() {
+        return spinCount;
+    }
+
+    public void setSpinCount(Integer spinCount) {
+        this.spinCount = spinCount;
+    }
+
+    public byte[] getEncryptedVerifierHashInput() {
+        return encryptedVerifierHashInput;
+    }
+
+    public void setEncryptedVerifierHashInput(byte[] encryptedVerifierHashInput) {
+        this.encryptedVerifierHashInput = encryptedVerifierHashInput;
+    }
+
+    public byte[] getEncryptedVerifierHashValue() {
+        return encryptedVerifierHashValue;
+    }
+
+    public void setEncryptedVerifierHashValue(byte[] encryptedVerifierHashValue) {
+        this.encryptedVerifierHashValue = encryptedVerifierHashValue;
+    }
+
+    public byte[] getEncryptedKeyValue() {
+        return encryptedKeyValue;
+    }
+
+    public void setEncryptedKeyValue(byte[] encryptedKeyValue) {
+        this.encryptedKeyValue = encryptedKeyValue;
+    }
+}
index 689c06932dbe4c948a816be4d3e366df3f0559f8..f771b775506decb1f62e7b6f32382df8d4dce527 100644 (file)
@@ -57,7 +57,7 @@ public class BinaryRC4EncryptionVerifier extends EncryptionVerifier implements E
     }
 
     @Override
-    protected void setSalt(byte[] salt) {
+    public void setSalt(byte[] salt) {
         if (salt == null || salt.length != 16) {
             throw new EncryptedDocumentException("invalid verifier salt");
         }
@@ -66,12 +66,12 @@ public class BinaryRC4EncryptionVerifier extends EncryptionVerifier implements E
     }
 
     @Override
-    protected void setEncryptedVerifier(byte[] encryptedVerifier) {
+    public void setEncryptedVerifier(byte[] encryptedVerifier) {
         super.setEncryptedVerifier(encryptedVerifier);
     }
 
     @Override
-    protected void setEncryptedVerifierHash(byte[] encryptedVerifierHash) {
+    public void setEncryptedVerifierHash(byte[] encryptedVerifierHash) {
         super.setEncryptedVerifierHash(encryptedVerifierHash);
     }
 
index c54b9851d0adf40c5f40b0c291977f18afcaf092..f2c00410b3f0bd70e333ed2c0dc683a1efb63ba6 100644 (file)
@@ -41,17 +41,17 @@ public class CryptoAPIEncryptionVerifier extends StandardEncryptionVerifier {
     }
 
     @Override
-    protected void setSalt(byte[] salt) {
+    public void setSalt(byte[] salt) {
         super.setSalt(salt);
     }
 
     @Override
-    protected void setEncryptedVerifier(byte[] encryptedVerifier) {
+    public void setEncryptedVerifier(byte[] encryptedVerifier) {
         super.setEncryptedVerifier(encryptedVerifier);
     }
 
     @Override
-    protected void setEncryptedVerifierHash(byte[] encryptedVerifierHash) {
+    public void setEncryptedVerifierHash(byte[] encryptedVerifierHash) {
         super.setEncryptedVerifierHash(encryptedVerifierHash);
     }
 
index 4c5f2e0d3d89d81b31925ea5b1dbd5b7f3fcd93f..d30fe998b2a655769157fdc2755db81947f333d8 100644 (file)
@@ -74,7 +74,7 @@ public class StandardEncryptionVerifier extends EncryptionVerifier implements En
 
     // make method visible for this package
     @Override
-    protected void setSalt(byte[] salt) {
+    public void setSalt(byte[] salt) {
         if (salt == null || salt.length != 16) {
             throw new EncryptedDocumentException("invalid verifier salt");
         }
@@ -83,13 +83,13 @@ public class StandardEncryptionVerifier extends EncryptionVerifier implements En
 
     // make method visible for this package
     @Override
-    protected void setEncryptedVerifier(byte[] encryptedVerifier) {
+    public void setEncryptedVerifier(byte[] encryptedVerifier) {
         super.setEncryptedVerifier(encryptedVerifier);
     }
 
     // make method visible for this package
     @Override
-    protected void setEncryptedVerifierHash(byte[] encryptedVerifierHash) {
+    public void setEncryptedVerifierHash(byte[] encryptedVerifierHash) {
         super.setEncryptedVerifierHash(encryptedVerifierHash);
     }
 
@@ -121,7 +121,7 @@ public class StandardEncryptionVerifier extends EncryptionVerifier implements En
         bos.write(encryptedVerifierHash);
     }
 
-    protected int getVerifierHashSize() {
+    public int getVerifierHashSize() {
         return verifierHashSize;
     }
 
index 8d6482b31c8dfa7b0a70b65ccda6c3df8e08374a..5f583a7f2c50b099fe594de0b5ec2857e3d2a7d2 100644 (file)
@@ -64,12 +64,12 @@ public class XOREncryptionVerifier extends EncryptionVerifier implements Encrypt
     }
 
     @Override
-    protected final void setEncryptedVerifier(byte[] encryptedVerifier) {
+    public final void setEncryptedVerifier(byte[] encryptedVerifier) {
         super.setEncryptedVerifier(encryptedVerifier);
     }
 
     @Override
-    protected final void setEncryptedKey(byte[] encryptedKey) {
+    public final void setEncryptedKey(byte[] encryptedKey) {
         super.setEncryptedKey(encryptedKey);
     }
 }
index 4019855854ab037b14ae9f017f535e0f5c94d555..c3e2693213f9294656077a29fbd8e008f4a1c3f3 100644 (file)
@@ -685,7 +685,7 @@ public class DrawTextParagraph implements Drawable {
                     // 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(beginIndex+partBegin, beginIndex+partEnd));
+                        LOG.log(POILogger.DEBUG, "mapped: ",fontMapped.getFontName(Locale.ROOT)," ",(beginIndex+partBegin)," ",(beginIndex+partEnd)," - ",runText.substring(partBegin, partEnd));
                     }
                 }
 
@@ -697,7 +697,7 @@ public class DrawTextParagraph implements Drawable {
                     // 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(beginIndex+partBegin, beginIndex+partEnd));
+                        LOG.log(POILogger.DEBUG, "fallback: ",fontFallback.getFontName(Locale.ROOT)," ",(beginIndex+partBegin)," ",(beginIndex+partEnd)," - ",runText.substring(partBegin, partEnd));
                     }
                 }
             }
index ad5a8446eafeb022f91eb14aa42278f01bfb0efd..25f5cde753ef792deef149cec4ce608b6a2351fb 100644 (file)
 ==================================================================== */
 package org.apache.poi.ss.usermodel;
 
+import static org.apache.poi.poifs.crypt.EncryptionInfo.ENCRYPTION_INFO_ENTRY;
+
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ServiceLoader;
 
+import org.apache.poi.EmptyFileException;
 import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.poifs.crypt.Decryptor;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
-import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
 import org.apache.poi.poifs.filesystem.FileMagic;
-import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.Removal;
 
 /**
  * Factory for creating the appropriate kind of Workbook
  *  (be it {@link HSSFWorkbook} or XSSFWorkbook),
  *  by auto-detecting from the supplied input.
  */
-public abstract class WorkbookFactory {
-
-    protected interface CreateWorkbook0 {
-        Workbook apply() throws IOException;
-    }
+public final class WorkbookFactory {
 
-    protected interface CreateWorkbook1<T> {
-        Workbook apply(T t) throws IOException;
+    private static class Singleton {
+        private static final WorkbookFactory INSTANCE = new WorkbookFactory();
     }
 
-    protected interface CreateWorkbook2<T, U> {
-        Workbook apply(T t, U u) throws IOException;
+    private interface ProviderMethod {
+        Workbook create(WorkbookProvider prov) throws IOException;
     }
 
-    private static final Object hssfLock = new Object();
-    private static final Object xssfLock = new Object();
+    private final List<WorkbookProvider> provider = new ArrayList<>();
 
-    protected static CreateWorkbook0 createHssfFromScratch;
-    protected static CreateWorkbook1<DirectoryNode> createHssfByNode;
+    private WorkbookFactory() {
+        ServiceLoader.load(WorkbookProvider.class).forEach(provider::add);
+    }
 
-    protected static CreateWorkbook0 createXssfFromScratch;
-    protected static CreateWorkbook1<InputStream> createXssfByStream;
-    protected static CreateWorkbook1<Object> createXssfByPackage;
-    protected static CreateWorkbook2<File,Boolean> createXssfByFile;
 
     /**
      * Create a new empty Workbook, either XSSF or HSSF depending
@@ -75,13 +68,7 @@ public abstract class WorkbookFactory {
      * @throws IOException if an error occurs while creating the objects
      */
     public static Workbook create(boolean xssf) throws IOException {
-        if(xssf) {
-            initXssf();
-            return createXssfFromScratch.apply();
-        } else {
-            initHssf();
-            return createHssfFromScratch.apply();
-        }
+        return wp(xssf ? FileMagic.OOXML : FileMagic.OLE2, WorkbookProvider::create);
     }
 
     /**
@@ -144,61 +131,12 @@ public abstract class WorkbookFactory {
     public static Workbook create(final DirectoryNode root, String password) throws IOException {
         // Encrypted OOXML files go inside OLE2 containers, is this one?
         if (root.hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
-            InputStream stream = null;
-            try {
-                stream = DocumentFactoryHelper.getDecryptedStream(root, password);
-                initXssf();
-                return createXssfByStream.apply(stream);
-            } finally {
-                IOUtils.closeQuietly(stream);
-
-                // as we processed the full stream already, we can close the filesystem here
-                // otherwise file handles are leaked
-                root.getFileSystem().close();
-            }
-        }
-
-        // If we get here, it isn't an encrypted PPTX file
-        // So, treat it as a regular HSLF PPT one
-        boolean passwordSet = false;
-        if (password != null) {
-            Biff8EncryptionKey.setCurrentUserPassword(password);
-            passwordSet = true;
-        }
-        try {
-            initHssf();
-            return createHssfByNode.apply(root);
-        } finally {
-            if (passwordSet) {
-                Biff8EncryptionKey.setCurrentUserPassword(null);
-            }
+            return wp(FileMagic.OOXML, w -> w.create(root, password));
+        } else {
+            return wp(FileMagic.OLE2, w ->  w.create(root, password));
         }
     }
 
-    /**
-     * Creates a XSSFWorkbook from the given OOXML Package.
-     * As the WorkbookFactory is located in the POI module, which doesn't know about the OOXML formats,
-     * this can be only achieved by using an Object reference to the OPCPackage.
-     *
-     * <p>Note that in order to properly release resources the
-     *  Workbook should be closed after use.</p>
-     *
-     *  @param pkg The org.apache.poi.openxml4j.opc.OPCPackage opened for reading data.
-     *
-     *  @return The created Workbook
-     *
-     *  @throws IOException if an error occurs while reading the data
-     *
-     * @deprecated use {@link #create(File)}, {@link #create(InputStream)} or
-     *          XSSFWorkbookFactory.create(OPCPackage) instead.
-     */
-    @Deprecated
-    @Removal(version = "4.2.0")
-    public static Workbook create(Object pkg) throws IOException {
-        initXssf();
-        return createXssfByPackage.apply(pkg);
-    }
-
     /**
      * Creates the appropriate HSSFWorkbook / XSSFWorkbook from
      *  the given InputStream.
@@ -248,18 +186,26 @@ public abstract class WorkbookFactory {
      */
     public static Workbook create(InputStream inp, String password) throws IOException, EncryptedDocumentException {
         InputStream is = FileMagic.prepareToCheckMagic(inp);
-        FileMagic fm = FileMagic.valueOf(is);
-
-        switch (fm) {
-            case OLE2:
-                POIFSFileSystem fs = new POIFSFileSystem(is);
-                return create(fs, password);
-            case OOXML:
-                initXssf();
-                return createXssfByStream.apply(is);
-            default:
-                throw new IOException("Your InputStream was neither an OLE2 stream, nor an OOXML stream");
+        byte[] emptyFileCheck = new byte[1];
+        is.mark(emptyFileCheck.length);
+        if (is.read(emptyFileCheck) < emptyFileCheck.length) {
+            throw new EmptyFileException();
+        }
+        is.reset();
+
+        final FileMagic fm = FileMagic.valueOf(is);
+        if (FileMagic.OOXML == fm) {
+            return wp(fm, w -> w.create(is));
+        }
+
+        if (FileMagic.OLE2 != fm) {
+            throw new IOException("Can't open workbook - unsupported file type: "+fm);
         }
+
+        POIFSFileSystem poifs = new POIFSFileSystem(is);
+        boolean isOOXML = poifs.getRoot().hasEntry(ENCRYPTION_INFO_ENTRY);
+
+        return wp(isOOXML ? FileMagic.OOXML : fm, w -> w.create(poifs.getRoot(), password));
     }
 
     /**
@@ -320,58 +266,33 @@ public abstract class WorkbookFactory {
             throw new FileNotFoundException(file.toString());
         }
 
-        POIFSFileSystem fs = null;
-        try {
-            fs = new POIFSFileSystem(file, readOnly);
-            return create(fs, password);
-        } catch(OfficeXmlFileException e) {
-            IOUtils.closeQuietly(fs);
-            initXssf();
-            return createXssfByFile.apply(file, readOnly);
-        } catch(RuntimeException e) {
-            IOUtils.closeQuietly(fs);
-            throw e;
+        if (file.length() == 0) {
+            throw new EmptyFileException();
         }
-    }
 
-    private static void initXssf() throws IOException {
-        if (createXssfFromScratch == null) {
-            synchronized (xssfLock) {
-                if (createXssfFromScratch == null) {
-                    String factoryClass = "org.apache.poi.xssf.usermodel.XSSFWorkbookFactory";
-                    Class<?> cls = initFactory(factoryClass, "poi-ooxml-*.jar");
-                    try {
-                        cls.getMethod("init").invoke(null);
-                    } catch (Exception e) {
-                        throw new IOException(factoryClass+" failed to init.");
-                    }
-                }
+        FileMagic fm = FileMagic.valueOf(file);
+        if (fm == FileMagic.OOXML) {
+            return wp(fm, w -> w.create(file, password, readOnly));
+        } else if (fm == FileMagic.OLE2) {
+            boolean ooxmlEnc = false;
+            try (POIFSFileSystem fs = new POIFSFileSystem(file, true)) {
+                ooxmlEnc = fs.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY);
             }
+            return wp(ooxmlEnc ? FileMagic.OOXML : fm, w -> w.create(file, password, readOnly));
         }
-    }
 
-    private static void initHssf() throws IOException {
-        if (createHssfFromScratch == null) {
-            // HSSF is part of the main jar, so this shouldn't fail ...
-            synchronized (hssfLock) {
-                if (createHssfFromScratch == null) {
-                    String factoryClass = "org.apache.poi.hssf.usermodel.HSSFWorkbookFactory";
-                    Class<?> cls = initFactory(factoryClass, "poi-*.jar");
-                    try {
-                        cls.getMethod("init").invoke(null);
-                    } catch (Exception e) {
-                        throw new IOException(factoryClass+" failed to init.");
-                    }
-                }
-            }
-        }
+        return null;
     }
 
-    private static Class<?> initFactory(String factoryClass, String jar) throws IOException {
-        try {
-            return Class.forName(factoryClass, true, WorkbookFactory.class.getClassLoader());
-        } catch (ClassNotFoundException e) {
-            throw new IOException(factoryClass+" not found - check if " + jar + " is on the classpath.");
+
+    private static Workbook wp(FileMagic fm, ProviderMethod fun) throws IOException {
+
+        for (WorkbookProvider prov : Singleton.INSTANCE.provider) {
+            if (prov.accepts(fm)) {
+                return fun.create(prov);
+            }
         }
+        throw new IOException("Your InputStream was neither an OLE2 stream, nor an OOXML stream " +
+            "or you haven't provide the poi-ooxml*.jar in the classpath/modulepath - FileMagic: "+fm);
     }
 }
diff --git a/src/java/org/apache/poi/ss/usermodel/WorkbookProvider.java b/src/java/org/apache/poi/ss/usermodel/WorkbookProvider.java
new file mode 100644 (file)
index 0000000..12b8cc8
--- /dev/null
@@ -0,0 +1,39 @@
+/* ====================================================================
+   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.ss.usermodel;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.FileMagic;
+
+public interface WorkbookProvider {
+    boolean accepts(FileMagic fm);
+
+    Workbook create();
+
+    Workbook create(InputStream inp) throws IOException;
+
+    Workbook create(InputStream inp, String password) throws IOException;
+
+    Workbook create(DirectoryNode root, String password) throws IOException;
+
+    Workbook create(File file, String password, boolean readOnly) throws IOException;
+}
index 5a17d04a1de169d2e22341c3d81599466ae07595..0252b4b684f046f2f43c466da25b98064e37ed16 100644 (file)
 
 package org.apache.poi.util;
 
+import static org.apache.poi.util.TempFile.JAVA_IO_TMPDIR;
+
 import java.io.File;
 import java.io.IOException;
 import java.security.SecureRandom;
 
-import static org.apache.poi.util.TempFile.JAVA_IO_TMPDIR;
-
 /**
  * Default implementation of the {@link TempFileCreationStrategy} used by {@link TempFile}:
  * Files are collected into one directory and by default are deleted on exit from the VM.
  * Files may be manually deleted by user prior to JVM exit.
  * Files can be kept by defining the system property {@link #KEEP_FILES}.
- * 
+ *
  * Each file is registered for deletion with the JVM and the temporary directory is not deleted
  * after the JVM exits. Files that are created in the poifiles directory outside
  * the control of DefaultTempFileCreationStrategy are not deleted.
@@ -36,37 +36,37 @@ import static org.apache.poi.util.TempFile.JAVA_IO_TMPDIR;
  * processes or limited temporary storage.
  */
 public class DefaultTempFileCreationStrategy implements TempFileCreationStrategy {
-    /*package*/ static final String POIFILES = "poifiles";
-    
+    public static final String POIFILES = "poifiles";
+
     /** To keep files after JVM exit, set the <code>-Dpoi.keep.tmp.files</code> JVM property */
     public static final String KEEP_FILES = "poi.keep.tmp.files";
-    
+
     /** random number generator to generate unique filenames */
     private static final SecureRandom random = new SecureRandom();
-    
+
     /** The directory where the temporary files will be created (<code>null</code> to use the default directory). */
     private File dir;
-    
+
     /**
      * Creates the strategy so that it creates the temporary files in the default directory.
-     * 
+     *
      * @see File#createTempFile(String, String)
      */
     public DefaultTempFileCreationStrategy() {
         this(null);
     }
-    
+
     /**
-     * Creates the strategy allowing to set the  
+     * Creates the strategy allowing to set the
      *
      * @param dir The directory where the temporary files will be created (<code>null</code> to use the default directory).
-     * 
+     *
      * @see File#createTempFile(String, String, File)
      */
     public DefaultTempFileCreationStrategy(File dir) {
         this.dir = dir;
     }
-    
+
     private void createPOIFilesDirectory() throws IOException {
         // Identify and create our temp dir, if needed
         // The directory is not deleted, even if it was created by this TempFileCreationStrategy
@@ -77,10 +77,10 @@ public class DefaultTempFileCreationStrategy implements TempFileCreationStrategy
             }
             dir = new File(tmpDir, POIFILES);
         }
-        
+
         createTempDirectory(dir);
     }
-    
+
     /**
      * Attempt to create a directory, including any necessary parent directories.
      * Does nothing if directory already exists.
@@ -92,7 +92,7 @@ public class DefaultTempFileCreationStrategy implements TempFileCreationStrategy
     private synchronized void createTempDirectory(File directory) throws IOException {
         // create directory if it doesn't exist
         final boolean dirExists = (directory.exists() || directory.mkdirs());
-        
+
         if (!dirExists) {
             throw new IOException("Could not create temporary directory '" + directory + "'");
         }
@@ -100,13 +100,13 @@ public class DefaultTempFileCreationStrategy implements TempFileCreationStrategy
             throw new IOException("Could not create temporary directory. '" + directory + "' exists but is not a directory.");
         }
     }
-    
+
     @Override
     public File createTempFile(String prefix, String suffix) throws IOException {
         // Identify and create our temp dir, if needed
         createPOIFilesDirectory();
-        
-        // Generate a unique new filename 
+
+        // Generate a unique new filename
         File newFile = File.createTempFile(prefix, suffix, dir);
 
         // Set the delete on exit flag, unless explicitly disabled
@@ -123,7 +123,7 @@ public class DefaultTempFileCreationStrategy implements TempFileCreationStrategy
     public File createTempDirectory(String prefix) throws IOException {
         // Identify and create our temp dir, if needed
         createPOIFilesDirectory();
-        
+
         // Generate a unique new filename
         // FIXME: Java 7+: use java.nio.Files#createTempDirectory
         final long n = random.nextLong();
diff --git a/src/multimodule/examples/java9/module-info.class b/src/multimodule/examples/java9/module-info.class
new file mode 100644 (file)
index 0000000..1b5faa4
Binary files /dev/null and b/src/multimodule/examples/java9/module-info.class differ
diff --git a/src/multimodule/examples/java9/module-info.java b/src/multimodule/examples/java9/module-info.java
new file mode 100644 (file)
index 0000000..68b580e
--- /dev/null
@@ -0,0 +1,40 @@
+/* ====================================================================
+   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.
+==================================================================== */
+
+module org.apache.poi.examples {
+
+    requires transitive org.apache.poi.ooxml;
+    requires transitive org.apache.poi.scratchpad;
+    requires java.xml;
+
+    exports org.apache.poi.examples.crypt;
+    exports org.apache.poi.examples.hpsf;
+    exports org.apache.poi.examples.hslf;
+    exports org.apache.poi.examples.hsmf;
+    exports org.apache.poi.examples.hssf.eventusermodel;
+    exports org.apache.poi.examples.hssf.usermodel;
+    exports org.apache.poi.examples.hwpf;
+    exports org.apache.poi.examples.ss;
+    exports org.apache.poi.examples.ss.formula;
+    exports org.apache.poi.examples.ss.html;
+    exports org.apache.poi.examples.util;
+    exports org.apache.poi.examples.xslf;
+    exports org.apache.poi.examples.xssf.eventusermodel;
+    exports org.apache.poi.examples.xssf.streaming;
+    exports org.apache.poi.examples.xssf.usermodel;
+    exports org.apache.poi.examples.xwpf.usermodel;
+}
\ No newline at end of file
diff --git a/src/multimodule/excelant/java9/module-info.class b/src/multimodule/excelant/java9/module-info.class
new file mode 100644 (file)
index 0000000..5218a9b
Binary files /dev/null and b/src/multimodule/excelant/java9/module-info.class differ
diff --git a/src/multimodule/excelant/java9/module-info.java b/src/multimodule/excelant/java9/module-info.java
new file mode 100644 (file)
index 0000000..43b6456
--- /dev/null
@@ -0,0 +1,28 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+module org.apache.poi.excelant {
+
+    requires ant;
+    requires org.apache.poi.ooxml;
+    requires org.apache.poi.scratchpad;
+
+    exports org.apache.poi.ss.excelant;
+    exports org.apache.poi.ss.excelant.util;
+
+    opens org.apache.poi.ss.excelant;
+}
\ No newline at end of file
diff --git a/src/multimodule/excelant/test9/module-info.class b/src/multimodule/excelant/test9/module-info.class
new file mode 100644 (file)
index 0000000..5218a9b
Binary files /dev/null and b/src/multimodule/excelant/test9/module-info.class differ
diff --git a/src/multimodule/excelant/test9/module-info.java b/src/multimodule/excelant/test9/module-info.java
new file mode 100644 (file)
index 0000000..43b6456
--- /dev/null
@@ -0,0 +1,28 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+module org.apache.poi.excelant {
+
+    requires ant;
+    requires org.apache.poi.ooxml;
+    requires org.apache.poi.scratchpad;
+
+    exports org.apache.poi.ss.excelant;
+    exports org.apache.poi.ss.excelant.util;
+
+    opens org.apache.poi.ss.excelant;
+}
\ No newline at end of file
diff --git a/src/multimodule/integration/java9/module-info.java b/src/multimodule/integration/java9/module-info.java
new file mode 100644 (file)
index 0000000..51d730c
--- /dev/null
@@ -0,0 +1,27 @@
+/* ====================================================================
+   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.
+==================================================================== */
+
+module org.apache.poi.stress {
+    requires junit;
+    requires net.bytebuddy;
+    requires java.desktop;
+
+    requires org.apache.poi.examples;
+
+    exports org.apache.poi.stress;
+
+}
\ No newline at end of file
diff --git a/src/multimodule/ooxml-lite-agent/java9/module-info.class b/src/multimodule/ooxml-lite-agent/java9/module-info.class
new file mode 100644 (file)
index 0000000..fb79979
Binary files /dev/null and b/src/multimodule/ooxml-lite-agent/java9/module-info.class differ
diff --git a/src/multimodule/ooxml-lite-agent/java9/module-info.java b/src/multimodule/ooxml-lite-agent/java9/module-info.java
new file mode 100644 (file)
index 0000000..04058f1
--- /dev/null
@@ -0,0 +1,22 @@
+/* ====================================================================
+   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.
+==================================================================== */
+
+module org.apache.poi.ooxml_lite {
+    requires java.instrument;
+
+    exports org.apache.poi.ooxml.lite;
+}
\ No newline at end of file
diff --git a/src/multimodule/ooxml-lite/java9/module-info.class b/src/multimodule/ooxml-lite/java9/module-info.class
new file mode 100644 (file)
index 0000000..78ddc1f
Binary files /dev/null and b/src/multimodule/ooxml-lite/java9/module-info.class differ
diff --git a/src/multimodule/ooxml-lite/java9/module-info.java b/src/multimodule/ooxml-lite/java9/module-info.java
new file mode 100644 (file)
index 0000000..77a3bb3
--- /dev/null
@@ -0,0 +1,47 @@
+/* ====================================================================
+   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.
+==================================================================== */
+
+
+open module org.apache.poi.ooxml.schemas {
+    // this still throws "requires transitive directive for an automatic module" in JDK 14
+    // see https://bugs.openjdk.java.net/browse/JDK-8240847
+    requires transitive org.apache.xmlbeans;
+    requires java.xml;
+
+    exports com.microsoft.schemas.compatibility;
+    exports com.microsoft.schemas.office.excel;
+    exports com.microsoft.schemas.office.office;
+    exports com.microsoft.schemas.office.visio.x2012.main;
+    exports com.microsoft.schemas.office.x2006.digsig;
+    exports com.microsoft.schemas.vml;
+    exports org.apache.poi.schemas.ooxml.system.ooxml;
+    exports org.etsi.uri.x01903.v13;
+    exports org.openxmlformats.schemas.drawingml.x2006.chart;
+    exports org.openxmlformats.schemas.drawingml.x2006.main;
+    exports org.openxmlformats.schemas.drawingml.x2006.picture;
+    exports org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing;
+    exports org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing;
+    exports org.openxmlformats.schemas.officeDocument.x2006.customProperties;
+    exports org.openxmlformats.schemas.officeDocument.x2006.docPropsVTypes;
+    exports org.openxmlformats.schemas.officeDocument.x2006.extendedProperties;
+    exports org.openxmlformats.schemas.officeDocument.x2006.relationships;
+    exports org.openxmlformats.schemas.presentationml.x2006.main;
+    exports org.openxmlformats.schemas.spreadsheetml.x2006.main;
+    exports org.openxmlformats.schemas.wordprocessingml.x2006.main;
+    exports org.openxmlformats.schemas.xpackage.x2006.digitalSignature;
+    exports org.w3.x2000.x09.xmldsig;
+}
\ No newline at end of file
index 83a16f01ec7ad933d3a12d2ba00a1af603b92fc1..339c9d793ed7d34bb1cdf4721ae65a906c08efa6 100644 (file)
Binary files a/src/multimodule/ooxml-schemas/java9/module-info.class and b/src/multimodule/ooxml-schemas/java9/module-info.class differ
index cd746371aef1b3fcdc1e3a27d0746a7d07ee4579..974467061fc8b76d8d5f43d51083bbd77673cc3c 100644 (file)
@@ -17,7 +17,9 @@
 
 
 open module org.apache.poi.ooxml.schemas {
-    requires transitive xmlbeans;
+    // this still throws "requires transitive directive for an automatic module" in JDK 14
+    // see https://bugs.openjdk.java.net/browse/JDK-8240847
+    requires transitive org.apache.xmlbeans;
     requires java.xml;
     exports com.microsoft.schemas.compatibility;
     exports com.microsoft.schemas.office.excel;
@@ -47,5 +49,11 @@ open module org.apache.poi.ooxml.schemas {
     exports org.openxmlformats.schemas.schemaLibrary.x2006.main;
     exports org.openxmlformats.schemas.spreadsheetml.x2006.main;
     exports org.openxmlformats.schemas.wordprocessingml.x2006.main;
-    // opens schemaorg_apache_xmlbeans.system.OoxmlSchemas to xmlbeans;
+
+    exports com.microsoft.schemas.office.x2006.digsig;
+    exports org.etsi.uri.x01903.v13;
+    exports org.etsi.uri.x01903.v14;
+    exports org.openxmlformats.schemas.xpackage.x2006.digitalSignature;
+    exports org.openxmlformats.schemas.xpackage.x2006.relationships;
+    exports org.w3.x2000.x09.xmldsig;
 }
\ No newline at end of file
diff --git a/src/multimodule/ooxml-security/java9/module-info.class b/src/multimodule/ooxml-security/java9/module-info.class
deleted file mode 100644 (file)
index ce9793c..0000000
Binary files a/src/multimodule/ooxml-security/java9/module-info.class and /dev/null differ
diff --git a/src/multimodule/ooxml-security/java9/module-info.java b/src/multimodule/ooxml-security/java9/module-info.java
deleted file mode 100644 (file)
index ac902c3..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-
-open module org.apache.poi.ooxml.security {
-    requires transitive xmlbeans;
-    requires java.xml;
-    exports com.microsoft.schemas.office.x2006.digsig;
-    exports com.microsoft.schemas.office.x2006.encryption;
-    exports com.microsoft.schemas.office.x2006.keyEncryptor.certificate;
-    exports com.microsoft.schemas.office.x2006.keyEncryptor.password;
-    exports org.etsi.uri.x01903.v13;
-    exports org.etsi.uri.x01903.v14;
-    exports org.openxmlformats.schemas.xpackage.x2006.digitalSignature;
-    exports org.openxmlformats.schemas.xpackage.x2006.relationships;
-    exports org.w3.x2000.x09.xmldsig;
-    // opens schemaorg_apache_xmlbeans.system.OoxmlSecurity to xmlbeans;
-}
\ No newline at end of file
diff --git a/src/multimodule/ooxml/java9/module-info.class b/src/multimodule/ooxml/java9/module-info.class
new file mode 100644 (file)
index 0000000..8dd7fcb
Binary files /dev/null and b/src/multimodule/ooxml/java9/module-info.class differ
diff --git a/src/multimodule/ooxml/java9/module-info.java b/src/multimodule/ooxml/java9/module-info.java
new file mode 100644 (file)
index 0000000..794e086
--- /dev/null
@@ -0,0 +1,87 @@
+/* ====================================================================
+   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.
+==================================================================== */
+
+module org.apache.poi.ooxml {
+    requires transitive org.apache.poi.poi;
+    requires transitive org.apache.xmlbeans;
+    requires transitive org.apache.poi.ooxml.schemas;
+    requires org.apache.commons.collections4;
+    requires org.apache.commons.codec;
+    requires commons.math3;
+    requires SparseBitSet;
+    requires commons.logging;
+    requires java.logging;
+    requires java.desktop;
+    requires java.security.jgss;
+
+    provides org.apache.poi.ss.usermodel.WorkbookProvider with org.apache.poi.xssf.usermodel.XSSFWorkbookFactory;
+
+    exports org.apache.poi.xwpf.extractor;
+    exports org.apache.poi.xwpf.usermodel;
+    exports org.apache.poi.xwpf.model;
+    exports org.apache.poi.xdgf.extractor;
+    exports org.apache.poi.xdgf.exceptions;
+    exports org.apache.poi.xdgf.usermodel;
+    exports org.apache.poi.xdgf.usermodel.section;
+    exports org.apache.poi.xdgf.usermodel.section.geometry;
+    exports org.apache.poi.xdgf.usermodel.shape;
+    exports org.apache.poi.xdgf.usermodel.shape.exceptions;
+    exports org.apache.poi.xdgf.xml;
+    exports org.apache.poi.xdgf.util;
+    exports org.apache.poi.xdgf.geom;
+    exports org.apache.poi.ooxml;
+    exports org.apache.poi.ooxml.dev;
+    exports org.apache.poi.ooxml.extractor;
+    exports org.apache.poi.ooxml.util;
+    exports org.apache.poi.xddf.usermodel;
+    exports org.apache.poi.xddf.usermodel.text;
+    exports org.apache.poi.xddf.usermodel.chart;
+    exports org.apache.poi.openxml4j.exceptions;
+    exports org.apache.poi.openxml4j.opc;
+    exports org.apache.poi.openxml4j.opc.internal;
+    exports org.apache.poi.openxml4j.opc.internal.marshallers;
+    exports org.apache.poi.openxml4j.opc.internal.unmarshallers;
+    exports org.apache.poi.openxml4j.util;
+    exports org.apache.poi.xssf;
+    exports org.apache.poi.xssf.extractor;
+    exports org.apache.poi.xssf.eventusermodel;
+    exports org.apache.poi.xssf.usermodel;
+    exports org.apache.poi.xssf.usermodel.helpers;
+    exports org.apache.poi.xssf.usermodel.extensions;
+    exports org.apache.poi.xssf.binary;
+    exports org.apache.poi.xssf.model;
+    exports org.apache.poi.xssf.streaming;
+    exports org.apache.poi.xssf.util;
+    exports org.apache.poi.xslf.draw;
+    exports org.apache.poi.xslf.usermodel;
+    exports org.apache.poi.xslf.model;
+    exports org.apache.poi.xslf.util;
+    exports org.apache.poi.poifs.crypt.dsig;
+    exports org.apache.poi.poifs.crypt.dsig.facets;
+    exports org.apache.poi.poifs.crypt.dsig.services;
+    exports org.apache.poi.poifs.crypt.temp;
+
+    opens org.apache.poi.openxml4j.opc to org.apache.poi.poi;
+
+
+    /* optional dependencies for xml signatures - you need to add a require entry your module-info
+     * or add them via the --add-modules JVM argument */
+    requires java.xml.crypto;
+    requires static org.apache.santuario.xmlsec;
+    requires static org.bouncycastle.provider;
+    requires static org.bouncycastle.pkix;
+}
\ No newline at end of file
diff --git a/src/multimodule/ooxml/test9/module-info.class b/src/multimodule/ooxml/test9/module-info.class
new file mode 100644 (file)
index 0000000..8d3730a
Binary files /dev/null and b/src/multimodule/ooxml/test9/module-info.class differ
diff --git a/src/multimodule/ooxml/test9/module-info.java b/src/multimodule/ooxml/test9/module-info.java
new file mode 100644 (file)
index 0000000..36427ad
--- /dev/null
@@ -0,0 +1,114 @@
+/* ====================================================================
+   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.
+==================================================================== */
+
+module org.apache.poi.ooxml {
+    requires transitive org.apache.poi.poi;
+    requires transitive org.apache.xmlbeans;
+    requires transitive org.apache.poi.ooxml.schemas;
+    requires org.apache.commons.collections4;
+    requires org.apache.commons.codec;
+    requires commons.math3;
+    requires SparseBitSet;
+    requires commons.logging;
+    requires java.logging;
+    requires java.desktop;
+    requires java.security.jgss;
+
+    provides org.apache.poi.ss.usermodel.WorkbookProvider with org.apache.poi.xssf.usermodel.XSSFWorkbookFactory;
+
+    exports org.apache.poi.xwpf.extractor;
+    exports org.apache.poi.xwpf.usermodel;
+    exports org.apache.poi.xwpf.model;
+    exports org.apache.poi.xdgf.extractor;
+    exports org.apache.poi.xdgf.exceptions;
+    exports org.apache.poi.xdgf.usermodel;
+    exports org.apache.poi.xdgf.usermodel.section;
+    exports org.apache.poi.xdgf.usermodel.section.geometry;
+    exports org.apache.poi.xdgf.usermodel.shape;
+    exports org.apache.poi.xdgf.usermodel.shape.exceptions;
+    exports org.apache.poi.xdgf.xml;
+    exports org.apache.poi.xdgf.util;
+    exports org.apache.poi.xdgf.geom;
+    exports org.apache.poi.ooxml;
+    exports org.apache.poi.ooxml.dev;
+    exports org.apache.poi.ooxml.extractor;
+    exports org.apache.poi.ooxml.util;
+    exports org.apache.poi.xddf.usermodel;
+    exports org.apache.poi.xddf.usermodel.text;
+    exports org.apache.poi.xddf.usermodel.chart;
+    exports org.apache.poi.openxml4j.exceptions;
+    exports org.apache.poi.openxml4j.opc;
+    exports org.apache.poi.openxml4j.opc.internal;
+    exports org.apache.poi.openxml4j.opc.internal.marshallers;
+    exports org.apache.poi.openxml4j.opc.internal.unmarshallers;
+    exports org.apache.poi.openxml4j.util;
+    exports org.apache.poi.xssf;
+    exports org.apache.poi.xssf.extractor;
+    exports org.apache.poi.xssf.eventusermodel;
+    exports org.apache.poi.xssf.usermodel;
+    exports org.apache.poi.xssf.usermodel.helpers;
+    exports org.apache.poi.xssf.usermodel.extensions;
+    exports org.apache.poi.xssf.binary;
+    exports org.apache.poi.xssf.model;
+    exports org.apache.poi.xssf.streaming;
+    exports org.apache.poi.xssf.util;
+    exports org.apache.poi.xslf.draw;
+    exports org.apache.poi.xslf.usermodel;
+    exports org.apache.poi.xslf.model;
+    exports org.apache.poi.xslf.util;
+    exports org.apache.poi.poifs.crypt.dsig;
+    exports org.apache.poi.poifs.crypt.dsig.facets;
+    exports org.apache.poi.poifs.crypt.dsig.services;
+    exports org.apache.poi.poifs.crypt.temp;
+
+    opens org.apache.poi.openxml4j.opc to org.apache.poi.poi;
+
+
+    /* optional dependencies for xml signatures - you need to add a require entry your module-info
+     * or add them via the --add-modules JVM argument */
+    requires java.xml.crypto;
+    requires org.apache.santuario.xmlsec;
+    requires org.bouncycastle.provider;
+    requires org.bouncycastle.pkix;
+
+
+    // test specific exports
+    requires junit;
+    requires com.google.common;
+
+    exports org.apache.poi.extractor.ooxml to junit;
+    exports org.apache.poi.openxml4j.opc.compliance to junit;
+    exports org.apache.poi.poifs.crypt.tests to junit;
+    exports org.apache.poi.sl.tests to junit;
+    exports org.apache.poi.sl.tests.draw to junit;
+    exports org.apache.poi.ss.tests to junit;
+    exports org.apache.poi.ss.tests.extractor to junit;
+    exports org.apache.poi.ss.tests.format to junit;
+    exports org.apache.poi.ss.tests.formula to junit;
+    exports org.apache.poi.ss.tests.formula.eval to junit;
+    exports org.apache.poi.ss.tests.formula.functions to junit;
+    exports org.apache.poi.ss.tests.usermodel to junit;
+    exports org.apache.poi.ss.tests.util to junit;
+    exports org.apache.poi.util.tests to junit;
+    exports org.apache.poi.xslf to junit;
+    exports org.apache.poi.xslf.extractor to junit;
+    exports org.apache.poi.xssf.io to junit;
+    exports org.apache.poi.xssf.usermodel.charts to junit;
+    exports org.apache.poi.xwpf to junit;
+
+
+}
\ No newline at end of file
diff --git a/src/multimodule/poi/java9/module-info.class b/src/multimodule/poi/java9/module-info.class
new file mode 100644 (file)
index 0000000..7e09b98
Binary files /dev/null and b/src/multimodule/poi/java9/module-info.class differ
index 65e100a014032ab44ea85f7dd3450c192274d9ef..50a41b014f134848c1987b013ff532e26a760d6e 100644 (file)
@@ -21,8 +21,16 @@ module org.apache.poi.poi {
     requires commons.math3;
     requires SparseBitSet;
     requires commons.logging;
+    requires java.logging;
+    requires java.desktop;
 
+    uses org.apache.poi.ss.usermodel.WorkbookProvider;
 
+    provides org.apache.poi.ss.usermodel.WorkbookProvider with org.apache.poi.hssf.usermodel.HSSFWorkbookFactory;
+
+    exports org.apache.poi;
+    exports org.apache.poi.common;
+    exports org.apache.poi.common.usermodel;
     exports org.apache.poi.common.usermodel.fonts;
     exports org.apache.poi.ddf;
     exports org.apache.poi.extractor;
@@ -49,6 +57,7 @@ module org.apache.poi.poi {
     exports org.apache.poi.hssf.util;
     exports org.apache.poi.poifs.common;
     exports org.apache.poi.poifs.crypt;
+    exports org.apache.poi.poifs.crypt.agile;
     exports org.apache.poi.poifs.crypt.binaryrc4;
     exports org.apache.poi.poifs.crypt.cryptoapi;
     exports org.apache.poi.poifs.crypt.standard;
diff --git a/src/multimodule/poi/test9/module-info.class b/src/multimodule/poi/test9/module-info.class
new file mode 100644 (file)
index 0000000..01d4a48
Binary files /dev/null and b/src/multimodule/poi/test9/module-info.class differ
diff --git a/src/multimodule/poi/test9/module-info.java b/src/multimodule/poi/test9/module-info.java
new file mode 100644 (file)
index 0000000..26579cd
--- /dev/null
@@ -0,0 +1,101 @@
+/* ====================================================================
+   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.
+==================================================================== */
+
+module org.apache.poi.poi {
+    requires org.apache.commons.collections4;
+    requires org.apache.commons.codec;
+    requires commons.math3;
+    requires SparseBitSet;
+    requires commons.logging;
+    requires java.logging;
+    requires java.desktop;
+
+    uses org.apache.poi.ss.usermodel.WorkbookProvider;
+
+    provides org.apache.poi.ss.usermodel.WorkbookProvider with org.apache.poi.hssf.usermodel.HSSFWorkbookFactory;
+
+    exports org.apache.poi;
+    exports org.apache.poi.common;
+    exports org.apache.poi.common.usermodel;
+    exports org.apache.poi.common.usermodel.fonts;
+    exports org.apache.poi.ddf;
+    exports org.apache.poi.extractor;
+    exports org.apache.poi.hpsf;
+    exports org.apache.poi.hpsf.extractor;
+    exports org.apache.poi.hpsf.wellknown;
+    exports org.apache.poi.hssf;
+    exports org.apache.poi.hssf.dev;
+    exports org.apache.poi.hssf.eventmodel;
+    exports org.apache.poi.hssf.eventusermodel;
+    exports org.apache.poi.hssf.eventusermodel.dummyrecord;
+    exports org.apache.poi.hssf.extractor;
+    exports org.apache.poi.hssf.model;
+    exports org.apache.poi.hssf.record;
+    exports org.apache.poi.hssf.record.aggregates;
+    exports org.apache.poi.hssf.record.cf;
+    exports org.apache.poi.hssf.record.chart;
+    exports org.apache.poi.hssf.record.common;
+    exports org.apache.poi.hssf.record.cont;
+    exports org.apache.poi.hssf.record.crypto;
+    exports org.apache.poi.hssf.record.pivottable;
+    exports org.apache.poi.hssf.usermodel;
+    exports org.apache.poi.hssf.usermodel.helpers;
+    exports org.apache.poi.hssf.util;
+    exports org.apache.poi.poifs.common;
+    exports org.apache.poi.poifs.crypt;
+    exports org.apache.poi.poifs.crypt.agile;
+    exports org.apache.poi.poifs.crypt.binaryrc4;
+    exports org.apache.poi.poifs.crypt.cryptoapi;
+    exports org.apache.poi.poifs.crypt.standard;
+    exports org.apache.poi.poifs.crypt.xor;
+    exports org.apache.poi.poifs.dev;
+    exports org.apache.poi.poifs.eventfilesystem;
+    exports org.apache.poi.poifs.filesystem;
+    exports org.apache.poi.poifs.macros;
+    exports org.apache.poi.poifs.nio;
+    exports org.apache.poi.poifs.property;
+    exports org.apache.poi.poifs.storage;
+    exports org.apache.poi.sl.draw;
+    exports org.apache.poi.sl.draw.geom;
+    exports org.apache.poi.sl.extractor;
+    exports org.apache.poi.sl.image;
+    exports org.apache.poi.sl.usermodel;
+    exports org.apache.poi.ss;
+    exports org.apache.poi.ss.extractor;
+    exports org.apache.poi.ss.format;
+    exports org.apache.poi.ss.formula;
+    exports org.apache.poi.ss.formula.atp;
+    exports org.apache.poi.ss.formula.constant;
+    exports org.apache.poi.ss.formula.eval;
+    exports org.apache.poi.ss.formula.eval.forked;
+    exports org.apache.poi.ss.formula.function;
+    exports org.apache.poi.ss.formula.functions;
+    exports org.apache.poi.ss.formula.ptg;
+    exports org.apache.poi.ss.formula.udf;
+    exports org.apache.poi.ss.usermodel;
+    exports org.apache.poi.ss.usermodel.helpers;
+    exports org.apache.poi.ss.util;
+    exports org.apache.poi.ss.util.cellwalk;
+    exports org.apache.poi.util;
+    exports org.apache.poi.wp.usermodel;
+
+    // test specific exports
+    requires junit;
+    requires net.bytebuddy;
+    opens org.apache.poi.hpsf.basic to junit;
+    opens org.apache.poi.hssf.record.pivot to junit;
+}
\ No newline at end of file
diff --git a/src/multimodule/scratchpad/java9/module-info.class b/src/multimodule/scratchpad/java9/module-info.class
new file mode 100644 (file)
index 0000000..879d58e
Binary files /dev/null and b/src/multimodule/scratchpad/java9/module-info.class differ
diff --git a/src/multimodule/scratchpad/java9/module-info.java b/src/multimodule/scratchpad/java9/module-info.java
new file mode 100644 (file)
index 0000000..df7ea26
--- /dev/null
@@ -0,0 +1,79 @@
+/* ====================================================================
+   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.
+==================================================================== */
+
+module org.apache.poi.scratchpad {
+    requires transitive org.apache.poi.poi;
+    requires java.desktop;
+    requires commons.math3;
+
+    exports org.apache.poi.hmef;
+    exports org.apache.poi.hmef.dev;
+    exports org.apache.poi.hmef.extractor;
+    exports org.apache.poi.hmef.attribute;
+    exports org.apache.poi.hdgf;
+    exports org.apache.poi.hdgf.dev;
+    exports org.apache.poi.hdgf.streams;
+    exports org.apache.poi.hdgf.extractor;
+    exports org.apache.poi.hdgf.pointers;
+    exports org.apache.poi.hdgf.exceptions;
+    exports org.apache.poi.hdgf.chunks;
+    exports org.apache.poi.hwpf;
+    exports org.apache.poi.hwpf.dev;
+    exports org.apache.poi.hwpf.sprm;
+    exports org.apache.poi.hwpf.converter;
+    exports org.apache.poi.hwpf.extractor;
+    exports org.apache.poi.hwpf.usermodel;
+    exports org.apache.poi.hwpf.model;
+    exports org.apache.poi.hwpf.model.io;
+    exports org.apache.poi.hwpf.model.types;
+    // exports org.apache.poi.hwmf;
+    exports org.apache.poi.hwmf.record;
+    exports org.apache.poi.hwmf.draw;
+    exports org.apache.poi.hwmf.usermodel;
+    // exports org.apache.poi.extractor;
+    exports org.apache.poi.extractor.ole2;
+    exports org.apache.poi.hpbf;
+    exports org.apache.poi.hpbf.dev;
+    exports org.apache.poi.hpbf.extractor;
+    exports org.apache.poi.hpbf.model;
+    exports org.apache.poi.hpbf.model.qcbits;
+    // exports org.apache.poi.hslf;
+    exports org.apache.poi.hslf.dev;
+    exports org.apache.poi.hslf.record;
+    exports org.apache.poi.hslf.extractor;
+    exports org.apache.poi.hslf.exceptions;
+    exports org.apache.poi.hslf.usermodel;
+    exports org.apache.poi.hslf.blip;
+    exports org.apache.poi.hslf.model;
+    exports org.apache.poi.hslf.model.textproperties;
+    exports org.apache.poi.hslf.util;
+    // exports org.apache.poi.hssf;
+    exports org.apache.poi.hssf.converter;
+    // exports org.apache.poi.hssf.usermodel;
+    exports org.apache.poi.hsmf;
+    exports org.apache.poi.hsmf.dev;
+    exports org.apache.poi.hsmf.datatypes;
+    exports org.apache.poi.hsmf.extractor;
+    exports org.apache.poi.hsmf.exceptions;
+    exports org.apache.poi.hsmf.parsers;
+    // exports org.apache.poi.hemf;
+    // exports org.apache.poi.hemf.record;
+    exports org.apache.poi.hemf.record.emf;
+    exports org.apache.poi.hemf.record.emfplus;
+    exports org.apache.poi.hemf.draw;
+    exports org.apache.poi.hemf.usermodel;
+}
\ No newline at end of file
diff --git a/src/multimodule/scratchpad/test9/module-info.class b/src/multimodule/scratchpad/test9/module-info.class
new file mode 100644 (file)
index 0000000..86ad206
Binary files /dev/null and b/src/multimodule/scratchpad/test9/module-info.class differ
diff --git a/src/multimodule/scratchpad/test9/module-info.java b/src/multimodule/scratchpad/test9/module-info.java
new file mode 100644 (file)
index 0000000..9360d6f
--- /dev/null
@@ -0,0 +1,84 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+module org.apache.poi.scratchpad {
+    requires transitive org.apache.poi.poi;
+    requires java.desktop;
+    requires commons.math3;
+
+    exports org.apache.poi.hmef;
+    exports org.apache.poi.hmef.dev;
+    exports org.apache.poi.hmef.extractor;
+    exports org.apache.poi.hmef.attribute;
+    exports org.apache.poi.hdgf;
+    exports org.apache.poi.hdgf.dev;
+    exports org.apache.poi.hdgf.streams;
+    exports org.apache.poi.hdgf.extractor;
+    exports org.apache.poi.hdgf.pointers;
+    exports org.apache.poi.hdgf.exceptions;
+    exports org.apache.poi.hdgf.chunks;
+    exports org.apache.poi.hwpf;
+    exports org.apache.poi.hwpf.dev;
+    exports org.apache.poi.hwpf.sprm;
+    exports org.apache.poi.hwpf.converter;
+    exports org.apache.poi.hwpf.extractor;
+    exports org.apache.poi.hwpf.usermodel;
+    exports org.apache.poi.hwpf.model;
+    exports org.apache.poi.hwpf.model.io;
+    exports org.apache.poi.hwpf.model.types;
+    exports org.apache.poi.hwmf.record;
+    exports org.apache.poi.hwmf.draw;
+    exports org.apache.poi.hwmf.usermodel;
+    exports org.apache.poi.extractor.ole2;
+    exports org.apache.poi.hpbf;
+    exports org.apache.poi.hpbf.dev;
+    exports org.apache.poi.hpbf.extractor;
+    exports org.apache.poi.hpbf.model;
+    exports org.apache.poi.hpbf.model.qcbits;
+    exports org.apache.poi.hslf.dev;
+    exports org.apache.poi.hslf.record;
+    exports org.apache.poi.hslf.extractor;
+    exports org.apache.poi.hslf.exceptions;
+    exports org.apache.poi.hslf.usermodel;
+    exports org.apache.poi.hslf.blip;
+    exports org.apache.poi.hslf.model;
+    exports org.apache.poi.hslf.model.textproperties;
+    exports org.apache.poi.hslf.util;
+    exports org.apache.poi.hssf.converter;
+    exports org.apache.poi.hsmf;
+    exports org.apache.poi.hsmf.dev;
+    exports org.apache.poi.hsmf.datatypes;
+    exports org.apache.poi.hsmf.extractor;
+    exports org.apache.poi.hsmf.exceptions;
+    exports org.apache.poi.hsmf.parsers;
+    exports org.apache.poi.hemf.record.emf;
+    exports org.apache.poi.hemf.record.emfplus;
+    exports org.apache.poi.hemf.draw;
+    exports org.apache.poi.hemf.usermodel;
+
+
+    // test specific exports
+    requires junit;
+    requires org.mockito;
+
+    exports org.apache.poi.hemf.hemfplus.extractor to junit;
+    exports org.apache.poi.hslf to junit;
+    exports org.apache.poi.hwmf to junit;
+
+    opens org.apache.poi.hwpf.model to org.mockito;
+    opens org.apache.poi.hwpf.model.types to org.mockito;
+}
\ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java
deleted file mode 100644 (file)
index f8efe0d..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.poifs.crypt.agile;
-
-import static org.apache.poi.poifs.crypt.CryptoFunctions.generateIv;
-import static org.apache.poi.poifs.crypt.CryptoFunctions.generateKey;
-import static org.apache.poi.poifs.crypt.CryptoFunctions.getBlock0;
-import static org.apache.poi.poifs.crypt.CryptoFunctions.getCipher;
-import static org.apache.poi.poifs.crypt.CryptoFunctions.getMessageDigest;
-import static org.apache.poi.poifs.crypt.CryptoFunctions.hashPassword;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.Arrays;
-
-import javax.crypto.Cipher;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.RC2ParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.poifs.crypt.ChainingMode;
-import org.apache.poi.poifs.crypt.ChunkedCipherInputStream;
-import org.apache.poi.poifs.crypt.CipherAlgorithm;
-import org.apache.poi.poifs.crypt.CryptoFunctions;
-import org.apache.poi.poifs.crypt.Decryptor;
-import org.apache.poi.poifs.crypt.EncryptionHeader;
-import org.apache.poi.poifs.crypt.EncryptionInfo;
-import org.apache.poi.poifs.crypt.HashAlgorithm;
-import org.apache.poi.poifs.filesystem.DirectoryNode;
-import org.apache.poi.poifs.filesystem.DocumentInputStream;
-import org.apache.poi.util.LittleEndian;
-
-/**
- * Decryptor implementation for Agile Encryption
- */
-public class AgileDecryptor extends Decryptor {
-    static final byte[] kVerifierInputBlock = longToBytes(0xfea7d2763b4b9e79L);
-    static final byte[] kHashedVerifierBlock = longToBytes(0xd7aa0f6d3061344eL);
-    static final byte[] kCryptoKeyBlock = longToBytes(0x146e0be7abacd0d6L);
-    static final byte[] kIntegrityKeyBlock = longToBytes(0x5fb2ad010cb9e1f6L);
-    static final byte[] kIntegrityValueBlock = longToBytes(0xa0677f02b22c8433L);
-
-    private long _length = -1;
-
-    protected AgileDecryptor() {
-    }
-
-    protected AgileDecryptor(AgileDecryptor other) {
-        super(other);
-        _length = other._length;
-    }
-
-    private static byte[] longToBytes(long l) {
-        return ByteBuffer.allocate(Long.BYTES).putLong(l).array();
-    }
-
-    /**
-     * set decryption password
-     */
-    @Override
-    public boolean verifyPassword(String password) throws GeneralSecurityException {
-        AgileEncryptionVerifier ver = (AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
-        AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
-
-        int blockSize = header.getBlockSize();
-
-        byte[] pwHash = hashPassword(password, ver.getHashAlgorithm(), ver.getSalt(), ver.getSpinCount());
-
-        /*
-         * encryptedVerifierHashInput: This attribute MUST be generated by using the following steps:
-         * 1. Generate a random array of bytes with the number of bytes used specified by the saltSize
-         *    attribute.
-         * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password,
-         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
-         *    consisting of the following bytes: 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, and 0x79.
-         * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue
-         *    attribute as an initialization vector as specified in section 2.3.4.12. If the array of bytes is not an
-         *    integral multiple of blockSize bytes, pad the array with 0x00 to the next integral multiple of
-         *    blockSize bytes.
-         * 4. Use base64 to encode the result of step 3.
-         */
-        byte[] verfierInputEnc = hashInput(ver, pwHash, kVerifierInputBlock, ver.getEncryptedVerifier(), Cipher.DECRYPT_MODE);
-        setVerifier(verfierInputEnc);
-        MessageDigest hashMD = getMessageDigest(ver.getHashAlgorithm());
-        byte[] verifierHash = hashMD.digest(verfierInputEnc);
-
-        /*
-         * encryptedVerifierHashValue: This attribute MUST be generated by using the following steps:
-         * 1. Obtain the hash value of the random array of bytes generated in step 1 of the steps for
-         *    encryptedVerifierHashInput.
-         * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password,
-         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
-         *    consisting of the following bytes: 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, and 0x4e.
-         * 3. Encrypt the hash value obtained in step 1 by using the binary form of the saltValue attribute as
-         *    an initialization vector as specified in section 2.3.4.12. If hashSize is not an integral multiple of
-         *    blockSize bytes, pad the hash value with 0x00 to an integral multiple of blockSize bytes.
-         * 4. Use base64 to encode the result of step 3.
-         */
-        byte[] verifierHashDec = hashInput(ver, pwHash, kHashedVerifierBlock, ver.getEncryptedVerifierHash(), Cipher.DECRYPT_MODE);
-        verifierHashDec = getBlock0(verifierHashDec, ver.getHashAlgorithm().hashSize);
-
-        /*
-         * encryptedKeyValue: This attribute MUST be generated by using the following steps:
-         * 1. Generate a random array of bytes that is the same size as specified by the
-         *    Encryptor.KeyData.keyBits attribute of the parent element.
-         * 2. Generate an encryption key as specified in section 2.3.4.11, using the user-supplied password,
-         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
-         *    consisting of the following bytes: 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, and 0xd6.
-         * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue
-         *    attribute as an initialization vector as specified in section 2.3.4.12. If the array of bytes is not an
-         *    integral multiple of blockSize bytes, pad the array with 0x00 to an integral multiple of
-         *    blockSize bytes.
-         * 4. Use base64 to encode the result of step 3.
-         */
-        byte[] keyspec = hashInput(ver, pwHash, kCryptoKeyBlock, ver.getEncryptedKey(), Cipher.DECRYPT_MODE);
-        keyspec = getBlock0(keyspec, header.getKeySize()/8);
-        SecretKeySpec secretKey = new SecretKeySpec(keyspec, header.getCipherAlgorithm().jceId);
-
-        /*
-         * 1. Obtain the intermediate key by decrypting the encryptedKeyValue from a KeyEncryptor
-         *    contained within the KeyEncryptors sequence. Use this key for encryption operations in the
-         *    remaining steps of this section.
-         * 2. Generate a random array of bytes, known as Salt, of the same length as the value of the
-         *    KeyData.hashSize attribute.
-         * 3. Encrypt the random array of bytes generated in step 2 by using the binary form of the
-         *    KeyData.saltValue attribute and a blockKey byte array consisting of the following bytes: 0x5f,
-         *    0xb2, 0xad, 0x01, 0x0c, 0xb9, 0xe1, and 0xf6 used to form an initialization vector as specified in
-         *    section 2.3.4.12. If the array of bytes is not an integral multiple of blockSize bytes, pad the
-         *    array with 0x00 to the next integral multiple of blockSize bytes.
-         * 4. Assign the encryptedHmacKey attribute to the base64-encoded form of the result of step 3.
-         */
-        byte[] vec = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityKeyBlock, blockSize);
-        CipherAlgorithm cipherAlgo = header.getCipherAlgorithm();
-        Cipher cipher = getCipher(secretKey, cipherAlgo, header.getChainingMode(), vec, Cipher.DECRYPT_MODE);
-        byte[] hmacKey = cipher.doFinal(header.getEncryptedHmacKey());
-        hmacKey = getBlock0(hmacKey, header.getHashAlgorithm().hashSize);
-
-        /*
-         * 5. Generate an HMAC, as specified in [RFC2104], of the encrypted form of the data (message),
-         *    which the DataIntegrity element will verify by using the Salt generated in step 2 as the key.
-         *    Note that the entire EncryptedPackage stream (1), including the StreamSize field, MUST be
-         *    used as the message.
-         * 6. Encrypt the HMAC as in step 3 by using a blockKey byte array consisting of the following bytes:
-         *    0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, and 0x33.
-         * 7. Assign the encryptedHmacValue attribute to the base64-encoded form of the result of step 6.
-         */
-        vec = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityValueBlock, blockSize);
-        cipher = getCipher(secretKey, cipherAlgo, ver.getChainingMode(), vec, Cipher.DECRYPT_MODE);
-        byte[] hmacValue = cipher.doFinal(header.getEncryptedHmacValue());
-        hmacValue = getBlock0(hmacValue, header.getHashAlgorithm().hashSize);
-
-        if (Arrays.equals(verifierHashDec, verifierHash)) {
-            setSecretKey(secretKey);
-            setIntegrityHmacKey(hmacKey);
-            setIntegrityHmacValue(hmacValue);
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    protected static int getNextBlockSize(int inputLen, int blockSize) {
-        return (int)Math.ceil(inputLen / (double)blockSize) * blockSize;
-    }
-
-    /* package */ static byte[] hashInput(AgileEncryptionVerifier ver, byte[] pwHash, byte[] blockKey, byte[] inputKey, int cipherMode) {
-        CipherAlgorithm cipherAlgo = ver.getCipherAlgorithm();
-        ChainingMode chainMode = ver.getChainingMode();
-        int keySize = ver.getKeySize()/8;
-        int blockSize = ver.getBlockSize();
-        HashAlgorithm hashAlgo = ver.getHashAlgorithm();
-
-        byte[] intermedKey = generateKey(pwHash, hashAlgo, blockKey, keySize);
-        SecretKey skey = new SecretKeySpec(intermedKey, cipherAlgo.jceId);
-        byte[] iv = generateIv(hashAlgo, ver.getSalt(), null, blockSize);
-        Cipher cipher = getCipher(skey, cipherAlgo, chainMode, iv, cipherMode);
-        byte[] hashFinal;
-
-        try {
-            inputKey = getBlock0(inputKey, getNextBlockSize(inputKey.length, blockSize));
-            hashFinal = cipher.doFinal(inputKey);
-            return hashFinal;
-        } catch (GeneralSecurityException e) {
-            throw new EncryptedDocumentException(e);
-        }
-    }
-
-    @Override
-    public InputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException {
-        DocumentInputStream dis = dir.createDocumentInputStream(DEFAULT_POIFS_ENTRY);
-        _length = dis.readLong();
-        return new AgileCipherInputStream(dis, _length);
-    }
-
-    @Override
-    public long getLength(){
-        if(_length == -1) {
-            throw new IllegalStateException("EcmaDecryptor.getDataStream() was not called");
-        }
-        return _length;
-    }
-
-
-    protected static Cipher initCipherForBlock(Cipher existing, int block, boolean lastChunk, EncryptionInfo encryptionInfo, SecretKey skey, int encryptionMode)
-    throws GeneralSecurityException {
-        EncryptionHeader header = encryptionInfo.getHeader();
-        String padding = (lastChunk ? "PKCS5Padding" : "NoPadding");
-        if (existing == null || !existing.getAlgorithm().endsWith(padding)) {
-            existing = getCipher(skey, header.getCipherAlgorithm(), header.getChainingMode(), header.getKeySalt(), encryptionMode, padding);
-        }
-
-        byte[] blockKey = new byte[4];
-        LittleEndian.putInt(blockKey, 0, block);
-        byte[] iv = generateIv(header.getHashAlgorithm(), header.getKeySalt(), blockKey, header.getBlockSize());
-
-        AlgorithmParameterSpec aps;
-        if (header.getCipherAlgorithm() == CipherAlgorithm.rc2) {
-            aps = new RC2ParameterSpec(skey.getEncoded().length*8, iv);
-        } else {
-            aps = new IvParameterSpec(iv);
-        }
-
-        existing.init(encryptionMode, skey, aps);
-
-        return existing;
-    }
-
-    /**
-     * 2.3.4.15 Data Encryption (Agile Encryption)
-     *
-     * The EncryptedPackage stream (1) MUST be encrypted in 4096-byte segments to facilitate nearly
-     * random access while allowing CBC modes to be used in the encryption process.
-     * The initialization vector for the encryption process MUST be obtained by using the zero-based
-     * segment number as a blockKey and the binary form of the KeyData.saltValue as specified in
-     * section 2.3.4.12. The block number MUST be represented as a 32-bit unsigned integer.
-     * Data blocks MUST then be encrypted by using the initialization vector and the intermediate key
-     * obtained by decrypting the encryptedKeyValue from a KeyEncryptor contained within the
-     * KeyEncryptors sequence as specified in section 2.3.4.10. The final data block MUST be padded to
-     * the next integral multiple of the KeyData.blockSize value. Any padding bytes can be used. Note
-     * that the StreamSize field of the EncryptedPackage field specifies the number of bytes of
-     * unencrypted data as specified in section 2.3.4.4.
-     */
-    private class AgileCipherInputStream extends ChunkedCipherInputStream {
-        public AgileCipherInputStream(DocumentInputStream stream, long size)
-        throws GeneralSecurityException {
-            super(stream, size, 4096);
-        }
-
-        // TODO: calculate integrity hmac while reading the stream
-        // for a post-validation of the data
-
-        @Override
-        protected Cipher initCipherForBlock(Cipher cipher, int block)
-        throws GeneralSecurityException {
-            return AgileDecryptor.initCipherForBlock(cipher, block, false, getEncryptionInfo(), getSecretKey(), Cipher.DECRYPT_MODE);
-        }
-    }
-
-    @Override
-    public AgileDecryptor copy() {
-        return new AgileDecryptor(this);
-    }
-}
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java
deleted file mode 100644 (file)
index 0c4983e..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.poifs.crypt.agile;
-
-import java.util.Map;
-import java.util.function.Supplier;
-
-import com.microsoft.schemas.office.x2006.encryption.CTDataIntegrity;
-import com.microsoft.schemas.office.x2006.encryption.CTKeyData;
-import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;
-import com.microsoft.schemas.office.x2006.encryption.STCipherChaining;
-import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.poifs.crypt.ChainingMode;
-import org.apache.poi.poifs.crypt.CipherAlgorithm;
-import org.apache.poi.poifs.crypt.EncryptionHeader;
-import org.apache.poi.poifs.crypt.HashAlgorithm;
-import org.apache.poi.util.GenericRecordUtil;
-
-public class AgileEncryptionHeader extends EncryptionHeader {
-    private byte[] encryptedHmacKey;
-    private byte[] encryptedHmacValue;
-
-    public AgileEncryptionHeader(String descriptor) {
-        this(AgileEncryptionInfoBuilder.parseDescriptor(descriptor));
-    }
-
-    public AgileEncryptionHeader(AgileEncryptionHeader other) {
-        super(other);
-        encryptedHmacKey = (other.encryptedHmacKey == null) ? null : other.encryptedHmacKey.clone();
-        encryptedHmacValue = (other.encryptedHmacValue == null) ? null : other.encryptedHmacValue.clone();
-    }
-
-    protected AgileEncryptionHeader(EncryptionDocument ed) {
-        CTKeyData keyData;
-        try {
-            keyData = ed.getEncryption().getKeyData();
-            if (keyData == null) {
-                throw new NullPointerException("keyData not set");
-            }
-        } catch (Exception e) {
-            throw new EncryptedDocumentException("Unable to parse keyData");
-        }
-
-        int keyBits = (int)keyData.getKeyBits();
-
-        CipherAlgorithm ca = CipherAlgorithm.fromXmlId(keyData.getCipherAlgorithm().toString(), keyBits);
-        setCipherAlgorithm(ca);
-        setCipherProvider(ca.provider);
-
-        setKeySize(keyBits);
-        setFlags(0);
-        setSizeExtra(0);
-        setCspName(null);
-        setBlockSize(keyData.getBlockSize());
-
-        switch (keyData.getCipherChaining().intValue()) {
-        case STCipherChaining.INT_CHAINING_MODE_CBC:
-            setChainingMode(ChainingMode.cbc);
-            break;
-        case STCipherChaining.INT_CHAINING_MODE_CFB:
-            setChainingMode(ChainingMode.cfb);
-            break;
-        default:
-            throw new EncryptedDocumentException("Unsupported chaining mode - "+ keyData.getCipherChaining());
-        }
-
-        int hashSize = keyData.getHashSize();
-
-        HashAlgorithm ha = HashAlgorithm.fromEcmaId(keyData.getHashAlgorithm().toString());
-        setHashAlgorithm(ha);
-
-        if (getHashAlgorithm().hashSize != hashSize) {
-            throw new EncryptedDocumentException("Unsupported hash algorithm: " +
-                    keyData.getHashAlgorithm() + " @ " + hashSize + " bytes");
-        }
-
-        int saltLength = keyData.getSaltSize();
-        setKeySalt(keyData.getSaltValue());
-        if (getKeySalt().length != saltLength) {
-            throw new EncryptedDocumentException("Invalid salt length");
-        }
-
-        CTDataIntegrity di = ed.getEncryption().getDataIntegrity();
-        setEncryptedHmacKey(di.getEncryptedHmacKey());
-        setEncryptedHmacValue(di.getEncryptedHmacValue());
-    }
-
-
-    public AgileEncryptionHeader(CipherAlgorithm algorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode chainingMode) {
-        setCipherAlgorithm(algorithm);
-        setHashAlgorithm(hashAlgorithm);
-        setKeySize(keyBits);
-        setBlockSize(blockSize);
-        setChainingMode(chainingMode);
-    }
-
-    // make method visible for this package
-    @Override
-    protected void setKeySalt(byte[] salt) {
-        if (salt == null || salt.length != getBlockSize()) {
-            throw new EncryptedDocumentException("invalid verifier salt");
-        }
-        super.setKeySalt(salt);
-    }
-
-    public byte[] getEncryptedHmacKey() {
-        return encryptedHmacKey;
-    }
-
-    protected void setEncryptedHmacKey(byte[] encryptedHmacKey) {
-        this.encryptedHmacKey = (encryptedHmacKey == null) ? null : encryptedHmacKey.clone();
-    }
-
-    public byte[] getEncryptedHmacValue() {
-        return encryptedHmacValue;
-    }
-
-    protected void setEncryptedHmacValue(byte[] encryptedHmacValue) {
-        this.encryptedHmacValue = (encryptedHmacValue == null) ? null : encryptedHmacValue.clone();
-    }
-
-    @Override
-    public Map<String, Supplier<?>> getGenericProperties() {
-        return GenericRecordUtil.getGenericProperties(
-            "base", super::getGenericProperties,
-            "encryptedHmacKey", this::getEncryptedHmacKey,
-            "encryptedHmacValue", this::getEncryptedHmacValue
-        );
-    }
-
-    @Override
-    public AgileEncryptionHeader copy() {
-        return new AgileEncryptionHeader(this);
-    }
-}
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionInfoBuilder.java b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionInfoBuilder.java
deleted file mode 100644 (file)
index d149d3a..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.poifs.crypt.agile;
-
-import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.poifs.crypt.ChainingMode;
-import org.apache.poi.poifs.crypt.CipherAlgorithm;
-import org.apache.poi.poifs.crypt.EncryptionInfo;
-import org.apache.poi.poifs.crypt.EncryptionInfoBuilder;
-import org.apache.poi.poifs.crypt.EncryptionMode;
-import org.apache.poi.poifs.crypt.HashAlgorithm;
-import org.apache.poi.util.LittleEndianInput;
-import org.apache.xmlbeans.XmlException;
-
-import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;
-
-public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {
-    
-    @Override
-    public void initialize(EncryptionInfo info, LittleEndianInput dis) throws IOException {
-        EncryptionDocument ed = parseDescriptor((InputStream)dis);
-        info.setHeader(new AgileEncryptionHeader(ed));
-        info.setVerifier(new AgileEncryptionVerifier(ed));
-        if (info.getVersionMajor() == EncryptionMode.agile.versionMajor
-            && info.getVersionMinor() == EncryptionMode.agile.versionMinor) {
-            AgileDecryptor dec = new AgileDecryptor();
-            dec.setEncryptionInfo(info);
-            info.setDecryptor(dec);
-            AgileEncryptor enc = new AgileEncryptor();
-            enc.setEncryptionInfo(info);
-            info.setEncryptor(enc);
-        }
-    }
-
-    @Override
-    public void initialize(EncryptionInfo info, CipherAlgorithm cipherAlgorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode chainingMode) {
-        if (cipherAlgorithm == null) {
-            cipherAlgorithm = CipherAlgorithm.aes128;
-        }
-        if (cipherAlgorithm == CipherAlgorithm.rc4) {
-            throw new EncryptedDocumentException("RC4 must not be used with agile encryption.");
-        }
-        if (hashAlgorithm == null) {
-            hashAlgorithm = HashAlgorithm.sha1;
-        }
-        if (chainingMode == null) {
-            chainingMode = ChainingMode.cbc;
-        }
-        if (!(chainingMode == ChainingMode.cbc || chainingMode == ChainingMode.cfb)) {
-            throw new EncryptedDocumentException("Agile encryption only supports CBC/CFB chaining.");
-        }
-        if (keyBits == -1) {
-            keyBits = cipherAlgorithm.defaultKeySize;
-        }
-        if (blockSize == -1) {
-            blockSize = cipherAlgorithm.blockSize;
-        }
-        boolean found = false;
-        for (int ks : cipherAlgorithm.allowedKeySize) {
-            found |= (ks == keyBits);
-        }
-        if (!found) {
-            throw new EncryptedDocumentException("KeySize "+keyBits+" not allowed for Cipher "+ cipherAlgorithm);
-        }
-        info.setHeader(new AgileEncryptionHeader(cipherAlgorithm, hashAlgorithm, keyBits, blockSize, chainingMode));
-        info.setVerifier(new AgileEncryptionVerifier(cipherAlgorithm, hashAlgorithm, keyBits, blockSize, chainingMode));
-        AgileDecryptor dec = new AgileDecryptor();
-        dec.setEncryptionInfo(info);
-        info.setDecryptor(dec);
-        AgileEncryptor enc = new AgileEncryptor();
-        enc.setEncryptionInfo(info);
-        info.setEncryptor(enc);
-    }
-    
-    protected static EncryptionDocument parseDescriptor(String descriptor) {
-        try {
-            return EncryptionDocument.Factory.parse(descriptor, DEFAULT_XML_OPTIONS);
-        } catch (XmlException e) {
-            throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);
-        }
-    }
-
-    protected static EncryptionDocument parseDescriptor(InputStream descriptor) {
-        try {
-            return EncryptionDocument.Factory.parse(descriptor, DEFAULT_XML_OPTIONS);
-        } catch (Exception e) {
-            throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);
-        }
-    }
-}
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java
deleted file mode 100644 (file)
index 4535b4b..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.poifs.crypt.agile;
-
-import java.util.Iterator;
-
-import com.microsoft.schemas.office.x2006.encryption.CTKeyEncryptor;
-import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;
-import com.microsoft.schemas.office.x2006.encryption.STCipherChaining;
-import com.microsoft.schemas.office.x2006.keyEncryptor.password.CTPasswordKeyEncryptor;
-import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.poifs.crypt.ChainingMode;
-import org.apache.poi.poifs.crypt.CipherAlgorithm;
-import org.apache.poi.poifs.crypt.EncryptionVerifier;
-import org.apache.poi.poifs.crypt.HashAlgorithm;
-
-/**
- * Used when checking if a key is valid for a document
- */
-public class AgileEncryptionVerifier extends EncryptionVerifier {
-
-    private int keyBits = -1;
-    private int blockSize = -1;
-
-    @SuppressWarnings("unused")
-    public AgileEncryptionVerifier(String descriptor) {
-        this(AgileEncryptionInfoBuilder.parseDescriptor(descriptor));
-    }
-
-    protected AgileEncryptionVerifier(EncryptionDocument ed) {
-        Iterator<CTKeyEncryptor> encList = ed.getEncryption().getKeyEncryptors().getKeyEncryptorList().iterator();
-        CTPasswordKeyEncryptor keyData;
-        try {
-            keyData = encList.next().getEncryptedPasswordKey();
-            if (keyData == null) {
-                throw new NullPointerException("encryptedKey not set");
-            }
-        } catch (Exception e) {
-            throw new EncryptedDocumentException("Unable to parse keyData", e);
-        }
-
-        int kb = (int)keyData.getKeyBits();
-        CipherAlgorithm ca = CipherAlgorithm.fromXmlId(keyData.getCipherAlgorithm().toString(), kb);
-        setCipherAlgorithm(ca);
-
-        setKeySize(kb);
-
-        int blockSize = keyData.getBlockSize();
-        setBlockSize(blockSize);
-
-        int hashSize = keyData.getHashSize();
-
-        HashAlgorithm ha = HashAlgorithm.fromEcmaId(keyData.getHashAlgorithm().toString());
-        setHashAlgorithm(ha);
-
-        if (getHashAlgorithm().hashSize != hashSize) {
-            throw new EncryptedDocumentException("Unsupported hash algorithm: " +
-                    keyData.getHashAlgorithm() + " @ " + hashSize + " bytes");
-        }
-
-        setSpinCount(keyData.getSpinCount());
-        setEncryptedVerifier(keyData.getEncryptedVerifierHashInput());
-        setSalt(keyData.getSaltValue());
-        setEncryptedKey(keyData.getEncryptedKeyValue());
-        setEncryptedVerifierHash(keyData.getEncryptedVerifierHashValue());
-
-        int saltSize = keyData.getSaltSize();
-        if (saltSize != getSalt().length) {
-            throw new EncryptedDocumentException("Invalid salt size");
-        }
-
-        switch (keyData.getCipherChaining().intValue()) {
-            case STCipherChaining.INT_CHAINING_MODE_CBC:
-                setChainingMode(ChainingMode.cbc);
-                break;
-            case STCipherChaining.INT_CHAINING_MODE_CFB:
-                setChainingMode(ChainingMode.cfb);
-                break;
-            default:
-                throw new EncryptedDocumentException("Unsupported chaining mode - "+ keyData.getCipherChaining());
-        }
-    }
-
-    public AgileEncryptionVerifier(CipherAlgorithm cipherAlgorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode chainingMode) {
-        setCipherAlgorithm(cipherAlgorithm);
-        setHashAlgorithm(hashAlgorithm);
-        setChainingMode(chainingMode);
-        setKeySize(keyBits);
-        setBlockSize(blockSize);
-        setSpinCount(100000); // TODO: use parameter
-    }
-
-    public AgileEncryptionVerifier(AgileEncryptionVerifier other) {
-        super(other);
-        keyBits = other.keyBits;
-        blockSize = other.blockSize;
-    }
-
-    @Override
-    protected void setSalt(byte[] salt) {
-        if (salt == null || salt.length != getCipherAlgorithm().blockSize) {
-            throw new EncryptedDocumentException("invalid verifier salt");
-        }
-        super.setSalt(salt);
-    }
-
-    // make method visible for this package
-    @Override
-    protected void setEncryptedVerifier(byte[] encryptedVerifier) {
-        super.setEncryptedVerifier(encryptedVerifier);
-    }
-
-    // make method visible for this package
-    @Override
-    protected void setEncryptedVerifierHash(byte[] encryptedVerifierHash) {
-        super.setEncryptedVerifierHash(encryptedVerifierHash);
-    }
-
-    // make method visible for this package
-    @Override
-    protected void setEncryptedKey(byte[] encryptedKey) {
-        super.setEncryptedKey(encryptedKey);
-    }
-
-    @Override
-    public AgileEncryptionVerifier copy() {
-        return new AgileEncryptionVerifier(this);
-    }
-
-
-    /**
-     * The keysize (in bits) of the verifier data. This usually equals the keysize of the header,
-     * but only on a few exceptions, like files generated by Office for Mac, can be
-     * different.
-     *
-     * @return the keysize (in bits) of the verifier.
-     */
-    public int getKeySize() {
-        return keyBits;
-    }
-
-
-    /**
-     * The blockSize (in bytes) of the verifier data.
-     * This usually equals the blocksize of the header.
-     *
-     * @return the blockSize (in bytes) of the verifier,
-     */
-    public int getBlockSize() {
-        return blockSize;
-    }
-
-    /**
-     * Sets the keysize (in bits) of the verifier
-     *
-     * @param keyBits the keysize (in bits)
-     */
-    protected void setKeySize(int keyBits) {
-        this.keyBits = keyBits;
-        for (int allowedBits : getCipherAlgorithm().allowedKeySize) {
-            if (allowedBits == keyBits) {
-                return;
-            }
-        }
-        throw new EncryptedDocumentException("KeySize "+keyBits+" not allowed for cipher "+getCipherAlgorithm());
-    }
-
-
-    /**
-     * Sets the blockSize (in bytes) of the verifier
-     *
-     * @param blockSize the blockSize (in bytes)
-     */
-    protected void setBlockSize(int blockSize) {
-        this.blockSize = blockSize;
-    }
-
-    @Override
-    protected final void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) {
-        super.setCipherAlgorithm(cipherAlgorithm);
-        if (cipherAlgorithm.allowedKeySize.length == 1) {
-            setKeySize(cipherAlgorithm.defaultKeySize);
-        }
-    }
-}
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java
deleted file mode 100644 (file)
index 05ab275..0000000
+++ /dev/null
@@ -1,424 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.poifs.crypt.agile;
-
-import static org.apache.poi.poifs.crypt.CryptoFunctions.getBlock0;
-import static org.apache.poi.poifs.crypt.CryptoFunctions.getCipher;
-import static org.apache.poi.poifs.crypt.CryptoFunctions.getMessageDigest;
-import static org.apache.poi.poifs.crypt.CryptoFunctions.hashPassword;
-import static org.apache.poi.poifs.crypt.DataSpaceMapUtils.createEncryptionEntry;
-import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.getNextBlockSize;
-import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.hashInput;
-import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kCryptoKeyBlock;
-import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kHashedVerifierBlock;
-import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kIntegrityKeyBlock;
-import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kIntegrityValueBlock;
-import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kVerifierInputBlock;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.security.SecureRandom;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-
-import javax.crypto.Cipher;
-import javax.crypto.Mac;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-
-import com.microsoft.schemas.office.x2006.encryption.CTDataIntegrity;
-import com.microsoft.schemas.office.x2006.encryption.CTEncryption;
-import com.microsoft.schemas.office.x2006.encryption.CTKeyData;
-import com.microsoft.schemas.office.x2006.encryption.CTKeyEncryptor;
-import com.microsoft.schemas.office.x2006.encryption.CTKeyEncryptors;
-import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;
-import com.microsoft.schemas.office.x2006.encryption.STCipherAlgorithm;
-import com.microsoft.schemas.office.x2006.encryption.STCipherChaining;
-import com.microsoft.schemas.office.x2006.encryption.STHashAlgorithm;
-import com.microsoft.schemas.office.x2006.keyEncryptor.password.CTPasswordKeyEncryptor;
-import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.poifs.crypt.ChunkedCipherOutputStream;
-import org.apache.poi.poifs.crypt.CryptoFunctions;
-import org.apache.poi.poifs.crypt.DataSpaceMapUtils;
-import org.apache.poi.poifs.crypt.EncryptionInfo;
-import org.apache.poi.poifs.crypt.Encryptor;
-import org.apache.poi.poifs.crypt.HashAlgorithm;
-import org.apache.poi.poifs.filesystem.DirectoryNode;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.LittleEndianByteArrayOutputStream;
-import org.apache.poi.util.LittleEndianConsts;
-import org.apache.xmlbeans.XmlOptions;
-
-public class AgileEncryptor extends Encryptor {
-
-    //arbitrarily selected; may need to increase
-    private static final int MAX_RECORD_LENGTH = 1_000_000;
-
-    private byte[] integritySalt;
-    private byte[] pwHash;
-
-       protected AgileEncryptor() {}
-
-    protected AgileEncryptor(AgileEncryptor other) {
-           super(other);
-           integritySalt = (other.integritySalt == null) ? null : other.integritySalt.clone();
-           pwHash = (other.pwHash == null) ? null : other.pwHash.clone();
-    }
-
-    @Override
-    public void confirmPassword(String password) {
-        // see [MS-OFFCRYPTO] - 2.3.3 EncryptionVerifier
-        Random r = new SecureRandom();
-        AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
-        int blockSize = header.getBlockSize();
-        int keySize = header.getKeySize()/8;
-        int hashSize = header.getHashAlgorithm().hashSize;
-
-        byte[] newVerifierSalt = IOUtils.safelyAllocate(blockSize, MAX_RECORD_LENGTH)
-             , newVerifier = IOUtils.safelyAllocate(blockSize, MAX_RECORD_LENGTH)
-             , newKeySalt = IOUtils.safelyAllocate(blockSize, MAX_RECORD_LENGTH)
-             , newKeySpec = IOUtils.safelyAllocate(keySize, MAX_RECORD_LENGTH)
-             , newIntegritySalt = IOUtils.safelyAllocate(hashSize, MAX_RECORD_LENGTH);
-        r.nextBytes(newVerifierSalt); // blocksize
-        r.nextBytes(newVerifier); // blocksize
-        r.nextBytes(newKeySalt); // blocksize
-        r.nextBytes(newKeySpec); // keysize
-        r.nextBytes(newIntegritySalt); // hashsize
-
-        confirmPassword(password, newKeySpec, newKeySalt, newVerifierSalt, newVerifier, newIntegritySalt);
-    }
-
-       @Override
-    public void confirmPassword(String password, byte[] keySpec, byte[] keySalt, byte[] verifier, byte[] verifierSalt, byte[] integritySalt) {
-        AgileEncryptionVerifier ver = (AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
-        AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
-
-        ver.setSalt(verifierSalt);
-        header.setKeySalt(keySalt);
-
-        int blockSize = header.getBlockSize();
-
-        pwHash = hashPassword(password, ver.getHashAlgorithm(), verifierSalt, ver.getSpinCount());
-
-        /*
-         * encryptedVerifierHashInput: This attribute MUST be generated by using the following steps:
-         * 1. Generate a random array of bytes with the number of bytes used specified by the saltSize
-         *    attribute.
-         * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password,
-         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
-         *    consisting of the following bytes: 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, and 0x79.
-         * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue
-         *    attribute as an initialization vector as specified in section 2.3.4.12. If the array of bytes is not an
-         *    integral multiple of blockSize bytes, pad the array with 0x00 to the next integral multiple of
-         *    blockSize bytes.
-         * 4. Use base64 to encode the result of step 3.
-         */
-        byte[] encryptedVerifier = hashInput(ver, pwHash, kVerifierInputBlock, verifier, Cipher.ENCRYPT_MODE);
-        ver.setEncryptedVerifier(encryptedVerifier);
-
-
-        /*
-         * encryptedVerifierHashValue: This attribute MUST be generated by using the following steps:
-         * 1. Obtain the hash value of the random array of bytes generated in step 1 of the steps for
-         *    encryptedVerifierHashInput.
-         * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password,
-         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
-         *    consisting of the following bytes: 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, and 0x4e.
-         * 3. Encrypt the hash value obtained in step 1 by using the binary form of the saltValue attribute as
-         *    an initialization vector as specified in section 2.3.4.12. If hashSize is not an integral multiple of
-         *    blockSize bytes, pad the hash value with 0x00 to an integral multiple of blockSize bytes.
-         * 4. Use base64 to encode the result of step 3.
-         */
-        MessageDigest hashMD = getMessageDigest(ver.getHashAlgorithm());
-        byte[] hashedVerifier = hashMD.digest(verifier);
-        byte[] encryptedVerifierHash = hashInput(ver, pwHash, kHashedVerifierBlock, hashedVerifier, Cipher.ENCRYPT_MODE);
-        ver.setEncryptedVerifierHash(encryptedVerifierHash);
-
-        /*
-         * encryptedKeyValue: This attribute MUST be generated by using the following steps:
-         * 1. Generate a random array of bytes that is the same size as specified by the
-         *    Encryptor.KeyData.keyBits attribute of the parent element.
-         * 2. Generate an encryption key as specified in section 2.3.4.11, using the user-supplied password,
-         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
-         *    consisting of the following bytes: 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, and 0xd6.
-         * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue
-         *    attribute as an initialization vector as specified in section 2.3.4.12. If the array of bytes is not an
-         *    integral multiple of blockSize bytes, pad the array with 0x00 to an integral multiple of
-         *    blockSize bytes.
-         * 4. Use base64 to encode the result of step 3.
-         */
-        byte[] encryptedKey = hashInput(ver, pwHash, kCryptoKeyBlock, keySpec, Cipher.ENCRYPT_MODE);
-        ver.setEncryptedKey(encryptedKey);
-
-        SecretKey secretKey = new SecretKeySpec(keySpec, header.getCipherAlgorithm().jceId);
-        setSecretKey(secretKey);
-
-        /*
-         * 2.3.4.14 DataIntegrity Generation (Agile Encryption)
-         *
-         * The DataIntegrity element contained within an Encryption element MUST be generated by using
-         * the following steps:
-         * 1. Obtain the intermediate key by decrypting the encryptedKeyValue from a KeyEncryptor
-         *    contained within the KeyEncryptors sequence. Use this key for encryption operations in the
-         *    remaining steps of this section.
-         * 2. Generate a random array of bytes, known as Salt, of the same length as the value of the
-         *    KeyData.hashSize attribute.
-         * 3. Encrypt the random array of bytes generated in step 2 by using the binary form of the
-         *    KeyData.saltValue attribute and a blockKey byte array consisting of the following bytes:
-         *    0x5f, 0xb2, 0xad, 0x01, 0x0c, 0xb9, 0xe1, and 0xf6 used to form an initialization vector as
-         *    specified in section 2.3.4.12. If the array of bytes is not an integral multiple of blockSize
-         *    bytes, pad the array with 0x00 to the next integral multiple of blockSize bytes.
-         * 4. Assign the encryptedHmacKey attribute to the base64-encoded form of the result of step 3.
-         * 5. Generate an HMAC, as specified in [RFC2104], of the encrypted form of the data (message),
-         *    which the DataIntegrity element will verify by using the Salt generated in step 2 as the key.
-         *    Note that the entire EncryptedPackage stream (1), including the StreamSize field, MUST be
-         *    used as the message.
-         * 6. Encrypt the HMAC as in step 3 by using a blockKey byte array consisting of the following bytes:
-         *    0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, and 0x33.
-         * 7.  Assign the encryptedHmacValue attribute to the base64-encoded form of the result of step 6.
-         */
-        this.integritySalt = integritySalt.clone();
-
-        try {
-            byte[] vec = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityKeyBlock, header.getBlockSize());
-            Cipher cipher = getCipher(secretKey, header.getCipherAlgorithm(), header.getChainingMode(), vec, Cipher.ENCRYPT_MODE);
-            byte[] hmacKey = getBlock0(this.integritySalt, getNextBlockSize(this.integritySalt.length, blockSize));
-            byte[] encryptedHmacKey = cipher.doFinal(hmacKey);
-            header.setEncryptedHmacKey(encryptedHmacKey);
-        } catch (GeneralSecurityException e) {
-            throw new EncryptedDocumentException(e);
-        }
-       }
-
-    @Override
-    public OutputStream getDataStream(DirectoryNode dir)
-            throws IOException, GeneralSecurityException {
-        // TODO: initialize headers
-        return new AgileCipherOutputStream(dir);
-    }
-
-    /**
-     * Generate an HMAC, as specified in [RFC2104], of the encrypted form of the data (message),
-     * which the DataIntegrity element will verify by using the Salt generated in step 2 as the key.
-     * Note that the entire EncryptedPackage stream (1), including the StreamSize field, MUST be
-     * used as the message.
-     *
-     * Encrypt the HMAC as in step 3 by using a blockKey byte array consisting of the following bytes:
-     * 0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, and 0x33.
-     **/
-    protected void updateIntegrityHMAC(File tmpFile, int oleStreamSize) throws GeneralSecurityException, IOException {
-        // as the integrity hmac needs to contain the StreamSize,
-        // it's not possible to calculate it on-the-fly while buffering
-        // TODO: add stream size parameter to getDataStream()
-        AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
-        int blockSize = header.getBlockSize();
-        HashAlgorithm hashAlgo = header.getHashAlgorithm();
-        Mac integrityMD = CryptoFunctions.getMac(hashAlgo);
-        byte[] hmacKey = getBlock0(this.integritySalt, getNextBlockSize(this.integritySalt.length, blockSize));
-        integrityMD.init(new SecretKeySpec(hmacKey, hashAlgo.jceHmacId));
-
-        byte[] buf = new byte[1024];
-        LittleEndian.putLong(buf, 0, oleStreamSize);
-        integrityMD.update(buf, 0, LittleEndianConsts.LONG_SIZE);
-
-        try (InputStream fis = new FileInputStream(tmpFile)) {
-            int readBytes;
-            while ((readBytes = fis.read(buf)) != -1) {
-                integrityMD.update(buf, 0, readBytes);
-            }
-        }
-
-        byte[] hmacValue = integrityMD.doFinal();
-        byte[] hmacValueFilled = getBlock0(hmacValue, getNextBlockSize(hmacValue.length, blockSize));
-
-        byte[] iv = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityValueBlock, blockSize);
-        Cipher cipher = CryptoFunctions.getCipher(getSecretKey(), header.getCipherAlgorithm(), header.getChainingMode(), iv, Cipher.ENCRYPT_MODE);
-        byte[] encryptedHmacValue = cipher.doFinal(hmacValueFilled);
-
-        header.setEncryptedHmacValue(encryptedHmacValue);
-    }
-
-    private final CTKeyEncryptor.Uri.Enum passwordUri =
-        CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_PASSWORD;
-
-    protected EncryptionDocument createEncryptionDocument() {
-        AgileEncryptionVerifier ver = (AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
-        AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
-
-        EncryptionDocument ed = EncryptionDocument.Factory.newInstance();
-        CTEncryption edRoot = ed.addNewEncryption();
-
-        CTKeyData keyData = edRoot.addNewKeyData();
-        CTKeyEncryptors keyEncList = edRoot.addNewKeyEncryptors();
-        CTKeyEncryptor keyEnc = keyEncList.addNewKeyEncryptor();
-        keyEnc.setUri(passwordUri);
-        CTPasswordKeyEncryptor keyPass = keyEnc.addNewEncryptedPasswordKey();
-
-        keyPass.setSpinCount(ver.getSpinCount());
-
-        keyData.setSaltSize(header.getBlockSize());
-        keyPass.setSaltSize(ver.getBlockSize());
-
-        keyData.setBlockSize(header.getBlockSize());
-        keyPass.setBlockSize(ver.getBlockSize());
-
-        keyData.setKeyBits(header.getKeySize());
-        keyPass.setKeyBits(ver.getKeySize());
-
-        keyData.setHashSize(header.getHashAlgorithm().hashSize);
-        keyPass.setHashSize(ver.getHashAlgorithm().hashSize);
-
-        // header and verifier have to have the same cipher algorithm
-        if (!header.getCipherAlgorithm().xmlId.equals(ver.getCipherAlgorithm().xmlId)) {
-            throw new EncryptedDocumentException("Cipher algorithm of header and verifier have to match");
-        }
-        STCipherAlgorithm.Enum xmlCipherAlgo = STCipherAlgorithm.Enum.forString(header.getCipherAlgorithm().xmlId);
-        if (xmlCipherAlgo == null) {
-            throw new EncryptedDocumentException("CipherAlgorithm "+header.getCipherAlgorithm()+" not supported.");
-        }
-        keyData.setCipherAlgorithm(xmlCipherAlgo);
-        keyPass.setCipherAlgorithm(xmlCipherAlgo);
-
-        switch (header.getChainingMode()) {
-        case cbc:
-            keyData.setCipherChaining(STCipherChaining.CHAINING_MODE_CBC);
-            keyPass.setCipherChaining(STCipherChaining.CHAINING_MODE_CBC);
-            break;
-        case cfb:
-            keyData.setCipherChaining(STCipherChaining.CHAINING_MODE_CFB);
-            keyPass.setCipherChaining(STCipherChaining.CHAINING_MODE_CFB);
-            break;
-        default:
-            throw new EncryptedDocumentException("ChainingMode "+header.getChainingMode()+" not supported.");
-        }
-
-        keyData.setHashAlgorithm(mapHashAlgorithm(header.getHashAlgorithm()));
-        keyPass.setHashAlgorithm(mapHashAlgorithm(ver.getHashAlgorithm()));
-
-        keyData.setSaltValue(header.getKeySalt());
-        keyPass.setSaltValue(ver.getSalt());
-        keyPass.setEncryptedVerifierHashInput(ver.getEncryptedVerifier());
-        keyPass.setEncryptedVerifierHashValue(ver.getEncryptedVerifierHash());
-        keyPass.setEncryptedKeyValue(ver.getEncryptedKey());
-
-        CTDataIntegrity hmacData = edRoot.addNewDataIntegrity();
-        hmacData.setEncryptedHmacKey(header.getEncryptedHmacKey());
-        hmacData.setEncryptedHmacValue(header.getEncryptedHmacValue());
-
-        return ed;
-    }
-
-    private static STHashAlgorithm.Enum mapHashAlgorithm(HashAlgorithm hashAlgo) {
-        STHashAlgorithm.Enum xmlHashAlgo = STHashAlgorithm.Enum.forString(hashAlgo.ecmaString);
-        if (xmlHashAlgo == null) {
-            throw new EncryptedDocumentException("HashAlgorithm "+hashAlgo+" not supported.");
-        }
-        return xmlHashAlgo;
-    }
-
-    protected void marshallEncryptionDocument(EncryptionDocument ed, LittleEndianByteArrayOutputStream os) {
-        XmlOptions xo = new XmlOptions();
-        xo.setCharacterEncoding("UTF-8");
-        Map<String,String> nsMap = new HashMap<>();
-        nsMap.put(passwordUri.toString(),"p");
-        xo.setUseDefaultNamespace();
-        xo.setSaveSuggestedPrefixes(nsMap);
-        xo.setSaveNamespacesFirst();
-        xo.setSaveAggressiveNamespaces();
-
-        // setting standalone doesn't work with xmlbeans-2.3 & 2.6
-        // ed.documentProperties().setStandalone(true);
-        xo.setSaveNoXmlDecl();
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        try {
-            bos.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n".getBytes(StandardCharsets.UTF_8));
-            ed.save(bos, xo);
-            bos.writeTo(os);
-        } catch (IOException e) {
-            throw new EncryptedDocumentException("error marshalling encryption info document", e);
-        }
-    }
-
-    /**
-     * 2.3.4.15 Data Encryption (Agile Encryption)
-     *
-     * The EncryptedPackage stream (1) MUST be encrypted in 4096-byte segments to facilitate nearly
-     * random access while allowing CBC modes to be used in the encryption process.
-     * The initialization vector for the encryption process MUST be obtained by using the zero-based
-     * segment number as a blockKey and the binary form of the KeyData.saltValue as specified in
-     * section 2.3.4.12. The block number MUST be represented as a 32-bit unsigned integer.
-     * Data blocks MUST then be encrypted by using the initialization vector and the intermediate key
-     * obtained by decrypting the encryptedKeyValue from a KeyEncryptor contained within the
-     * KeyEncryptors sequence as specified in section 2.3.4.10. The final data block MUST be padded to
-     * the next integral multiple of the KeyData.blockSize value. Any padding bytes can be used. Note
-     * that the StreamSize field of the EncryptedPackage field specifies the number of bytes of
-     * unencrypted data as specified in section 2.3.4.4.
-     */
-    private class AgileCipherOutputStream extends ChunkedCipherOutputStream {
-        public AgileCipherOutputStream(DirectoryNode dir) throws IOException, GeneralSecurityException {
-            super(dir, 4096);
-        }
-
-        @Override
-        protected Cipher initCipherForBlock(Cipher existing, int block, boolean lastChunk)
-        throws GeneralSecurityException {
-            return AgileDecryptor.initCipherForBlock(existing, block, lastChunk, getEncryptionInfo(), getSecretKey(), Cipher.ENCRYPT_MODE);
-        }
-
-        @Override
-        protected void calculateChecksum(File fileOut, int oleStreamSize)
-        throws GeneralSecurityException, IOException {
-            // integrityHMAC needs to be updated before the encryption document is created
-            updateIntegrityHMAC(fileOut, oleStreamSize);
-        }
-
-        @Override
-        protected void createEncryptionInfoEntry(DirectoryNode dir, File tmpFile)
-        throws IOException {
-            DataSpaceMapUtils.addDefaultDataSpace(dir);
-            createEncryptionEntry(dir, "EncryptionInfo", this::marshallEncryptionRecord);
-        }
-
-        private void marshallEncryptionRecord(LittleEndianByteArrayOutputStream bos) {
-            final EncryptionInfo info = getEncryptionInfo();
-
-            // EncryptionVersionInfo (4 bytes): A Version structure (section 2.1.4), where
-            // Version.vMajor MUST be 0x0004 and Version.vMinor MUST be 0x0004
-            bos.writeShort(info.getVersionMajor());
-            bos.writeShort(info.getVersionMinor());
-            // Reserved (4 bytes): A value that MUST be 0x00000040
-            bos.writeInt(info.getEncryptionFlags());
-
-            EncryptionDocument ed = createEncryptionDocument();
-            marshallEncryptionDocument(ed, bos);
-        }
-    }
-
-    @Override
-    public AgileEncryptor copy() {
-        return new AgileEncryptor(this);
-    }
-}
index 78fc0805e2b63ad90f7c2d1e4b685cf8b0618dd8..725c9418640d628cf19ac05ee6f4cb3e4def957f 100644 (file)
@@ -25,20 +25,20 @@ import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.opc.PackageAccess;
-import org.apache.poi.openxml4j.opc.ZipPackage;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookProvider;
+import org.apache.poi.util.Internal;
 
-public class XSSFWorkbookFactory extends WorkbookFactory {
+@Internal
+public class XSSFWorkbookFactory implements WorkbookProvider {
 
-    static {
-        init();
-    }
-
-    public static void init() {
-        WorkbookFactory.createXssfFromScratch = XSSFWorkbookFactory::createWorkbook;
-        WorkbookFactory.createXssfByStream = XSSFWorkbookFactory::createWorkbook;
-        WorkbookFactory.createXssfByPackage = o -> XSSFWorkbookFactory.createWorkbook((OPCPackage)o);
-        WorkbookFactory.createXssfByFile = XSSFWorkbookFactory::createWorkbook;
+    @Override
+    public boolean accepts(FileMagic fm) {
+        return fm == FileMagic.OOXML;
     }
 
     /**
@@ -46,41 +46,62 @@ public class XSSFWorkbookFactory extends WorkbookFactory {
      *
      * @return The created workbook
      */
-    public static XSSFWorkbook createWorkbook() {
+    @Override
+    public XSSFWorkbook create() {
         return new XSSFWorkbook();
     }
 
-    /**
-     * Creates a XSSFWorkbook from the given OOXML Package.
-     * This is a convenience method to go along the create-methods of the super class.
-     *
-     * <p>Note that in order to properly release resources the
-     *  Workbook should be closed after use.</p>
-     *
-     *  @param pkg The {@link OPCPackage} opened for reading data.
-     *
-     *  @return The created Workbook
-     *
-     *  @throws IOException if an error occurs while reading the data
-     */
-    public static XSSFWorkbook create(OPCPackage pkg) throws IOException {
-        return createWorkbook(pkg);
+    @Override
+    public XSSFWorkbook create(DirectoryNode root, String password) throws IOException {
+        try (InputStream stream = DocumentFactoryHelper.getDecryptedStream(root, password)) {
+            return create(stream);
+        } finally {
+            // as we processed the full stream already, we can close the filesystem here
+            // otherwise file handles are leaked
+            root.getFileSystem().close();
+        }
+    }
+
+    @Override
+    public Workbook create(InputStream inp, String password) throws IOException {
+        InputStream bufInp = FileMagic.prepareToCheckMagic(inp);
+        FileMagic fm = FileMagic.valueOf(bufInp);
+
+        if (fm == FileMagic.OLE2) {
+            try (POIFSFileSystem poifs = new POIFSFileSystem(bufInp);
+                 InputStream stream = DocumentFactoryHelper.getDecryptedStream(poifs.getRoot(), password)) {
+                return create(stream);
+            }
+        }
+
+        if (fm == FileMagic.OOXML) {
+            return create(bufInp);
+        }
+
+        return null;
     }
 
     /**
-     * Creates a XSSFWorkbook from the given OOXML Package
+     * Creates a XSSFWorkbook from the given InputStream
      *
      * <p>Note that in order to properly release resources the
-     *  Workbook should be closed after use.</p>
+     * Workbook should be closed after use.</p>
      *
-     *  @param pkg The {@link ZipPackage} opened for reading data.
+     * @param stream The {@link InputStream} to read data from.
      *
-     *  @return The created Workbook
+     * @return The created Workbook
      *
-     *  @throws IOException if an error occurs while reading the data
+     * @throws IOException if an error occurs while reading the data
      */
-    public static XSSFWorkbook createWorkbook(ZipPackage pkg) throws IOException {
-        return createWorkbook((OPCPackage)pkg);
+    @SuppressWarnings("resource")
+    @Override
+    public XSSFWorkbook create(InputStream stream) throws IOException {
+        try {
+            OPCPackage pkg = OPCPackage.open(stream);
+            return createWorkbook(pkg);
+        } catch (InvalidFormatException e) {
+            throw new IOException(e);
+        }
     }
 
     /**
@@ -122,31 +143,18 @@ public class XSSFWorkbookFactory extends WorkbookFactory {
      *  @throws EncryptedDocumentException If the wrong password is given for a protected file
      */
     @SuppressWarnings("resource")
-    public static XSSFWorkbook createWorkbook(File file, boolean readOnly) throws IOException {
-        try {
-            OPCPackage pkg = OPCPackage.open(file, readOnly ? PackageAccess.READ : PackageAccess.READ_WRITE);
-            return createWorkbook(pkg);
-        } catch (InvalidFormatException e) {
-            throw new IOException(e);
+    public XSSFWorkbook create(File file, String password, boolean readOnly) throws IOException {
+        FileMagic fm = FileMagic.valueOf(file);
+
+        if (fm == FileMagic.OLE2) {
+            try (POIFSFileSystem poifs = new POIFSFileSystem(file, true);
+                 InputStream stream = DocumentFactoryHelper.getDecryptedStream(poifs.getRoot(), password)) {
+                return create(stream);
+            }
         }
-    }
 
-    /**
-     * Creates a XSSFWorkbook from the given InputStream
-     *
-     * <p>Note that in order to properly release resources the
-     * Workbook should be closed after use.</p>
-     *
-     * @param stream The {@link InputStream} to read data from.
-     *
-     * @return The created Workbook
-     *
-     * @throws IOException if an error occurs while reading the data
-     */
-    @SuppressWarnings("resource")
-    public static XSSFWorkbook createWorkbook(InputStream stream) throws IOException {
         try {
-            OPCPackage pkg = OPCPackage.open(stream);
+            OPCPackage pkg = OPCPackage.open(file, readOnly ? PackageAccess.READ : PackageAccess.READ_WRITE);
             return createWorkbook(pkg);
         } catch (InvalidFormatException e) {
             throw new IOException(e);
diff --git a/src/ooxml/testcases/org/apache/poi/TestDetectAsOOXML.java b/src/ooxml/testcases/org/apache/poi/TestDetectAsOOXML.java
deleted file mode 100644 (file)
index 09ade05..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
-import org.apache.poi.poifs.filesystem.FileMagic;
-import org.apache.poi.util.IOUtils;
-import org.junit.Test;
-
-/**
- * Class to test that HXF correctly detects OOXML
- *  documents
- */
-@SuppressWarnings("deprecation")
-public class TestDetectAsOOXML {
-    @Test
-       public void testOpensProperly() throws IOException, InvalidFormatException {
-               OPCPackage.open(HSSFTestDataSamples.openSampleFileStream("sample.xlsx")).close();
-       }
-       
-    @Test
-       public void testDetectAsPOIFS() throws IOException {
-        Object[][] fileAndMagic = {
-                {"SampleSS.xlsx", FileMagic.OOXML},
-                {"SampleSS.xls", FileMagic.OLE2},
-                {"SampleSS.txt", FileMagic.UNKNOWN}
-        };
-
-           for (Object[] fm : fileAndMagic) {
-               InputStream is = HSSFTestDataSamples.openSampleFileStream((String)fm[0]);
-               is = FileMagic.prepareToCheckMagic(is);
-               FileMagic act = FileMagic.valueOf(is);
-               
-                       assertEquals("OOXML files should be detected, others not",
-                                       act == FileMagic.OOXML, DocumentFactoryHelper.hasOOXMLHeader(is));
-
-               assertEquals("file magic failed for "+fm[0], fm[1], act);
-               is.close();
-           }
-       }
-    
-    @Test
-    public void testFileCorruption() throws Exception {
-           // create test InputStream
-           byte[] testData = { 1, 2, 3 };
-        ByteArrayInputStream testInput = new ByteArrayInputStream(testData);
-        InputStream is = FileMagic.prepareToCheckMagic(testInput);
-        
-        // detect header
-        assertFalse(DocumentFactoryHelper.hasOOXMLHeader(is));
-        
-        // check if InputStream is still intact
-        byte[] act = IOUtils.toByteArray(is);
-        assertArrayEquals(testData, act);
-        assertEquals(-1, is.read());
-        is.close();
-       }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/TestEmbedded.java b/src/ooxml/testcases/org/apache/poi/TestEmbedded.java
deleted file mode 100644 (file)
index 26ba806..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-
-package org.apache.poi;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import org.apache.poi.ooxml.POIXMLDocument;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.openxml4j.opc.PackagePart;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.xslf.usermodel.XSLFSlideShow;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.junit.Test;
-
-/**
- * Class to test that we handle embeded bits in OOXML files properly
- */
-public class TestEmbedded {
-       @Test
-       public void testExcel() throws Exception {
-               POIXMLDocument doc = new XSSFWorkbook(
-                POIDataSamples.getSpreadSheetInstance().openResourceAsStream("ExcelWithAttachments.xlsm")
-        );
-               test(doc, 4);
-       }
-
-       @Test
-       public void testWord() throws Exception {
-               POIXMLDocument doc = new XWPFDocument(
-                POIDataSamples.getDocumentInstance().openResourceAsStream("WordWithAttachments.docx")
-        );
-               test(doc, 5);
-       }
-
-       @Test
-       public void testPowerPoint() throws Exception {
-               POIXMLDocument doc = new XSLFSlideShow(OPCPackage.open(
-                POIDataSamples.getSlideShowInstance().openResourceAsStream("PPTWithAttachments.pptm"))
-        );
-               test(doc, 4);
-       }
-
-       private void test(POIXMLDocument doc, int expectedCount) throws Exception {
-               assertNotNull(doc.getAllEmbeddedParts());
-               assertEquals(expectedCount, doc.getAllEmbeddedParts().size());
-
-               for(int i=0; i<doc.getAllEmbeddedParts().size(); i++) {
-                       PackagePart pp = doc.getAllEmbeddedParts().get(i);
-                       assertNotNull(pp);
-
-                       byte[] b = IOUtils.toByteArray(pp.getInputStream());
-                       assertTrue(b.length > 0);
-               }
-
-               doc.close();
-       }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/TestXMLPropertiesTextExtractor.java b/src/ooxml/testcases/org/apache/poi/TestXMLPropertiesTextExtractor.java
deleted file mode 100644 (file)
index 7186d64..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi;
-
-import static org.apache.poi.POITestCase.assertContains;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import org.apache.poi.ooxml.extractor.POIXMLPropertiesTextExtractor;
-import org.apache.poi.ooxml.util.PackageHelper;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.xslf.usermodel.XSLFSlideShow;
-import org.apache.poi.xssf.extractor.XSSFExcelExtractor;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.junit.Test;
-
-public final class TestXMLPropertiesTextExtractor {
-    private static final POIDataSamples _ssSamples = POIDataSamples.getSpreadSheetInstance();
-    private static final POIDataSamples _slSamples = POIDataSamples.getSlideShowInstance();
-
-       @Test
-       public void testGetFromMainExtractor() throws Exception {
-               OPCPackage pkg = PackageHelper.open(_ssSamples.openResourceAsStream("ExcelWithAttachments.xlsm"));
-
-               XSSFWorkbook wb = new XSSFWorkbook(pkg);
-
-               XSSFExcelExtractor ext = new XSSFExcelExtractor(wb);
-               POIXMLPropertiesTextExtractor textExt = ext.getMetadataTextExtractor();
-
-               // Check basics
-               assertNotNull(textExt);
-               assertTrue(textExt.getText().length() > 0);
-
-               // Check some of the content
-               String text = textExt.getText();
-               String cText = textExt.getCorePropertiesText();
-
-               assertContains(text, "LastModifiedBy = Yury Batrakov");
-               assertContains(cText, "LastModifiedBy = Yury Batrakov");
-
-               textExt.close();
-               ext.close();
-       }
-
-       @Test
-       public void testCore() throws Exception {
-               OPCPackage pkg = PackageHelper.open(
-                _ssSamples.openResourceAsStream("ExcelWithAttachments.xlsm")
-               );
-               XSSFWorkbook wb = new XSSFWorkbook(pkg);
-
-               POIXMLPropertiesTextExtractor ext = new POIXMLPropertiesTextExtractor(wb);
-               ext.getText();
-
-               // Now check
-               String text = ext.getText();
-               String cText = ext.getCorePropertiesText();
-
-               assertContains(text, "LastModifiedBy = Yury Batrakov");
-               assertContains(cText, "LastModifiedBy = Yury Batrakov");
-
-               ext.close();
-       }
-
-       @Test
-       public void testExtended() throws Exception {
-               OPCPackage pkg = OPCPackage.open(
-                _ssSamples.openResourceAsStream("ExcelWithAttachments.xlsm")
-               );
-               XSSFWorkbook wb = new XSSFWorkbook(pkg);
-
-               POIXMLPropertiesTextExtractor ext = new POIXMLPropertiesTextExtractor(wb);
-               ext.getText();
-
-               // Now check
-               String text = ext.getText();
-               String eText = ext.getExtendedPropertiesText();
-
-               assertContains(text, "Application = Microsoft Excel");
-               assertContains(text, "Company = Mera");
-               assertContains(eText, "Application = Microsoft Excel");
-               assertContains(eText, "Company = Mera");
-
-               ext.close();
-       }
-
-       @Test
-       public void testCustom() throws Exception {
-      OPCPackage pkg = OPCPackage.open(
-                _ssSamples.openResourceAsStream("ExcelWithAttachments.xlsm")
-      );
-      XSSFWorkbook wb = new XSSFWorkbook(pkg);
-
-      POIXMLPropertiesTextExtractor ext = new POIXMLPropertiesTextExtractor(wb);
-      ext.getText();
-
-      // Now check
-      String text = ext.getText();
-      String cText = ext.getCustomPropertiesText();
-
-      assertContains(text, "description = another value");
-      assertContains(cText, "description = another value");
-
-      ext.close();
-       }
-
-       /**
-        * Bug #49386 - some properties, especially
-        *  dates can be null
-        */
-       @Test
-       public void testWithSomeNulls() throws Exception {
-      OPCPackage pkg = OPCPackage.open(
-            _slSamples.openResourceAsStream("49386-null_dates.pptx")
-      );
-      XSLFSlideShow sl = new XSLFSlideShow(pkg);
-
-      POIXMLPropertiesTextExtractor ext = new POIXMLPropertiesTextExtractor(sl);
-      ext.getText();
-
-      String text = ext.getText();
-      assertFalse(text.contains("Created =")); // With date is null
-      assertContains(text, "CreatedString = "); // Via string is blank
-      assertContains(text, "LastModifiedBy = IT Client Services");
-
-      ext.close();
-       }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ooxml/TestDetectAsOOXML.java b/src/ooxml/testcases/org/apache/poi/ooxml/TestDetectAsOOXML.java
new file mode 100644 (file)
index 0000000..6ab773d
--- /dev/null
@@ -0,0 +1,83 @@
+/* ====================================================================
+   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.ooxml;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.util.IOUtils;
+import org.junit.Test;
+
+/**
+ * Class to test that HXF correctly detects OOXML
+ *  documents
+ */
+@SuppressWarnings("deprecation")
+public class TestDetectAsOOXML {
+    @Test
+       public void testOpensProperly() throws IOException, InvalidFormatException {
+               OPCPackage.open(HSSFTestDataSamples.openSampleFileStream("sample.xlsx")).close();
+       }
+
+    @Test
+       public void testDetectAsPOIFS() throws IOException {
+        Object[][] fileAndMagic = {
+                {"SampleSS.xlsx", FileMagic.OOXML},
+                {"SampleSS.xls", FileMagic.OLE2},
+                {"SampleSS.txt", FileMagic.UNKNOWN}
+        };
+
+           for (Object[] fm : fileAndMagic) {
+               InputStream is = HSSFTestDataSamples.openSampleFileStream((String)fm[0]);
+               is = FileMagic.prepareToCheckMagic(is);
+               FileMagic act = FileMagic.valueOf(is);
+
+                       assertEquals("OOXML files should be detected, others not",
+                                       act == FileMagic.OOXML, DocumentFactoryHelper.hasOOXMLHeader(is));
+
+               assertEquals("file magic failed for "+fm[0], fm[1], act);
+               is.close();
+           }
+       }
+
+    @Test
+    public void testFileCorruption() throws Exception {
+           // create test InputStream
+           byte[] testData = { 1, 2, 3 };
+        ByteArrayInputStream testInput = new ByteArrayInputStream(testData);
+        InputStream is = FileMagic.prepareToCheckMagic(testInput);
+
+        // detect header
+        assertFalse(DocumentFactoryHelper.hasOOXMLHeader(is));
+
+        // check if InputStream is still intact
+        byte[] act = IOUtils.toByteArray(is);
+        assertArrayEquals(testData, act);
+        assertEquals(-1, is.read());
+        is.close();
+       }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ooxml/TestEmbedded.java b/src/ooxml/testcases/org/apache/poi/ooxml/TestEmbedded.java
new file mode 100644 (file)
index 0000000..f7bd526
--- /dev/null
@@ -0,0 +1,77 @@
+
+/* ====================================================================
+   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.ooxml;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xslf.usermodel.XSLFSlideShow;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.junit.Test;
+
+/**
+ * Class to test that we handle embeded bits in OOXML files properly
+ */
+public class TestEmbedded {
+       @Test
+       public void testExcel() throws Exception {
+               POIXMLDocument doc = new XSSFWorkbook(
+                POIDataSamples.getSpreadSheetInstance().openResourceAsStream("ExcelWithAttachments.xlsm")
+        );
+               test(doc, 4);
+       }
+
+       @Test
+       public void testWord() throws Exception {
+               POIXMLDocument doc = new XWPFDocument(
+                POIDataSamples.getDocumentInstance().openResourceAsStream("WordWithAttachments.docx")
+        );
+               test(doc, 5);
+       }
+
+       @Test
+       public void testPowerPoint() throws Exception {
+               POIXMLDocument doc = new XSLFSlideShow(OPCPackage.open(
+                POIDataSamples.getSlideShowInstance().openResourceAsStream("PPTWithAttachments.pptm"))
+        );
+               test(doc, 4);
+       }
+
+       private void test(POIXMLDocument doc, int expectedCount) throws Exception {
+               assertNotNull(doc.getAllEmbeddedParts());
+               assertEquals(expectedCount, doc.getAllEmbeddedParts().size());
+
+               for(int i=0; i<doc.getAllEmbeddedParts().size(); i++) {
+                       PackagePart pp = doc.getAllEmbeddedParts().get(i);
+                       assertNotNull(pp);
+
+                       byte[] b = IOUtils.toByteArray(pp.getInputStream());
+                       assertTrue(b.length > 0);
+               }
+
+               doc.close();
+       }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ooxml/TestXMLPropertiesTextExtractor.java b/src/ooxml/testcases/org/apache/poi/ooxml/TestXMLPropertiesTextExtractor.java
new file mode 100644 (file)
index 0000000..6a8091c
--- /dev/null
@@ -0,0 +1,144 @@
+/* ====================================================================
+   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.ooxml;
+
+import static org.apache.poi.POITestCase.assertContains;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.ooxml.extractor.POIXMLPropertiesTextExtractor;
+import org.apache.poi.ooxml.util.PackageHelper;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.xslf.usermodel.XSLFSlideShow;
+import org.apache.poi.xssf.extractor.XSSFExcelExtractor;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.Test;
+
+public final class TestXMLPropertiesTextExtractor {
+    private static final POIDataSamples _ssSamples = POIDataSamples.getSpreadSheetInstance();
+    private static final POIDataSamples _slSamples = POIDataSamples.getSlideShowInstance();
+
+       @Test
+       public void testGetFromMainExtractor() throws Exception {
+               OPCPackage pkg = PackageHelper.open(_ssSamples.openResourceAsStream("ExcelWithAttachments.xlsm"));
+
+               XSSFWorkbook wb = new XSSFWorkbook(pkg);
+
+               XSSFExcelExtractor ext = new XSSFExcelExtractor(wb);
+               POIXMLPropertiesTextExtractor textExt = ext.getMetadataTextExtractor();
+
+               // Check basics
+               assertNotNull(textExt);
+               assertTrue(textExt.getText().length() > 0);
+
+               // Check some of the content
+               String text = textExt.getText();
+               String cText = textExt.getCorePropertiesText();
+
+               assertContains(text, "LastModifiedBy = Yury Batrakov");
+               assertContains(cText, "LastModifiedBy = Yury Batrakov");
+
+               textExt.close();
+               ext.close();
+       }
+
+       @Test
+       public void testCore() throws Exception {
+               OPCPackage pkg = PackageHelper.open(
+                _ssSamples.openResourceAsStream("ExcelWithAttachments.xlsm")
+               );
+               XSSFWorkbook wb = new XSSFWorkbook(pkg);
+
+               POIXMLPropertiesTextExtractor ext = new POIXMLPropertiesTextExtractor(wb);
+               ext.getText();
+
+               // Now check
+               String text = ext.getText();
+               String cText = ext.getCorePropertiesText();
+
+               assertContains(text, "LastModifiedBy = Yury Batrakov");
+               assertContains(cText, "LastModifiedBy = Yury Batrakov");
+
+               ext.close();
+       }
+
+       @Test
+       public void testExtended() throws Exception {
+               OPCPackage pkg = OPCPackage.open(
+                _ssSamples.openResourceAsStream("ExcelWithAttachments.xlsm")
+               );
+               XSSFWorkbook wb = new XSSFWorkbook(pkg);
+
+               POIXMLPropertiesTextExtractor ext = new POIXMLPropertiesTextExtractor(wb);
+               ext.getText();
+
+               // Now check
+               String text = ext.getText();
+               String eText = ext.getExtendedPropertiesText();
+
+               assertContains(text, "Application = Microsoft Excel");
+               assertContains(text, "Company = Mera");
+               assertContains(eText, "Application = Microsoft Excel");
+               assertContains(eText, "Company = Mera");
+
+               ext.close();
+       }
+
+       @Test
+       public void testCustom() throws Exception {
+      OPCPackage pkg = OPCPackage.open(
+                _ssSamples.openResourceAsStream("ExcelWithAttachments.xlsm")
+      );
+      XSSFWorkbook wb = new XSSFWorkbook(pkg);
+
+      POIXMLPropertiesTextExtractor ext = new POIXMLPropertiesTextExtractor(wb);
+      ext.getText();
+
+      // Now check
+      String text = ext.getText();
+      String cText = ext.getCustomPropertiesText();
+
+      assertContains(text, "description = another value");
+      assertContains(cText, "description = another value");
+
+      ext.close();
+       }
+
+       /**
+        * Bug #49386 - some properties, especially
+        *  dates can be null
+        */
+       @Test
+       public void testWithSomeNulls() throws Exception {
+      OPCPackage pkg = OPCPackage.open(
+            _slSamples.openResourceAsStream("49386-null_dates.pptx")
+      );
+      XSLFSlideShow sl = new XSLFSlideShow(pkg);
+
+      POIXMLPropertiesTextExtractor ext = new POIXMLPropertiesTextExtractor(sl);
+      ext.getText();
+
+      String text = ext.getText();
+      assertFalse(text.contains("Created =")); // With date is null
+      assertContains(text, "CreatedString = "); // Via string is blank
+      assertContains(text, "LastModifiedBy = IT Client Services");
+
+      ext.close();
+       }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ooxml/lite/OOXMLLiteAgent.java b/src/ooxml/testcases/org/apache/poi/ooxml/lite/OOXMLLiteAgent.java
new file mode 100644 (file)
index 0000000..21c7f28
--- /dev/null
@@ -0,0 +1,78 @@
+/* ====================================================================
+   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.ooxml.lite;
+
+import java.io.IOException;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.Instrumentation;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.security.ProtectionDomain;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+/**
+ * OOXMLLiteAgent is the replacement for the former OOXMLLite, because in Java 12
+ * it isn't possible to access the privates :) of the ClassLoader
+ */
+public class OOXMLLiteAgent {
+
+    static class LoggingTransformer implements ClassFileTransformer {
+        final Path path;
+        final Pattern includes;
+        final Set<Integer> fileHashes = new HashSet<>();
+
+        public LoggingTransformer(String agentArgs) {
+            String[] args = (agentArgs == null ? "" : agentArgs).split("\\|", 2);
+            path = Paths.get(args.length >= 1 ? args[0] : "ooxml-lite.out");
+            includes = Pattern.compile(args.length >= 2 ? args[1] : ".*/schemas/.*");
+
+            try {
+                if (Files.exists(path)) {
+                    try (Stream<String> stream = Files.lines(path)) {
+                        stream.forEach((s) -> fileHashes.add(s.hashCode()));
+                    }
+                } else {
+                    Files.createFile(path);
+                }
+            } catch (IOException ignored) {
+            }
+        }
+
+        public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) {
+            if (path != null && className != null && !fileHashes.contains(className.hashCode()) && includes.matcher(className).find()) {
+                try {
+                    // TODO: check if this is atomic ... as transform() is probably called synchronized, it doesn't matter anyway
+                    Files.write(path, (className+"\n").getBytes(StandardCharsets.ISO_8859_1), StandardOpenOption.APPEND);
+                    fileHashes.add(className.hashCode());
+                } catch (IOException ignroed) {
+                }
+            }
+            return bytes;
+        }
+    }
+
+    public static void premain(String agentArgs, Instrumentation inst) {
+        inst.addTransformer(new LoggingTransformer(agentArgs));
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ooxml/util/OOXMLLiteAgent.java b/src/ooxml/testcases/org/apache/poi/ooxml/util/OOXMLLiteAgent.java
deleted file mode 100644 (file)
index 1c7d5d6..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ooxml.util;
-
-import java.io.IOException;
-import java.lang.instrument.ClassFileTransformer;
-import java.lang.instrument.Instrumentation;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.security.ProtectionDomain;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Pattern;
-import java.util.stream.Stream;
-
-/**
- * OOXMLLiteAgent is the replacement for the former OOXMLLite, because in Java 12
- * it isn't possible to access the privates :) of the ClassLoader
- */
-public class OOXMLLiteAgent {
-
-    static class LoggingTransformer implements ClassFileTransformer {
-        final Path path;
-        final Pattern includes;
-        final Set<Integer> fileHashes = new HashSet<>();
-
-        public LoggingTransformer(String agentArgs) {
-            String[] args = (agentArgs == null ? "" : agentArgs).split("\\|", 2);
-            path = Paths.get(args.length >= 1 ? args[0] : "ooxml-lite.out");
-            includes = Pattern.compile(args.length >= 2 ? args[1] : ".*/schemas/.*");
-
-            try {
-                if (Files.exists(path)) {
-                    try (Stream<String> stream = Files.lines(path)) {
-                        stream.forEach((s) -> fileHashes.add(s.hashCode()));
-                    }
-                } else {
-                    Files.createFile(path);
-                }
-            } catch (IOException ignored) {
-            }
-        }
-
-        public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) {
-            if (path != null && className != null && !fileHashes.contains(className.hashCode()) && includes.matcher(className).find()) {
-                try {
-                    // TODO: check if this is atomic ... as transform() is probably called synchronized, it doesn't matter anyway
-                    Files.write(path, (className+"\n").getBytes(StandardCharsets.ISO_8859_1), StandardOpenOption.APPEND);
-                    fileHashes.add(className.hashCode());
-                } catch (IOException ignroed) {
-                }
-            }
-            return bytes;
-        }
-    }
-
-    public static void premain(String agentArgs, Instrumentation inst) {
-        inst.addTransformer(new LoggingTransformer(agentArgs));
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/AllPOIFSCryptoTests.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/AllPOIFSCryptoTests.java
deleted file mode 100644 (file)
index ffdbdff..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.poifs.crypt;
-
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-
-
-/**
- * Tests for org.apache.poi.poifs.crypt
- */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-      TestEncryptionInfo.class
-    , TestDecryptor.class
-    , TestEncryptor.class
-    , TestAgileEncryptionParameters.class
-})
-public final class AllPOIFSCryptoTests {
-}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestAgileEncryptionParameters.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestAgileEncryptionParameters.java
deleted file mode 100644 (file)
index 6c8cc16..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.poifs.crypt;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import javax.crypto.Cipher;
-
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.util.IOUtils;
-import org.junit.Assume;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class TestAgileEncryptionParameters {
-
-    static byte[] testData;
-    
-    @Parameter(value = 0)
-    public CipherAlgorithm ca;
-    @Parameter(value = 1)
-    public HashAlgorithm ha;
-    @Parameter(value = 2)
-    public ChainingMode cm;
-
-    @Parameters(name="{0} {1} {2}")
-    public static Collection<Object[]> data() {
-        CipherAlgorithm[] caList = {CipherAlgorithm.aes128, CipherAlgorithm.aes192, CipherAlgorithm.aes256, CipherAlgorithm.rc2, CipherAlgorithm.des, CipherAlgorithm.des3};
-        HashAlgorithm[] haList = {HashAlgorithm.sha1, HashAlgorithm.sha256, HashAlgorithm.sha384, HashAlgorithm.sha512, HashAlgorithm.md5};
-        ChainingMode[] cmList = {ChainingMode.cbc, ChainingMode.cfb};
-
-        List<Object[]> data = new ArrayList<>();
-        for (CipherAlgorithm ca : caList) {
-            for (HashAlgorithm ha : haList) {
-                for (ChainingMode cm : cmList) {
-                    data.add(new Object[]{ca,ha,cm});
-                }
-            }
-        }
-        
-        return data;
-    }
-    
-    @BeforeClass
-    public static void initTestData() throws Exception {
-        InputStream testFile = POIDataSamples.getDocumentInstance().openResourceAsStream("SampleDoc.docx");
-        testData = IOUtils.toByteArray(testFile);
-        testFile.close();
-    }
-    
-    @Test
-    public void testAgileEncryptionModes() throws Exception {
-        int maxKeyLen = Cipher.getMaxAllowedKeyLength(ca.jceId);
-        Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files", maxKeyLen >= ca.defaultKeySize);
-        
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-
-        POIFSFileSystem fsEnc = new POIFSFileSystem();
-        EncryptionInfo infoEnc = new EncryptionInfo(EncryptionMode.agile, ca, ha, -1, -1, cm);
-        Encryptor enc = infoEnc.getEncryptor();
-        enc.confirmPassword("foobaa");
-        OutputStream os = enc.getDataStream(fsEnc);
-        os.write(testData);
-        os.close();
-        bos.reset();
-        fsEnc.writeFilesystem(bos);
-        fsEnc.close();
-        
-        POIFSFileSystem fsDec = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
-        EncryptionInfo infoDec = new EncryptionInfo(fsDec);
-        Decryptor dec = infoDec.getDecryptor();
-        boolean passed = dec.verifyPassword("foobaa");
-        assertTrue(passed);
-        InputStream is = dec.getDataStream(fsDec);
-        byte[] actualData = IOUtils.toByteArray(is);
-        is.close();
-        fsDec.close();
-        assertArrayEquals("Failed roundtrip - "+ca+"-"+ha+"-"+cm, testData, actualData);
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java
deleted file mode 100644 (file)
index 3979518..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.poifs.crypt;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.GeneralSecurityException;
-import java.util.stream.IntStream;
-
-import javax.crypto.Cipher;
-
-import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
-import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.poifs.filesystem.DirectoryNode;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.util.IOUtils;
-import org.junit.Assume;
-import org.junit.Test;
-
-public class TestDecryptor {
-    private static final POIDataSamples samples = POIDataSamples.getPOIFSInstance();
-
-    @Test
-    public void passwordVerification() throws IOException, GeneralSecurityException {
-        try (InputStream is = samples.openResourceAsStream("protect.xlsx");
-            POIFSFileSystem fs = new POIFSFileSystem(is)) {
-            EncryptionInfo info = new EncryptionInfo(fs);
-            Decryptor d = Decryptor.getInstance(info);
-            assertTrue(d.verifyPassword(Decryptor.DEFAULT_PASSWORD));
-        }
-    }
-
-    @Test
-    public void decrypt() throws IOException, GeneralSecurityException {
-        try (InputStream is = samples.openResourceAsStream("protect.xlsx");
-             POIFSFileSystem fs = new POIFSFileSystem(is)) {
-            EncryptionInfo info = new EncryptionInfo(fs);
-            Decryptor d = Decryptor.getInstance(info);
-            d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
-            zipOk(fs.getRoot(), d);
-        }
-    }
-
-    @Test
-    public void agile() throws IOException, GeneralSecurityException {
-        try (InputStream is = samples.openResourceAsStream("protected_agile.docx");
-            POIFSFileSystem fs = new POIFSFileSystem(is)) {
-            EncryptionInfo info = new EncryptionInfo(fs);
-            assertTrue(info.getVersionMajor() == 4 && info.getVersionMinor() == 4);
-            Decryptor d = Decryptor.getInstance(info);
-            assertTrue(d.verifyPassword(Decryptor.DEFAULT_PASSWORD));
-            zipOk(fs.getRoot(), d);
-        }
-    }
-
-    private void zipOk(DirectoryNode root, Decryptor d) throws IOException, GeneralSecurityException {
-        try (ZipArchiveInputStream zin = new ZipArchiveInputStream(d.getDataStream(root))) {
-
-            while (true) {
-                ZipArchiveEntry entry = zin.getNextZipEntry();
-                if (entry == null) {
-                    break;
-                }
-                // crc32 is checked within zip-stream
-                if (entry.isDirectory()) {
-                    continue;
-                }
-                assertEquals(entry.getSize() - 1, zin.skip(entry.getSize() - 1));
-                byte[] buf = new byte[10];
-                int readBytes = zin.read(buf);
-                // zin.available() doesn't work for entries
-                assertEquals("size failed for " + entry.getName(), 1, readBytes);
-            }
-        }
-    }
-
-    @Test
-    public void dataLength() throws Exception {
-        try (InputStream fsIs = samples.openResourceAsStream("protected_agile.docx");
-            POIFSFileSystem fs = new POIFSFileSystem(fsIs)) {
-            EncryptionInfo info = new EncryptionInfo(fs);
-            Decryptor d = Decryptor.getInstance(info);
-            d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
-
-            try (InputStream is = d.getDataStream(fs)) {
-
-                long len = d.getLength();
-                assertEquals(12810, len);
-
-                byte[] buf = new byte[(int) len];
-                assertEquals(12810, is.read(buf));
-
-        ZipArchiveInputStream zin = new ZipArchiveInputStream(new ByteArrayInputStream(buf));
-
-        while (true) {
-            ZipArchiveEntry entry = zin.getNextZipEntry();
-            if (entry==null) {
-                break;
-            }
-
-                    IOUtils.toByteArray(zin);
-                }
-            }
-        }
-    }
-
-    @Test
-    public void bug57080() throws Exception {
-        // the test file contains a wrong ole entry size, produced by extenxls
-        // the fix limits the available size and tries to read all entries
-        File f = samples.getFile("extenxls_pwd123.xlsx");
-
-        try (POIFSFileSystem fs = new POIFSFileSystem(f, true)) {
-            EncryptionInfo info = new EncryptionInfo(fs);
-            Decryptor d = Decryptor.getInstance(info);
-            d.verifyPassword("pwd123");
-
-            final ByteArrayOutputStream bos = new ByteArrayOutputStream(10000);
-            try (final ZipArchiveInputStream zis = new ZipArchiveInputStream(d.getDataStream(fs))) {
-                IntStream.of(3711, 1155, 445, 9376, 450, 588, 1337, 2593, 304, 7910).forEach(size -> {
-                    try {
-                        final ZipArchiveEntry ze = zis.getNextZipEntry();
-                        assertNotNull(ze);
-                        IOUtils.copy(zis, bos);
-                        assertEquals(size, bos.size());
-                        bos.reset();
-                    } catch (IOException e) {
-                        fail(e.getMessage());
-                    }
-                });
-            }
-        }
-    }
-
-    @Test
-    public void test58616() throws IOException, GeneralSecurityException {
-        try (InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("58616.xlsx");
-            POIFSFileSystem pfs = new POIFSFileSystem(is)) {
-            EncryptionInfo info = new EncryptionInfo(pfs);
-            Decryptor dec = Decryptor.getInstance(info);
-            dec.getDataStream(pfs).close();
-        }
-    }
-
-    @Test
-    public void bug60320() throws IOException, GeneralSecurityException {
-        int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
-        Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files for AES 256", maxKeyLen == 2147483647);
-
-        try (InputStream is = samples.openResourceAsStream("60320-protected.xlsx");
-            POIFSFileSystem fs = new POIFSFileSystem(is)) {
-            EncryptionInfo info = new EncryptionInfo(fs);
-            Decryptor d = Decryptor.getInstance(info);
-            assertTrue(d.verifyPassword("Test001!!"));
-            zipOk(fs.getRoot(), d);
-        }
-    }    
-}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptionInfo.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptionInfo.java
deleted file mode 100644 (file)
index 0b4e3d2..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.poifs.crypt;
-
-import static org.junit.Assert.assertEquals;
-
-import java.io.IOException;
-
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.junit.Test;
-
-public class TestEncryptionInfo {
-    @Test
-    public void testEncryptionInfo() throws IOException {
-        POIFSFileSystem fs = new POIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protect.xlsx"));
-
-        EncryptionInfo info = new EncryptionInfo(fs);
-
-        assertEquals(3, info.getVersionMajor());
-        assertEquals(2, info.getVersionMinor());
-
-        assertEquals(CipherAlgorithm.aes128, info.getHeader().getCipherAlgorithm());
-        assertEquals(HashAlgorithm.sha1, info.getHeader().getHashAlgorithm());
-        assertEquals(128, info.getHeader().getKeySize());
-        assertEquals(32, info.getVerifier().getEncryptedVerifierHash().length);
-        assertEquals(CipherProvider.aes, info.getHeader().getCipherProvider());                
-        assertEquals("Microsoft Enhanced RSA and AES Cryptographic Provider", info.getHeader().getCspName());
-        
-        fs.close();
-    }
-    
-    @Test
-    public void testEncryptionInfoSHA512() throws Exception {
-        POIFSFileSystem fs = new POIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protected_sha512.xlsx"));
-
-        EncryptionInfo info = new EncryptionInfo(fs);
-
-        assertEquals(4, info.getVersionMajor());
-        assertEquals(4, info.getVersionMinor());
-
-        assertEquals(CipherAlgorithm.aes256, info.getHeader().getCipherAlgorithm());
-        assertEquals(HashAlgorithm.sha512, info.getHeader().getHashAlgorithm());
-        assertEquals(256, info.getHeader().getKeySize());
-        assertEquals(64, info.getVerifier().getEncryptedVerifierHash().length);
-        assertEquals(CipherProvider.aes, info.getHeader().getCipherProvider());                
-//        assertEquals("Microsoft Enhanced RSA and AES Cryptographic Provider", info.getHeader().getCspName());
-        
-        fs.close();
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptor.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptor.java
deleted file mode 100644 (file)
index 5531412..0000000
+++ /dev/null
@@ -1,670 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.poifs.crypt;
-
-import static org.apache.poi.poifs.crypt.CryptoFunctions.getMessageDigest;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.DigestInputStream;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.util.Iterator;
-import java.util.Random;
-
-import javax.crypto.Cipher;
-
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.openxml4j.opc.ContentTypes;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.poifs.crypt.agile.AgileDecryptor;
-import org.apache.poi.poifs.crypt.agile.AgileEncryptionHeader;
-import org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier;
-import org.apache.poi.poifs.filesystem.DirectoryNode;
-import org.apache.poi.poifs.filesystem.DocumentEntry;
-import org.apache.poi.poifs.filesystem.DocumentNode;
-import org.apache.poi.poifs.filesystem.Entry;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.poifs.filesystem.TempFilePOIFSFileSystem;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.NullOutputStream;
-import org.apache.poi.util.TempFile;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.poi.xwpf.usermodel.XWPFParagraph;
-import org.junit.Assume;
-import org.junit.Ignore;
-import org.junit.Test;
-
-public class TestEncryptor {
-    @Test
-    public void binaryRC4Encryption() throws Exception {
-        // please contribute a real sample file, which is binary rc4 encrypted
-        // ... at least the output can be opened in Excel Viewer
-        String password = "pass";
-
-        final byte[] payloadExpected;
-        try (InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleMultiCell.xlsx")) {
-            payloadExpected = IOUtils.toByteArray(is);
-        }
-
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        try (POIFSFileSystem fs = new POIFSFileSystem()) {
-            EncryptionInfo ei = new EncryptionInfo(EncryptionMode.binaryRC4);
-            Encryptor enc = ei.getEncryptor();
-            enc.confirmPassword(password);
-
-            try (OutputStream os = enc.getDataStream(fs.getRoot())) {
-                os.write(payloadExpected);
-            }
-
-            fs.writeFilesystem(bos);
-        }
-
-        final byte[] payloadActual;
-        try (POIFSFileSystem fs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()))) {
-            EncryptionInfo ei = new EncryptionInfo(fs);
-            Decryptor dec = ei.getDecryptor();
-            boolean b = dec.verifyPassword(password);
-            assertTrue(b);
-
-            try (InputStream is = dec.getDataStream(fs.getRoot())) {
-                payloadActual = IOUtils.toByteArray(is);
-            }
-        }
-
-        assertArrayEquals(payloadExpected, payloadActual);
-    }
-
-    @Test
-    public void tempFileAgileEncryption() throws Exception {
-        String password = "pass";
-
-        final byte[] payloadExpected;
-        try (InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleMultiCell.xlsx")) {
-            payloadExpected = IOUtils.toByteArray(is);
-        }
-
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        try (POIFSFileSystem fs = new TempFilePOIFSFileSystem()) {
-            EncryptionInfo ei = new EncryptionInfo(EncryptionMode.agile);
-            Encryptor enc = ei.getEncryptor();
-            enc.confirmPassword(password);
-
-            try (OutputStream os = enc.getDataStream(fs.getRoot())) {
-                os.write(payloadExpected);
-            }
-
-            fs.writeFilesystem(bos);
-        }
-
-        final byte[] payloadActual;
-        try (POIFSFileSystem fs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()))) {
-            EncryptionInfo ei = new EncryptionInfo(fs);
-            Decryptor dec = ei.getDecryptor();
-            boolean b = dec.verifyPassword(password);
-            assertTrue(b);
-
-            try (InputStream is = dec.getDataStream(fs.getRoot())) {
-                payloadActual = IOUtils.toByteArray(is);
-            }
-        }
-
-        assertArrayEquals(payloadExpected, payloadActual);
-    }
-
-    @Test
-    public void agileEncryption() throws Exception {
-        int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
-        Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files for AES 256", maxKeyLen == 2147483647);
-
-        File file = POIDataSamples.getDocumentInstance().getFile("bug53475-password-is-pass.docx");
-        String pass = "pass";
-
-        final byte[] payloadExpected, encPackExpected;
-        final long decPackLenExpected;
-        final EncryptionInfo infoExpected;
-        final Decryptor decExpected;
-
-        try (POIFSFileSystem nfs = new POIFSFileSystem(file, true)) {
-
-            // Check the encryption details
-            infoExpected = new EncryptionInfo(nfs);
-            decExpected = Decryptor.getInstance(infoExpected);
-            boolean passed = decExpected.verifyPassword(pass);
-            assertTrue("Unable to process: document is encrypted", passed);
-
-            // extract the payload
-            try (InputStream is = decExpected.getDataStream(nfs)) {
-                payloadExpected = IOUtils.toByteArray(is);
-            }
-
-            decPackLenExpected = decExpected.getLength();
-            assertEquals(decPackLenExpected, payloadExpected.length);
-
-            final DirectoryNode root = nfs.getRoot();
-            final DocumentEntry entry = (DocumentEntry)root.getEntry(Decryptor.DEFAULT_POIFS_ENTRY);
-            try (InputStream is = root.createDocumentInputStream(entry)) {
-                // ignore padding block
-                encPackExpected = IOUtils.toByteArray(is, entry.getSize()-16);
-            }
-        }
-
-        // check that same verifier/salt lead to same hashes
-        final byte[] verifierSaltExpected = infoExpected.getVerifier().getSalt();
-        final byte[] verifierExpected = decExpected.getVerifier();
-        final byte[] keySalt = infoExpected.getHeader().getKeySalt();
-        final byte[] keySpec = decExpected.getSecretKey().getEncoded();
-        final byte[] integritySalt = decExpected.getIntegrityHmacKey();
-        // the hmacs of the file always differ, as we use PKCS5-padding to pad the bytes
-        // whereas office just uses random bytes
-        // byte integrityHash[] = d.getIntegrityHmacValue();
-
-        final EncryptionInfo infoActual = new EncryptionInfo(
-              EncryptionMode.agile
-            , infoExpected.getVerifier().getCipherAlgorithm()
-            , infoExpected.getVerifier().getHashAlgorithm()
-            , infoExpected.getHeader().getKeySize()
-            , infoExpected.getHeader().getBlockSize()
-            , infoExpected.getVerifier().getChainingMode()
-        );
-
-        Encryptor e = Encryptor.getInstance(infoActual);
-        e.confirmPassword(pass, keySpec, keySalt, verifierExpected, verifierSaltExpected, integritySalt);
-
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        try (POIFSFileSystem fs = new POIFSFileSystem()) {
-            try (OutputStream os = e.getDataStream(fs)) {
-                os.write(payloadExpected);
-            }
-            fs.writeFilesystem(bos);
-        }
-
-        final EncryptionInfo infoActual2;
-        final byte[] payloadActual, encPackActual;
-        final long decPackLenActual;
-        try (POIFSFileSystem nfs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()))) {
-            infoActual2 = new EncryptionInfo(nfs.getRoot());
-            Decryptor decActual = Decryptor.getInstance(infoActual2);
-            boolean passed = decActual.verifyPassword(pass);
-            assertTrue("Unable to process: document is encrypted", passed);
-
-            // extract the payload
-            try (InputStream is = decActual.getDataStream(nfs)) {
-                payloadActual = IOUtils.toByteArray(is);
-            }
-
-            decPackLenActual = decActual.getLength();
-
-            final DirectoryNode root = nfs.getRoot();
-            final DocumentEntry entry = (DocumentEntry)root.getEntry(Decryptor.DEFAULT_POIFS_ENTRY);
-            try (InputStream is = root.createDocumentInputStream(entry)) {
-                // ignore padding block
-                encPackActual = IOUtils.toByteArray(is, entry.getSize()-16);
-            }
-        }
-
-        AgileEncryptionHeader aehExpected = (AgileEncryptionHeader)infoExpected.getHeader();
-        AgileEncryptionHeader aehActual = (AgileEncryptionHeader)infoActual.getHeader();
-        assertArrayEquals(aehExpected.getEncryptedHmacKey(), aehActual.getEncryptedHmacKey());
-        assertEquals(decPackLenExpected, decPackLenActual);
-        assertArrayEquals(payloadExpected, payloadActual);
-        assertArrayEquals(encPackExpected, encPackActual);
-    }
-
-    @Test
-    public void standardEncryption() throws Exception {
-        File file = POIDataSamples.getDocumentInstance().getFile("bug53475-password-is-solrcell.docx");
-        final String pass = "solrcell";
-
-        final byte[] payloadExpected;
-        final EncryptionInfo infoExpected;
-        final Decryptor d;
-        try (POIFSFileSystem nfs = new POIFSFileSystem(file, true)) {
-
-            // Check the encryption details
-            infoExpected = new EncryptionInfo(nfs);
-            d = Decryptor.getInstance(infoExpected);
-            boolean passed = d.verifyPassword(pass);
-            assertTrue("Unable to process: document is encrypted", passed);
-
-            // extract the payload
-            try (InputStream is = d.getDataStream(nfs)) {
-                payloadExpected = IOUtils.toByteArray(is);
-            }
-        }
-
-        // check that same verifier/salt lead to same hashes
-        final byte[] verifierSaltExpected = infoExpected.getVerifier().getSalt();
-        final byte[] verifierExpected = d.getVerifier();
-        final byte[] keySpec = d.getSecretKey().getEncoded();
-        final byte[] keySalt = infoExpected.getHeader().getKeySalt();
-
-
-        final EncryptionInfo infoActual = new EncryptionInfo(
-              EncryptionMode.standard
-            , infoExpected.getVerifier().getCipherAlgorithm()
-            , infoExpected.getVerifier().getHashAlgorithm()
-            , infoExpected.getHeader().getKeySize()
-            , infoExpected.getHeader().getBlockSize()
-            , infoExpected.getVerifier().getChainingMode()
-        );
-
-        final Encryptor e = Encryptor.getInstance(infoActual);
-        e.confirmPassword(pass, keySpec, keySalt, verifierExpected, verifierSaltExpected, null);
-
-        assertArrayEquals(infoExpected.getVerifier().getEncryptedVerifier(), infoActual.getVerifier().getEncryptedVerifier());
-        assertArrayEquals(infoExpected.getVerifier().getEncryptedVerifierHash(), infoActual.getVerifier().getEncryptedVerifierHash());
-
-        // now we use a newly generated salt/verifier and check
-        // if the file content is still the same
-
-        final byte[] encBytes;
-        try (POIFSFileSystem fs = new POIFSFileSystem()) {
-
-            final EncryptionInfo infoActual2 = new EncryptionInfo(
-                    EncryptionMode.standard
-                    , infoExpected.getVerifier().getCipherAlgorithm()
-                    , infoExpected.getVerifier().getHashAlgorithm()
-                    , infoExpected.getHeader().getKeySize()
-                    , infoExpected.getHeader().getBlockSize()
-                    , infoExpected.getVerifier().getChainingMode()
-            );
-
-            final Encryptor e2 = Encryptor.getInstance(infoActual2);
-            e2.confirmPassword(pass);
-
-            try (OutputStream os = e2.getDataStream(fs)) {
-                os.write(payloadExpected);
-            }
-
-            final ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
-            fs.writeFilesystem(bos);
-            encBytes = bos.toByteArray();
-        }
-
-        final byte[] payloadActual;
-        try (POIFSFileSystem nfs = new POIFSFileSystem(new ByteArrayInputStream(encBytes))) {
-            final EncryptionInfo ei = new EncryptionInfo(nfs);
-            Decryptor d2 = Decryptor.getInstance(ei);
-            assertTrue("Unable to process: document is encrypted", d2.verifyPassword(pass));
-
-            try (InputStream is = d2.getDataStream(nfs)) {
-                payloadActual = IOUtils.toByteArray(is);
-            }
-        }
-
-        assertArrayEquals(payloadExpected, payloadActual);
-    }
-
-    /**
-     * Ensure we can encrypt a package that is missing the Core
-     *  Properties, eg one from dodgy versions of Jasper Reports
-     * See https://github.com/nestoru/xlsxenc/ and
-     * http://stackoverflow.com/questions/28593223
-     */
-    @Test
-    public void encryptPackageWithoutCoreProperties() throws Exception {
-        // Open our file without core properties
-        final byte[] encBytes;
-        try (InputStream is = POIDataSamples.getOpenXML4JInstance().openResourceAsStream("OPCCompliance_NoCoreProperties.xlsx");
-            OPCPackage pkg = OPCPackage.open(is)) {
-
-            // It doesn't have any core properties yet
-            assertEquals(0, pkg.getPartsByContentType(ContentTypes.CORE_PROPERTIES_PART).size());
-            assertNotNull(pkg.getPackageProperties());
-            assertNotNull(pkg.getPackageProperties().getLanguageProperty());
-            assertFalse(pkg.getPackageProperties().getLanguageProperty().isPresent());
-
-            // Encrypt it
-            EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
-            Encryptor enc = info.getEncryptor();
-            enc.confirmPassword("password");
-
-            try (POIFSFileSystem fs = new POIFSFileSystem()) {
-
-                try (OutputStream os = enc.getDataStream(fs)) {
-                    pkg.save(os);
-                }
-
-                // Save the resulting OLE2 document, and re-open it
-                ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                fs.writeFilesystem(baos);
-                encBytes = baos.toByteArray();
-            }
-        }
-
-
-        try (POIFSFileSystem inpFS = new POIFSFileSystem(new ByteArrayInputStream(encBytes))) {
-            // Check we can decrypt it
-            EncryptionInfo info = new EncryptionInfo(inpFS);
-            Decryptor d = Decryptor.getInstance(info);
-            assertTrue(d.verifyPassword("password"));
-
-            try (OPCPackage inpPkg = OPCPackage.open(d.getDataStream(inpFS))) {
-                // Check it now has empty core properties
-                assertEquals(1, inpPkg.getPartsByContentType(ContentTypes.CORE_PROPERTIES_PART).size());
-                assertNotNull(inpPkg.getPackageProperties());
-                assertNotNull(inpPkg.getPackageProperties().getLanguageProperty());
-                assertFalse(inpPkg.getPackageProperties().getLanguageProperty().isPresent());
-
-            }
-        }
-    }
-
-    @Test
-    @Ignore
-    public void inPlaceRewrite() throws Exception {
-        File f = TempFile.createTempFile("protected_agile", ".docx");
-
-        try (FileOutputStream fos = new FileOutputStream(f);
-             InputStream fis = POIDataSamples.getPOIFSInstance().openResourceAsStream("protected_agile.docx")) {
-            IOUtils.copy(fis, fos);
-        }
-
-        try (POIFSFileSystem fs = new POIFSFileSystem(f, false)) {
-
-            // decrypt the protected file - in this case it was encrypted with the default password
-            EncryptionInfo encInfo = new EncryptionInfo(fs);
-            Decryptor d = encInfo.getDecryptor();
-            boolean b = d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
-            assertTrue(b);
-
-            try (InputStream docIS = d.getDataStream(fs);
-                 XWPFDocument docx = new XWPFDocument(docIS)) {
-
-                // do some strange things with it ;)
-                XWPFParagraph p = docx.getParagraphArray(0);
-                p.insertNewRun(0).setText("POI was here! All your base are belong to us!");
-                p.insertNewRun(1).addBreak();
-
-                // and encrypt it again
-                Encryptor e = encInfo.getEncryptor();
-                e.confirmPassword("AYBABTU");
-
-                try (OutputStream os = e.getDataStream(fs)) {
-                    docx.write(os);
-                }
-            }
-        }
-    }
-
-
-    private void listEntry(DocumentNode de, String ext, String path) throws IOException {
-        path += "\\" + de.getName().replaceAll("[\\p{Cntrl}]", "_");
-        System.out.println(ext+": "+path+" ("+de.getSize()+" bytes)");
-
-        String name = de.getName().replaceAll("[\\p{Cntrl}]", "_");
-
-        InputStream is = ((DirectoryNode)de.getParent()).createDocumentInputStream(de);
-        FileOutputStream fos = new FileOutputStream("solr."+name+"."+ext);
-        IOUtils.copy(is, fos);
-        fos.close();
-        is.close();
-    }
-
-    @SuppressWarnings("unused")
-    private void listDir(DirectoryNode dn, String ext, String path) throws IOException {
-        path += "\\" + dn.getName().replace('\u0006', '_');
-        System.out.println(ext+": "+path+" ("+dn.getStorageClsid()+")");
-
-        Iterator<Entry> iter = dn.getEntries();
-        while (iter.hasNext()) {
-            Entry ent = iter.next();
-            if (ent instanceof DirectoryNode) {
-                listDir((DirectoryNode)ent, ext, path);
-            } else {
-                listEntry((DocumentNode)ent, ext, path);
-            }
-        }
-    }
-
-    /*
-     * this test simulates the generation of bugs 60320 sample file
-     * as the padding bytes of the EncryptedPackage stream are random or in POIs case PKCS5-padded
-     * one would need to mock those bytes to get the same hmacValues - see diff below
-     *
-     * this use-case is experimental - for the time being the setters of the encryption classes
-     * are spreaded between two packages and are protected - so you would need to violate
-     * the packages rules and provide a helper class in the *poifs.crypt package-namespace.
-     * the default way of defining the encryption settings is via the EncryptionInfo class
-     */
-    @Test
-    public void bug60320CustomEncrypt() throws Exception {
-        int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
-        Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files for AES 256", maxKeyLen == 2147483647);
-
-        // --- src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java  (revision 1766745)
-        // +++ src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java  (working copy)
-        // @@ -208,6 +208,13 @@
-        //      protected int invokeCipher(int posInChunk, boolean doFinal) throws GeneralSecurityException {
-        //          byte plain[] = (_plainByteFlags.isEmpty()) ? null : _chunk.clone();
-        //
-        // +        if (posInChunk < 4096) {
-        // +            _cipher.update(_chunk, 0, posInChunk, _chunk);
-        // +            byte bla[] = { (byte)0x7A,(byte)0x0F,(byte)0x27,(byte)0xF0,(byte)0x17,(byte)0x6E,(byte)0x77,(byte)0x05,(byte)0xB9,(byte)0xDA,(byte)0x49,(byte)0xF9,(byte)0xD7,(byte)0x8E,(byte)0x03,(byte)0x1D };
-        // +            System.arraycopy(bla, 0, _chunk, posInChunk-2, bla.length);
-        // +            return posInChunk-2+bla.length;
-        // +        }
-        // +
-        //          int ciLen = (doFinal)
-        //              ? _cipher.doFinal(_chunk, 0, posInChunk, _chunk)
-        //              : _cipher.update(_chunk, 0, posInChunk, _chunk);
-        //
-        //      --- src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java (revision 1766745)
-        //      +++ src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java (working copy)
-        //
-        //      @@ -300,7 +297,7 @@
-        //      protected static Cipher initCipherForBlock(Cipher existing, int block, boolean lastChunk, EncryptionInfo encryptionInfo, SecretKey skey, int encryptionMode)
-        //      throws GeneralSecurityException {
-        //          EncryptionHeader header = encryptionInfo.getHeader();
-        // -        String padding = (lastChunk ? "PKCS5Padding" : "NoPadding");
-        // +        String padding = "NoPadding"; // (lastChunk ? "PKCS5Padding" : "NoPadding");
-        //          if (existing == null || !existing.getAlgorithm().endsWith(padding)) {
-        //              existing = getCipher(skey, header.getCipherAlgorithm(), header.getChainingMode(), header.getKeySalt(), encryptionMode, padding);
-        //          }
-
-        final EncryptionInfo infoOrig;
-        final byte[] zipInput, epOrigBytes;
-        try (InputStream is = POIDataSamples.getPOIFSInstance().openResourceAsStream("60320-protected.xlsx");
-            POIFSFileSystem fsOrig = new POIFSFileSystem(is)) {
-            infoOrig = new EncryptionInfo(fsOrig);
-            Decryptor decOrig = infoOrig.getDecryptor();
-            boolean b = decOrig.verifyPassword("Test001!!");
-            assertTrue(b);
-            try (InputStream decIn = decOrig.getDataStream(fsOrig)) {
-                zipInput = IOUtils.toByteArray(decIn);
-            }
-
-            try (InputStream epOrig = fsOrig.getRoot().createDocumentInputStream("EncryptedPackage")) {
-                // ignore the 16 padding bytes
-                epOrigBytes = IOUtils.toByteArray(epOrig, 9400);
-            }
-        }
-
-        EncryptionInfo eiNew = new EncryptionInfo(EncryptionMode.agile);
-        AgileEncryptionHeader aehHeader = (AgileEncryptionHeader)eiNew.getHeader();
-        aehHeader.setCipherAlgorithm(CipherAlgorithm.aes128);
-        aehHeader.setHashAlgorithm(HashAlgorithm.sha1);
-        AgileEncryptionVerifier aehVerifier = (AgileEncryptionVerifier)eiNew.getVerifier();
-
-        // this cast might look strange - if the setters would be public, it will become obsolete
-        // see http://stackoverflow.com/questions/5637650/overriding-protected-methods-in-java
-        ((EncryptionVerifier)aehVerifier).setCipherAlgorithm(CipherAlgorithm.aes256);
-        aehVerifier.setHashAlgorithm(HashAlgorithm.sha512);
-
-        Encryptor enc = eiNew.getEncryptor();
-        enc.confirmPassword("Test001!!",
-            infoOrig.getDecryptor().getSecretKey().getEncoded(),
-            infoOrig.getHeader().getKeySalt(),
-            infoOrig.getDecryptor().getVerifier(),
-            infoOrig.getVerifier().getSalt(),
-            infoOrig.getDecryptor().getIntegrityHmacKey()
-        );
-
-        final byte[] epNewBytes;
-        final EncryptionInfo infoReload;
-        try (POIFSFileSystem fsNew = new POIFSFileSystem()) {
-            try (OutputStream os = enc.getDataStream(fsNew)) {
-                os.write(zipInput);
-            }
-
-            ByteArrayOutputStream bos = new ByteArrayOutputStream();
-            fsNew.writeFilesystem(bos);
-
-            try (POIFSFileSystem fsReload = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()))) {
-                infoReload = new EncryptionInfo(fsReload);
-                try (InputStream epReload = fsReload.getRoot().createDocumentInputStream("EncryptedPackage")) {
-                    epNewBytes = IOUtils.toByteArray(epReload, 9400);
-                }
-            }
-        }
-
-        assertArrayEquals(epOrigBytes, epNewBytes);
-
-        Decryptor decReload = infoReload.getDecryptor();
-        assertTrue(decReload.verifyPassword("Test001!!"));
-
-        AgileEncryptionHeader aehOrig = (AgileEncryptionHeader)infoOrig.getHeader();
-        AgileEncryptionHeader aehReload = (AgileEncryptionHeader)infoReload.getHeader();
-        assertEquals(aehOrig.getBlockSize(), aehReload.getBlockSize());
-        assertEquals(aehOrig.getChainingMode(), aehReload.getChainingMode());
-        assertEquals(aehOrig.getCipherAlgorithm(), aehReload.getCipherAlgorithm());
-        assertEquals(aehOrig.getCipherProvider(), aehReload.getCipherProvider());
-        assertEquals(aehOrig.getCspName(), aehReload.getCspName());
-        assertArrayEquals(aehOrig.getEncryptedHmacKey(), aehReload.getEncryptedHmacKey());
-        // this only works, when the paddings are mocked to be the same ...
-        // assertArrayEquals(aehOrig.getEncryptedHmacValue(), aehReload.getEncryptedHmacValue());
-        assertEquals(aehOrig.getFlags(), aehReload.getFlags());
-        assertEquals(aehOrig.getHashAlgorithm(), aehReload.getHashAlgorithm());
-        assertArrayEquals(aehOrig.getKeySalt(), aehReload.getKeySalt());
-        assertEquals(aehOrig.getKeySize(), aehReload.getKeySize());
-
-        AgileEncryptionVerifier aevOrig = (AgileEncryptionVerifier)infoOrig.getVerifier();
-        AgileEncryptionVerifier aevReload = (AgileEncryptionVerifier)infoReload.getVerifier();
-        assertEquals(aevOrig.getBlockSize(), aevReload.getBlockSize());
-        assertEquals(aevOrig.getChainingMode(), aevReload.getChainingMode());
-        assertEquals(aevOrig.getCipherAlgorithm(), aevReload.getCipherAlgorithm());
-        assertArrayEquals(aevOrig.getEncryptedKey(), aevReload.getEncryptedKey());
-        assertArrayEquals(aevOrig.getEncryptedVerifier(), aevReload.getEncryptedVerifier());
-        assertArrayEquals(aevOrig.getEncryptedVerifierHash(), aevReload.getEncryptedVerifierHash());
-        assertEquals(aevOrig.getHashAlgorithm(), aevReload.getHashAlgorithm());
-        assertEquals(aevOrig.getKeySize(), aevReload.getKeySize());
-        assertArrayEquals(aevOrig.getSalt(), aevReload.getSalt());
-        assertEquals(aevOrig.getSpinCount(), aevReload.getSpinCount());
-
-        AgileDecryptor adOrig = (AgileDecryptor)infoOrig.getDecryptor();
-        AgileDecryptor adReload = (AgileDecryptor)infoReload.getDecryptor();
-
-        assertArrayEquals(adOrig.getIntegrityHmacKey(), adReload.getIntegrityHmacKey());
-        // doesn't work without mocking ... see above
-        // assertArrayEquals(adOrig.getIntegrityHmacValue(), adReload.getIntegrityHmacValue());
-        assertArrayEquals(adOrig.getSecretKey().getEncoded(), adReload.getSecretKey().getEncoded());
-        assertArrayEquals(adOrig.getVerifier(), adReload.getVerifier());
-    }
-
-    @Test
-    public void smallFile() throws IOException, GeneralSecurityException {
-        // see https://stackoverflow.com/questions/61463301
-        final int tinyFileSize = 80_000_000;
-        final String pass = "s3cr3t";
-
-        File tmpFile = TempFile.createTempFile("tiny", ".bin");
-
-        // create/populate empty file
-        try (POIFSFileSystem poifs = new POIFSFileSystem();
-             FileOutputStream fos = new FileOutputStream(tmpFile)) {
-            poifs.writeFilesystem(fos);
-        }
-
-        EncryptionInfo info1 = new EncryptionInfo(EncryptionMode.agile);
-        Encryptor enc = info1.getEncryptor();
-        enc.confirmPassword(pass);
-
-        final MessageDigest md = getMessageDigest(HashAlgorithm.sha256);
-
-        // reopen as mmap-ed file
-        try (POIFSFileSystem poifs = new POIFSFileSystem(tmpFile, false)) {
-            try (OutputStream os = enc.getDataStream(poifs);
-                 RandomStream rs = new RandomStream(md)) {
-                IOUtils.copy(rs, os, tinyFileSize);
-            }
-            poifs.writeFilesystem();
-        }
-
-        final byte[] digest1 = md.digest();
-        md.reset();
-
-        // reopen and check the digest
-        try (POIFSFileSystem poifs = new POIFSFileSystem(tmpFile)) {
-            EncryptionInfo info2 = new EncryptionInfo(poifs);
-            Decryptor dec = info2.getDecryptor();
-            boolean passOk = dec.verifyPassword(pass);
-            assertTrue(passOk);
-
-            try (InputStream is = dec.getDataStream(poifs);
-                 DigestInputStream dis = new DigestInputStream(is, md);
-                 NullOutputStream nos = new NullOutputStream()) {
-                IOUtils.copy(dis, nos);
-            }
-        }
-
-        final byte[] digest2 = md.digest();
-        assertArrayEquals(digest1, digest2);
-
-        boolean isDeleted = tmpFile.delete();
-        assertTrue(isDeleted);
-    }
-
-    private static final class RandomStream extends InputStream {
-        private final Random rand = new Random();
-        private final byte[] buf = new byte[1024];
-        private final MessageDigest md;
-
-        private RandomStream(MessageDigest md) {
-            this.md = md;
-        }
-
-        @Override
-        public int read() {
-            int ret = rand.nextInt(256);
-            md.update((byte)ret);
-            return ret;
-        }
-
-        @Override
-        public int read(byte[] b, final int off, int len) {
-            for (int start = off; start-off < len; start += buf.length) {
-                rand.nextBytes(buf);
-                int copyLen = Math.min(buf.length, len-(start-off));
-                System.arraycopy(buf, 0, b, start, copyLen);
-                md.update(buf, 0, copyLen);
-            }
-            return len;
-        }
-    }
-
-}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestHxxFEncryption.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestHxxFEncryption.java
deleted file mode 100644 (file)
index 25443d7..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.poifs.crypt;
-
-import static org.apache.poi.POIDataSamples.getDocumentInstance;
-import static org.apache.poi.POIDataSamples.getSlideShowInstance;
-import static org.apache.poi.POIDataSamples.getSpreadSheetInstance;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Collection;
-
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.POIDocument;
-import org.apache.poi.extractor.POITextExtractor;
-import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
-import org.apache.poi.ooxml.extractor.ExtractorFactory;
-import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
-import org.apache.poi.poifs.crypt.cryptoapi.CryptoAPIEncryptionHeader;
-import org.apache.poi.poifs.storage.RawDataUtil;
-import org.apache.xmlbeans.XmlException;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class TestHxxFEncryption {
-    @Parameter(value = 0)
-    public POIDataSamples sampleDir;
-
-    @Parameter(value = 1)
-    public String file;
-
-    @Parameter(value = 2)
-    public String password;
-
-    @Parameter(value = 3)
-    public String expected;
-
-    @Parameters(name="{1}")
-    public static Collection<Object[]> data() throws IOException {
-        final String base64 =
-            "H4sIAAAAAAAAAF1Uu24bMRDs/RULVwkgCUhSpHaZwkDgpHJH8fZ0G/Nx4ZI6y13yG/mRfIb9R5mlZFlIpdPtcnZmdnjPf57/vvx6+f3h6obuv3"+
-            "ylbY5bEiVHe1fEpUp5pOgkrK0iabehm7FyoZi1ks8xcvHiQu8h5bLnorTlnUvkJ/YPOHKsLVInAqCs91KakuaxLq4w3g00SgCo9Xou1UnCmSBe"+
-            "MhpRY6qHmXVFteQfQJ5yUaaOw4qXwgPVjPGAqhNH5bBHAfTmwqqoSkLdFT/J3nC0eZBRk7yiu5s7yoU+r+9l3tDtm5A3jgt6AQxNOY2ya+U4sK"+
-            "XZ+YczbpfSVVuzFOuunKraqIVD2ND3yVXauT3TNthR/O3IJAM7gzTOGeIcXZvj14ahotW8wSognlMu0Yyp/Fi7O6s+CK6haUUjtPCji7MVcgqH"+
-            "jh+42tqeqPDMroJ/lBAE4AZbJbJu6Fu35ej42Tw9mYeTwVXoBKJiPeFV94q2rZJAyNEPo/qOdWYLBpq3B2JX8GDZeJ14mZf3tOQWBmpd9yQ7kI"+
-            "DCY/jmkj1oGOicFy62r9vutC5uJsVEMFgmAXXfYcC6BRBKNHCybALFJolnrDcPXNLl+K60Vctt09YZT7YgbeOICGJ/ZgC2JztOnm1JhX3eJXni"+
-            "U5Bqhezzlu334vD/Ajr3yDGXw5G9IZ6aLmLfQafY42N3J7cjj1LaXOHihSrcC5ThmuYIB5FX5AU8tKlnNG9Dn1EnsdD4KcnPhsSNPRiXtz461b"+
-            "VZw8Pm6vn0afh4fvr0D5P/+cMuBAAA";
-        final String x = new String(RawDataUtil.decompress(base64), StandardCharsets.UTF_8);
-
-        return Arrays.asList(
-            // binary rc4
-            new Object[]{ getDocumentInstance(), "password_tika_binaryrc4.doc", "tika", "This is an encrypted Word 2007 File." },
-            // cryptoapi
-            new Object[]{ getDocumentInstance(), "password_password_cryptoapi.doc", "password", "This is a test" },
-            // binary rc4
-            new Object[]{ getSpreadSheetInstance(), "password.xls", "password", x },
-            // cryptoapi
-            new Object[]{ getSpreadSheetInstance(), "35897-type4.xls", "freedom", "Sheet1\nhello there!" },
-            // cryptoapi (PPT only supports cryptoapi...)
-            new Object[]{ getSlideShowInstance(), "cryptoapi-proc2356.ppt", "crypto", "Dominic Salemno" }
-        );
-    }
-
-    @Test
-    public void extract() throws IOException, OpenXML4JException, XmlException {
-        File f = sampleDir.getFile(file);
-        Biff8EncryptionKey.setCurrentUserPassword(password);
-        try (POITextExtractor te = ExtractorFactory.createExtractor(f)) {
-            String actual = te.getText().trim();
-            assertEquals(expected, actual);
-        } finally {
-            Biff8EncryptionKey.setCurrentUserPassword(null);
-        }
-    }
-    
-    @Test
-    public void changePassword() throws IOException, OpenXML4JException, XmlException {
-        newPassword("test");
-    }
-    
-    @Test
-    public void removePassword() throws IOException, OpenXML4JException, XmlException {
-        newPassword(null);
-    }
-    
-    private void newPassword(String newPass) throws IOException, OpenXML4JException, XmlException {
-        File f = sampleDir.getFile(file);
-        Biff8EncryptionKey.setCurrentUserPassword(password);
-        try (POITextExtractor te1 = ExtractorFactory.createExtractor(f)) {
-            Biff8EncryptionKey.setCurrentUserPassword(newPass);
-            ByteArrayOutputStream bos = new ByteArrayOutputStream();
-            try (POIDocument doc = (POIDocument) te1.getDocument()) {
-                doc.write(bos);
-            }
-            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
-            try (POITextExtractor te2 = ExtractorFactory.createExtractor(bis)) {
-                String actual = te2.getText().trim();
-                assertEquals(expected, actual);
-            }
-        } finally {
-            Biff8EncryptionKey.setCurrentUserPassword(null);
-        }
-    }
-
-    /** changing the encryption mode and key size in poor mans style - see comments below */
-    @Test
-    public void changeEncryption() throws IOException, OpenXML4JException, XmlException {
-        File f = sampleDir.getFile(file);
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        Biff8EncryptionKey.setCurrentUserPassword(password);
-        try (POITextExtractor te1 = ExtractorFactory.createExtractor(f)) {
-            // first remove encryption
-            Biff8EncryptionKey.setCurrentUserPassword(null);
-            try (POIDocument doc = (POIDocument) te1.getDocument()) {
-                doc.write(bos);
-            }
-            // then use default setting, which is cryptoapi
-            String newPass = "newPass";
-            try (POITextExtractor te2 = ExtractorFactory.createExtractor(new ByteArrayInputStream(bos.toByteArray()))) {
-                Biff8EncryptionKey.setCurrentUserPassword(newPass);
-                try (POIDocument doc = (POIDocument) te2.getDocument()) {
-                    bos.reset();
-                    doc.write(bos);
-                }
-            }
-            // and finally update cryptoapi setting
-            try (POITextExtractor te3 = ExtractorFactory.createExtractor(new ByteArrayInputStream(bos.toByteArray()));
-                 POIDocument doc = (POIDocument) te3.getDocument()) {
-                // need to cache data (i.e. read all data) before changing the key size
-                Class<?> clazz = doc.getClass();
-                if ("HSLFSlideShowImpl".equals(clazz.getSimpleName())) {
-                    try {
-                        clazz.getDeclaredMethod("getPictureData").invoke(doc);
-                    } catch (ReflectiveOperationException e) {
-                        fail("either scratchpad jar is included and this should work or the clazz should be != HSLFSlideShowImpl");
-                    }
-                    doc.getDocumentSummaryInformation();
-                }
-                EncryptionInfo ei = doc.getEncryptionInfo();
-                assertNotNull(ei);
-                assertTrue(ei.getHeader() instanceof CryptoAPIEncryptionHeader);
-                assertEquals(0x28, ei.getHeader().getKeySize());
-                ei.getHeader().setKeySize(0x78);
-                bos.reset();
-                doc.write(bos);
-            }
-            // check the setting
-            try (POITextExtractor te4 = ExtractorFactory.createExtractor(new ByteArrayInputStream(bos.toByteArray()));
-                 POIDocument doc = (POIDocument) te4.getDocument()) {
-                EncryptionInfo ei = doc.getEncryptionInfo();
-                assertNotNull(ei);
-                assertTrue(ei.getHeader() instanceof CryptoAPIEncryptionHeader);
-                assertEquals(0x78, ei.getHeader().getKeySize());
-            }
-        } finally {
-            Biff8EncryptionKey.setCurrentUserPassword(null);
-        }
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSecureTempZip.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSecureTempZip.java
deleted file mode 100644 (file)
index 6244cec..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.poifs.crypt;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import javax.crypto.Cipher;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.GeneralSecurityException;
-
-import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.openxml4j.util.ZipEntrySource;
-import org.apache.poi.poifs.crypt.temp.AesZipFileZipEntrySource;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.xssf.XSSFTestDataSamples;
-import org.apache.poi.xssf.extractor.XSSFBEventBasedExcelExtractor;
-import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.apache.xmlbeans.XmlException;
-import org.junit.Assume;
-import org.junit.Test;
-
-public class TestSecureTempZip {
-
-    /**
-     * Test case for #59841 - this is an example on how to use encrypted temp files,
-     * which are streamed into POI opposed to having everything in memory
-     */
-    @Test
-    public void protectedTempZip() throws IOException, GeneralSecurityException, XmlException, OpenXML4JException {
-        File tikaProt = XSSFTestDataSamples.getSampleFile("protected_passtika.xlsx");
-        FileInputStream fis = new FileInputStream(tikaProt);
-        POIFSFileSystem poifs = new POIFSFileSystem(fis);
-        EncryptionInfo ei = new EncryptionInfo(poifs);
-        Decryptor dec = ei.getDecryptor();
-        boolean passOk = dec.verifyPassword("tika");
-        assertTrue(passOk);
-
-        // extract encrypted ooxml file and write to custom encrypted zip file 
-        InputStream is = dec.getDataStream(poifs);
-        
-        // provide ZipEntrySource to poi which decrypts on the fly
-        ZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(is);
-
-        // test the source
-        OPCPackage opc = OPCPackage.open(source);
-        String expected = "This is an Encrypted Excel spreadsheet.";
-        
-        XSSFEventBasedExcelExtractor extractor = new XSSFEventBasedExcelExtractor(opc);
-        extractor.setIncludeSheetNames(false);
-        String txt = extractor.getText();
-        assertEquals(expected, txt.trim());
-        
-        XSSFWorkbook wb = new XSSFWorkbook(opc);
-        txt = wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue();
-        assertEquals(expected, txt);
-
-        extractor.close();
-        
-        wb.close();
-        opc.close();
-        source.close();
-        poifs.close();
-        fis.close();
-    }
-
-    /**
-     * Now try with xlsb.
-     */
-    @Test
-    public void protectedXLSBZip() throws IOException, GeneralSecurityException, XmlException, OpenXML4JException {
-        //The test file requires that JCE unlimited be installed.
-        //If it isn't installed, skip this test.
-        int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
-        Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files for AES 256",
-                maxKeyLen == 2147483647);
-
-        File tikaProt = XSSFTestDataSamples.getSampleFile("protected_passtika.xlsb");
-        FileInputStream fis = new FileInputStream(tikaProt);
-        POIFSFileSystem poifs = new POIFSFileSystem(fis);
-        EncryptionInfo ei = new EncryptionInfo(poifs);
-        Decryptor dec = ei.getDecryptor();
-        boolean passOk = dec.verifyPassword("tika");
-        assertTrue(passOk);
-
-        // extract encrypted ooxml file and write to custom encrypted zip file
-        InputStream is = dec.getDataStream(poifs);
-
-        // provide ZipEntrySource to poi which decrypts on the fly
-        ZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(is);
-
-        // test the source
-        OPCPackage opc = OPCPackage.open(source);
-        String expected = "You can't see me";
-
-        XSSFBEventBasedExcelExtractor extractor = new XSSFBEventBasedExcelExtractor(opc);
-        extractor.setIncludeSheetNames(false);
-        String txt = extractor.getText();
-        assertEquals(expected, txt.trim());
-
-        extractor.close();
-        opc.close();
-        poifs.close();
-        fis.close();
-    }
-
-}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java
deleted file mode 100644 (file)
index e997a00..0000000
+++ /dev/null
@@ -1,1138 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-/* ====================================================================
-   This product contains an ASLv2 licensed version of the OOXML signer
-   package from the eID Applet project
-   http://code.google.com/p/eid-applet/source/browse/trunk/README.txt
-   Copyright (C) 2008-2014 FedICT.
-   ================================================================= */
-package org.apache.poi.poifs.crypt;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.math.BigInteger;
-import java.net.ConnectException;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.SocketTimeoutException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.security.Key;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.cert.CRLException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509CRL;
-import java.security.cert.X509Certificate;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.RSAKeyGenParameterSpec;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.xml.crypto.MarshalException;
-import javax.xml.crypto.dsig.CanonicalizationMethod;
-import javax.xml.crypto.dsig.XMLSignatureException;
-import javax.xml.crypto.dsig.dom.DOMSignContext;
-
-import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
-import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.ooxml.util.DocumentHelper;
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.openxml4j.opc.PackageAccess;
-import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
-import org.apache.poi.poifs.crypt.dsig.SignatureConfig;
-import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
-import org.apache.poi.poifs.crypt.dsig.SignaturePart;
-import org.apache.poi.poifs.crypt.dsig.facets.EnvelopedSignatureFacet;
-import org.apache.poi.poifs.crypt.dsig.facets.KeyInfoSignatureFacet;
-import org.apache.poi.poifs.crypt.dsig.facets.OOXMLSignatureFacet;
-import org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet;
-import org.apache.poi.poifs.crypt.dsig.facets.XAdESXLSignatureFacet;
-import org.apache.poi.poifs.crypt.dsig.services.RevocationData;
-import org.apache.poi.poifs.crypt.dsig.services.RevocationDataService;
-import org.apache.poi.poifs.crypt.dsig.services.TimeStampService;
-import org.apache.poi.poifs.crypt.dsig.services.TimeStampServiceValidator;
-import org.apache.poi.poifs.storage.RawDataUtil;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
-import org.apache.poi.xssf.streaming.SXSSFWorkbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.apache.xmlbeans.SystemProperties;
-import org.apache.xmlbeans.XmlObject;
-import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
-import org.bouncycastle.asn1.x509.BasicConstraints;
-import org.bouncycastle.asn1.x509.CRLNumber;
-import org.bouncycastle.asn1.x509.Extension;
-import org.bouncycastle.asn1.x509.Extensions;
-import org.bouncycastle.asn1.x509.KeyUsage;
-import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.cert.X509CRLHolder;
-import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.X509ExtensionUtils;
-import org.bouncycastle.cert.X509v2CRLBuilder;
-import org.bouncycastle.cert.X509v3CertificateBuilder;
-import org.bouncycastle.cert.jcajce.JcaX509CRLConverter;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-import org.bouncycastle.cert.ocsp.BasicOCSPResp;
-import org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder;
-import org.bouncycastle.cert.ocsp.CertificateID;
-import org.bouncycastle.cert.ocsp.CertificateStatus;
-import org.bouncycastle.cert.ocsp.OCSPReq;
-import org.bouncycastle.cert.ocsp.OCSPReqBuilder;
-import org.bouncycastle.cert.ocsp.OCSPResp;
-import org.bouncycastle.cert.ocsp.OCSPRespBuilder;
-import org.bouncycastle.cert.ocsp.Req;
-import org.bouncycastle.crypto.params.RSAKeyParameters;
-import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
-import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.DigestCalculator;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
-import org.etsi.uri.x01903.v13.DigestAlgAndValueType;
-import org.etsi.uri.x01903.v13.QualifyingPropertiesType;
-import org.junit.AfterClass;
-import org.junit.Assume;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.w3.x2000.x09.xmldsig.ReferenceType;
-import org.w3.x2000.x09.xmldsig.SignatureDocument;
-import org.w3c.dom.Document;
-
-public class TestSignatureInfo {
-    private static final POILogger LOG = POILogFactory.getLogger(TestSignatureInfo.class);
-    private static final POIDataSamples testdata = POIDataSamples.getXmlDSignInstance();
-
-    private static Calendar cal;
-    private KeyPair keyPair;
-    private X509Certificate x509;
-
-    @Rule
-    public ExpectedException thrown = ExpectedException.none();
-
-    @AfterClass
-    public static void removeUserLocale() {
-        LocaleUtil.resetUserLocale();
-    }
-
-    @BeforeClass
-    public static void initBouncy() {
-        CryptoFunctions.registerBouncyCastle();
-
-        // Set cal to now ... only set to fixed date for debugging ...
-        LocaleUtil.resetUserLocale();
-        LocaleUtil.resetUserTimeZone();
-
-        cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
-        assertNotNull(cal);
-
-        // don't run this test when we are using older Xerces as it triggers an XML Parser backwards compatibility issue
-        // in the xmlsec jar file
-        String additionalJar = System.getProperty("additionaljar");
-        //System.out.println("Having: " + additionalJar);
-        Assume.assumeTrue("Not running TestSignatureInfo because we are testing with additionaljar set to " + additionalJar,
-                          additionalJar == null || additionalJar.trim().length() == 0);
-
-        System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true");
-
-        // Set line.separator for bug61182
-        // System.setProperty("line.separator", "\n");
-    }
-
-    @Ignore("This test is very sensitive, it breaks with every little change to the produced XML")
-    @Test
-    public void bug61182() throws Exception {
-        final String pfxInput =
-                "H4sIAAAAAAAAAFXTfzzTeRwH8P2uGRmG6hKSmJh9a2HsuPy60VnHCEU6v86sieZH2Jr2qFl+s+ZHJ5tfUcfKb4uho/OjiFq1qTv5ceFyp0PqEK"+
-                        "fH4+66++Pz+Dwer9fj8f7r9cRzEd4QMBTPRWxDIM14ZN47NfAWsJgL34Bx4at4Lvwdngvd9b8KqgbjQpGbMXzzgRGovytVFTBEzIXU47kQCd4U"+
-                        "ofJPvHl8JwyTjRS55hbKoor3UJLDE1i/PcPKCBAIDATjQlKiK67XjVYdcnkZgD2txroiAUb8W9dtn57DvTsbM+3wIsdocXDEN7TdPKgaSl+tU1"+
-                        "xq9oqiB5yMaZCPho8uUEbFU9U6u3N7lEMLTJGeA0RfX+5FMRrpXPFrbrlJ8uNUCE2H247P28Ckyfqlsy32yeKg/HTbH5JpqUDNw2B32+SaiRw7"+
-                        "ofRMePUpaAoK7KYgmd5ZIc0rLLYjJBfOWCb28xlrGhbpJvdToFdqt5PXVjEz5YOJ6g7W0fskuKW9/iZP0yLEVpR9XkkHmb6tfpcE8YwCdWNCan"+
-                        "LvAsco25JdF1j2/FLAMVU79HdOex07main90dy40511OZtTGZ+TdVd3lKZ7D3clEg9hLESHwSNnZ6239X4yLM4xYSElQ/hqSbwdmiozYG9PhF2"+
-                        "Zf0XaZnxzTK0Iot+rJ3kYoxWTLE8DR9leV62Ywbtlg4mapYOxb3lT7fQ1x4EQ44flh2oFWSPLR8LMbsc6jzJsV6OZ3TrODjHEdw9W+8OD32vd8"+
-                        "XQ6iCaIHcrSOn6qS0TKLr786234eeSAhvAQbEsVn7vrvc/487Be/O2e/+5Y5zRq2zAtz6pfcNyraJNDqMW1inNkgJ3t3VESbZ3pNzyl3KHILs0"+
-                        "51dY6msDYSlWhw40TglXxj9rw95O6gFWIuN012W/vhS50jpKXcao4gc1aLaXtJXxirbRkpZ/0e7a0pD6TDa7+GxEdEEML3VGo9udD5YUKhU3y7"+
-                        "SzWAgN6WIEIglq7LilvCjqIVLIfg8CvVGL9f5iSsCDf5hef4vMxbyvcjINuy06gZu+iPYOWNxjfrwKGYzoqqotK2aywgYVrPMh0JovfkDuN95n"+
-                        "MdVlYHbN1Mnn4TxAwuv+u3AkBlDZvRUUCwoDMUGxeMNPhTaAgWl60xhhBgCBaEMgAACReMAav7n3x598IDYJ9GxGXRAwaPOT/kfO/1AgPqLQkp"+
-                        "MiIVaHthnUS4v2y32e2BjdMPyIImUTBW3cV3R5tjVQm0MOm+D2C5+bBW9vHLjLR4lun4toQiY3Ls/v4bES/OJ4EmpZk5xhL9i5ClofYZNEsxFn"+
-                        "An/q821Tg+Cq9Er4XYGQe8ogjjLJ2b7dUsJ3auFQFNUJF7Ke7yUL2EeYYxl6vz5l4q5u8704mRbFts1E1eWMp6WIy91GPrsVlRGvtuNERfrjfE"+
-                        "YtzUI3Flcv65zJUbUBEzUnTS0fEYso2XyToAl8kb251mUY2o2lJzv5dp/1htmcjeeP2MjxC+3S45ljx7jd52Pv9XAat+ryiauFOF7YgztkoWWD"+
-                        "h62tplPH1bzDV+d0NLdaE5AfVJ09HuUYTFS+iggtvT5Euyk+unj4N2XvzW91n+GNjtgWfKOHmkinUPvYRh70Jv+wlPJrVaT8mL7GxJLqDC9jbv"+
-                        "Gznoiae6es+wQejnk3XjU366MrK/zXxngBYj9J6NnXc9mMiTFLX8WqQ8iTelTAFs2NJzPoDzrBUz4JFIEOa6Dja6dULc68g1jFDTeEHZyra7RZ"+
-                        "2ElqGDEqcNRo3SNX6feMy9EF1GOyZK0Sa87KwjKw8aM68dpsIYjfLcTXaZ6atg0BKfMnl6axeUGEaIFSP7rzj9wjzumRbG3jgUVp2lX5AK/tsO"+
-                        "7R4TQX/9/H6RiN34c9KldmPZZGANXzzTajZS9mR2OSvlJ+F4AgSko4htrMAKFTBu51/5SWNsO1vlRaaG48ZRJ+8PzuHQMdvS36gNpRPi7jhF1S"+
-                        "H3B2ycI4y0VURv6SrqJNUY/X645ZFJQ+eBO+ptG7o8axf1dcqh2beiQk+GRTeZ37LVeUlaeo9vl1/+8tyBfyT2v5lFC5E19WdKIyCuZe7r99Px"+
-                        "D/Od4Qj0TA92+DQnbCQTCMy/wwse9O4gsEebkkpPIP5GBV3Q0YBsj75XE0uSFQ1tCZSW8bNa9MUJZ/nPBfExohHlgGAAA=";
-
-        // Unix
-        final String unixSignExp =
-                "QkqTFQZjXagjRAoOWKpAGa8AR0rKqkSfBtfSWqtjBmTgyjarn+t2POHkpySIpheHAbg+90GKSH88ACMtPHbG7q" +
-                        "FL4gtgAD9Kjew6j16j0IRBwy145UlPrSLFMfF7YF7UlU1k1LBkIlRJ6Fv4MAJl6XspuzZOZIUmHZrWrdxycUQ=";
-
-        // Windows
-        final String winSignExp =
-                "GmAlL7+bT1r3FsMHJOp3pKg8betblYieZTjhMIrPZPRBbSzjO7KsYRGNtr0aOE3qr8xzyYJN6/8QdF5X7pUEUc" +
-                        "2m8ctrm7s5o2vZTkAqk9ENJGDjBPXX7TnuVOiVeL1cJdtjHC2QpjtRwkFR+B54G6b1OXLOFuQpP3vqR3+/XXE=";
-
-        // Mac
-        final String macSignExp =
-                "NZedY/LNTYU4nAUEUhIOg5+fKdgVtzRXKmdD3v+47E7Mb84oeiUGv9cCEE91DU3StF/JFIhjOJqavOzKnCsNcz" +
-                        "NJ4j/inggUl1OJUsicqIGQnA7E8vzWnN1kf5lINgJLv+0PyrrX9sQZbItzxUpgqyOFYcD0trid+31nRt4wtaA=";
-
-
-
-        Calendar cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
-        cal.clear();
-        cal.setTimeZone(LocaleUtil.TIMEZONE_UTC);
-        cal.set(2017, Calendar.JULY, 1);
-
-        SignatureConfig signatureConfig = prepareConfig(pfxInput);
-        signatureConfig.setExecutionTime(cal.getTime());
-
-        SignatureInfo si = new SignatureInfo();
-        si.setSignatureConfig(signatureConfig);
-
-        ByteArrayOutputStream bos = new ByteArrayOutputStream(100000);
-        try (XSSFWorkbook wb1 = new XSSFWorkbook()) {
-            wb1.createSheet().createRow(1).createCell(1).setCellValue("Test");
-            wb1.write(bos);
-        }
-
-        try (OPCPackage pkg1 = OPCPackage.open(new ByteArrayInputStream(bos.toByteArray()))) {
-            si.setOpcPackage(pkg1);
-            si.confirmSignature();
-            assertTrue(si.verifySignature());
-            bos.reset();
-            pkg1.save(bos);
-        }
-
-        try (XSSFWorkbook wb2 = new XSSFWorkbook(new ByteArrayInputStream(bos.toByteArray()))) {
-            assertEquals("Test", wb2.getSheetAt(0).getRow(1).getCell(1).getStringCellValue());
-            OPCPackage pkg2 = wb2.getPackage();
-            si.setOpcPackage(pkg2);
-            assertTrue(si.verifySignature());
-
-            // xmlbeans adds line-breaks depending on the system setting, so we get different
-            // test results on Unix/Mac/Windows
-            // if the xml documents eventually change, this test needs to be run with the
-            // separator set to the various system configurations
-            String sep = SystemProperties.getProperty("line.separator");
-            String signExp;
-            assumeTrue("Hashes only known for Windows/Unix/Mac", sep == null || "\n".equals(sep) || "\r\n".equals(sep) || "\r".equals(sep));
-            signExp = (sep == null || "\n".equals(sep)) ? unixSignExp : ("\r\n".equals(sep)) ? winSignExp : macSignExp;
-
-            String signAct = si.getSignatureParts().iterator().next().
-                    getSignatureDocument().getSignature().getSignatureValue().getStringValue();
-            assertEquals(signExp, signAct);
-        }
-    }
-
-    @Test
-    public void office2007prettyPrintedRels() throws Exception {
-        try (OPCPackage pkg = OPCPackage.open(testdata.getFile("office2007prettyPrintedRels.docx"), PackageAccess.READ)) {
-            SignatureConfig sic = new SignatureConfig();
-            SignatureInfo si = new SignatureInfo();
-            si.setOpcPackage(pkg);
-            si.setSignatureConfig(sic);
-            boolean isValid = si.verifySignature();
-            assertTrue(isValid);
-        }
-    }
-
-    @Test
-    public void getSignerUnsigned() throws Exception {
-        String[] testFiles = {
-                "hello-world-unsigned.docx",
-                "hello-world-unsigned.pptx",
-                "hello-world-unsigned.xlsx",
-                "hello-world-office-2010-technical-preview-unsigned.docx"
-        };
-
-        for (String testFile : testFiles) {
-            List<X509Certificate> result = new ArrayList<>();
-            try (OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ)) {
-                SignatureConfig sic = new SignatureConfig();
-                SignatureInfo si = new SignatureInfo();
-                si.setOpcPackage(pkg);
-                si.setSignatureConfig(sic);
-                for (SignaturePart sp : si.getSignatureParts()) {
-                    if (sp.validate()) {
-                        result.add(sp.getSigner());
-                    }
-                }
-                pkg.revert();
-            }
-            assertNotNull(result);
-            assertTrue(result.isEmpty());
-        }
-    }
-
-    @Test
-    public void getSigner() throws Exception {
-        String[] testFiles = {
-                "hyperlink-example-signed.docx",
-                "hello-world-signed.docx",
-                "hello-world-signed.pptx",
-                "hello-world-signed.xlsx",
-                "hello-world-office-2010-technical-preview.docx",
-                "ms-office-2010-signed.docx",
-                "ms-office-2010-signed.pptx",
-                "ms-office-2010-signed.xlsx",
-                "Office2010-SP1-XAdES-X-L.docx",
-                "signed.docx"
-        };
-
-        for (String testFile : testFiles) {
-            try (OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ)) {
-                SignatureConfig sic = new SignatureConfig();
-                SignatureInfo si = new SignatureInfo();
-                si.setOpcPackage(pkg);
-                si.setSignatureConfig(sic);
-                List<X509Certificate> result = new ArrayList<>();
-                for (SignaturePart sp : si.getSignatureParts()) {
-                    if (sp.validate()) {
-                        result.add(sp.getSigner());
-                    }
-                }
-
-                assertNotNull(result);
-                assertEquals("test-file: " + testFile, 1, result.size());
-                X509Certificate signer = result.get(0);
-                LOG.log(POILogger.DEBUG, "signer: " + signer.getSubjectX500Principal());
-
-                boolean b = si.verifySignature();
-                assertTrue("test-file: " + testFile, b);
-                pkg.revert();
-            }
-        }
-    }
-
-    @Test
-    public void getMultiSigners() throws Exception {
-        String testFile = "hello-world-signed-twice.docx";
-        try (OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ)) {
-            SignatureConfig sic = new SignatureConfig();
-            SignatureInfo si = new SignatureInfo();
-            si.setOpcPackage(pkg);
-            si.setSignatureConfig(sic);
-            List<X509Certificate> result = new ArrayList<>();
-            for (SignaturePart sp : si.getSignatureParts()) {
-                if (sp.validate()) {
-                    result.add(sp.getSigner());
-                }
-            }
-
-            assertNotNull(result);
-            assertEquals("test-file: " + testFile, 2, result.size());
-            X509Certificate signer1 = result.get(0);
-            X509Certificate signer2 = result.get(1);
-            LOG.log(POILogger.DEBUG, "signer 1: " + signer1.getSubjectX500Principal());
-            LOG.log(POILogger.DEBUG, "signer 2: " + signer2.getSubjectX500Principal());
-
-            boolean b = si.verifySignature();
-            assertTrue("test-file: " + testFile, b);
-            pkg.revert();
-        }
-    }
-
-    @Test
-    public void testSignSpreadsheet() throws Exception {
-        String testFile = "hello-world-unsigned.xlsx";
-        try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
-            sign(pkg);
-        }
-    }
-
-    private static class CommitableWorkbook extends XSSFWorkbook {
-        CommitableWorkbook(OPCPackage pkg) throws IOException {
-            super(pkg);
-        }
-        public void commit() throws IOException {
-            super.commit();
-        }
-    }
-
-    @Test
-    public void testManipulation() throws Exception {
-        // sign & validate
-        String testFile = "hello-world-unsigned.xlsx";
-        try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
-            sign(pkg);
-
-            // manipulate
-            try (CommitableWorkbook wb = new CommitableWorkbook(pkg)) {
-                wb.setSheetName(0, "manipulated");
-                // ... I don't know, why commit is protected ...
-                wb.commit();
-
-                // todo: test a manipulation on a package part, which is not signed
-                // ... maybe in combination with #56164
-
-                // validate
-                SignatureConfig sic = new SignatureConfig();
-                SignatureInfo si = new SignatureInfo();
-                si.setOpcPackage(pkg);
-                si.setSignatureConfig(sic);
-                boolean b = si.verifySignature();
-                assertFalse("signature should be broken", b);
-            }
-        }
-    }
-
-    @Test
-    public void testSignSpreadsheetWithSignatureInfo() throws Exception {
-        initKeyPair();
-        String testFile = "hello-world-unsigned.xlsx";
-        try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
-            SignatureConfig sic = new SignatureConfig();
-            sic.setKey(keyPair.getPrivate());
-            sic.setSigningCertificateChain(Collections.singletonList(x509));
-            SignatureInfo si = new SignatureInfo();
-            si.setOpcPackage(pkg);
-            si.setSignatureConfig(sic);
-            // hash > sha1 doesn't work in excel viewer ...
-            si.confirmSignature();
-            List<X509Certificate> result = new ArrayList<>();
-            for (SignaturePart sp : si.getSignatureParts()) {
-                if (sp.validate()) {
-                    result.add(sp.getSigner());
-                }
-            }
-            assertEquals(1, result.size());
-        }
-    }
-
-    @Test
-    public void testSignEnvelopingDocument() throws Exception {
-        String testFile = "hello-world-unsigned.xlsx";
-        File sigCopy = testdata.getFile(testFile);
-        ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
-
-        final String execTimestr;
-
-
-        try (OPCPackage pkg = OPCPackage.open(copy(sigCopy), PackageAccess.READ_WRITE)) {
-
-            initKeyPair();
-            final X509CRL crl = generateCrl(x509, keyPair.getPrivate());
-
-            // setup
-            SignatureConfig signatureConfig = new SignatureConfig();
-            signatureConfig.setKey(keyPair.getPrivate());
-
-            /*
-             * We need at least 2 certificates for the XAdES-C complete certificate
-             * refs construction.
-             */
-            List<X509Certificate> certificateChain = new ArrayList<>();
-            certificateChain.add(x509);
-            certificateChain.add(x509);
-            signatureConfig.setSigningCertificateChain(certificateChain);
-
-            signatureConfig.addSignatureFacet(new OOXMLSignatureFacet());
-            signatureConfig.addSignatureFacet(new EnvelopedSignatureFacet());
-            signatureConfig.addSignatureFacet(new KeyInfoSignatureFacet());
-            signatureConfig.addSignatureFacet(new XAdESSignatureFacet());
-            signatureConfig.addSignatureFacet(new XAdESXLSignatureFacet());
-
-            // check for internet, no error means it works
-            boolean mockTsp = (getAccessError("http://timestamp.comodoca.com/rfc3161", true, 10000) != null);
-
-            // http://timestamping.edelweb.fr/service/tsp
-            // http://tsa.belgium.be/connect
-            // http://timestamp.comodoca.com/authenticode
-            // http://timestamp.comodoca.com/rfc3161
-            // http://services.globaltrustfinder.com/adss/tsa
-            signatureConfig.setTspUrl("http://timestamp.comodoca.com/rfc3161");
-            signatureConfig.setTspRequestPolicy(null); // comodoca request fails, if default policy is set ...
-            signatureConfig.setTspOldProtocol(false);
-
-            signatureConfig.setXadesDigestAlgo(HashAlgorithm.sha512);
-            signatureConfig.setXadesRole("Xades Reviewer");
-            signatureConfig.setSignatureDescription("test xades signature");
-
-            execTimestr = signatureConfig.formatExecutionTime();
-
-            //set proxy info if any
-            String proxy = System.getProperty("http_proxy");
-            if (proxy != null && proxy.trim().length() > 0) {
-                signatureConfig.setProxyUrl(proxy);
-            }
-
-            if (mockTsp) {
-                TimeStampService tspService = (signatureInfo, data, revocationData) -> {
-                    revocationData.addCRL(crl);
-                    return "time-stamp-token".getBytes(LocaleUtil.CHARSET_1252);
-                };
-                signatureConfig.setTspService(tspService);
-            } else {
-                TimeStampServiceValidator tspValidator = (validateChain, revocationData) -> {
-                    for (X509Certificate certificate : validateChain) {
-                        LOG.log(POILogger.DEBUG, "certificate: " + certificate.getSubjectX500Principal());
-                        LOG.log(POILogger.DEBUG, "validity: " + certificate.getNotBefore() + " - " + certificate.getNotAfter());
-                    }
-                };
-                signatureConfig.setTspValidator(tspValidator);
-                signatureConfig.setTspOldProtocol(signatureConfig.getTspUrl().contains("edelweb"));
-            }
-
-            final RevocationData revocationData = new RevocationData();
-            revocationData.addCRL(crl);
-            OCSPResp ocspResp = createOcspResp(x509, x509, x509, keyPair.getPrivate(), cal.getTimeInMillis());
-            revocationData.addOCSP(ocspResp.getEncoded());
-
-            RevocationDataService revocationDataService = revocationChain -> revocationData;
-            signatureConfig.setRevocationDataService(revocationDataService);
-
-            // operate
-            SignatureInfo si = new SignatureInfo();
-            si.setOpcPackage(pkg);
-            si.setSignatureConfig(signatureConfig);
-            try {
-                si.confirmSignature();
-            } catch (RuntimeException e) {
-                // only allow a ConnectException because of timeout, we see this in Jenkins from time to time...
-                if (e.getCause() == null) {
-                    throw e;
-                }
-                if ((e.getCause() instanceof ConnectException) || (e.getCause() instanceof SocketTimeoutException)) {
-                    Assume.assumeFalse("Only allowing ConnectException with 'timed out' as message here, but had: " + e,
-                                       e.getCause().getMessage().contains("timed out"));
-                } else if (e.getCause() instanceof IOException) {
-                    Assume.assumeFalse("Only allowing IOException with 'Error contacting TSP server' as message here, but had: " + e,
-                                       e.getCause().getMessage().contains("Error contacting TSP server"));
-                } else if (e.getCause() instanceof RuntimeException) {
-                    Assume.assumeFalse("Only allowing RuntimeException with 'This site is cur' as message here, but had: " + e,
-                                       e.getCause().getMessage().contains("This site is cur"));
-                }
-                throw e;
-            }
-
-            // verify
-            Iterator<SignaturePart> spIter = si.getSignatureParts().iterator();
-            assertTrue("Had: " + pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN), spIter.hasNext());
-            SignaturePart sp = spIter.next();
-            boolean valid = sp.validate();
-            assertTrue(valid);
-
-            SignatureDocument sigDoc = sp.getSignatureDocument();
-            String declareNS =
-                    "declare namespace xades='http://uri.etsi.org/01903/v1.3.2#'; "
-                            + "declare namespace ds='http://www.w3.org/2000/09/xmldsig#'; ";
-
-            String digestValXQuery = declareNS +
-                    "$this/ds:Signature/ds:SignedInfo/ds:Reference";
-            for (ReferenceType rt : (ReferenceType[]) sigDoc.selectPath(digestValXQuery)) {
-                assertNotNull(rt.getDigestValue());
-                assertEquals(signatureConfig.getDigestMethodUri(), rt.getDigestMethod().getAlgorithm());
-            }
-
-            String certDigestXQuery = declareNS +
-                    "$this//xades:SigningCertificate/xades:Cert/xades:CertDigest";
-            XmlObject[] xoList = sigDoc.selectPath(certDigestXQuery);
-            assertEquals(xoList.length, 1);
-            DigestAlgAndValueType certDigest = (DigestAlgAndValueType) xoList[0];
-            assertNotNull(certDigest.getDigestValue());
-
-            String qualPropXQuery = declareNS +
-                    "$this/ds:Signature/ds:Object/xades:QualifyingProperties";
-            xoList = sigDoc.selectPath(qualPropXQuery);
-            assertEquals(xoList.length, 1);
-            QualifyingPropertiesType qualProp = (QualifyingPropertiesType) xoList[0];
-            boolean qualPropXsdOk = qualProp.validate();
-            assertTrue(qualPropXsdOk);
-
-            pkg.save(bos);
-        }
-
-        try (OPCPackage pkg = OPCPackage.open(new ByteArrayInputStream(bos.toByteArray()))) {
-            SignatureConfig signatureConfig = new SignatureConfig();
-            signatureConfig.setUpdateConfigOnValidate(true);
-
-            SignatureInfo si = new SignatureInfo();
-            si.setOpcPackage(pkg);
-            si.setSignatureConfig(signatureConfig);
-
-            assertTrue(si.verifySignature());
-
-            assertEquals(HashAlgorithm.sha512, signatureConfig.getXadesDigestAlgo());
-            assertEquals("Xades Reviewer", signatureConfig.getXadesRole());
-            assertEquals("test xades signature", signatureConfig.getSignatureDescription());
-            assertEquals(execTimestr, signatureConfig.formatExecutionTime());
-        }
-    }
-
-    public static String getAccessError(String destinationUrl, boolean fireRequest, int timeout) {
-        URL url;
-        try {
-            url = new URL(destinationUrl);
-        } catch (MalformedURLException e) {
-            throw new IllegalArgumentException("Invalid destination URL", e);
-        }
-
-        HttpURLConnection conn = null;
-        try {
-            conn = (HttpURLConnection) url.openConnection();
-
-            // set specified timeout if non-zero
-            if(timeout != 0) {
-                conn.setConnectTimeout(timeout);
-                conn.setReadTimeout(timeout);
-            }
-
-            conn.setDoOutput(false);
-            conn.setDoInput(true);
-
-            /* if connecting is not possible this will throw a connection refused exception */
-            conn.connect();
-
-            if (fireRequest) {
-                conn.getInputStream().close();
-            }
-            /* if connecting is possible we return true here */
-            return null;
-
-        } catch (IOException e) {
-            /* exception is thrown -> server not available */
-            return e.getClass().getName() + ": " + e.getMessage();
-        } finally {
-            if (conn != null) {
-                conn.disconnect();
-            }
-        }
-    }
-
-    @Test
-    public void testCertChain() throws Exception {
-        KeyStore keystore = KeyStore.getInstance("PKCS12");
-        String password = "test";
-        try (InputStream is = testdata.openResourceAsStream("chaintest.pfx")) {
-            keystore.load(is, password.toCharArray());
-        }
-
-        Key key = keystore.getKey("poitest", password.toCharArray());
-        Certificate[] chainList = keystore.getCertificateChain("poitest");
-        List<X509Certificate> certChain = new ArrayList<>();
-        for (Certificate c : chainList) {
-            certChain.add((X509Certificate)c);
-        }
-        x509 = certChain.get(0);
-        keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key);
-
-        String testFile = "hello-world-unsigned.xlsx";
-        try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
-
-            SignatureConfig signatureConfig = new SignatureConfig();
-            signatureConfig.setKey(keyPair.getPrivate());
-            signatureConfig.setSigningCertificateChain(certChain);
-            Calendar oldCal = LocaleUtil.getLocaleCalendar(2007, 7, 1);
-            signatureConfig.setExecutionTime(oldCal.getTime());
-            signatureConfig.setDigestAlgo(HashAlgorithm.sha1);
-
-            SignatureInfo si = new SignatureInfo();
-            si.setOpcPackage(pkg);
-            si.setSignatureConfig(signatureConfig);
-
-            si.confirmSignature();
-
-            for (SignaturePart sp : si.getSignatureParts()) {
-                assertTrue("Could not validate", sp.validate());
-                X509Certificate signer = sp.getSigner();
-                assertNotNull("signer undefined?!", signer);
-                List<X509Certificate> certChainRes = sp.getCertChain();
-                assertEquals(3, certChainRes.size());
-            }
-
-        }
-    }
-
-    @Test
-    public void testNonSha1() throws Exception {
-        String testFile = "hello-world-unsigned.xlsx";
-        initKeyPair();
-
-        SignatureConfig signatureConfig = new SignatureConfig();
-        signatureConfig.setKey(keyPair.getPrivate());
-        signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
-
-        HashAlgorithm[] testAlgo = {HashAlgorithm.sha224, HashAlgorithm.sha256
-                , HashAlgorithm.sha384, HashAlgorithm.sha512, HashAlgorithm.ripemd160};
-
-        for (HashAlgorithm ha : testAlgo) {
-            signatureConfig.setDigestAlgo(ha);
-            try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
-                SignatureInfo si = new SignatureInfo();
-                si.setOpcPackage(pkg);
-                si.setSignatureConfig(signatureConfig);
-
-                si.confirmSignature();
-                boolean b = si.verifySignature();
-                assertTrue("Signature not correctly calculated for " + ha, b);
-            } catch (EncryptedDocumentException e) {
-                Assume.assumeTrue(e.getMessage().startsWith("Export Restrictions"));
-            }
-        }
-    }
-
-    @Test
-    public void bug58630() throws Exception {
-        // test deletion of sheet 0 and signing
-        File tpl = copy(testdata.getFile("bug58630.xlsx"));
-        try (SXSSFWorkbook wb1 = new SXSSFWorkbook((XSSFWorkbook)WorkbookFactory.create(tpl), 10)) {
-            wb1.setCompressTempFiles(true);
-            wb1.removeSheetAt(0);
-            ByteArrayOutputStream os = new ByteArrayOutputStream();
-            wb1.write(os);
-
-            try (OPCPackage pkg = OPCPackage.open(new ByteArrayInputStream(os.toByteArray()))) {
-                initKeyPair();
-                SignatureConfig signatureConfig = new SignatureConfig();
-                signatureConfig.setKey(keyPair.getPrivate());
-                signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
-
-                SignatureInfo si = new SignatureInfo();
-                si.setOpcPackage(pkg);
-                si.setSignatureConfig(signatureConfig);
-                si.confirmSignature();
-                assertTrue("invalid signature", si.verifySignature());
-            }
-        }
-    }
-
-    @Test
-    public void testMultiSign() throws Exception {
-        cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
-        cal.clear();
-        cal.setTimeZone(LocaleUtil.TIMEZONE_UTC);
-        cal.set(2018, Calendar.DECEMBER, 14);
-
-        // test signing with separate opened packages
-        File tpl = copy(testdata.getFile("hello-world-unsigned.xlsx"));
-        try (OPCPackage pkg = OPCPackage.open(tpl)) {
-            signPkg63011(pkg, "bug63011_key1.pem", true);
-        }
-
-        try (OPCPackage pkg = OPCPackage.open(tpl)) {
-            signPkg63011(pkg, "bug63011_key2.pem", true);
-        }
-
-        verifyPkg63011(tpl, true);
-
-        // test signing with single opened package
-        tpl = copy(testdata.getFile("hello-world-unsigned.xlsx"));
-        try (OPCPackage pkg = OPCPackage.open(tpl)) {
-            signPkg63011(pkg, "bug63011_key1.pem", true);
-            signPkg63011(pkg, "bug63011_key2.pem", true);
-        }
-
-        verifyPkg63011(tpl, true);
-
-        try (OPCPackage pkg = OPCPackage.open(tpl)) {
-            signPkg63011(pkg, "bug63011_key1.pem", true);
-            signPkg63011(pkg, "bug63011_key2.pem", false);
-        }
-
-        verifyPkg63011(tpl, false);
-    }
-
-    private void verifyPkg63011(File tpl, boolean multi) throws InvalidFormatException, IOException {
-        try (OPCPackage pkg = OPCPackage.open(tpl, PackageAccess.READ)) {
-            SignatureConfig sic = new SignatureConfig();
-            SignatureInfo si = new SignatureInfo();
-            si.setOpcPackage(pkg);
-            si.setSignatureConfig(sic);
-            List<X509Certificate> result = new ArrayList<>();
-            for (SignaturePart sp : si.getSignatureParts()) {
-                if (sp.validate()) {
-                    result.add(sp.getSigner());
-                }
-            }
-
-            assertNotNull(result);
-
-            if (multi) {
-                assertEquals(2, result.size());
-                assertEquals("CN=Muj Klic", result.get(0).getSubjectDN().toString());
-                assertEquals("CN=My Second key", result.get(1).getSubjectDN().toString());
-            } else {
-                assertEquals(1, result.size());
-                assertEquals("CN=My Second key", result.get(0).getSubjectDN().toString());
-            }
-
-            assertTrue(si.verifySignature());
-            pkg.revert();
-        }
-    }
-
-    private void signPkg63011(OPCPackage pkg, String pemFile, boolean multi)
-            throws IOException, CertificateException, XMLSignatureException, MarshalException {
-        assertNotNull(pkg);
-        initKeyFromPEM(testdata.getFile(pemFile));
-
-        SignatureConfig config = new SignatureConfig();
-        config.setKey(keyPair.getPrivate());
-        config.setSigningCertificateChain(Collections.singletonList(x509));
-        config.setExecutionTime(cal.getTime());
-        config.setAllowMultipleSignatures(multi);
-
-        SignatureInfo si = new SignatureInfo();
-        si.setOpcPackage(pkg);
-        si.setSignatureConfig(config);
-        si.confirmSignature();
-    }
-
-    @Test
-    public void testRetrieveCertificate() throws InvalidFormatException, IOException {
-        SignatureConfig sic = new SignatureConfig();
-        final File file = testdata.getFile("PPT2016withComment.pptx");
-        try (final OPCPackage pkg = OPCPackage.open(file, PackageAccess.READ)) {
-            sic.setUpdateConfigOnValidate(true);
-            SignatureInfo si = new SignatureInfo();
-            si.setOpcPackage(pkg);
-            si.setSignatureConfig(sic);
-            assertTrue(si.verifySignature());
-        }
-
-        final List<X509Certificate> certs = sic.getSigningCertificateChain();
-        assertEquals(1, certs.size());
-        assertEquals("CN=Test", certs.get(0).getSubjectDN().getName());
-        assertEquals("SuperDuper-Reviewer", sic.getXadesRole());
-        assertEquals("Purpose for signing", sic.getSignatureDescription());
-        assertEquals("2018-06-10T09:00:54Z", sic.formatExecutionTime());
-        assertEquals(CanonicalizationMethod.INCLUSIVE, sic.getCanonicalizationMethod());
-    }
-
-    private SignatureConfig prepareConfig(String pfxInput) throws Exception {
-        initKeyPair(pfxInput);
-
-        SignatureConfig signatureConfig = new SignatureConfig();
-        signatureConfig.setKey(keyPair.getPrivate());
-        signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
-        signatureConfig.setExecutionTime(cal.getTime());
-        signatureConfig.setDigestAlgo(HashAlgorithm.sha1);
-
-        return signatureConfig;
-    }
-
-    private void sign(OPCPackage pkgCopy) throws Exception {
-        int signerCount = 1;
-
-        SignatureConfig signatureConfig = prepareConfig(null);
-
-        SignatureInfo si = new SignatureInfo();
-        si.setOpcPackage(pkgCopy);
-        si.setSignatureConfig(signatureConfig);
-
-        final Document document = DocumentHelper.createDocument();
-        final DOMSignContext xmlSignContext = si.createXMLSignContext(document);
-
-        // operate
-        final DOMSignedInfo signedInfo = si.preSign(xmlSignContext);
-
-        // verify
-        assertNotNull(signedInfo);
-        assertEquals("Office OpenXML Document", signatureConfig.getSignatureDescription());
-
-        // setup: key material, signature value
-        final String signatureValue = si.signDigest(xmlSignContext, signedInfo);
-
-        // operate: postSign
-        si.postSign(xmlSignContext, signatureValue);
-
-        // verify: signature
-        si.setOpcPackage(pkgCopy);
-        List<X509Certificate> result = new ArrayList<>();
-        for (SignaturePart sp : si.getSignatureParts()) {
-            if (sp.validate()) {
-                result.add(sp.getSigner());
-            }
-        }
-        assertEquals(signerCount, result.size());
-    }
-
-    private void initKeyPair() throws Exception {
-        initKeyPair(null);
-    }
-
-    private void initKeyPair(String pfxInput) throws Exception {
-        final String alias = "Test";
-        final char[] password = "test".toCharArray();
-        File file = new File("build/test.pfx");
-
-        KeyStore keystore = KeyStore.getInstance("PKCS12");
-
-        if (pfxInput != null) {
-            try (InputStream fis = new ByteArrayInputStream(RawDataUtil.decompress(pfxInput))) {
-                keystore.load(fis, password);
-            }
-        } else if (file.exists()) {
-            try (InputStream fis = new FileInputStream(file)) {
-                keystore.load(fis, password);
-            }
-        } else {
-            keystore.load(null, password);
-        }
-
-        if (keystore.isKeyEntry(alias)) {
-            Key key = keystore.getKey(alias, password);
-            x509 = (X509Certificate)keystore.getCertificate(alias);
-            keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key);
-        } else {
-            keyPair = generateKeyPair();
-            Date notBefore = cal.getTime();
-            Calendar cal2 = (Calendar)cal.clone();
-            cal2.add(Calendar.YEAR, 1);
-            Date notAfter = cal2.getTime();
-            KeyUsage keyUsage = new KeyUsage(KeyUsage.digitalSignature);
-
-            x509 = generateCertificate(keyPair.getPublic(), notBefore, notAfter, keyPair.getPrivate(), keyUsage);
-
-            keystore.setKeyEntry(alias, keyPair.getPrivate(), password, new Certificate[]{x509});
-
-            if (pfxInput == null) {
-                try (FileOutputStream fos = new FileOutputStream(file)) {
-                    keystore.store(fos, password);
-                }
-            }
-        }
-    }
-
-    private void initKeyFromPEM(File pemFile) throws IOException, CertificateException {
-        // see https://stackoverflow.com/questions/11787571/how-to-read-pem-file-to-get-private-and-public-key
-        PrivateKey key = null;
-        x509 = null;
-
-        try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(pemFile), StandardCharsets.ISO_8859_1))) {
-            PEMParser parser = new PEMParser(br);
-            for (Object obj; (obj = parser.readObject()) != null; ) {
-                if (obj instanceof PrivateKeyInfo) {
-                    key = new JcaPEMKeyConverter().setProvider("BC").getPrivateKey((PrivateKeyInfo)obj);
-                } else if (obj instanceof X509CertificateHolder) {
-                    x509 = new JcaX509CertificateConverter().setProvider("BC").getCertificate((X509CertificateHolder)obj);
-                }
-            }
-        }
-
-        if (key != null && x509 != null) {
-            keyPair = new KeyPair(x509.getPublicKey(), key);
-        }
-    }
-
-    private static File copy(File input) throws IOException {
-        String extension = input.getName().replaceAll(".*?(\\.[^.]+)?$", "$1");
-        if (extension.isEmpty()) {
-            extension = ".zip";
-        }
-
-        // ensure that we create the "build" directory as it might not be existing
-        // in the Sonar Maven runs where we are at a different source directory
-        File buildDir = new File("build");
-        if(!buildDir.exists()) {
-            assertTrue("Failed to create " + buildDir.getAbsolutePath(), buildDir.mkdirs());
-        }
-        File tmpFile = new File(buildDir, "sigtest"+extension);
-
-        try (OutputStream fos = new FileOutputStream(tmpFile)) {
-            try (InputStream fis = new FileInputStream(input)) {
-                IOUtils.copy(fis, fos);
-            }
-        }
-
-        return tmpFile;
-    }
-
-    private static KeyPair generateKeyPair() throws Exception {
-        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
-        SecureRandom random = new SecureRandom();
-        keyPairGenerator.initialize(new RSAKeyGenParameterSpec(1024,
-                                                               RSAKeyGenParameterSpec.F4), random);
-        return keyPairGenerator.generateKeyPair();
-    }
-
-    private static X509Certificate generateCertificate(PublicKey subjectPublicKey,
-                                                       Date notBefore, Date notAfter,
-                                                       PrivateKey issuerPrivateKey,
-                                                       KeyUsage keyUsage)
-            throws IOException, OperatorCreationException, CertificateException {
-        final String signatureAlgorithm = "SHA1withRSA";
-        final String subjectDn = "CN=Test";
-        X500Name issuerName = new X500Name(subjectDn);
-
-        RSAPublicKey rsaPubKey = (RSAPublicKey)subjectPublicKey;
-        RSAKeyParameters rsaSpec = new RSAKeyParameters(false, rsaPubKey.getModulus(), rsaPubKey.getPublicExponent());
-
-        SubjectPublicKeyInfo subjectPublicKeyInfo =
-                SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(rsaSpec);
-
-        DigestCalculator digestCalc = new JcaDigestCalculatorProviderBuilder()
-                .setProvider("BC").build().get(CertificateID.HASH_SHA1);
-
-        X509v3CertificateBuilder certificateGenerator = new X509v3CertificateBuilder(
-                issuerName
-                , new BigInteger(128, new SecureRandom())
-                , notBefore
-                , notAfter
-                , new X500Name(subjectDn)
-                , subjectPublicKeyInfo
-        );
-
-        X509ExtensionUtils exUtils = new X509ExtensionUtils(digestCalc);
-        SubjectKeyIdentifier subKeyId = exUtils.createSubjectKeyIdentifier(subjectPublicKeyInfo);
-        AuthorityKeyIdentifier autKeyId = exUtils.createAuthorityKeyIdentifier(subjectPublicKeyInfo);
-
-        certificateGenerator.addExtension(Extension.subjectKeyIdentifier, false, subKeyId);
-        certificateGenerator.addExtension(Extension.authorityKeyIdentifier, false, autKeyId);
-
-        BasicConstraints bc = new BasicConstraints(0);
-        certificateGenerator.addExtension(Extension.basicConstraints, false, bc);
-
-        if (null != keyUsage) {
-            certificateGenerator.addExtension(Extension.keyUsage, true, keyUsage);
-        }
-
-        JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder(signatureAlgorithm);
-        signerBuilder.setProvider("BC");
-
-        X509CertificateHolder certHolder =
-                certificateGenerator.build(signerBuilder.build(issuerPrivateKey));
-
-        /*
-         * Next certificate factory trick is needed to make sure that the
-         * certificate delivered to the caller is provided by the default
-         * security provider instead of BouncyCastle. If we don't do this trick
-         * we might run into trouble when trying to use the CertPath validator.
-         */
-//        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
-//        certificate = (X509Certificate) certificateFactory
-//                .generateCertificate(new ByteArrayInputStream(certificate
-//                        .getEncoded()));
-        return new JcaX509CertificateConverter().getCertificate(certHolder);
-    }
-
-    private static X509CRL generateCrl(X509Certificate issuer, PrivateKey issuerPrivateKey)
-            throws CertificateEncodingException, IOException, CRLException, OperatorCreationException {
-
-        X509CertificateHolder holder = new X509CertificateHolder(issuer.getEncoded());
-        X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(holder.getIssuer(), new Date());
-        crlBuilder.setNextUpdate(new Date(new Date().getTime() + 100000));
-        JcaContentSignerBuilder contentBuilder = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC");
-
-        CRLNumber crlNumber = new CRLNumber(new BigInteger("1234"));
-
-        crlBuilder.addExtension(Extension.cRLNumber, false, crlNumber);
-        X509CRLHolder x509Crl = crlBuilder.build(contentBuilder.build(issuerPrivateKey));
-        return new JcaX509CRLConverter().setProvider("BC").getCRL(x509Crl);
-    }
-
-    private static OCSPResp createOcspResp(X509Certificate certificate,
-                                           X509Certificate issuerCertificate,
-                                           X509Certificate ocspResponderCertificate,
-                                           PrivateKey ocspResponderPrivateKey,
-                                           long nonceTimeinMillis)
-            throws Exception {
-        DigestCalculator digestCalc = new JcaDigestCalculatorProviderBuilder()
-                .setProvider("BC").build().get(CertificateID.HASH_SHA1);
-        X509CertificateHolder issuerHolder = new X509CertificateHolder(issuerCertificate.getEncoded());
-        CertificateID certId = new CertificateID(digestCalc, issuerHolder, certificate.getSerialNumber());
-
-        // request
-        //create a nonce to avoid replay attack
-        BigInteger nonce = BigInteger.valueOf(nonceTimeinMillis);
-        DEROctetString nonceDer = new DEROctetString(nonce.toByteArray());
-        Extension ext = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, true, nonceDer);
-        Extensions exts = new Extensions(ext);
-
-        OCSPReqBuilder ocspReqBuilder = new OCSPReqBuilder();
-        ocspReqBuilder.addRequest(certId);
-        ocspReqBuilder.setRequestExtensions(exts);
-        OCSPReq ocspReq = ocspReqBuilder.build();
-
-
-        SubjectPublicKeyInfo keyInfo = new SubjectPublicKeyInfo
-                (CertificateID.HASH_SHA1, ocspResponderCertificate.getPublicKey().getEncoded());
-
-        BasicOCSPRespBuilder basicOCSPRespBuilder = new BasicOCSPRespBuilder(keyInfo, digestCalc);
-        basicOCSPRespBuilder.setResponseExtensions(exts);
-
-        // request processing
-        Req[] requestList = ocspReq.getRequestList();
-        for (Req ocspRequest : requestList) {
-            CertificateID certificateID = ocspRequest.getCertID();
-            CertificateStatus certificateStatus = CertificateStatus.GOOD;
-            basicOCSPRespBuilder.addResponse(certificateID, certificateStatus);
-        }
-
-        // basic response generation
-        X509CertificateHolder[] chain = null;
-        if (!ocspResponderCertificate.equals(issuerCertificate)) {
-            // TODO: HorribleProxy can't convert array input params yet
-            chain = new X509CertificateHolder[] {
-                    new X509CertificateHolder(ocspResponderCertificate.getEncoded()),
-                    issuerHolder
-            };
-        }
-
-        ContentSigner contentSigner = new JcaContentSignerBuilder("SHA1withRSA")
-                .setProvider("BC").build(ocspResponderPrivateKey);
-        BasicOCSPResp basicOCSPResp = basicOCSPRespBuilder.build(contentSigner, chain, new Date(nonceTimeinMillis));
-
-
-        OCSPRespBuilder ocspRespBuilder = new OCSPRespBuilder();
-
-        return ocspRespBuilder.build(OCSPRespBuilder.SUCCESSFUL, basicOCSPResp);
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/dsig/TestSignatureInfo.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/dsig/TestSignatureInfo.java
new file mode 100644 (file)
index 0000000..a4e977c
--- /dev/null
@@ -0,0 +1,1137 @@
+/* ====================================================================
+   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.
+==================================================================== */
+
+/* ====================================================================
+   This product contains an ASLv2 licensed version of the OOXML signer
+   package from the eID Applet project
+   http://code.google.com/p/eid-applet/source/browse/trunk/README.txt
+   Copyright (C) 2008-2014 FedICT.
+   ================================================================= */
+package org.apache.poi.poifs.crypt.dsig;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.net.ConnectException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.RSAKeyGenParameterSpec;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.crypto.MarshalException;
+import javax.xml.crypto.dsig.CanonicalizationMethod;
+import javax.xml.crypto.dsig.XMLSignatureException;
+import javax.xml.crypto.dsig.dom.DOMSignContext;
+
+import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.ooxml.util.DocumentHelper;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackageAccess;
+import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.poifs.crypt.dsig.facets.EnvelopedSignatureFacet;
+import org.apache.poi.poifs.crypt.dsig.facets.KeyInfoSignatureFacet;
+import org.apache.poi.poifs.crypt.dsig.facets.OOXMLSignatureFacet;
+import org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet;
+import org.apache.poi.poifs.crypt.dsig.facets.XAdESXLSignatureFacet;
+import org.apache.poi.poifs.crypt.dsig.services.RevocationData;
+import org.apache.poi.poifs.crypt.dsig.services.RevocationDataService;
+import org.apache.poi.poifs.crypt.dsig.services.TimeStampService;
+import org.apache.poi.poifs.crypt.dsig.services.TimeStampServiceValidator;
+import org.apache.poi.poifs.storage.RawDataUtil;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.xmlbeans.SystemProperties;
+import org.apache.xmlbeans.XmlObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.CRLNumber;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.Extensions;
+import org.bouncycastle.asn1.x509.KeyUsage;
+import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.cert.X509CRLHolder;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.X509ExtensionUtils;
+import org.bouncycastle.cert.X509v2CRLBuilder;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CRLConverter;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.ocsp.BasicOCSPResp;
+import org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder;
+import org.bouncycastle.cert.ocsp.CertificateID;
+import org.bouncycastle.cert.ocsp.CertificateStatus;
+import org.bouncycastle.cert.ocsp.OCSPReq;
+import org.bouncycastle.cert.ocsp.OCSPReqBuilder;
+import org.bouncycastle.cert.ocsp.OCSPResp;
+import org.bouncycastle.cert.ocsp.OCSPRespBuilder;
+import org.bouncycastle.cert.ocsp.Req;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.DigestCalculator;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.etsi.uri.x01903.v13.DigestAlgAndValueType;
+import org.etsi.uri.x01903.v13.QualifyingPropertiesType;
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.w3.x2000.x09.xmldsig.ReferenceType;
+import org.w3.x2000.x09.xmldsig.SignatureDocument;
+import org.w3c.dom.Document;
+
+public class TestSignatureInfo {
+    private static final POILogger LOG = POILogFactory.getLogger(TestSignatureInfo.class);
+    private static final POIDataSamples testdata = POIDataSamples.getXmlDSignInstance();
+
+    private static Calendar cal;
+    private KeyPair keyPair;
+    private X509Certificate x509;
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @AfterClass
+    public static void removeUserLocale() {
+        LocaleUtil.resetUserLocale();
+    }
+
+    @BeforeClass
+    public static void initBouncy() {
+        CryptoFunctions.registerBouncyCastle();
+
+        // Set cal to now ... only set to fixed date for debugging ...
+        LocaleUtil.resetUserLocale();
+        LocaleUtil.resetUserTimeZone();
+
+        cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
+        assertNotNull(cal);
+
+        // don't run this test when we are using older Xerces as it triggers an XML Parser backwards compatibility issue
+        // in the xmlsec jar file
+        String additionalJar = System.getProperty("additionaljar");
+        //System.out.println("Having: " + additionalJar);
+        Assume.assumeTrue("Not running TestSignatureInfo because we are testing with additionaljar set to " + additionalJar,
+                          additionalJar == null || additionalJar.trim().length() == 0);
+
+        System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true");
+
+        // Set line.separator for bug61182
+        // System.setProperty("line.separator", "\n");
+    }
+
+    @Ignore("This test is very sensitive, it breaks with every little change to the produced XML")
+    @Test
+    public void bug61182() throws Exception {
+        final String pfxInput =
+                "H4sIAAAAAAAAAFXTfzzTeRwH8P2uGRmG6hKSmJh9a2HsuPy60VnHCEU6v86sieZH2Jr2qFl+s+ZHJ5tfUcfKb4uho/OjiFq1qTv5ceFyp0PqEK"+
+                        "fH4+66++Pz+Dwer9fj8f7r9cRzEd4QMBTPRWxDIM14ZN47NfAWsJgL34Bx4at4Lvwdngvd9b8KqgbjQpGbMXzzgRGovytVFTBEzIXU47kQCd4U"+
+                        "ofJPvHl8JwyTjRS55hbKoor3UJLDE1i/PcPKCBAIDATjQlKiK67XjVYdcnkZgD2txroiAUb8W9dtn57DvTsbM+3wIsdocXDEN7TdPKgaSl+tU1"+
+                        "xq9oqiB5yMaZCPho8uUEbFU9U6u3N7lEMLTJGeA0RfX+5FMRrpXPFrbrlJ8uNUCE2H247P28Ckyfqlsy32yeKg/HTbH5JpqUDNw2B32+SaiRw7"+
+                        "ofRMePUpaAoK7KYgmd5ZIc0rLLYjJBfOWCb28xlrGhbpJvdToFdqt5PXVjEz5YOJ6g7W0fskuKW9/iZP0yLEVpR9XkkHmb6tfpcE8YwCdWNCan"+
+                        "LvAsco25JdF1j2/FLAMVU79HdOex07main90dy40511OZtTGZ+TdVd3lKZ7D3clEg9hLESHwSNnZ6239X4yLM4xYSElQ/hqSbwdmiozYG9PhF2"+
+                        "Zf0XaZnxzTK0Iot+rJ3kYoxWTLE8DR9leV62Ywbtlg4mapYOxb3lT7fQ1x4EQ44flh2oFWSPLR8LMbsc6jzJsV6OZ3TrODjHEdw9W+8OD32vd8"+
+                        "XQ6iCaIHcrSOn6qS0TKLr786234eeSAhvAQbEsVn7vrvc/487Be/O2e/+5Y5zRq2zAtz6pfcNyraJNDqMW1inNkgJ3t3VESbZ3pNzyl3KHILs0"+
+                        "51dY6msDYSlWhw40TglXxj9rw95O6gFWIuN012W/vhS50jpKXcao4gc1aLaXtJXxirbRkpZ/0e7a0pD6TDa7+GxEdEEML3VGo9udD5YUKhU3y7"+
+                        "SzWAgN6WIEIglq7LilvCjqIVLIfg8CvVGL9f5iSsCDf5hef4vMxbyvcjINuy06gZu+iPYOWNxjfrwKGYzoqqotK2aywgYVrPMh0JovfkDuN95n"+
+                        "MdVlYHbN1Mnn4TxAwuv+u3AkBlDZvRUUCwoDMUGxeMNPhTaAgWl60xhhBgCBaEMgAACReMAav7n3x598IDYJ9GxGXRAwaPOT/kfO/1AgPqLQkp"+
+                        "MiIVaHthnUS4v2y32e2BjdMPyIImUTBW3cV3R5tjVQm0MOm+D2C5+bBW9vHLjLR4lun4toQiY3Ls/v4bES/OJ4EmpZk5xhL9i5ClofYZNEsxFn"+
+                        "An/q821Tg+Cq9Er4XYGQe8ogjjLJ2b7dUsJ3auFQFNUJF7Ke7yUL2EeYYxl6vz5l4q5u8704mRbFts1E1eWMp6WIy91GPrsVlRGvtuNERfrjfE"+
+                        "YtzUI3Flcv65zJUbUBEzUnTS0fEYso2XyToAl8kb251mUY2o2lJzv5dp/1htmcjeeP2MjxC+3S45ljx7jd52Pv9XAat+ryiauFOF7YgztkoWWD"+
+                        "h62tplPH1bzDV+d0NLdaE5AfVJ09HuUYTFS+iggtvT5Euyk+unj4N2XvzW91n+GNjtgWfKOHmkinUPvYRh70Jv+wlPJrVaT8mL7GxJLqDC9jbv"+
+                        "Gznoiae6es+wQejnk3XjU366MrK/zXxngBYj9J6NnXc9mMiTFLX8WqQ8iTelTAFs2NJzPoDzrBUz4JFIEOa6Dja6dULc68g1jFDTeEHZyra7RZ"+
+                        "2ElqGDEqcNRo3SNX6feMy9EF1GOyZK0Sa87KwjKw8aM68dpsIYjfLcTXaZ6atg0BKfMnl6axeUGEaIFSP7rzj9wjzumRbG3jgUVp2lX5AK/tsO"+
+                        "7R4TQX/9/H6RiN34c9KldmPZZGANXzzTajZS9mR2OSvlJ+F4AgSko4htrMAKFTBu51/5SWNsO1vlRaaG48ZRJ+8PzuHQMdvS36gNpRPi7jhF1S"+
+                        "H3B2ycI4y0VURv6SrqJNUY/X645ZFJQ+eBO+ptG7o8axf1dcqh2beiQk+GRTeZ37LVeUlaeo9vl1/+8tyBfyT2v5lFC5E19WdKIyCuZe7r99Px"+
+                        "D/Od4Qj0TA92+DQnbCQTCMy/wwse9O4gsEebkkpPIP5GBV3Q0YBsj75XE0uSFQ1tCZSW8bNa9MUJZ/nPBfExohHlgGAAA=";
+
+        // Unix
+        final String unixSignExp =
+                "QkqTFQZjXagjRAoOWKpAGa8AR0rKqkSfBtfSWqtjBmTgyjarn+t2POHkpySIpheHAbg+90GKSH88ACMtPHbG7q" +
+                        "FL4gtgAD9Kjew6j16j0IRBwy145UlPrSLFMfF7YF7UlU1k1LBkIlRJ6Fv4MAJl6XspuzZOZIUmHZrWrdxycUQ=";
+
+        // Windows
+        final String winSignExp =
+                "GmAlL7+bT1r3FsMHJOp3pKg8betblYieZTjhMIrPZPRBbSzjO7KsYRGNtr0aOE3qr8xzyYJN6/8QdF5X7pUEUc" +
+                        "2m8ctrm7s5o2vZTkAqk9ENJGDjBPXX7TnuVOiVeL1cJdtjHC2QpjtRwkFR+B54G6b1OXLOFuQpP3vqR3+/XXE=";
+
+        // Mac
+        final String macSignExp =
+                "NZedY/LNTYU4nAUEUhIOg5+fKdgVtzRXKmdD3v+47E7Mb84oeiUGv9cCEE91DU3StF/JFIhjOJqavOzKnCsNcz" +
+                        "NJ4j/inggUl1OJUsicqIGQnA7E8vzWnN1kf5lINgJLv+0PyrrX9sQZbItzxUpgqyOFYcD0trid+31nRt4wtaA=";
+
+
+
+        Calendar cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
+        cal.clear();
+        cal.setTimeZone(LocaleUtil.TIMEZONE_UTC);
+        cal.set(2017, Calendar.JULY, 1);
+
+        SignatureConfig signatureConfig = prepareConfig(pfxInput);
+        signatureConfig.setExecutionTime(cal.getTime());
+
+        SignatureInfo si = new SignatureInfo();
+        si.setSignatureConfig(signatureConfig);
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream(100000);
+        try (XSSFWorkbook wb1 = new XSSFWorkbook()) {
+            wb1.createSheet().createRow(1).createCell(1).setCellValue("Test");
+            wb1.write(bos);
+        }
+
+        try (OPCPackage pkg1 = OPCPackage.open(new ByteArrayInputStream(bos.toByteArray()))) {
+            si.setOpcPackage(pkg1);
+            si.confirmSignature();
+            assertTrue(si.verifySignature());
+            bos.reset();
+            pkg1.save(bos);
+        }
+
+        try (XSSFWorkbook wb2 = new XSSFWorkbook(new ByteArrayInputStream(bos.toByteArray()))) {
+            assertEquals("Test", wb2.getSheetAt(0).getRow(1).getCell(1).getStringCellValue());
+            OPCPackage pkg2 = wb2.getPackage();
+            si.setOpcPackage(pkg2);
+            assertTrue(si.verifySignature());
+
+            // xmlbeans adds line-breaks depending on the system setting, so we get different
+            // test results on Unix/Mac/Windows
+            // if the xml documents eventually change, this test needs to be run with the
+            // separator set to the various system configurations
+            String sep = SystemProperties.getProperty("line.separator");
+            String signExp;
+            assumeTrue("Hashes only known for Windows/Unix/Mac", sep == null || "\n".equals(sep) || "\r\n".equals(sep) || "\r".equals(sep));
+            signExp = (sep == null || "\n".equals(sep)) ? unixSignExp : ("\r\n".equals(sep)) ? winSignExp : macSignExp;
+
+            String signAct = si.getSignatureParts().iterator().next().
+                    getSignatureDocument().getSignature().getSignatureValue().getStringValue();
+            assertEquals(signExp, signAct);
+        }
+    }
+
+    @Test
+    public void office2007prettyPrintedRels() throws Exception {
+        try (OPCPackage pkg = OPCPackage.open(testdata.getFile("office2007prettyPrintedRels.docx"), PackageAccess.READ)) {
+            SignatureConfig sic = new SignatureConfig();
+            SignatureInfo si = new SignatureInfo();
+            si.setOpcPackage(pkg);
+            si.setSignatureConfig(sic);
+            boolean isValid = si.verifySignature();
+            assertTrue(isValid);
+        }
+    }
+
+    @Test
+    public void getSignerUnsigned() throws Exception {
+        String[] testFiles = {
+                "hello-world-unsigned.docx",
+                "hello-world-unsigned.pptx",
+                "hello-world-unsigned.xlsx",
+                "hello-world-office-2010-technical-preview-unsigned.docx"
+        };
+
+        for (String testFile : testFiles) {
+            List<X509Certificate> result = new ArrayList<>();
+            try (OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ)) {
+                SignatureConfig sic = new SignatureConfig();
+                SignatureInfo si = new SignatureInfo();
+                si.setOpcPackage(pkg);
+                si.setSignatureConfig(sic);
+                for (SignaturePart sp : si.getSignatureParts()) {
+                    if (sp.validate()) {
+                        result.add(sp.getSigner());
+                    }
+                }
+                pkg.revert();
+            }
+            assertNotNull(result);
+            assertTrue(result.isEmpty());
+        }
+    }
+
+    @Test
+    public void getSigner() throws Exception {
+        String[] testFiles = {
+                "hyperlink-example-signed.docx",
+                "hello-world-signed.docx",
+                "hello-world-signed.pptx",
+                "hello-world-signed.xlsx",
+                "hello-world-office-2010-technical-preview.docx",
+                "ms-office-2010-signed.docx",
+                "ms-office-2010-signed.pptx",
+                "ms-office-2010-signed.xlsx",
+                "Office2010-SP1-XAdES-X-L.docx",
+                "signed.docx"
+        };
+
+        for (String testFile : testFiles) {
+            try (OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ)) {
+                SignatureConfig sic = new SignatureConfig();
+                SignatureInfo si = new SignatureInfo();
+                si.setOpcPackage(pkg);
+                si.setSignatureConfig(sic);
+                List<X509Certificate> result = new ArrayList<>();
+                for (SignaturePart sp : si.getSignatureParts()) {
+                    if (sp.validate()) {
+                        result.add(sp.getSigner());
+                    }
+                }
+
+                assertNotNull(result);
+                assertEquals("test-file: " + testFile, 1, result.size());
+                X509Certificate signer = result.get(0);
+                LOG.log(POILogger.DEBUG, "signer: " + signer.getSubjectX500Principal());
+
+                boolean b = si.verifySignature();
+                assertTrue("test-file: " + testFile, b);
+                pkg.revert();
+            }
+        }
+    }
+
+    @Test
+    public void getMultiSigners() throws Exception {
+        String testFile = "hello-world-signed-twice.docx";
+        try (OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ)) {
+            SignatureConfig sic = new SignatureConfig();
+            SignatureInfo si = new SignatureInfo();
+            si.setOpcPackage(pkg);
+            si.setSignatureConfig(sic);
+            List<X509Certificate> result = new ArrayList<>();
+            for (SignaturePart sp : si.getSignatureParts()) {
+                if (sp.validate()) {
+                    result.add(sp.getSigner());
+                }
+            }
+
+            assertNotNull(result);
+            assertEquals("test-file: " + testFile, 2, result.size());
+            X509Certificate signer1 = result.get(0);
+            X509Certificate signer2 = result.get(1);
+            LOG.log(POILogger.DEBUG, "signer 1: " + signer1.getSubjectX500Principal());
+            LOG.log(POILogger.DEBUG, "signer 2: " + signer2.getSubjectX500Principal());
+
+            boolean b = si.verifySignature();
+            assertTrue("test-file: " + testFile, b);
+            pkg.revert();
+        }
+    }
+
+    @Test
+    public void testSignSpreadsheet() throws Exception {
+        String testFile = "hello-world-unsigned.xlsx";
+        try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
+            sign(pkg);
+        }
+    }
+
+    private static class CommitableWorkbook extends XSSFWorkbook {
+        CommitableWorkbook(OPCPackage pkg) throws IOException {
+            super(pkg);
+        }
+        public void commit() throws IOException {
+            super.commit();
+        }
+    }
+
+    @Test
+    public void testManipulation() throws Exception {
+        // sign & validate
+        String testFile = "hello-world-unsigned.xlsx";
+        try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
+            sign(pkg);
+
+            // manipulate
+            try (CommitableWorkbook wb = new CommitableWorkbook(pkg)) {
+                wb.setSheetName(0, "manipulated");
+                // ... I don't know, why commit is protected ...
+                wb.commit();
+
+                // todo: test a manipulation on a package part, which is not signed
+                // ... maybe in combination with #56164
+
+                // validate
+                SignatureConfig sic = new SignatureConfig();
+                SignatureInfo si = new SignatureInfo();
+                si.setOpcPackage(pkg);
+                si.setSignatureConfig(sic);
+                boolean b = si.verifySignature();
+                assertFalse("signature should be broken", b);
+            }
+        }
+    }
+
+    @Test
+    public void testSignSpreadsheetWithSignatureInfo() throws Exception {
+        initKeyPair();
+        String testFile = "hello-world-unsigned.xlsx";
+        try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
+            SignatureConfig sic = new SignatureConfig();
+            sic.setKey(keyPair.getPrivate());
+            sic.setSigningCertificateChain(Collections.singletonList(x509));
+            SignatureInfo si = new SignatureInfo();
+            si.setOpcPackage(pkg);
+            si.setSignatureConfig(sic);
+            // hash > sha1 doesn't work in excel viewer ...
+            si.confirmSignature();
+            List<X509Certificate> result = new ArrayList<>();
+            for (SignaturePart sp : si.getSignatureParts()) {
+                if (sp.validate()) {
+                    result.add(sp.getSigner());
+                }
+            }
+            assertEquals(1, result.size());
+        }
+    }
+
+    @Test
+    public void testSignEnvelopingDocument() throws Exception {
+        String testFile = "hello-world-unsigned.xlsx";
+        File sigCopy = testdata.getFile(testFile);
+        ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
+
+        final String execTimestr;
+
+
+        try (OPCPackage pkg = OPCPackage.open(copy(sigCopy), PackageAccess.READ_WRITE)) {
+
+            initKeyPair();
+            final X509CRL crl = generateCrl(x509, keyPair.getPrivate());
+
+            // setup
+            SignatureConfig signatureConfig = new SignatureConfig();
+            signatureConfig.setKey(keyPair.getPrivate());
+
+            /*
+             * We need at least 2 certificates for the XAdES-C complete certificate
+             * refs construction.
+             */
+            List<X509Certificate> certificateChain = new ArrayList<>();
+            certificateChain.add(x509);
+            certificateChain.add(x509);
+            signatureConfig.setSigningCertificateChain(certificateChain);
+
+            signatureConfig.addSignatureFacet(new OOXMLSignatureFacet());
+            signatureConfig.addSignatureFacet(new EnvelopedSignatureFacet());
+            signatureConfig.addSignatureFacet(new KeyInfoSignatureFacet());
+            signatureConfig.addSignatureFacet(new XAdESSignatureFacet());
+            signatureConfig.addSignatureFacet(new XAdESXLSignatureFacet());
+
+            // check for internet, no error means it works
+            boolean mockTsp = (getAccessError("http://timestamp.comodoca.com/rfc3161", true, 10000) != null);
+
+            // http://timestamping.edelweb.fr/service/tsp
+            // http://tsa.belgium.be/connect
+            // http://timestamp.comodoca.com/authenticode
+            // http://timestamp.comodoca.com/rfc3161
+            // http://services.globaltrustfinder.com/adss/tsa
+            signatureConfig.setTspUrl("http://timestamp.comodoca.com/rfc3161");
+            signatureConfig.setTspRequestPolicy(null); // comodoca request fails, if default policy is set ...
+            signatureConfig.setTspOldProtocol(false);
+
+            signatureConfig.setXadesDigestAlgo(HashAlgorithm.sha512);
+            signatureConfig.setXadesRole("Xades Reviewer");
+            signatureConfig.setSignatureDescription("test xades signature");
+
+            execTimestr = signatureConfig.formatExecutionTime();
+
+            //set proxy info if any
+            String proxy = System.getProperty("http_proxy");
+            if (proxy != null && proxy.trim().length() > 0) {
+                signatureConfig.setProxyUrl(proxy);
+            }
+
+            if (mockTsp) {
+                TimeStampService tspService = (signatureInfo, data, revocationData) -> {
+                    revocationData.addCRL(crl);
+                    return "time-stamp-token".getBytes(LocaleUtil.CHARSET_1252);
+                };
+                signatureConfig.setTspService(tspService);
+            } else {
+                TimeStampServiceValidator tspValidator = (validateChain, revocationData) -> {
+                    for (X509Certificate certificate : validateChain) {
+                        LOG.log(POILogger.DEBUG, "certificate: " + certificate.getSubjectX500Principal());
+                        LOG.log(POILogger.DEBUG, "validity: " + certificate.getNotBefore() + " - " + certificate.getNotAfter());
+                    }
+                };
+                signatureConfig.setTspValidator(tspValidator);
+                signatureConfig.setTspOldProtocol(signatureConfig.getTspUrl().contains("edelweb"));
+            }
+
+            final RevocationData revocationData = new RevocationData();
+            revocationData.addCRL(crl);
+            OCSPResp ocspResp = createOcspResp(x509, x509, x509, keyPair.getPrivate(), cal.getTimeInMillis());
+            revocationData.addOCSP(ocspResp.getEncoded());
+
+            RevocationDataService revocationDataService = revocationChain -> revocationData;
+            signatureConfig.setRevocationDataService(revocationDataService);
+
+            // operate
+            SignatureInfo si = new SignatureInfo();
+            si.setOpcPackage(pkg);
+            si.setSignatureConfig(signatureConfig);
+            try {
+                si.confirmSignature();
+            } catch (RuntimeException e) {
+                // only allow a ConnectException because of timeout, we see this in Jenkins from time to time...
+                if (e.getCause() == null) {
+                    throw e;
+                }
+                if ((e.getCause() instanceof ConnectException) || (e.getCause() instanceof SocketTimeoutException)) {
+                    Assume.assumeFalse("Only allowing ConnectException with 'timed out' as message here, but had: " + e,
+                                       e.getCause().getMessage().contains("timed out"));
+                } else if (e.getCause() instanceof IOException) {
+                    Assume.assumeFalse("Only allowing IOException with 'Error contacting TSP server' as message here, but had: " + e,
+                                       e.getCause().getMessage().contains("Error contacting TSP server"));
+                } else if (e.getCause() instanceof RuntimeException) {
+                    Assume.assumeFalse("Only allowing RuntimeException with 'This site is cur' as message here, but had: " + e,
+                                       e.getCause().getMessage().contains("This site is cur"));
+                }
+                throw e;
+            }
+
+            // verify
+            Iterator<SignaturePart> spIter = si.getSignatureParts().iterator();
+            assertTrue("Had: " + pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN), spIter.hasNext());
+            SignaturePart sp = spIter.next();
+            boolean valid = sp.validate();
+            assertTrue(valid);
+
+            SignatureDocument sigDoc = sp.getSignatureDocument();
+            String declareNS =
+                    "declare namespace xades='http://uri.etsi.org/01903/v1.3.2#'; "
+                            + "declare namespace ds='http://www.w3.org/2000/09/xmldsig#'; ";
+
+            String digestValXQuery = declareNS +
+                    "$this/ds:Signature/ds:SignedInfo/ds:Reference";
+            for (ReferenceType rt : (ReferenceType[]) sigDoc.selectPath(digestValXQuery)) {
+                assertNotNull(rt.getDigestValue());
+                assertEquals(signatureConfig.getDigestMethodUri(), rt.getDigestMethod().getAlgorithm());
+            }
+
+            String certDigestXQuery = declareNS +
+                    "$this//xades:SigningCertificate/xades:Cert/xades:CertDigest";
+            XmlObject[] xoList = sigDoc.selectPath(certDigestXQuery);
+            assertEquals(xoList.length, 1);
+            DigestAlgAndValueType certDigest = (DigestAlgAndValueType) xoList[0];
+            assertNotNull(certDigest.getDigestValue());
+
+            String qualPropXQuery = declareNS +
+                    "$this/ds:Signature/ds:Object/xades:QualifyingProperties";
+            xoList = sigDoc.selectPath(qualPropXQuery);
+            assertEquals(xoList.length, 1);
+            QualifyingPropertiesType qualProp = (QualifyingPropertiesType) xoList[0];
+            boolean qualPropXsdOk = qualProp.validate();
+            assertTrue(qualPropXsdOk);
+
+            pkg.save(bos);
+        }
+
+        try (OPCPackage pkg = OPCPackage.open(new ByteArrayInputStream(bos.toByteArray()))) {
+            SignatureConfig signatureConfig = new SignatureConfig();
+            signatureConfig.setUpdateConfigOnValidate(true);
+
+            SignatureInfo si = new SignatureInfo();
+            si.setOpcPackage(pkg);
+            si.setSignatureConfig(signatureConfig);
+
+            assertTrue(si.verifySignature());
+
+            assertEquals(HashAlgorithm.sha512, signatureConfig.getXadesDigestAlgo());
+            assertEquals("Xades Reviewer", signatureConfig.getXadesRole());
+            assertEquals("test xades signature", signatureConfig.getSignatureDescription());
+            assertEquals(execTimestr, signatureConfig.formatExecutionTime());
+        }
+    }
+
+    public static String getAccessError(String destinationUrl, boolean fireRequest, int timeout) {
+        URL url;
+        try {
+            url = new URL(destinationUrl);
+        } catch (MalformedURLException e) {
+            throw new IllegalArgumentException("Invalid destination URL", e);
+        }
+
+        HttpURLConnection conn = null;
+        try {
+            conn = (HttpURLConnection) url.openConnection();
+
+            // set specified timeout if non-zero
+            if(timeout != 0) {
+                conn.setConnectTimeout(timeout);
+                conn.setReadTimeout(timeout);
+            }
+
+            conn.setDoOutput(false);
+            conn.setDoInput(true);
+
+            /* if connecting is not possible this will throw a connection refused exception */
+            conn.connect();
+
+            if (fireRequest) {
+                conn.getInputStream().close();
+            }
+            /* if connecting is possible we return true here */
+            return null;
+
+        } catch (IOException e) {
+            /* exception is thrown -> server not available */
+            return e.getClass().getName() + ": " + e.getMessage();
+        } finally {
+            if (conn != null) {
+                conn.disconnect();
+            }
+        }
+    }
+
+    @Test
+    public void testCertChain() throws Exception {
+        KeyStore keystore = KeyStore.getInstance("PKCS12");
+        String password = "test";
+        try (InputStream is = testdata.openResourceAsStream("chaintest.pfx")) {
+            keystore.load(is, password.toCharArray());
+        }
+
+        Key key = keystore.getKey("poitest", password.toCharArray());
+        Certificate[] chainList = keystore.getCertificateChain("poitest");
+        List<X509Certificate> certChain = new ArrayList<>();
+        for (Certificate c : chainList) {
+            certChain.add((X509Certificate)c);
+        }
+        x509 = certChain.get(0);
+        keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key);
+
+        String testFile = "hello-world-unsigned.xlsx";
+        try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
+
+            SignatureConfig signatureConfig = new SignatureConfig();
+            signatureConfig.setKey(keyPair.getPrivate());
+            signatureConfig.setSigningCertificateChain(certChain);
+            Calendar oldCal = LocaleUtil.getLocaleCalendar(2007, 7, 1);
+            signatureConfig.setExecutionTime(oldCal.getTime());
+            signatureConfig.setDigestAlgo(HashAlgorithm.sha1);
+
+            SignatureInfo si = new SignatureInfo();
+            si.setOpcPackage(pkg);
+            si.setSignatureConfig(signatureConfig);
+
+            si.confirmSignature();
+
+            for (SignaturePart sp : si.getSignatureParts()) {
+                assertTrue("Could not validate", sp.validate());
+                X509Certificate signer = sp.getSigner();
+                assertNotNull("signer undefined?!", signer);
+                List<X509Certificate> certChainRes = sp.getCertChain();
+                assertEquals(3, certChainRes.size());
+            }
+
+        }
+    }
+
+    @Test
+    public void testNonSha1() throws Exception {
+        String testFile = "hello-world-unsigned.xlsx";
+        initKeyPair();
+
+        SignatureConfig signatureConfig = new SignatureConfig();
+        signatureConfig.setKey(keyPair.getPrivate());
+        signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
+
+        HashAlgorithm[] testAlgo = {HashAlgorithm.sha224, HashAlgorithm.sha256
+                , HashAlgorithm.sha384, HashAlgorithm.sha512, HashAlgorithm.ripemd160};
+
+        for (HashAlgorithm ha : testAlgo) {
+            signatureConfig.setDigestAlgo(ha);
+            try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
+                SignatureInfo si = new SignatureInfo();
+                si.setOpcPackage(pkg);
+                si.setSignatureConfig(signatureConfig);
+
+                si.confirmSignature();
+                boolean b = si.verifySignature();
+                assertTrue("Signature not correctly calculated for " + ha, b);
+            } catch (EncryptedDocumentException e) {
+                Assume.assumeTrue(e.getMessage().startsWith("Export Restrictions"));
+            }
+        }
+    }
+
+    @Test
+    public void bug58630() throws Exception {
+        // test deletion of sheet 0 and signing
+        File tpl = copy(testdata.getFile("bug58630.xlsx"));
+        try (SXSSFWorkbook wb1 = new SXSSFWorkbook((XSSFWorkbook)WorkbookFactory.create(tpl), 10)) {
+            wb1.setCompressTempFiles(true);
+            wb1.removeSheetAt(0);
+            ByteArrayOutputStream os = new ByteArrayOutputStream();
+            wb1.write(os);
+
+            try (OPCPackage pkg = OPCPackage.open(new ByteArrayInputStream(os.toByteArray()))) {
+                initKeyPair();
+                SignatureConfig signatureConfig = new SignatureConfig();
+                signatureConfig.setKey(keyPair.getPrivate());
+                signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
+
+                SignatureInfo si = new SignatureInfo();
+                si.setOpcPackage(pkg);
+                si.setSignatureConfig(signatureConfig);
+                si.confirmSignature();
+                assertTrue("invalid signature", si.verifySignature());
+            }
+        }
+    }
+
+    @Test
+    public void testMultiSign() throws Exception {
+        cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
+        cal.clear();
+        cal.setTimeZone(LocaleUtil.TIMEZONE_UTC);
+        cal.set(2018, Calendar.DECEMBER, 14);
+
+        // test signing with separate opened packages
+        File tpl = copy(testdata.getFile("hello-world-unsigned.xlsx"));
+        try (OPCPackage pkg = OPCPackage.open(tpl)) {
+            signPkg63011(pkg, "bug63011_key1.pem", true);
+        }
+
+        try (OPCPackage pkg = OPCPackage.open(tpl)) {
+            signPkg63011(pkg, "bug63011_key2.pem", true);
+        }
+
+        verifyPkg63011(tpl, true);
+
+        // test signing with single opened package
+        tpl = copy(testdata.getFile("hello-world-unsigned.xlsx"));
+        try (OPCPackage pkg = OPCPackage.open(tpl)) {
+            signPkg63011(pkg, "bug63011_key1.pem", true);
+            signPkg63011(pkg, "bug63011_key2.pem", true);
+        }
+
+        verifyPkg63011(tpl, true);
+
+        try (OPCPackage pkg = OPCPackage.open(tpl)) {
+            signPkg63011(pkg, "bug63011_key1.pem", true);
+            signPkg63011(pkg, "bug63011_key2.pem", false);
+        }
+
+        verifyPkg63011(tpl, false);
+    }
+
+    private void verifyPkg63011(File tpl, boolean multi) throws InvalidFormatException, IOException {
+        try (OPCPackage pkg = OPCPackage.open(tpl, PackageAccess.READ)) {
+            SignatureConfig sic = new SignatureConfig();
+            SignatureInfo si = new SignatureInfo();
+            si.setOpcPackage(pkg);
+            si.setSignatureConfig(sic);
+            List<X509Certificate> result = new ArrayList<>();
+            for (SignaturePart sp : si.getSignatureParts()) {
+                if (sp.validate()) {
+                    result.add(sp.getSigner());
+                }
+            }
+
+            assertNotNull(result);
+
+            if (multi) {
+                assertEquals(2, result.size());
+                assertEquals("CN=Muj Klic", result.get(0).getSubjectDN().toString());
+                assertEquals("CN=My Second key", result.get(1).getSubjectDN().toString());
+            } else {
+                assertEquals(1, result.size());
+                assertEquals("CN=My Second key", result.get(0).getSubjectDN().toString());
+            }
+
+            assertTrue(si.verifySignature());
+            pkg.revert();
+        }
+    }
+
+    private void signPkg63011(OPCPackage pkg, String pemFile, boolean multi)
+            throws IOException, CertificateException, XMLSignatureException, MarshalException {
+        assertNotNull(pkg);
+        initKeyFromPEM(testdata.getFile(pemFile));
+
+        SignatureConfig config = new SignatureConfig();
+        config.setKey(keyPair.getPrivate());
+        config.setSigningCertificateChain(Collections.singletonList(x509));
+        config.setExecutionTime(cal.getTime());
+        config.setAllowMultipleSignatures(multi);
+
+        SignatureInfo si = new SignatureInfo();
+        si.setOpcPackage(pkg);
+        si.setSignatureConfig(config);
+        si.confirmSignature();
+    }
+
+    @Test
+    public void testRetrieveCertificate() throws InvalidFormatException, IOException {
+        SignatureConfig sic = new SignatureConfig();
+        final File file = testdata.getFile("PPT2016withComment.pptx");
+        try (final OPCPackage pkg = OPCPackage.open(file, PackageAccess.READ)) {
+            sic.setUpdateConfigOnValidate(true);
+            SignatureInfo si = new SignatureInfo();
+            si.setOpcPackage(pkg);
+            si.setSignatureConfig(sic);
+            assertTrue(si.verifySignature());
+        }
+
+        final List<X509Certificate> certs = sic.getSigningCertificateChain();
+        assertEquals(1, certs.size());
+        assertEquals("CN=Test", certs.get(0).getSubjectDN().getName());
+        assertEquals("SuperDuper-Reviewer", sic.getXadesRole());
+        assertEquals("Purpose for signing", sic.getSignatureDescription());
+        assertEquals("2018-06-10T09:00:54Z", sic.formatExecutionTime());
+        assertEquals(CanonicalizationMethod.INCLUSIVE, sic.getCanonicalizationMethod());
+    }
+
+    private SignatureConfig prepareConfig(String pfxInput) throws Exception {
+        initKeyPair(pfxInput);
+
+        SignatureConfig signatureConfig = new SignatureConfig();
+        signatureConfig.setKey(keyPair.getPrivate());
+        signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
+        signatureConfig.setExecutionTime(cal.getTime());
+        signatureConfig.setDigestAlgo(HashAlgorithm.sha1);
+
+        return signatureConfig;
+    }
+
+    private void sign(OPCPackage pkgCopy) throws Exception {
+        int signerCount = 1;
+
+        SignatureConfig signatureConfig = prepareConfig(null);
+
+        SignatureInfo si = new SignatureInfo();
+        si.setOpcPackage(pkgCopy);
+        si.setSignatureConfig(signatureConfig);
+
+        final Document document = DocumentHelper.createDocument();
+        final DOMSignContext xmlSignContext = si.createXMLSignContext(document);
+
+        // operate
+        final DOMSignedInfo signedInfo = si.preSign(xmlSignContext);
+
+        // verify
+        assertNotNull(signedInfo);
+        assertEquals("Office OpenXML Document", signatureConfig.getSignatureDescription());
+
+        // setup: key material, signature value
+        final String signatureValue = si.signDigest(xmlSignContext, signedInfo);
+
+        // operate: postSign
+        si.postSign(xmlSignContext, signatureValue);
+
+        // verify: signature
+        si.setOpcPackage(pkgCopy);
+        List<X509Certificate> result = new ArrayList<>();
+        for (SignaturePart sp : si.getSignatureParts()) {
+            if (sp.validate()) {
+                result.add(sp.getSigner());
+            }
+        }
+        assertEquals(signerCount, result.size());
+    }
+
+    private void initKeyPair() throws Exception {
+        initKeyPair(null);
+    }
+
+    private void initKeyPair(String pfxInput) throws Exception {
+        final String alias = "Test";
+        final char[] password = "test".toCharArray();
+        File file = new File("build/test.pfx");
+
+        KeyStore keystore = KeyStore.getInstance("PKCS12");
+
+        if (pfxInput != null) {
+            try (InputStream fis = new ByteArrayInputStream(RawDataUtil.decompress(pfxInput))) {
+                keystore.load(fis, password);
+            }
+        } else if (file.exists()) {
+            try (InputStream fis = new FileInputStream(file)) {
+                keystore.load(fis, password);
+            }
+        } else {
+            keystore.load(null, password);
+        }
+
+        if (keystore.isKeyEntry(alias)) {
+            Key key = keystore.getKey(alias, password);
+            x509 = (X509Certificate)keystore.getCertificate(alias);
+            keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key);
+        } else {
+            keyPair = generateKeyPair();
+            Date notBefore = cal.getTime();
+            Calendar cal2 = (Calendar)cal.clone();
+            cal2.add(Calendar.YEAR, 1);
+            Date notAfter = cal2.getTime();
+            KeyUsage keyUsage = new KeyUsage(KeyUsage.digitalSignature);
+
+            x509 = generateCertificate(keyPair.getPublic(), notBefore, notAfter, keyPair.getPrivate(), keyUsage);
+
+            keystore.setKeyEntry(alias, keyPair.getPrivate(), password, new Certificate[]{x509});
+
+            if (pfxInput == null) {
+                try (FileOutputStream fos = new FileOutputStream(file)) {
+                    keystore.store(fos, password);
+                }
+            }
+        }
+    }
+
+    private void initKeyFromPEM(File pemFile) throws IOException, CertificateException {
+        // see https://stackoverflow.com/questions/11787571/how-to-read-pem-file-to-get-private-and-public-key
+        PrivateKey key = null;
+        x509 = null;
+
+        try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(pemFile), StandardCharsets.ISO_8859_1))) {
+            PEMParser parser = new PEMParser(br);
+            for (Object obj; (obj = parser.readObject()) != null; ) {
+                if (obj instanceof PrivateKeyInfo) {
+                    key = new JcaPEMKeyConverter().setProvider("BC").getPrivateKey((PrivateKeyInfo)obj);
+                } else if (obj instanceof X509CertificateHolder) {
+                    x509 = new JcaX509CertificateConverter().setProvider("BC").getCertificate((X509CertificateHolder)obj);
+                }
+            }
+        }
+
+        if (key != null && x509 != null) {
+            keyPair = new KeyPair(x509.getPublicKey(), key);
+        }
+    }
+
+    private static File copy(File input) throws IOException {
+        String extension = input.getName().replaceAll(".*?(\\.[^.]+)?$", "$1");
+        if (extension.isEmpty()) {
+            extension = ".zip";
+        }
+
+        // ensure that we create the "build" directory as it might not be existing
+        // in the Sonar Maven runs where we are at a different source directory
+        File buildDir = new File("build");
+        if(!buildDir.exists()) {
+            assertTrue("Failed to create " + buildDir.getAbsolutePath(), buildDir.mkdirs());
+        }
+        File tmpFile = new File(buildDir, "sigtest"+extension);
+
+        try (OutputStream fos = new FileOutputStream(tmpFile)) {
+            try (InputStream fis = new FileInputStream(input)) {
+                IOUtils.copy(fis, fos);
+            }
+        }
+
+        return tmpFile;
+    }
+
+    private static KeyPair generateKeyPair() throws Exception {
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+        SecureRandom random = new SecureRandom();
+        keyPairGenerator.initialize(new RSAKeyGenParameterSpec(1024,
+                                                               RSAKeyGenParameterSpec.F4), random);
+        return keyPairGenerator.generateKeyPair();
+    }
+
+    private static X509Certificate generateCertificate(PublicKey subjectPublicKey,
+                                                       Date notBefore, Date notAfter,
+                                                       PrivateKey issuerPrivateKey,
+                                                       KeyUsage keyUsage)
+            throws IOException, OperatorCreationException, CertificateException {
+        final String signatureAlgorithm = "SHA1withRSA";
+        final String subjectDn = "CN=Test";
+        X500Name issuerName = new X500Name(subjectDn);
+
+        RSAPublicKey rsaPubKey = (RSAPublicKey)subjectPublicKey;
+        RSAKeyParameters rsaSpec = new RSAKeyParameters(false, rsaPubKey.getModulus(), rsaPubKey.getPublicExponent());
+
+        SubjectPublicKeyInfo subjectPublicKeyInfo =
+                SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(rsaSpec);
+
+        DigestCalculator digestCalc = new JcaDigestCalculatorProviderBuilder()
+                .setProvider("BC").build().get(CertificateID.HASH_SHA1);
+
+        X509v3CertificateBuilder certificateGenerator = new X509v3CertificateBuilder(
+                issuerName
+                , new BigInteger(128, new SecureRandom())
+                , notBefore
+                , notAfter
+                , new X500Name(subjectDn)
+                , subjectPublicKeyInfo
+        );
+
+        X509ExtensionUtils exUtils = new X509ExtensionUtils(digestCalc);
+        SubjectKeyIdentifier subKeyId = exUtils.createSubjectKeyIdentifier(subjectPublicKeyInfo);
+        AuthorityKeyIdentifier autKeyId = exUtils.createAuthorityKeyIdentifier(subjectPublicKeyInfo);
+
+        certificateGenerator.addExtension(Extension.subjectKeyIdentifier, false, subKeyId);
+        certificateGenerator.addExtension(Extension.authorityKeyIdentifier, false, autKeyId);
+
+        BasicConstraints bc = new BasicConstraints(0);
+        certificateGenerator.addExtension(Extension.basicConstraints, false, bc);
+
+        if (null != keyUsage) {
+            certificateGenerator.addExtension(Extension.keyUsage, true, keyUsage);
+        }
+
+        JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder(signatureAlgorithm);
+        signerBuilder.setProvider("BC");
+
+        X509CertificateHolder certHolder =
+                certificateGenerator.build(signerBuilder.build(issuerPrivateKey));
+
+        /*
+         * Next certificate factory trick is needed to make sure that the
+         * certificate delivered to the caller is provided by the default
+         * security provider instead of BouncyCastle. If we don't do this trick
+         * we might run into trouble when trying to use the CertPath validator.
+         */
+//        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
+//        certificate = (X509Certificate) certificateFactory
+//                .generateCertificate(new ByteArrayInputStream(certificate
+//                        .getEncoded()));
+        return new JcaX509CertificateConverter().getCertificate(certHolder);
+    }
+
+    private static X509CRL generateCrl(X509Certificate issuer, PrivateKey issuerPrivateKey)
+            throws CertificateEncodingException, IOException, CRLException, OperatorCreationException {
+
+        X509CertificateHolder holder = new X509CertificateHolder(issuer.getEncoded());
+        X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(holder.getIssuer(), new Date());
+        crlBuilder.setNextUpdate(new Date(new Date().getTime() + 100000));
+        JcaContentSignerBuilder contentBuilder = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC");
+
+        CRLNumber crlNumber = new CRLNumber(new BigInteger("1234"));
+
+        crlBuilder.addExtension(Extension.cRLNumber, false, crlNumber);
+        X509CRLHolder x509Crl = crlBuilder.build(contentBuilder.build(issuerPrivateKey));
+        return new JcaX509CRLConverter().setProvider("BC").getCRL(x509Crl);
+    }
+
+    private static OCSPResp createOcspResp(X509Certificate certificate,
+                                           X509Certificate issuerCertificate,
+                                           X509Certificate ocspResponderCertificate,
+                                           PrivateKey ocspResponderPrivateKey,
+                                           long nonceTimeinMillis)
+            throws Exception {
+        DigestCalculator digestCalc = new JcaDigestCalculatorProviderBuilder()
+                .setProvider("BC").build().get(CertificateID.HASH_SHA1);
+        X509CertificateHolder issuerHolder = new X509CertificateHolder(issuerCertificate.getEncoded());
+        CertificateID certId = new CertificateID(digestCalc, issuerHolder, certificate.getSerialNumber());
+
+        // request
+        //create a nonce to avoid replay attack
+        BigInteger nonce = BigInteger.valueOf(nonceTimeinMillis);
+        DEROctetString nonceDer = new DEROctetString(nonce.toByteArray());
+        Extension ext = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, true, nonceDer);
+        Extensions exts = new Extensions(ext);
+
+        OCSPReqBuilder ocspReqBuilder = new OCSPReqBuilder();
+        ocspReqBuilder.addRequest(certId);
+        ocspReqBuilder.setRequestExtensions(exts);
+        OCSPReq ocspReq = ocspReqBuilder.build();
+
+
+        SubjectPublicKeyInfo keyInfo = new SubjectPublicKeyInfo
+                (CertificateID.HASH_SHA1, ocspResponderCertificate.getPublicKey().getEncoded());
+
+        BasicOCSPRespBuilder basicOCSPRespBuilder = new BasicOCSPRespBuilder(keyInfo, digestCalc);
+        basicOCSPRespBuilder.setResponseExtensions(exts);
+
+        // request processing
+        Req[] requestList = ocspReq.getRequestList();
+        for (Req ocspRequest : requestList) {
+            CertificateID certificateID = ocspRequest.getCertID();
+            CertificateStatus certificateStatus = CertificateStatus.GOOD;
+            basicOCSPRespBuilder.addResponse(certificateID, certificateStatus);
+        }
+
+        // basic response generation
+        X509CertificateHolder[] chain = null;
+        if (!ocspResponderCertificate.equals(issuerCertificate)) {
+            // TODO: HorribleProxy can't convert array input params yet
+            chain = new X509CertificateHolder[] {
+                    new X509CertificateHolder(ocspResponderCertificate.getEncoded()),
+                    issuerHolder
+            };
+        }
+
+        ContentSigner contentSigner = new JcaContentSignerBuilder("SHA1withRSA")
+                .setProvider("BC").build(ocspResponderPrivateKey);
+        BasicOCSPResp basicOCSPResp = basicOCSPRespBuilder.build(contentSigner, chain, new Date(nonceTimeinMillis));
+
+
+        OCSPRespBuilder ocspRespBuilder = new OCSPRespBuilder();
+
+        return ocspRespBuilder.build(OCSPRespBuilder.SUCCESSFUL, basicOCSPResp);
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/AllPOIFSCryptoTests.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/AllPOIFSCryptoTests.java
new file mode 100644 (file)
index 0000000..1e3fb42
--- /dev/null
@@ -0,0 +1,35 @@
+/* ====================================================================
+   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.poifs.crypt.tests;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+
+/**
+ * Tests for org.apache.poi.poifs.crypt
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+      TestEncryptionInfo.class
+    , TestDecryptor.class
+    , TestEncryptor.class
+    , TestAgileEncryptionParameters.class
+})
+public final class AllPOIFSCryptoTests {
+}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestAgileEncryptionParameters.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestAgileEncryptionParameters.java
new file mode 100644 (file)
index 0000000..a892b9b
--- /dev/null
@@ -0,0 +1,116 @@
+/* ====================================================================
+   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.poifs.crypt.tests;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.crypto.Cipher;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.poifs.crypt.ChainingMode;
+import org.apache.poi.poifs.crypt.CipherAlgorithm;
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.EncryptionMode;
+import org.apache.poi.poifs.crypt.Encryptor;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.IOUtils;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TestAgileEncryptionParameters {
+
+    static byte[] testData;
+
+    @Parameter(value = 0)
+    public CipherAlgorithm ca;
+    @Parameter(value = 1)
+    public HashAlgorithm ha;
+    @Parameter(value = 2)
+    public ChainingMode cm;
+
+    @Parameters(name="{0} {1} {2}")
+    public static Collection<Object[]> data() {
+        CipherAlgorithm[] caList = {CipherAlgorithm.aes128, CipherAlgorithm.aes192, CipherAlgorithm.aes256, CipherAlgorithm.rc2, CipherAlgorithm.des, CipherAlgorithm.des3};
+        HashAlgorithm[] haList = {HashAlgorithm.sha1, HashAlgorithm.sha256, HashAlgorithm.sha384, HashAlgorithm.sha512, HashAlgorithm.md5};
+        ChainingMode[] cmList = {ChainingMode.cbc, ChainingMode.cfb};
+
+        List<Object[]> data = new ArrayList<>();
+        for (CipherAlgorithm ca : caList) {
+            for (HashAlgorithm ha : haList) {
+                for (ChainingMode cm : cmList) {
+                    data.add(new Object[]{ca,ha,cm});
+                }
+            }
+        }
+
+        return data;
+    }
+
+    @BeforeClass
+    public static void initTestData() throws Exception {
+        InputStream testFile = POIDataSamples.getDocumentInstance().openResourceAsStream("SampleDoc.docx");
+        testData = IOUtils.toByteArray(testFile);
+        testFile.close();
+    }
+
+    @Test
+    public void testAgileEncryptionModes() throws Exception {
+        int maxKeyLen = Cipher.getMaxAllowedKeyLength(ca.jceId);
+        Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files", maxKeyLen >= ca.defaultKeySize);
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+        POIFSFileSystem fsEnc = new POIFSFileSystem();
+        EncryptionInfo infoEnc = new EncryptionInfo(EncryptionMode.agile, ca, ha, -1, -1, cm);
+        Encryptor enc = infoEnc.getEncryptor();
+        enc.confirmPassword("foobaa");
+        OutputStream os = enc.getDataStream(fsEnc);
+        os.write(testData);
+        os.close();
+        bos.reset();
+        fsEnc.writeFilesystem(bos);
+        fsEnc.close();
+
+        POIFSFileSystem fsDec = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
+        EncryptionInfo infoDec = new EncryptionInfo(fsDec);
+        Decryptor dec = infoDec.getDecryptor();
+        boolean passed = dec.verifyPassword("foobaa");
+        assertTrue(passed);
+        InputStream is = dec.getDataStream(fsDec);
+        byte[] actualData = IOUtils.toByteArray(is);
+        is.close();
+        fsDec.close();
+        assertArrayEquals("Failed roundtrip - "+ca+"-"+ha+"-"+cm, testData, actualData);
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestDecryptor.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestDecryptor.java
new file mode 100644 (file)
index 0000000..7c06982
--- /dev/null
@@ -0,0 +1,183 @@
+/* ====================================================================
+   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.poifs.crypt.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.util.stream.IntStream;
+
+import javax.crypto.Cipher;
+
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.IOUtils;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class TestDecryptor {
+    private static final POIDataSamples samples = POIDataSamples.getPOIFSInstance();
+
+    @Test
+    public void passwordVerification() throws IOException, GeneralSecurityException {
+        try (InputStream is = samples.openResourceAsStream("protect.xlsx");
+            POIFSFileSystem fs = new POIFSFileSystem(is)) {
+            EncryptionInfo info = new EncryptionInfo(fs);
+            Decryptor d = Decryptor.getInstance(info);
+            assertTrue(d.verifyPassword(Decryptor.DEFAULT_PASSWORD));
+        }
+    }
+
+    @Test
+    public void decrypt() throws IOException, GeneralSecurityException {
+        try (InputStream is = samples.openResourceAsStream("protect.xlsx");
+             POIFSFileSystem fs = new POIFSFileSystem(is)) {
+            EncryptionInfo info = new EncryptionInfo(fs);
+            Decryptor d = Decryptor.getInstance(info);
+            d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
+            zipOk(fs.getRoot(), d);
+        }
+    }
+
+    @Test
+    public void agile() throws IOException, GeneralSecurityException {
+        try (InputStream is = samples.openResourceAsStream("protected_agile.docx");
+            POIFSFileSystem fs = new POIFSFileSystem(is)) {
+            EncryptionInfo info = new EncryptionInfo(fs);
+            assertTrue(info.getVersionMajor() == 4 && info.getVersionMinor() == 4);
+            Decryptor d = Decryptor.getInstance(info);
+            assertTrue(d.verifyPassword(Decryptor.DEFAULT_PASSWORD));
+            zipOk(fs.getRoot(), d);
+        }
+    }
+
+    private void zipOk(DirectoryNode root, Decryptor d) throws IOException, GeneralSecurityException {
+        try (ZipArchiveInputStream zin = new ZipArchiveInputStream(d.getDataStream(root))) {
+
+            while (true) {
+                ZipArchiveEntry entry = zin.getNextZipEntry();
+                if (entry == null) {
+                    break;
+                }
+                // crc32 is checked within zip-stream
+                if (entry.isDirectory()) {
+                    continue;
+                }
+                assertEquals(entry.getSize() - 1, zin.skip(entry.getSize() - 1));
+                byte[] buf = new byte[10];
+                int readBytes = zin.read(buf);
+                // zin.available() doesn't work for entries
+                assertEquals("size failed for " + entry.getName(), 1, readBytes);
+            }
+        }
+    }
+
+    @Test
+    public void dataLength() throws Exception {
+        try (InputStream fsIs = samples.openResourceAsStream("protected_agile.docx");
+            POIFSFileSystem fs = new POIFSFileSystem(fsIs)) {
+            EncryptionInfo info = new EncryptionInfo(fs);
+            Decryptor d = Decryptor.getInstance(info);
+            d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
+
+            try (InputStream is = d.getDataStream(fs)) {
+
+                long len = d.getLength();
+                assertEquals(12810, len);
+
+                byte[] buf = new byte[(int) len];
+                assertEquals(12810, is.read(buf));
+
+        ZipArchiveInputStream zin = new ZipArchiveInputStream(new ByteArrayInputStream(buf));
+
+        while (true) {
+            ZipArchiveEntry entry = zin.getNextZipEntry();
+            if (entry==null) {
+                break;
+            }
+
+                    IOUtils.toByteArray(zin);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void bug57080() throws Exception {
+        // the test file contains a wrong ole entry size, produced by extenxls
+        // the fix limits the available size and tries to read all entries
+        File f = samples.getFile("extenxls_pwd123.xlsx");
+
+        try (POIFSFileSystem fs = new POIFSFileSystem(f, true)) {
+            EncryptionInfo info = new EncryptionInfo(fs);
+            Decryptor d = Decryptor.getInstance(info);
+            d.verifyPassword("pwd123");
+
+            final ByteArrayOutputStream bos = new ByteArrayOutputStream(10000);
+            try (final ZipArchiveInputStream zis = new ZipArchiveInputStream(d.getDataStream(fs))) {
+                IntStream.of(3711, 1155, 445, 9376, 450, 588, 1337, 2593, 304, 7910).forEach(size -> {
+                    try {
+                        final ZipArchiveEntry ze = zis.getNextZipEntry();
+                        assertNotNull(ze);
+                        IOUtils.copy(zis, bos);
+                        assertEquals(size, bos.size());
+                        bos.reset();
+                    } catch (IOException e) {
+                        fail(e.getMessage());
+                    }
+                });
+            }
+        }
+    }
+
+    @Test
+    public void test58616() throws IOException, GeneralSecurityException {
+        try (InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("58616.xlsx");
+            POIFSFileSystem pfs = new POIFSFileSystem(is)) {
+            EncryptionInfo info = new EncryptionInfo(pfs);
+            Decryptor dec = Decryptor.getInstance(info);
+            dec.getDataStream(pfs).close();
+        }
+    }
+
+    @Test
+    public void bug60320() throws IOException, GeneralSecurityException {
+        int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
+        Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files for AES 256", maxKeyLen == 2147483647);
+
+        try (InputStream is = samples.openResourceAsStream("60320-protected.xlsx");
+            POIFSFileSystem fs = new POIFSFileSystem(is)) {
+            EncryptionInfo info = new EncryptionInfo(fs);
+            Decryptor d = Decryptor.getInstance(info);
+            assertTrue(d.verifyPassword("Test001!!"));
+            zipOk(fs.getRoot(), d);
+        }
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestEncryptionInfo.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestEncryptionInfo.java
new file mode 100644 (file)
index 0000000..bbdad4d
--- /dev/null
@@ -0,0 +1,70 @@
+/* ====================================================================
+   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.poifs.crypt.tests;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.poifs.crypt.CipherAlgorithm;
+import org.apache.poi.poifs.crypt.CipherProvider;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestEncryptionInfo {
+    @Test
+    public void testEncryptionInfo() throws IOException {
+        POIFSFileSystem fs = new POIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protect.xlsx"));
+
+        EncryptionInfo info = new EncryptionInfo(fs);
+
+        assertEquals(3, info.getVersionMajor());
+        assertEquals(2, info.getVersionMinor());
+
+        Assert.assertEquals(CipherAlgorithm.aes128, info.getHeader().getCipherAlgorithm());
+        Assert.assertEquals(HashAlgorithm.sha1, info.getHeader().getHashAlgorithm());
+        assertEquals(128, info.getHeader().getKeySize());
+        assertEquals(32, info.getVerifier().getEncryptedVerifierHash().length);
+        Assert.assertEquals(CipherProvider.aes, info.getHeader().getCipherProvider());
+        assertEquals("Microsoft Enhanced RSA and AES Cryptographic Provider", info.getHeader().getCspName());
+
+        fs.close();
+    }
+
+    @Test
+    public void testEncryptionInfoSHA512() throws Exception {
+        POIFSFileSystem fs = new POIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protected_sha512.xlsx"));
+
+        EncryptionInfo info = new EncryptionInfo(fs);
+
+        assertEquals(4, info.getVersionMajor());
+        assertEquals(4, info.getVersionMinor());
+
+        assertEquals(CipherAlgorithm.aes256, info.getHeader().getCipherAlgorithm());
+        assertEquals(HashAlgorithm.sha512, info.getHeader().getHashAlgorithm());
+        assertEquals(256, info.getHeader().getKeySize());
+        assertEquals(64, info.getVerifier().getEncryptedVerifierHash().length);
+        assertEquals(CipherProvider.aes, info.getHeader().getCipherProvider());
+//        assertEquals("Microsoft Enhanced RSA and AES Cryptographic Provider", info.getHeader().getCspName());
+
+        fs.close();
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestEncryptor.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestEncryptor.java
new file mode 100644 (file)
index 0000000..bcf60b9
--- /dev/null
@@ -0,0 +1,677 @@
+/* ====================================================================
+   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.poifs.crypt.tests;
+
+import static org.apache.poi.poifs.crypt.CryptoFunctions.getMessageDigest;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.DigestInputStream;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.util.Iterator;
+import java.util.Random;
+
+import javax.crypto.Cipher;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.openxml4j.opc.ContentTypes;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.poifs.crypt.CipherAlgorithm;
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.EncryptionMode;
+import org.apache.poi.poifs.crypt.EncryptionVerifier;
+import org.apache.poi.poifs.crypt.Encryptor;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.poifs.crypt.agile.AgileDecryptor;
+import org.apache.poi.poifs.crypt.agile.AgileEncryptionHeader;
+import org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.DocumentEntry;
+import org.apache.poi.poifs.filesystem.DocumentNode;
+import org.apache.poi.poifs.filesystem.Entry;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.poifs.filesystem.TempFilePOIFSFileSystem;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.NullOutputStream;
+import org.apache.poi.util.TempFile;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.junit.Assume;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class TestEncryptor {
+    @Test
+    public void binaryRC4Encryption() throws Exception {
+        // please contribute a real sample file, which is binary rc4 encrypted
+        // ... at least the output can be opened in Excel Viewer
+        String password = "pass";
+
+        final byte[] payloadExpected;
+        try (InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleMultiCell.xlsx")) {
+            payloadExpected = IOUtils.toByteArray(is);
+        }
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try (POIFSFileSystem fs = new POIFSFileSystem()) {
+            EncryptionInfo ei = new EncryptionInfo(EncryptionMode.binaryRC4);
+            Encryptor enc = ei.getEncryptor();
+            enc.confirmPassword(password);
+
+            try (OutputStream os = enc.getDataStream(fs.getRoot())) {
+                os.write(payloadExpected);
+            }
+
+            fs.writeFilesystem(bos);
+        }
+
+        final byte[] payloadActual;
+        try (POIFSFileSystem fs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()))) {
+            EncryptionInfo ei = new EncryptionInfo(fs);
+            Decryptor dec = ei.getDecryptor();
+            boolean b = dec.verifyPassword(password);
+            assertTrue(b);
+
+            try (InputStream is = dec.getDataStream(fs.getRoot())) {
+                payloadActual = IOUtils.toByteArray(is);
+            }
+        }
+
+        assertArrayEquals(payloadExpected, payloadActual);
+    }
+
+    @Test
+    public void tempFileAgileEncryption() throws Exception {
+        String password = "pass";
+
+        final byte[] payloadExpected;
+        try (InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleMultiCell.xlsx")) {
+            payloadExpected = IOUtils.toByteArray(is);
+        }
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try (POIFSFileSystem fs = new TempFilePOIFSFileSystem()) {
+            EncryptionInfo ei = new EncryptionInfo(EncryptionMode.agile);
+            Encryptor enc = ei.getEncryptor();
+            enc.confirmPassword(password);
+
+            try (OutputStream os = enc.getDataStream(fs.getRoot())) {
+                os.write(payloadExpected);
+            }
+
+            fs.writeFilesystem(bos);
+        }
+
+        final byte[] payloadActual;
+        try (POIFSFileSystem fs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()))) {
+            EncryptionInfo ei = new EncryptionInfo(fs);
+            Decryptor dec = ei.getDecryptor();
+            boolean b = dec.verifyPassword(password);
+            assertTrue(b);
+
+            try (InputStream is = dec.getDataStream(fs.getRoot())) {
+                payloadActual = IOUtils.toByteArray(is);
+            }
+        }
+
+        assertArrayEquals(payloadExpected, payloadActual);
+    }
+
+    @Test
+    public void agileEncryption() throws Exception {
+        int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
+        Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files for AES 256", maxKeyLen == 2147483647);
+
+        File file = POIDataSamples.getDocumentInstance().getFile("bug53475-password-is-pass.docx");
+        String pass = "pass";
+
+        final byte[] payloadExpected, encPackExpected;
+        final long decPackLenExpected;
+        final EncryptionInfo infoExpected;
+        final Decryptor decExpected;
+
+        try (POIFSFileSystem nfs = new POIFSFileSystem(file, true)) {
+
+            // Check the encryption details
+            infoExpected = new EncryptionInfo(nfs);
+            decExpected = Decryptor.getInstance(infoExpected);
+            boolean passed = decExpected.verifyPassword(pass);
+            assertTrue("Unable to process: document is encrypted", passed);
+
+            // extract the payload
+            try (InputStream is = decExpected.getDataStream(nfs)) {
+                payloadExpected = IOUtils.toByteArray(is);
+            }
+
+            decPackLenExpected = decExpected.getLength();
+            assertEquals(decPackLenExpected, payloadExpected.length);
+
+            final DirectoryNode root = nfs.getRoot();
+            final DocumentEntry entry = (DocumentEntry)root.getEntry(Decryptor.DEFAULT_POIFS_ENTRY);
+            try (InputStream is = root.createDocumentInputStream(entry)) {
+                // ignore padding block
+                encPackExpected = IOUtils.toByteArray(is, entry.getSize()-16);
+            }
+        }
+
+        // check that same verifier/salt lead to same hashes
+        final byte[] verifierSaltExpected = infoExpected.getVerifier().getSalt();
+        final byte[] verifierExpected = decExpected.getVerifier();
+        final byte[] keySalt = infoExpected.getHeader().getKeySalt();
+        final byte[] keySpec = decExpected.getSecretKey().getEncoded();
+        final byte[] integritySalt = decExpected.getIntegrityHmacKey();
+        // the hmacs of the file always differ, as we use PKCS5-padding to pad the bytes
+        // whereas office just uses random bytes
+        // byte integrityHash[] = d.getIntegrityHmacValue();
+
+        final EncryptionInfo infoActual = new EncryptionInfo(
+              EncryptionMode.agile
+            , infoExpected.getVerifier().getCipherAlgorithm()
+            , infoExpected.getVerifier().getHashAlgorithm()
+            , infoExpected.getHeader().getKeySize()
+            , infoExpected.getHeader().getBlockSize()
+            , infoExpected.getVerifier().getChainingMode()
+        );
+
+        Encryptor e = Encryptor.getInstance(infoActual);
+        e.confirmPassword(pass, keySpec, keySalt, verifierExpected, verifierSaltExpected, integritySalt);
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try (POIFSFileSystem fs = new POIFSFileSystem()) {
+            try (OutputStream os = e.getDataStream(fs)) {
+                os.write(payloadExpected);
+            }
+            fs.writeFilesystem(bos);
+        }
+
+        final EncryptionInfo infoActual2;
+        final byte[] payloadActual, encPackActual;
+        final long decPackLenActual;
+        try (POIFSFileSystem nfs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()))) {
+            infoActual2 = new EncryptionInfo(nfs.getRoot());
+            Decryptor decActual = Decryptor.getInstance(infoActual2);
+            boolean passed = decActual.verifyPassword(pass);
+            assertTrue("Unable to process: document is encrypted", passed);
+
+            // extract the payload
+            try (InputStream is = decActual.getDataStream(nfs)) {
+                payloadActual = IOUtils.toByteArray(is);
+            }
+
+            decPackLenActual = decActual.getLength();
+
+            final DirectoryNode root = nfs.getRoot();
+            final DocumentEntry entry = (DocumentEntry)root.getEntry(Decryptor.DEFAULT_POIFS_ENTRY);
+            try (InputStream is = root.createDocumentInputStream(entry)) {
+                // ignore padding block
+                encPackActual = IOUtils.toByteArray(is, entry.getSize()-16);
+            }
+        }
+
+        AgileEncryptionHeader aehExpected = (AgileEncryptionHeader)infoExpected.getHeader();
+        AgileEncryptionHeader aehActual = (AgileEncryptionHeader)infoActual.getHeader();
+        assertArrayEquals(aehExpected.getEncryptedHmacKey(), aehActual.getEncryptedHmacKey());
+        assertEquals(decPackLenExpected, decPackLenActual);
+        assertArrayEquals(payloadExpected, payloadActual);
+        assertArrayEquals(encPackExpected, encPackActual);
+    }
+
+    @Test
+    public void standardEncryption() throws Exception {
+        File file = POIDataSamples.getDocumentInstance().getFile("bug53475-password-is-solrcell.docx");
+        final String pass = "solrcell";
+
+        final byte[] payloadExpected;
+        final EncryptionInfo infoExpected;
+        final Decryptor d;
+        try (POIFSFileSystem nfs = new POIFSFileSystem(file, true)) {
+
+            // Check the encryption details
+            infoExpected = new EncryptionInfo(nfs);
+            d = Decryptor.getInstance(infoExpected);
+            boolean passed = d.verifyPassword(pass);
+            assertTrue("Unable to process: document is encrypted", passed);
+
+            // extract the payload
+            try (InputStream is = d.getDataStream(nfs)) {
+                payloadExpected = IOUtils.toByteArray(is);
+            }
+        }
+
+        // check that same verifier/salt lead to same hashes
+        final byte[] verifierSaltExpected = infoExpected.getVerifier().getSalt();
+        final byte[] verifierExpected = d.getVerifier();
+        final byte[] keySpec = d.getSecretKey().getEncoded();
+        final byte[] keySalt = infoExpected.getHeader().getKeySalt();
+
+
+        final EncryptionInfo infoActual = new EncryptionInfo(
+              EncryptionMode.standard
+            , infoExpected.getVerifier().getCipherAlgorithm()
+            , infoExpected.getVerifier().getHashAlgorithm()
+            , infoExpected.getHeader().getKeySize()
+            , infoExpected.getHeader().getBlockSize()
+            , infoExpected.getVerifier().getChainingMode()
+        );
+
+        final Encryptor e = Encryptor.getInstance(infoActual);
+        e.confirmPassword(pass, keySpec, keySalt, verifierExpected, verifierSaltExpected, null);
+
+        assertArrayEquals(infoExpected.getVerifier().getEncryptedVerifier(), infoActual.getVerifier().getEncryptedVerifier());
+        assertArrayEquals(infoExpected.getVerifier().getEncryptedVerifierHash(), infoActual.getVerifier().getEncryptedVerifierHash());
+
+        // now we use a newly generated salt/verifier and check
+        // if the file content is still the same
+
+        final byte[] encBytes;
+        try (POIFSFileSystem fs = new POIFSFileSystem()) {
+
+            final EncryptionInfo infoActual2 = new EncryptionInfo(
+                    EncryptionMode.standard
+                    , infoExpected.getVerifier().getCipherAlgorithm()
+                    , infoExpected.getVerifier().getHashAlgorithm()
+                    , infoExpected.getHeader().getKeySize()
+                    , infoExpected.getHeader().getBlockSize()
+                    , infoExpected.getVerifier().getChainingMode()
+            );
+
+            final Encryptor e2 = Encryptor.getInstance(infoActual2);
+            e2.confirmPassword(pass);
+
+            try (OutputStream os = e2.getDataStream(fs)) {
+                os.write(payloadExpected);
+            }
+
+            final ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
+            fs.writeFilesystem(bos);
+            encBytes = bos.toByteArray();
+        }
+
+        final byte[] payloadActual;
+        try (POIFSFileSystem nfs = new POIFSFileSystem(new ByteArrayInputStream(encBytes))) {
+            final EncryptionInfo ei = new EncryptionInfo(nfs);
+            Decryptor d2 = Decryptor.getInstance(ei);
+            assertTrue("Unable to process: document is encrypted", d2.verifyPassword(pass));
+
+            try (InputStream is = d2.getDataStream(nfs)) {
+                payloadActual = IOUtils.toByteArray(is);
+            }
+        }
+
+        assertArrayEquals(payloadExpected, payloadActual);
+    }
+
+    /**
+     * Ensure we can encrypt a package that is missing the Core
+     *  Properties, eg one from dodgy versions of Jasper Reports
+     * See https://github.com/nestoru/xlsxenc/ and
+     * http://stackoverflow.com/questions/28593223
+     */
+    @Test
+    public void encryptPackageWithoutCoreProperties() throws Exception {
+        // Open our file without core properties
+        final byte[] encBytes;
+        try (InputStream is = POIDataSamples.getOpenXML4JInstance().openResourceAsStream("OPCCompliance_NoCoreProperties.xlsx");
+            OPCPackage pkg = OPCPackage.open(is)) {
+
+            // It doesn't have any core properties yet
+            assertEquals(0, pkg.getPartsByContentType(ContentTypes.CORE_PROPERTIES_PART).size());
+            assertNotNull(pkg.getPackageProperties());
+            assertNotNull(pkg.getPackageProperties().getLanguageProperty());
+            assertFalse(pkg.getPackageProperties().getLanguageProperty().isPresent());
+
+            // Encrypt it
+            EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
+            Encryptor enc = info.getEncryptor();
+            enc.confirmPassword("password");
+
+            try (POIFSFileSystem fs = new POIFSFileSystem()) {
+
+                try (OutputStream os = enc.getDataStream(fs)) {
+                    pkg.save(os);
+                }
+
+                // Save the resulting OLE2 document, and re-open it
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                fs.writeFilesystem(baos);
+                encBytes = baos.toByteArray();
+            }
+        }
+
+
+        try (POIFSFileSystem inpFS = new POIFSFileSystem(new ByteArrayInputStream(encBytes))) {
+            // Check we can decrypt it
+            EncryptionInfo info = new EncryptionInfo(inpFS);
+            Decryptor d = Decryptor.getInstance(info);
+            assertTrue(d.verifyPassword("password"));
+
+            try (OPCPackage inpPkg = OPCPackage.open(d.getDataStream(inpFS))) {
+                // Check it now has empty core properties
+                assertEquals(1, inpPkg.getPartsByContentType(ContentTypes.CORE_PROPERTIES_PART).size());
+                assertNotNull(inpPkg.getPackageProperties());
+                assertNotNull(inpPkg.getPackageProperties().getLanguageProperty());
+                assertFalse(inpPkg.getPackageProperties().getLanguageProperty().isPresent());
+
+            }
+        }
+    }
+
+    @Test
+    @Ignore
+    public void inPlaceRewrite() throws Exception {
+        File f = TempFile.createTempFile("protected_agile", ".docx");
+
+        try (FileOutputStream fos = new FileOutputStream(f);
+             InputStream fis = POIDataSamples.getPOIFSInstance().openResourceAsStream("protected_agile.docx")) {
+            IOUtils.copy(fis, fos);
+        }
+
+        try (POIFSFileSystem fs = new POIFSFileSystem(f, false)) {
+
+            // decrypt the protected file - in this case it was encrypted with the default password
+            EncryptionInfo encInfo = new EncryptionInfo(fs);
+            Decryptor d = encInfo.getDecryptor();
+            boolean b = d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
+            assertTrue(b);
+
+            try (InputStream docIS = d.getDataStream(fs);
+                 XWPFDocument docx = new XWPFDocument(docIS)) {
+
+                // do some strange things with it ;)
+                XWPFParagraph p = docx.getParagraphArray(0);
+                p.insertNewRun(0).setText("POI was here! All your base are belong to us!");
+                p.insertNewRun(1).addBreak();
+
+                // and encrypt it again
+                Encryptor e = encInfo.getEncryptor();
+                e.confirmPassword("AYBABTU");
+
+                try (OutputStream os = e.getDataStream(fs)) {
+                    docx.write(os);
+                }
+            }
+        }
+    }
+
+
+    private void listEntry(DocumentNode de, String ext, String path) throws IOException {
+        path += "\\" + de.getName().replaceAll("[\\p{Cntrl}]", "_");
+        System.out.println(ext+": "+path+" ("+de.getSize()+" bytes)");
+
+        String name = de.getName().replaceAll("[\\p{Cntrl}]", "_");
+
+        InputStream is = ((DirectoryNode)de.getParent()).createDocumentInputStream(de);
+        FileOutputStream fos = new FileOutputStream("solr."+name+"."+ext);
+        IOUtils.copy(is, fos);
+        fos.close();
+        is.close();
+    }
+
+    @SuppressWarnings("unused")
+    private void listDir(DirectoryNode dn, String ext, String path) throws IOException {
+        path += "\\" + dn.getName().replace('\u0006', '_');
+        System.out.println(ext+": "+path+" ("+dn.getStorageClsid()+")");
+
+        Iterator<Entry> iter = dn.getEntries();
+        while (iter.hasNext()) {
+            Entry ent = iter.next();
+            if (ent instanceof DirectoryNode) {
+                listDir((DirectoryNode)ent, ext, path);
+            } else {
+                listEntry((DocumentNode)ent, ext, path);
+            }
+        }
+    }
+
+    /*
+     * this test simulates the generation of bugs 60320 sample file
+     * as the padding bytes of the EncryptedPackage stream are random or in POIs case PKCS5-padded
+     * one would need to mock those bytes to get the same hmacValues - see diff below
+     *
+     * this use-case is experimental - for the time being the setters of the encryption classes
+     * are spreaded between two packages and are protected - so you would need to violate
+     * the packages rules and provide a helper class in the *poifs.crypt package-namespace.
+     * the default way of defining the encryption settings is via the EncryptionInfo class
+     */
+    @Test
+    public void bug60320CustomEncrypt() throws Exception {
+        int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
+        Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files for AES 256", maxKeyLen == 2147483647);
+
+        // --- src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java  (revision 1766745)
+        // +++ src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java  (working copy)
+        // @@ -208,6 +208,13 @@
+        //      protected int invokeCipher(int posInChunk, boolean doFinal) throws GeneralSecurityException {
+        //          byte plain[] = (_plainByteFlags.isEmpty()) ? null : _chunk.clone();
+        //
+        // +        if (posInChunk < 4096) {
+        // +            _cipher.update(_chunk, 0, posInChunk, _chunk);
+        // +            byte bla[] = { (byte)0x7A,(byte)0x0F,(byte)0x27,(byte)0xF0,(byte)0x17,(byte)0x6E,(byte)0x77,(byte)0x05,(byte)0xB9,(byte)0xDA,(byte)0x49,(byte)0xF9,(byte)0xD7,(byte)0x8E,(byte)0x03,(byte)0x1D };
+        // +            System.arraycopy(bla, 0, _chunk, posInChunk-2, bla.length);
+        // +            return posInChunk-2+bla.length;
+        // +        }
+        // +
+        //          int ciLen = (doFinal)
+        //              ? _cipher.doFinal(_chunk, 0, posInChunk, _chunk)
+        //              : _cipher.update(_chunk, 0, posInChunk, _chunk);
+        //
+        //      --- src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java (revision 1766745)
+        //      +++ src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java (working copy)
+        //
+        //      @@ -300,7 +297,7 @@
+        //      protected static Cipher initCipherForBlock(Cipher existing, int block, boolean lastChunk, EncryptionInfo encryptionInfo, SecretKey skey, int encryptionMode)
+        //      throws GeneralSecurityException {
+        //          EncryptionHeader header = encryptionInfo.getHeader();
+        // -        String padding = (lastChunk ? "PKCS5Padding" : "NoPadding");
+        // +        String padding = "NoPadding"; // (lastChunk ? "PKCS5Padding" : "NoPadding");
+        //          if (existing == null || !existing.getAlgorithm().endsWith(padding)) {
+        //              existing = getCipher(skey, header.getCipherAlgorithm(), header.getChainingMode(), header.getKeySalt(), encryptionMode, padding);
+        //          }
+
+        final EncryptionInfo infoOrig;
+        final byte[] zipInput, epOrigBytes;
+        try (InputStream is = POIDataSamples.getPOIFSInstance().openResourceAsStream("60320-protected.xlsx");
+            POIFSFileSystem fsOrig = new POIFSFileSystem(is)) {
+            infoOrig = new EncryptionInfo(fsOrig);
+            Decryptor decOrig = infoOrig.getDecryptor();
+            boolean b = decOrig.verifyPassword("Test001!!");
+            assertTrue(b);
+            try (InputStream decIn = decOrig.getDataStream(fsOrig)) {
+                zipInput = IOUtils.toByteArray(decIn);
+            }
+
+            try (InputStream epOrig = fsOrig.getRoot().createDocumentInputStream("EncryptedPackage")) {
+                // ignore the 16 padding bytes
+                epOrigBytes = IOUtils.toByteArray(epOrig, 9400);
+            }
+        }
+
+        EncryptionInfo eiNew = new EncryptionInfo(EncryptionMode.agile);
+        AgileEncryptionHeader aehHeader = (AgileEncryptionHeader)eiNew.getHeader();
+        aehHeader.setCipherAlgorithm(CipherAlgorithm.aes128);
+        aehHeader.setHashAlgorithm(HashAlgorithm.sha1);
+        AgileEncryptionVerifier aehVerifier = (AgileEncryptionVerifier)eiNew.getVerifier();
+
+        // this cast might look strange - if the setters would be public, it will become obsolete
+        // see http://stackoverflow.com/questions/5637650/overriding-protected-methods-in-java
+        ((EncryptionVerifier)aehVerifier).setCipherAlgorithm(CipherAlgorithm.aes256);
+        aehVerifier.setHashAlgorithm(HashAlgorithm.sha512);
+
+        Encryptor enc = eiNew.getEncryptor();
+        enc.confirmPassword("Test001!!",
+            infoOrig.getDecryptor().getSecretKey().getEncoded(),
+            infoOrig.getHeader().getKeySalt(),
+            infoOrig.getDecryptor().getVerifier(),
+            infoOrig.getVerifier().getSalt(),
+            infoOrig.getDecryptor().getIntegrityHmacKey()
+        );
+
+        final byte[] epNewBytes;
+        final EncryptionInfo infoReload;
+        try (POIFSFileSystem fsNew = new POIFSFileSystem()) {
+            try (OutputStream os = enc.getDataStream(fsNew)) {
+                os.write(zipInput);
+            }
+
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            fsNew.writeFilesystem(bos);
+
+            try (POIFSFileSystem fsReload = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()))) {
+                infoReload = new EncryptionInfo(fsReload);
+                try (InputStream epReload = fsReload.getRoot().createDocumentInputStream("EncryptedPackage")) {
+                    epNewBytes = IOUtils.toByteArray(epReload, 9400);
+                }
+            }
+        }
+
+        assertArrayEquals(epOrigBytes, epNewBytes);
+
+        Decryptor decReload = infoReload.getDecryptor();
+        assertTrue(decReload.verifyPassword("Test001!!"));
+
+        AgileEncryptionHeader aehOrig = (AgileEncryptionHeader)infoOrig.getHeader();
+        AgileEncryptionHeader aehReload = (AgileEncryptionHeader)infoReload.getHeader();
+        assertEquals(aehOrig.getBlockSize(), aehReload.getBlockSize());
+        assertEquals(aehOrig.getChainingMode(), aehReload.getChainingMode());
+        assertEquals(aehOrig.getCipherAlgorithm(), aehReload.getCipherAlgorithm());
+        assertEquals(aehOrig.getCipherProvider(), aehReload.getCipherProvider());
+        assertEquals(aehOrig.getCspName(), aehReload.getCspName());
+        assertArrayEquals(aehOrig.getEncryptedHmacKey(), aehReload.getEncryptedHmacKey());
+        // this only works, when the paddings are mocked to be the same ...
+        // assertArrayEquals(aehOrig.getEncryptedHmacValue(), aehReload.getEncryptedHmacValue());
+        assertEquals(aehOrig.getFlags(), aehReload.getFlags());
+        assertEquals(aehOrig.getHashAlgorithm(), aehReload.getHashAlgorithm());
+        assertArrayEquals(aehOrig.getKeySalt(), aehReload.getKeySalt());
+        assertEquals(aehOrig.getKeySize(), aehReload.getKeySize());
+
+        AgileEncryptionVerifier aevOrig = (AgileEncryptionVerifier)infoOrig.getVerifier();
+        AgileEncryptionVerifier aevReload = (AgileEncryptionVerifier)infoReload.getVerifier();
+        assertEquals(aevOrig.getBlockSize(), aevReload.getBlockSize());
+        assertEquals(aevOrig.getChainingMode(), aevReload.getChainingMode());
+        assertEquals(aevOrig.getCipherAlgorithm(), aevReload.getCipherAlgorithm());
+        assertArrayEquals(aevOrig.getEncryptedKey(), aevReload.getEncryptedKey());
+        assertArrayEquals(aevOrig.getEncryptedVerifier(), aevReload.getEncryptedVerifier());
+        assertArrayEquals(aevOrig.getEncryptedVerifierHash(), aevReload.getEncryptedVerifierHash());
+        assertEquals(aevOrig.getHashAlgorithm(), aevReload.getHashAlgorithm());
+        assertEquals(aevOrig.getKeySize(), aevReload.getKeySize());
+        assertArrayEquals(aevOrig.getSalt(), aevReload.getSalt());
+        assertEquals(aevOrig.getSpinCount(), aevReload.getSpinCount());
+
+        AgileDecryptor adOrig = (AgileDecryptor)infoOrig.getDecryptor();
+        AgileDecryptor adReload = (AgileDecryptor)infoReload.getDecryptor();
+
+        assertArrayEquals(adOrig.getIntegrityHmacKey(), adReload.getIntegrityHmacKey());
+        // doesn't work without mocking ... see above
+        // assertArrayEquals(adOrig.getIntegrityHmacValue(), adReload.getIntegrityHmacValue());
+        assertArrayEquals(adOrig.getSecretKey().getEncoded(), adReload.getSecretKey().getEncoded());
+        assertArrayEquals(adOrig.getVerifier(), adReload.getVerifier());
+    }
+
+    @Test
+    public void smallFile() throws IOException, GeneralSecurityException {
+        // see https://stackoverflow.com/questions/61463301
+        final int tinyFileSize = 80_000_000;
+        final String pass = "s3cr3t";
+
+        File tmpFile = TempFile.createTempFile("tiny", ".bin");
+
+        // create/populate empty file
+        try (POIFSFileSystem poifs = new POIFSFileSystem();
+             FileOutputStream fos = new FileOutputStream(tmpFile)) {
+            poifs.writeFilesystem(fos);
+        }
+
+        EncryptionInfo info1 = new EncryptionInfo(EncryptionMode.agile);
+        Encryptor enc = info1.getEncryptor();
+        enc.confirmPassword(pass);
+
+        final MessageDigest md = getMessageDigest(HashAlgorithm.sha256);
+
+        // reopen as mmap-ed file
+        try (POIFSFileSystem poifs = new POIFSFileSystem(tmpFile, false)) {
+            try (OutputStream os = enc.getDataStream(poifs);
+                 RandomStream rs = new RandomStream(md)) {
+                IOUtils.copy(rs, os, tinyFileSize);
+            }
+            poifs.writeFilesystem();
+        }
+
+        final byte[] digest1 = md.digest();
+        md.reset();
+
+        // reopen and check the digest
+        try (POIFSFileSystem poifs = new POIFSFileSystem(tmpFile)) {
+            EncryptionInfo info2 = new EncryptionInfo(poifs);
+            Decryptor dec = info2.getDecryptor();
+            boolean passOk = dec.verifyPassword(pass);
+            assertTrue(passOk);
+
+            try (InputStream is = dec.getDataStream(poifs);
+                 DigestInputStream dis = new DigestInputStream(is, md);
+                 NullOutputStream nos = new NullOutputStream()) {
+                IOUtils.copy(dis, nos);
+            }
+        }
+
+        final byte[] digest2 = md.digest();
+        assertArrayEquals(digest1, digest2);
+
+        boolean isDeleted = tmpFile.delete();
+        assertTrue(isDeleted);
+    }
+
+    private static final class RandomStream extends InputStream {
+        private final Random rand = new Random();
+        private final byte[] buf = new byte[1024];
+        private final MessageDigest md;
+
+        private RandomStream(MessageDigest md) {
+            this.md = md;
+        }
+
+        @Override
+        public int read() {
+            int ret = rand.nextInt(256);
+            md.update((byte)ret);
+            return ret;
+        }
+
+        @Override
+        public int read(byte[] b, final int off, int len) {
+            for (int start = off; start-off < len; start += buf.length) {
+                rand.nextBytes(buf);
+                int copyLen = Math.min(buf.length, len-(start-off));
+                System.arraycopy(buf, 0, b, start, copyLen);
+                md.update(buf, 0, copyLen);
+            }
+            return len;
+        }
+    }
+
+}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestHxxFEncryption.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestHxxFEncryption.java
new file mode 100644 (file)
index 0000000..487e16d
--- /dev/null
@@ -0,0 +1,188 @@
+/* ====================================================================
+   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.poifs.crypt.tests;
+
+import static org.apache.poi.POIDataSamples.getDocumentInstance;
+import static org.apache.poi.POIDataSamples.getSlideShowInstance;
+import static org.apache.poi.POIDataSamples.getSpreadSheetInstance;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.POIDocument;
+import org.apache.poi.extractor.POITextExtractor;
+import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
+import org.apache.poi.ooxml.extractor.ExtractorFactory;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.cryptoapi.CryptoAPIEncryptionHeader;
+import org.apache.poi.poifs.storage.RawDataUtil;
+import org.apache.xmlbeans.XmlException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TestHxxFEncryption {
+    @Parameter(value = 0)
+    public POIDataSamples sampleDir;
+
+    @Parameter(value = 1)
+    public String file;
+
+    @Parameter(value = 2)
+    public String password;
+
+    @Parameter(value = 3)
+    public String expected;
+
+    @Parameters(name="{1}")
+    public static Collection<Object[]> data() throws IOException {
+        final String base64 =
+            "H4sIAAAAAAAAAF1Uu24bMRDs/RULVwkgCUhSpHaZwkDgpHJH8fZ0G/Nx4ZI6y13yG/mRfIb9R5mlZFlIpdPtcnZmdnjPf57/vvx6+f3h6obuv3"+
+            "ylbY5bEiVHe1fEpUp5pOgkrK0iabehm7FyoZi1ks8xcvHiQu8h5bLnorTlnUvkJ/YPOHKsLVInAqCs91KakuaxLq4w3g00SgCo9Xou1UnCmSBe"+
+            "MhpRY6qHmXVFteQfQJ5yUaaOw4qXwgPVjPGAqhNH5bBHAfTmwqqoSkLdFT/J3nC0eZBRk7yiu5s7yoU+r+9l3tDtm5A3jgt6AQxNOY2ya+U4sK"+
+            "XZ+YczbpfSVVuzFOuunKraqIVD2ND3yVXauT3TNthR/O3IJAM7gzTOGeIcXZvj14ahotW8wSognlMu0Yyp/Fi7O6s+CK6haUUjtPCji7MVcgqH"+
+            "jh+42tqeqPDMroJ/lBAE4AZbJbJu6Fu35ej42Tw9mYeTwVXoBKJiPeFV94q2rZJAyNEPo/qOdWYLBpq3B2JX8GDZeJ14mZf3tOQWBmpd9yQ7kI"+
+            "DCY/jmkj1oGOicFy62r9vutC5uJsVEMFgmAXXfYcC6BRBKNHCybALFJolnrDcPXNLl+K60Vctt09YZT7YgbeOICGJ/ZgC2JztOnm1JhX3eJXni"+
+            "U5Bqhezzlu334vD/Ajr3yDGXw5G9IZ6aLmLfQafY42N3J7cjj1LaXOHihSrcC5ThmuYIB5FX5AU8tKlnNG9Dn1EnsdD4KcnPhsSNPRiXtz461b"+
+            "VZw8Pm6vn0afh4fvr0D5P/+cMuBAAA";
+        final String x = new String(RawDataUtil.decompress(base64), StandardCharsets.UTF_8);
+
+        return Arrays.asList(
+            // binary rc4
+            new Object[]{ getDocumentInstance(), "password_tika_binaryrc4.doc", "tika", "This is an encrypted Word 2007 File." },
+            // cryptoapi
+            new Object[]{ getDocumentInstance(), "password_password_cryptoapi.doc", "password", "This is a test" },
+            // binary rc4
+            new Object[]{ getSpreadSheetInstance(), "password.xls", "password", x },
+            // cryptoapi
+            new Object[]{ getSpreadSheetInstance(), "35897-type4.xls", "freedom", "Sheet1\nhello there!" },
+            // cryptoapi (PPT only supports cryptoapi...)
+            new Object[]{ getSlideShowInstance(), "cryptoapi-proc2356.ppt", "crypto", "Dominic Salemno" }
+        );
+    }
+
+    @Test
+    public void extract() throws IOException, OpenXML4JException, XmlException {
+        File f = sampleDir.getFile(file);
+        Biff8EncryptionKey.setCurrentUserPassword(password);
+        try (POITextExtractor te = ExtractorFactory.createExtractor(f)) {
+            String actual = te.getText().trim();
+            assertEquals(expected, actual);
+        } finally {
+            Biff8EncryptionKey.setCurrentUserPassword(null);
+        }
+    }
+
+    @Test
+    public void changePassword() throws IOException, OpenXML4JException, XmlException {
+        newPassword("test");
+    }
+
+    @Test
+    public void removePassword() throws IOException, OpenXML4JException, XmlException {
+        newPassword(null);
+    }
+
+    private void newPassword(String newPass) throws IOException, OpenXML4JException, XmlException {
+        File f = sampleDir.getFile(file);
+        Biff8EncryptionKey.setCurrentUserPassword(password);
+        try (POITextExtractor te1 = ExtractorFactory.createExtractor(f)) {
+            Biff8EncryptionKey.setCurrentUserPassword(newPass);
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            try (POIDocument doc = (POIDocument) te1.getDocument()) {
+                doc.write(bos);
+            }
+            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+            try (POITextExtractor te2 = ExtractorFactory.createExtractor(bis)) {
+                String actual = te2.getText().trim();
+                assertEquals(expected, actual);
+            }
+        } finally {
+            Biff8EncryptionKey.setCurrentUserPassword(null);
+        }
+    }
+
+    /** changing the encryption mode and key size in poor mans style - see comments below */
+    @Test
+    public void changeEncryption() throws IOException, OpenXML4JException, XmlException {
+        File f = sampleDir.getFile(file);
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        Biff8EncryptionKey.setCurrentUserPassword(password);
+        try (POITextExtractor te1 = ExtractorFactory.createExtractor(f)) {
+            // first remove encryption
+            Biff8EncryptionKey.setCurrentUserPassword(null);
+            try (POIDocument doc = (POIDocument) te1.getDocument()) {
+                doc.write(bos);
+            }
+            // then use default setting, which is cryptoapi
+            String newPass = "newPass";
+            try (POITextExtractor te2 = ExtractorFactory.createExtractor(new ByteArrayInputStream(bos.toByteArray()))) {
+                Biff8EncryptionKey.setCurrentUserPassword(newPass);
+                try (POIDocument doc = (POIDocument) te2.getDocument()) {
+                    bos.reset();
+                    doc.write(bos);
+                }
+            }
+            // and finally update cryptoapi setting
+            try (POITextExtractor te3 = ExtractorFactory.createExtractor(new ByteArrayInputStream(bos.toByteArray()));
+                 POIDocument doc = (POIDocument) te3.getDocument()) {
+                // need to cache data (i.e. read all data) before changing the key size
+                Class<?> clazz = doc.getClass();
+                if ("HSLFSlideShowImpl".equals(clazz.getSimpleName())) {
+                    try {
+                        clazz.getDeclaredMethod("getPictureData").invoke(doc);
+                    } catch (ReflectiveOperationException e) {
+                        fail("either scratchpad jar is included and this should work or the clazz should be != HSLFSlideShowImpl");
+                    }
+                    doc.getDocumentSummaryInformation();
+                }
+                EncryptionInfo ei = doc.getEncryptionInfo();
+                assertNotNull(ei);
+                assertTrue(ei.getHeader() instanceof CryptoAPIEncryptionHeader);
+                assertEquals(0x28, ei.getHeader().getKeySize());
+                ei.getHeader().setKeySize(0x78);
+                bos.reset();
+                doc.write(bos);
+            }
+            // check the setting
+            try (POITextExtractor te4 = ExtractorFactory.createExtractor(new ByteArrayInputStream(bos.toByteArray()));
+                 POIDocument doc = (POIDocument) te4.getDocument()) {
+                EncryptionInfo ei = doc.getEncryptionInfo();
+                assertNotNull(ei);
+                assertTrue(ei.getHeader() instanceof CryptoAPIEncryptionHeader);
+                assertEquals(0x78, ei.getHeader().getKeySize());
+            }
+        } finally {
+            Biff8EncryptionKey.setCurrentUserPassword(null);
+        }
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestSecureTempZip.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/tests/TestSecureTempZip.java
new file mode 100644 (file)
index 0000000..f939257
--- /dev/null
@@ -0,0 +1,130 @@
+/* ====================================================================
+   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.poifs.crypt.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+
+import javax.crypto.Cipher;
+
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.util.ZipEntrySource;
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.temp.AesZipFileZipEntrySource;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.apache.poi.xssf.extractor.XSSFBEventBasedExcelExtractor;
+import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.xmlbeans.XmlException;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class TestSecureTempZip {
+
+    /**
+     * Test case for #59841 - this is an example on how to use encrypted temp files,
+     * which are streamed into POI opposed to having everything in memory
+     */
+    @Test
+    public void protectedTempZip() throws IOException, GeneralSecurityException, XmlException, OpenXML4JException {
+        File tikaProt = XSSFTestDataSamples.getSampleFile("protected_passtika.xlsx");
+        FileInputStream fis = new FileInputStream(tikaProt);
+        POIFSFileSystem poifs = new POIFSFileSystem(fis);
+        EncryptionInfo ei = new EncryptionInfo(poifs);
+        Decryptor dec = ei.getDecryptor();
+        boolean passOk = dec.verifyPassword("tika");
+        assertTrue(passOk);
+
+        // extract encrypted ooxml file and write to custom encrypted zip file
+        InputStream is = dec.getDataStream(poifs);
+
+        // provide ZipEntrySource to poi which decrypts on the fly
+        ZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(is);
+
+        // test the source
+        OPCPackage opc = OPCPackage.open(source);
+        String expected = "This is an Encrypted Excel spreadsheet.";
+
+        XSSFEventBasedExcelExtractor extractor = new XSSFEventBasedExcelExtractor(opc);
+        extractor.setIncludeSheetNames(false);
+        String txt = extractor.getText();
+        assertEquals(expected, txt.trim());
+
+        XSSFWorkbook wb = new XSSFWorkbook(opc);
+        txt = wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue();
+        assertEquals(expected, txt);
+
+        extractor.close();
+
+        wb.close();
+        opc.close();
+        source.close();
+        poifs.close();
+        fis.close();
+    }
+
+    /**
+     * Now try with xlsb.
+     */
+    @Test
+    public void protectedXLSBZip() throws IOException, GeneralSecurityException, XmlException, OpenXML4JException {
+        //The test file requires that JCE unlimited be installed.
+        //If it isn't installed, skip this test.
+        int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
+        Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files for AES 256",
+                maxKeyLen == 2147483647);
+
+        File tikaProt = XSSFTestDataSamples.getSampleFile("protected_passtika.xlsb");
+        FileInputStream fis = new FileInputStream(tikaProt);
+        POIFSFileSystem poifs = new POIFSFileSystem(fis);
+        EncryptionInfo ei = new EncryptionInfo(poifs);
+        Decryptor dec = ei.getDecryptor();
+        boolean passOk = dec.verifyPassword("tika");
+        assertTrue(passOk);
+
+        // extract encrypted ooxml file and write to custom encrypted zip file
+        InputStream is = dec.getDataStream(poifs);
+
+        // provide ZipEntrySource to poi which decrypts on the fly
+        ZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(is);
+
+        // test the source
+        OPCPackage opc = OPCPackage.open(source);
+        String expected = "You can't see me";
+
+        XSSFBEventBasedExcelExtractor extractor = new XSSFBEventBasedExcelExtractor(opc);
+        extractor.setIncludeSheetNames(false);
+        String txt = extractor.getText();
+        assertEquals(expected, txt.trim());
+
+        extractor.close();
+        opc.close();
+        poifs.close();
+        fis.close();
+    }
+
+}
diff --git a/src/ooxml/testcases/org/apache/poi/sl/SLCommonUtils.java b/src/ooxml/testcases/org/apache/poi/sl/SLCommonUtils.java
deleted file mode 100644 (file)
index 1b2b182..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.sl;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.sl.usermodel.SlideShow;
-import org.apache.poi.sl.usermodel.SlideShowFactory;
-
-public class SLCommonUtils {
-    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
-    
-    /** a generic way to open a sample slideshow document **/
-    public static SlideShow<?,?> openSampleSlideshow(String sampleName) throws IOException {
-        try (InputStream is = _slTests.openResourceAsStream(sampleName)) {
-            return SlideShowFactory.create(is);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tests, if the scratchpad classes are on the classpath
-     * 
-     * @return true, if only xslf is on the classpath, and false, if both classpaths
-     *    (XSLF and HSLF) can be used/referenced 
-     */
-    public static boolean xslfOnly() {
-        try {
-            Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow");
-            return false;
-        } catch (Exception e) {
-            return true;
-        }
-    }
-
-}
diff --git a/src/ooxml/testcases/org/apache/poi/sl/TestFonts.java b/src/ooxml/testcases/org/apache/poi/sl/TestFonts.java
deleted file mode 100644 (file)
index 0590e8d..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.sl;
-
-import static org.apache.poi.sl.SLCommonUtils.xslfOnly;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.FontFormatException;
-import java.awt.Graphics2D;
-import java.awt.GraphicsEnvironment;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.common.usermodel.fonts.FontGroup;
-import org.apache.poi.sl.draw.Drawable;
-import org.apache.poi.sl.usermodel.Slide;
-import org.apache.poi.sl.usermodel.SlideShow;
-import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
-import org.apache.poi.sl.usermodel.TextBox;
-import org.apache.poi.sl.usermodel.TextParagraph;
-import org.apache.poi.sl.usermodel.TextRun;
-import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-
-/**
- * Test rendering - specific to font handling
- */
-public class TestFonts {
-    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
-
-    private static final String JPTEXT =
-        "\u3061\u3087\u3063\u3068\u65E9\u3044\u3051\u3069T\u30B7\u30E3\u30C4\u304C\u7740\u305F\u304F\u306A" +
-        "\u308B\u5B63\u7BC0\u2661\u304A\u6BCD\u3055\u3093\u306E\u5F71\u97FF\u304B\u3001\u975E\u5E38\u306B" +
-        "\u6050\u7ADC\u304C\u5927\u597D\u304D\u3067\u3059\u3002\u3082\u3046\u98FC\u3044\u305F\u3044\u304F" +
-        "\u3089\u3044\u5927\u597D\u304D\u3067\u3059\u3002#\u30B8\u30E5\u30E9\u30B7\u30C3\u30AF\u30EF\u30FC" +
-        "\u30EB\u30C9 \u306E\u30E9\u30D7\u30C8\u30EB4\u59C9\u59B9\u3068\u304B\u6FC0\u7684\u306B\u53EF\u611B" +
-        "\u304F\u3066\u53EF\u611B\u304F\u3066\u53EF\u611B\u304F\u3066\u53EF\u611B\u3044\u3067\u3059\u3002" +
-        "\u3081\u308D\u3081\u308D\u3001\u5927\u597D\u304D\u2661\u304A\u6BCD\u3055\u3093\u3082\u6050\u7ADC" +
-        "\u304C\u597D\u304D\u3067\u3001\u5C0F\u3055\u3044\u9803\u3001\u53E4\u4EE3\u751F\u7269\u306E\u56F3" +
-        "\u9451\u3092\u4E00\u7DD2\u306B\u898B\u3066\u305F\u306E\u601D\u3044\u51FA\u3059\u301C\u3068\u3044";
-
-    private static final String[] INIT_FONTS = {"mona.ttf"};
-
-    @BeforeClass
-    public static void initGE() throws FontFormatException, IOException {
-        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
-        for (String s : INIT_FONTS) {
-            Font font = Font.createFont(Font.TRUETYPE_FONT, _slTests.getFile(s));
-            ge.registerFont(font);
-        }
-    }
-
-    @Test
-    public void resizeToFitTextHSLF() throws IOException, ReflectiveOperationException {
-        assumeFalse(xslfOnly());
-        SlideShow<?,?> ppt = (SlideShow<?,?>)Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow").newInstance();
-        resizeToFitText(ppt);
-        ppt.close();
-    }
-
-    @Test
-    public void resizeToFitTextXSLF() throws IOException {
-        SlideShow<?,?> ppt = new XMLSlideShow();
-        resizeToFitText(ppt);
-        ppt.close();
-    }
-
-    private void resizeToFitText(SlideShow<?,?> slideshow) throws IOException {
-        Slide<?,?> sld = slideshow.createSlide();
-        TextBox<?,?> tb = sld.createTextBox();
-        tb.setAnchor(new Rectangle(50, 50, 200, 50));
-        tb.setStrokeStyle(Color.black, LineDash.SOLID, 3);
-        tb.setText(JPTEXT);
-
-        setFont(tb, "NoSuchFont", FontGroup.LATIN);
-
-        Dimension pgsize = slideshow.getPageSize();
-        int width = (int)pgsize.getWidth();
-        int height = (int)pgsize.getHeight();
-
-        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-        Graphics2D graphics = img.createGraphics();
-
-        Map<String,String> fallbackMap = new HashMap<>();
-        fallbackMap.put("NoSuchFont", "Mona");
-        // in XSLF the fonts default to the theme fonts (Calibri), if the font group is not overridden
-        // see XSLFTextRun.XSLFTextInfo.getCTTextFont
-        fallbackMap.put("Calibri", "Mona");
-        graphics.setRenderingHint(Drawable.FONT_FALLBACK, fallbackMap);
-        graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
-
-        tb.resizeToFitText(graphics);
-        graphics.dispose();
-
-        Rectangle2D anc = tb.getAnchor();
-        // ignore font metrics differences on windows / linux (... hopefully ...)
-        int tbHeight = (int)anc.getHeight();
-        assertTrue(tbHeight > 100);
-    }
-
-    private void setFont(TextBox<?,?> tb, String fontFamily, FontGroup fontGroup) {
-        // TODO: set east asian font family - MS Office uses "MS Mincho" or "MS Gothic" as a fallback
-        // see https://stackoverflow.com/questions/26063828 for good explanation about the font metrics
-        // differences on different environments
-        for (TextParagraph<?,?,? extends TextRun> p : tb.getTextParagraphs()) {
-            for (TextRun r : p.getTextRuns()) {
-                r.setFontFamily(fontFamily, fontGroup);
-            }
-        }
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/sl/TestHeadersFooters.java b/src/ooxml/testcases/org/apache/poi/sl/TestHeadersFooters.java
deleted file mode 100644 (file)
index a4b50bf..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.sl;
-
-import static org.apache.poi.sl.SLCommonUtils.openSampleSlideshow;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-import java.util.List;
-
-import org.apache.poi.sl.usermodel.Shape;
-import org.apache.poi.sl.usermodel.Slide;
-import org.apache.poi.sl.usermodel.SlideShow;
-import org.apache.poi.sl.usermodel.TextParagraph;
-import org.apache.poi.sl.usermodel.TextShape;
-import org.junit.Test;
-
-public class TestHeadersFooters {
-    @Test
-    public void bug58144c() throws IOException {
-        SlideShow<?,?> ppt = openSampleSlideshow("bug58144-headers-footers-2007.pptx");
-        testSlideShow(ppt);
-        ppt.close();
-    }
-    
-    private void testSlideShow(SlideShow<?,?> ppt) {
-        Slide<?,?> sl =  ppt.getSlides().get(0);
-        
-        List<? extends Shape<?,?>> shapes = sl.getShapes();
-        TextShape<?,?> ts0 = (TextShape<?,?>)shapes.get(0);
-        assertEquals("Test file", ts0.getText());
-        TextShape<?,?> ts1 = (TextShape<?,?>)shapes.get(1);
-        assertEquals("Has some text in the headers and footers", ts1.getText());
-        TextShape<?,?> ts2 = (TextShape<?,?>)shapes.get(2);
-        assertEquals("Slide footer", ts2.getText());
-        List<? extends TextParagraph<?,?,?>> ltp = ts2.getTextParagraphs();
-        assertTrue(ltp.get(0).isHeaderOrFooter());
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java b/src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java
deleted file mode 100644 (file)
index 44f901d..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.sl;
-
-import static org.apache.poi.sl.SLCommonUtils.xslfOnly;
-import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.EXCEL_V12;
-import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.EXCEL_V8;
-import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.PDF;
-import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.WORD_V12;
-import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.WORD_V8;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeFalse;
-
-import java.awt.geom.Rectangle2D;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.Collection;
-
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.POIDocument;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.poifs.storage.RawDataUtil;
-import org.apache.poi.sl.usermodel.ObjectMetaData;
-import org.apache.poi.sl.usermodel.ObjectShape;
-import org.apache.poi.sl.usermodel.PictureData;
-import org.apache.poi.sl.usermodel.PictureData.PictureType;
-import org.apache.poi.sl.usermodel.Slide;
-import org.apache.poi.sl.usermodel.SlideShow;
-import org.apache.poi.sl.usermodel.SlideShowFactory;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class TestOleShape {
-    private static final String PDF_SAMPLE =
-        "H4sIAAAAAAAAAJWUezRUWxzHe+o2FXncVtxLpxi3FPOeKYspjMdM5J1S4TTOaDIzxzpzJo9CUrnrSiUxIeT" +
-        "9jB7yqInihrhepTwqt1AT5VZCC7XcY0LWcv+5Z521zz6fvX+/vb/7t9cX78CyMiQZ0XD4W4OFEzgKQATgg4" +
-        "dxJiYAwRYS+aCHACqGnHAAABCs+AIUQrCvAEQhFsSFvSEck4kTowgECnEBl6E4OxGesfLkl2Bc0g5V/MCHt" +
-        "duqroTFC27YIKGAp+OL5Ou1SsmebA1XvciLk+Ucg84aLclQZhRZmh0amrG9Ina4t7Lh+ZCAHyezsg/NXsZg" +
-        "vuPw8NIedsrI2sZlz2vfhLkZfIgfMr4zFvTrmfbRgMmPw1UTvWk+r4MCZfLtj2WPPStVJ0P2PiKkxo+YnJ5" +
-        "Ua7v5UnefkB9ev0vSR37a8NrsC2lApaLp7086wS3Lzi2LqB3TMW2POrdRRUYMFYWs8vBo/kSQ6dYXpR6rxM" +
-        "UXM0vqu4arpe5dha7XS5MYS5P1arVG653sb8pXqReVw/TfjK8R3q4Z7X7Uk9dZ2Bcl8Wpmsl80Xf1QTOxe3" +
-        "Nutwus0kYge1LoHvgKLbc/f6WvdcsBfS9ctU3vSaneHNm0w/uhrm0Zett5O83s2xh2Gm8WZfWJ+/CNWruZ2" +
-        "cap8tR2/U9bAfRBbYt3PL9jvb3+0usqSF6vfrFuEq8Hf6jgrx/fERpZJEjKbHtJ11jCdUwI7Oc8QrmZf2pr" +
-        "L43WJn1mlT1ydV+QbrndcdN3qSEnicVhmoJyfWyprUEsIZlPyvi0tiEy7FzkOnqlE/qC6xFSpyg0E8tODa7" +
-        "qiKX61hMxRkZt73ITLWIHwtZtj71NbS4/BgKHnssOMcXOp1aacX4A//V+VFN4TWl6QryxdkcAp79BZcipmP" +
-        "OWOWkS6KhqUWlG+yCCxVMMtfW+9e56++gKHYEs9PNJztTI6KtyfOCDPOBppt3udRs3NpGrKfrs3i3Nivtrs" +
-        "VTl5LFerXZlTbf5XumbeYsOfwnve5ksEjKy6s1Z78rpbeJq7biTdzWwU3vhZ1GqkYb9D+t6mYvWLhXn6FWi" +
-        "c60VWpbBtVYHLQkmbh6Txwm6Ul3LbNW/Hs5FtLnlNX3fsAX2jPdlOI5W3HDIcm2MyNiR39rdyHlpwusjoOj" +
-        "I3IKfgPMILSzHZInmQaWyUFXEi0bHsCLX8pm9Gzl2vou7E3rrkPYdt1EwW3R5Qcg8rwzk88c1p13l8v+WkY" +
-        "75FHeS7XrvRsHgLy+wfr2EBRfNJ/4UVhUrihRqDktXciPGxWv1eXs396/0lqWG3YtU/A+D90hrT46cumSUN" +
-        "rBdG0G2Knn3T9Kw0X96vbhxMyr92uqUNOa4aEnGqP8us6GULm7mIyFKuxnOW2MZEEuKXmOpxnnqlwiMn+ju" +
-        "Xu+inC5mpG9oesxKkhcJq9bra5vR3H7l10hGbAxqu6t0LvHzaDnPIp/zeu0iXj1NNtVc+cMyUsH18u7TGXJ" +
-        "XiL4W3tqaL2mq6zkgXWB6kOTB3RxW8PHAOvzfaufDptdg7qmZlEcrUzbd5jKtVb85Sr9jaMT8a3y2Q30+3/" +
-        "FrsfGZDblh/mYnHhCg3ekm2q1JIYEVCd9rv42PNb9RFpuSsa4MNE0GfdSYDv6lsudikg4NE3tNugfWmfIY6" +
-        "7TeYvZCItG0zmDxrQwrjsQxArZ1RzHSA72CKgURgyqQszAASQOCCWItZETaAtdg7nYc2x85cAv0ggOAA+kC" +
-        "KnA4gAolQLGzG3ewgbz5oDgcA+zBEBEhUkhGDQiZvpc3tHlBMtYBFKBYsBiiz0dYILPGbs73vqynoDHLGKA" +
-        "KKxH5TK3MDZzAbQBEJNPNngc1iQUf4XMjJ2nxazxR3gsSwBOFCYoCsWPOHRtJ/ahQronbyvcWYnqljcJrdu" +
-        "2RK9pwE9DkJLLDioDACbOSCfAQGSEYkqhGJCGw8hKJ+xgSCgvogoN8hPldsBCM+mzZ9P0wE9pZwof8V92MD" +
-        "jHkKLEAUFMA+04XC1EzX6UdMAALxcERgK444+wB0Go1CA3jANCNRGdj1UoyIZhlpPsMobf48GmkeI1Pp8xi" +
-        "Nsm0eo9O3/mAoAvIFEKIQ58wPgrAtK+oJwyjAmL0+bBEPBugzGsUoiKAKhSQGmYjD4y3trXD/AmBc9IeqBwAA";
-    
-    enum Api { HSLF, XSLF }
-
-
-    @Parameter(value = 0)
-    public Api api;
-    @Parameter(value = 1)
-    public ObjectMetaData.Application app;
-
-    
-    private static File pictureFile;
-
-    @BeforeClass
-    public static void initPicture() {
-        pictureFile = POIDataSamples.getSlideShowInstance().getFile("wrench.emf");
-    }
-    
-    
-    @Parameters(name="{0} {1}")
-    public static Collection<Object[]> data() {
-        return Arrays.asList(new Object[][] {
-            { Api.HSLF, EXCEL_V8 },
-            { Api.HSLF, WORD_V8 },
-            { Api.HSLF, PDF },
-            { Api.XSLF, EXCEL_V12 },
-            { Api.XSLF, WORD_V12 },
-            { Api.XSLF, PDF },
-        });
-    }
-    
-    @Test
-    public void embedData() throws IOException, InvalidFormatException, ReflectiveOperationException {
-        final ByteArrayInputStream pptBytes;
-        try (SlideShow<?,?> ppt = createSlideShow()) {
-            final PictureData picData = ppt.addPicture(pictureFile,  PictureType.EMF);
-            final Slide<?,?> slide = ppt.createSlide();
-            final ObjectShape<?,?> oleShape = slide.createOleShape(picData);
-            oleShape.setAnchor(new Rectangle2D.Double(100,100,100,100));
-            try (OutputStream os = oleShape.updateObjectData(app, null)) {
-                fillOleData(os);
-            }
-            final ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
-            ppt.write(bos);
-            pptBytes = new ByteArrayInputStream(bos.toByteArray());
-        }
-        try (SlideShow<?,?> ppt = SlideShowFactory.create(pptBytes)) {
-            final ObjectShape<?,?> oleShape = (ObjectShape<?,?>)ppt.getSlides().get(0).getShapes().get(0);
-            try (InputStream bis = oleShape.readObjectData()) {
-                validateOleData(bis);
-            }
-        }
-    }
-    
-    private SlideShow<?,?> createSlideShow() throws ReflectiveOperationException {
-        if (api == Api.XSLF) {
-            return new XMLSlideShow();
-        } else {
-            assumeFalse(xslfOnly());
-            return (SlideShow<?,?>)Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow").newInstance();
-        }
-    }
-
-
-    private void fillOleData(final OutputStream out) throws IOException {
-        switch (app) {
-        case EXCEL_V8:
-        case EXCEL_V12:
-            try (Workbook wb = (app == EXCEL_V12) ? new XSSFWorkbook() : new HSSFWorkbook()) {
-                wb.createSheet().createRow(0).createCell(0).setCellValue("test me");
-                wb.write(out);
-            }
-            break;
-        case WORD_V8:
-            try (InputStream is = POIDataSamples.getDocumentInstance().openResourceAsStream("simple.doc")) {
-                IOUtils.copy(is, out);
-            }
-            break;
-        case WORD_V12:
-            try (XWPFDocument doc = new XWPFDocument()) {
-                doc.createParagraph().createRun().setText("Test me");
-                doc.write(out);
-            }
-            break;
-        case PDF:
-            out.write(RawDataUtil.decompress(PDF_SAMPLE));
-            break;
-        default:
-        case CUSTOM:
-            fail("not implemented");
-            break;
-        }
-    }
-    
-    private void validateOleData(final InputStream in) throws IOException, InvalidFormatException, ReflectiveOperationException {
-        switch (app) {
-        case EXCEL_V8:
-        case EXCEL_V12:
-            try (Workbook wb = WorkbookFactory.create(in)) {
-                assertEquals("test me", wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
-            }
-            break;
-        case WORD_V8:
-            Class<? extends POIDocument> clazz = (Class<? extends POIDocument>)Class.forName("org.apache.poi.hwpf.HWPFDocument");
-            Constructor<? extends POIDocument> con = clazz.getDeclaredConstructor(InputStream.class);
-            Method m = clazz.getMethod("getDocumentText");
-            try (POIDocument doc = con.newInstance(in)) {
-                assertEquals("This is a simple file created with Word 97-SR2.\r", m.invoke(doc));
-            }
-            break;
-        case WORD_V12:
-            try (XWPFDocument doc = new XWPFDocument(in)) {
-                assertEquals("Test me", doc.getParagraphs().get(0).getText());
-            }
-            break;
-        case PDF:
-            final byte[] expected = RawDataUtil.decompress(PDF_SAMPLE);
-            final byte[] actual = IOUtils.toByteArray(in);
-            assertArrayEquals(expected, actual);
-            break;
-        default:
-        case CUSTOM:
-            fail("not implemented");
-            break;
-        }
-        
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/sl/TestSlide.java b/src/ooxml/testcases/org/apache/poi/sl/TestSlide.java
deleted file mode 100644 (file)
index 60a8a36..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.sl;
-
-import static org.apache.poi.sl.SLCommonUtils.xslfOnly;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.poi.sl.usermodel.SlideShow;
-import org.apache.poi.sl.usermodel.SlideShowFactory;
-import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.junit.Test;
-
-public class TestSlide {
-
-    @Test
-    public void hideHSLF() throws IOException, ReflectiveOperationException {
-        assumeFalse(xslfOnly());
-        SlideShow<?,?> ppt1 = (SlideShow<?,?>)Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow").newInstance();
-        hideSlide(ppt1);
-        ppt1.close();
-    }
-    
-    @Test
-    public void hideXSLF() throws IOException {
-        SlideShow<?,?> ppt1 = new XMLSlideShow();
-        hideSlide(ppt1);
-        ppt1.close();
-    }
-    
-    private void hideSlide(SlideShow<?,?> ppt1) throws IOException {
-        ppt1.createSlide().setHidden(true);
-        ppt1.createSlide();
-        
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        ppt1.write(bos);
-        ppt1.close();
-        
-        InputStream is = new ByteArrayInputStream(bos.toByteArray());
-        SlideShow<?,?> ppt2 = SlideShowFactory.create(is);
-
-        Boolean[] hiddenState = ppt2.getSlides().stream().map(e -> e.isHidden()).toArray(Boolean[]::new);
-        
-        assertTrue(hiddenState[0]);
-        assertFalse(hiddenState[1]);
-        
-        ppt2.close();
-    }
-}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/sl/TestTable.java b/src/ooxml/testcases/org/apache/poi/sl/TestTable.java
deleted file mode 100644 (file)
index 7c04047..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.sl;
-
-import static org.apache.poi.sl.SLCommonUtils.openSampleSlideshow;
-import static org.apache.poi.sl.SLCommonUtils.xslfOnly;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
-
-import java.awt.geom.Rectangle2D;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.poi.sl.usermodel.Slide;
-import org.apache.poi.sl.usermodel.SlideShow;
-import org.apache.poi.sl.usermodel.SlideShowFactory;
-import org.apache.poi.sl.usermodel.TableCell;
-import org.apache.poi.sl.usermodel.TableShape;
-import org.apache.poi.sl.usermodel.TextShape.TextDirection;
-import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.junit.Test;
-
-public class TestTable {
-    
-    @Test
-    public void colWidthRowHeight() throws IOException {
-        assumeFalse(xslfOnly());
-
-        // Test of table dimensions of same slideshow saved as ppt/x
-        // to check if both return similar (points) value
-        SlideShow<?,?> ppt = openSampleSlideshow("table_test.ppt");
-        TableShape<?,?> ts = (TableShape<?,?>)ppt.getSlides().get(0).getShapes().get(0);
-
-        SlideShow<?,?> pptx = openSampleSlideshow("table_test.pptx");
-        TableShape<?,?> tsx = (TableShape<?,?>)pptx.getSlides().get(0).getShapes().get(0);
-        
-        // assume table shape should be equal to itself
-        confirmTableShapeEqual(ts, ts);
-        confirmTableShapeEqual(tsx, tsx);
-        
-        // assert ppt and pptx versions of the same table have the same shape
-        confirmTableShapeEqual(ts, tsx);
-        
-        // change row height and validate again
-        tsx.setRowHeight(1, 50);
-        ts.setRowHeight(1, 50);
-        confirmTableShapeEqual(ts, tsx);
-        
-        pptx.close();
-        ppt.close();
-    }
-    
-    private void confirmTableShapeEqual(TableShape<?,?> tableA, TableShape<?,?> tableB) {
-        int cols = tableA.getNumberOfColumns();
-        int rows = tableA.getNumberOfRows();
-        
-        int colsx = tableB.getNumberOfColumns();
-        int rowsx = tableB.getNumberOfRows();
-        
-        assertEquals("tables should have same number of columns", cols, colsx);
-        assertEquals("tables should have same number of rows", rows, rowsx);
-        
-        for (int i=0; i<cols; i++) {
-            assertEquals("Width of column " + i + " should be equal",
-                    tableA.getColumnWidth(i), tableB.getColumnWidth(i), 0.2);
-        }
-
-        for (int i=0; i<rows; i++) {
-            assertEquals("Height of row " + i + " should be equal",
-                    tableA.getRowHeight(i), tableB.getRowHeight(i), 0.3);
-        }
-    }
-
-    @Test
-    public void directionHSLF() throws IOException, ReflectiveOperationException {
-        assumeFalse(xslfOnly());
-        SlideShow<?,?> ppt1 = (SlideShow<?,?>)Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow").newInstance();
-        testTextDirection(ppt1);
-        ppt1.close();
-    }
-    
-    @Test
-    public void directionXSLF() throws IOException {
-        SlideShow<?,?> ppt1 = new XMLSlideShow();
-        testTextDirection(ppt1);
-        ppt1.close();
-    }
-    
-    private void testTextDirection(SlideShow<?,?> ppt1) throws IOException {
-
-        TextDirection[] tds = {
-                TextDirection.HORIZONTAL,
-                TextDirection.VERTICAL,
-                TextDirection.VERTICAL_270,
-                // TextDirection.STACKED is not supported on HSLF
-        };
-        
-        TableShape<?,?> tbl1 = ppt1.createSlide().createTable(1, 3);
-        tbl1.setAnchor(new Rectangle2D.Double(50, 50, 200, 200));
-    
-        int col = 0;
-        for (TextDirection td : tds) {
-            TableCell<?,?> c = tbl1.getCell(0, col++);
-            if (c != null) {
-                c.setTextDirection(td);
-                c.setText("bla");
-            }
-        }
-        
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        ppt1.write(bos);
-        ppt1.close();
-        
-        InputStream is = new ByteArrayInputStream(bos.toByteArray());
-        SlideShow<?,?> ppt2 = SlideShowFactory.create(is);
-        TableShape<?,?> tbl2 = (TableShape<?,?>)ppt2.getSlides().get(0).getShapes().get(0);
-        
-        col = 0;
-        for (TextDirection td : tds) {
-            TableCell<?,?> c = tbl2.getCell(0, col++);
-            assertEquals(td, c.getTextDirection());
-        }
-        ppt2.close();
-    }
-    
-    @Test
-    public void tableSpan() throws IOException {
-        String[] files = (xslfOnly()) ? new String[]{"bug60993.pptx"} : new String[]{"bug60993.pptx", "bug60993.ppt"};
-        for (String f : files) {
-            SlideShow<?,?> ppt = openSampleSlideshow(f);
-            Slide<?,?> slide = ppt.getSlides().get(0);
-            TableShape<?,?> ts = (TableShape<?,?>)slide.getShapes().get(0);
-            int cols = ts.getNumberOfColumns();
-            int rows = ts.getNumberOfRows();
-            for (int r=0; r<rows; r++) {
-                for (int c=0; c<cols; c++) {
-                    TableCell<?,?> tc = ts.getCell(r, c);
-                    int rc = r*10+c;
-                    String msg = f+" (r"+r+",c"+c+")";
-                    switch (rc) {
-                        case 22:
-                        case 51:
-                            if (f.endsWith("ppt")) {
-                                assertNull(msg, tc);
-                            } else {
-                                assertNotNull(msg, tc);
-                                assertTrue(msg, tc.isMerged());
-                            }
-                            break;
-                        case 21:
-                            assertNotNull(msg, tc);
-                            assertEquals(msg, 1, tc.getRowSpan());
-                            assertEquals(msg, 2, tc.getGridSpan());
-                            assertFalse(msg, tc.isMerged());
-                            break;
-                        case 41:
-                            assertNotNull(msg, tc);
-                            assertEquals(msg, 2, tc.getRowSpan());
-                            assertEquals(msg, 1, tc.getGridSpan());
-                            assertFalse(msg, tc.isMerged());
-                            break;
-                        default:
-                            assertNotNull(msg, tc);
-                            assertEquals(msg, 1, tc.getRowSpan());
-                            assertEquals(msg, 1, tc.getGridSpan());
-                            assertFalse(msg, tc.isMerged());
-                            break;
-                    }
-                }
-            }
-            ppt.close();
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/sl/draw/TestDrawPictureShape.java b/src/ooxml/testcases/org/apache/poi/sl/draw/TestDrawPictureShape.java
deleted file mode 100644 (file)
index 8534610..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-package org.apache.poi.sl.draw;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeFalse;
-
-import java.awt.Dimension;
-import java.awt.geom.Rectangle2D;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.sl.usermodel.PictureData;
-import org.apache.poi.sl.usermodel.PictureShape;
-import org.apache.poi.sl.usermodel.RectAlign;
-import org.apache.poi.sl.usermodel.Shape;
-import org.apache.poi.sl.usermodel.Slide;
-import org.apache.poi.sl.usermodel.SlideShow;
-import org.apache.poi.sl.usermodel.SlideShowFactory;
-import org.apache.poi.util.Units;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-public class TestDrawPictureShape {
-    final static POIDataSamples ssSamples = POIDataSamples.getSlideShowInstance();
-
-    private static boolean xslfOnly;
-
-    @BeforeClass
-    public static void checkHslf() {
-        try {
-            Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow");
-        } catch (Exception e) {
-            xslfOnly = true;
-        }
-    }
-
-    /** a generic way to open a sample slideshow document **/
-    public static SlideShow<?,?> openSampleDocument(String sampleName) throws IOException {
-        try (InputStream is = ssSamples.openResourceAsStream(sampleName)) {
-            return SlideShowFactory.create(is);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Test
-    public void testResizeHSLF() throws IOException {
-        assumeFalse(xslfOnly);
-        testResize("pictures.ppt");
-    }
-
-    @Test
-    public void testResizeXSLF() throws IOException {
-        testResize("shapes.pptx");
-    }
-
-
-    public void testResize(String file) throws IOException {
-        SlideShow<?,?> ss = openSampleDocument(file);
-
-        Slide<?,?> slide = ss.getSlides().get(0);
-        PictureShape<?,?> picShape = null;
-        for (Shape<?,?> shape : slide.getShapes()) {
-            if (shape instanceof PictureShape) {
-                picShape = (PictureShape<?,?>)shape;
-                break;
-            }
-        }
-        assertNotNull(picShape);
-        PictureData pd = picShape.getPictureData();
-        Dimension dimPd = pd.getImageDimension();
-        new DrawPictureShape(picShape).resize();
-        Dimension dimShape = new Dimension(
-            (int)picShape.getAnchor().getWidth(),
-            (int)picShape.getAnchor().getHeight()
-        );
-        assertEquals(dimPd, dimShape);
-
-        double newWidth = (dimPd.getWidth()*(100d/dimPd.getHeight()));
-        // ... -1 is a rounding error
-        Rectangle2D expRect = new Rectangle2D.Double(rbf(50+300-newWidth, picShape), 50, rbf(newWidth, picShape), 100);
-        Rectangle2D target = new Rectangle2D.Double(50,50,300,100);
-        new DrawPictureShape(picShape).resize(target, RectAlign.BOTTOM_RIGHT);
-        Rectangle2D actRect = picShape.getAnchor();
-        assertEquals(expRect.getX(), actRect.getX(), .0001);
-        assertEquals(expRect.getY(), actRect.getY(), .0001);
-        assertEquals(expRect.getWidth(), actRect.getWidth(), .0001);
-        assertEquals(expRect.getHeight(), actRect.getHeight(), .0001);
-        ss.close();
-    }
-
-    // round back and forth - points -> master -> points
-    static double rbf(double val, PictureShape<?,?> picShape) {
-        if (picShape.getClass().getName().contains("HSLF")) {
-            return Units.masterToPoints(Units.pointsToMaster(val));
-        } else {
-            return val;
-        }
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/sl/tests/SLCommonUtils.java b/src/ooxml/testcases/org/apache/poi/sl/tests/SLCommonUtils.java
new file mode 100644 (file)
index 0000000..3c3d243
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  ====================================================================
+ *    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.sl.tests;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.SlideShowFactory;
+
+public class SLCommonUtils {
+    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
+
+    /** a generic way to open a sample slideshow document **/
+    public static SlideShow<?,?> openSampleSlideshow(String sampleName) throws IOException {
+        try (InputStream is = _slTests.openResourceAsStream(sampleName)) {
+            return SlideShowFactory.create(is);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tests, if the scratchpad classes are on the classpath
+     *
+     * @return true, if only xslf is on the classpath, and false, if both classpaths
+     *    (XSLF and HSLF) can be used/referenced
+     */
+    public static boolean xslfOnly() {
+        try {
+            Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow");
+            return false;
+        } catch (Exception e) {
+            return true;
+        }
+    }
+
+}
diff --git a/src/ooxml/testcases/org/apache/poi/sl/tests/TestFonts.java b/src/ooxml/testcases/org/apache/poi/sl/tests/TestFonts.java
new file mode 100644 (file)
index 0000000..2b9963e
--- /dev/null
@@ -0,0 +1,138 @@
+/* ====================================================================
+   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.sl.tests;
+
+import static org.apache.poi.sl.tests.SLCommonUtils.xslfOnly;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontFormatException;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.common.usermodel.fonts.FontGroup;
+import org.apache.poi.sl.draw.Drawable;
+import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
+import org.apache.poi.sl.usermodel.TextBox;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.sl.usermodel.TextRun;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+/**
+ * Test rendering - specific to font handling
+ */
+public class TestFonts {
+    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
+
+    private static final String JPTEXT =
+        "\u3061\u3087\u3063\u3068\u65E9\u3044\u3051\u3069T\u30B7\u30E3\u30C4\u304C\u7740\u305F\u304F\u306A" +
+        "\u308B\u5B63\u7BC0\u2661\u304A\u6BCD\u3055\u3093\u306E\u5F71\u97FF\u304B\u3001\u975E\u5E38\u306B" +
+        "\u6050\u7ADC\u304C\u5927\u597D\u304D\u3067\u3059\u3002\u3082\u3046\u98FC\u3044\u305F\u3044\u304F" +
+        "\u3089\u3044\u5927\u597D\u304D\u3067\u3059\u3002#\u30B8\u30E5\u30E9\u30B7\u30C3\u30AF\u30EF\u30FC" +
+        "\u30EB\u30C9 \u306E\u30E9\u30D7\u30C8\u30EB4\u59C9\u59B9\u3068\u304B\u6FC0\u7684\u306B\u53EF\u611B" +
+        "\u304F\u3066\u53EF\u611B\u304F\u3066\u53EF\u611B\u304F\u3066\u53EF\u611B\u3044\u3067\u3059\u3002" +
+        "\u3081\u308D\u3081\u308D\u3001\u5927\u597D\u304D\u2661\u304A\u6BCD\u3055\u3093\u3082\u6050\u7ADC" +
+        "\u304C\u597D\u304D\u3067\u3001\u5C0F\u3055\u3044\u9803\u3001\u53E4\u4EE3\u751F\u7269\u306E\u56F3" +
+        "\u9451\u3092\u4E00\u7DD2\u306B\u898B\u3066\u305F\u306E\u601D\u3044\u51FA\u3059\u301C\u3068\u3044";
+
+    private static final String[] INIT_FONTS = {"mona.ttf"};
+
+    @BeforeClass
+    public static void initGE() throws FontFormatException, IOException {
+        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        for (String s : INIT_FONTS) {
+            Font font = Font.createFont(Font.TRUETYPE_FONT, _slTests.getFile(s));
+            ge.registerFont(font);
+        }
+    }
+
+    @Test
+    public void resizeToFitTextHSLF() throws IOException, ReflectiveOperationException {
+        assumeFalse(xslfOnly());
+        SlideShow<?,?> ppt = (SlideShow<?,?>)Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow").newInstance();
+        resizeToFitText(ppt);
+        ppt.close();
+    }
+
+    @Test
+    public void resizeToFitTextXSLF() throws IOException {
+        SlideShow<?,?> ppt = new XMLSlideShow();
+        resizeToFitText(ppt);
+        ppt.close();
+    }
+
+    private void resizeToFitText(SlideShow<?,?> slideshow) throws IOException {
+        Slide<?,?> sld = slideshow.createSlide();
+        TextBox<?,?> tb = sld.createTextBox();
+        tb.setAnchor(new Rectangle(50, 50, 200, 50));
+        tb.setStrokeStyle(Color.black, LineDash.SOLID, 3);
+        tb.setText(JPTEXT);
+
+        setFont(tb, "NoSuchFont", FontGroup.LATIN);
+
+        Dimension pgsize = slideshow.getPageSize();
+        int width = (int)pgsize.getWidth();
+        int height = (int)pgsize.getHeight();
+
+        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+        Graphics2D graphics = img.createGraphics();
+
+        Map<String,String> fallbackMap = new HashMap<>();
+        fallbackMap.put("NoSuchFont", "Mona");
+        // in XSLF the fonts default to the theme fonts (Calibri), if the font group is not overridden
+        // see XSLFTextRun.XSLFTextInfo.getCTTextFont
+        fallbackMap.put("Calibri", "Mona");
+        graphics.setRenderingHint(Drawable.FONT_FALLBACK, fallbackMap);
+        graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+
+        tb.resizeToFitText(graphics);
+        graphics.dispose();
+
+        Rectangle2D anc = tb.getAnchor();
+        // ignore font metrics differences on windows / linux (... hopefully ...)
+        int tbHeight = (int)anc.getHeight();
+        assertTrue(tbHeight > 100);
+    }
+
+    private void setFont(TextBox<?,?> tb, String fontFamily, FontGroup fontGroup) {
+        // TODO: set east asian font family - MS Office uses "MS Mincho" or "MS Gothic" as a fallback
+        // see https://stackoverflow.com/questions/26063828 for good explanation about the font metrics
+        // differences on different environments
+        for (TextParagraph<?,?,? extends TextRun> p : tb.getTextParagraphs()) {
+            for (TextRun r : p.getTextRuns()) {
+                r.setFontFamily(fontFamily, fontGroup);
+            }
+        }
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/sl/tests/TestHeadersFooters.java b/src/ooxml/testcases/org/apache/poi/sl/tests/TestHeadersFooters.java
new file mode 100644 (file)
index 0000000..ceb65d6
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *  ====================================================================
+ *    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.sl.tests;
+
+import static org.apache.poi.sl.tests.SLCommonUtils.openSampleSlideshow;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.sl.usermodel.Shape;
+import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.sl.usermodel.TextShape;
+import org.junit.Test;
+
+public class TestHeadersFooters {
+    @Test
+    public void bug58144c() throws IOException {
+        SlideShow<?,?> ppt = openSampleSlideshow("bug58144-headers-footers-2007.pptx");
+        testSlideShow(ppt);
+        ppt.close();
+    }
+
+    private void testSlideShow(SlideShow<?,?> ppt) {
+        Slide<?,?> sl =  ppt.getSlides().get(0);
+
+        List<? extends Shape<?,?>> shapes = sl.getShapes();
+        TextShape<?,?> ts0 = (TextShape<?,?>)shapes.get(0);
+        assertEquals("Test file", ts0.getText());
+        TextShape<?,?> ts1 = (TextShape<?,?>)shapes.get(1);
+        assertEquals("Has some text in the headers and footers", ts1.getText());
+        TextShape<?,?> ts2 = (TextShape<?,?>)shapes.get(2);
+        assertEquals("Slide footer", ts2.getText());
+        List<? extends TextParagraph<?,?,?>> ltp = ts2.getTextParagraphs();
+        assertTrue(ltp.get(0).isHeaderOrFooter());
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/sl/tests/TestOleShape.java b/src/ooxml/testcases/org/apache/poi/sl/tests/TestOleShape.java
new file mode 100644 (file)
index 0000000..f652bcc
--- /dev/null
@@ -0,0 +1,223 @@
+/* ====================================================================
+   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.sl.tests;
+
+import static org.apache.poi.sl.tests.SLCommonUtils.xslfOnly;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.EXCEL_V12;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.EXCEL_V8;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.PDF;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.WORD_V12;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.WORD_V8;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+
+import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.POIDocument;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.poifs.storage.RawDataUtil;
+import org.apache.poi.sl.usermodel.ObjectMetaData;
+import org.apache.poi.sl.usermodel.ObjectShape;
+import org.apache.poi.sl.usermodel.PictureData;
+import org.apache.poi.sl.usermodel.PictureData.PictureType;
+import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.SlideShowFactory;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TestOleShape {
+    private static final String PDF_SAMPLE =
+        "H4sIAAAAAAAAAJWUezRUWxzHe+o2FXncVtxLpxi3FPOeKYspjMdM5J1S4TTOaDIzxzpzJo9CUrnrSiUxIeT" +
+        "9jB7yqInihrhepTwqt1AT5VZCC7XcY0LWcv+5Z521zz6fvX+/vb/7t9cX78CyMiQZ0XD4W4OFEzgKQATgg4" +
+        "dxJiYAwRYS+aCHACqGnHAAABCs+AIUQrCvAEQhFsSFvSEck4kTowgECnEBl6E4OxGesfLkl2Bc0g5V/MCHt" +
+        "duqroTFC27YIKGAp+OL5Ou1SsmebA1XvciLk+Ucg84aLclQZhRZmh0amrG9Ina4t7Lh+ZCAHyezsg/NXsZg" +
+        "vuPw8NIedsrI2sZlz2vfhLkZfIgfMr4zFvTrmfbRgMmPw1UTvWk+r4MCZfLtj2WPPStVJ0P2PiKkxo+YnJ5" +
+        "Ua7v5UnefkB9ev0vSR37a8NrsC2lApaLp7086wS3Lzi2LqB3TMW2POrdRRUYMFYWs8vBo/kSQ6dYXpR6rxM" +
+        "UXM0vqu4arpe5dha7XS5MYS5P1arVG653sb8pXqReVw/TfjK8R3q4Z7X7Uk9dZ2Bcl8Wpmsl80Xf1QTOxe3" +
+        "Nutwus0kYge1LoHvgKLbc/f6WvdcsBfS9ctU3vSaneHNm0w/uhrm0Zett5O83s2xh2Gm8WZfWJ+/CNWruZ2" +
+        "cap8tR2/U9bAfRBbYt3PL9jvb3+0usqSF6vfrFuEq8Hf6jgrx/fERpZJEjKbHtJ11jCdUwI7Oc8QrmZf2pr" +
+        "L43WJn1mlT1ydV+QbrndcdN3qSEnicVhmoJyfWyprUEsIZlPyvi0tiEy7FzkOnqlE/qC6xFSpyg0E8tODa7" +
+        "qiKX61hMxRkZt73ITLWIHwtZtj71NbS4/BgKHnssOMcXOp1aacX4A//V+VFN4TWl6QryxdkcAp79BZcipmP" +
+        "OWOWkS6KhqUWlG+yCCxVMMtfW+9e56++gKHYEs9PNJztTI6KtyfOCDPOBppt3udRs3NpGrKfrs3i3Nivtrs" +
+        "VTl5LFerXZlTbf5XumbeYsOfwnve5ksEjKy6s1Z78rpbeJq7biTdzWwU3vhZ1GqkYb9D+t6mYvWLhXn6FWi" +
+        "c60VWpbBtVYHLQkmbh6Txwm6Ul3LbNW/Hs5FtLnlNX3fsAX2jPdlOI5W3HDIcm2MyNiR39rdyHlpwusjoOj" +
+        "I3IKfgPMILSzHZInmQaWyUFXEi0bHsCLX8pm9Gzl2vou7E3rrkPYdt1EwW3R5Qcg8rwzk88c1p13l8v+WkY" +
+        "75FHeS7XrvRsHgLy+wfr2EBRfNJ/4UVhUrihRqDktXciPGxWv1eXs396/0lqWG3YtU/A+D90hrT46cumSUN" +
+        "rBdG0G2Knn3T9Kw0X96vbhxMyr92uqUNOa4aEnGqP8us6GULm7mIyFKuxnOW2MZEEuKXmOpxnnqlwiMn+ju" +
+        "Xu+inC5mpG9oesxKkhcJq9bra5vR3H7l10hGbAxqu6t0LvHzaDnPIp/zeu0iXj1NNtVc+cMyUsH18u7TGXJ" +
+        "XiL4W3tqaL2mq6zkgXWB6kOTB3RxW8PHAOvzfaufDptdg7qmZlEcrUzbd5jKtVb85Sr9jaMT8a3y2Q30+3/" +
+        "FrsfGZDblh/mYnHhCg3ekm2q1JIYEVCd9rv42PNb9RFpuSsa4MNE0GfdSYDv6lsudikg4NE3tNugfWmfIY6" +
+        "7TeYvZCItG0zmDxrQwrjsQxArZ1RzHSA72CKgURgyqQszAASQOCCWItZETaAtdg7nYc2x85cAv0ggOAA+kC" +
+        "KnA4gAolQLGzG3ewgbz5oDgcA+zBEBEhUkhGDQiZvpc3tHlBMtYBFKBYsBiiz0dYILPGbs73vqynoDHLGKA" +
+        "KKxH5TK3MDZzAbQBEJNPNngc1iQUf4XMjJ2nxazxR3gsSwBOFCYoCsWPOHRtJ/ahQronbyvcWYnqljcJrdu" +
+        "2RK9pwE9DkJLLDioDACbOSCfAQGSEYkqhGJCGw8hKJ+xgSCgvogoN8hPldsBCM+mzZ9P0wE9pZwof8V92MD" +
+        "jHkKLEAUFMA+04XC1EzX6UdMAALxcERgK444+wB0Go1CA3jANCNRGdj1UoyIZhlpPsMobf48GmkeI1Pp8xi" +
+        "Nsm0eo9O3/mAoAvIFEKIQ58wPgrAtK+oJwyjAmL0+bBEPBugzGsUoiKAKhSQGmYjD4y3trXD/AmBc9IeqBwAA";
+
+    enum Api { HSLF, XSLF }
+
+
+    @Parameter(value = 0)
+    public Api api;
+    @Parameter(value = 1)
+    public ObjectMetaData.Application app;
+
+
+    private static File pictureFile;
+
+    @BeforeClass
+    public static void initPicture() {
+        pictureFile = POIDataSamples.getSlideShowInstance().getFile("wrench.emf");
+    }
+
+
+    @Parameters(name="{0} {1}")
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] {
+            { Api.HSLF, EXCEL_V8 },
+            { Api.HSLF, WORD_V8 },
+            { Api.HSLF, PDF },
+            { Api.XSLF, EXCEL_V12 },
+            { Api.XSLF, WORD_V12 },
+            { Api.XSLF, PDF },
+        });
+    }
+
+    @Test
+    public void embedData() throws IOException, InvalidFormatException, ReflectiveOperationException {
+        final ByteArrayInputStream pptBytes;
+        try (SlideShow<?,?> ppt = createSlideShow()) {
+            final PictureData picData = ppt.addPicture(pictureFile,  PictureType.EMF);
+            final Slide<?,?> slide = ppt.createSlide();
+            final ObjectShape<?,?> oleShape = slide.createOleShape(picData);
+            oleShape.setAnchor(new Rectangle2D.Double(100,100,100,100));
+            try (OutputStream os = oleShape.updateObjectData(app, null)) {
+                fillOleData(os);
+            }
+            final ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
+            ppt.write(bos);
+            pptBytes = new ByteArrayInputStream(bos.toByteArray());
+        }
+        try (SlideShow<?,?> ppt = SlideShowFactory.create(pptBytes)) {
+            final ObjectShape<?,?> oleShape = (ObjectShape<?,?>)ppt.getSlides().get(0).getShapes().get(0);
+            try (InputStream bis = oleShape.readObjectData()) {
+                validateOleData(bis);
+            }
+        }
+    }
+
+    private SlideShow<?,?> createSlideShow() throws ReflectiveOperationException {
+        if (api == Api.XSLF) {
+            return new XMLSlideShow();
+        } else {
+            assumeFalse(xslfOnly());
+            return (SlideShow<?,?>)Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow").newInstance();
+        }
+    }
+
+
+    private void fillOleData(final OutputStream out) throws IOException {
+        switch (app) {
+        case EXCEL_V8:
+        case EXCEL_V12:
+            try (Workbook wb = (app == EXCEL_V12) ? new XSSFWorkbook() : new HSSFWorkbook()) {
+                wb.createSheet().createRow(0).createCell(0).setCellValue("test me");
+                wb.write(out);
+            }
+            break;
+        case WORD_V8:
+            try (InputStream is = POIDataSamples.getDocumentInstance().openResourceAsStream("simple.doc")) {
+                IOUtils.copy(is, out);
+            }
+            break;
+        case WORD_V12:
+            try (XWPFDocument doc = new XWPFDocument()) {
+                doc.createParagraph().createRun().setText("Test me");
+                doc.write(out);
+            }
+            break;
+        case PDF:
+            out.write(RawDataUtil.decompress(PDF_SAMPLE));
+            break;
+        default:
+        case CUSTOM:
+            fail("not implemented");
+            break;
+        }
+    }
+
+    private void validateOleData(final InputStream in) throws IOException, InvalidFormatException, ReflectiveOperationException {
+        switch (app) {
+        case EXCEL_V8:
+        case EXCEL_V12:
+            try (Workbook wb = WorkbookFactory.create(in)) {
+                assertEquals("test me", wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
+            }
+            break;
+        case WORD_V8:
+            Class<? extends POIDocument> clazz = (Class<? extends POIDocument>)Class.forName("org.apache.poi.hwpf.HWPFDocument");
+            Constructor<? extends POIDocument> con = clazz.getDeclaredConstructor(InputStream.class);
+            Method m = clazz.getMethod("getDocumentText");
+            try (POIDocument doc = con.newInstance(in)) {
+                assertEquals("This is a simple file created with Word 97-SR2.\r", m.invoke(doc));
+            }
+            break;
+        case WORD_V12:
+            try (XWPFDocument doc = new XWPFDocument(in)) {
+                assertEquals("Test me", doc.getParagraphs().get(0).getText());
+            }
+            break;
+        case PDF:
+            final byte[] expected = RawDataUtil.decompress(PDF_SAMPLE);
+            final byte[] actual = IOUtils.toByteArray(in);
+            assertArrayEquals(expected, actual);
+            break;
+        default:
+        case CUSTOM:
+            fail("not implemented");
+            break;
+        }
+
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/sl/tests/TestSlide.java b/src/ooxml/testcases/org/apache/poi/sl/tests/TestSlide.java
new file mode 100644 (file)
index 0000000..47494b3
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  ====================================================================
+ *    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.sl.tests;
+
+import static org.apache.poi.sl.tests.SLCommonUtils.xslfOnly;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.SlideShowFactory;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.junit.Test;
+
+public class TestSlide {
+
+    @Test
+    public void hideHSLF() throws IOException, ReflectiveOperationException {
+        assumeFalse(xslfOnly());
+        SlideShow<?,?> ppt1 = (SlideShow<?,?>)Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow").newInstance();
+        hideSlide(ppt1);
+        ppt1.close();
+    }
+
+    @Test
+    public void hideXSLF() throws IOException {
+        SlideShow<?,?> ppt1 = new XMLSlideShow();
+        hideSlide(ppt1);
+        ppt1.close();
+    }
+
+    private void hideSlide(SlideShow<?,?> ppt1) throws IOException {
+        ppt1.createSlide().setHidden(true);
+        ppt1.createSlide();
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ppt1.write(bos);
+        ppt1.close();
+
+        InputStream is = new ByteArrayInputStream(bos.toByteArray());
+        SlideShow<?,?> ppt2 = SlideShowFactory.create(is);
+
+        Boolean[] hiddenState = ppt2.getSlides().stream().map(e -> e.isHidden()).toArray(Boolean[]::new);
+
+        assertTrue(hiddenState[0]);
+        assertFalse(hiddenState[1]);
+
+        ppt2.close();
+    }
+}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/sl/tests/TestTable.java b/src/ooxml/testcases/org/apache/poi/sl/tests/TestTable.java
new file mode 100644 (file)
index 0000000..fd31762
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ *  ====================================================================
+ *    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.sl.tests;
+
+import static org.apache.poi.sl.tests.SLCommonUtils.openSampleSlideshow;
+import static org.apache.poi.sl.tests.SLCommonUtils.xslfOnly;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+
+import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.SlideShowFactory;
+import org.apache.poi.sl.usermodel.TableCell;
+import org.apache.poi.sl.usermodel.TableShape;
+import org.apache.poi.sl.usermodel.TextShape.TextDirection;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.junit.Test;
+
+public class TestTable {
+
+    @Test
+    public void colWidthRowHeight() throws IOException {
+        assumeFalse(xslfOnly());
+
+        // Test of table dimensions of same slideshow saved as ppt/x
+        // to check if both return similar (points) value
+        SlideShow<?,?> ppt = openSampleSlideshow("table_test.ppt");
+        TableShape<?,?> ts = (TableShape<?,?>)ppt.getSlides().get(0).getShapes().get(0);
+
+        SlideShow<?,?> pptx = openSampleSlideshow("table_test.pptx");
+        TableShape<?,?> tsx = (TableShape<?,?>)pptx.getSlides().get(0).getShapes().get(0);
+
+        // assume table shape should be equal to itself
+        confirmTableShapeEqual(ts, ts);
+        confirmTableShapeEqual(tsx, tsx);
+
+        // assert ppt and pptx versions of the same table have the same shape
+        confirmTableShapeEqual(ts, tsx);
+
+        // change row height and validate again
+        tsx.setRowHeight(1, 50);
+        ts.setRowHeight(1, 50);
+        confirmTableShapeEqual(ts, tsx);
+
+        pptx.close();
+        ppt.close();
+    }
+
+    private void confirmTableShapeEqual(TableShape<?,?> tableA, TableShape<?,?> tableB) {
+        int cols = tableA.getNumberOfColumns();
+        int rows = tableA.getNumberOfRows();
+
+        int colsx = tableB.getNumberOfColumns();
+        int rowsx = tableB.getNumberOfRows();
+
+        assertEquals("tables should have same number of columns", cols, colsx);
+        assertEquals("tables should have same number of rows", rows, rowsx);
+
+        for (int i=0; i<cols; i++) {
+            assertEquals("Width of column " + i + " should be equal",
+                    tableA.getColumnWidth(i), tableB.getColumnWidth(i), 0.2);
+        }
+
+        for (int i=0; i<rows; i++) {
+            assertEquals("Height of row " + i + " should be equal",
+                    tableA.getRowHeight(i), tableB.getRowHeight(i), 0.3);
+        }
+    }
+
+    @Test
+    public void directionHSLF() throws IOException, ReflectiveOperationException {
+        assumeFalse(xslfOnly());
+        SlideShow<?,?> ppt1 = (SlideShow<?,?>)Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow").newInstance();
+        testTextDirection(ppt1);
+        ppt1.close();
+    }
+
+    @Test
+    public void directionXSLF() throws IOException {
+        SlideShow<?,?> ppt1 = new XMLSlideShow();
+        testTextDirection(ppt1);
+        ppt1.close();
+    }
+
+    private void testTextDirection(SlideShow<?,?> ppt1) throws IOException {
+
+        TextDirection[] tds = {
+                TextDirection.HORIZONTAL,
+                TextDirection.VERTICAL,
+                TextDirection.VERTICAL_270,
+                // TextDirection.STACKED is not supported on HSLF
+        };
+
+        TableShape<?,?> tbl1 = ppt1.createSlide().createTable(1, 3);
+        tbl1.setAnchor(new Rectangle2D.Double(50, 50, 200, 200));
+
+        int col = 0;
+        for (TextDirection td : tds) {
+            TableCell<?,?> c = tbl1.getCell(0, col++);
+            if (c != null) {
+                c.setTextDirection(td);
+                c.setText("bla");
+            }
+        }
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ppt1.write(bos);
+        ppt1.close();
+
+        InputStream is = new ByteArrayInputStream(bos.toByteArray());
+        SlideShow<?,?> ppt2 = SlideShowFactory.create(is);
+        TableShape<?,?> tbl2 = (TableShape<?,?>)ppt2.getSlides().get(0).getShapes().get(0);
+
+        col = 0;
+        for (TextDirection td : tds) {
+            TableCell<?,?> c = tbl2.getCell(0, col++);
+            assertEquals(td, c.getTextDirection());
+        }
+        ppt2.close();
+    }
+
+    @Test
+    public void tableSpan() throws IOException {
+        String[] files = (xslfOnly()) ? new String[]{"bug60993.pptx"} : new String[]{"bug60993.pptx", "bug60993.ppt"};
+        for (String f : files) {
+            SlideShow<?,?> ppt = openSampleSlideshow(f);
+            Slide<?,?> slide = ppt.getSlides().get(0);
+            TableShape<?,?> ts = (TableShape<?,?>)slide.getShapes().get(0);
+            int cols = ts.getNumberOfColumns();
+            int rows = ts.getNumberOfRows();
+            for (int r=0; r<rows; r++) {
+                for (int c=0; c<cols; c++) {
+                    TableCell<?,?> tc = ts.getCell(r, c);
+                    int rc = r*10+c;
+                    String msg = f+" (r"+r+",c"+c+")";
+                    switch (rc) {
+                        case 22:
+                        case 51:
+                            if (f.endsWith("ppt")) {
+                                assertNull(msg, tc);
+                            } else {
+                                assertNotNull(msg, tc);
+                                assertTrue(msg, tc.isMerged());
+                            }
+                            break;
+                        case 21:
+                            assertNotNull(msg, tc);
+                            assertEquals(msg, 1, tc.getRowSpan());
+                            assertEquals(msg, 2, tc.getGridSpan());
+                            assertFalse(msg, tc.isMerged());
+                            break;
+                        case 41:
+                            assertNotNull(msg, tc);
+                            assertEquals(msg, 2, tc.getRowSpan());
+                            assertEquals(msg, 1, tc.getGridSpan());
+                            assertFalse(msg, tc.isMerged());
+                            break;
+                        default:
+                            assertNotNull(msg, tc);
+                            assertEquals(msg, 1, tc.getRowSpan());
+                            assertEquals(msg, 1, tc.getGridSpan());
+                            assertFalse(msg, tc.isMerged());
+                            break;
+                    }
+                }
+            }
+            ppt.close();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/sl/tests/draw/TestDrawPictureShape.java b/src/ooxml/testcases/org/apache/poi/sl/tests/draw/TestDrawPictureShape.java
new file mode 100644 (file)
index 0000000..944ff42
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  ====================================================================
+ *    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.sl.tests.draw;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeFalse;
+
+import java.awt.Dimension;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.sl.draw.DrawPictureShape;
+import org.apache.poi.sl.usermodel.PictureData;
+import org.apache.poi.sl.usermodel.PictureShape;
+import org.apache.poi.sl.usermodel.RectAlign;
+import org.apache.poi.sl.usermodel.Shape;
+import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.SlideShowFactory;
+import org.apache.poi.util.Units;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestDrawPictureShape {
+    final static POIDataSamples ssSamples = POIDataSamples.getSlideShowInstance();
+
+    private static boolean xslfOnly;
+
+    @BeforeClass
+    public static void checkHslf() {
+        try {
+            Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow");
+        } catch (Exception e) {
+            xslfOnly = true;
+        }
+    }
+
+    /** a generic way to open a sample slideshow document **/
+    public static SlideShow<?,?> openSampleDocument(String sampleName) throws IOException {
+        try (InputStream is = ssSamples.openResourceAsStream(sampleName)) {
+            return SlideShowFactory.create(is);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Test
+    public void testResizeHSLF() throws IOException {
+        assumeFalse(xslfOnly);
+        testResize("pictures.ppt");
+    }
+
+    @Test
+    public void testResizeXSLF() throws IOException {
+        testResize("shapes.pptx");
+    }
+
+
+    public void testResize(String file) throws IOException {
+        SlideShow<?,?> ss = openSampleDocument(file);
+
+        Slide<?,?> slide = ss.getSlides().get(0);
+        PictureShape<?,?> picShape = null;
+        for (Shape<?,?> shape : slide.getShapes()) {
+            if (shape instanceof PictureShape) {
+                picShape = (PictureShape<?,?>)shape;
+                break;
+            }
+        }
+        assertNotNull(picShape);
+        PictureData pd = picShape.getPictureData();
+        Dimension dimPd = pd.getImageDimension();
+        new DrawPictureShape(picShape).resize();
+        Dimension dimShape = new Dimension(
+            (int)picShape.getAnchor().getWidth(),
+            (int)picShape.getAnchor().getHeight()
+        );
+        assertEquals(dimPd, dimShape);
+
+        double newWidth = (dimPd.getWidth()*(100d/dimPd.getHeight()));
+        // ... -1 is a rounding error
+        Rectangle2D expRect = new Rectangle2D.Double(rbf(50+300-newWidth, picShape), 50, rbf(newWidth, picShape), 100);
+        Rectangle2D target = new Rectangle2D.Double(50,50,300,100);
+        new DrawPictureShape(picShape).resize(target, RectAlign.BOTTOM_RIGHT);
+        Rectangle2D actRect = picShape.getAnchor();
+        assertEquals(expRect.getX(), actRect.getX(), .0001);
+        assertEquals(expRect.getY(), actRect.getY(), .0001);
+        assertEquals(expRect.getWidth(), actRect.getWidth(), .0001);
+        assertEquals(expRect.getHeight(), actRect.getHeight(), .0001);
+        ss.close();
+    }
+
+    // round back and forth - points -> master -> points
+    static double rbf(double val, PictureShape<?,?> picShape) {
+        if (picShape.getClass().getName().contains("HSLF")) {
+            return Units.masterToPoints(Units.pointsToMaster(val));
+        } else {
+            return val;
+        }
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/TestWorkbookFactory.java b/src/ooxml/testcases/org/apache/poi/ss/TestWorkbookFactory.java
deleted file mode 100644 (file)
index 731f581..0000000
+++ /dev/null
@@ -1,479 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
-import org.apache.poi.EmptyFileException;
-import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.openxml4j.opc.PackageAccess;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
-import org.apache.poi.util.SuppressForbidden;
-import org.apache.poi.util.TempFile;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbookFactory;
-import org.junit.Test;
-
-public final class TestWorkbookFactory {
-    private static final String xls = "SampleSS.xls";
-    private static final String xlsx = "SampleSS.xlsx";
-    private static final String[] xls_protected = new String[] {"password.xls", "password"};
-    private static final String[] xlsx_protected = new String[]{"protected_passtika.xlsx", "tika"};
-    private static final String txt = "SampleSS.txt";
-
-    private static final POILogger LOGGER = POILogFactory.getLogger(TestWorkbookFactory.class);
-
-    /**
-     * Closes the sample workbook read in from filename.
-     * Throws an exception if closing the workbook results in the file on disk getting modified.
-     *
-     * @param filename the sample workbook to read in
-     * @param wb the workbook to close
-     */
-    private static void assertCloseDoesNotModifyFile(String filename, Workbook wb) throws IOException {
-        final byte[] before = HSSFTestDataSamples.getTestDataFileContent(filename);
-        // FIXME: replace with wb.close() when bug 58779 is resolved
-        closeOrRevert(wb);
-        final byte[] after = HSSFTestDataSamples.getTestDataFileContent(filename);
-        assertArrayEquals(filename + " sample file was modified as a result of closing the workbook",
-                before, after);
-    }
-
-    /**
-     * bug 58779: Closing an XSSFWorkbook that was created with WorkbookFactory modifies the file
-     * FIXME: replace this method with wb.close() when bug 58779 is resolved.
-     *
-     * @param wb the workbook to close or revert
-     */
-    private static void closeOrRevert(Workbook wb) throws IOException {
-        if (wb instanceof HSSFWorkbook) {
-            wb.close();
-        }
-        else if (wb instanceof XSSFWorkbook) {
-            final XSSFWorkbook xwb = (XSSFWorkbook) wb;
-            if (PackageAccess.READ == xwb.getPackage().getPackageAccess()) {
-                xwb.close();
-            }
-            else {
-                // TODO: close() re-writes the sample-file?! Resort to revert() for now to close file handle...
-                LOGGER.log(POILogger.WARN,
-                        "reverting XSSFWorkbook rather than closing it to avoid close() modifying the file on disk. " +
-                        "Refer to bug 58779.");
-                xwb.getPackage().revert();
-            }
-        } else {
-            throw new RuntimeException("Unsupported workbook type");
-        }
-    }
-
-    @Test
-    public void testCreateNative() throws Exception {
-        Workbook wb;
-
-        // POIFS -> hssf
-        wb = WorkbookFactory.create(
-                new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream(xls))
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof HSSFWorkbook);
-        assertCloseDoesNotModifyFile(xls, wb);
-
-        wb = WorkbookFactory.create(
-                new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream(xls)).getRoot()
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof HSSFWorkbook);
-        assertCloseDoesNotModifyFile(xls, wb);
-
-        // Package -> xssf
-        wb = XSSFWorkbookFactory.create(
-                OPCPackage.open(
-                        HSSFTestDataSamples.openSampleFileStream(xlsx))
-        );
-        assertNotNull(wb);
-        //noinspection ConstantConditions
-        assertTrue(wb instanceof XSSFWorkbook);
-        assertCloseDoesNotModifyFile(xlsx, wb);
-    }
-
-    @Test
-    public void testCreateReadOnly() throws Exception {
-        Workbook wb;
-
-        // POIFS -> hssf
-        wb = WorkbookFactory.create(HSSFTestDataSamples.getSampleFile(xls), null, true);
-        assertNotNull(wb);
-        assertTrue(wb instanceof HSSFWorkbook);
-        assertCloseDoesNotModifyFile(xls, wb);
-
-        // Package -> xssf
-        wb = WorkbookFactory.create(HSSFTestDataSamples.getSampleFile(xlsx), null, true);
-        assertNotNull(wb);
-        assertTrue(wb instanceof XSSFWorkbook);
-        assertCloseDoesNotModifyFile(xlsx, wb);
-    }
-
-    /**
-     * Creates the appropriate kind of Workbook, but
-     *  checking the mime magic at the start of the
-     *  InputStream, then creating what's required.
-     */
-    @Test
-    public void testCreateGeneric() throws Exception {
-        Workbook wb;
-
-        // InputStream -> either
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.openSampleFileStream(xls)
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof HSSFWorkbook);
-        assertCloseDoesNotModifyFile(xls, wb);
-
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.openSampleFileStream(xlsx)
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof XSSFWorkbook);
-        assertCloseDoesNotModifyFile(xlsx, wb);
-
-        // File -> either
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.getSampleFile(xls)
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof HSSFWorkbook);
-        assertCloseDoesNotModifyFile(xls, wb);
-
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.getSampleFile(xlsx)
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof XSSFWorkbook);
-        assertCloseDoesNotModifyFile(xlsx, wb);
-
-        // Invalid type -> exception
-        final byte[] before = HSSFTestDataSamples.getTestDataFileContent(txt);
-        try {
-            try (InputStream stream = HSSFTestDataSamples.openSampleFileStream(txt)) {
-                wb = WorkbookFactory.create(stream);
-                assertNotNull(wb);
-            }
-            fail();
-        } catch(IOException e) {
-            // Good
-        }
-        final byte[] after = HSSFTestDataSamples.getTestDataFileContent(txt);
-        assertArrayEquals("Invalid type file was modified after trying to open the file as a spreadsheet",
-                before, after);
-    }
-
-    /**
-     * Check that the overloaded stream methods which take passwords work properly
-     */
-    @Test
-    public void testCreateWithPasswordFromStream() throws Exception {
-        Workbook wb;
-
-        // Unprotected, no password given, opens normally
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.openSampleFileStream(xls), null
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof HSSFWorkbook);
-        assertCloseDoesNotModifyFile(xls, wb);
-
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.openSampleFileStream(xlsx), null
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof XSSFWorkbook);
-        assertCloseDoesNotModifyFile(xlsx, wb);
-
-
-        // Unprotected, wrong password, opens normally
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.openSampleFileStream(xls), "wrong"
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof HSSFWorkbook);
-        assertCloseDoesNotModifyFile(xls, wb);
-
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.openSampleFileStream(xlsx), "wrong"
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof XSSFWorkbook);
-        assertCloseDoesNotModifyFile(xlsx, wb);
-
-
-        // Protected, correct password, opens fine
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.openSampleFileStream(xls_protected[0]), xls_protected[1]
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof HSSFWorkbook);
-        assertCloseDoesNotModifyFile(xls_protected[0], wb);
-
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.openSampleFileStream(xlsx_protected[0]), xlsx_protected[1]
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof XSSFWorkbook);
-        assertCloseDoesNotModifyFile(xlsx_protected[0], wb);
-
-
-        // Protected, wrong password, throws Exception
-        try {
-            wb = WorkbookFactory.create(
-                    HSSFTestDataSamples.openSampleFileStream(xls_protected[0]), "wrong"
-            );
-            assertCloseDoesNotModifyFile(xls_protected[0], wb);
-            fail("Shouldn't be able to open with the wrong password");
-        } catch (EncryptedDocumentException e) {
-            // expected here
-        }
-
-        try {
-            wb = WorkbookFactory.create(
-                    HSSFTestDataSamples.openSampleFileStream(xlsx_protected[0]), "wrong"
-            );
-            assertCloseDoesNotModifyFile(xlsx_protected[0], wb);
-            fail("Shouldn't be able to open with the wrong password");
-        } catch (EncryptedDocumentException e) {
-            // expected here
-        }
-    }
-
-    /**
-     * Check that the overloaded file methods which take passwords work properly
-     */
-    @Test
-    public void testCreateWithPasswordFromFile() throws Exception {
-        Workbook wb;
-
-        // Unprotected, no password given, opens normally
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.getSampleFile(xls), null
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof HSSFWorkbook);
-        assertCloseDoesNotModifyFile(xls, wb);
-
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.getSampleFile(xlsx), null
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof XSSFWorkbook);
-        assertCloseDoesNotModifyFile(xlsx, wb);
-
-        // Unprotected, wrong password, opens normally
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.getSampleFile(xls), "wrong"
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof HSSFWorkbook);
-        assertCloseDoesNotModifyFile(xls, wb);
-
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.getSampleFile(xlsx), "wrong"
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof XSSFWorkbook);
-        assertCloseDoesNotModifyFile(xlsx, wb);
-
-        // Protected, correct password, opens fine
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.getSampleFile(xls_protected[0]), xls_protected[1]
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof HSSFWorkbook);
-        assertCloseDoesNotModifyFile(xls_protected[0], wb);
-
-        wb = WorkbookFactory.create(
-                HSSFTestDataSamples.getSampleFile(xlsx_protected[0]), xlsx_protected[1]
-        );
-        assertNotNull(wb);
-        assertTrue(wb instanceof XSSFWorkbook);
-        assertTrue(wb.getNumberOfSheets() > 0);
-        assertNotNull(wb.getSheetAt(0));
-        assertNotNull(wb.getSheetAt(0).getRow(0));
-        assertCloseDoesNotModifyFile(xlsx_protected[0], wb);
-
-        // Protected, wrong password, throws Exception
-        try {
-            wb = WorkbookFactory.create(
-                    HSSFTestDataSamples.getSampleFile(xls_protected[0]), "wrong"
-            );
-            assertCloseDoesNotModifyFile(xls_protected[0], wb);
-            fail("Shouldn't be able to open with the wrong password");
-        } catch (EncryptedDocumentException e) {
-            // expected here
-        }
-
-        try {
-            wb = WorkbookFactory.create(
-                    HSSFTestDataSamples.getSampleFile(xlsx_protected[0]), "wrong"
-            );
-            assertCloseDoesNotModifyFile(xlsx_protected[0], wb);
-            fail("Shouldn't be able to open with the wrong password");
-        } catch (EncryptedDocumentException e) {
-            // expected here
-        }
-    }
-
-    /**
-     * Check that a helpful exception is given on an empty input stream
-     */
-    @Test(expected = EmptyFileException.class)
-    public void testEmptyInputStream() throws Exception {
-        InputStream emptyStream = new ByteArrayInputStream(new byte[0]);
-        WorkbookFactory.create(emptyStream);
-    }
-
-    /**
-     * Check that a helpful exception is given on an empty file
-     */
-    @Test(expected = EmptyFileException.class)
-    public void testEmptyFile() throws Exception {
-        File emptyFile = TempFile.createTempFile("empty", ".poi");
-        try {
-            WorkbookFactory.create(emptyFile);
-            fail("Shouldn't be able to create for an empty file");
-        } finally {
-            assertTrue(emptyFile.delete());
-        }
-    }
-
-    /**
-      * Check that a helpful exception is raised on a non-existing file
-      */
-    @Test(expected = FileNotFoundException.class)
-    public void testNonExistingFile() throws Exception {
-        File nonExistingFile = new File("notExistingFile");
-        assertFalse(nonExistingFile.exists());
-        WorkbookFactory.create(nonExistingFile, "password", true);
-    }
-
-    /**
-     * See Bugzilla bug #62831 - #WorkbookFactory.create(File) needs
-     *  to work for sub-classes of File too, eg JFileChooser
-     */
-    @Test(expected = ClassCastException.class)
-    public void testFileSubclass() throws Exception {
-        File normalXLS = HSSFTestDataSamples.getSampleFile(xls);
-        File normalXLSX = HSSFTestDataSamples.getSampleFile(xlsx);
-        File altXLS = new TestFile(normalXLS.getAbsolutePath());
-        File altXLSX = new TestFile(normalXLSX.getAbsolutePath());
-        assertTrue(altXLS.exists());
-        assertTrue(altXLSX.exists());
-
-        Workbook wb = WorkbookFactory.create(altXLS);
-        assertNotNull(wb);
-        assertTrue(wb instanceof HSSFWorkbook);
-        closeOrRevert(wb);
-
-        wb = WorkbookFactory.create(altXLSX);
-        assertNotNull(wb);
-        assertTrue(wb instanceof XSSFWorkbook);
-        closeOrRevert(wb);
-
-        // check what happens if the file is passed as "Object"
-
-        //noinspection deprecation
-        WorkbookFactory.create((Object)altXLSX);
-        // expected a ClassCastException here because create() in this case expects an object of type "OPCPackage"
-    }
-
-    private static class TestFile extends File {
-        public TestFile(String file) {
-            super(file);
-        }
-    }
-
-    /**
-     * Check that the overloaded file methods which take passwords work properly
-     */
-    @Test
-    public void testCreateEmpty() throws Exception {
-        Workbook wb = WorkbookFactory.create(false);
-        assertTrue(wb instanceof HSSFWorkbook);
-        closeOrRevert(wb);
-
-        wb = WorkbookFactory.create(true);
-        assertTrue(wb instanceof XSSFWorkbook);
-        closeOrRevert(wb);
-    }
-
-    @Test
-    @SuppressForbidden("test code")
-    public void testOpenManyHSSF() throws Exception {
-        final int size = 1000;
-        ExecutorService executorService = Executors.newFixedThreadPool(10);
-        ArrayList<Future<Boolean>> futures = new ArrayList(size);
-        for (int i = 0; i < size; i++) {
-            futures.add(executorService.submit(() -> openHSSFFile()));
-        }
-        for (Future<Boolean> future: futures) {
-            assertTrue(future.get());
-        }
-    }
-
-    @Test(expected = IOException.class)
-    public void testInvalidFormatException() throws IOException {
-        String filename = "OPCCompliance_DerivedPartNameFAIL.docx";
-        WorkbookFactory.create(POIDataSamples.getOpenXML4JInstance().openResourceAsStream(filename));
-    }
-
-    private boolean openHSSFFile() {
-        try {
-            // POIFS -> hssf
-            Workbook wb = WorkbookFactory.create(
-                    new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream(xls))
-            );
-            assertNotNull(wb);
-            assertTrue(wb instanceof HSSFWorkbook);
-            assertCloseDoesNotModifyFile(xls, wb);
-            return true;
-        } catch (Exception e) {
-            return false;
-        }
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/extractor/TestEmbeddedExtractor.java b/src/ooxml/testcases/org/apache/poi/ss/extractor/TestEmbeddedExtractor.java
deleted file mode 100644 (file)
index 0b755b9..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.extractor;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.Base64;
-import java.util.List;
-
-import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
-import org.junit.Test;
-
-public class TestEmbeddedExtractor {
-    private static final POIDataSamples samples = POIDataSamples.getSpreadSheetInstance();
-
-    @Test
-    public void extractPDFfromEMF() throws Exception {
-        InputStream fis = samples.openResourceAsStream("Basic_Expense_Template_2011.xls");
-        Workbook wb = WorkbookFactory.create(fis);
-        fis.close();
-
-        EmbeddedExtractor ee = new EmbeddedExtractor();
-        List<EmbeddedData> edList = new ArrayList<>();
-        for (Sheet s : wb) {
-            edList.addAll(ee.extractAll(s));
-        }
-        wb.close();
-
-        assertEquals(2, edList.size());
-
-        String filename1 = "Sample.pdf";
-        EmbeddedData ed0 = edList.get(0);
-        assertEquals(filename1, ed0.getFilename());
-        assertEquals(filename1, ed0.getShape().getShapeName().trim());
-        assertEquals("uNplB1QpYug+LWappiTh0w==", md5hash(ed0.getEmbeddedData()));
-
-        String filename2 = "kalastuslupa_jiyjhnj_yuiyuiyuio_uyte_sldfsdfsdf_sfsdfsdf_sfsssfsf_sdfsdfsdfsdf_sdfsdfsdf.pdf";
-        EmbeddedData ed1 = edList.get(1);
-        assertEquals(filename2, ed1.getFilename());
-        assertEquals(filename2, ed1.getShape().getShapeName().trim());
-        assertEquals("QjLuAZ+cd7KbhVz4sj+QdA==", md5hash(ed1.getEmbeddedData()));
-    }
-
-    @Test
-    public void extractFromXSSF() throws IOException, EncryptedDocumentException, InvalidFormatException {
-        InputStream fis = samples.openResourceAsStream("58325_db.xlsx");
-        Workbook wb = WorkbookFactory.create(fis);
-        fis.close();
-
-        EmbeddedExtractor ee = new EmbeddedExtractor();
-        List<EmbeddedData> edList = new ArrayList<>();
-        for (Sheet s : wb) {
-            edList.addAll(ee.extractAll(s));
-        }
-        wb.close();
-
-        assertEquals(4, edList.size());
-        EmbeddedData ed0 = edList.get(0);
-        assertEquals("Object 1.pdf", ed0.getFilename());
-        assertEquals("Object 1", ed0.getShape().getShapeName().trim());
-        assertEquals("Oyys6UtQU1gbHYBYqA4NFA==", md5hash(ed0.getEmbeddedData()));
-
-        EmbeddedData ed1 = edList.get(1);
-        assertEquals("Object 2.pdf", ed1.getFilename());
-        assertEquals("Object 2", ed1.getShape().getShapeName().trim());
-        assertEquals("xLScPUS0XH+5CTZ2A3neNw==", md5hash(ed1.getEmbeddedData()));
-
-        EmbeddedData ed2 = edList.get(2);
-        assertEquals("Object 3.pdf", ed2.getFilename());
-        assertEquals("Object 3", ed2.getShape().getShapeName().trim());
-        assertEquals("rX4klZqJAeM5npb54Gi2+Q==", md5hash(ed2.getEmbeddedData()));
-
-        EmbeddedData ed3 = edList.get(3);
-        assertEquals("Microsoft_Excel_Worksheet1.xlsx", ed3.getFilename());
-        assertEquals("Object 1", ed3.getShape().getShapeName().trim());
-        assertEquals("4m4N8ji2tjpEGPQuw2YwGA==", md5hash(ed3.getEmbeddedData()));
-    }
-
-    public static String md5hash(byte[] input) {
-        try {
-            MessageDigest md = MessageDigest.getInstance("MD5");
-            byte[] hash = md.digest(input);
-            return Base64.getEncoder().encodeToString(hash);
-        } catch (NoSuchAlgorithmException e) {
-            // doesn't happen
-            throw new RuntimeException(e);
-        }
-    }
-
-
-    @Test
-    public void testNPE() throws IOException {
-        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("angelo.edu_content_files_19555-nsse-2011-multiyear-benchmark.xls");
-        EmbeddedExtractor ee = new EmbeddedExtractor();
-
-        for (Sheet s : wb) {
-            for (EmbeddedData ed : ee.extractAll(s)) {
-                assertNotNull(ed.getFilename());
-                assertNotNull(ed.getEmbeddedData());
-                assertNotNull(ed.getShape());
-            }
-        }
-
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/format/TestCellFormatPart.java b/src/ooxml/testcases/org/apache/poi/ss/format/TestCellFormatPart.java
deleted file mode 100644 (file)
index 2ddbb24..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.ss.format;
-
-import static java.awt.Color.ORANGE;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.awt.Color;
-import java.io.IOException;
-import java.util.Locale;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Stream;
-
-import javax.swing.JLabel;
-
-import org.apache.poi.hssf.util.HSSFColor;
-import org.apache.poi.ss.ITestDataProvider;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellType;
-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.util.LocaleUtil;
-import org.apache.poi.xssf.XSSFITestDataProvider;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-/**
- * Class for spreadsheet-based tests, such as are used for cell formatting.
- * This reads tests from the spreadsheet, as well as reading
- * flags that can be used to paramterize these tests.
- * <p>
- * Each test has four parts: The expected result (column A), the format string
- * (column B), the value to format (column C), and a comma-separated list of
- * categores that this test falls in. Normally all tests are run, but if the
- * flag "Categories" is not empty, only tests that have at least one category
- * listed in "Categories" are run.
- */
-public class TestCellFormatPart {
-    private static final Pattern NUMBER_EXTRACT_FMT = Pattern.compile(
-            "([-+]?[0-9]+)(\\.[0-9]+)?.*(?:(e).*?([+-]?[0-9]+))",
-            Pattern.CASE_INSENSITIVE);
-    private static final Color TEST_COLOR = ORANGE.darker();
-    private static Locale userLocale;
-
-
-
-    @BeforeClass
-    public static void setLocale() {
-        userLocale = LocaleUtil.getUserLocale();
-        LocaleUtil.setUserLocale(Locale.UK);
-    }
-
-    @AfterClass
-    public static void unsetLocale() {
-        LocaleUtil.setUserLocale(userLocale);
-    }
-
-    private final ITestDataProvider _testDataProvider = XSSFITestDataProvider.instance;
-
-    private interface CellValue {
-        Object getValue(Cell cell);
-
-        default void equivalent(String expected, String actual, CellFormatPart format) {
-            assertEquals("format \"" + format + "\"", '"' + expected + '"',
-                         '"' + actual + '"');
-        }
-    }
-
-    @Test
-    public void testGeneralFormat() throws IOException {
-        runFormatTests("GeneralFormatTests.xlsx", cell -> {
-            assertNotNull(cell);
-            switch (CellFormat.ultimateType(cell)) {
-                case BOOLEAN:
-                    return cell.getBooleanCellValue();
-                case NUMERIC:
-                    return cell.getNumericCellValue();
-                default:
-                    return cell.getStringCellValue();
-            }
-        });
-    }
-
-    @Test
-    public void testNumberFormat() throws IOException {
-        runFormatTests("NumberFormatTests.xlsx", Cell::getNumericCellValue);
-    }
-
-    @Test
-    public void testNumberApproxFormat() throws IOException {
-        runFormatTests("NumberFormatApproxTests.xlsx", new CellValue() {
-            @Override
-            public Object getValue(Cell cell) {
-                return cell.getNumericCellValue();
-            }
-
-            @Override
-            public void equivalent(String expected, String actual,
-                    CellFormatPart format) {
-                double expectedVal = extractNumber(expected);
-                double actualVal = extractNumber(actual);
-                // equal within 1%
-                double delta = expectedVal / 100;
-                assertEquals("format \"" + format + "\"," + expected + " ~= " +
-                        actual, expectedVal, actualVal, delta);
-            }
-        });
-    }
-
-    @Test
-    public void testDateFormat() throws IOException {
-        TimeZone tz = LocaleUtil.getUserTimeZone();
-        LocaleUtil.setUserTimeZone(TimeZone.getTimeZone("CET"));
-        try {
-            runFormatTests("DateFormatTests.xlsx", Cell::getDateCellValue);
-        } finally {
-            LocaleUtil.setUserTimeZone(tz);
-        }
-    }
-
-    @Test
-    public void testElapsedFormat() throws IOException {
-        runFormatTests("ElapsedFormatTests.xlsx", Cell::getNumericCellValue);
-    }
-
-    @Test
-    public void testTextFormat() throws IOException {
-        runFormatTests("TextFormatTests.xlsx", cell ->
-            (CellFormat.ultimateType(cell) == CellType.BOOLEAN) ? cell.getBooleanCellValue() : cell.getStringCellValue()
-        );
-    }
-
-    @Test
-    public void testConditions() throws IOException {
-        runFormatTests("FormatConditionTests.xlsx", Cell::getNumericCellValue);
-    }
-
-    @Test
-    public void testNamedColors() {
-        assertTrue(CellFormatPart.NAMED_COLORS.size() >= HSSFColor.HSSFColorPredefined.values().length);
-        Stream.of("GREEN","Green","RED","Red","BLUE","Blue","YELLOW","Yellow")
-            .map(CellFormatPart.NAMED_COLORS::get)
-            .forEach(Assert::assertNotNull);
-    }
-
-    private double extractNumber(String str) {
-        Matcher m = NUMBER_EXTRACT_FMT.matcher(str);
-        if (!m.find()) {
-            throw new IllegalArgumentException("Cannot find number in \"" + str + "\"");
-        }
-
-        StringBuilder sb = new StringBuilder();
-        // The groups in the pattern are the parts of the number
-        for (int i = 1; i <= m.groupCount(); i++) {
-            String part = m.group(i);
-            if (part != null)
-                sb.append(part);
-        }
-        return Double.parseDouble(sb.toString());
-    }
-
-
-    protected void runFormatTests(String workbookName, CellValue valueGetter) throws IOException {
-        try (Workbook workbook = _testDataProvider.openSampleWorkbook(workbookName)) {
-            workbook.setMissingCellPolicy(Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
-
-            Sheet sheet = workbook.getSheet("Tests");
-            boolean isHeader = true;
-            for (Row row : sheet) {
-                // Skip the header row
-                if (isHeader || row == null) {
-                    isHeader = false;
-                    continue;
-                }
-                String expectedText = row.getCell(0).getStringCellValue();
-                String format = row.getCell(1).getStringCellValue();
-                Cell value = row.getCell(2);
-
-                if (expectedText.isEmpty() && format.isEmpty()) {
-                    continue;
-                }
-
-                Object objVal = valueGetter.getValue(value);
-                JLabel label = new JLabel();
-                label.setForeground(TEST_COLOR);
-                label.setText("xyzzy");
-
-                Color origColor = label.getForeground();
-                CellFormatPart cellFormatPart = new CellFormatPart(format);
-                // If this doesn't apply, no color change is expected
-                Color expectedColor = cellFormatPart.apply(label, objVal).applies ? TEST_COLOR : origColor;
-
-                String actualText = label.getText();
-                Color actualColor = label.getForeground();
-                valueGetter.equivalent(expectedText, actualText, cellFormatPart);
-                assertEquals("no color", expectedColor, actualColor);
-            }
-        }
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/formula/TestFormulaParser.java b/src/ooxml/testcases/org/apache/poi/ss/formula/TestFormulaParser.java
deleted file mode 100644 (file)
index 36c9601..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-package org.apache.poi.ss.formula;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.formula.ptg.AbstractFunctionPtg;
-import org.apache.poi.ss.formula.ptg.NameXPxg;
-import org.apache.poi.ss.formula.ptg.Ptg;
-import org.apache.poi.ss.formula.ptg.Ref3DPxg;
-import org.apache.poi.ss.formula.ptg.StringPtg;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.xssf.XSSFTestDataSamples;
-import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.junit.Test;
-
-/**
- * Test {@link FormulaParser}'s handling of row numbers at the edge of the
- * HSSF/XSSF ranges.
- * 
- * @author David North
- */
-public class TestFormulaParser {
-
-    @Test
-    public void testHSSFFailsForOver65536() {
-        FormulaParsingWorkbook workbook = HSSFEvaluationWorkbook.create(new HSSFWorkbook());
-        try {
-            FormulaParser.parse("Sheet1!1:65537", workbook, FormulaType.CELL, 0);
-            fail("Expected exception");
-        }
-        catch (FormulaParseException expected) {
-            // expected here
-        }
-    }
-
-    private static void checkHSSFFormula(String formula) {
-        HSSFWorkbook wb = new HSSFWorkbook();
-        FormulaParsingWorkbook workbook = HSSFEvaluationWorkbook.create(wb);
-        FormulaParser.parse(formula, workbook, FormulaType.CELL, 0);
-        IOUtils.closeQuietly(wb);
-    } 
-    private static void checkXSSFFormula(String formula) {
-        XSSFWorkbook wb = new XSSFWorkbook();
-        FormulaParsingWorkbook workbook = XSSFEvaluationWorkbook.create(wb);
-        FormulaParser.parse(formula, workbook, FormulaType.CELL, 0);
-        IOUtils.closeQuietly(wb);
-    } 
-    private static void checkFormula(String formula) {
-        checkHSSFFormula(formula);
-        checkXSSFFormula(formula);
-    }
-
-    @Test
-    public void testHSSFPassCase() {
-        checkHSSFFormula("Sheet1!1:65536");
-    }
-
-    @Test
-    public void testXSSFWorksForOver65536() {
-        checkXSSFFormula("Sheet1!1:65537");
-    }
-
-    @Test
-    public void testXSSFFailCase() {
-        FormulaParsingWorkbook workbook = XSSFEvaluationWorkbook.create(new XSSFWorkbook());
-        try {
-            FormulaParser.parse("Sheet1!1:1048577", workbook, FormulaType.CELL, 0); // one more than max rows.
-            fail("Expected exception");
-        }
-        catch (FormulaParseException expected) {
-            // expected here
-        }
-    }
-    
-    // copied from org.apache.poi.hssf.model.TestFormulaParser
-    @Test
-    public void testMacroFunction() throws Exception {
-        // testNames.xlsm contains a VB function called 'myFunc'
-        final String testFile = "testNames.xlsm";
-        try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook(testFile)) {
-            XSSFEvaluationWorkbook workbook = XSSFEvaluationWorkbook.create(wb);
-
-            //Expected ptg stack: [NamePtg(myFunc), StringPtg(arg), (additional operands would go here...), FunctionPtg(myFunc)]
-            Ptg[] ptg = FormulaParser.parse("myFunc(\"arg\")", workbook, FormulaType.CELL, -1);
-            assertEquals(3, ptg.length);
-
-            // the name gets encoded as the first operand on the stack
-            NameXPxg tname = (NameXPxg) ptg[0];
-            assertEquals("myFunc", tname.toFormulaString());
-
-            // the function's arguments are pushed onto the stack from left-to-right as OperandPtgs
-            StringPtg arg = (StringPtg) ptg[1];
-            assertEquals("arg", arg.getValue());
-
-            // The external FunctionPtg is the last Ptg added to the stack
-            // During formula evaluation, this Ptg pops off the the appropriate number of
-            // arguments (getNumberOfOperands()) and pushes the result on the stack
-            AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[2];
-            assertTrue(tfunc.isExternalFunction());
-
-            // confirm formula parsing is case-insensitive
-            FormulaParser.parse("mYfUnC(\"arg\")", workbook, FormulaType.CELL, -1);
-
-            // confirm formula parsing doesn't care about argument count or type
-            // this should only throw an error when evaluating the formula.
-            FormulaParser.parse("myFunc()", workbook, FormulaType.CELL, -1);
-            FormulaParser.parse("myFunc(\"arg\", 0, TRUE)", workbook, FormulaType.CELL, -1);
-
-            // A completely unknown formula name (not saved in workbook) should still be parseable and renderable
-            // but will throw an NotImplementedFunctionException or return a #NAME? error value if evaluated.
-            FormulaParser.parse("yourFunc(\"arg\")", workbook, FormulaType.CELL, -1);
-
-            // Make sure workbook can be written and read
-            XSSFTestDataSamples.writeOutAndReadBack(wb).close();
-
-            // Manually check to make sure file isn't corrupted
-            // TODO: develop a process for occasionally manually reviewing workbooks
-            // to verify workbooks are not corrupted
-            /*
-            final File fileIn = XSSFTestDataSamples.getSampleFile(testFile);
-            final File reSavedFile = new File(fileIn.getParentFile(), fileIn.getName().replace(".xlsm", "-saved.xlsm"));
-            final FileOutputStream fos = new FileOutputStream(reSavedFile);
-            wb.write(fos);
-            fos.close();
-            */
-        }
-    }
-    
-    @Test
-    public void testParserErrors() throws Exception {
-        try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("testNames.xlsm")) {
-            XSSFEvaluationWorkbook workbook = XSSFEvaluationWorkbook.create(wb);
-
-            parseExpectedException("(");
-            parseExpectedException(")");
-            parseExpectedException("+");
-            parseExpectedException("42+");
-            parseExpectedException("IF()");
-            parseExpectedException("IF("); //no closing paren
-            parseExpectedException("myFunc(", workbook); //no closing paren
-        }
-    }
-    
-    private static void parseExpectedException(String formula) {
-        parseExpectedException(formula, null);
-    }
-    
-    /** confirm formula has invalid syntax and parsing the formula results in FormulaParseException
-     */
-    private static void parseExpectedException(String formula, FormulaParsingWorkbook wb) {
-        try {
-            FormulaParser.parse(formula, wb, FormulaType.CELL, -1);
-            fail("Expected FormulaParseException: " + formula);
-        } catch (final FormulaParseException e) {
-            // expected during successful test
-            assertNotNull(e.getMessage());
-        }
-    }
-    
-    // trivial case for bug 60219: FormulaParser can't parse external references when sheet name is quoted
-    @Test
-    public void testParseExternalReferencesWithUnquotedSheetName() throws Exception {
-        XSSFWorkbook wb = new XSSFWorkbook();
-        XSSFEvaluationWorkbook fpwb = XSSFEvaluationWorkbook.create(wb);
-        Ptg[] ptgs = FormulaParser.parse("[1]Sheet1!A1", fpwb, FormulaType.CELL, -1);
-        // org.apache.poi.ss.formula.ptg.Ref3DPxg [ [workbook=1] sheet=Sheet 1 ! A1]
-        assertEquals("Ptgs length", 1, ptgs.length);
-        assertTrue("Ptg class", ptgs[0] instanceof Ref3DPxg);
-        Ref3DPxg pxg = (Ref3DPxg) ptgs[0];
-        assertEquals("External workbook number", 1, pxg.getExternalWorkbookNumber());
-        assertEquals("Sheet name", "Sheet1", pxg.getSheetName());
-        assertEquals("Row", 0, pxg.getRow());
-        assertEquals("Column", 0, pxg.getColumn());
-        wb.close();
-    }
-    
-    // bug 60219: FormulaParser can't parse external references when sheet name is quoted
-    @Test
-    public void testParseExternalReferencesWithQuotedSheetName() throws Exception {
-        XSSFWorkbook wb = new XSSFWorkbook();
-        XSSFEvaluationWorkbook fpwb = XSSFEvaluationWorkbook.create(wb);
-        Ptg[] ptgs = FormulaParser.parse("'[1]Sheet 1'!A1", fpwb, FormulaType.CELL, -1);
-        // org.apache.poi.ss.formula.ptg.Ref3DPxg [ [workbook=1] sheet=Sheet 1 ! A1]
-        assertEquals("Ptgs length", 1, ptgs.length);
-        assertTrue("Ptg class", ptgs[0] instanceof Ref3DPxg);
-        Ref3DPxg pxg = (Ref3DPxg) ptgs[0];
-        assertEquals("External workbook number", 1, pxg.getExternalWorkbookNumber());
-        assertEquals("Sheet name", "Sheet 1", pxg.getSheetName());
-        assertEquals("Row", 0, pxg.getRow());
-        assertEquals("Column", 0, pxg.getColumn());
-        wb.close();
-    }
-
-    // bug 60260
-    @Test
-    public void testUnicodeSheetName() {
-        checkFormula("'Sheet\u30FB1'!A1:A6");
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/formula/TestStructuredReferences.java b/src/ooxml/testcases/org/apache/poi/ss/formula/TestStructuredReferences.java
deleted file mode 100644 (file)
index 547555d..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.formula;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import org.apache.poi.ss.SpreadsheetVersion;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.CellValue;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Table;
-import org.apache.poi.ss.util.AreaReference;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xssf.XSSFTestDataSamples;
-import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFTable;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.junit.Test;
-
-/**
- * Tests Excel Table expressions (structured references)
- * @see <a href="https://support.office.com/en-us/article/Using-structured-references-with-Excel-tables-F5ED2452-2337-4F71-BED3-C8AE6D2B276E">
- *         Excel Structured Reference Syntax
- *      </a>
- */
-public class TestStructuredReferences {
-
-    /**
-     * Test the regular expression used in INDIRECT() evaluation to recognize structured references
-     */
-    @Test
-    public void testTableExpressionSyntax() {
-        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("abc[col1]").matches());
-        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("_abc[col1]").matches());
-        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("_[col1]").matches());
-        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("\\[col1]").matches());
-        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("\\[col1]").matches());
-        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("\\[#This Row]").matches());
-        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("\\[ [col1], [col2] ]").matches());
-        
-        // can't have a space between the table name and open bracket
-        assertFalse("Invalid structured reference syntax didn't fail expression", Table.isStructuredReference.matcher("\\abc [ [col1], [col2] ]").matches());
-    }
-    
-    @Test
-    public void testTableFormulas() throws Exception {
-        try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("StructuredReferences.xlsx")) {
-
-            final FormulaEvaluator eval = new XSSFFormulaEvaluator(wb);
-            final XSSFSheet tableSheet = wb.getSheet("Table");
-            final XSSFSheet formulaSheet = wb.getSheet("Formulas");
-
-            confirm(eval, tableSheet.getRow(5).getCell(0), 49);
-            confirm(eval, formulaSheet.getRow(0).getCell(0), 209);
-            confirm(eval, formulaSheet.getRow(1).getCell(0), "one");
-
-            // test changing a table value, to see if the caches are properly cleared
-            // Issue 59814
-
-            // this test passes before the fix for 59814
-            tableSheet.getRow(1).getCell(1).setCellValue("ONEA");
-            confirm(eval, formulaSheet.getRow(1).getCell(0), "ONEA");
-
-            // test adding a row to a table, issue 59814
-            Row newRow = tableSheet.getRow(7);
-            if (newRow == null) newRow = tableSheet.createRow(7);
-            newRow.createCell(0, CellType.FORMULA).setCellFormula("\\_Prime.1[[#This Row],[@Number]]*\\_Prime.1[[#This Row],[@Number]]");
-            newRow.createCell(1, CellType.STRING).setCellValue("thirteen");
-            newRow.createCell(2, CellType.NUMERIC).setCellValue(13);
-
-            // update Table
-            final XSSFTable table = wb.getTable("\\_Prime.1");
-            final AreaReference newArea = wb.getCreationHelper().createAreaReference(
-                    table.getStartCellReference(),
-                    new CellReference(table.getEndRowIndex() + 1, table.getEndColIndex()));
-            String newAreaStr = newArea.formatAsString();
-            table.getCTTable().setRef(newAreaStr);
-            table.getCTTable().getAutoFilter().setRef(newAreaStr);
-            table.updateHeaders();
-            table.updateReferences();
-
-            // these fail before the fix for 59814
-            confirm(eval, tableSheet.getRow(7).getCell(0), 13 * 13);
-            confirm(eval, formulaSheet.getRow(0).getCell(0), 209 + 13 * 13);
-
-        }
-    }
-
-    private static void confirm(FormulaEvaluator fe, Cell cell, double expectedResult) {
-        fe.clearAllCachedResultValues();
-        CellValue cv = fe.evaluate(cell);
-        if (cv.getCellType() != CellType.NUMERIC) {
-            fail("expected numeric cell type but got " + cv.formatAsString());
-        }
-        assertEquals(expectedResult, cv.getNumberValue(), 0.0);
-    }
-
-    private static void confirm(FormulaEvaluator fe, Cell cell, String expectedResult) {
-        fe.clearAllCachedResultValues();
-        CellValue cv = fe.evaluate(cell);
-        if (cv.getCellType() != CellType.STRING) {
-            fail("expected String cell type but got " + cv.formatAsString());
-        }
-        assertEquals(expectedResult, cv.getStringValue());
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/formula/eval/TestXSSFCircularReferences.java b/src/ooxml/testcases/org/apache/poi/ss/formula/eval/TestXSSFCircularReferences.java
deleted file mode 100644 (file)
index 0b8c9fc..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.formula.eval;
-
-import org.apache.poi.xssf.XSSFITestDataProvider;
-
-/**
- * Tests XSSFFormulaEvaluator for its handling of cell formula circular references.
- *
- * @author Josh Micich
- */
-public final class TestXSSFCircularReferences extends BaseTestCircularReferences {
-       public TestXSSFCircularReferences() {
-        super(XSSFITestDataProvider.instance);
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/formula/functions/CountifsTests.java b/src/ooxml/testcases/org/apache/poi/ss/formula/functions/CountifsTests.java
deleted file mode 100644 (file)
index 3b3d714..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-
-package org.apache.poi.ss.formula.functions;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.CellValue;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
-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.util.SheetUtil;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.xssf.XSSFTestDataSamples;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Test the COUNTIFS() function
- */
-public class CountifsTests {
-
-    private Workbook workbook;
-    
-    /**
-     * initialize a workbook
-     */
-    @Before
-    public void before() {
-        // not sure why we allow this, COUNTIFS() is only available
-        // in OOXML, it was introduced with Office 2007
-        workbook = new HSSFWorkbook();
-    }
-    
-    /**
-     * Close the workbook if needed
-     */
-    @After
-    public void after() {
-        IOUtils.closeQuietly(workbook);
-    }
-    
-    /**
-     * Basic call
-     */
-    @Test
-    public void testCallFunction() {
-        Sheet sheet = workbook.createSheet("test");
-        Row row1 = sheet.createRow(0);
-        Cell cellA1 = row1.createCell(0, CellType.FORMULA);
-        Cell cellB1 = row1.createCell(1, CellType.NUMERIC);
-        Cell cellC1 = row1.createCell(2, CellType.NUMERIC);
-        Cell cellD1 = row1.createCell(3, CellType.NUMERIC);
-        Cell cellE1 = row1.createCell(4, CellType.NUMERIC);
-        cellB1.setCellValue(1);
-        cellC1.setCellValue(1);
-        cellD1.setCellValue(2);
-        cellE1.setCellValue(4);
-
-        cellA1.setCellFormula("COUNTIFS(B1:C1,1, D1:E1,2)");
-        FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
-        CellValue evaluate = evaluator.evaluate(cellA1);
-        assertEquals(1.0d, evaluate.getNumberValue(), 0.000000000000001);
-    }
-
-    /**
-     * Test argument count check
-     */
-    @Test
-    public void testCallFunction_invalidArgs() {
-        Sheet sheet = workbook.createSheet("test");
-        Row row1 = sheet.createRow(0);
-        Cell cellA1 = row1.createCell(0, CellType.FORMULA);
-        cellA1.setCellFormula("COUNTIFS()");
-        FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
-        CellValue evaluate = evaluator.evaluate(cellA1);
-        assertEquals(15, evaluate.getErrorValue());
-        cellA1.setCellFormula("COUNTIFS(A1:C1)");
-        evaluator = workbook.getCreationHelper().createFormulaEvaluator();
-        evaluate = evaluator.evaluate(cellA1);
-        assertEquals(15, evaluate.getErrorValue());
-        cellA1.setCellFormula("COUNTIFS(A1:C1,2,2)");
-        evaluator = workbook.getCreationHelper().createFormulaEvaluator();
-        evaluate = evaluator.evaluate(cellA1);
-        assertEquals(15, evaluate.getErrorValue());
-    }
-    
-    /**
-     * the bug returned the wrong count, this verifies the fix
-     * @throws Exception if the file can't be read
-     */
-    @Test
-    public void testBug56822() throws Exception {
-        workbook = XSSFTestDataSamples.openSampleWorkbook("56822-Countifs.xlsx");
-        FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
-        Cell cell = SheetUtil.getCell(workbook.getSheetAt(0), 0, 3);
-        assertNotNull("Test workbook missing cell D1", cell);
-        CellValue evaluate = evaluator.evaluate(cell);
-        assertEquals(2.0d, evaluate.getNumberValue(), 0.00000000000001);
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/formula/functions/TestProper.java b/src/ooxml/testcases/org/apache/poi/ss/formula/functions/TestProper.java
deleted file mode 100644 (file)
index 89fdb52..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.formula.functions;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.formula.eval.StringEval;
-import org.apache.poi.ss.formula.eval.ValueEval;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.CellValue;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.junit.Test;
-
-public final class TestProper {
-    private Cell cell11;
-    private FormulaEvaluator evaluator;
-
-    @Test
-    public void testValidHSSF() {
-        HSSFWorkbook wb = new HSSFWorkbook();
-        evaluator = new HSSFFormulaEvaluator(wb);
-
-        confirm(wb);
-    }
-
-    @Test
-    public void testValidXSSF() {
-        XSSFWorkbook wb = new XSSFWorkbook();
-        evaluator = new XSSFFormulaEvaluator(wb);
-
-        confirm(wb);
-    }
-
-    private void confirm(Workbook wb) {
-        Sheet sheet = wb.createSheet("new sheet");
-        cell11 = sheet.createRow(0).createCell(0);
-
-        confirm("PROPER(\"hi there\")", "Hi There"); //simple case
-        confirm("PROPER(\"what's up\")", "What'S Up"); //apostrophes are treated as word breaks
-        confirm("PROPER(\"I DON'T TH!NK SO!\")", "I Don'T Th!Nk So!"); //capitalization is ignored, special punctuation is treated as a word break
-        confirm("PROPER(\"dr\u00dcb\u00f6'\u00e4 \u00e9lo\u015f|\u00eb\u00e8 \")", "Dr\u00fcb\u00f6'\u00c4 \u00c9lo\u015f|\u00cb\u00e8 ");
-        confirm("PROPER(\"hi123 the123re\")", "Hi123 The123Re"); //numbers are treated as word breaks
-        confirm("PROPER(\"-\")", "-"); //nothing happens with ascii punctuation that is not upper or lower case
-        confirm("PROPER(\"!\u00a7$\")", "!\u00a7$"); //nothing happens with unicode punctuation (section sign) that is not upper or lower case
-        confirm("PROPER(\"/&%\")", "/&%"); //nothing happens with ascii punctuation that is not upper or lower case
-        confirm("PROPER(\"Apache POI\")", "Apache Poi"); //acronyms are not special
-        confirm("PROPER(\"  hello world\")", "  Hello World"); //leading whitespace is ignored
-
-        final String scharfes = "\u00df"; //German lowercase eszett, scharfes s, sharp s
-        confirm("PROPER(\"stra"+scharfes+"e\")", "Stra"+scharfes+"e");
-        assertTrue(Character.isLetter(scharfes.charAt(0)));
-
-        // CURRENTLY FAILS: result: "SSUnd"+scharfes
-        // LibreOffice 5.0.3.2 behavior: "Sund"+scharfes
-        // Excel 2013 behavior: ???
-        confirm("PROPER(\""+scharfes+"und"+scharfes+"\")", "SSund"+scharfes);
-
-        // also test longer string
-        StringBuilder builder = new StringBuilder("A");
-        StringBuilder expected = new StringBuilder("A");
-        for(int i = 1;i < 254;i++) {
-            builder.append((char)(65 + (i % 26)));
-            expected.append((char)(97 + (i % 26)));
-        }
-        confirm("PROPER(\"" + builder + "\")", expected.toString());
-    }
-
-    private void confirm(String formulaText, String expectedResult) {
-        cell11.setCellFormula(formulaText);
-        evaluator.clearAllCachedResultValues();
-        CellValue cv = evaluator.evaluate(cell11);
-        assertEquals("Wrong result type", CellType.STRING, cv.getCellType());
-        String actualValue = cv.getStringValue();
-        assertEquals(expectedResult, actualValue);
-    }
-
-    @Test
-    public void test() {
-        checkProper("", "");
-        checkProper("a", "A");
-        checkProper("abc", "Abc");
-        checkProper("abc abc", "Abc Abc");
-        checkProper("abc/abc", "Abc/Abc");
-        checkProper("ABC/ABC", "Abc/Abc");
-        checkProper("aBc/ABC", "Abc/Abc");
-        checkProper("aBc@#$%^&*()_+=-ABC", "Abc@#$%^&*()_+=-Abc");
-        checkProper("aBc25aerg/ABC", "Abc25Aerg/Abc");
-        checkProper("aBc/\u00C4\u00F6\u00DF\u00FC/ABC", "Abc/\u00C4\u00F6\u00DF\u00FC/Abc");  // Some German umlauts with uppercase first letter is not changed
-        checkProper("\u00FC", "\u00DC");
-        checkProper("\u00DC", "\u00DC");
-        checkProper("\u00DF", "SS");    // German "scharfes s" is uppercased to "SS"
-        checkProper("\u00DFomesing", "SSomesing");    // German "scharfes s" is uppercased to "SS"
-        checkProper("aBc/\u00FC\u00C4\u00F6\u00DF\u00FC/ABC", "Abc/\u00DC\u00E4\u00F6\u00DF\u00FC/Abc");  // Some German umlauts with lowercase first letter is changed to uppercase
-    }
-
-    @Test
-    public void testMicroBenchmark() {
-        ValueEval strArg = new StringEval("some longer text that needs a number of replacements to check for runtime of different implementations");
-        long start = System.currentTimeMillis();
-        for(int i = 0;i < 300000;i++) {
-            final ValueEval ret = TextFunction.PROPER.evaluate(new ValueEval[]{strArg}, 0, 0);
-            assertEquals("Some Longer Text That Needs A Number Of Replacements To Check For Runtime Of Different Implementations", ((StringEval)ret).getStringValue());
-        }
-        // Took approx. 600ms on a decent Laptop in July 2016
-        //System.out.println("Took: " + (System.currentTimeMillis() - start) + "ms");
-    }
-
-    private void checkProper(String input, String expected) {
-        ValueEval strArg = new StringEval(input);
-        final ValueEval ret = TextFunction.PROPER.evaluate(new ValueEval[]{strArg}, 0, 0);
-        assertEquals(expected, ((StringEval)ret).getStringValue());
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/formula/functions/TestSumifsXSSF.java b/src/ooxml/testcases/org/apache/poi/ss/formula/functions/TestSumifsXSSF.java
deleted file mode 100644 (file)
index 7929a95..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.ss.formula.functions;
-
-import static org.junit.Assert.assertEquals;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.XSSFTestDataSamples;
-import org.junit.Test;
-
-import java.io.IOException;
-
-/**
- *
- */
-public class TestSumifsXSSF {
-
-    /**
-     * handle null cell predicate
-     */
-    @Test
-    public void testBug60858() throws IOException {
-        try (Workbook wb = XSSFTestDataSamples.openSampleWorkbook("bug60858.xlsx")) {
-            FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
-
-            Sheet sheet = wb.getSheetAt(0);
-            Cell cell = sheet.getRow(1).getCell(5);
-            fe.evaluate(cell);
-            assertEquals(0.0, cell.getNumericCellValue(), 0.0000000000000001);
-        }
-    }
-
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/formula/functions/TestVlookup.java b/src/ooxml/testcases/org/apache/poi/ss/formula/functions/TestVlookup.java
deleted file mode 100644 (file)
index 0dc0655..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.formula.functions;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.CellValue;
-import org.apache.poi.ss.usermodel.CreationHelper;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
-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.xssf.XSSFTestDataSamples;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.junit.Test;
-
-import java.io.IOException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-/**
- * Test the VLOOKUP function
- */
-public class TestVlookup {
-
-    @Test
-    public void testFullColumnAreaRef61841() throws IOException {
-        try (Workbook wb = XSSFTestDataSamples.openSampleWorkbook("VLookupFullColumn.xlsx")) {
-            FormulaEvaluator feval = wb.getCreationHelper().createFormulaEvaluator();
-            feval.evaluateAll();
-            assertEquals("Wrong lookup value", "Value1",
-                    feval.evaluate(wb.getSheetAt(0).getRow(3).getCell(1)).getStringValue());
-            assertEquals("Lookup should return #N/A",
-                    CellType.ERROR, feval.evaluate(wb.getSheetAt(0).getRow(4).getCell(1)).getCellType());
-        }
-    }
-
-    @Test
-    public void bug62275_true() throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {
-            Sheet sheet = wb.createSheet();
-            Row row = sheet.createRow(0);
-
-            Cell cell = row.createCell(0);
-            cell.setCellFormula("vlookup(A2,B1:B5,2,true)");
-
-            CreationHelper createHelper = wb.getCreationHelper();
-            FormulaEvaluator eval = createHelper.createFormulaEvaluator();
-            CellValue value = eval.evaluate(cell);
-
-            assertFalse(value.getBooleanValue());
-        }
-    }
-
-    @Test
-    public void bug62275_false() throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {
-            Sheet sheet = wb.createSheet();
-            Row row = sheet.createRow(0);
-
-            Cell cell = row.createCell(0);
-            cell.setCellFormula("vlookup(A2,B1:B5,2,false)");
-
-            CreationHelper crateHelper = wb.getCreationHelper();
-            FormulaEvaluator eval = crateHelper.createFormulaEvaluator();
-            CellValue value = eval.evaluate(cell);
-
-            assertFalse(value.getBooleanValue());
-        }
-    }
-
-    @Test
-    public void bug62275_empty_3args() throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {
-            Sheet sheet = wb.createSheet();
-            Row row = sheet.createRow(0);
-
-            Cell cell = row.createCell(0);
-            cell.setCellFormula("vlookup(A2,B1:B5,2,)");
-
-            CreationHelper crateHelper = wb.getCreationHelper();
-            FormulaEvaluator eval = crateHelper.createFormulaEvaluator();
-            CellValue value = eval.evaluate(cell);
-
-            assertFalse(value.getBooleanValue());
-        }
-    }
-
-    @Test
-    public void bug62275_empty_2args() throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {
-            Sheet sheet = wb.createSheet();
-            Row row = sheet.createRow(0);
-
-            Cell cell = row.createCell(0);
-            cell.setCellFormula("vlookup(A2,B1:B5,,)");
-
-            CreationHelper crateHelper = wb.getCreationHelper();
-            FormulaEvaluator eval = crateHelper.createFormulaEvaluator();
-            CellValue value = eval.evaluate(cell);
-
-            assertFalse(value.getBooleanValue());
-        }
-    }
-
-    @Test
-    public void bug62275_empty_1arg() throws IOException {
-        try (Workbook wb = new XSSFWorkbook()) {
-            Sheet sheet = wb.createSheet();
-            Row row = sheet.createRow(0);
-
-            Cell cell = row.createCell(0);
-            cell.setCellFormula("vlookup(A2,,,)");
-
-            CreationHelper crateHelper = wb.getCreationHelper();
-            FormulaEvaluator eval = crateHelper.createFormulaEvaluator();
-            CellValue value = eval.evaluate(cell);
-
-            assertFalse(value.getBooleanValue());
-        }
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/TestWorkbookFactory.java b/src/ooxml/testcases/org/apache/poi/ss/tests/TestWorkbookFactory.java
new file mode 100644 (file)
index 0000000..9f2dc29
--- /dev/null
@@ -0,0 +1,475 @@
+/* ====================================================================
+   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.ss.tests;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.apache.poi.EmptyFileException;
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackageAccess;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.util.SuppressForbidden;
+import org.apache.poi.util.TempFile;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbookFactory;
+import org.junit.Test;
+
+public final class TestWorkbookFactory {
+    private static final String xls = "SampleSS.xls";
+    private static final String xlsx = "SampleSS.xlsx";
+    private static final String[] xls_protected = new String[] {"password.xls", "password"};
+    private static final String[] xlsx_protected = new String[]{"protected_passtika.xlsx", "tika"};
+    private static final String txt = "SampleSS.txt";
+
+    private static final POILogger LOGGER = POILogFactory.getLogger(TestWorkbookFactory.class);
+
+    /**
+     * Closes the sample workbook read in from filename.
+     * Throws an exception if closing the workbook results in the file on disk getting modified.
+     *
+     * @param filename the sample workbook to read in
+     * @param wb the workbook to close
+     */
+    private static void assertCloseDoesNotModifyFile(String filename, Workbook wb) throws IOException {
+        final byte[] before = HSSFTestDataSamples.getTestDataFileContent(filename);
+        // FIXME: replace with wb.close() when bug 58779 is resolved
+        closeOrRevert(wb);
+        final byte[] after = HSSFTestDataSamples.getTestDataFileContent(filename);
+        assertArrayEquals(filename + " sample file was modified as a result of closing the workbook",
+                before, after);
+    }
+
+    /**
+     * bug 58779: Closing an XSSFWorkbook that was created with WorkbookFactory modifies the file
+     * FIXME: replace this method with wb.close() when bug 58779 is resolved.
+     *
+     * @param wb the workbook to close or revert
+     */
+    private static void closeOrRevert(Workbook wb) throws IOException {
+        if (wb instanceof HSSFWorkbook) {
+            wb.close();
+        }
+        else if (wb instanceof XSSFWorkbook) {
+            final XSSFWorkbook xwb = (XSSFWorkbook) wb;
+            if (PackageAccess.READ == xwb.getPackage().getPackageAccess()) {
+                xwb.close();
+            }
+            else {
+                // TODO: close() re-writes the sample-file?! Resort to revert() for now to close file handle...
+                LOGGER.log(POILogger.WARN,
+                        "reverting XSSFWorkbook rather than closing it to avoid close() modifying the file on disk. " +
+                        "Refer to bug 58779.");
+                xwb.getPackage().revert();
+            }
+        } else {
+            throw new RuntimeException("Unsupported workbook type");
+        }
+    }
+
+    @Test
+    public void testCreateNative() throws Exception {
+        Workbook wb;
+
+        // POIFS -> hssf
+        wb = WorkbookFactory.create(
+                new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream(xls))
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof HSSFWorkbook);
+        assertCloseDoesNotModifyFile(xls, wb);
+
+        wb = WorkbookFactory.create(
+                new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream(xls)).getRoot()
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof HSSFWorkbook);
+        assertCloseDoesNotModifyFile(xls, wb);
+
+        // Package -> xssf
+        wb = XSSFWorkbookFactory.createWorkbook(
+                OPCPackage.open(
+                        HSSFTestDataSamples.openSampleFileStream(xlsx))
+        );
+        assertNotNull(wb);
+        //noinspection ConstantConditions
+        assertTrue(wb instanceof XSSFWorkbook);
+        assertCloseDoesNotModifyFile(xlsx, wb);
+    }
+
+    @Test
+    public void testCreateReadOnly() throws Exception {
+        Workbook wb;
+
+        // POIFS -> hssf
+        wb = WorkbookFactory.create(HSSFTestDataSamples.getSampleFile(xls), null, true);
+        assertNotNull(wb);
+        assertTrue(wb instanceof HSSFWorkbook);
+        assertCloseDoesNotModifyFile(xls, wb);
+
+        // Package -> xssf
+        wb = WorkbookFactory.create(HSSFTestDataSamples.getSampleFile(xlsx), null, true);
+        assertNotNull(wb);
+        assertTrue(wb instanceof XSSFWorkbook);
+        assertCloseDoesNotModifyFile(xlsx, wb);
+    }
+
+    /**
+     * Creates the appropriate kind of Workbook, but
+     *  checking the mime magic at the start of the
+     *  InputStream, then creating what's required.
+     */
+    @Test
+    public void testCreateGeneric() throws Exception {
+        Workbook wb;
+
+        // InputStream -> either
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.openSampleFileStream(xls)
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof HSSFWorkbook);
+        assertCloseDoesNotModifyFile(xls, wb);
+
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.openSampleFileStream(xlsx)
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof XSSFWorkbook);
+        assertCloseDoesNotModifyFile(xlsx, wb);
+
+        // File -> either
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.getSampleFile(xls)
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof HSSFWorkbook);
+        assertCloseDoesNotModifyFile(xls, wb);
+
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.getSampleFile(xlsx)
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof XSSFWorkbook);
+        assertCloseDoesNotModifyFile(xlsx, wb);
+
+        // Invalid type -> exception
+        final byte[] before = HSSFTestDataSamples.getTestDataFileContent(txt);
+        try {
+            try (InputStream stream = HSSFTestDataSamples.openSampleFileStream(txt)) {
+                wb = WorkbookFactory.create(stream);
+                assertNotNull(wb);
+            }
+            fail();
+        } catch(IOException e) {
+            // Good
+        }
+        final byte[] after = HSSFTestDataSamples.getTestDataFileContent(txt);
+        assertArrayEquals("Invalid type file was modified after trying to open the file as a spreadsheet",
+                before, after);
+    }
+
+    /**
+     * Check that the overloaded stream methods which take passwords work properly
+     */
+    @Test
+    public void testCreateWithPasswordFromStream() throws Exception {
+        Workbook wb;
+
+        // Unprotected, no password given, opens normally
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.openSampleFileStream(xls), null
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof HSSFWorkbook);
+        assertCloseDoesNotModifyFile(xls, wb);
+
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.openSampleFileStream(xlsx), null
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof XSSFWorkbook);
+        assertCloseDoesNotModifyFile(xlsx, wb);
+
+
+        // Unprotected, wrong password, opens normally
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.openSampleFileStream(xls), "wrong"
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof HSSFWorkbook);
+        assertCloseDoesNotModifyFile(xls, wb);
+
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.openSampleFileStream(xlsx), "wrong"
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof XSSFWorkbook);
+        assertCloseDoesNotModifyFile(xlsx, wb);
+
+
+        // Protected, correct password, opens fine
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.openSampleFileStream(xls_protected[0]), xls_protected[1]
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof HSSFWorkbook);
+        assertCloseDoesNotModifyFile(xls_protected[0], wb);
+
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.openSampleFileStream(xlsx_protected[0]), xlsx_protected[1]
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof XSSFWorkbook);
+        assertCloseDoesNotModifyFile(xlsx_protected[0], wb);
+
+
+        // Protected, wrong password, throws Exception
+        try {
+            wb = WorkbookFactory.create(
+                    HSSFTestDataSamples.openSampleFileStream(xls_protected[0]), "wrong"
+            );
+            assertCloseDoesNotModifyFile(xls_protected[0], wb);
+            fail("Shouldn't be able to open with the wrong password");
+        } catch (EncryptedDocumentException e) {
+            // expected here
+        }
+
+        try {
+            wb = WorkbookFactory.create(
+                    HSSFTestDataSamples.openSampleFileStream(xlsx_protected[0]), "wrong"
+            );
+            assertCloseDoesNotModifyFile(xlsx_protected[0], wb);
+            fail("Shouldn't be able to open with the wrong password");
+        } catch (EncryptedDocumentException e) {
+            // expected here
+        }
+    }
+
+    /**
+     * Check that the overloaded file methods which take passwords work properly
+     */
+    @Test
+    public void testCreateWithPasswordFromFile() throws Exception {
+        Workbook wb;
+
+        // Unprotected, no password given, opens normally
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.getSampleFile(xls), null
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof HSSFWorkbook);
+        assertCloseDoesNotModifyFile(xls, wb);
+
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.getSampleFile(xlsx), null
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof XSSFWorkbook);
+        assertCloseDoesNotModifyFile(xlsx, wb);
+
+        // Unprotected, wrong password, opens normally
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.getSampleFile(xls), "wrong"
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof HSSFWorkbook);
+        assertCloseDoesNotModifyFile(xls, wb);
+
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.getSampleFile(xlsx), "wrong"
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof XSSFWorkbook);
+        assertCloseDoesNotModifyFile(xlsx, wb);
+
+        // Protected, correct password, opens fine
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.getSampleFile(xls_protected[0]), xls_protected[1]
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof HSSFWorkbook);
+        assertCloseDoesNotModifyFile(xls_protected[0], wb);
+
+        wb = WorkbookFactory.create(
+                HSSFTestDataSamples.getSampleFile(xlsx_protected[0]), xlsx_protected[1]
+        );
+        assertNotNull(wb);
+        assertTrue(wb instanceof XSSFWorkbook);
+        assertTrue(wb.getNumberOfSheets() > 0);
+        assertNotNull(wb.getSheetAt(0));
+        assertNotNull(wb.getSheetAt(0).getRow(0));
+        assertCloseDoesNotModifyFile(xlsx_protected[0], wb);
+
+        // Protected, wrong password, throws Exception
+        try {
+            wb = WorkbookFactory.create(
+                    HSSFTestDataSamples.getSampleFile(xls_protected[0]), "wrong"
+            );
+            assertCloseDoesNotModifyFile(xls_protected[0], wb);
+            fail("Shouldn't be able to open with the wrong password");
+        } catch (EncryptedDocumentException e) {
+            // expected here
+        }
+
+        try {
+            wb = WorkbookFactory.create(
+                    HSSFTestDataSamples.getSampleFile(xlsx_protected[0]), "wrong"
+            );
+            assertCloseDoesNotModifyFile(xlsx_protected[0], wb);
+            fail("Shouldn't be able to open with the wrong password");
+        } catch (EncryptedDocumentException e) {
+            // expected here
+        }
+    }
+
+    /**
+     * Check that a helpful exception is given on an empty input stream
+     */
+    @Test(expected = EmptyFileException.class)
+    public void testEmptyInputStream() throws Exception {
+        InputStream emptyStream = new ByteArrayInputStream(new byte[0]);
+        WorkbookFactory.create(emptyStream);
+    }
+
+    /**
+     * Check that a helpful exception is given on an empty file
+     */
+    @Test(expected = EmptyFileException.class)
+    public void testEmptyFile() throws Exception {
+        File emptyFile = TempFile.createTempFile("empty", ".poi");
+        try {
+            WorkbookFactory.create(emptyFile);
+            fail("Shouldn't be able to create for an empty file");
+        } finally {
+            assertTrue(emptyFile.delete());
+        }
+    }
+
+    /**
+      * Check that a helpful exception is raised on a non-existing file
+      */
+    @Test(expected = FileNotFoundException.class)
+    public void testNonExistingFile() throws Exception {
+        File nonExistingFile = new File("notExistingFile");
+        assertFalse(nonExistingFile.exists());
+        WorkbookFactory.create(nonExistingFile, "password", true);
+    }
+
+    /**
+     * See Bugzilla bug #62831 - #WorkbookFactory.create(File) needs
+     *  to work for sub-classes of File too, eg JFileChooser
+     */
+    @Test
+    public void testFileSubclass() throws Exception {
+        File normalXLS = HSSFTestDataSamples.getSampleFile(xls);
+        File normalXLSX = HSSFTestDataSamples.getSampleFile(xlsx);
+        File altXLS = new TestFile(normalXLS.getAbsolutePath());
+        File altXLSX = new TestFile(normalXLSX.getAbsolutePath());
+        assertTrue(altXLS.exists());
+        assertTrue(altXLSX.exists());
+
+        try (Workbook wb = WorkbookFactory.create(altXLS)) {
+            assertNotNull(wb);
+            assertTrue(wb instanceof HSSFWorkbook);
+            closeOrRevert(wb);
+        }
+
+        try (Workbook wb = WorkbookFactory.create(altXLSX)) {
+            assertNotNull(wb);
+            assertTrue(wb instanceof XSSFWorkbook);
+            closeOrRevert(wb);
+        }
+    }
+
+    private static class TestFile extends File {
+        public TestFile(String file) {
+            super(file);
+        }
+    }
+
+    /**
+     * Check that the overloaded file methods which take passwords work properly
+     */
+    @Test
+    public void testCreateEmpty() throws Exception {
+        Workbook wb = WorkbookFactory.create(false);
+        assertTrue(wb instanceof HSSFWorkbook);
+        closeOrRevert(wb);
+
+        wb = WorkbookFactory.create(true);
+        assertTrue(wb instanceof XSSFWorkbook);
+        closeOrRevert(wb);
+    }
+
+    @Test
+    @SuppressForbidden("test code")
+    public void testOpenManyHSSF() throws Exception {
+        final int size = 1000;
+        ExecutorService executorService = Executors.newFixedThreadPool(10);
+        ArrayList<Future<Boolean>> futures = new ArrayList(size);
+        for (int i = 0; i < size; i++) {
+            futures.add(executorService.submit(() -> openHSSFFile()));
+        }
+        for (Future<Boolean> future: futures) {
+            assertTrue(future.get());
+        }
+    }
+
+    @Test(expected = IOException.class)
+    public void testInvalidFormatException() throws IOException {
+        String filename = "OPCCompliance_DerivedPartNameFAIL.docx";
+        WorkbookFactory.create(POIDataSamples.getOpenXML4JInstance().openResourceAsStream(filename));
+    }
+
+    private boolean openHSSFFile() {
+        try {
+            // POIFS -> hssf
+            Workbook wb = WorkbookFactory.create(
+                    new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream(xls))
+            );
+            assertNotNull(wb);
+            assertTrue(wb instanceof HSSFWorkbook);
+            assertCloseDoesNotModifyFile(xls, wb);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/extractor/TestEmbeddedExtractor.java b/src/ooxml/testcases/org/apache/poi/ss/tests/extractor/TestEmbeddedExtractor.java
new file mode 100644 (file)
index 0000000..d5d0c47
--- /dev/null
@@ -0,0 +1,135 @@
+/* ====================================================================
+   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.ss.tests.extractor;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.List;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.ss.extractor.EmbeddedData;
+import org.apache.poi.ss.extractor.EmbeddedExtractor;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.junit.Test;
+
+public class TestEmbeddedExtractor {
+    private static final POIDataSamples samples = POIDataSamples.getSpreadSheetInstance();
+
+    @Test
+    public void extractPDFfromEMF() throws Exception {
+        InputStream fis = samples.openResourceAsStream("Basic_Expense_Template_2011.xls");
+        Workbook wb = WorkbookFactory.create(fis);
+        fis.close();
+
+        EmbeddedExtractor ee = new EmbeddedExtractor();
+        List<EmbeddedData> edList = new ArrayList<>();
+        for (Sheet s : wb) {
+            edList.addAll(ee.extractAll(s));
+        }
+        wb.close();
+
+        assertEquals(2, edList.size());
+
+        String filename1 = "Sample.pdf";
+        EmbeddedData ed0 = edList.get(0);
+        assertEquals(filename1, ed0.getFilename());
+        assertEquals(filename1, ed0.getShape().getShapeName().trim());
+        assertEquals("uNplB1QpYug+LWappiTh0w==", md5hash(ed0.getEmbeddedData()));
+
+        String filename2 = "kalastuslupa_jiyjhnj_yuiyuiyuio_uyte_sldfsdfsdf_sfsdfsdf_sfsssfsf_sdfsdfsdfsdf_sdfsdfsdf.pdf";
+        EmbeddedData ed1 = edList.get(1);
+        assertEquals(filename2, ed1.getFilename());
+        assertEquals(filename2, ed1.getShape().getShapeName().trim());
+        assertEquals("QjLuAZ+cd7KbhVz4sj+QdA==", md5hash(ed1.getEmbeddedData()));
+    }
+
+    @Test
+    public void extractFromXSSF() throws IOException, EncryptedDocumentException, InvalidFormatException {
+        InputStream fis = samples.openResourceAsStream("58325_db.xlsx");
+        Workbook wb = WorkbookFactory.create(fis);
+        fis.close();
+
+        EmbeddedExtractor ee = new EmbeddedExtractor();
+        List<EmbeddedData> edList = new ArrayList<>();
+        for (Sheet s : wb) {
+            edList.addAll(ee.extractAll(s));
+        }
+        wb.close();
+
+        assertEquals(4, edList.size());
+        EmbeddedData ed0 = edList.get(0);
+        assertEquals("Object 1.pdf", ed0.getFilename());
+        assertEquals("Object 1", ed0.getShape().getShapeName().trim());
+        assertEquals("Oyys6UtQU1gbHYBYqA4NFA==", md5hash(ed0.getEmbeddedData()));
+
+        EmbeddedData ed1 = edList.get(1);
+        assertEquals("Object 2.pdf", ed1.getFilename());
+        assertEquals("Object 2", ed1.getShape().getShapeName().trim());
+        assertEquals("xLScPUS0XH+5CTZ2A3neNw==", md5hash(ed1.getEmbeddedData()));
+
+        EmbeddedData ed2 = edList.get(2);
+        assertEquals("Object 3.pdf", ed2.getFilename());
+        assertEquals("Object 3", ed2.getShape().getShapeName().trim());
+        assertEquals("rX4klZqJAeM5npb54Gi2+Q==", md5hash(ed2.getEmbeddedData()));
+
+        EmbeddedData ed3 = edList.get(3);
+        assertEquals("Microsoft_Excel_Worksheet1.xlsx", ed3.getFilename());
+        assertEquals("Object 1", ed3.getShape().getShapeName().trim());
+        assertEquals("4m4N8ji2tjpEGPQuw2YwGA==", md5hash(ed3.getEmbeddedData()));
+    }
+
+    public static String md5hash(byte[] input) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] hash = md.digest(input);
+            return Base64.getEncoder().encodeToString(hash);
+        } catch (NoSuchAlgorithmException e) {
+            // doesn't happen
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    @Test
+    public void testNPE() throws IOException {
+        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("angelo.edu_content_files_19555-nsse-2011-multiyear-benchmark.xls");
+        EmbeddedExtractor ee = new EmbeddedExtractor();
+
+        for (Sheet s : wb) {
+            for (EmbeddedData ed : ee.extractAll(s)) {
+                assertNotNull(ed.getFilename());
+                assertNotNull(ed.getEmbeddedData());
+                assertNotNull(ed.getShape());
+            }
+        }
+
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/format/TestCellFormatPart.java b/src/ooxml/testcases/org/apache/poi/ss/tests/format/TestCellFormatPart.java
new file mode 100644 (file)
index 0000000..824fe4b
--- /dev/null
@@ -0,0 +1,211 @@
+/* ====================================================================
+   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.ss.tests.format;
+
+import static java.awt.Color.ORANGE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.JLabel;
+
+import org.apache.poi.ss.ITestDataProvider;
+import org.apache.poi.ss.format.CellFormat;
+import org.apache.poi.ss.format.CellFormatPart;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+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.util.LocaleUtil;
+import org.apache.poi.xssf.XSSFITestDataProvider;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Class for spreadsheet-based tests, such as are used for cell formatting.
+ * This reads tests from the spreadsheet, as well as reading
+ * flags that can be used to paramterize these tests.
+ * <p>
+ * Each test has four parts: The expected result (column A), the format string
+ * (column B), the value to format (column C), and a comma-separated list of
+ * categores that this test falls in. Normally all tests are run, but if the
+ * flag "Categories" is not empty, only tests that have at least one category
+ * listed in "Categories" are run.
+ */
+public class TestCellFormatPart {
+    private static final Pattern NUMBER_EXTRACT_FMT = Pattern.compile(
+            "([-+]?[0-9]+)(\\.[0-9]+)?.*(?:(e).*?([+-]?[0-9]+))",
+            Pattern.CASE_INSENSITIVE);
+    private static final Color TEST_COLOR = ORANGE.darker();
+    private static Locale userLocale;
+
+
+
+    @BeforeClass
+    public static void setLocale() {
+        userLocale = LocaleUtil.getUserLocale();
+        LocaleUtil.setUserLocale(Locale.UK);
+    }
+
+    @AfterClass
+    public static void unsetLocale() {
+        LocaleUtil.setUserLocale(userLocale);
+    }
+
+    private final ITestDataProvider _testDataProvider = XSSFITestDataProvider.instance;
+
+    private interface CellValue {
+        Object getValue(Cell cell);
+
+        default void equivalent(String expected, String actual, CellFormatPart format) {
+            assertEquals("format \"" + format + "\"", '"' + expected + '"',
+                         '"' + actual + '"');
+        }
+    }
+
+    @Test
+    public void testGeneralFormat() throws IOException {
+        runFormatTests("GeneralFormatTests.xlsx", cell -> {
+            assertNotNull(cell);
+            switch (CellFormat.ultimateType(cell)) {
+                case BOOLEAN:
+                    return cell.getBooleanCellValue();
+                case NUMERIC:
+                    return cell.getNumericCellValue();
+                default:
+                    return cell.getStringCellValue();
+            }
+        });
+    }
+
+    @Test
+    public void testNumberFormat() throws IOException {
+        runFormatTests("NumberFormatTests.xlsx", Cell::getNumericCellValue);
+    }
+
+    @Test
+    public void testNumberApproxFormat() throws IOException {
+        runFormatTests("NumberFormatApproxTests.xlsx", new CellValue() {
+            @Override
+            public Object getValue(Cell cell) {
+                return cell.getNumericCellValue();
+            }
+
+            @Override
+            public void equivalent(String expected, String actual,
+                    CellFormatPart format) {
+                double expectedVal = extractNumber(expected);
+                double actualVal = extractNumber(actual);
+                // equal within 1%
+                double delta = expectedVal / 100;
+                assertEquals("format \"" + format + "\"," + expected + " ~= " +
+                        actual, expectedVal, actualVal, delta);
+            }
+        });
+    }
+
+    @Test
+    public void testDateFormat() throws IOException {
+        TimeZone tz = LocaleUtil.getUserTimeZone();
+        LocaleUtil.setUserTimeZone(TimeZone.getTimeZone("CET"));
+        try {
+            runFormatTests("DateFormatTests.xlsx", Cell::getDateCellValue);
+        } finally {
+            LocaleUtil.setUserTimeZone(tz);
+        }
+    }
+
+    @Test
+    public void testElapsedFormat() throws IOException {
+        runFormatTests("ElapsedFormatTests.xlsx", Cell::getNumericCellValue);
+    }
+
+    @Test
+    public void testTextFormat() throws IOException {
+        runFormatTests("TextFormatTests.xlsx", cell ->
+            (CellFormat.ultimateType(cell) == CellType.BOOLEAN) ? cell.getBooleanCellValue() : cell.getStringCellValue()
+        );
+    }
+
+    @Test
+    public void testConditions() throws IOException {
+        runFormatTests("FormatConditionTests.xlsx", Cell::getNumericCellValue);
+    }
+
+    private double extractNumber(String str) {
+        Matcher m = NUMBER_EXTRACT_FMT.matcher(str);
+        if (!m.find()) {
+            throw new IllegalArgumentException("Cannot find number in \"" + str + "\"");
+        }
+
+        StringBuilder sb = new StringBuilder();
+        // The groups in the pattern are the parts of the number
+        for (int i = 1; i <= m.groupCount(); i++) {
+            String part = m.group(i);
+            if (part != null)
+                sb.append(part);
+        }
+        return Double.parseDouble(sb.toString());
+    }
+
+
+    protected void runFormatTests(String workbookName, CellValue valueGetter) throws IOException {
+        try (Workbook workbook = _testDataProvider.openSampleWorkbook(workbookName)) {
+            workbook.setMissingCellPolicy(Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
+
+            Sheet sheet = workbook.getSheet("Tests");
+            boolean isHeader = true;
+            for (Row row : sheet) {
+                // Skip the header row
+                if (isHeader || row == null) {
+                    isHeader = false;
+                    continue;
+                }
+                String expectedText = row.getCell(0).getStringCellValue();
+                String format = row.getCell(1).getStringCellValue();
+                Cell value = row.getCell(2);
+
+                if (expectedText.isEmpty() && format.isEmpty()) {
+                    continue;
+                }
+
+                Object objVal = valueGetter.getValue(value);
+                JLabel label = new JLabel();
+                label.setForeground(TEST_COLOR);
+                label.setText("xyzzy");
+
+                Color origColor = label.getForeground();
+                CellFormatPart cellFormatPart = new CellFormatPart(format);
+                // If this doesn't apply, no color change is expected
+                Color expectedColor = cellFormatPart.apply(label, objVal).applies ? TEST_COLOR : origColor;
+
+                String actualText = label.getText();
+                Color actualColor = label.getForeground();
+                valueGetter.equivalent(expectedText, actualText, cellFormatPart);
+                assertEquals("no color", expectedColor, actualColor);
+            }
+        }
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/formula/TestFormulaParser.java b/src/ooxml/testcases/org/apache/poi/ss/tests/formula/TestFormulaParser.java
new file mode 100644 (file)
index 0000000..01c2f13
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ *  ====================================================================
+ *    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.ss.tests.formula;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.FormulaParseException;
+import org.apache.poi.ss.formula.FormulaParser;
+import org.apache.poi.ss.formula.FormulaParsingWorkbook;
+import org.apache.poi.ss.formula.FormulaType;
+import org.apache.poi.ss.formula.ptg.AbstractFunctionPtg;
+import org.apache.poi.ss.formula.ptg.NameXPxg;
+import org.apache.poi.ss.formula.ptg.Ptg;
+import org.apache.poi.ss.formula.ptg.Ref3DPxg;
+import org.apache.poi.ss.formula.ptg.StringPtg;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.Test;
+
+/**
+ * Test {@link FormulaParser}'s handling of row numbers at the edge of the
+ * HSSF/XSSF ranges.
+ *
+ * @author David North
+ */
+public class TestFormulaParser {
+
+    @Test
+    public void testHSSFFailsForOver65536() {
+        FormulaParsingWorkbook workbook = HSSFEvaluationWorkbook.create(new HSSFWorkbook());
+        try {
+            FormulaParser.parse("Sheet1!1:65537", workbook, FormulaType.CELL, 0);
+            fail("Expected exception");
+        }
+        catch (FormulaParseException expected) {
+            // expected here
+        }
+    }
+
+    private static void checkHSSFFormula(String formula) {
+        HSSFWorkbook wb = new HSSFWorkbook();
+        FormulaParsingWorkbook workbook = HSSFEvaluationWorkbook.create(wb);
+        FormulaParser.parse(formula, workbook, FormulaType.CELL, 0);
+        IOUtils.closeQuietly(wb);
+    }
+    private static void checkXSSFFormula(String formula) {
+        XSSFWorkbook wb = new XSSFWorkbook();
+        FormulaParsingWorkbook workbook = XSSFEvaluationWorkbook.create(wb);
+        FormulaParser.parse(formula, workbook, FormulaType.CELL, 0);
+        IOUtils.closeQuietly(wb);
+    }
+    private static void checkFormula(String formula) {
+        checkHSSFFormula(formula);
+        checkXSSFFormula(formula);
+    }
+
+    @Test
+    public void testHSSFPassCase() {
+        checkHSSFFormula("Sheet1!1:65536");
+    }
+
+    @Test
+    public void testXSSFWorksForOver65536() {
+        checkXSSFFormula("Sheet1!1:65537");
+    }
+
+    @Test
+    public void testXSSFFailCase() {
+        FormulaParsingWorkbook workbook = XSSFEvaluationWorkbook.create(new XSSFWorkbook());
+        try {
+            FormulaParser.parse("Sheet1!1:1048577", workbook, FormulaType.CELL, 0); // one more than max rows.
+            fail("Expected exception");
+        }
+        catch (FormulaParseException expected) {
+            // expected here
+        }
+    }
+
+    // copied from org.apache.poi.hssf.model.TestFormulaParser
+    @Test
+    public void testMacroFunction() throws Exception {
+        // testNames.xlsm contains a VB function called 'myFunc'
+        final String testFile = "testNames.xlsm";
+        try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook(testFile)) {
+            XSSFEvaluationWorkbook workbook = XSSFEvaluationWorkbook.create(wb);
+
+            //Expected ptg stack: [NamePtg(myFunc), StringPtg(arg), (additional operands would go here...), FunctionPtg(myFunc)]
+            Ptg[] ptg = FormulaParser.parse("myFunc(\"arg\")", workbook, FormulaType.CELL, -1);
+            assertEquals(3, ptg.length);
+
+            // the name gets encoded as the first operand on the stack
+            NameXPxg tname = (NameXPxg) ptg[0];
+            assertEquals("myFunc", tname.toFormulaString());
+
+            // the function's arguments are pushed onto the stack from left-to-right as OperandPtgs
+            StringPtg arg = (StringPtg) ptg[1];
+            assertEquals("arg", arg.getValue());
+
+            // The external FunctionPtg is the last Ptg added to the stack
+            // During formula evaluation, this Ptg pops off the the appropriate number of
+            // arguments (getNumberOfOperands()) and pushes the result on the stack
+            AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[2];
+            assertTrue(tfunc.isExternalFunction());
+
+            // confirm formula parsing is case-insensitive
+            FormulaParser.parse("mYfUnC(\"arg\")", workbook, FormulaType.CELL, -1);
+
+            // confirm formula parsing doesn't care about argument count or type
+            // this should only throw an error when evaluating the formula.
+            FormulaParser.parse("myFunc()", workbook, FormulaType.CELL, -1);
+            FormulaParser.parse("myFunc(\"arg\", 0, TRUE)", workbook, FormulaType.CELL, -1);
+
+            // A completely unknown formula name (not saved in workbook) should still be parseable and renderable
+            // but will throw an NotImplementedFunctionException or return a #NAME? error value if evaluated.
+            FormulaParser.parse("yourFunc(\"arg\")", workbook, FormulaType.CELL, -1);
+
+            // Make sure workbook can be written and read
+            XSSFTestDataSamples.writeOutAndReadBack(wb).close();
+
+            // Manually check to make sure file isn't corrupted
+            // TODO: develop a process for occasionally manually reviewing workbooks
+            // to verify workbooks are not corrupted
+            /*
+            final File fileIn = XSSFTestDataSamples.getSampleFile(testFile);
+            final File reSavedFile = new File(fileIn.getParentFile(), fileIn.getName().replace(".xlsm", "-saved.xlsm"));
+            final FileOutputStream fos = new FileOutputStream(reSavedFile);
+            wb.write(fos);
+            fos.close();
+            */
+        }
+    }
+
+    @Test
+    public void testParserErrors() throws Exception {
+        try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("testNames.xlsm")) {
+            XSSFEvaluationWorkbook workbook = XSSFEvaluationWorkbook.create(wb);
+
+            parseExpectedException("(");
+            parseExpectedException(")");
+            parseExpectedException("+");
+            parseExpectedException("42+");
+            parseExpectedException("IF()");
+            parseExpectedException("IF("); //no closing paren
+            parseExpectedException("myFunc(", workbook); //no closing paren
+        }
+    }
+
+    private static void parseExpectedException(String formula) {
+        parseExpectedException(formula, null);
+    }
+
+    /** confirm formula has invalid syntax and parsing the formula results in FormulaParseException
+     */
+    private static void parseExpectedException(String formula, FormulaParsingWorkbook wb) {
+        try {
+            FormulaParser.parse(formula, wb, FormulaType.CELL, -1);
+            fail("Expected FormulaParseException: " + formula);
+        } catch (final FormulaParseException e) {
+            // expected during successful test
+            assertNotNull(e.getMessage());
+        }
+    }
+
+    // trivial case for bug 60219: FormulaParser can't parse external references when sheet name is quoted
+    @Test
+    public void testParseExternalReferencesWithUnquotedSheetName() throws Exception {
+        XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFEvaluationWorkbook fpwb = XSSFEvaluationWorkbook.create(wb);
+        Ptg[] ptgs = FormulaParser.parse("[1]Sheet1!A1", fpwb, FormulaType.CELL, -1);
+        // org.apache.poi.ss.formula.ptg.Ref3DPxg [ [workbook=1] sheet=Sheet 1 ! A1]
+        assertEquals("Ptgs length", 1, ptgs.length);
+        assertTrue("Ptg class", ptgs[0] instanceof Ref3DPxg);
+        Ref3DPxg pxg = (Ref3DPxg) ptgs[0];
+        assertEquals("External workbook number", 1, pxg.getExternalWorkbookNumber());
+        assertEquals("Sheet name", "Sheet1", pxg.getSheetName());
+        assertEquals("Row", 0, pxg.getRow());
+        assertEquals("Column", 0, pxg.getColumn());
+        wb.close();
+    }
+
+    // bug 60219: FormulaParser can't parse external references when sheet name is quoted
+    @Test
+    public void testParseExternalReferencesWithQuotedSheetName() throws Exception {
+        XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFEvaluationWorkbook fpwb = XSSFEvaluationWorkbook.create(wb);
+        Ptg[] ptgs = FormulaParser.parse("'[1]Sheet 1'!A1", fpwb, FormulaType.CELL, -1);
+        // org.apache.poi.ss.formula.ptg.Ref3DPxg [ [workbook=1] sheet=Sheet 1 ! A1]
+        assertEquals("Ptgs length", 1, ptgs.length);
+        assertTrue("Ptg class", ptgs[0] instanceof Ref3DPxg);
+        Ref3DPxg pxg = (Ref3DPxg) ptgs[0];
+        assertEquals("External workbook number", 1, pxg.getExternalWorkbookNumber());
+        assertEquals("Sheet name", "Sheet 1", pxg.getSheetName());
+        assertEquals("Row", 0, pxg.getRow());
+        assertEquals("Column", 0, pxg.getColumn());
+        wb.close();
+    }
+
+    // bug 60260
+    @Test
+    public void testUnicodeSheetName() {
+        checkFormula("'Sheet\u30FB1'!A1:A6");
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/formula/TestStructuredReferences.java b/src/ooxml/testcases/org/apache/poi/ss/tests/formula/TestStructuredReferences.java
new file mode 100644 (file)
index 0000000..aa239a1
--- /dev/null
@@ -0,0 +1,126 @@
+/* ====================================================================
+   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.ss.tests.formula;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.CellValue;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Table;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFTable;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.Test;
+
+/**
+ * Tests Excel Table expressions (structured references)
+ * @see <a href="https://support.office.com/en-us/article/Using-structured-references-with-Excel-tables-F5ED2452-2337-4F71-BED3-C8AE6D2B276E">
+ *         Excel Structured Reference Syntax
+ *      </a>
+ */
+public class TestStructuredReferences {
+
+    /**
+     * Test the regular expression used in INDIRECT() evaluation to recognize structured references
+     */
+    @Test
+    public void testTableExpressionSyntax() {
+        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("abc[col1]").matches());
+        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("_abc[col1]").matches());
+        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("_[col1]").matches());
+        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("\\[col1]").matches());
+        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("\\[col1]").matches());
+        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("\\[#This Row]").matches());
+        assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("\\[ [col1], [col2] ]").matches());
+
+        // can't have a space between the table name and open bracket
+        assertFalse("Invalid structured reference syntax didn't fail expression", Table.isStructuredReference.matcher("\\abc [ [col1], [col2] ]").matches());
+    }
+
+    @Test
+    public void testTableFormulas() throws Exception {
+        try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("StructuredReferences.xlsx")) {
+
+            final FormulaEvaluator eval = new XSSFFormulaEvaluator(wb);
+            final XSSFSheet tableSheet = wb.getSheet("Table");
+            final XSSFSheet formulaSheet = wb.getSheet("Formulas");
+
+            confirm(eval, tableSheet.getRow(5).getCell(0), 49);
+            confirm(eval, formulaSheet.getRow(0).getCell(0), 209);
+            confirm(eval, formulaSheet.getRow(1).getCell(0), "one");
+
+            // test changing a table value, to see if the caches are properly cleared
+            // Issue 59814
+
+            // this test passes before the fix for 59814
+            tableSheet.getRow(1).getCell(1).setCellValue("ONEA");
+            confirm(eval, formulaSheet.getRow(1).getCell(0), "ONEA");
+
+            // test adding a row to a table, issue 59814
+            Row newRow = tableSheet.getRow(7);
+            if (newRow == null) newRow = tableSheet.createRow(7);
+            newRow.createCell(0, CellType.FORMULA).setCellFormula("\\_Prime.1[[#This Row],[@Number]]*\\_Prime.1[[#This Row],[@Number]]");
+            newRow.createCell(1, CellType.STRING).setCellValue("thirteen");
+            newRow.createCell(2, CellType.NUMERIC).setCellValue(13);
+
+            // update Table
+            final XSSFTable table = wb.getTable("\\_Prime.1");
+            final AreaReference newArea = wb.getCreationHelper().createAreaReference(
+                    table.getStartCellReference(),
+                    new CellReference(table.getEndRowIndex() + 1, table.getEndColIndex()));
+            String newAreaStr = newArea.formatAsString();
+            table.getCTTable().setRef(newAreaStr);
+            table.getCTTable().getAutoFilter().setRef(newAreaStr);
+            table.updateHeaders();
+            table.updateReferences();
+
+            // these fail before the fix for 59814
+            confirm(eval, tableSheet.getRow(7).getCell(0), 13 * 13);
+            confirm(eval, formulaSheet.getRow(0).getCell(0), 209 + 13 * 13);
+
+        }
+    }
+
+    private static void confirm(FormulaEvaluator fe, Cell cell, double expectedResult) {
+        fe.clearAllCachedResultValues();
+        CellValue cv = fe.evaluate(cell);
+        if (cv.getCellType() != CellType.NUMERIC) {
+            fail("expected numeric cell type but got " + cv.formatAsString());
+        }
+        assertEquals(expectedResult, cv.getNumberValue(), 0.0);
+    }
+
+    private static void confirm(FormulaEvaluator fe, Cell cell, String expectedResult) {
+        fe.clearAllCachedResultValues();
+        CellValue cv = fe.evaluate(cell);
+        if (cv.getCellType() != CellType.STRING) {
+            fail("expected String cell type but got " + cv.formatAsString());
+        }
+        assertEquals(expectedResult, cv.getStringValue());
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/formula/eval/TestXSSFCircularReferences.java b/src/ooxml/testcases/org/apache/poi/ss/tests/formula/eval/TestXSSFCircularReferences.java
new file mode 100644 (file)
index 0000000..114f70a
--- /dev/null
@@ -0,0 +1,32 @@
+/* ====================================================================
+   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.ss.tests.formula.eval;
+
+import org.apache.poi.ss.formula.eval.BaseTestCircularReferences;
+import org.apache.poi.xssf.XSSFITestDataProvider;
+
+/**
+ * Tests XSSFFormulaEvaluator for its handling of cell formula circular references.
+ *
+ * @author Josh Micich
+ */
+public final class TestXSSFCircularReferences extends BaseTestCircularReferences {
+       public TestXSSFCircularReferences() {
+        super(XSSFITestDataProvider.instance);
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/formula/functions/CountifsTests.java b/src/ooxml/testcases/org/apache/poi/ss/tests/formula/functions/CountifsTests.java
new file mode 100644 (file)
index 0000000..45318e4
--- /dev/null
@@ -0,0 +1,122 @@
+/* ====================================================================
+   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.ss.tests.formula.functions;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.CellValue;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+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.util.SheetUtil;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test the COUNTIFS() function
+ */
+public class CountifsTests {
+
+    private Workbook workbook;
+
+    /**
+     * initialize a workbook
+     */
+    @Before
+    public void before() {
+        // not sure why we allow this, COUNTIFS() is only available
+        // in OOXML, it was introduced with Office 2007
+        workbook = new HSSFWorkbook();
+    }
+
+    /**
+     * Close the workbook if needed
+     */
+    @After
+    public void after() {
+        IOUtils.closeQuietly(workbook);
+    }
+
+    /**
+     * Basic call
+     */
+    @Test
+    public void testCallFunction() {
+        Sheet sheet = workbook.createSheet("test");
+        Row row1 = sheet.createRow(0);
+        Cell cellA1 = row1.createCell(0, CellType.FORMULA);
+        Cell cellB1 = row1.createCell(1, CellType.NUMERIC);
+        Cell cellC1 = row1.createCell(2, CellType.NUMERIC);
+        Cell cellD1 = row1.createCell(3, CellType.NUMERIC);
+        Cell cellE1 = row1.createCell(4, CellType.NUMERIC);
+        cellB1.setCellValue(1);
+        cellC1.setCellValue(1);
+        cellD1.setCellValue(2);
+        cellE1.setCellValue(4);
+
+        cellA1.setCellFormula("COUNTIFS(B1:C1,1, D1:E1,2)");
+        FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
+        CellValue evaluate = evaluator.evaluate(cellA1);
+        assertEquals(1.0d, evaluate.getNumberValue(), 0.000000000000001);
+    }
+
+    /**
+     * Test argument count check
+     */
+    @Test
+    public void testCallFunction_invalidArgs() {
+        Sheet sheet = workbook.createSheet("test");
+        Row row1 = sheet.createRow(0);
+        Cell cellA1 = row1.createCell(0, CellType.FORMULA);
+        cellA1.setCellFormula("COUNTIFS()");
+        FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
+        CellValue evaluate = evaluator.evaluate(cellA1);
+        assertEquals(15, evaluate.getErrorValue());
+        cellA1.setCellFormula("COUNTIFS(A1:C1)");
+        evaluator = workbook.getCreationHelper().createFormulaEvaluator();
+        evaluate = evaluator.evaluate(cellA1);
+        assertEquals(15, evaluate.getErrorValue());
+        cellA1.setCellFormula("COUNTIFS(A1:C1,2,2)");
+        evaluator = workbook.getCreationHelper().createFormulaEvaluator();
+        evaluate = evaluator.evaluate(cellA1);
+        assertEquals(15, evaluate.getErrorValue());
+    }
+
+    /**
+     * the bug returned the wrong count, this verifies the fix
+     * @throws Exception if the file can't be read
+     */
+    @Test
+    public void testBug56822() throws Exception {
+        workbook = XSSFTestDataSamples.openSampleWorkbook("56822-Countifs.xlsx");
+        FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
+        Cell cell = SheetUtil.getCell(workbook.getSheetAt(0), 0, 3);
+        assertNotNull("Test workbook missing cell D1", cell);
+        CellValue evaluate = evaluator.evaluate(cell);
+        assertEquals(2.0d, evaluate.getNumberValue(), 0.00000000000001);
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/formula/functions/TestProper.java b/src/ooxml/testcases/org/apache/poi/ss/tests/formula/functions/TestProper.java
new file mode 100644 (file)
index 0000000..963fda3
--- /dev/null
@@ -0,0 +1,137 @@
+/* ====================================================================
+   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.ss.tests.formula.functions;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.eval.StringEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.functions.TextFunction;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.CellValue;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.Test;
+
+public final class TestProper {
+    private Cell cell11;
+    private FormulaEvaluator evaluator;
+
+    @Test
+    public void testValidHSSF() {
+        HSSFWorkbook wb = new HSSFWorkbook();
+        evaluator = new HSSFFormulaEvaluator(wb);
+
+        confirm(wb);
+    }
+
+    @Test
+    public void testValidXSSF() {
+        XSSFWorkbook wb = new XSSFWorkbook();
+        evaluator = new XSSFFormulaEvaluator(wb);
+
+        confirm(wb);
+    }
+
+    private void confirm(Workbook wb) {
+        Sheet sheet = wb.createSheet("new sheet");
+        cell11 = sheet.createRow(0).createCell(0);
+
+        confirm("PROPER(\"hi there\")", "Hi There"); //simple case
+        confirm("PROPER(\"what's up\")", "What'S Up"); //apostrophes are treated as word breaks
+        confirm("PROPER(\"I DON'T TH!NK SO!\")", "I Don'T Th!Nk So!"); //capitalization is ignored, special punctuation is treated as a word break
+        confirm("PROPER(\"dr\u00dcb\u00f6'\u00e4 \u00e9lo\u015f|\u00eb\u00e8 \")", "Dr\u00fcb\u00f6'\u00c4 \u00c9lo\u015f|\u00cb\u00e8 ");
+        confirm("PROPER(\"hi123 the123re\")", "Hi123 The123Re"); //numbers are treated as word breaks
+        confirm("PROPER(\"-\")", "-"); //nothing happens with ascii punctuation that is not upper or lower case
+        confirm("PROPER(\"!\u00a7$\")", "!\u00a7$"); //nothing happens with unicode punctuation (section sign) that is not upper or lower case
+        confirm("PROPER(\"/&%\")", "/&%"); //nothing happens with ascii punctuation that is not upper or lower case
+        confirm("PROPER(\"Apache POI\")", "Apache Poi"); //acronyms are not special
+        confirm("PROPER(\"  hello world\")", "  Hello World"); //leading whitespace is ignored
+
+        final String scharfes = "\u00df"; //German lowercase eszett, scharfes s, sharp s
+        confirm("PROPER(\"stra"+scharfes+"e\")", "Stra"+scharfes+"e");
+        assertTrue(Character.isLetter(scharfes.charAt(0)));
+
+        // CURRENTLY FAILS: result: "SSUnd"+scharfes
+        // LibreOffice 5.0.3.2 behavior: "Sund"+scharfes
+        // Excel 2013 behavior: ???
+        confirm("PROPER(\""+scharfes+"und"+scharfes+"\")", "SSund"+scharfes);
+
+        // also test longer string
+        StringBuilder builder = new StringBuilder("A");
+        StringBuilder expected = new StringBuilder("A");
+        for(int i = 1;i < 254;i++) {
+            builder.append((char)(65 + (i % 26)));
+            expected.append((char)(97 + (i % 26)));
+        }
+        confirm("PROPER(\"" + builder + "\")", expected.toString());
+    }
+
+    private void confirm(String formulaText, String expectedResult) {
+        cell11.setCellFormula(formulaText);
+        evaluator.clearAllCachedResultValues();
+        CellValue cv = evaluator.evaluate(cell11);
+        assertEquals("Wrong result type", CellType.STRING, cv.getCellType());
+        String actualValue = cv.getStringValue();
+        assertEquals(expectedResult, actualValue);
+    }
+
+    @Test
+    public void test() {
+        checkProper("", "");
+        checkProper("a", "A");
+        checkProper("abc", "Abc");
+        checkProper("abc abc", "Abc Abc");
+        checkProper("abc/abc", "Abc/Abc");
+        checkProper("ABC/ABC", "Abc/Abc");
+        checkProper("aBc/ABC", "Abc/Abc");
+        checkProper("aBc@#$%^&*()_+=-ABC", "Abc@#$%^&*()_+=-Abc");
+        checkProper("aBc25aerg/ABC", "Abc25Aerg/Abc");
+        checkProper("aBc/\u00C4\u00F6\u00DF\u00FC/ABC", "Abc/\u00C4\u00F6\u00DF\u00FC/Abc");  // Some German umlauts with uppercase first letter is not changed
+        checkProper("\u00FC", "\u00DC");
+        checkProper("\u00DC", "\u00DC");
+        checkProper("\u00DF", "SS");    // German "scharfes s" is uppercased to "SS"
+        checkProper("\u00DFomesing", "SSomesing");    // German "scharfes s" is uppercased to "SS"
+        checkProper("aBc/\u00FC\u00C4\u00F6\u00DF\u00FC/ABC", "Abc/\u00DC\u00E4\u00F6\u00DF\u00FC/Abc");  // Some German umlauts with lowercase first letter is changed to uppercase
+    }
+
+    @Test
+    public void testMicroBenchmark() {
+        ValueEval strArg = new StringEval("some longer text that needs a number of replacements to check for runtime of different implementations");
+        long start = System.currentTimeMillis();
+        for(int i = 0;i < 300000;i++) {
+            final ValueEval ret = TextFunction.PROPER.evaluate(new ValueEval[]{strArg}, 0, 0);
+            assertEquals("Some Longer Text That Needs A Number Of Replacements To Check For Runtime Of Different Implementations", ((StringEval)ret).getStringValue());
+        }
+        // Took approx. 600ms on a decent Laptop in July 2016
+        //System.out.println("Took: " + (System.currentTimeMillis() - start) + "ms");
+    }
+
+    private void checkProper(String input, String expected) {
+        ValueEval strArg = new StringEval(input);
+        final ValueEval ret = TextFunction.PROPER.evaluate(new ValueEval[]{strArg}, 0, 0);
+        assertEquals(expected, ((StringEval)ret).getStringValue());
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/formula/functions/TestSumifsXSSF.java b/src/ooxml/testcases/org/apache/poi/ss/tests/formula/functions/TestSumifsXSSF.java
new file mode 100644 (file)
index 0000000..4963148
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one or more
+ *    contributor license agreements.  See the NOTICE file distributed with
+ *    this work for additional information regarding copyright ownership.
+ *    The ASF licenses this file to You under the Apache License, Version 2.0
+ *    (the "License"); you may not use this file except in compliance with
+ *    the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.ss.tests.formula.functions;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class TestSumifsXSSF {
+
+    /**
+     * handle null cell predicate
+     */
+    @Test
+    public void testBug60858() throws IOException {
+        try (Workbook wb = XSSFTestDataSamples.openSampleWorkbook("bug60858.xlsx")) {
+            FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
+
+            Sheet sheet = wb.getSheetAt(0);
+            Cell cell = sheet.getRow(1).getCell(5);
+            fe.evaluate(cell);
+            assertEquals(0.0, cell.getNumericCellValue(), 0.0000000000000001);
+        }
+    }
+
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/formula/functions/TestVlookup.java b/src/ooxml/testcases/org/apache/poi/ss/tests/formula/functions/TestVlookup.java
new file mode 100644 (file)
index 0000000..34bc850
--- /dev/null
@@ -0,0 +1,138 @@
+/* ====================================================================
+   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.ss.tests.formula.functions;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.CellValue;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+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.xssf.XSSFTestDataSamples;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.Test;
+
+/**
+ * Test the VLOOKUP function
+ */
+public class TestVlookup {
+
+    @Test
+    public void testFullColumnAreaRef61841() throws IOException {
+        try (Workbook wb = XSSFTestDataSamples.openSampleWorkbook("VLookupFullColumn.xlsx")) {
+            FormulaEvaluator feval = wb.getCreationHelper().createFormulaEvaluator();
+            feval.evaluateAll();
+            assertEquals("Wrong lookup value", "Value1",
+                    feval.evaluate(wb.getSheetAt(0).getRow(3).getCell(1)).getStringValue());
+            assertEquals("Lookup should return #N/A",
+                    CellType.ERROR, feval.evaluate(wb.getSheetAt(0).getRow(4).getCell(1)).getCellType());
+        }
+    }
+
+    @Test
+    public void bug62275_true() throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {
+            Sheet sheet = wb.createSheet();
+            Row row = sheet.createRow(0);
+
+            Cell cell = row.createCell(0);
+            cell.setCellFormula("vlookup(A2,B1:B5,2,true)");
+
+            CreationHelper createHelper = wb.getCreationHelper();
+            FormulaEvaluator eval = createHelper.createFormulaEvaluator();
+            CellValue value = eval.evaluate(cell);
+
+            assertFalse(value.getBooleanValue());
+        }
+    }
+
+    @Test
+    public void bug62275_false() throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {
+            Sheet sheet = wb.createSheet();
+            Row row = sheet.createRow(0);
+
+            Cell cell = row.createCell(0);
+            cell.setCellFormula("vlookup(A2,B1:B5,2,false)");
+
+            CreationHelper crateHelper = wb.getCreationHelper();
+            FormulaEvaluator eval = crateHelper.createFormulaEvaluator();
+            CellValue value = eval.evaluate(cell);
+
+            assertFalse(value.getBooleanValue());
+        }
+    }
+
+    @Test
+    public void bug62275_empty_3args() throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {
+            Sheet sheet = wb.createSheet();
+            Row row = sheet.createRow(0);
+
+            Cell cell = row.createCell(0);
+            cell.setCellFormula("vlookup(A2,B1:B5,2,)");
+
+            CreationHelper crateHelper = wb.getCreationHelper();
+            FormulaEvaluator eval = crateHelper.createFormulaEvaluator();
+            CellValue value = eval.evaluate(cell);
+
+            assertFalse(value.getBooleanValue());
+        }
+    }
+
+    @Test
+    public void bug62275_empty_2args() throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {
+            Sheet sheet = wb.createSheet();
+            Row row = sheet.createRow(0);
+
+            Cell cell = row.createCell(0);
+            cell.setCellFormula("vlookup(A2,B1:B5,,)");
+
+            CreationHelper crateHelper = wb.getCreationHelper();
+            FormulaEvaluator eval = crateHelper.createFormulaEvaluator();
+            CellValue value = eval.evaluate(cell);
+
+            assertFalse(value.getBooleanValue());
+        }
+    }
+
+    @Test
+    public void bug62275_empty_1arg() throws IOException {
+        try (Workbook wb = new XSSFWorkbook()) {
+            Sheet sheet = wb.createSheet();
+            Row row = sheet.createRow(0);
+
+            Cell cell = row.createCell(0);
+            cell.setCellFormula("vlookup(A2,,,)");
+
+            CreationHelper crateHelper = wb.getCreationHelper();
+            FormulaEvaluator eval = crateHelper.createFormulaEvaluator();
+            CellValue value = eval.evaluate(cell);
+
+            assertFalse(value.getBooleanValue());
+        }
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/BaseTestXCell.java b/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/BaseTestXCell.java
new file mode 100644 (file)
index 0000000..f3eb744
--- /dev/null
@@ -0,0 +1,63 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.tests.usermodel;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.ss.ITestDataProvider;
+import org.apache.poi.ss.usermodel.BaseTestCell;
+import org.apache.poi.ss.usermodel.Cell;
+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.xssf.streaming.SXSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.junit.Test;
+
+/**
+ * Class for combined testing of XML-specific functionality of
+ * {@link XSSFCell} and {@link SXSSFCell}.
+ *
+ *  Any test that is applicable for {@link HSSFCell} as well should go into
+ *  the common base class {@link BaseTestCell}.
+ */
+public abstract class BaseTestXCell extends BaseTestCell {
+    protected BaseTestXCell(ITestDataProvider testDataProvider) {
+        super(testDataProvider);
+    }
+
+    @Test
+    public void testXmlEncoding() throws IOException {
+        Workbook wb1 = _testDataProvider.createWorkbook();
+        Sheet sh = wb1.createSheet();
+        Row row = sh.createRow(0);
+        Cell cell = row.createCell(0);
+        String sval = "\u0000\u0002\u0012<>\t\n\u00a0 &\"POI'\u2122";
+        cell.setCellValue(sval);
+
+        Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1);
+        wb1.close();
+
+        // invalid characters are replaced with question marks
+        assertEquals("???<>\t\n\u00a0 &\"POI'\u2122", wb2.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
+        wb2.close();
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/BaseTestXRow.java b/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/BaseTestXRow.java
new file mode 100644 (file)
index 0000000..b4f2bef
--- /dev/null
@@ -0,0 +1,49 @@
+/* ====================================================================
+   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.ss.tests.usermodel;
+
+import java.io.IOException;
+
+import org.apache.poi.ss.ITestDataProvider;
+import org.apache.poi.ss.usermodel.BaseTestRow;
+import org.apache.poi.xssf.streaming.SXSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.junit.Test;
+
+/**
+ * Class for combined testing of XML-specific functionality of
+ * {@link XSSFRow} and {@link SXSSFRow}.
+ *
+ *  Any test that is applicable for {@link org.apache.poi.hssf.usermodel.HSSFRow} as well should go into
+ *  the common base class {@link BaseTestRow}.
+ */
+public abstract class BaseTestXRow extends BaseTestRow {
+    protected BaseTestXRow(ITestDataProvider testDataProvider) {
+        super(testDataProvider);
+    }
+
+    @Test
+    public void testRowBounds() throws IOException {
+        baseTestRowBounds(_testDataProvider.getSpreadsheetVersion().getLastRowIndex());
+    }
+
+    @Test
+    public void testCellBounds() throws IOException {
+        baseTestCellBounds(_testDataProvider.getSpreadsheetVersion().getLastColumnIndex());
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/BaseTestXSheet.java b/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/BaseTestXSheet.java
new file mode 100644 (file)
index 0000000..ae68cac
--- /dev/null
@@ -0,0 +1,36 @@
+/* ====================================================================
+   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.ss.tests.usermodel;
+
+import org.apache.poi.ss.ITestDataProvider;
+import org.apache.poi.ss.usermodel.BaseTestSheet;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+
+/**
+ * Class for combined testing of XML-specific functionality of
+ * {@link XSSFSheet} and {@link SXSSFSheet}.
+ *
+ *  Any test that is applicable for {@link org.apache.poi.hssf.usermodel.HSSFSheet} as well should go into
+ *  the common base class {@link BaseTestSheet}.
+ */
+public abstract class BaseTestXSheet extends BaseTestSheet {
+    protected BaseTestXSheet(ITestDataProvider testDataProvider) {
+        super(testDataProvider);
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/BaseTestXWorkbook.java b/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/BaseTestXWorkbook.java
new file mode 100644 (file)
index 0000000..49ea01f
--- /dev/null
@@ -0,0 +1,36 @@
+/* ====================================================================
+   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.ss.tests.usermodel;
+
+import org.apache.poi.ss.ITestDataProvider;
+import org.apache.poi.ss.usermodel.BaseTestWorkbook;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Class for combined testing of XML-specific functionality of
+ * {@link XSSFWorkbook} and {@link SXSSFWorkbook}.
+ *
+ *  Any test that is applicable for {@link org.apache.poi.hssf.usermodel.HSSFWorkbook} as well should go into
+ *  the common base class {@link BaseTestWorkbook}.
+ */
+public abstract class BaseTestXWorkbook extends BaseTestWorkbook {
+    protected BaseTestXWorkbook(ITestDataProvider testDataProvider) {
+        super(testDataProvider);
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/ConditionalFormattingEvalTest.java b/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/ConditionalFormattingEvalTest.java
new file mode 100644 (file)
index 0000000..e4e859b
--- /dev/null
@@ -0,0 +1,223 @@
+/* ====================================================================
+   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.ss.tests.usermodel;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.poi.ss.formula.ConditionalFormattingEvaluator;
+import org.apache.poi.ss.formula.EvaluationConditionalFormatRule;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Color;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ConditionalFormattingEvalTest {
+
+    private XSSFWorkbook wb;
+    private Sheet sheet;
+    private XSSFFormulaEvaluator formulaEval;
+    private ConditionalFormattingEvaluator cfe;
+    private CellReference ref;
+    private List<EvaluationConditionalFormatRule> rules;
+
+    @Before
+    public void openWB() {
+        wb = XSSFTestDataSamples.openSampleWorkbook("ConditionalFormattingSamples.xlsx");
+        formulaEval = new XSSFFormulaEvaluator(wb);
+        cfe = new ConditionalFormattingEvaluator(wb, formulaEval);
+    }
+
+    @After
+    public void closeWB() {
+        formulaEval = null;
+        cfe = null;
+        ref = null;
+        rules = null;
+        try {
+            if (wb != null) wb.close();
+        } catch (IOException e) {
+            // keep going, this shouldn't cancel things
+            e.printStackTrace();
+        }
+    }
+
+    @Test
+    public void testFormattingEvaluation() {
+        sheet = wb.getSheet("Products1");
+
+        getRulesFor(12, 1);
+        assertEquals("wrong # of rules for " + ref, 1, rules.size());
+        assertEquals("wrong bg color for " + ref, "FFFFEB9C", getColor(rules.get(0).getRule().getPatternFormatting().getFillBackgroundColorColor()));
+        assertFalse("should not be italic " + ref, rules.get(0).getRule().getFontFormatting().isItalic());
+
+        getRulesFor(16, 3);
+        assertEquals("wrong # of rules for " + ref, 1, rules.size());
+        assertEquals("wrong bg color for " + ref, 0.7999816888943144d, getTint(rules.get(0).getRule().getPatternFormatting().getFillBackgroundColorColor()), 0.000000000000001);
+
+        getRulesFor(12, 3);
+        assertEquals("wrong # of rules for " + ref, 0, rules.size());
+
+        sheet = wb.getSheet("Products2");
+
+        getRulesFor(15,1);
+        assertEquals("wrong # of rules for " + ref, 1, rules.size());
+        assertEquals("wrong bg color for " + ref, "FFFFEB9C", getColor(rules.get(0).getRule().getPatternFormatting().getFillBackgroundColorColor()));
+
+        getRulesFor(20,3);
+        assertEquals("wrong # of rules for " + ref, 0, rules.size());
+
+        // now change a cell value that's an input for the rules
+        Cell cell = sheet.getRow(1).getCell(6);
+        cell.setCellValue("Dairy");
+        formulaEval.notifyUpdateCell(cell);
+        cell = sheet.getRow(4).getCell(6);
+        cell.setCellValue(500);
+        formulaEval.notifyUpdateCell(cell);
+        // need to throw away all evaluations, since we don't know how value changes may have affected format formulas
+        cfe.clearAllCachedValues();
+
+        // test that the conditional validation evaluations changed
+        getRulesFor(15,1);
+        assertEquals("wrong # of rules for " + ref, 0, rules.size());
+
+        getRulesFor(20,3);
+        assertEquals("wrong # of rules for " + ref, 1, rules.size());
+        assertEquals("wrong bg color for " + ref, 0.7999816888943144d, getTint(rules.get(0).getRule().getPatternFormatting().getFillBackgroundColorColor()), 0.000000000000001);
+
+        getRulesFor(20,1);
+        assertEquals("wrong # of rules for " + ref, 1, rules.size());
+        assertEquals("wrong bg color for " + ref, "FFFFEB9C", getColor(rules.get(0).getRule().getPatternFormatting().getFillBackgroundColorColor()));
+
+        sheet = wb.getSheet("Book tour");
+
+        getRulesFor(8,2);
+        assertEquals("wrong # of rules for " + ref, 1, rules.size());
+
+        sheet = wb.getSheet("Compare to totals");
+        getRulesFor(3, 2);
+        assertEquals("wrong # of rules for " + ref, 1, rules.size());
+        assertEquals("wrong fg color for " + ref, "FFFF0000", getColor(rules.get(0).getRule().getFontFormatting().getFontColor()));
+        getRulesFor(3, 3);
+        assertEquals("wrong # of rules for " + ref, 0, rules.size());
+        getRulesFor(15, 4);
+        assertEquals("wrong # of rules for " + ref, 0, rules.size());
+        getRulesFor(16, 1);
+        assertEquals("wrong # of rules for " + ref, 1, rules.size());
+        assertEquals("wrong fg color for " + ref, "FFFF0000", getColor(rules.get(0).getRule().getFontFormatting().getFontColor()));
+
+        sheet = wb.getSheet("Products3");
+        sheet.getRow(8).getCell(0).setCellValue(new Date());
+        getRulesFor(8, 0);
+        assertEquals("wrong # of rules for " + ref, 1, rules.size());
+        getRulesFor(8, 3);
+        assertEquals("wrong # of rules for " + ref, 1, rules.size());
+
+        sheet = wb.getSheet("Customers2");
+        getRulesFor(3, 0);
+        assertEquals("wrong # of rules for " + ref, 0, rules.size());
+    }
+
+    @Test
+    public void testFormattingOnUndefinedCell() throws Exception {
+        wb = XSSFTestDataSamples.openSampleWorkbook("conditional_formatting_with_formula_on_second_sheet.xlsx");
+        formulaEval = new XSSFFormulaEvaluator(wb);
+        cfe = new ConditionalFormattingEvaluator(wb, formulaEval);
+
+        sheet = wb.getSheet("Sales Plan");
+        getRulesFor(9,2);
+        assertNotEquals("No rules for " + ref, 0, rules.size());
+        assertEquals("wrong bg color for " + ref, "FFFFFF00", getColor(rules.get(0).getRule().getPatternFormatting().getFillBackgroundColorColor()));
+    }
+
+    @Test
+    public void testRepeatedEval() throws Exception {
+        wb = XSSFTestDataSamples.openSampleWorkbook("test_conditional_formatting.xlsx");
+        formulaEval = new XSSFFormulaEvaluator(wb);
+        cfe = new ConditionalFormattingEvaluator(wb, formulaEval);
+
+        sheet = wb.getSheetAt(0);
+        assertEquals("no rules should apply", 0, getRulesFor(2, 1).size());
+
+        assertEquals("no rules should apply", 0, getRulesFor(2, 1).size());
+
+    }
+
+    @Test
+    public void testCellValueIsWrongType() throws Exception {
+        wb = XSSFTestDataSamples.openSampleWorkbook("conditional_formatting_cell_is.xlsx");
+        formulaEval = new XSSFFormulaEvaluator(wb);
+        cfe = new ConditionalFormattingEvaluator(wb, formulaEval);
+
+        sheet = wb.getSheetAt(1);
+
+        assertEquals("wrong # of matching rules", 1, getRulesFor(3, 1).size());
+    }
+
+    @Test
+    public void testRangeCondition() throws Exception {
+        wb = XSSFTestDataSamples.openSampleWorkbook("conditional_formatting_multiple_ranges.xlsx");
+        formulaEval = new XSSFFormulaEvaluator(wb);
+        cfe = new ConditionalFormattingEvaluator(wb, formulaEval);
+
+        sheet = wb.getSheetAt(0);
+
+        assertEquals("wrong # of matching rules", 0, getRulesFor(0, 0).size());
+        assertEquals("wrong # of matching rules", 0, getRulesFor(1, 0).size());
+        assertEquals("wrong # of matching rules", 0, getRulesFor(2, 0).size());
+        assertEquals("wrong # of matching rules", 1, getRulesFor(3, 0).size());
+        assertEquals("wrong # of matching rules", 0, getRulesFor(0, 1).size());
+        assertEquals("wrong # of matching rules", 0, getRulesFor(1, 1).size());
+        assertEquals("wrong # of matching rules", 1, getRulesFor(2, 1).size());
+        assertEquals("wrong # of matching rules", 1, getRulesFor(3, 1).size());
+        assertEquals("wrong # of matching rules", 1, getRulesFor(0, 3).size());
+        assertEquals("wrong # of matching rules", 0, getRulesFor(1, 3).size());
+        assertEquals("wrong # of matching rules", 1, getRulesFor(2, 3).size());
+        assertEquals("wrong # of matching rules", 0, getRulesFor(0, 6).size());
+        assertEquals("wrong # of matching rules", 0, getRulesFor(3, 6).size());
+        assertEquals("wrong # of matching rules", 0, getRulesFor(2, 6).size());
+    }
+
+    private List<EvaluationConditionalFormatRule> getRulesFor(int row, int col) {
+        ref = new CellReference(sheet.getSheetName(), row, col, false, false);
+        return rules = cfe.getConditionalFormattingForCell(ref);
+    }
+
+    private String getColor(Color color) {
+        final XSSFColor c = XSSFColor.toXSSFColor(color);
+        return c.getARGBHex();
+    }
+
+    private double getTint(Color color) {
+        final XSSFColor c = XSSFColor.toXSSFColor(color);
+        return c.getTint();
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/TestEmbedOLEPackage.java b/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/TestEmbedOLEPackage.java
new file mode 100644 (file)
index 0000000..f184b01
--- /dev/null
@@ -0,0 +1,231 @@
+/* ====================================================================
+   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.ss.tests.usermodel;
+
+import static org.apache.poi.sl.tests.SLCommonUtils.xslfOnly;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.hpsf.ClassIDPredefined;
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.EntryUtils;
+import org.apache.poi.poifs.filesystem.Ole10Native;
+import org.apache.poi.poifs.filesystem.Ole10NativeException;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.sl.usermodel.AutoShape;
+import org.apache.poi.sl.usermodel.ShapeType;
+import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.ss.extractor.EmbeddedData;
+import org.apache.poi.ss.extractor.EmbeddedExtractor;
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.ObjectData;
+import org.apache.poi.ss.usermodel.Shape;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.apache.poi.xssf.usermodel.XSSFObjectData;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestEmbedOLEPackage {
+    private static byte[] samplePPT, samplePPTX, samplePNG;
+
+    private static final POIDataSamples ssamples = POIDataSamples.getSpreadSheetInstance();
+
+    @BeforeClass
+    public static void init() throws IOException, ReflectiveOperationException {
+        samplePPT = getSamplePPT(false);
+        samplePPTX = getSamplePPT(true);
+        samplePNG = ssamples.readFile("logoKarmokar4.png");
+    }
+
+    @Test
+    public void embedPDF() throws IOException {
+        try (InputStream is = ssamples.openResourceAsStream("bug64512_embed.xlsx");
+            XSSFWorkbook wb = new XSSFWorkbook(is)) {
+            List<XSSFObjectData> oleShapes = new ArrayList<>();
+            List<Ole10Native> ole10s = new ArrayList<>();
+            List<String> digests = new ArrayList<>();
+
+            final boolean digestMatch =
+                wb.getSheetAt(0).getDrawingPatriarch().getShapes().stream()
+                .map(s -> (XSSFObjectData)s)
+                .filter(oleShapes::add)
+                .map(TestEmbedOLEPackage::extractOle10Native)
+                .filter(ole10s::add)
+                .map(TestEmbedOLEPackage::digest)
+                .allMatch("FUJBVHTAZ0ly/TNDNmEj1gQ4a2TbZwDMVF4WUkDQLaM="::equals);
+
+            assertEquals(2, oleShapes.size());
+            assertEquals("Package", oleShapes.get(0).getOLE2ClassName());
+            assertEquals("Package2", oleShapes.get(1).getOLE2ClassName());
+            assertTrue(digestMatch);
+
+            final String expLabel = "Apache_POI_project_logo_(2018).pdf";
+            final String expFilenName = "C:\\Dell\\Apache_POI_project_logo_(2018).pdf";
+            final String expCmd1 = "C:\\Users\\KIWIWI~1\\AppData\\Local\\Temp\\{84287F34-B79C-4F3A-9A92-6BB664586F48}\\Apache_POI_project_logo_(2018).pdf";
+            final String expCmd2 = "C:\\Users\\KIWIWI~1\\AppData\\Local\\Temp\\{84287F34-B79C-4F3A-9A92-6BB664586F48}\\Apache_POI_project_logo_(2).pdf";
+
+            assertTrue(ole10s.stream().map(Ole10Native::getLabel).allMatch(expLabel::equals));
+            assertTrue(ole10s.stream().map(Ole10Native::getFileName).allMatch(expFilenName::equals));
+            assertEquals(expCmd1, ole10s.get(0).getCommand());
+            assertEquals(expCmd2, ole10s.get(1).getCommand());
+
+            for (Ole10Native o : ole10s) {
+                assertEquals(o.getLabel(), o.getLabel2());
+                assertEquals(o.getCommand(), o.getCommand2());
+                assertEquals(o.getFileName(), o.getFileName2());
+            }
+
+            Ole10Native scratch = new Ole10Native(expLabel, expFilenName, expCmd1,  ole10s.get(0).getDataBuffer());
+            scratch.setLabel2(expLabel);
+            scratch.setFileName2(expFilenName);
+            scratch.setCommand2(expCmd1);
+
+            try (POIFSFileSystem scratchFS = new POIFSFileSystem();
+                POIFSFileSystem ole1FS = new POIFSFileSystem(new ByteArrayInputStream(oleShapes.get(0).getObjectData()))) {
+                ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                scratch.writeOut(bos);
+                scratchFS.createDocument(new ByteArrayInputStream(bos.toByteArray()), Ole10Native.OLE10_NATIVE);
+                scratchFS.getRoot().setStorageClsid(ClassIDPredefined.OLE_V1_PACKAGE.getClassID());
+                assertTrue(EntryUtils.areDirectoriesIdentical(ole1FS.getRoot(), scratchFS.getRoot()));
+            }
+        }
+    }
+
+    private static Ole10Native extractOle10Native(XSSFObjectData objectData) {
+        try (InputStream is = objectData.getObjectPart().getInputStream();
+             POIFSFileSystem poifs = new POIFSFileSystem(is)) {
+            return Ole10Native.createFromEmbeddedOleObject(poifs);
+        } catch (IOException | Ole10NativeException e) {
+            throw new AssertionError(e.getMessage(), e);
+        }
+    }
+
+    private static String digest(Ole10Native ole10) {
+        MessageDigest sha = CryptoFunctions.getMessageDigest(HashAlgorithm.sha256);
+        byte[] digest = sha.digest(ole10.getDataBuffer());
+        return Base64.encodeBase64String(digest);
+    }
+
+    @Test
+    public void embedXSSF() throws IOException {
+        Workbook wb1 = new XSSFWorkbook();
+        addEmbeddedObjects(wb1);
+
+        Workbook wb2 = XSSFTestDataSamples.writeOutAndReadBack(wb1);
+        validateEmbeddedObjects(wb2);
+
+        wb2.close();
+        wb1.close();
+    }
+
+    @Test
+    public void embedHSSF() throws IOException {
+        assumeFalse(xslfOnly());
+
+        HSSFWorkbook wb1 = new HSSFWorkbook();
+        addEmbeddedObjects(wb1);
+        Workbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb1);
+        validateEmbeddedObjects(wb2);
+
+        wb2.close();
+        wb1.close();
+    }
+
+    static void validateEmbeddedObjects(Workbook wb) throws IOException {
+        boolean ooxml = wb.getClass().getName().toLowerCase(Locale.ROOT).contains("xssf");
+        byte[] data = (ooxml) ? samplePPTX : samplePPT;
+        Iterator<Integer> shapeIds = Arrays.asList(1025,1026,2049).iterator();
+        EmbeddedExtractor ee = new EmbeddedExtractor();
+        for (Sheet sheet : wb) {
+            Drawing<? extends Shape> pat = sheet.getDrawingPatriarch();
+            for (Shape shape : pat) {
+                assertTrue(shape instanceof ObjectData);
+                ObjectData od = (ObjectData)shape;
+                EmbeddedData ed = ee.extractOne((DirectoryNode)od.getDirectory());
+                assertArrayEquals(data, ed.getEmbeddedData());
+                assertArrayEquals(samplePNG, od.getPictureData().getData());
+                assertEquals((int)shapeIds.next(), od.getShapeId());
+            }
+        }
+    }
+
+    static void addEmbeddedObjects(Workbook wb) throws IOException {
+        boolean ooxml = wb.getClass().getName().toLowerCase(Locale.ROOT).contains("xssf");
+        int picIdx = wb.addPicture(samplePNG, Workbook.PICTURE_TYPE_PNG);
+        byte[] data = (ooxml) ? samplePPTX : samplePPT;
+        String ext = (ooxml) ? ".pptx" : ".ppt";
+
+        int oleIdx1a = wb.addOlePackage(data, "dummy1a"+ext, "dummy1a"+ext, "dummy1a"+ext);
+        int oleIdx1b = wb.addOlePackage(data, "dummy1b"+ext, "dummy1b"+ext, "dummy1b"+ext);
+        int oleIdx2 = wb.addOlePackage(data, "dummy2"+ext, "dummy2"+ext, "dummy2"+ext);
+
+        Sheet sh1 = wb.createSheet();
+        Drawing<?> pat1 = sh1.createDrawingPatriarch();
+        ClientAnchor anchor1a = pat1.createAnchor(0, 0, 0, 0, 1, 1, 3, 6);
+        pat1.createObjectData(anchor1a, oleIdx1a, picIdx);
+        ClientAnchor anchor1b = pat1.createAnchor(0, 0, 0, 0, 1, 1+7, 3, 6+7);
+        pat1.createObjectData(anchor1b, oleIdx1b, picIdx);
+
+        Sheet sh2 = wb.createSheet();
+        Drawing<?> pat2 = sh2.createDrawingPatriarch();
+        ClientAnchor anchor2 = pat2.createAnchor(0, 0, 0, 0, 1, 1, 3, 6);
+        pat2.createObjectData(anchor2, oleIdx2, picIdx);
+    }
+
+    static byte[] getSamplePPT(boolean ooxml) throws IOException, ReflectiveOperationException {
+        SlideShow<?,?> ppt = (ooxml) ? new XMLSlideShow()
+            : (SlideShow<?,?>)Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow").newInstance();
+        Slide<?,?> slide = ppt.createSlide();
+
+        AutoShape<?,?> sh1 = slide.createAutoShape();
+        sh1.setShapeType(ShapeType.STAR_32);
+        sh1.setAnchor(new java.awt.Rectangle(50, 50, 100, 200));
+        sh1.setFillColor(java.awt.Color.red);
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ppt.write(bos);
+        ppt.close();
+
+        return bos.toByteArray();
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/TestXSSFBorderStyle.java b/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/TestXSSFBorderStyle.java
new file mode 100644 (file)
index 0000000..d191c7a
--- /dev/null
@@ -0,0 +1,31 @@
+/* ====================================================================
+   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.ss.tests.usermodel;
+
+import org.apache.poi.ss.usermodel.BaseTestBorderStyle;
+import org.apache.poi.xssf.XSSFITestDataProvider;
+
+/**
+ * @author Yegor Kozlov
+ */
+public final class TestXSSFBorderStyle extends BaseTestBorderStyle {
+
+    public TestXSSFBorderStyle() {
+        super(XSSFITestDataProvider.instance);
+    }
+}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/TestXSSFRangeCopier.java b/src/ooxml/testcases/org/apache/poi/ss/tests/usermodel/TestXSSFRangeCopier.java
new file mode 100644 (file)
index 0000000..858014e
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  ====================================================================
+ *    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.ss.tests.usermodel;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.BaseTestRangeCopier;
+import org.apache.poi.ss.usermodel.CellCopyPolicy;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.xssf.XSSFITestDataProvider;
+import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.apache.poi.xssf.usermodel.XSSFRangeCopier;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestXSSFRangeCopier extends BaseTestRangeCopier {
+    public TestXSSFRangeCopier() {
+        super();
+        workbook = new XSSFWorkbook();
+        testDataProvider = XSSFITestDataProvider.instance;
+    }
+
+    @Before
+    public void init() {
+        workbook = XSSFTestDataSamples.openSampleWorkbook("tile-range-test.xlsx");
+        initSheets();
+        rangeCopier = new XSSFRangeCopier(sheet1, sheet1);
+        transSheetRangeCopier = new XSSFRangeCopier(sheet1, sheet2);
+    }
+
+    @After
+    public void shutdown() throws IOException {
+        workbook.close();
+    }
+
+    @Test // XSSF only. HSSF version wouldn't be so simple. And also this test is contained in following, more complex tests, so it's not really important.
+    public void copyRow() {
+        Row existingRow = sheet1.getRow(4);
+        XSSFRow newRow = (XSSFRow)sheet1.getRow(5);
+        CellCopyPolicy policy = new CellCopyPolicy();
+        newRow.copyRowFrom(existingRow, policy);
+        assertEquals("$C2+B$2", newRow.getCell(1).getCellFormula());
+    }
+
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/util/TestSXSSFCellUtil.java b/src/ooxml/testcases/org/apache/poi/ss/tests/util/TestSXSSFCellUtil.java
new file mode 100644 (file)
index 0000000..3340637
--- /dev/null
@@ -0,0 +1,27 @@
+/* ====================================================================
+   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.ss.tests.util;
+
+import org.apache.poi.ss.util.BaseTestCellUtil;
+import org.apache.poi.xssf.SXSSFITestDataProvider;
+
+public class TestSXSSFCellUtil extends BaseTestCellUtil {
+    public TestSXSSFCellUtil() {
+        super(SXSSFITestDataProvider.instance);
+    }
+}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/util/TestXSSFCellUtil.java b/src/ooxml/testcases/org/apache/poi/ss/tests/util/TestXSSFCellUtil.java
new file mode 100644 (file)
index 0000000..50fc0cf
--- /dev/null
@@ -0,0 +1,27 @@
+/* ====================================================================
+   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.ss.tests.util;
+
+import org.apache.poi.ss.util.BaseTestCellUtil;
+import org.apache.poi.xssf.XSSFITestDataProvider;
+
+public class TestXSSFCellUtil extends BaseTestCellUtil {
+    public TestXSSFCellUtil() {
+        super(XSSFITestDataProvider.instance);
+    }
+}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/ss/tests/util/TestXSSFPropertyTemplate.java b/src/ooxml/testcases/org/apache/poi/ss/tests/util/TestXSSFPropertyTemplate.java
new file mode 100644 (file)
index 0000000..36d0e5b
--- /dev/null
@@ -0,0 +1,138 @@
+/* ====================================================================
+   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.ss.tests.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.BorderExtent;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.IndexedColors;
+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.util.CellRangeAddress;
+import org.apache.poi.ss.util.PropertyTemplate;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.Test;
+
+public class TestXSSFPropertyTemplate {
+
+    @Test
+    public void applyBorders() throws IOException {
+        CellRangeAddress a1c3 = new CellRangeAddress(0, 2, 0, 2);
+        CellRangeAddress b2 = new CellRangeAddress(1, 1, 1, 1);
+        PropertyTemplate pt = new PropertyTemplate();
+        Workbook wb = new XSSFWorkbook();
+        Sheet sheet = wb.createSheet();
+
+        pt.drawBorders(a1c3, BorderStyle.THIN, IndexedColors.RED.getIndex(), BorderExtent.ALL);
+        pt.applyBorders(sheet);
+
+        for (Row row: sheet) {
+            for (Cell cell: row) {
+                CellStyle cs = cell.getCellStyle();
+                assertEquals(BorderStyle.THIN, cs.getBorderTop());
+                assertEquals(IndexedColors.RED.getIndex(), cs.getTopBorderColor());
+                assertEquals(BorderStyle.THIN, cs.getBorderBottom());
+                assertEquals(IndexedColors.RED.getIndex(), cs.getBottomBorderColor());
+                assertEquals(BorderStyle.THIN, cs.getBorderLeft());
+                assertEquals(IndexedColors.RED.getIndex(), cs.getLeftBorderColor());
+                assertEquals(BorderStyle.THIN, cs.getBorderRight());
+                assertEquals(IndexedColors.RED.getIndex(), cs.getRightBorderColor());
+            }
+        }
+
+        pt.drawBorders(b2, BorderStyle.NONE, BorderExtent.ALL);
+        pt.applyBorders(sheet);
+
+        for (Row row: sheet) {
+            for (Cell cell: row) {
+                CellStyle cs = cell.getCellStyle();
+                if (cell.getColumnIndex() != 1 || row.getRowNum() == 0) {
+                assertEquals(BorderStyle.THIN, cs.getBorderTop());
+                assertEquals(IndexedColors.RED.getIndex(), cs.getTopBorderColor());
+                } else {
+                    assertEquals(BorderStyle.NONE, cs.getBorderTop());
+                }
+                if (cell.getColumnIndex() != 1 || row.getRowNum() == 2) {
+                assertEquals(BorderStyle.THIN, cs.getBorderBottom());
+                assertEquals(IndexedColors.RED.getIndex(), cs.getBottomBorderColor());
+                } else {
+                    assertEquals(BorderStyle.NONE, cs.getBorderBottom());
+                }
+                if (cell.getColumnIndex() == 0 || row.getRowNum() != 1) {
+                assertEquals(BorderStyle.THIN, cs.getBorderLeft());
+                assertEquals(IndexedColors.RED.getIndex(), cs.getLeftBorderColor());
+                } else {
+                    assertEquals(BorderStyle.NONE, cs.getBorderLeft());
+                }
+                if (cell.getColumnIndex() == 2 || row.getRowNum() != 1) {
+                assertEquals(BorderStyle.THIN, cs.getBorderRight());
+                assertEquals(IndexedColors.RED.getIndex(), cs.getRightBorderColor());
+                } else {
+                    assertEquals(BorderStyle.NONE, cs.getBorderRight());
+                }
+            }
+        }
+
+        wb.close();
+    }
+
+    @Test
+    public void clonePropertyTemplate() throws IOException {
+        CellRangeAddress a1c3 = new CellRangeAddress(0, 2, 0, 2);
+        PropertyTemplate pt = new PropertyTemplate();
+        pt.drawBorders(a1c3, BorderStyle.MEDIUM, IndexedColors.RED.getIndex(), BorderExtent.ALL);
+        PropertyTemplate pt2 = new PropertyTemplate(pt);
+        assertNotSame(pt2, pt);
+        for (int i = 0; i <= 2; i++) {
+            for (int j = 0; j <= 2; j++) {
+                assertEquals(4, pt2.getNumBorderColors(i, j));
+                assertEquals(4, pt2.getNumBorderColors(i, j));
+            }
+        }
+
+        CellRangeAddress b2 = new CellRangeAddress(1,1,1,1);
+        pt2.drawBorders(b2, BorderStyle.THIN, BorderExtent.ALL);
+
+        Workbook wb = new XSSFWorkbook();
+        Sheet sheet = wb.createSheet();
+        pt.applyBorders(sheet);
+
+        for (Row row : sheet) {
+            for (Cell cell : row) {
+                CellStyle cs = cell.getCellStyle();
+                assertEquals(BorderStyle.MEDIUM, cs.getBorderTop());
+                assertEquals(BorderStyle.MEDIUM, cs.getBorderBottom());
+                assertEquals(BorderStyle.MEDIUM, cs.getBorderLeft());
+                assertEquals(BorderStyle.MEDIUM, cs.getBorderRight());
+                assertEquals(IndexedColors.RED.getIndex(), cs.getTopBorderColor());
+                assertEquals(IndexedColors.RED.getIndex(), cs.getBottomBorderColor());
+                assertEquals(IndexedColors.RED.getIndex(), cs.getLeftBorderColor());
+                assertEquals(IndexedColors.RED.getIndex(), cs.getRightBorderColor());
+            }
+        }
+
+        wb.close();
+    }
+}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/ss/usermodel/BaseTestXCell.java b/src/ooxml/testcases/org/apache/poi/ss/usermodel/BaseTestXCell.java
deleted file mode 100644 (file)
index 46d7d63..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.usermodel;
-
-import static org.junit.Assert.assertEquals;
-
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.ss.ITestDataProvider;
-import org.apache.poi.xssf.streaming.SXSSFCell;
-import org.apache.poi.xssf.usermodel.XSSFCell;
-import org.junit.Test;
-
-/**
- * Class for combined testing of XML-specific functionality of
- * {@link XSSFCell} and {@link SXSSFCell}.
- *
- *  Any test that is applicable for {@link HSSFCell} as well should go into
- *  the common base class {@link BaseTestCell}.
- */
-public abstract class BaseTestXCell extends BaseTestCell {
-    protected BaseTestXCell(ITestDataProvider testDataProvider) {
-        super(testDataProvider);
-    }
-
-    @Test
-    public void testXmlEncoding() throws IOException {
-        Workbook wb1 = _testDataProvider.createWorkbook();
-        Sheet sh = wb1.createSheet();
-        Row row = sh.createRow(0);
-        Cell cell = row.createCell(0);
-        String sval = "\u0000\u0002\u0012<>\t\n\u00a0 &\"POI'\u2122";
-        cell.setCellValue(sval);
-
-        Workbook wb2 = _testDataProvider.writeOutAndReadBack(wb1);
-        wb1.close();
-
-        // invalid characters are replaced with question marks
-        assertEquals("???<>\t\n\u00a0 &\"POI'\u2122", wb2.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
-        wb2.close();
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/usermodel/BaseTestXRow.java b/src/ooxml/testcases/org/apache/poi/ss/usermodel/BaseTestXRow.java
deleted file mode 100644 (file)
index a4b2100..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.usermodel;
-
-import java.io.IOException;
-
-import org.apache.poi.ss.ITestDataProvider;
-import org.apache.poi.xssf.streaming.SXSSFRow;
-import org.apache.poi.xssf.usermodel.XSSFRow;
-import org.junit.Test;
-
-/**
- * Class for combined testing of XML-specific functionality of 
- * {@link XSSFRow} and {@link SXSSFRow}.
- * 
- *  Any test that is applicable for {@link org.apache.poi.hssf.usermodel.HSSFRow} as well should go into
- *  the common base class {@link BaseTestRow}.
- */
-public abstract class BaseTestXRow extends BaseTestRow {
-    protected BaseTestXRow(ITestDataProvider testDataProvider) {
-        super(testDataProvider);
-    }
-
-    @Test
-    public void testRowBounds() throws IOException {
-        baseTestRowBounds(_testDataProvider.getSpreadsheetVersion().getLastRowIndex());
-    }
-
-    @Test
-    public void testCellBounds() throws IOException {
-        baseTestCellBounds(_testDataProvider.getSpreadsheetVersion().getLastColumnIndex());
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/usermodel/BaseTestXSheet.java b/src/ooxml/testcases/org/apache/poi/ss/usermodel/BaseTestXSheet.java
deleted file mode 100644 (file)
index f6e1bff..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.usermodel;
-
-import org.apache.poi.ss.ITestDataProvider;
-import org.apache.poi.xssf.streaming.SXSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-
-/**
- * Class for combined testing of XML-specific functionality of 
- * {@link XSSFSheet} and {@link SXSSFSheet}.
- * 
- *  Any test that is applicable for {@link org.apache.poi.hssf.usermodel.HSSFSheet} as well should go into
- *  the common base class {@link BaseTestSheet}.
- */
-public abstract class BaseTestXSheet extends BaseTestSheet {
-    protected BaseTestXSheet(ITestDataProvider testDataProvider) {
-        super(testDataProvider);
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/usermodel/BaseTestXWorkbook.java b/src/ooxml/testcases/org/apache/poi/ss/usermodel/BaseTestXWorkbook.java
deleted file mode 100644 (file)
index 9c7fe3a..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.usermodel;
-
-import org.apache.poi.ss.ITestDataProvider;
-import org.apache.poi.xssf.streaming.SXSSFWorkbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-/**
- * Class for combined testing of XML-specific functionality of 
- * {@link XSSFWorkbook} and {@link SXSSFWorkbook}.
- * 
- *  Any test that is applicable for {@link org.apache.poi.hssf.usermodel.HSSFWorkbook} as well should go into
- *  the common base class {@link BaseTestWorkbook}.
- */
-public abstract class BaseTestXWorkbook extends BaseTestWorkbook {
-    protected BaseTestXWorkbook(ITestDataProvider testDataProvider) {
-        super(testDataProvider);
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/usermodel/ConditionalFormattingEvalTest.java b/src/ooxml/testcases/org/apache/poi/ss/usermodel/ConditionalFormattingEvalTest.java
deleted file mode 100644 (file)
index c889eb8..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.usermodel;
-
-
-import java.io.IOException;
-import java.util.Date;
-import java.util.List;
-
-import org.apache.poi.ss.formula.ConditionalFormattingEvaluator;
-import org.apache.poi.ss.formula.EvaluationConditionalFormatRule;
-import org.apache.poi.ss.formula.eval.NotImplementedException;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xssf.XSSFTestDataSamples;
-import org.apache.poi.xssf.usermodel.XSSFColor;
-import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ConditionalFormattingEvalTest {
-
-    private XSSFWorkbook wb;
-    private Sheet sheet;
-    private XSSFFormulaEvaluator formulaEval;
-    private ConditionalFormattingEvaluator cfe;
-    private CellReference ref;
-    private List<EvaluationConditionalFormatRule> rules;
-
-    @Before
-    public void openWB() {
-        wb = XSSFTestDataSamples.openSampleWorkbook("ConditionalFormattingSamples.xlsx");
-        formulaEval = new XSSFFormulaEvaluator(wb);
-        cfe = new ConditionalFormattingEvaluator(wb, formulaEval);
-    }
-    
-    @After
-    public void closeWB() {
-        formulaEval = null;
-        cfe = null;
-        ref = null;
-        rules = null;
-        try {
-            if (wb != null) wb.close();
-        } catch (IOException e) {
-            // keep going, this shouldn't cancel things
-            e.printStackTrace();
-        }
-    }
-
-    @Test
-    public void testFormattingEvaluation() {
-        sheet = wb.getSheet("Products1");
-        
-        getRulesFor(12, 1);
-        assertEquals("wrong # of rules for " + ref, 1, rules.size());
-        assertEquals("wrong bg color for " + ref, "FFFFEB9C", getColor(rules.get(0).getRule().getPatternFormatting().getFillBackgroundColorColor()));
-        assertFalse("should not be italic " + ref, rules.get(0).getRule().getFontFormatting().isItalic());
-        
-        getRulesFor(16, 3);
-        assertEquals("wrong # of rules for " + ref, 1, rules.size());
-        assertEquals("wrong bg color for " + ref, 0.7999816888943144d, getTint(rules.get(0).getRule().getPatternFormatting().getFillBackgroundColorColor()), 0.000000000000001);
-        
-        getRulesFor(12, 3);
-        assertEquals("wrong # of rules for " + ref, 0, rules.size());
-        
-        sheet = wb.getSheet("Products2");
-        
-        getRulesFor(15,1);
-        assertEquals("wrong # of rules for " + ref, 1, rules.size());
-        assertEquals("wrong bg color for " + ref, "FFFFEB9C", getColor(rules.get(0).getRule().getPatternFormatting().getFillBackgroundColorColor()));
-
-        getRulesFor(20,3);
-        assertEquals("wrong # of rules for " + ref, 0, rules.size());
-
-        // now change a cell value that's an input for the rules
-        Cell cell = sheet.getRow(1).getCell(6);
-        cell.setCellValue("Dairy");
-        formulaEval.notifyUpdateCell(cell);
-        cell = sheet.getRow(4).getCell(6);
-        cell.setCellValue(500);
-        formulaEval.notifyUpdateCell(cell);
-        // need to throw away all evaluations, since we don't know how value changes may have affected format formulas
-        cfe.clearAllCachedValues();
-        
-        // test that the conditional validation evaluations changed
-        getRulesFor(15,1);
-        assertEquals("wrong # of rules for " + ref, 0, rules.size());
-        
-        getRulesFor(20,3);
-        assertEquals("wrong # of rules for " + ref, 1, rules.size());
-        assertEquals("wrong bg color for " + ref, 0.7999816888943144d, getTint(rules.get(0).getRule().getPatternFormatting().getFillBackgroundColorColor()), 0.000000000000001);
-        
-        getRulesFor(20,1);
-        assertEquals("wrong # of rules for " + ref, 1, rules.size());
-        assertEquals("wrong bg color for " + ref, "FFFFEB9C", getColor(rules.get(0).getRule().getPatternFormatting().getFillBackgroundColorColor()));
-        
-        sheet = wb.getSheet("Book tour");
-        
-        getRulesFor(8,2);
-        assertEquals("wrong # of rules for " + ref, 1, rules.size());
-        
-        sheet = wb.getSheet("Compare to totals");
-        getRulesFor(3, 2);
-        assertEquals("wrong # of rules for " + ref, 1, rules.size());
-        assertEquals("wrong fg color for " + ref, "FFFF0000", getColor(rules.get(0).getRule().getFontFormatting().getFontColor()));
-        getRulesFor(3, 3);
-        assertEquals("wrong # of rules for " + ref, 0, rules.size());
-        getRulesFor(15, 4);
-        assertEquals("wrong # of rules for " + ref, 0, rules.size());
-        getRulesFor(16, 1);
-        assertEquals("wrong # of rules for " + ref, 1, rules.size());
-        assertEquals("wrong fg color for " + ref, "FFFF0000", getColor(rules.get(0).getRule().getFontFormatting().getFontColor()));
-        
-        sheet = wb.getSheet("Products3");
-        sheet.getRow(8).getCell(0).setCellValue(new Date());
-        getRulesFor(8, 0);
-        assertEquals("wrong # of rules for " + ref, 1, rules.size());
-        getRulesFor(8, 3);
-        assertEquals("wrong # of rules for " + ref, 1, rules.size());
-
-        sheet = wb.getSheet("Customers2");
-        getRulesFor(3, 0);
-        assertEquals("wrong # of rules for " + ref, 0, rules.size());
-    }
-
-    @Test
-    public void testFormattingOnUndefinedCell() throws Exception {
-        wb = XSSFTestDataSamples.openSampleWorkbook("conditional_formatting_with_formula_on_second_sheet.xlsx");
-        formulaEval = new XSSFFormulaEvaluator(wb);
-        cfe = new ConditionalFormattingEvaluator(wb, formulaEval);
-
-        sheet = wb.getSheet("Sales Plan");
-        getRulesFor(9,2);
-        assertNotEquals("No rules for " + ref, 0, rules.size());
-        assertEquals("wrong bg color for " + ref, "FFFFFF00", getColor(rules.get(0).getRule().getPatternFormatting().getFillBackgroundColorColor()));
-    }
-    
-    @Test
-    public void testRepeatedEval() throws Exception {
-        wb = XSSFTestDataSamples.openSampleWorkbook("test_conditional_formatting.xlsx");
-        formulaEval = new XSSFFormulaEvaluator(wb);
-        cfe = new ConditionalFormattingEvaluator(wb, formulaEval);
-
-        sheet = wb.getSheetAt(0);
-        assertEquals("no rules should apply", 0, getRulesFor(2, 1).size());
-
-        assertEquals("no rules should apply", 0, getRulesFor(2, 1).size());
-        
-    }
-    
-    @Test
-    public void testCellValueIsWrongType() throws Exception {
-        wb = XSSFTestDataSamples.openSampleWorkbook("conditional_formatting_cell_is.xlsx");
-        formulaEval = new XSSFFormulaEvaluator(wb);
-        cfe = new ConditionalFormattingEvaluator(wb, formulaEval);
-
-        sheet = wb.getSheetAt(1);
-        
-        assertEquals("wrong # of matching rules", 1, getRulesFor(3, 1).size());
-    }
-    
-    @Test
-    public void testRangeCondition() throws Exception {
-        wb = XSSFTestDataSamples.openSampleWorkbook("conditional_formatting_multiple_ranges.xlsx");
-        formulaEval = new XSSFFormulaEvaluator(wb);
-        cfe = new ConditionalFormattingEvaluator(wb, formulaEval);
-        
-        sheet = wb.getSheetAt(0);
-        
-        assertEquals("wrong # of matching rules", 0, getRulesFor(0, 0).size());
-        assertEquals("wrong # of matching rules", 0, getRulesFor(1, 0).size());
-        assertEquals("wrong # of matching rules", 0, getRulesFor(2, 0).size());
-        assertEquals("wrong # of matching rules", 1, getRulesFor(3, 0).size());
-        assertEquals("wrong # of matching rules", 0, getRulesFor(0, 1).size());
-        assertEquals("wrong # of matching rules", 0, getRulesFor(1, 1).size());
-        assertEquals("wrong # of matching rules", 1, getRulesFor(2, 1).size());
-        assertEquals("wrong # of matching rules", 1, getRulesFor(3, 1).size());
-        assertEquals("wrong # of matching rules", 1, getRulesFor(0, 3).size());
-        assertEquals("wrong # of matching rules", 0, getRulesFor(1, 3).size());
-        assertEquals("wrong # of matching rules", 1, getRulesFor(2, 3).size());
-        assertEquals("wrong # of matching rules", 0, getRulesFor(0, 6).size());
-        assertEquals("wrong # of matching rules", 0, getRulesFor(3, 6).size());
-        assertEquals("wrong # of matching rules", 0, getRulesFor(2, 6).size());
-    }
-    
-    private List<EvaluationConditionalFormatRule> getRulesFor(int row, int col) {
-        ref = new CellReference(sheet.getSheetName(), row, col, false, false);
-        return rules = cfe.getConditionalFormattingForCell(ref);
-    }
-    
-    private String getColor(Color color) {
-        final XSSFColor c = XSSFColor.toXSSFColor(color);
-        return c.getARGBHex();
-    }
-
-    private double getTint(Color color) {
-        final XSSFColor c = XSSFColor.toXSSFColor(color);
-        return c.getTint();
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestEmbedOLEPackage.java b/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestEmbedOLEPackage.java
deleted file mode 100644 (file)
index 0be9f1f..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.usermodel;
-
-import static org.apache.poi.sl.SLCommonUtils.xslfOnly;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.MessageDigest;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.hpsf.ClassIDPredefined;
-import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.poifs.crypt.CryptoFunctions;
-import org.apache.poi.poifs.crypt.HashAlgorithm;
-import org.apache.poi.poifs.filesystem.DirectoryNode;
-import org.apache.poi.poifs.filesystem.EntryUtils;
-import org.apache.poi.poifs.filesystem.Ole10Native;
-import org.apache.poi.poifs.filesystem.Ole10NativeException;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.sl.usermodel.AutoShape;
-import org.apache.poi.sl.usermodel.ShapeType;
-import org.apache.poi.sl.usermodel.Slide;
-import org.apache.poi.sl.usermodel.SlideShow;
-import org.apache.poi.ss.extractor.EmbeddedData;
-import org.apache.poi.ss.extractor.EmbeddedExtractor;
-import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.apache.poi.xssf.XSSFTestDataSamples;
-import org.apache.poi.xssf.usermodel.XSSFObjectData;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-public class TestEmbedOLEPackage {
-    private static byte[] samplePPT, samplePPTX, samplePNG;
-
-    private static final POIDataSamples ssamples = POIDataSamples.getSpreadSheetInstance();
-
-    @BeforeClass
-    public static void init() throws IOException, ReflectiveOperationException {
-        samplePPT = getSamplePPT(false);
-        samplePPTX = getSamplePPT(true);
-        samplePNG = ssamples.readFile("logoKarmokar4.png");
-    }
-
-    @Test
-    public void embedPDF() throws IOException {
-        try (InputStream is = ssamples.openResourceAsStream("bug64512_embed.xlsx");
-            XSSFWorkbook wb = new XSSFWorkbook(is)) {
-            List<XSSFObjectData> oleShapes = new ArrayList<>();
-            List<Ole10Native> ole10s = new ArrayList<>();
-            List<String> digests = new ArrayList<>();
-
-            final boolean digestMatch =
-                wb.getSheetAt(0).getDrawingPatriarch().getShapes().stream()
-                .map(s -> (XSSFObjectData)s)
-                .filter(oleShapes::add)
-                .map(TestEmbedOLEPackage::extractOle10Native)
-                .filter(ole10s::add)
-                .map(TestEmbedOLEPackage::digest)
-                .allMatch("FUJBVHTAZ0ly/TNDNmEj1gQ4a2TbZwDMVF4WUkDQLaM="::equals);
-
-            assertEquals(2, oleShapes.size());
-            assertEquals("Package", oleShapes.get(0).getOLE2ClassName());
-            assertEquals("Package2", oleShapes.get(1).getOLE2ClassName());
-            assertTrue(digestMatch);
-
-            final String expLabel = "Apache_POI_project_logo_(2018).pdf";
-            final String expFilenName = "C:\\Dell\\Apache_POI_project_logo_(2018).pdf";
-            final String expCmd1 = "C:\\Users\\KIWIWI~1\\AppData\\Local\\Temp\\{84287F34-B79C-4F3A-9A92-6BB664586F48}\\Apache_POI_project_logo_(2018).pdf";
-            final String expCmd2 = "C:\\Users\\KIWIWI~1\\AppData\\Local\\Temp\\{84287F34-B79C-4F3A-9A92-6BB664586F48}\\Apache_POI_project_logo_(2).pdf";
-
-            assertTrue(ole10s.stream().map(Ole10Native::getLabel).allMatch(expLabel::equals));
-            assertTrue(ole10s.stream().map(Ole10Native::getFileName).allMatch(expFilenName::equals));
-            assertEquals(expCmd1, ole10s.get(0).getCommand());
-            assertEquals(expCmd2, ole10s.get(1).getCommand());
-
-            for (Ole10Native o : ole10s) {
-                assertEquals(o.getLabel(), o.getLabel2());
-                assertEquals(o.getCommand(), o.getCommand2());
-                assertEquals(o.getFileName(), o.getFileName2());
-            }
-
-            Ole10Native scratch = new Ole10Native(expLabel, expFilenName, expCmd1,  ole10s.get(0).getDataBuffer());
-            scratch.setLabel2(expLabel);
-            scratch.setFileName2(expFilenName);
-            scratch.setCommand2(expCmd1);
-
-            try (POIFSFileSystem scratchFS = new POIFSFileSystem();
-                POIFSFileSystem ole1FS = new POIFSFileSystem(new ByteArrayInputStream(oleShapes.get(0).getObjectData()))) {
-                ByteArrayOutputStream bos = new ByteArrayOutputStream();
-                scratch.writeOut(bos);
-                scratchFS.createDocument(new ByteArrayInputStream(bos.toByteArray()), Ole10Native.OLE10_NATIVE);
-                scratchFS.getRoot().setStorageClsid(ClassIDPredefined.OLE_V1_PACKAGE.getClassID());
-                assertTrue(EntryUtils.areDirectoriesIdentical(ole1FS.getRoot(), scratchFS.getRoot()));
-            }
-        }
-    }
-
-    private static Ole10Native extractOle10Native(XSSFObjectData objectData) {
-        try (InputStream is = objectData.getObjectPart().getInputStream();
-             POIFSFileSystem poifs = new POIFSFileSystem(is)) {
-            return Ole10Native.createFromEmbeddedOleObject(poifs);
-        } catch (IOException | Ole10NativeException e) {
-            throw new AssertionError(e.getMessage(), e);
-        }
-    }
-
-    private static String digest(Ole10Native ole10) {
-        MessageDigest sha = CryptoFunctions.getMessageDigest(HashAlgorithm.sha256);
-        byte[] digest = sha.digest(ole10.getDataBuffer());
-        return Base64.encodeBase64String(digest);
-    }
-
-    @Test
-    public void embedXSSF() throws IOException {
-        Workbook wb1 = new XSSFWorkbook();
-        addEmbeddedObjects(wb1);
-
-        Workbook wb2 = XSSFTestDataSamples.writeOutAndReadBack(wb1);
-        validateEmbeddedObjects(wb2);
-
-        wb2.close();
-        wb1.close();
-    }
-
-    @Test
-    public void embedHSSF() throws IOException {
-        assumeFalse(xslfOnly());
-
-        HSSFWorkbook wb1 = new HSSFWorkbook();
-        addEmbeddedObjects(wb1);
-        Workbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb1);
-        validateEmbeddedObjects(wb2);
-
-        wb2.close();
-        wb1.close();
-    }
-
-    static void validateEmbeddedObjects(Workbook wb) throws IOException {
-        boolean ooxml = wb.getClass().getName().toLowerCase(Locale.ROOT).contains("xssf");
-        byte[] data = (ooxml) ? samplePPTX : samplePPT;
-        Iterator<Integer> shapeIds = Arrays.asList(1025,1026,2049).iterator();
-        EmbeddedExtractor ee = new EmbeddedExtractor();
-        for (Sheet sheet : wb) {
-            Drawing<? extends Shape> pat = sheet.getDrawingPatriarch();
-            for (Shape shape : pat) {
-                assertTrue(shape instanceof ObjectData);
-                ObjectData od = (ObjectData)shape;
-                EmbeddedData ed = ee.extractOne((DirectoryNode)od.getDirectory());
-                assertArrayEquals(data, ed.getEmbeddedData());
-                assertArrayEquals(samplePNG, od.getPictureData().getData());
-                assertEquals((int)shapeIds.next(), od.getShapeId());
-            }
-        }
-    }
-
-    static void addEmbeddedObjects(Workbook wb) throws IOException {
-        boolean ooxml = wb.getClass().getName().toLowerCase(Locale.ROOT).contains("xssf");
-        int picIdx = wb.addPicture(samplePNG, Workbook.PICTURE_TYPE_PNG);
-        byte[] data = (ooxml) ? samplePPTX : samplePPT;
-        String ext = (ooxml) ? ".pptx" : ".ppt";
-
-        int oleIdx1a = wb.addOlePackage(data, "dummy1a"+ext, "dummy1a"+ext, "dummy1a"+ext);
-        int oleIdx1b = wb.addOlePackage(data, "dummy1b"+ext, "dummy1b"+ext, "dummy1b"+ext);
-        int oleIdx2 = wb.addOlePackage(data, "dummy2"+ext, "dummy2"+ext, "dummy2"+ext);
-
-        Sheet sh1 = wb.createSheet();
-        Drawing<?> pat1 = sh1.createDrawingPatriarch();
-        ClientAnchor anchor1a = pat1.createAnchor(0, 0, 0, 0, 1, 1, 3, 6);
-        pat1.createObjectData(anchor1a, oleIdx1a, picIdx);
-        ClientAnchor anchor1b = pat1.createAnchor(0, 0, 0, 0, 1, 1+7, 3, 6+7);
-        pat1.createObjectData(anchor1b, oleIdx1b, picIdx);
-
-        Sheet sh2 = wb.createSheet();
-        Drawing<?> pat2 = sh2.createDrawingPatriarch();
-        ClientAnchor anchor2 = pat2.createAnchor(0, 0, 0, 0, 1, 1, 3, 6);
-        pat2.createObjectData(anchor2, oleIdx2, picIdx);
-    }
-
-    static byte[] getSamplePPT(boolean ooxml) throws IOException, ReflectiveOperationException {
-        SlideShow<?,?> ppt = (ooxml) ? new XMLSlideShow()
-            : (SlideShow<?,?>)Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow").newInstance();
-        Slide<?,?> slide = ppt.createSlide();
-
-        AutoShape<?,?> sh1 = slide.createAutoShape();
-        sh1.setShapeType(ShapeType.STAR_32);
-        sh1.setAnchor(new java.awt.Rectangle(50, 50, 100, 200));
-        sh1.setFillColor(java.awt.Color.red);
-
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        ppt.write(bos);
-        ppt.close();
-
-        return bos.toByteArray();
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestXSSFBorderStyle.java b/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestXSSFBorderStyle.java
deleted file mode 100644 (file)
index 2e9334b..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.usermodel;
-
-import org.apache.poi.xssf.XSSFITestDataProvider;
-
-/**
- * @author Yegor Kozlov
- */
-public final class TestXSSFBorderStyle extends BaseTestBorderStyle  {
-
-    public TestXSSFBorderStyle() {
-        super(XSSFITestDataProvider.instance);
-    }
-}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestXSSFRangeCopier.java b/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestXSSFRangeCopier.java
deleted file mode 100644 (file)
index 35f8911..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.ss.usermodel;
-
-import static org.junit.Assert.assertEquals;
-
-import org.apache.poi.xssf.XSSFITestDataProvider;
-import org.apache.poi.xssf.XSSFTestDataSamples;
-import org.apache.poi.xssf.usermodel.XSSFRangeCopier;
-import org.apache.poi.xssf.usermodel.XSSFRow;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.IOException;
-
-public class TestXSSFRangeCopier extends TestRangeCopier {
-    public TestXSSFRangeCopier() {
-        super();
-        workbook = new XSSFWorkbook();
-        testDataProvider = XSSFITestDataProvider.instance;
-    }
-
-    @Before
-    public void init() {
-        workbook = XSSFTestDataSamples.openSampleWorkbook("tile-range-test.xlsx");
-        initSheets();
-        rangeCopier = new XSSFRangeCopier(sheet1, sheet1);
-        transSheetRangeCopier = new XSSFRangeCopier(sheet1, sheet2);
-    }
-
-    @After
-    public void shutdown() throws IOException {
-        workbook.close();
-    }
-
-    @Test // XSSF only. HSSF version wouldn't be so simple. And also this test is contained in following, more complex tests, so it's not really important.
-    public void copyRow() {
-        Row existingRow = sheet1.getRow(4);
-        XSSFRow newRow = (XSSFRow)sheet1.getRow(5);
-        CellCopyPolicy policy = new CellCopyPolicy();
-        newRow.copyRowFrom(existingRow, policy);
-        assertEquals("$C2+B$2", newRow.getCell(1).getCellFormula());
-    }
-
-}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/util/TestSXSSFCellUtil.java b/src/ooxml/testcases/org/apache/poi/ss/util/TestSXSSFCellUtil.java
deleted file mode 100644 (file)
index 70c5fae..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-   
-   http://www.apache.org/licenses/LICENSE-2.0
-   
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-   ==================================================================== */
-
-package org.apache.poi.ss.util;
-
-import org.apache.poi.xssf.SXSSFITestDataProvider;
-
-public class TestSXSSFCellUtil extends BaseTestCellUtil {
-    public TestSXSSFCellUtil() {
-        super(SXSSFITestDataProvider.instance);
-    }
-}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/ss/util/TestXSSFCellUtil.java b/src/ooxml/testcases/org/apache/poi/ss/util/TestXSSFCellUtil.java
deleted file mode 100644 (file)
index c58ebe9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-   
-   http://www.apache.org/licenses/LICENSE-2.0
-   
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-   ==================================================================== */
-
-package org.apache.poi.ss.util;
-
-import org.apache.poi.xssf.XSSFITestDataProvider;
-
-public class TestXSSFCellUtil extends BaseTestCellUtil {
-    public TestXSSFCellUtil() {
-        super(XSSFITestDataProvider.instance);
-    }
-}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/ss/util/TestXSSFPropertyTemplate.java b/src/ooxml/testcases/org/apache/poi/ss/util/TestXSSFPropertyTemplate.java
deleted file mode 100644 (file)
index b1055e1..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotSame;
-
-import java.io.IOException;
-
-import org.apache.poi.ss.usermodel.BorderExtent;
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.IndexedColors;
-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.xssf.usermodel.XSSFWorkbook;
-import org.junit.Test;
-
-public class TestXSSFPropertyTemplate {
-    
-    @Test
-    public void applyBorders() throws IOException {
-        CellRangeAddress a1c3 = new CellRangeAddress(0, 2, 0, 2);
-        CellRangeAddress b2 = new CellRangeAddress(1, 1, 1, 1);
-        PropertyTemplate pt = new PropertyTemplate();
-        Workbook wb = new XSSFWorkbook();
-        Sheet sheet = wb.createSheet();
-        
-        pt.drawBorders(a1c3, BorderStyle.THIN, IndexedColors.RED.getIndex(), BorderExtent.ALL);
-        pt.applyBorders(sheet);
-        
-        for (Row row: sheet) {
-            for (Cell cell: row) {
-                CellStyle cs = cell.getCellStyle();
-                assertEquals(BorderStyle.THIN, cs.getBorderTop());
-                assertEquals(IndexedColors.RED.getIndex(), cs.getTopBorderColor());
-                assertEquals(BorderStyle.THIN, cs.getBorderBottom());
-                assertEquals(IndexedColors.RED.getIndex(), cs.getBottomBorderColor());
-                assertEquals(BorderStyle.THIN, cs.getBorderLeft());
-                assertEquals(IndexedColors.RED.getIndex(), cs.getLeftBorderColor());
-                assertEquals(BorderStyle.THIN, cs.getBorderRight());
-                assertEquals(IndexedColors.RED.getIndex(), cs.getRightBorderColor());
-            }
-        }
-        
-        pt.drawBorders(b2, BorderStyle.NONE, BorderExtent.ALL);
-        pt.applyBorders(sheet);
-        
-        for (Row row: sheet) {
-            for (Cell cell: row) {
-                CellStyle cs = cell.getCellStyle();
-                if (cell.getColumnIndex() != 1 || row.getRowNum() == 0) {
-                assertEquals(BorderStyle.THIN, cs.getBorderTop());
-                assertEquals(IndexedColors.RED.getIndex(), cs.getTopBorderColor());
-                } else {
-                    assertEquals(BorderStyle.NONE, cs.getBorderTop());
-                }
-                if (cell.getColumnIndex() != 1 || row.getRowNum() == 2) {
-                assertEquals(BorderStyle.THIN, cs.getBorderBottom());
-                assertEquals(IndexedColors.RED.getIndex(), cs.getBottomBorderColor());
-                } else {
-                    assertEquals(BorderStyle.NONE, cs.getBorderBottom());
-                }
-                if (cell.getColumnIndex() == 0 || row.getRowNum() != 1) {
-                assertEquals(BorderStyle.THIN, cs.getBorderLeft());
-                assertEquals(IndexedColors.RED.getIndex(), cs.getLeftBorderColor());
-                } else {
-                    assertEquals(BorderStyle.NONE, cs.getBorderLeft());
-                }
-                if (cell.getColumnIndex() == 2 || row.getRowNum() != 1) {
-                assertEquals(BorderStyle.THIN, cs.getBorderRight());
-                assertEquals(IndexedColors.RED.getIndex(), cs.getRightBorderColor());
-                } else {
-                    assertEquals(BorderStyle.NONE, cs.getBorderRight());
-                }
-            }
-        }
-        
-        wb.close();
-    }
-    
-    @Test
-    public void clonePropertyTemplate() throws IOException {
-        CellRangeAddress a1c3 = new CellRangeAddress(0, 2, 0, 2);
-        PropertyTemplate pt = new PropertyTemplate();
-        pt.drawBorders(a1c3, BorderStyle.MEDIUM, IndexedColors.RED.getIndex(), BorderExtent.ALL);
-        PropertyTemplate pt2 = new PropertyTemplate(pt);
-        assertNotSame(pt2, pt);
-        for (int i = 0; i <= 2; i++) {
-            for (int j = 0; j <= 2; j++) {
-                assertEquals(4, pt2.getNumBorderColors(i, j));
-                assertEquals(4, pt2.getNumBorderColors(i, j));
-            }
-        }
-        
-        CellRangeAddress b2 = new CellRangeAddress(1,1,1,1);
-        pt2.drawBorders(b2, BorderStyle.THIN, BorderExtent.ALL);
-        
-        Workbook wb = new XSSFWorkbook();
-        Sheet sheet = wb.createSheet();
-        pt.applyBorders(sheet);
-        
-        for (Row row : sheet) {
-            for (Cell cell : row) {
-                CellStyle cs = cell.getCellStyle();
-                assertEquals(BorderStyle.MEDIUM, cs.getBorderTop());
-                assertEquals(BorderStyle.MEDIUM, cs.getBorderBottom());
-                assertEquals(BorderStyle.MEDIUM, cs.getBorderLeft());
-                assertEquals(BorderStyle.MEDIUM, cs.getBorderRight());
-                assertEquals(IndexedColors.RED.getIndex(), cs.getTopBorderColor());
-                assertEquals(IndexedColors.RED.getIndex(), cs.getBottomBorderColor());
-                assertEquals(IndexedColors.RED.getIndex(), cs.getLeftBorderColor());
-                assertEquals(IndexedColors.RED.getIndex(), cs.getRightBorderColor());
-            }
-        }
-        
-        wb.close();
-    }
-}
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/util/TestIdentifierManager.java b/src/ooxml/testcases/org/apache/poi/util/TestIdentifierManager.java
deleted file mode 100644 (file)
index 8b7b6dc..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import org.apache.poi.ooxml.util.IdentifierManager;
-import org.junit.Test;
-
-public class TestIdentifierManager {
-    @Test
-    public void testBasic()
-    {
-        IdentifierManager manager = new IdentifierManager(0L,100L);
-        assertEquals(101L,manager.getRemainingIdentifiers());
-        assertEquals(0L,manager.reserveNew());
-        assertEquals(100L,manager.getRemainingIdentifiers());
-        assertEquals(1L,manager.reserve(0L));
-        assertEquals(99L,manager.getRemainingIdentifiers());
-    }
-
-    @Test
-    public void testLongLimits() {
-        long min = IdentifierManager.MIN_ID;
-        long max = IdentifierManager.MAX_ID;
-        IdentifierManager manager = new IdentifierManager(min,max);
-        assertTrue("Limits lead to a long variable overflow", max - min + 1 > 0);
-        assertTrue("Limits lead to a long variable overflow", manager.getRemainingIdentifiers() > 0);
-        assertEquals(min,manager.reserveNew());
-        assertEquals(max,manager.reserve(max));
-        assertEquals(max - min -1, manager.getRemainingIdentifiers());
-        manager.release(max);
-        manager.release(min);
-    }
-
-    @Test
-    public void testReserve() {
-        IdentifierManager manager = new IdentifierManager(10L,30L);
-        assertEquals(12L,manager.reserve(12L));
-        long reserve = manager.reserve(12L);
-        assertNotEquals("Same id must be reserved twice!", 12L, reserve);
-        assertTrue(manager.release(12L));
-        assertTrue(manager.release(reserve));
-        assertFalse(manager.release(12L));
-        assertFalse(manager.release(reserve));
-
-        manager = new IdentifierManager(0L,2L);
-        assertEquals(0L,manager.reserve(0L));
-        assertEquals(1L,manager.reserve(1L));
-        assertEquals(2L,manager.reserve(2L));
-        try {
-            manager.reserve(0L);
-            fail("Exception expected");
-        } catch(IllegalStateException e) {
-            // expected
-        }
-        try {
-            manager.reserve(1L);
-            fail("Exception expected");
-        } catch(IllegalStateException e) {
-            // expected
-        }
-        try {
-            manager.reserve(2L);
-            fail("Exception expected");
-        } catch(IllegalStateException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void testReserveNew() {
-        IdentifierManager manager = new IdentifierManager(10L,12L);
-        assertSame(10L,manager.reserveNew());
-        assertSame(11L,manager.reserveNew());
-        assertSame(12L,manager.reserveNew());
-        try {
-            manager.reserveNew();
-            fail("IllegalStateException expected");
-        } catch (IllegalStateException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void testRelease() {
-        IdentifierManager manager = new IdentifierManager(10L,20L);
-        assertEquals(10L,manager.reserve(10L));
-        assertEquals(11L,manager.reserve(11L));
-        assertEquals(12L,manager.reserve(12L));
-        assertEquals(13L,manager.reserve(13L));
-        assertEquals(14L,manager.reserve(14L));
-
-        assertTrue(manager.release(10L));
-        assertEquals(10L,manager.reserve(10L));
-        assertTrue(manager.release(10L));
-
-        assertTrue(manager.release(11L));
-        assertEquals(11L,manager.reserve(11L));
-        assertTrue(manager.release(11L));
-        assertFalse(manager.release(11L));
-        assertFalse(manager.release(10L));
-
-        assertEquals(10L,manager.reserve(10L));
-        assertEquals(11L,manager.reserve(11L));
-        assertTrue(manager.release(12L));
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/util/TestTempFileThreaded.java b/src/ooxml/testcases/org/apache/poi/util/TestTempFileThreaded.java
deleted file mode 100644 (file)
index 5b6e18c..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.util;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.xssf.streaming.SXSSFSheet;
-import org.apache.poi.xssf.streaming.SXSSFWorkbook;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import static org.apache.poi.util.DefaultTempFileCreationStrategy.POIFILES;
-import static org.apache.poi.util.TempFile.JAVA_IO_TMPDIR;
-import static org.junit.Assert.assertEquals;
-
-public class TestTempFileThreaded {
-    private static final int NUMBER_OF_THREADS = 10;
-    private static final int NUMBER_OF_TESTS = 200;
-
-    private volatile Throwable exception;
-    private int[] executions;
-
-    // the actual thread-safe temp-file strategy
-    private static TempFileCreationStrategy createTempFileCreationStrategy(File poiTempFileDirectory) {
-        return new TempFileCreationStrategy() {
-            @Override
-            public File createTempFile(String prefix, String suffix) throws IOException {
-                long threadId = Thread.currentThread().getId();
-                File threadDir = new File(poiTempFileDirectory, Long.toString(threadId));
-                if (!threadDir.exists()) {
-                    if (!threadDir.mkdirs()) {
-                        throw new IOException("mkdir of " + threadDir + " failed");
-                    }
-                }
-
-                File file = File.createTempFile(prefix, suffix, threadDir);
-                file.deleteOnExit();
-                return file;
-            }
-
-            @Override
-            public File createTempDirectory(String prefix) {
-                throw new UnsupportedOperationException("createTempDirectory");
-            }
-        };
-    }
-
-    @BeforeClass
-    public static void setUpClass() throws IOException {
-        String tmpDir = System.getProperty(JAVA_IO_TMPDIR);
-        if (tmpDir == null) {
-            throw new IOException("Systems temporary directory not defined - set the -D" + JAVA_IO_TMPDIR + " jvm property!");
-        }
-
-        TempFile.setTempFileCreationStrategy(createTempFileCreationStrategy(new File(new File(tmpDir, POIFILES), "TestTempFileThreaded")));
-    }
-
-    @Before
-    public void setUp() {
-        // Initialize array to allow to summarize afterwards
-        executions = new int[NUMBER_OF_THREADS];
-    }
-
-    @Test
-    public void runTest() throws Throwable {
-        List<Thread> threads = new LinkedList<>();
-
-        // start all threads
-        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
-            Thread t = startThread(i, new TestRunnable());
-            threads.add(t);
-        }
-
-        // wait for all threads
-        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
-            threads.get(i).join();
-        }
-
-        // report exceptions if there were any
-        if (exception != null) {
-            throw exception;
-        }
-
-        // make sure the resulting number of executions is correct
-        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
-            // check if enough items were performed
-            assertEquals("Thread " + i
-                            + " did not execute all iterations", NUMBER_OF_TESTS,
-                    executions[i]);
-        }
-    }
-
-    private static class TestRunnable {
-        Map<Integer, List<File>> files = new HashMap<>();
-
-        public TestRunnable() {
-            for (int i = 0; i < NUMBER_OF_THREADS; i++) {
-                files.put(i, new ArrayList<>());
-            }
-        }
-
-        public void doEnd(int threadNum) {
-            for (File file : files.get(threadNum)) {
-                if (!file.exists()) {
-                    throw new IllegalStateException("File " + file + " does not exist");
-                }
-                if (!file.delete()) {
-                    throw new IllegalStateException("Deletion of " + file + " failed");
-                }
-            }
-        }
-
-        public void run(int threadNum, int iter) throws Exception {
-            try (SXSSFWorkbook wb = new SXSSFWorkbook()) {
-                SXSSFSheet sheet = wb.createSheet("test");
-
-                for (int i = 0; i < 100; i++) {
-                    Row row = sheet.createRow(i);
-                    for (int j = 0; j < 10; j++) {
-                        Cell cell = row.createCell(j);
-                        cell.setCellValue("123");
-                    }
-                }
-
-                File file = TempFile.createTempFile("TestTempFile-" + threadNum + "-" + iter + "-", ".xlsx");
-                try (OutputStream outputStream = new FileOutputStream(file)) {
-                    wb.write(outputStream);
-                }
-
-                files.get(threadNum).add(file);
-
-                if (iter % 30 == 0) {
-                    System.out.println("thread: " + threadNum + ", iter: " + iter + ": " + file);
-                }
-            }
-        }
-    }
-
-    private Thread startThread(final int threadNum, final TestRunnable run) {
-        Thread t1 = new Thread(() -> {
-            try {
-                for (int iter = 0; iter < NUMBER_OF_TESTS && exception == null; iter++) {
-                    // call the actual test-code
-                    run.run(threadNum, iter);
-
-                    executions[threadNum]++;
-                }
-
-                // do end-work here, we don't do this in a finally as we log
-                // Exception
-                // then anyway
-                run.doEnd(threadNum);
-            } catch (Throwable e) {
-                exception = e;
-            }
-
-        }, "ThreadTestHelper-Thread " + threadNum + ": " + run.getClass().getName());
-
-        t1.start();
-
-        return t1;
-    }
-}
diff --git a/src/ooxml/testcases/org/apache/poi/util/tests/TestIdentifierManager.java b/src/ooxml/testcases/org/apache/poi/util/tests/TestIdentifierManager.java
new file mode 100644 (file)
index 0000000..8697365
--- /dev/null
@@ -0,0 +1,127 @@
+/* ====================================================================
+   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.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.poi.ooxml.util.IdentifierManager;
+import org.junit.Test;
+
+public class TestIdentifierManager {
+    @Test
+    public void testBasic()
+    {
+        IdentifierManager manager = new IdentifierManager(0L,100L);
+        assertEquals(101L,manager.getRemainingIdentifiers());
+        assertEquals(0L,manager.reserveNew());
+        assertEquals(100L,manager.getRemainingIdentifiers());
+        assertEquals(1L,manager.reserve(0L));
+        assertEquals(99L,manager.getRemainingIdentifiers());
+    }
+
+    @Test
+    public void testLongLimits() {
+        long min = IdentifierManager.MIN_ID;
+        long max = IdentifierManager.MAX_ID;
+        IdentifierManager manager = new IdentifierManager(min,max);
+        assertTrue("Limits lead to a long variable overflow", max - min + 1 > 0);
+        assertTrue("Limits lead to a long variable overflow", manager.getRemainingIdentifiers() > 0);
+        assertEquals(min,manager.reserveNew());
+        assertEquals(max,manager.reserve(max));
+        assertEquals(max - min -1, manager.getRemainingIdentifiers());
+        manager.release(max);
+        manager.release(min);
+    }
+
+    @Test
+    public void testReserve() {
+        IdentifierManager manager = new IdentifierManager(10L,30L);
+        assertEquals(12L,manager.reserve(12L));
+        long reserve = manager.reserve(12L);
+        assertNotEquals("Same id must be reserved twice!", 12L, reserve);
+        assertTrue(manager.release(12L));
+        assertTrue(manager.release(reserve));
+        assertFalse(manager.release(12L));
+        assertFalse(manager.release(reserve));
+
+        manager = new IdentifierManager(0L,2L);
+        assertEquals(0L,manager.reserve(0L));
+        assertEquals(1L,manager.reserve(1L));
+        assertEquals(2L,manager.reserve(2L));
+        try {
+            manager.reserve(0L);
+            fail("Exception expected");
+        } catch(IllegalStateException e) {
+            // expected
+        }
+        try {
+            manager.reserve(1L);
+            fail("Exception expected");
+        } catch(IllegalStateException e) {
+            // expected
+        }
+        try {
+            manager.reserve(2L);
+            fail("Exception expected");
+        } catch(IllegalStateException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testReserveNew() {
+        IdentifierManager manager = new IdentifierManager(10L,12L);
+        assertSame(10L,manager.reserveNew());
+        assertSame(11L,manager.reserveNew());
+        assertSame(12L,manager.reserveNew());
+        try {
+            manager.reserveNew();
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testRelease() {
+        IdentifierManager manager = new IdentifierManager(10L,20L);
+        assertEquals(10L,manager.reserve(10L));
+        assertEquals(11L,manager.reserve(11L));
+        assertEquals(12L,manager.reserve(12L));
+        assertEquals(13L,manager.reserve(13L));
+        assertEquals(14L,manager.reserve(14L));
+
+        assertTrue(manager.release(10L));
+        assertEquals(10L,manager.reserve(10L));
+        assertTrue(manager.release(10L));
+
+        assertTrue(manager.release(11L));
+        assertEquals(11L,manager.reserve(11L));
+        assertTrue(manager.release(11L));
+        assertFalse(manager.release(11L));
+        assertFalse(manager.release(10L));
+
+        assertEquals(10L,manager.reserve(10L));
+        assertEquals(11L,manager.reserve(11L));
+        assertTrue(manager.release(12L));
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/util/tests/TestTempFileThreaded.java b/src/ooxml/testcases/org/apache/poi/util/tests/TestTempFileThreaded.java
new file mode 100644 (file)
index 0000000..8c203e6
--- /dev/null
@@ -0,0 +1,190 @@
+/* ====================================================================
+   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.tests;
+
+import static org.apache.poi.util.DefaultTempFileCreationStrategy.POIFILES;
+import static org.apache.poi.util.TempFile.JAVA_IO_TMPDIR;
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.util.TempFile;
+import org.apache.poi.util.TempFileCreationStrategy;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestTempFileThreaded {
+    private static final int NUMBER_OF_THREADS = 10;
+    private static final int NUMBER_OF_TESTS = 200;
+
+    private volatile Throwable exception;
+    private int[] executions;
+
+    // the actual thread-safe temp-file strategy
+    private static TempFileCreationStrategy createTempFileCreationStrategy(File poiTempFileDirectory) {
+        return new TempFileCreationStrategy() {
+            @Override
+            public File createTempFile(String prefix, String suffix) throws IOException {
+                long threadId = Thread.currentThread().getId();
+                File threadDir = new File(poiTempFileDirectory, Long.toString(threadId));
+                if (!threadDir.exists()) {
+                    if (!threadDir.mkdirs()) {
+                        throw new IOException("mkdir of " + threadDir + " failed");
+                    }
+                }
+
+                File file = File.createTempFile(prefix, suffix, threadDir);
+                file.deleteOnExit();
+                return file;
+            }
+
+            @Override
+            public File createTempDirectory(String prefix) {
+                throw new UnsupportedOperationException("createTempDirectory");
+            }
+        };
+    }
+
+    @BeforeClass
+    public static void setUpClass() throws IOException {
+        String tmpDir = System.getProperty(JAVA_IO_TMPDIR);
+        if (tmpDir == null) {
+            throw new IOException("Systems temporary directory not defined - set the -D" + JAVA_IO_TMPDIR + " jvm property!");
+        }
+
+        TempFile.setTempFileCreationStrategy(createTempFileCreationStrategy(new File(new File(tmpDir, POIFILES), "TestTempFileThreaded")));
+    }
+
+    @Before
+    public void setUp() {
+        // Initialize array to allow to summarize afterwards
+        executions = new int[NUMBER_OF_THREADS];
+    }
+
+    @Test
+    public void runTest() throws Throwable {
+        List<Thread> threads = new LinkedList<>();
+
+        // start all threads
+        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
+            Thread t = startThread(i, new TestRunnable());
+            threads.add(t);
+        }
+
+        // wait for all threads
+        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
+            threads.get(i).join();
+        }
+
+        // report exceptions if there were any
+        if (exception != null) {
+            throw exception;
+        }
+
+        // make sure the resulting number of executions is correct
+        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
+            // check if enough items were performed
+            assertEquals("Thread " + i
+                            + " did not execute all iterations", NUMBER_OF_TESTS,
+                    executions[i]);
+        }
+    }
+
+    private static class TestRunnable {
+        Map<Integer, List<File>> files = new HashMap<>();
+
+        public TestRunnable() {
+            for (int i = 0; i < NUMBER_OF_THREADS; i++) {
+                files.put(i, new ArrayList<>());
+            }
+        }
+
+        public void doEnd(int threadNum) {
+            for (File file : files.get(threadNum)) {
+                if (!file.exists()) {
+                    throw new IllegalStateException("File " + file + " does not exist");
+                }
+                if (!file.delete()) {
+                    throw new IllegalStateException("Deletion of " + file + " failed");
+                }
+            }
+        }
+
+        public void run(int threadNum, int iter) throws Exception {
+            try (SXSSFWorkbook wb = new SXSSFWorkbook()) {
+                SXSSFSheet sheet = wb.createSheet("test");
+
+                for (int i = 0; i < 100; i++) {
+                    Row row = sheet.createRow(i);
+                    for (int j = 0; j < 10; j++) {
+                        Cell cell = row.createCell(j);
+                        cell.setCellValue("123");
+                    }
+                }
+
+                File file = TempFile.createTempFile("TestTempFile-" + threadNum + "-" + iter + "-", ".xlsx");
+                try (OutputStream outputStream = new FileOutputStream(file)) {
+                    wb.write(outputStream);
+                }
+
+                files.get(threadNum).add(file);
+
+                if (iter % 30 == 0) {
+                    System.out.println("thread: " + threadNum + ", iter: " + iter + ": " + file);
+                }
+            }
+        }
+    }
+
+    private Thread startThread(final int threadNum, final TestRunnable run) {
+        Thread t1 = new Thread(() -> {
+            try {
+                for (int iter = 0; iter < NUMBER_OF_TESTS && exception == null; iter++) {
+                    // call the actual test-code
+                    run.run(threadNum, iter);
+
+                    executions[threadNum]++;
+                }
+
+                // do end-work here, we don't do this in a finally as we log
+                // Exception
+                // then anyway
+                run.doEnd(threadNum);
+            } catch (Throwable e) {
+                exception = e;
+            }
+
+        }, "ThreadTestHelper-Thread " + threadNum + ": " + run.getClass().getName());
+
+        t1.start();
+
+        return t1;
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/geom/TestFormulaParser.java b/src/ooxml/testcases/org/apache/poi/xslf/geom/TestFormulaParser.java
deleted file mode 100644 (file)
index e78cefd..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-package org.apache.poi.xslf.geom;
-
-import static org.junit.Assert.assertEquals;
-
-import org.apache.poi.sl.draw.geom.Context;
-import org.apache.poi.sl.draw.geom.CustomGeometry;
-import org.apache.poi.sl.draw.geom.Formula;
-import org.apache.poi.sl.draw.geom.Guide;
-import org.junit.Test;
-
-/**
- * Date: 10/24/11
- *
- * @author Yegor Kozlov
- */
-public class TestFormulaParser {
-    @Test
-    public void testParse(){
-
-        Formula[] ops = {
-            newGuide("adj1", "val 100"),
-            newGuide("adj2", "val 200"),
-            newGuide("adj3", "val -1"),
-            newGuide("a1", "*/ adj1 2 adj2"), // a1 = 100*2 / 200
-            newGuide("a2", "+- adj2 a1 adj1"), // a2 = 200 + a1 - 100
-            newGuide("a3", "+/ adj1 adj2 adj2"), // a3 = (100 + 200) / 200
-            newGuide("a4", "?: adj3 adj1 adj2"), // a4 = adj3 > 0 ? adj1 : adj2
-            newGuide("a5", "abs -2"),
-        };
-
-        CustomGeometry geom = new CustomGeometry();
-        Context ctx = new Context(geom, null, null);
-        for(Formula fmla : ops) {
-            ctx.evaluate(fmla);
-        }
-
-        assertEquals(100.0, ctx.getValue("adj1"), 0.0);
-        assertEquals(200.0, ctx.getValue("adj2"), 0.0);
-        assertEquals(1.0, ctx.getValue("a1"), 0.0);
-        assertEquals(101.0, ctx.getValue("a2"), 0.0);
-        assertEquals(1.5, ctx.getValue("a3"), 0.0);
-        assertEquals(200.0, ctx.getValue("a4"), 0.0);
-        assertEquals(2.0, ctx.getValue("a5"), 0.0);
-    }
-
-    private static Guide newGuide(String name, String fmla) {
-        Guide gd = new Guide();
-        gd.setName(name);
-        gd.setFmla(fmla);
-        return gd;
-    }
-}
index cdb3dc41823820c2ba6f1e8e9d01e14faeccfa21..7c4ee0944501a313d708b5240315fa2367b81a6a 100644 (file)
@@ -16,7 +16,7 @@
 ==================================================================== */
 package org.apache.poi.xslf.usermodel;
 
-import static org.apache.poi.sl.TestCommonSL.getColor;
+import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
index a5b2dc8e1be9197baa3a1104985c2a0d58a6cdf8..1a1396bdfe168d13d697d34081d543442f61d785 100644 (file)
@@ -16,7 +16,7 @@
 ==================================================================== */
 package org.apache.poi.xslf.usermodel;
 
-import static org.apache.poi.sl.TestCommonSL.getColor;
+import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
index 8d26fc62e520455b5a28d4487ebd86444ff3d415..dfa1d572abf4b37bf6cf8076e8e5af095802c5b8 100644 (file)
@@ -18,7 +18,7 @@
  */
 package org.apache.poi.xslf.usermodel;
 
-import static org.apache.poi.sl.TestCommonSL.getColor;
+import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -29,7 +29,6 @@ import java.io.IOException;
 import java.io.InputStream;
 
 import org.apache.poi.POIDataSamples;
-import org.apache.poi.ooxml.POIXMLDocumentPart;
 import org.apache.poi.sl.draw.DrawTextParagraph;
 import org.junit.Test;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak;
index 474bd52c9347cb8724c5180e0905f3cedd88da2f..e01db97bf1c938a9ebd2361bfedaa6b23dfda534 100644 (file)
@@ -16,7 +16,7 @@
 ==================================================================== */
 package org.apache.poi.xslf.usermodel;
 
-import static org.apache.poi.sl.TestCommonSL.getColor;
+import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor;
 import static org.apache.poi.xslf.usermodel.TestXSLFSimpleShape.getSpPr;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
index 4a90fbc769781ab49ae7721cb6c5838266852ffd..12ddf0eabdf646a9e5fdfa67c2b0dacb5084a935 100644 (file)
@@ -16,7 +16,7 @@
 ==================================================================== */
 package org.apache.poi.xslf.usermodel;
 
-import static org.apache.poi.sl.TestCommonSL.getColor;
+import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
index 93f35aac49d7c29bbdb07f48f9c5547be51c7f51..e6a61f0afa7bbd0d17f8494bec9f299fedbaf5dd 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.apache.poi.xssf;
 
-import org.apache.poi.ss.format.TestCellFormatPart;
+import org.apache.poi.ss.tests.format.TestCellFormatPart;
 import org.apache.poi.xssf.extractor.TestXSSFExcelExtractor;
 import org.apache.poi.xssf.io.TestLoadSaveXSSF;
 import org.apache.poi.xssf.model.TestCommentsTable;
@@ -42,7 +42,7 @@ import org.junit.runners.Suite;
     //TestStylesTable.class, //converted to junit4
     //TestCellReference.class, //converted to junit4
     TestCTColComparator.class,
-    TestNumericRanges.class,       
+    TestNumericRanges.class,
     TestCellFormatPart.class,
     TestXSSFCloneSheet.class
 })
index 4e72ff69b53b884b1f3893a4257466f617a82fab..879a2d4ed66b5884d49ddd64b20481a93c4e906a 100644 (file)
 
 package org.apache.poi.xssf.streaming;
 
-import org.apache.poi.ss.usermodel.BaseTestXWorkbook;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+
+import org.apache.poi.ss.tests.usermodel.BaseTestXWorkbook;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
@@ -33,21 +42,17 @@ import org.junit.After;
 import org.junit.Ignore;
 import org.junit.Test;
 
-import java.io.IOException;
-
-import static org.junit.Assert.*;
-
 public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
-    
+
     public TestDeferredSXSSFWorkbook() {
         super(DeferredSXSSFITestDataProvider.instance);
     }
-    
+
     @After
     public void tearDown() {
         ((DeferredSXSSFITestDataProvider) _testDataProvider).cleanup();
     }
-    
+
     /**
      * cloning of sheets is not supported in SXSSF
      */
@@ -61,7 +66,7 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
             assertEquals("Not Implemented", e.getMessage());
         }
     }
-    
+
     /**
      * cloning of sheets is not supported in SXSSF
      */
@@ -75,7 +80,7 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
             assertEquals("Not Implemented", e.getMessage());
         }
     }
-    
+
     /**
      * Skip this test, as SXSSF doesn't update formulas on sheet name changes.
      */
@@ -101,7 +106,7 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
         DeferredSXSSFWorkbook wb1 = new DeferredSXSSFWorkbook(xssfWb1);
         XSSFWorkbook xssfWb2 = DeferredSXSSFITestDataProvider.instance.writeOutAndReadBack(wb1);
         assertTrue(wb1.dispose());
-        
+
         DeferredSXSSFWorkbook wb2 = new DeferredSXSSFWorkbook(xssfWb2);
         assertEquals(1, wb2.getNumberOfSheets());
         Sheet sheet = wb2.getStreamingSheetAt(0);
@@ -110,7 +115,7 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
         assertTrue(wb2.dispose());
         xssfWb2.close();
         xssfWb1.close();
-        
+
         wb2.close();
         wb1.close();
     }
@@ -127,7 +132,7 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
         XSSFWorkbook xssfWb2 = DeferredSXSSFITestDataProvider.instance.writeOutAndReadBack(wb1);
         assertTrue(wb1.dispose());
         xssfWb1.close();
-        
+
         DeferredSXSSFWorkbook wb2 = new DeferredSXSSFWorkbook(xssfWb2);
         // Add a row to the existing empty sheet
         DeferredSXSSFSheet ssheet1 = wb2.getStreamingSheetAt(0);
@@ -136,7 +141,7 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
             Cell cell1_1_1 = row1_1.createCell(1);
             cell1_1_1.setCellValue("value 1_1_1");
         });
-        
+
         // Add a row to the existing non-empty sheet
         DeferredSXSSFSheet ssheet2 = wb2.getStreamingSheetAt(1);
         ssheet2.setRowGenerator((ssxSheet) -> {
@@ -151,10 +156,10 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
             Cell cell3_1_1 = row3_1.createCell(1);
             cell3_1_1.setCellValue("value 3_1_1");
         });
-        
+
         XSSFWorkbook xssfWb3 = DeferredSXSSFITestDataProvider.instance.writeOutAndReadBack(wb2);
         wb2.close();
-        
+
         assertEquals(3, xssfWb3.getNumberOfSheets());
         // Verify sheet 1
         XSSFSheet sheet1 = xssfWb3.getSheetAt(0);
@@ -188,12 +193,12 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
         XSSFCell cell3_1_1 = row3_1.getCell(1);
         assertNotNull(cell3_1_1);
         assertEquals("value 3_1_1", cell3_1_1.getStringCellValue());
-        
+
         xssfWb2.close();
         xssfWb3.close();
         wb1.close();
     }
-    
+
     @Test
     public void sheetdataWriter() throws IOException {
         DeferredSXSSFWorkbook wb = new DeferredSXSSFWorkbook();
@@ -228,7 +233,7 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
             }
         }
     }
-    
+
     @Test
     public void gzipSheetdataWriter() throws IOException {
         DeferredSXSSFWorkbook wb = new DeferredSXSSFWorkbook();
@@ -236,7 +241,7 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
         final int rowNum = 1000;
         final int sheetNum = 5;
         populateData(wb, 1000, 5);
-        
+
         XSSFWorkbook xwb = DeferredSXSSFITestDataProvider.instance.writeOutAndReadBack(wb);
         for (int i = 0; i < sheetNum; i++) {
             Sheet sh = xwb.getSheetAt(i);
@@ -246,15 +251,15 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
                 assertNotNull("row[" + j + "]", row);
                 Cell cell1 = row.getCell(0);
                 assertEquals(new CellReference(cell1).formatAsString(), cell1.getStringCellValue());
-                
+
                 Cell cell2 = row.getCell(1);
                 assertEquals(i, (int) cell2.getNumericCellValue());
-                
+
                 Cell cell3 = row.getCell(2);
                 assertEquals(j, (int) cell3.getNumericCellValue());
             }
         }
-        
+
         assertTrue(wb.dispose());
         xwb.close();
         wb.close();
@@ -273,23 +278,23 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
         assertWorkbookDispose(wb2);
         wb2.close();
     }
-    
+
     private static void assertWorkbookDispose(DeferredSXSSFWorkbook wb) {
         populateData(wb, 1000, 5);
-        
+
         for (Sheet sheet : wb) {
             DeferredSXSSFSheet sxSheet = (DeferredSXSSFSheet) sheet;
             assertNull(sxSheet.getSheetDataWriter());
         }
-        
+
         assertTrue(wb.dispose());
-        
+
         for (Sheet sheet : wb) {
             DeferredSXSSFSheet sxSheet = (DeferredSXSSFSheet) sheet;
             assertNull(sxSheet.getSheetDataWriter());
         }
     }
-    
+
     private static void populateData(DeferredSXSSFWorkbook wb, final int rowNum, final int sheetNum) {
         for (int i = 0; i < sheetNum; i++) {
             DeferredSXSSFSheet sheet = wb.createSheet("sheet" + i);
@@ -299,10 +304,10 @@ public final class TestDeferredSXSSFWorkbook extends BaseTestXWorkbook {
                     Row row = sh.createRow(j);
                     Cell cell1 = row.createCell(0);
                     cell1.setCellValue(new CellReference(cell1).formatAsString());
-                    
+
                     Cell cell2 = row.createCell(1);
                     cell2.setCellValue(index);
-                    
+
                     Cell cell3 = row.createCell(2);
                     cell3.setCellValue(j);
                 }
index f0519d203539cddfcb6d2b3aa87e0fad4b626add..182eb17775d35ba0e1e3733708b014faa4927e6a 100644 (file)
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.spy;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
@@ -30,7 +31,7 @@ import java.nio.charset.StandardCharsets;
 import javax.xml.namespace.QName;
 
 import org.apache.poi.ss.SpreadsheetVersion;
-import org.apache.poi.ss.usermodel.BaseTestXCell;
+import org.apache.poi.ss.tests.usermodel.BaseTestXCell;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.ss.usermodel.RichTextString;
@@ -46,9 +47,6 @@ import org.junit.Ignore;
 import org.junit.Test;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRst;
 
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
 /**
  * Tests various functionality having to do with {@link SXSSFCell}.  For instance support for
  * particular datatypes, etc.
index ee237cc9b031acacb12ceae19dd70d9ec99eb6a2..88c12d7e014305f7fdbd1d09552589171a55f0d5 100644 (file)
@@ -19,7 +19,7 @@
 
 package org.apache.poi.xssf.streaming;
 
-import org.apache.poi.ss.usermodel.BaseTestXRow;
+import org.apache.poi.ss.tests.usermodel.BaseTestXRow;
 import org.apache.poi.xssf.SXSSFITestDataProvider;
 import org.junit.After;
 import org.junit.Ignore;
@@ -48,8 +48,8 @@ public final class TestSXSSFRow extends BaseTestXRow {
     @Override
     @Ignore ("see <https://bz.apache.org/bugzilla/show_bug.cgi?id=62030#c1>") @Test
     public void testCellShiftingLeft(){
-        // Remove when SXSSFRow.shiftCellsLeft() is implemented. 
+        // Remove when SXSSFRow.shiftCellsLeft() is implemented.
     }
 
-    
+
 }
index 4bc9bd519161c8d7bd6bcaae41d7d0d9c2859c12..15dcf326a05aea207f596c8943e39d7eeb3ffb60 100644 (file)
@@ -24,7 +24,7 @@ import static org.junit.Assert.fail;
 
 import java.io.IOException;
 
-import org.apache.poi.ss.usermodel.BaseTestXSheet;
+import org.apache.poi.ss.tests.usermodel.BaseTestXSheet;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.xssf.SXSSFITestDataProvider;
@@ -44,7 +44,7 @@ public final class TestSXSSFSheet extends BaseTestXSheet {
     public void tearDown(){
         SXSSFITestDataProvider.instance.cleanup();
     }
-    
+
     @Override
     protected void trackColumnsForAutoSizingIfSXSSF(Sheet sheet) {
         SXSSFSheet sxSheet = (SXSSFSheet) sheet;
@@ -70,7 +70,7 @@ public final class TestSXSSFSheet extends BaseTestXSheet {
         thrown.expectMessage("Not Implemented");
         super.cloneSheetMultipleTimes();
     }
-    
+
     /**
      * shifting rows is not supported in SXSSF
      */
@@ -98,11 +98,11 @@ public final class TestSXSSFSheet extends BaseTestXSheet {
     @Override
     @Test
     public void getCellComment() throws IOException {
-        // TODO: reading cell comments via Sheet does not work currently as it tries 
+        // TODO: reading cell comments via Sheet does not work currently as it tries
         // to access the underlying sheet for this, but comments are stored as
         // properties on Cells...
     }
-    
+
     @Override
     @Test
     public void defaultColumnStyle() {
@@ -133,7 +133,7 @@ public final class TestSXSSFSheet extends BaseTestXSheet {
         Workbook wb = new SXSSFWorkbook(template);
         try {
             Sheet sheet = wb.getSheetAt(0);
-    
+
             try {
                 sheet.createRow(1);
                 fail("expected exception");
@@ -160,13 +160,13 @@ public final class TestSXSSFSheet extends BaseTestXSheet {
         SXSSFRow row0 = sheet.createRow(0);
         SXSSFRow row1 = sheet.createRow(1);
         sheet.changeRowNum(row0, 2);
-        
+
         assertEquals("Row 1 knows its row number", 1, row1.getRowNum());
         assertEquals("Row 2 knows its row number", 2, row0.getRowNum());
         assertEquals("Sheet knows Row 1's row number", 1, sheet.getRowNum(row1));
         assertEquals("Sheet knows Row 2's row number", 2, sheet.getRowNum(row0));
         assertEquals("Sheet row iteratation order should be ascending", row1, sheet.iterator().next());
-        
+
         wb.close();
     }
 }
index aa0045f809bceb1e4976f92870c61f59f294dccd..9e592df284a2195df7a180a6580fca782538a340 100644 (file)
@@ -19,8 +19,8 @@
 
 package org.apache.poi.xssf.streaming;
 
-import static org.apache.poi.POITestCase.assertStartsWith;
 import static org.apache.poi.POITestCase.assertEndsWith;
+import static org.apache.poi.POITestCase.assertStartsWith;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -37,10 +37,9 @@ import java.io.IOException;
 import java.util.Arrays;
 
 import org.apache.poi.POIDataSamples;
-import org.apache.poi.POITestCase;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.opc.PackageAccess;
-import org.apache.poi.ss.usermodel.BaseTestXWorkbook;
+import org.apache.poi.ss.tests.usermodel.BaseTestXWorkbook;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.ss.usermodel.Row;
@@ -122,7 +121,7 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
            assertTrue(wb2.dispose());
            xssfWb2.close();
            xssfWb1.close();
-           
+
            wb2.close();
            wb1.close();
     }
@@ -131,8 +130,8 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
     public void useSharedStringsTable() throws Exception {
         SXSSFWorkbook wb = new SXSSFWorkbook(null, 10, false, true);
 
-        SharedStringsTable sss = POITestCase.getFieldValue(SXSSFWorkbook.class, wb, SharedStringsTable.class, "_sharedStringSource");
-        
+        SharedStringsTable sss = wb.getSharedStringSource();
+
         assertNotNull(sss);
 
         Row row = wb.createSheet("S1").createRow(0);
@@ -142,7 +141,7 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
         row.createCell(2).setCellValue("A");
 
         XSSFWorkbook xssfWorkbook = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb);
-        sss = POITestCase.getFieldValue(SXSSFWorkbook.class, wb, SharedStringsTable.class, "_sharedStringSource");
+        sss = wb.getSharedStringSource();
         assertEquals(2, sss.getUniqueCount());
         assertTrue(wb.dispose());
 
@@ -199,7 +198,7 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
 
        XSSFWorkbook xssfWb3 = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb2);
        wb2.close();
-       
+
        assertEquals(3, xssfWb3.getNumberOfSheets());
        // Verify sheet 1
        sheet1 = xssfWb3.getSheetAt(0);
@@ -233,7 +232,7 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
        cell3_1_1 = row3_1.getCell(1);
        assertNotNull(cell3_1_1);
        assertEquals("value 3_1_1", cell3_1_1.getStringCellValue());
-       
+
         xssfWb2.close();
        xssfWb3.close();
        wb1.close();
@@ -437,15 +436,15 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
 
         // Some tests commented out because close() modifies the file
         // See bug 58779
-        
+
         // String
         //wb = new SXSSFWorkbook(new XSSFWorkbook(file.getPath()));
         //assertCloseDoesNotModifyFile(filename, wb);
-        
+
         // File
         //wb = new SXSSFWorkbook(new XSSFWorkbook(file));
         //assertCloseDoesNotModifyFile(filename, wb);
-        
+
         // InputStream
 
         try (FileInputStream fis = new FileInputStream(file);
@@ -453,15 +452,15 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
              SXSSFWorkbook wb = new SXSSFWorkbook(xwb)) {
             assertCloseDoesNotModifyFile(filename, wb);
         }
-        
+
         // OPCPackage
         //wb = new SXSSFWorkbook(new XSSFWorkbook(OPCPackage.open(file)));
         //assertCloseDoesNotModifyFile(filename, wb);
     }
-    
+
     /**
      * Bug #59743
-     * 
+     *
      * this is only triggered on other files apart of sheet[1,2,...].xml
      * as those are either copied uncompressed or with the use of GZIPInputStream
      * so we use shared strings
@@ -472,7 +471,7 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
         SXSSFSheet s = swb.createSheet();
         char[] useless = new char[32767];
         Arrays.fill(useless, ' ');
-        
+
         for (int row=0; row<1; row++) {
             Row r = s.createRow(row);
             for (int col=0; col<10; col++) {
@@ -483,13 +482,13 @@ public final class TestSXSSFWorkbook extends BaseTestXWorkbook {
                 r.createCell(col, CellType.STRING).setCellValue(ul);
             }
         }
-        
+
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         swb.write(bos);
         swb.dispose();
         swb.close();
     }
-    
+
     /**
      * To avoid accident changes to the template, you should be able
      *  to create a SXSSFWorkbook from a read-only XSSF one, then
index 4ccb70e9d1edddfe5d5a2a720679648d84574dd0..d88d1fd959735b6639c53403eacf86900777caa2 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.apache.poi.xssf.usermodel;
 
-import org.apache.poi.ss.formula.eval.forked.TestForkedEvaluator;
+import org.apache.poi.ss.formula.eval.forked.BaseTestForkedEvaluator;
 import org.apache.poi.xssf.usermodel.extensions.TestXSSFBorder;
 import org.apache.poi.xssf.usermodel.extensions.TestXSSFCellFill;
 import org.apache.poi.xssf.usermodel.helpers.TestColumnHelper;
@@ -58,7 +58,7 @@ import org.junit.runners.Suite;
     TestColumnHelper.class,
     TestHeaderFooterHelper.class,
     //TestXSSFPivotTable.class, //converted to junit4
-    TestForkedEvaluator.class
+    BaseTestForkedEvaluator.class
 })
 public final class AllXSSFUsermodelTests {
 }
index 97744249aaf948e36b977be34d82019adcb83e15..e1ffbd633719307d463ec7378b7d73c9208133f8 100644 (file)
@@ -33,7 +33,7 @@ import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.opc.PackageAccess;
 import org.apache.poi.ss.formula.eval.TestFormulasFromSpreadsheet;
-import org.apache.poi.ss.formula.functions.TestMathX;
+import org.apache.poi.ss.formula.functions.BaseTestNumeric;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.ss.usermodel.CellValue;
@@ -55,10 +55,10 @@ import org.junit.runners.Parameterized.Parameters;
  *  except for a XSSF spreadsheet, not a HSSF one.
  * This allows us to check that all our Formula Evaluation code
  *  is able to work for XSSF, as well as for HSSF.
- * 
+ *
  * Periodically, you should open FormulaEvalTestData.xls in
  *  Excel 2007, and re-save it as FormulaEvalTestData_Copy.xlsx
- *  
+ *
  */
 @RunWith(Parameterized.class)
 public final class TestFormulaEvaluatorOnXSSF {
@@ -68,12 +68,12 @@ public final class TestFormulaEvaluatorOnXSSF {
     private static Sheet sheet;
     private static FormulaEvaluator evaluator;
     private static Locale userLocale;
-    
-       /** 
+
+       /**
         * This class defines constants for navigating around the test data spreadsheet used for these tests.
         */
        private static interface SS {
-               
+
                /**
                 * Name of the test spreadsheet (found in the standard test data folder)
                 */
@@ -119,7 +119,7 @@ public final class TestFormulaEvaluatorOnXSSF {
         LocaleUtil.setUserLocale(userLocale);
         workbook.close();
     }
-    
+
     @Parameters(name="{0}")
     public static Collection<Object[]> data() throws Exception {
         // Function "Text" uses custom-formats which are locale specific
@@ -131,9 +131,9 @@ public final class TestFormulaEvaluatorOnXSSF {
         workbook = new XSSFWorkbook( OPCPackage.open(HSSFTestDataSamples.getSampleFile(SS.FILENAME), PackageAccess.READ) );
         sheet = workbook.getSheetAt( 0 );
         evaluator = new XSSFFormulaEvaluator(workbook);
-        
+
         List<Object[]> data = new ArrayList<>();
-        
+
         processFunctionGroup(data, SS.START_OPERATORS_ROW_INDEX, null);
         processFunctionGroup(data, SS.START_FUNCTIONS_ROW_INDEX, null);
         // example for debugging individual functions/operators:
@@ -142,10 +142,10 @@ public final class TestFormulaEvaluatorOnXSSF {
 
         return data;
     }
-    
+
     /**
-     * @param startRowIndex row index in the spreadsheet where the first function/operator is found 
-     * @param testFocusFunctionName name of a single function/operator to test alone. 
+     * @param startRowIndex row index in the spreadsheet where the first function/operator is found
+     * @param testFocusFunctionName name of a single function/operator to test alone.
      * Typically pass <code>null</code> to test all functions
      */
     private static void processFunctionGroup(List<Object[]> data, int startRowIndex, String testFocusFunctionName) {
@@ -154,7 +154,7 @@ public final class TestFormulaEvaluatorOnXSSF {
 
             // only evaluate non empty row
             if(r == null) continue;
-            
+
             String targetFunctionName = getTargetFunctionName(r);
             assertNotNull("Test spreadsheet cell empty on row ("
                 + (rowIndex+1) + "). Expected function name or '"
@@ -165,14 +165,14 @@ public final class TestFormulaEvaluatorOnXSSF {
                 break;
             }
             if(testFocusFunctionName == null || targetFunctionName.equalsIgnoreCase(testFocusFunctionName)) {
-                
+
                 // expected results are on the row below
                 Row expectedValuesRow = sheet.getRow(rowIndex + 1);
                 // +1 for 1-based, +1 for next row
-                assertNotNull("Missing expected values row for function '" 
+                assertNotNull("Missing expected values row for function '"
                     + targetFunctionName + " (row " + rowIndex + 2 + ")"
                     , expectedValuesRow);
-                
+
                 data.add(new Object[]{targetFunctionName, rowIndex, rowIndex + 1});
             }
         }
@@ -183,7 +183,7 @@ public final class TestFormulaEvaluatorOnXSSF {
        public void processFunctionRow() {
            Row formulasRow = sheet.getRow(formulasRowIdx);
            Row expectedValuesRow = sheet.getRow(expectedValuesRowIdx);
-           
+
                short endcolnum = formulasRow.getLastCellNum();
 
                // iterate across the row for all the evaluation cases
@@ -198,10 +198,10 @@ public final class TestFormulaEvaluatorOnXSSF {
 
                        String msg = String.format(Locale.ROOT, "Function '%s': Formula: %s @ %d:%d"
                        , targetFunctionName, c.getCellFormula(), formulasRow.getRowNum(), colnum);
-                       
+
                        assertNotNull(msg + " - Bad setup data expected value is null", expValue);
                        assertNotNull(msg + " - actual value was null", actValue);
-               
+
                final CellType expectedCellType = expValue.getCellType();
                switch (expectedCellType) {
                    case BLANK:
@@ -221,7 +221,7 @@ public final class TestFormulaEvaluatorOnXSSF {
                        fail("Cannot expect formula as result of formula evaluation: " + msg);
                    case NUMERIC:
                        assertEquals(msg, CellType.NUMERIC, actValue.getCellType());
-                       TestMathX.assertEquals(msg, expValue.getNumericCellValue(), actValue.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR);
+                                       BaseTestNumeric.assertEquals(msg, expValue.getNumericCellValue(), actValue.getNumberValue(), BaseTestNumeric.POS_ZERO, BaseTestNumeric.DIFF_TOLERANCE_FACTOR);
 //                   double delta = Math.abs(expValue.getNumericCellValue()-actValue.getNumberValue());
 //                   double pctExpValue = Math.abs(0.00001*expValue.getNumericCellValue());
 //                   assertTrue(msg, delta <= pctExpValue);
@@ -237,16 +237,16 @@ public final class TestFormulaEvaluatorOnXSSF {
        }
 
        /*
-        * TODO - these are all formulas which currently (Apr-2008) break on ooxml 
+        * TODO - these are all formulas which currently (Apr-2008) break on ooxml
         */
        private static void ignoredFormulaTestCase(String cellFormula) {
         // full row ranges are not parsed properly yet.
-        // These cases currently work in svn trunk because of another bug which causes the 
-        // formula to get rendered as COLUMN($A$1:$IV$2) or ROW($A$2:$IV$3) 
+        // These cases currently work in svn trunk because of another bug which causes the
+        // formula to get rendered as COLUMN($A$1:$IV$2) or ROW($A$2:$IV$3)
            assumeFalse("COLUMN(1:2)".equals(cellFormula));
            assumeFalse("ROW(2:3)".equals(cellFormula));
 
-        // currently throws NPE because unknown function "currentcell" causes name lookup 
+        // currently throws NPE because unknown function "currentcell" causes name lookup
         // Name lookup requires some equivalent object of the Workbook within xSSFWorkbook.
            assumeFalse("ISREF(currentcell())".equals(cellFormula));
        }
@@ -270,7 +270,7 @@ public final class TestFormulaEvaluatorOnXSSF {
                if(cell.getCellType() == CellType.STRING) {
                        return cell.getRichStringCellValue().getString();
                }
-               
+
                fail("Bad cell type for 'function name' column: ("+cell.getColumnIndex()+") row ("+(r.getRowNum()+1)+")");
                return null;
        }
index a5b7dcbc2f7e1a3320529b55ee8b5c4f81a7d524..487ce8560a9bba12a9ccdb507044af82649e445d 100644 (file)
@@ -27,7 +27,7 @@ import java.util.List;
 import java.util.Locale;
 
 import org.apache.poi.ss.formula.eval.ErrorEval;
-import org.apache.poi.ss.formula.functions.TestMathX;
+import org.apache.poi.ss.formula.functions.BaseTestNumeric;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.ss.usermodel.CellValue;
@@ -196,7 +196,7 @@ public final class TestMatrixFormulasFromXMLSpreadsheet {
                        fail("Cannot expect formula as result of formula evaluation: " + msg);
                    case NUMERIC:
                        assertEquals(msg, CellType.NUMERIC, actValue.getCellType());
-                       TestMathX.assertEquals(msg, expValue.getNumericCellValue(), actValue.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR);
+                       BaseTestNumeric.assertEquals(msg, expValue.getNumericCellValue(), actValue.getNumberValue(), BaseTestNumeric.POS_ZERO, BaseTestNumeric.DIFF_TOLERANCE_FACTOR);
                        break;
                    case STRING:
                        assertEquals(msg, CellType.STRING, actValue.getCellType());
index 0de5eb5a460633b6934b5e57a7eed6d64de0e5e2..f8ba0ff7db90464b95f78eb75f84d2777322137e 100644 (file)
 
 package org.apache.poi.xssf.usermodel;
 
+import static org.junit.Assert.assertNotNull;
+
 import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.ss.formula.TestMissingWorkbook;
+import org.apache.poi.ss.formula.BaseTestMissingWorkbook;
 import org.apache.poi.xssf.XSSFTestDataSamples;
 import org.junit.Before;
 
-import static org.junit.Assert.assertNotNull;
-
 /**
  * XSSF Specific version of the Missing Workbooks test
  */
-public final class TestMissingWorkbookOnXSSF extends TestMissingWorkbook {
+public final class TestMissingWorkbookOnXSSF extends BaseTestMissingWorkbook {
     public TestMissingWorkbookOnXSSF() {
         super("52575_main.xlsx", "source_dummy.xlsx", "52575_source.xls");
     }
index 74648bb7e6cf5ddd356e971322ac4f150b2290e6..09817ecd454f1cecb89dc053f7f6ded59fc63687 100644 (file)
@@ -31,8 +31,7 @@ import java.util.Locale;
 import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.opc.PackageAccess;
-import org.apache.poi.ss.formula.eval.TestFormulasFromSpreadsheet;
-import org.apache.poi.ss.formula.functions.TestMathX;
+import org.apache.poi.ss.formula.functions.BaseTestNumeric;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.ss.usermodel.CellValue;
@@ -53,7 +52,7 @@ import org.junit.runners.Parameterized.Parameters;
  */
 @RunWith(Parameterized.class)
 public final class TestMultiSheetFormulaEvaluatorOnXSSF {
-    private static final POILogger logger = POILogFactory.getLogger(TestFormulasFromSpreadsheet.class);
+    private static final POILogger logger = POILogFactory.getLogger(TestMultiSheetFormulaEvaluatorOnXSSF.class);
 
     private static XSSFWorkbook workbook;
     private static Sheet sheet;
@@ -204,7 +203,7 @@ public final class TestMultiSheetFormulaEvaluatorOnXSSF {
                 fail("Cannot expect formula as result of formula evaluation: " + msg);
             case NUMERIC:
                 assertEquals(msg, CellType.NUMERIC, actValue.getCellType());
-                TestMathX.assertEquals(msg, expValue.getNumericCellValue(), actValue.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR);
+                               BaseTestNumeric.assertEquals(msg, expValue.getNumericCellValue(), actValue.getNumberValue(), BaseTestNumeric.POS_ZERO, BaseTestNumeric.DIFF_TOLERANCE_FACTOR);
 //              double delta = Math.abs(expected.getNumericCellValue()-actual.getNumberValue());
 //              double pctExpected = Math.abs(0.00001*expected.getNumericCellValue());
 //              assertTrue(msg, delta <= pctExpected);
index 873d7a0699c83dc6ee48dc3b10a15ecb72eb876d..b456d91aa64c816b6cf1679356dd504038288b28 100644 (file)
@@ -1994,7 +1994,7 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues {
 
         // Workbook Factory gives helpful error on package
         try {
-            XSSFWorkbookFactory.create(pkg).close();
+            XSSFWorkbookFactory.createWorkbook(pkg).close();
             fail(".xlsb files not supported");
         } catch (XLSBUnsupportedException e) {
             // Good, detected and warned
index 4dae58a238a7b49285011132649381592f8ab936..c5c0427f17dc0d08e5fcb5cb50e5ebab3c26f9c5 100644 (file)
 
 package org.apache.poi.xssf.usermodel;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import java.io.IOException;
 import java.util.List;
 
@@ -24,7 +33,7 @@ import org.apache.poi.common.usermodel.HyperlinkType;
 import org.apache.poi.hssf.HSSFITestDataProvider;
 import org.apache.poi.ss.SpreadsheetVersion;
 import org.apache.poi.ss.formula.FormulaParseException;
-import org.apache.poi.ss.usermodel.BaseTestXCell;
+import org.apache.poi.ss.tests.usermodel.BaseTestXCell;
 import org.apache.poi.ss.usermodel.BorderStyle;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellCopyPolicy;
@@ -53,8 +62,6 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellType;
 
-import static org.junit.Assert.*;
-
 public final class TestXSSFCell extends BaseTestXCell {
 
     public TestXSSFCell() {
index 4da863fafbf2b0f54ff8a5d59f76b144663988d4..ca9ba631f93bec2464e5320f2b1cea13ac2a538e 100644 (file)
 
 package org.apache.poi.xssf.usermodel;
 
-import org.apache.poi.ss.formula.eval.forked.TestForkedEvaluator;
+import org.apache.poi.ss.formula.eval.forked.BaseTestForkedEvaluator;
 import org.apache.poi.ss.usermodel.Workbook;
 
-public class TestXSSFForkedEvaluator extends TestForkedEvaluator {
-    
+public class TestXSSFForkedEvaluator extends BaseTestForkedEvaluator {
+
     @Override
     protected Workbook newWorkbook() {
         return new XSSFWorkbook();
index 698562570135ab3cc6d362cfe1299a37d5256a8e..669544fd41576c656b85daff7e567497d8aed28e 100644 (file)
@@ -23,7 +23,7 @@ import static org.junit.Assert.assertSame;
 
 import java.io.IOException;
 
-import org.apache.poi.ss.usermodel.BaseTestXRow;
+import org.apache.poi.ss.tests.usermodel.BaseTestXRow;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellCopyPolicy;
 import org.apache.poi.ss.usermodel.CellType;
@@ -42,7 +42,7 @@ public final class TestXSSFRow extends BaseTestXRow {
     public TestXSSFRow() {
         super(XSSFITestDataProvider.instance);
     }
-    
+
     @Test
     public void testCopyRowFrom() throws IOException {
         final XSSFWorkbook workbook = new XSSFWorkbook();
@@ -50,21 +50,21 @@ public final class TestXSSFRow extends BaseTestXRow {
         final XSSFRow srcRow = sheet.createRow(0);
         srcRow.createCell(0).setCellValue("Hello");
         final XSSFRow destRow = sheet.createRow(1);
-        
+
         destRow.copyRowFrom(srcRow, new CellCopyPolicy());
         assertNotNull(destRow.getCell(0));
         assertEquals("Hello", destRow.getCell(0).getStringCellValue());
-        
+
         workbook.close();
     }
-    
+
     @Test
     public void testCopyRowFromExternalSheet() throws IOException {
         final XSSFWorkbook workbook = new XSSFWorkbook();
         final Sheet srcSheet = workbook.createSheet("src");
         final XSSFSheet destSheet = workbook.createSheet("dest");
         workbook.createSheet("other");
-        
+
         final Row srcRow = srcSheet.createRow(0);
         int col = 0;
         //Test 2D and 3D Ref Ptgs (Pxg for OOXML Workbooks)
@@ -72,13 +72,13 @@ public final class TestXSSFRow extends BaseTestXRow {
         srcRow.createCell(col++).setCellFormula("src!B5");
         srcRow.createCell(col++).setCellFormula("dest!B5");
         srcRow.createCell(col++).setCellFormula("other!B5");
-        
+
         //Test 2D and 3D Ref Ptgs with absolute row
         srcRow.createCell(col++).setCellFormula("B$5");
         srcRow.createCell(col++).setCellFormula("src!B$5");
         srcRow.createCell(col++).setCellFormula("dest!B$5");
         srcRow.createCell(col++).setCellFormula("other!B$5");
-        
+
         //Test 2D and 3D Area Ptgs (Pxg for OOXML Workbooks)
         srcRow.createCell(col++).setCellFormula("SUM(B5:D$5)");
         srcRow.createCell(col++).setCellFormula("SUM(src!B5:D$5)");
@@ -89,81 +89,81 @@ public final class TestXSSFRow extends BaseTestXRow {
 
         final XSSFRow destRow = destSheet.createRow(1);
         destRow.copyRowFrom(srcRow, new CellCopyPolicy());
-        
+
         //////////////////
-        
+
         //Test 2D and 3D Ref Ptgs (Pxg for OOXML Workbooks)
         col = 0;
         Cell cell = destRow.getCell(col++);
         assertNotNull(cell);
         assertEquals("RefPtg", "B6", cell.getCellFormula());
-        
+
         cell = destRow.getCell(col++);
         assertNotNull(cell);
         assertEquals("Ref3DPtg", "src!B6", cell.getCellFormula());
-        
+
         cell = destRow.getCell(col++);
         assertNotNull(cell);
         assertEquals("Ref3DPtg", "dest!B6", cell.getCellFormula());
-        
+
         cell = destRow.getCell(col++);
         assertNotNull(cell);
         assertEquals("Ref3DPtg", "other!B6", cell.getCellFormula());
-        
+
         /////////////////////////////////////////////
-        
+
         //Test 2D and 3D Ref Ptgs with absolute row (Ptg row number shouldn't change)
         cell = destRow.getCell(col++);
         assertNotNull(cell);
         assertEquals("RefPtg", "B$5", cell.getCellFormula());
-        
+
         cell = destRow.getCell(col++);
         assertNotNull(cell);
         assertEquals("Ref3DPtg", "src!B$5", cell.getCellFormula());
-        
+
         cell = destRow.getCell(col++);
         assertNotNull(cell);
         assertEquals("Ref3DPtg", "dest!B$5", cell.getCellFormula());
-        
+
         cell = destRow.getCell(col++);
         assertNotNull(cell);
         assertEquals("Ref3DPtg", "other!B$5", cell.getCellFormula());
-        
+
         //////////////////////////////////////////
-        
+
         //Test 2D and 3D Area Ptgs (Pxg for OOXML Workbooks)
         // Note: absolute row changes from last cell to first cell in order
         // to maintain topLeft:bottomRight order
         cell = destRow.getCell(col++);
         assertNotNull(cell);
         assertEquals("Area2DPtg", "SUM(B$5:D6)", cell.getCellFormula());
-        
+
         cell = destRow.getCell(col++);
         assertNotNull(cell);
         assertEquals("Area3DPtg", "SUM(src!B$5:D6)", cell.getCellFormula());
-        
+
         cell = destRow.getCell(col++);
         assertNotNull(destRow.getCell(6));
         assertEquals("Area3DPtg", "SUM(dest!B$5:D6)", cell.getCellFormula());
-        
+
         cell = destRow.getCell(col++);
         assertNotNull(destRow.getCell(7));
         assertEquals("Area3DPtg", "SUM(other!B$5:D6)", cell.getCellFormula());
-        
+
         workbook.close();
     }
-    
+
     @Test
     public void testCopyRowOverwritesExistingRow() throws IOException {
         final XSSFWorkbook workbook = new XSSFWorkbook();
         final XSSFSheet sheet1 = workbook.createSheet("Sheet1");
         final Sheet sheet2 = workbook.createSheet("Sheet2");
-        
+
         final Row srcRow = sheet1.createRow(0);
         final XSSFRow destRow = sheet1.createRow(1);
         final Row observerRow = sheet1.createRow(2);
         final Row externObserverRow = sheet2.createRow(0);
-        
+
         srcRow.createCell(0).setCellValue("hello");
         srcRow.createCell(1).setCellValue("world");
         destRow.createCell(0).setCellValue(5.0); //A2 -> 5.0
@@ -171,10 +171,10 @@ public final class TestXSSFRow extends BaseTestXRow {
         observerRow.createCell(0).setCellFormula("A2"); // A3 -> A2 -> 5.0
         observerRow.createCell(1).setCellFormula("B2"); // B3 -> B2 -> A1 -> "hello"
         externObserverRow.createCell(0).setCellFormula("Sheet1!A2"); //Sheet2!A1 -> Sheet1!A2 -> 5.0
-        
+
         // overwrite existing destRow with row-copy of srcRow
         destRow.copyRowFrom(srcRow, new CellCopyPolicy());
-        
+
         // copyRowFrom should update existing destRow, rather than creating a new row and reassigning the destRow pointer
         // to the new row (and allow the old row to be garbage collected)
         // this is mostly so existing references to rows that are overwritten are updated
@@ -183,16 +183,16 @@ public final class TestXSSFRow extends BaseTestXRow {
         assertSame("existing references to destRow are still valid", destRow, sheet1.getRow(1));
         assertSame("existing references to observerRow are still valid", observerRow, sheet1.getRow(2));
         assertSame("existing references to externObserverRow are still valid", externObserverRow, sheet2.getRow(0));
-        
+
         // Make sure copyRowFrom actually copied row (this is tested elsewhere)
         assertEquals(CellType.STRING, destRow.getCell(0).getCellType());
         assertEquals("hello", destRow.getCell(0).getStringCellValue());
-        
+
         // We don't want #REF! errors if we copy a row that contains cells that are referred to by other cells outside of copied region
         assertEquals("references to overwritten cells are unmodified", "A2", observerRow.getCell(0).getCellFormula());
         assertEquals("references to overwritten cells are unmodified", "B2", observerRow.getCell(1).getCellFormula());
         assertEquals("references to overwritten cells are unmodified", "Sheet1!A2", externObserverRow.getCell(0).getCellFormula());
-        
+
         workbook.close();
     }
 
index 618575c5d1a54a3e84453da5455dcbe5db6389d8..28239f47b3007e1a9549c9d351d8583a2a9acd27 100644 (file)
@@ -27,7 +27,6 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -37,13 +36,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.ooxml.POIXMLException;
 import org.apache.poi.poifs.crypt.CryptoFunctions;
 import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.ss.tests.usermodel.BaseTestXSheet;
 import org.apache.poi.ss.usermodel.AutoFilter;
-import org.apache.poi.ss.usermodel.BaseTestXSheet;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellCopyPolicy;
 import org.apache.poi.ss.usermodel.CellType;
@@ -57,8 +55,10 @@ import org.apache.poi.ss.usermodel.IndexedColors;
 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.WorkbookFactory;
-import org.apache.poi.ss.util.*;
+import org.apache.poi.ss.util.CellAddress;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.ss.util.CellUtil;
 import org.apache.poi.util.LocaleUtil;
 import org.apache.poi.xssf.XSSFITestDataProvider;
 import org.apache.poi.xssf.XSSFTestDataSamples;
index bdab306964ac826c022dd1705b42ca7b84fd8a60..e2b2d88d5ed972c3e7d2c06d2a98c6319dcf1c4f 100644 (file)
@@ -54,7 +54,7 @@ import org.apache.poi.openxml4j.opc.PackagingURIHelper;
 import org.apache.poi.openxml4j.opc.internal.FileHelper;
 import org.apache.poi.openxml4j.opc.internal.MemoryPackagePart;
 import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart;
-import org.apache.poi.ss.usermodel.BaseTestXWorkbook;
+import org.apache.poi.ss.tests.usermodel.BaseTestXWorkbook;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.Font;
@@ -81,7 +81,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode;
 
-public final class TestXSSFWorkbook extends BaseTestXWorkbook {
+public final class  TestXSSFWorkbook extends BaseTestXWorkbook {
 
     public TestXSSFWorkbook() {
         super(XSSFITestDataProvider.instance);
@@ -1007,26 +1007,26 @@ public final class TestXSSFWorkbook extends BaseTestXWorkbook {
             assertTrue(file.exists());
 
             // read-only mode works!
-            Workbook workbook = WorkbookFactory.create(OPCPackage.open(file, PackageAccess.READ));
+            Workbook workbook = XSSFWorkbookFactory.createWorkbook(OPCPackage.open(file, PackageAccess.READ));
             Date dateAct = workbook.getSheetAt(0).getRow(0).getCell(0, MissingCellPolicy.CREATE_NULL_AS_BLANK).getDateCellValue();
             assertEquals(dateExp, dateAct);
             workbook.close();
             workbook = null;
 
-            workbook = WorkbookFactory.create(OPCPackage.open(file, PackageAccess.READ));
+            workbook = XSSFWorkbookFactory.createWorkbook(OPCPackage.open(file, PackageAccess.READ));
             dateAct = workbook.getSheetAt(0).getRow(0).getCell(0, MissingCellPolicy.CREATE_NULL_AS_BLANK).getDateCellValue();
             assertEquals(dateExp, dateAct);
             workbook.close();
             workbook = null;
 
             // now check read/write mode
-            workbook = WorkbookFactory.create(OPCPackage.open(file, PackageAccess.READ_WRITE));
+            workbook = XSSFWorkbookFactory.createWorkbook(OPCPackage.open(file, PackageAccess.READ_WRITE));
             dateAct = workbook.getSheetAt(0).getRow(0).getCell(0, MissingCellPolicy.CREATE_NULL_AS_BLANK).getDateCellValue();
             assertEquals(dateExp, dateAct);
             workbook.close();
             workbook = null;
 
-            workbook = WorkbookFactory.create(OPCPackage.open(file, PackageAccess.READ_WRITE));
+            workbook = XSSFWorkbookFactory.createWorkbook(OPCPackage.open(file, PackageAccess.READ_WRITE));
             dateAct = workbook.getSheetAt(0).getRow(0).getCell(0, MissingCellPolicy.CREATE_NULL_AS_BLANK).getDateCellValue();
             assertEquals(dateExp, dateAct);
             workbook.close();
diff --git a/src/resources/main/META-INF/services/org.apache.poi.ss.usermodel.WorkbookProvider b/src/resources/main/META-INF/services/org.apache.poi.ss.usermodel.WorkbookProvider
new file mode 100644 (file)
index 0000000..fe7fe8c
--- /dev/null
@@ -0,0 +1,18 @@
+# ====================================================================
+#  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.
+# ====================================================================
+
+org.apache.poi.hssf.usermodel.HSSFWorkbookFactory
\ No newline at end of file
diff --git a/src/resources/ooxml/META-INF/services/org.apache.poi.ss.usermodel.WorkbookProvider b/src/resources/ooxml/META-INF/services/org.apache.poi.ss.usermodel.WorkbookProvider
new file mode 100644 (file)
index 0000000..48b8932
--- /dev/null
@@ -0,0 +1,18 @@
+# ====================================================================
+#  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.
+# ====================================================================
+
+org.apache.poi.xssf.usermodel.XSSFWorkbookFactory
\ No newline at end of file
diff --git a/src/scratchpad/testcases/org/apache/poi/TestJDK12.java b/src/scratchpad/testcases/org/apache/poi/TestJDK12.java
deleted file mode 100644 (file)
index d0d33b2..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi;
-
-import org.junit.Test;
-
-import java.awt.Graphics2D;
-import java.awt.RenderingHints;
-import java.awt.font.TextLayout;
-import java.awt.image.BufferedImage;
-import java.text.AttributedString;
-
-/**
- * Minimal Test-Class found when running the Apache POI regression tests.
- *
- * This reproduces a crash introduced in JDK 12-ea+28 and JDK 13-ea+4
- *
- * This works in recent JDK 8, JDK 11 and at least up to JDK 12-ea+20
- *
- * https://bugs.openjdk.java.net/browse/JDK-8217768
- *
- * Should be fixed in JDK 12-ea+29 and JDK 13-ea+5
- */
-public class TestJDK12 {
-    @Test
-    public void test() throws Exception {
-        BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
-        Graphics2D graphics = img.createGraphics();
-        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-        graphics.scale(200, 1);
-
-        new TextLayout(new AttributedString("agriculture").getIterator(), graphics.getFontRenderContext());
-
-        graphics.dispose();
-        img.flush();
-    }
-
-}
diff --git a/src/scratchpad/testcases/org/apache/poi/TestPOIDocumentScratchpad.java b/src/scratchpad/testcases/org/apache/poi/TestPOIDocumentScratchpad.java
deleted file mode 100644 (file)
index d10c6f0..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-
-
-package org.apache.poi;
-
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-import org.apache.poi.hpsf.DocumentSummaryInformation;
-import org.apache.poi.hpsf.HPSFPropertiesOnlyDocument;
-import org.apache.poi.hpsf.SummaryInformation;
-import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl;
-import org.apache.poi.hwpf.HWPFTestDataSamples;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Tests that POIDocument correctly loads and saves the common
- *  (hspf) Document Properties
- *
- * This is part 2 of 2 of the tests - it only does the POIDocuments
- *  which are part of the scratchpad (not main)
- */
-public final class TestPOIDocumentScratchpad {
-       // The POI Documents to work on
-       private POIDocument doc;
-       private POIDocument doc2;
-
-       /**
-        * Set things up, using a PowerPoint document and
-        *  a Word Document for our testing
-        */
-       @Before
-    public void setUp() throws IOException {
-               doc = new HSLFSlideShowImpl(POIDataSamples.getSlideShowInstance().openResourceAsStream("basic_test_ppt_file.ppt"));
-               doc2 = HWPFTestDataSamples.openSampleFile("test2.doc");
-       }
-
-       @Test
-       public void testReadProperties() {
-           testReadPropertiesHelper(doc);
-       }
-       
-       private void testReadPropertiesHelper(POIDocument docPH) {
-               // We should have both sets
-               assertNotNull(docPH.getDocumentSummaryInformation());
-               assertNotNull(docPH.getSummaryInformation());
-
-               // Check they are as expected for the test doc
-               assertEquals("Hogwarts", docPH.getSummaryInformation().getAuthor());
-               assertEquals(10598, docPH.getDocumentSummaryInformation().getByteCount());
-       }
-
-       @Test
-       public void testReadProperties2() {
-               // Check again on the word one
-               assertNotNull(doc2.getDocumentSummaryInformation());
-               assertNotNull(doc2.getSummaryInformation());
-
-               assertEquals("Hogwarts", doc2.getSummaryInformation().getAuthor());
-               assertEquals("", doc2.getSummaryInformation().getKeywords());
-               assertEquals(0, doc2.getDocumentSummaryInformation().getByteCount());
-       }
-
-       @Test
-       public void testWriteProperties() throws IOException {
-               // Just check we can write them back out into a filesystem
-               POIFSFileSystem outFS = new POIFSFileSystem();
-               doc.writeProperties(outFS);
-
-               // Should now hold them
-               assertNotNull(outFS.createDocumentInputStream(SummaryInformation.DEFAULT_STREAM_NAME));
-               assertNotNull(outFS.createDocumentInputStream(DocumentSummaryInformation.DEFAULT_STREAM_NAME));
-               outFS.close();
-       }
-
-       @Test
-    public void testWriteReadProperties() throws IOException {
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
-       // Write them out
-       POIFSFileSystem outFS = new POIFSFileSystem();
-       doc.writeProperties(outFS);
-       outFS.writeFilesystem(baos);
-
-       // Create a new version
-       ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-       POIFSFileSystem inFS = new POIFSFileSystem(bais);
-
-       // Check they're still there
-       POIDocument ppt = new HPSFPropertiesOnlyDocument(inFS);
-       ppt.readProperties();
-
-       // Delegate test
-       testReadPropertiesHelper(ppt);
-       
-       ppt.close();
-       inFS.close();
-    }
-}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/TestPOIDocumentScratchpad.java b/src/scratchpad/testcases/org/apache/poi/hslf/TestPOIDocumentScratchpad.java
new file mode 100644 (file)
index 0000000..03f3fcf
--- /dev/null
@@ -0,0 +1,125 @@
+
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+
+
+package org.apache.poi.hslf;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.POIDocument;
+import org.apache.poi.hpsf.DocumentSummaryInformation;
+import org.apache.poi.hpsf.HPSFPropertiesOnlyDocument;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl;
+import org.apache.poi.hwpf.HWPFTestDataSamples;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests that POIDocument correctly loads and saves the common
+ *  (hspf) Document Properties
+ *
+ * This is part 2 of 2 of the tests - it only does the POIDocuments
+ *  which are part of the scratchpad (not main)
+ */
+public final class TestPOIDocumentScratchpad {
+       // The POI Documents to work on
+       private POIDocument doc;
+       private POIDocument doc2;
+
+       /**
+        * Set things up, using a PowerPoint document and
+        *  a Word Document for our testing
+        */
+       @Before
+    public void setUp() throws IOException {
+               doc = new HSLFSlideShowImpl(POIDataSamples.getSlideShowInstance().openResourceAsStream("basic_test_ppt_file.ppt"));
+               doc2 = HWPFTestDataSamples.openSampleFile("test2.doc");
+       }
+
+       @Test
+       public void testReadProperties() {
+           testReadPropertiesHelper(doc);
+       }
+
+       private void testReadPropertiesHelper(POIDocument docPH) {
+               // We should have both sets
+               assertNotNull(docPH.getDocumentSummaryInformation());
+               assertNotNull(docPH.getSummaryInformation());
+
+               // Check they are as expected for the test doc
+               assertEquals("Hogwarts", docPH.getSummaryInformation().getAuthor());
+               assertEquals(10598, docPH.getDocumentSummaryInformation().getByteCount());
+       }
+
+       @Test
+       public void testReadProperties2() {
+               // Check again on the word one
+               assertNotNull(doc2.getDocumentSummaryInformation());
+               assertNotNull(doc2.getSummaryInformation());
+
+               assertEquals("Hogwarts", doc2.getSummaryInformation().getAuthor());
+               assertEquals("", doc2.getSummaryInformation().getKeywords());
+               assertEquals(0, doc2.getDocumentSummaryInformation().getByteCount());
+       }
+
+       @Test
+       public void testWriteProperties() throws IOException {
+               // Just check we can write them back out into a filesystem
+               POIFSFileSystem outFS = new POIFSFileSystem();
+               doc.writeProperties(outFS);
+
+               // Should now hold them
+               assertNotNull(outFS.createDocumentInputStream(SummaryInformation.DEFAULT_STREAM_NAME));
+               assertNotNull(outFS.createDocumentInputStream(DocumentSummaryInformation.DEFAULT_STREAM_NAME));
+               outFS.close();
+       }
+
+       @Test
+    public void testWriteReadProperties() throws IOException {
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+       // Write them out
+       POIFSFileSystem outFS = new POIFSFileSystem();
+       doc.writeProperties(outFS);
+       outFS.writeFilesystem(baos);
+
+       // Create a new version
+       ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+       POIFSFileSystem inFS = new POIFSFileSystem(bais);
+
+       // Check they're still there
+       POIDocument ppt = new HPSFPropertiesOnlyDocument(inFS);
+       ppt.readProperties();
+
+       // Delegate test
+       testReadPropertiesHelper(ppt);
+
+       ppt.close();
+       inFS.close();
+    }
+}
index fa0b4ea71b99d59e3a4efbdac207d926f90722c7..25f9725ec216cc5f66f6920442239de0aadbd324 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.apache.poi.hslf.model;
 
-import static org.apache.poi.sl.TestCommonSL.getColor;
+import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
index 4a6c02696f4fb955344d36afd73f3906ca821bc4..7d46ed14b101bc21a781f82f85c455bac2cc6298 100644 (file)
@@ -18,7 +18,7 @@
 package org.apache.poi.hslf.record;
 
 
-import static org.apache.poi.ss.formula.functions.AbstractNumericTestCase.assertEquals;
+import static org.apache.poi.ss.formula.functions.BaseTestNumeric.assertEquals;
 import static org.junit.Assert.assertArrayEquals;
 
 import java.io.ByteArrayOutputStream;
index 6bae49681a46c61153aacedc7e11fae2a2a178d0..04d8c056012f0d4db703dcf1dfc95f0491d1f695 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.apache.poi.hslf.usermodel;
 
-import static org.apache.poi.sl.TestCommonSL.getColor;
+import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestHSSFChart.java b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestHSSFChart.java
deleted file mode 100644 (file)
index 987741f..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-
-import java.io.IOException;
-
-import org.apache.poi.hssf.HSSFITestDataProvider;
-import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.record.chart.SeriesRecord;
-import org.apache.poi.hssf.usermodel.HSSFChart.HSSFSeries;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.CellRangeAddressBase;
-import org.junit.Test;
-
-/**
- * Tests for {@link HSSFChart}
- */
-public final class TestHSSFChart {
-
-       @Test
-       public void testSingleChart() {
-               HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("WithChart.xls");
-
-               HSSFSheet s1 = wb.getSheetAt(0);
-               HSSFSheet s2 = wb.getSheetAt(1);
-               HSSFSheet s3 = wb.getSheetAt(2);
-
-               assertEquals(0, HSSFChart.getSheetCharts(s1).length);
-               assertEquals(1, HSSFChart.getSheetCharts(s2).length);
-               assertEquals(0, HSSFChart.getSheetCharts(s3).length);
-
-               HSSFChart[] charts;
-
-               // Check the chart on the 2nd sheet
-               charts = HSSFChart.getSheetCharts(s2);
-               assertEquals(1, charts.length);
-
-               assertEquals(2, charts[0].getSeries().length);
-               assertEquals("1st Column", charts[0].getSeries()[0].getSeriesTitle());
-               assertEquals("2nd Column", charts[0].getSeries()[1].getSeriesTitle());
-               assertNull(charts[0].getChartTitle());
-
-               // Check x, y, width, height
-               assertEquals(0, charts[0].getChartX());
-               assertEquals(0, charts[0].getChartY());
-               assertEquals(26492928, charts[0].getChartWidth());
-               assertEquals(15040512, charts[0].getChartHeight());
-       }
-
-       @Test
-       public void testTwoCharts() {
-               HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("WithTwoCharts.xls");
-
-               HSSFSheet s1 = wb.getSheetAt(0);
-               HSSFSheet s2 = wb.getSheetAt(1);
-               HSSFSheet s3 = wb.getSheetAt(2);
-
-               assertEquals(0, HSSFChart.getSheetCharts(s1).length);
-               assertEquals(1, HSSFChart.getSheetCharts(s2).length);
-               assertEquals(1, HSSFChart.getSheetCharts(s3).length);
-
-               HSSFChart[] charts;
-
-               // Check the chart on the 2nd sheet
-               charts = HSSFChart.getSheetCharts(s2);
-               assertEquals(1, charts.length);
-
-               assertEquals(2, charts[0].getSeries().length);
-               assertEquals("1st Column", charts[0].getSeries()[0].getSeriesTitle());
-               assertEquals("2nd Column", charts[0].getSeries()[1].getSeriesTitle());
-               assertNull(charts[0].getChartTitle());
-
-               // And the third sheet
-               charts = HSSFChart.getSheetCharts(s3);
-               assertEquals(1, charts.length);
-
-               assertEquals(2, charts[0].getSeries().length);
-               assertEquals("Squares", charts[0].getSeries()[0].getSeriesTitle());
-               assertEquals("Base Numbers", charts[0].getSeries()[1].getSeriesTitle());
-               assertNull(charts[0].getChartTitle());
-       }
-
-       @Test
-       public void testThreeCharts() {
-               HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("WithThreeCharts.xls");
-
-               HSSFSheet s1 = wb.getSheetAt(0);
-               HSSFSheet s2 = wb.getSheetAt(1);
-               HSSFSheet s3 = wb.getSheetAt(2);
-
-               assertEquals(0, HSSFChart.getSheetCharts(s1).length);
-               assertEquals(2, HSSFChart.getSheetCharts(s2).length);
-               assertEquals(1, HSSFChart.getSheetCharts(s3).length);
-
-               HSSFChart[] charts;
-
-               // Check the charts on the 2nd sheet
-               charts = HSSFChart.getSheetCharts(s2);
-               assertEquals(2, charts.length);
-
-               assertEquals(2, charts[0].getSeries().length);
-               assertEquals("1st Column", charts[0].getSeries()[0].getSeriesTitle());
-               assertEquals("2nd Column", charts[0].getSeries()[1].getSeriesTitle());
-               assertEquals(6, charts[0].getSeries()[0].getNumValues());
-               assertEquals(6, charts[0].getSeries()[1].getNumValues());
-               assertEquals(SeriesRecord.CATEGORY_DATA_TYPE_NUMERIC, charts[0].getSeries()[0].getValueType());
-               assertEquals(SeriesRecord.CATEGORY_DATA_TYPE_NUMERIC, charts[0].getSeries()[1].getValueType());
-               assertNull(charts[0].getChartTitle());
-
-               assertEquals(1, charts[1].getSeries().length);
-               assertNull(charts[1].getSeries()[0].getSeriesTitle());
-               assertEquals("Pie Chart Title Thingy", charts[1].getChartTitle());
-
-               // And the third sheet
-               charts = HSSFChart.getSheetCharts(s3);
-               assertEquals(1, charts.length);
-
-               assertEquals(2, charts[0].getSeries().length);
-               assertEquals("Squares", charts[0].getSeries()[0].getSeriesTitle());
-               assertEquals("Base Numbers", charts[0].getSeries()[1].getSeriesTitle());
-               assertEquals("Sheet 3 Chart with Title", charts[0].getChartTitle());
-       }
-       
-    @Test
-    public void testExistingSheet3() throws Exception {
-        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("49581.xls");
-        
-        HSSFSheet sheet = wb.getSheetAt( 2 ) ;
-        HSSFChart[] charts = HSSFChart.getSheetCharts( sheet ) ;
-        assertEquals(1, charts.length);
-        
-        for ( HSSFChart chart : charts ) {
-            for ( HSSFSeries series : chart.getSeries() ) {
-                chart.removeSeries( series ) ;
-            }
-        }
-        
-        // Save and re-check
-        wb = HSSFITestDataProvider.instance.writeOutAndReadBack(wb);
-        sheet = wb.getSheetAt( 2 ) ;
-        assertEquals(1, HSSFChart.getSheetCharts(sheet).length);
-        
-        HSSFChart c = HSSFChart.getSheetCharts(sheet)[0];
-        assertEquals(0, c.getSeries().length);
-    }
-
-    @Test
-    public void testExistingSheet2() throws Exception {
-        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("49581.xls");
-        HSSFSheet sheet = wb.getSheetAt( 1 ) ;
-        HSSFChart[] charts = HSSFChart.getSheetCharts( sheet ) ;
-        
-        assertEquals(1, charts.length);
-        for ( HSSFChart chart : charts ) {
-            HSSFSeries series ;
-            
-            // Starts with one
-            assertEquals(1, chart.getSeries().length);
-
-            // Add two more
-            series = chart.createSeries() ;
-            series.setCategoryLabelsCellRange( new CellRangeAddress( 3, 4, 0, 0 ) ) ;
-            series.setValuesCellRange( new CellRangeAddress( 3, 4, 1, 1 ) ) ;
-
-            series = chart.createSeries() ;
-            series.setCategoryLabelsCellRange( new CellRangeAddress( 6, 7, 0, 0 ) ) ;
-            series.setValuesCellRange( new CellRangeAddress( 6, 7, 1, 1 ) ) ;
-        }
-        
-        // Save and re-check
-        wb = HSSFITestDataProvider.instance.writeOutAndReadBack(wb);
-        sheet = wb.getSheetAt( 1 ) ;
-        assertEquals(1, HSSFChart.getSheetCharts(sheet).length);
-        
-        HSSFChart c = HSSFChart.getSheetCharts(sheet)[0];
-        assertEquals(3, c.getSeries().length);
-    }
-
-    @Test
-    public void testExistingSheet1() throws Exception {
-       HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("49581.xls");
-        HSSFSheet sheet = wb.getSheetAt( 0 ) ;
-        HSSFChart[] charts = HSSFChart.getSheetCharts( sheet ) ;
-        
-        for ( HSSFChart chart : charts ) {
-            //System.out.println( chart.getType() ) ;
-            HSSFSeries[] seriesArray = chart.getSeries() ;
-            //System.out.println( "seriesArray.length=" + seriesArray.length ) ;
-            for ( HSSFSeries series : seriesArray )
-            {
-                //System.out.println( "serie.getNumValues()=" + series.getNumValues() ) ;
-                CellRangeAddressBase range ;
-
-                range = series.getValuesCellRange() ;
-                //System.out.println( range.toString() ) ;
-                range.setLastRow( range.getLastRow() + 1 ) ;
-                series.setValuesCellRange( range ) ;
-
-                range = series.getCategoryLabelsCellRange() ;
-                //System.out.println( range.toString() ) ;
-                range.setLastRow( range.getLastRow() + 1 ) ;
-                series.setCategoryLabelsCellRange( range ) ;
-            }
-
-            for ( int id = 0 ; id < 2 ; id++ )
-            {
-                HSSFSeries newSeries = chart.createSeries() ;
-                newSeries.setValuesCellRange( new CellRangeAddress( 1 + id, 4, 3, 3 ) ) ;
-                String oldSeriesTitle = newSeries.getSeriesTitle() ;
-                if ( oldSeriesTitle != null )
-                {
-                    //System.out.println( "old series title: " + oldSeriesTitle ) ;
-                    newSeries.setSeriesTitle( "new series" ) ;
-                }
-            }
-        }
-
-        HSSFChart chart = charts[ 2 ] ;
-        chart.removeSeries( chart.getSeries()[ 0 ] ) ;
-    }
-    
-    /**
-     * Bug 26862: HSSFWorkbook.cloneSheet copies charts
-     */
-    @Test
-    public void test26862() throws IOException, Exception {
-        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SimpleChart.xls");
-        HSSFSheet srcSheet = wb.getSheetAt(0);
-        HSSFChart[] srcCharts = HSSFChart.getSheetCharts(srcSheet);
-        assertEquals(1, srcCharts.length);
-        HSSFChart srcChart = srcCharts[0];
-        
-        // Clone the sheet
-        HSSFSheet clonedSheet = wb.cloneSheet(0);
-        
-        // Verify the chart was copied
-        HSSFChart[] clonedCharts = HSSFChart.getSheetCharts(clonedSheet);
-        assertEquals(1, clonedCharts.length);
-        HSSFChart clonedChart = clonedCharts[0];
-        assertNotSame(srcChart, clonedChart); //refer to different objects
-        assertEquals(srcChart.getType(), clonedChart.getType());
-        assertEquals(srcChart.getChartTitle(), clonedChart.getChartTitle());
-        assertEquals(srcChart.getChartWidth(), clonedChart.getChartWidth());
-        assertEquals(srcChart.getChartHeight(), clonedChart.getChartHeight());
-        assertEquals(srcChart.getChartX(), clonedChart.getChartX());
-        assertEquals(srcChart.getChartY(), clonedChart.getChartY());
-        
-        // Check if chart was shallow copied or deep copied
-        clonedChart.setChartWidth(clonedChart.getChartWidth()+10);
-        assertEquals(srcChart.getChartWidth()+10, clonedChart.getChartWidth());
-        
-        wb.close();
-    }
-}
diff --git a/src/testcases/org/apache/poi/TestJDK12.java b/src/testcases/org/apache/poi/TestJDK12.java
new file mode 100644 (file)
index 0000000..dfac092
--- /dev/null
@@ -0,0 +1,53 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi;
+
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.font.TextLayout;
+import java.awt.image.BufferedImage;
+import java.text.AttributedString;
+
+import org.junit.Test;
+
+/**
+ * Minimal Test-Class found when running the Apache POI regression tests.
+ *
+ * This reproduces a crash introduced in JDK 12-ea+28 and JDK 13-ea+4
+ *
+ * This works in recent JDK 8, JDK 11 and at least up to JDK 12-ea+20
+ *
+ * https://bugs.openjdk.java.net/browse/JDK-8217768
+ *
+ * Should be fixed in JDK 12-ea+29 and JDK 13-ea+5
+ */
+public class TestJDK12 {
+    @Test
+    public void test() throws Exception {
+        BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
+        Graphics2D graphics = img.createGraphics();
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        graphics.scale(200, 1);
+
+        new TextLayout(new AttributedString("agriculture").getIterator(), graphics.getFontRenderContext());
+
+        graphics.dispose();
+        img.flush();
+    }
+
+}
diff --git a/src/testcases/org/apache/poi/hssf/dev/BaseTestIteratingXLS.java b/src/testcases/org/apache/poi/hssf/dev/BaseTestIteratingXLS.java
new file mode 100644 (file)
index 0000000..a8b30a0
--- /dev/null
@@ -0,0 +1,104 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.hssf.dev;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.util.NullOutputStream;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Base class for integration-style tests which iterate over all test-files
+ * and execute the same action to find out if any change breaks these applications.
+ *
+ * This test uses {@link Parameterized} to run the test for each file separatedely.
+ */
+@RunWith(Parameterized.class)
+public abstract class BaseTestIteratingXLS {
+    protected static final OutputStream NULL_OUTPUT_STREAM = new NullOutputStream();
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+       protected static final Map<String,Class<? extends Throwable>> EXCLUDED =
+            new HashMap<>();
+
+    @Parameters(name="{index}: {0}")
+    public static Iterable<Object[]> files() {
+        String dataDirName = System.getProperty(POIDataSamples.TEST_PROPERTY);
+        if(dataDirName == null) {
+            dataDirName = "test-data";
+        }
+
+        List<Object[]> files = new ArrayList<>();
+        findFile(files, dataDirName + "/spreadsheet");
+        findFile(files, dataDirName + "/hpsf");
+
+        return files;
+    }
+
+    private static void findFile(List<Object[]> list, String dir) {
+        String[] files = new File(dir).list((arg0, arg1) -> arg1.toLowerCase(Locale.ROOT).endsWith(".xls"));
+
+        assertNotNull("Did not find any xls files in directory " + dir, files);
+
+        for(String file : files) {
+            list.add(new Object[] { new File(dir, file) });
+        }
+    }
+
+    @Parameter
+    public File file;
+
+       @Test
+       public void testMain() throws Exception {
+           String fileName = file.getName();
+           if (EXCLUDED.containsKey(fileName)) {
+               thrown.expect(EXCLUDED.get(fileName));
+           }
+
+               try {
+                       runOneFile(file);
+               } catch (Exception e) {
+                       // try to read it in HSSFWorkbook to quickly fail if we cannot read the file there at all and thus probably should use EXCLUDED instead
+            try (FileInputStream stream = new FileInputStream(file); HSSFWorkbook wb = new HSSFWorkbook(stream)) {
+                assertNotNull(wb);
+            }
+
+                       throw e;
+               }
+       }
+
+       abstract void runOneFile(File pFile) throws Exception;
+}
diff --git a/src/testcases/org/apache/poi/hssf/dev/BaseXLSIteratingTest.java b/src/testcases/org/apache/poi/hssf/dev/BaseXLSIteratingTest.java
deleted file mode 100644 (file)
index d57583a..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.hssf.dev;
-
-import static org.junit.Assert.assertNotNull;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.util.NullOutputStream;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-/**
- * Base class for integration-style tests which iterate over all test-files
- * and execute the same action to find out if any change breaks these applications.
- * 
- * This test uses {@link Parameterized} to run the test for each file separatedely.
- */
-@RunWith(Parameterized.class)
-public abstract class BaseXLSIteratingTest {
-    protected static final OutputStream NULL_OUTPUT_STREAM = new NullOutputStream();
-
-    @Rule
-    public ExpectedException thrown = ExpectedException.none();
-    
-       protected static final Map<String,Class<? extends Throwable>> EXCLUDED =
-            new HashMap<>();
-
-    @Parameters(name="{index}: {0}")
-    public static Iterable<Object[]> files() {
-        String dataDirName = System.getProperty(POIDataSamples.TEST_PROPERTY);
-        if(dataDirName == null) {
-            dataDirName = "test-data";
-        }
-
-        List<Object[]> files = new ArrayList<>();
-        findFile(files, dataDirName + "/spreadsheet");
-        findFile(files, dataDirName + "/hpsf");
-        
-        return files;
-    }
-       
-    private static void findFile(List<Object[]> list, String dir) {
-        String[] files = new File(dir).list((arg0, arg1) -> arg1.toLowerCase(Locale.ROOT).endsWith(".xls"));
-        
-        assertNotNull("Did not find any xls files in directory " + dir, files);
-        
-        for(String file : files) {
-            list.add(new Object[] { new File(dir, file) });
-        }
-    }
-    
-    @Parameter
-    public File file;
-    
-       @Test
-       public void testMain() throws Exception {
-           String fileName = file.getName();
-           if (EXCLUDED.containsKey(fileName)) {
-               thrown.expect(EXCLUDED.get(fileName));
-           }
-           
-               try {
-                       runOneFile(file);
-               } catch (Exception e) {
-                       // try to read it in HSSFWorkbook to quickly fail if we cannot read the file there at all and thus probably should use EXCLUDED instead
-            try (FileInputStream stream = new FileInputStream(file); HSSFWorkbook wb = new HSSFWorkbook(stream)) {
-                assertNotNull(wb);
-            }
-                       
-                       throw e;
-               }
-       }
-
-       abstract void runOneFile(File pFile) throws Exception;
-}
index 17b43f0da13f477984bbaaf64bc14ea8ca4c339f..12d7c6fbaf758042fb4b14870c69219b5c12e325 100644 (file)
@@ -26,7 +26,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.util.RecordFormatException;
 import org.junit.BeforeClass;
 
-public class TestBiffDrawingToXml extends BaseXLSIteratingTest {
+public class TestBiffDrawingToXml extends BaseTestIteratingXLS {
     @BeforeClass
     public static void setup() {
         EXCLUDED.clear();
index 82a46327b980bbe89e919dd1befc7d7265cea444..d4fd62fa99d8d2185a9f3cf226837b865a2c503d 100644 (file)
@@ -33,7 +33,7 @@ import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 
-public class TestBiffViewer extends BaseXLSIteratingTest {
+public class TestBiffViewer extends BaseTestIteratingXLS {
     @BeforeClass
     public static void setup() {
         EXCLUDED.clear();
index a24b4967f73ca7077838cf74a729ec85d08e4b90..d32e0b71eb71456e7287a331bc3e9571d6ad5dc3 100644 (file)
@@ -27,7 +27,7 @@ import org.apache.poi.util.LocaleUtil;
 import org.apache.poi.util.RecordFormatException;
 import org.junit.BeforeClass;
 
-public class TestEFBiffViewer extends BaseXLSIteratingTest {
+public class TestEFBiffViewer extends BaseTestIteratingXLS {
     @BeforeClass
     public static void setup() {
         EXCLUDED.clear();
index ec69abb4cb4d80b2fcfc9c27cb29fa09409de339..b92223099401b254b7aa234c56270ddf8352c2a2 100644 (file)
@@ -28,7 +28,7 @@ import org.apache.poi.util.LocaleUtil;
 import org.apache.poi.util.RecordFormatException;
 import org.junit.BeforeClass;
 
-public class TestFormulaViewer extends BaseXLSIteratingTest {
+public class TestFormulaViewer extends BaseTestIteratingXLS {
     @BeforeClass
     public static void setup() {
         EXCLUDED.clear();
index 97b84e21acdb7c0dd331dc007b9ed6ebeeba47d2..890ef1e8372afcd31e8dc8669e3a42c935c8ac53 100644 (file)
@@ -31,7 +31,7 @@ import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 
-public class TestReSave extends BaseXLSIteratingTest {
+public class TestReSave extends BaseTestIteratingXLS {
     @BeforeClass
     public static void setup() {
         EXCLUDED.clear();
index f15801390b64d6ab9b0079017b23c7b33aefba9b..934eb5b89d39c8998b93f42593e78a53f1a5194a 100644 (file)
@@ -25,7 +25,7 @@ import org.apache.poi.util.LocaleUtil;
 import org.apache.poi.util.RecordFormatException;
 import org.junit.BeforeClass;
 
-public class TestRecordLister extends BaseXLSIteratingTest {
+public class TestRecordLister extends BaseTestIteratingXLS {
     @BeforeClass
     public static void setup() {
         EXCLUDED.clear();
@@ -40,7 +40,7 @@ public class TestRecordLister extends BaseXLSIteratingTest {
         EXCLUDED.put("61300.xls", RecordFormatException.class);
         EXCLUDED.put("64130.xls", OldExcelFormatException.class); //Biff 5
     }
-       
+
        @Override
        void runOneFile(File fileIn) throws IOException {
                PrintStream save = System.out;
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFChart.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFChart.java
new file mode 100644 (file)
index 0000000..987741f
--- /dev/null
@@ -0,0 +1,273 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.usermodel;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+
+import org.apache.poi.hssf.HSSFITestDataProvider;
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.record.chart.SeriesRecord;
+import org.apache.poi.hssf.usermodel.HSSFChart.HSSFSeries;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddressBase;
+import org.junit.Test;
+
+/**
+ * Tests for {@link HSSFChart}
+ */
+public final class TestHSSFChart {
+
+       @Test
+       public void testSingleChart() {
+               HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("WithChart.xls");
+
+               HSSFSheet s1 = wb.getSheetAt(0);
+               HSSFSheet s2 = wb.getSheetAt(1);
+               HSSFSheet s3 = wb.getSheetAt(2);
+
+               assertEquals(0, HSSFChart.getSheetCharts(s1).length);
+               assertEquals(1, HSSFChart.getSheetCharts(s2).length);
+               assertEquals(0, HSSFChart.getSheetCharts(s3).length);
+
+               HSSFChart[] charts;
+
+               // Check the chart on the 2nd sheet
+               charts = HSSFChart.getSheetCharts(s2);
+               assertEquals(1, charts.length);
+
+               assertEquals(2, charts[0].getSeries().length);
+               assertEquals("1st Column", charts[0].getSeries()[0].getSeriesTitle());
+               assertEquals("2nd Column", charts[0].getSeries()[1].getSeriesTitle());
+               assertNull(charts[0].getChartTitle());
+
+               // Check x, y, width, height
+               assertEquals(0, charts[0].getChartX());
+               assertEquals(0, charts[0].getChartY());
+               assertEquals(26492928, charts[0].getChartWidth());
+               assertEquals(15040512, charts[0].getChartHeight());
+       }
+
+       @Test
+       public void testTwoCharts() {
+               HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("WithTwoCharts.xls");
+
+               HSSFSheet s1 = wb.getSheetAt(0);
+               HSSFSheet s2 = wb.getSheetAt(1);
+               HSSFSheet s3 = wb.getSheetAt(2);
+
+               assertEquals(0, HSSFChart.getSheetCharts(s1).length);
+               assertEquals(1, HSSFChart.getSheetCharts(s2).length);
+               assertEquals(1, HSSFChart.getSheetCharts(s3).length);
+
+               HSSFChart[] charts;
+
+               // Check the chart on the 2nd sheet
+               charts = HSSFChart.getSheetCharts(s2);
+               assertEquals(1, charts.length);
+
+               assertEquals(2, charts[0].getSeries().length);
+               assertEquals("1st Column", charts[0].getSeries()[0].getSeriesTitle());
+               assertEquals("2nd Column", charts[0].getSeries()[1].getSeriesTitle());
+               assertNull(charts[0].getChartTitle());
+
+               // And the third sheet
+               charts = HSSFChart.getSheetCharts(s3);
+               assertEquals(1, charts.length);
+
+               assertEquals(2, charts[0].getSeries().length);
+               assertEquals("Squares", charts[0].getSeries()[0].getSeriesTitle());
+               assertEquals("Base Numbers", charts[0].getSeries()[1].getSeriesTitle());
+               assertNull(charts[0].getChartTitle());
+       }
+
+       @Test
+       public void testThreeCharts() {
+               HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("WithThreeCharts.xls");
+
+               HSSFSheet s1 = wb.getSheetAt(0);
+               HSSFSheet s2 = wb.getSheetAt(1);
+               HSSFSheet s3 = wb.getSheetAt(2);
+
+               assertEquals(0, HSSFChart.getSheetCharts(s1).length);
+               assertEquals(2, HSSFChart.getSheetCharts(s2).length);
+               assertEquals(1, HSSFChart.getSheetCharts(s3).length);
+
+               HSSFChart[] charts;
+
+               // Check the charts on the 2nd sheet
+               charts = HSSFChart.getSheetCharts(s2);
+               assertEquals(2, charts.length);
+
+               assertEquals(2, charts[0].getSeries().length);
+               assertEquals("1st Column", charts[0].getSeries()[0].getSeriesTitle());
+               assertEquals("2nd Column", charts[0].getSeries()[1].getSeriesTitle());
+               assertEquals(6, charts[0].getSeries()[0].getNumValues());
+               assertEquals(6, charts[0].getSeries()[1].getNumValues());
+               assertEquals(SeriesRecord.CATEGORY_DATA_TYPE_NUMERIC, charts[0].getSeries()[0].getValueType());
+               assertEquals(SeriesRecord.CATEGORY_DATA_TYPE_NUMERIC, charts[0].getSeries()[1].getValueType());
+               assertNull(charts[0].getChartTitle());
+
+               assertEquals(1, charts[1].getSeries().length);
+               assertNull(charts[1].getSeries()[0].getSeriesTitle());
+               assertEquals("Pie Chart Title Thingy", charts[1].getChartTitle());
+
+               // And the third sheet
+               charts = HSSFChart.getSheetCharts(s3);
+               assertEquals(1, charts.length);
+
+               assertEquals(2, charts[0].getSeries().length);
+               assertEquals("Squares", charts[0].getSeries()[0].getSeriesTitle());
+               assertEquals("Base Numbers", charts[0].getSeries()[1].getSeriesTitle());
+               assertEquals("Sheet 3 Chart with Title", charts[0].getChartTitle());
+       }
+       
+    @Test
+    public void testExistingSheet3() throws Exception {
+        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("49581.xls");
+        
+        HSSFSheet sheet = wb.getSheetAt( 2 ) ;
+        HSSFChart[] charts = HSSFChart.getSheetCharts( sheet ) ;
+        assertEquals(1, charts.length);
+        
+        for ( HSSFChart chart : charts ) {
+            for ( HSSFSeries series : chart.getSeries() ) {
+                chart.removeSeries( series ) ;
+            }
+        }
+        
+        // Save and re-check
+        wb = HSSFITestDataProvider.instance.writeOutAndReadBack(wb);
+        sheet = wb.getSheetAt( 2 ) ;
+        assertEquals(1, HSSFChart.getSheetCharts(sheet).length);
+        
+        HSSFChart c = HSSFChart.getSheetCharts(sheet)[0];
+        assertEquals(0, c.getSeries().length);
+    }
+
+    @Test
+    public void testExistingSheet2() throws Exception {
+        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("49581.xls");
+        HSSFSheet sheet = wb.getSheetAt( 1 ) ;
+        HSSFChart[] charts = HSSFChart.getSheetCharts( sheet ) ;
+        
+        assertEquals(1, charts.length);
+        for ( HSSFChart chart : charts ) {
+            HSSFSeries series ;
+            
+            // Starts with one
+            assertEquals(1, chart.getSeries().length);
+
+            // Add two more
+            series = chart.createSeries() ;
+            series.setCategoryLabelsCellRange( new CellRangeAddress( 3, 4, 0, 0 ) ) ;
+            series.setValuesCellRange( new CellRangeAddress( 3, 4, 1, 1 ) ) ;
+
+            series = chart.createSeries() ;
+            series.setCategoryLabelsCellRange( new CellRangeAddress( 6, 7, 0, 0 ) ) ;
+            series.setValuesCellRange( new CellRangeAddress( 6, 7, 1, 1 ) ) ;
+        }
+        
+        // Save and re-check
+        wb = HSSFITestDataProvider.instance.writeOutAndReadBack(wb);
+        sheet = wb.getSheetAt( 1 ) ;
+        assertEquals(1, HSSFChart.getSheetCharts(sheet).length);
+        
+        HSSFChart c = HSSFChart.getSheetCharts(sheet)[0];
+        assertEquals(3, c.getSeries().length);
+    }
+
+    @Test
+    public void testExistingSheet1() throws Exception {
+       HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("49581.xls");
+        HSSFSheet sheet = wb.getSheetAt( 0 ) ;
+        HSSFChart[] charts = HSSFChart.getSheetCharts( sheet ) ;
+        
+        for ( HSSFChart chart : charts ) {
+            //System.out.println( chart.getType() ) ;
+            HSSFSeries[] seriesArray = chart.getSeries() ;
+            //System.out.println( "seriesArray.length=" + seriesArray.length ) ;
+            for ( HSSFSeries series : seriesArray )
+            {
+                //System.out.println( "serie.getNumValues()=" + series.getNumValues() ) ;
+                CellRangeAddressBase range ;
+
+                range = series.getValuesCellRange() ;
+                //System.out.println( range.toString() ) ;
+                range.setLastRow( range.getLastRow() + 1 ) ;
+                series.setValuesCellRange( range ) ;
+
+                range = series.getCategoryLabelsCellRange() ;
+                //System.out.println( range.toString() ) ;
+                range.setLastRow( range.getLastRow() + 1 ) ;
+                series.setCategoryLabelsCellRange( range ) ;
+            }
+
+            for ( int id = 0 ; id < 2 ; id++ )
+            {
+                HSSFSeries newSeries = chart.createSeries() ;
+                newSeries.setValuesCellRange( new CellRangeAddress( 1 + id, 4, 3, 3 ) ) ;
+                String oldSeriesTitle = newSeries.getSeriesTitle() ;
+                if ( oldSeriesTitle != null )
+                {
+                    //System.out.println( "old series title: " + oldSeriesTitle ) ;
+                    newSeries.setSeriesTitle( "new series" ) ;
+                }
+            }
+        }
+
+        HSSFChart chart = charts[ 2 ] ;
+        chart.removeSeries( chart.getSeries()[ 0 ] ) ;
+    }
+    
+    /**
+     * Bug 26862: HSSFWorkbook.cloneSheet copies charts
+     */
+    @Test
+    public void test26862() throws IOException, Exception {
+        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SimpleChart.xls");
+        HSSFSheet srcSheet = wb.getSheetAt(0);
+        HSSFChart[] srcCharts = HSSFChart.getSheetCharts(srcSheet);
+        assertEquals(1, srcCharts.length);
+        HSSFChart srcChart = srcCharts[0];
+        
+        // Clone the sheet
+        HSSFSheet clonedSheet = wb.cloneSheet(0);
+        
+        // Verify the chart was copied
+        HSSFChart[] clonedCharts = HSSFChart.getSheetCharts(clonedSheet);
+        assertEquals(1, clonedCharts.length);
+        HSSFChart clonedChart = clonedCharts[0];
+        assertNotSame(srcChart, clonedChart); //refer to different objects
+        assertEquals(srcChart.getType(), clonedChart.getType());
+        assertEquals(srcChart.getChartTitle(), clonedChart.getChartTitle());
+        assertEquals(srcChart.getChartWidth(), clonedChart.getChartWidth());
+        assertEquals(srcChart.getChartHeight(), clonedChart.getChartHeight());
+        assertEquals(srcChart.getChartX(), clonedChart.getChartX());
+        assertEquals(srcChart.getChartY(), clonedChart.getChartY());
+        
+        // Check if chart was shallow copied or deep copied
+        clonedChart.setChartWidth(clonedChart.getChartWidth()+10);
+        assertEquals(srcChart.getChartWidth()+10, clonedChart.getChartWidth());
+        
+        wb.close();
+    }
+}
index 8d685fc68df80ad4855db1fcfbfa2ba60ae8fdc7..07f37d8e4acee700e84eaa87894d809ded6f0b2a 100644 (file)
@@ -21,10 +21,10 @@ package org.apache.poi.hssf.usermodel;
 
 import org.apache.poi.hssf.HSSFITestDataProvider;
 import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.ss.usermodel.TestRangeCopier;
+import org.apache.poi.ss.usermodel.BaseTestRangeCopier;
 import org.junit.Before;
 
-public class TestHSSFRangeCopier extends TestRangeCopier {
+public class TestHSSFRangeCopier extends BaseTestRangeCopier {
 
     public TestHSSFRangeCopier() {
         super();
diff --git a/src/testcases/org/apache/poi/sl/TestCommonSL.java b/src/testcases/org/apache/poi/sl/TestCommonSL.java
deleted file mode 100644 (file)
index 2911b12..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-package org.apache.poi.sl;
-
-import java.awt.Color;
-
-import org.apache.poi.sl.draw.DrawPaint;
-import org.apache.poi.sl.usermodel.PaintStyle;
-import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
-import org.junit.Ignore;
-
-/**
- * Currently only contains helper methods
- */
-@Ignore
-public class TestCommonSL {
-
-    public static Color getColor(PaintStyle paintActual) {
-        return (paintActual instanceof SolidPaint)
-            ? DrawPaint.applyColorTransform(((SolidPaint)paintActual).getSolidColor())
-            : null;
-    }
-
-}
diff --git a/src/testcases/org/apache/poi/sl/draw/geom/TestFormulaParser.java b/src/testcases/org/apache/poi/sl/draw/geom/TestFormulaParser.java
new file mode 100644 (file)
index 0000000..0d82c2a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  ====================================================================
+ *    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.sl.draw.geom;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+/**
+ * Date: 10/24/11
+ *
+ * @author Yegor Kozlov
+ */
+public class TestFormulaParser {
+    @Test
+    public void testParse(){
+
+        Formula[] ops = {
+            newGuide("adj1", "val 100"),
+            newGuide("adj2", "val 200"),
+            newGuide("adj3", "val -1"),
+            newGuide("a1", "*/ adj1 2 adj2"), // a1 = 100*2 / 200
+            newGuide("a2", "+- adj2 a1 adj1"), // a2 = 200 + a1 - 100
+            newGuide("a3", "+/ adj1 adj2 adj2"), // a3 = (100 + 200) / 200
+            newGuide("a4", "?: adj3 adj1 adj2"), // a4 = adj3 > 0 ? adj1 : adj2
+            newGuide("a5", "abs -2"),
+        };
+
+        CustomGeometry geom = new CustomGeometry();
+        Context ctx = new Context(geom, null, null);
+        for(Formula fmla : ops) {
+            ctx.evaluate(fmla);
+        }
+
+        assertEquals(100.0, ctx.getValue("adj1"), 0.0);
+        assertEquals(200.0, ctx.getValue("adj2"), 0.0);
+        assertEquals(1.0, ctx.getValue("a1"), 0.0);
+        assertEquals(101.0, ctx.getValue("a2"), 0.0);
+        assertEquals(1.5, ctx.getValue("a3"), 0.0);
+        assertEquals(200.0, ctx.getValue("a4"), 0.0);
+        assertEquals(2.0, ctx.getValue("a5"), 0.0);
+    }
+
+    private static Guide newGuide(String name, String fmla) {
+        Guide gd = new Guide();
+        gd.setName(name);
+        gd.setFmla(fmla);
+        return gd;
+    }
+}
index c12c96559fb73ad30dc3b431d6b7f19cf376827c..5d53b4bd6253f02ebe0022f3f58d4cfffc7022b5 100644 (file)
@@ -31,6 +31,7 @@ import java.util.List;
 
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.common.usermodel.fonts.FontInfo;
+import org.apache.poi.sl.draw.DrawPaint;
 import org.apache.poi.sl.usermodel.PictureData.PictureType;
 import org.apache.poi.sl.usermodel.TabStop.TabStopType;
 import org.junit.Test;
@@ -40,24 +41,24 @@ public abstract class BaseTestSlideShow<
         P extends TextParagraph<S,P,? extends TextRun>
 > {
     protected static final POIDataSamples slTests = POIDataSamples.getSlideShowInstance();
-    
+
     public abstract SlideShow<S,P> createSlideShow();
 
     public abstract SlideShow<S,P> reopen(SlideShow<S,P> show);
-    
+
     @Test
     public void addPicture_File() throws IOException {
         SlideShow<S,P> show = createSlideShow();
         File f = slTests.getFile("clock.jpg");
-        
+
         assertEquals(0, show.getPictureData().size());
         PictureData picture = show.addPicture(f, PictureType.JPEG);
         assertEquals(1, show.getPictureData().size());
         assertSame(picture, show.getPictureData().get(0));
-        
+
         show.close();
     }
-    
+
     @Test
     public void addPicture_Stream() throws IOException {
         try (SlideShow<S,P> show = createSlideShow();
@@ -68,34 +69,34 @@ public abstract class BaseTestSlideShow<
             assertSame(picture, show.getPictureData().get(0));
         }
     }
-    
+
     @Test
     public void addPicture_ByteArray() throws IOException {
         SlideShow<S,P> show = createSlideShow();
         byte[] data = slTests.readFile("clock.jpg");
-        
+
         assertEquals(0, show.getPictureData().size());
         PictureData picture = show.addPicture(data, PictureType.JPEG);
         assertEquals(1, show.getPictureData().size());
         assertSame(picture, show.getPictureData().get(0));
-        
+
         show.close();
     }
-    
+
     @Test
     public void findPicture() throws IOException {
         SlideShow<S,P> show = createSlideShow();
         byte[] data = slTests.readFile("clock.jpg");
-        
+
         assertNull(show.findPictureData(data));
         PictureData picture = show.addPicture(data, PictureType.JPEG);
         PictureData found = show.findPictureData(data);
         assertNotNull(found);
         assertEquals(picture, found);
-        
+
         show.close();
     }
-    
+
     @Test
     public void addTabStops() throws IOException {
         try (final SlideShow<S,P> show1 = createSlideShow()) {
@@ -109,7 +110,7 @@ public abstract class BaseTestSlideShow<
                 master1_tp.addTabStops(10+i1*10, tst);
                 i1++;
             }
-            
+
             // then set it on a normal slide
             final Slide<S,P> slide1 = show1.createSlide();
             final AutoShape<S,P> slide1_as = slide1.createAutoShape();
@@ -123,7 +124,7 @@ public abstract class BaseTestSlideShow<
                 slide1_tp.addTabStops(15+i2*5, tst);
                 i2++;
             }
-            
+
             try (final SlideShow<S,P> show2 = reopen(show1)) {
                 final MasterSheet<S,P> master2 = show2.getSlideMasters().get(0);
                 final AutoShape<S,P> master2_as = (AutoShape<S,P>)master2.getPlaceholder(Placeholder.BODY);
@@ -137,8 +138,8 @@ public abstract class BaseTestSlideShow<
                     assertEquals(tst, ts.getType());
                     i3++;
                 }
-                
-                
+
+
                 final Slide<S,P> slide2 = show2.getSlides().get(0);
                 @SuppressWarnings("unchecked")
                 final AutoShape<S,P> slide2_as = (AutoShape<S,P>)slide2.getShapes().get(0);
@@ -153,7 +154,7 @@ public abstract class BaseTestSlideShow<
                     i4++;
                 }
             }
-        }        
+        }
     }
 
     @Test
@@ -191,4 +192,11 @@ public abstract class BaseTestSlideShow<
             }
         }
     }
+
+    public static Color getColor(PaintStyle paintActual) {
+        return (paintActual instanceof PaintStyle.SolidPaint)
+                ? DrawPaint.applyColorTransform(((PaintStyle.SolidPaint)paintActual).getSolidColor())
+                : null;
+    }
+
 }
index 8234a93e4a4ad4d204b27a58a51ec6e9e6ba708f..fa24171b9e8386d0e96498a2fbb260e83de683b6 100644 (file)
@@ -16,7 +16,9 @@
 ==================================================================== */
 package org.apache.poi.ss.format;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.text.ParseException;
@@ -24,10 +26,12 @@ import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Locale;
 import java.util.TimeZone;
+import java.util.stream.Stream;
 
 import javax.swing.JLabel;
 
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.DateUtil;
 import org.apache.poi.ss.usermodel.Row;
@@ -35,6 +39,7 @@ import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.util.LocaleUtil;
 import org.junit.AfterClass;
+import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -1013,4 +1018,12 @@ public class TestCellFormat {
         CellFormat cf = CellFormat.getInstance("\"ca. \"0");
         assertEquals("ca. 5", cf.apply((double) 5).text);
     }
+
+    @Test
+    public void testNamedColors() {
+        assertTrue(CellFormatPart.NAMED_COLORS.size() >= HSSFColor.HSSFColorPredefined.values().length);
+        Stream.of("GREEN", "Green", "RED", "Red", "BLUE", "Blue", "YELLOW", "Yellow")
+                .map(CellFormatPart.NAMED_COLORS::get)
+                .forEach(Assert::assertNotNull);
+    }
 }
index 59631017d2fef16d0e38e34314e5c832521a882a..14427df5d43c8d7373ac48b23504dfd9f66597f0 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.apache.poi.ss.formula;
 
-import org.apache.poi.ss.formula.eval.forked.TestForkedEvaluator;
+import org.apache.poi.ss.formula.eval.forked.BaseTestForkedEvaluator;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
 
@@ -29,7 +29,7 @@ import org.junit.runners.Suite;
     TestCellCacheEntry.class,
     TestEvaluationCache.class,
     TestWorkbookEvaluator.class,
-    TestForkedEvaluator.class
+    BaseTestForkedEvaluator.class
 })
 public class AllSSFormulaTests {
 }
diff --git a/src/testcases/org/apache/poi/ss/formula/BaseTestMissingWorkbook.java b/src/testcases/org/apache/poi/ss/formula/BaseTestMissingWorkbook.java
new file mode 100644 (file)
index 0000000..9cb755c
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ *  ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one or more
+ *    contributor license agreements.  See the NOTICE file distributed with
+ *    this work for additional information regarding copyright ownership.
+ *    The ASF licenses this file to You under the Apache License, Version 2.0
+ *    (the "License"); you may not use this file except in compliance with
+ *    the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.ss.formula;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class BaseTestMissingWorkbook {
+    protected Workbook mainWorkbook;
+    protected Workbook sourceWorkbook;
+
+    protected final String MAIN_WORKBOOK_FILENAME;
+    protected final String SOURCE_DUMMY_WORKBOOK_FILENAME;
+    protected final String SOURCE_WORKBOOK_FILENAME;
+
+    public BaseTestMissingWorkbook() {
+        this("52575_main.xls", "source_dummy.xls", "52575_source.xls");
+    }
+
+    protected BaseTestMissingWorkbook(String MAIN_WORKBOOK_FILENAME,
+                                                                         String SOURCE_DUMMY_WORKBOOK_FILENAME, String SOURCE_WORKBOOK_FILENAME) {
+        this.MAIN_WORKBOOK_FILENAME = MAIN_WORKBOOK_FILENAME;
+        this.SOURCE_DUMMY_WORKBOOK_FILENAME = SOURCE_DUMMY_WORKBOOK_FILENAME;
+        this.SOURCE_WORKBOOK_FILENAME = SOURCE_WORKBOOK_FILENAME;
+    }
+
+       @Before
+       public void setUp() throws Exception {
+               mainWorkbook = HSSFTestDataSamples.openSampleWorkbook(MAIN_WORKBOOK_FILENAME);
+               sourceWorkbook = HSSFTestDataSamples.openSampleWorkbook(SOURCE_WORKBOOK_FILENAME);
+
+               assertNotNull(mainWorkbook);
+               assertNotNull(sourceWorkbook);
+       }
+
+       @After
+       public void tearDown() throws Exception {
+               if(mainWorkbook != null) {
+                       mainWorkbook.close();
+               }
+
+               if(sourceWorkbook != null) {
+                       sourceWorkbook.close();
+               }
+       }
+
+       @Test
+       public void testMissingWorkbookMissing() {
+               FormulaEvaluator evaluator = mainWorkbook.getCreationHelper().createFormulaEvaluator();
+
+               Sheet lSheet = mainWorkbook.getSheetAt(0);
+               Row lARow = lSheet.getRow(0);
+               Cell lA1Cell = lARow.getCell(0);
+
+               assertEquals(CellType.FORMULA, lA1Cell.getCellType());
+               try {
+                       evaluator.evaluateFormulaCell(lA1Cell);
+                       fail("Missing external workbook reference exception expected!");
+               } catch(RuntimeException re) {
+                       assertTrue("Unexpected exception: " + re, re.getMessage().contains(SOURCE_DUMMY_WORKBOOK_FILENAME));
+               }
+       }
+
+       @Test
+       public void testMissingWorkbookMissingOverride() {
+               Sheet lSheet = mainWorkbook.getSheetAt(0);
+               Cell lA1Cell = lSheet.getRow(0).getCell(0);
+               Cell lB1Cell = lSheet.getRow(1).getCell(0);
+               Cell lC1Cell = lSheet.getRow(2).getCell(0);
+
+               assertEquals(CellType.FORMULA, lA1Cell.getCellType());
+               assertEquals(CellType.FORMULA, lB1Cell.getCellType());
+               assertEquals(CellType.FORMULA, lC1Cell.getCellType());
+
+               // Check cached values
+        assertEquals(10.0d, lA1Cell.getNumericCellValue(), 0.00001d);
+        assertEquals("POI rocks!", lB1Cell.getStringCellValue());
+               assertTrue(lC1Cell.getBooleanCellValue());
+
+        // Evaluate
+               FormulaEvaluator evaluator = mainWorkbook.getCreationHelper().createFormulaEvaluator();
+        evaluator.setIgnoreMissingWorkbooks(true);
+
+               assertEquals(CellType.NUMERIC, evaluator.evaluateFormulaCell(lA1Cell));
+               assertEquals(CellType.STRING,  evaluator.evaluateFormulaCell(lB1Cell));
+               assertEquals(CellType.BOOLEAN, evaluator.evaluateFormulaCell(lC1Cell));
+
+               assertEquals(10.0d, lA1Cell.getNumericCellValue(), 0.00001d);
+               assertEquals("POI rocks!", lB1Cell.getStringCellValue());
+               assertTrue(lC1Cell.getBooleanCellValue());
+       }
+
+       @Test
+       public void testExistingWorkbook() {
+               Sheet lSheet = mainWorkbook.getSheetAt(0);
+               Cell lA1Cell = lSheet.getRow(0).getCell(0);
+               Cell lB1Cell = lSheet.getRow(1).getCell(0);
+               Cell lC1Cell = lSheet.getRow(2).getCell(0);
+
+               assertEquals(CellType.FORMULA, lA1Cell.getCellType());
+               assertEquals(CellType.FORMULA, lB1Cell.getCellType());
+               assertEquals(CellType.FORMULA, lC1Cell.getCellType());
+
+               FormulaEvaluator lMainWorkbookEvaluator = mainWorkbook.getCreationHelper().createFormulaEvaluator();
+               FormulaEvaluator lSourceEvaluator = sourceWorkbook.getCreationHelper().createFormulaEvaluator();
+               Map<String,FormulaEvaluator> workbooks = new HashMap<>();
+               workbooks.put(MAIN_WORKBOOK_FILENAME, lMainWorkbookEvaluator);
+               workbooks.put(SOURCE_DUMMY_WORKBOOK_FILENAME, lSourceEvaluator);
+               lMainWorkbookEvaluator.setupReferencedWorkbooks(workbooks);
+
+               assertEquals(CellType.NUMERIC, lMainWorkbookEvaluator.evaluateFormulaCell(lA1Cell));
+               assertEquals(CellType.STRING, lMainWorkbookEvaluator.evaluateFormulaCell(lB1Cell));
+               assertEquals(CellType.BOOLEAN, lMainWorkbookEvaluator.evaluateFormulaCell(lC1Cell));
+
+               assertEquals(20.0d, lA1Cell.getNumericCellValue(), 0.00001d);
+               assertEquals("Apache rocks!", lB1Cell.getStringCellValue());
+               assertFalse(lC1Cell.getBooleanCellValue());
+       }
+}
diff --git a/src/testcases/org/apache/poi/ss/formula/TestMissingWorkbook.java b/src/testcases/org/apache/poi/ss/formula/TestMissingWorkbook.java
deleted file mode 100644 (file)
index 1093e54..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.ss.formula;
-
-import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-public class TestMissingWorkbook {
-    protected Workbook mainWorkbook;
-    protected Workbook sourceWorkbook;
-    
-    protected final String MAIN_WORKBOOK_FILENAME;
-    protected final String SOURCE_DUMMY_WORKBOOK_FILENAME;
-    protected final String SOURCE_WORKBOOK_FILENAME;
-    
-    public TestMissingWorkbook() {
-        this("52575_main.xls", "source_dummy.xls", "52575_source.xls");
-    }
-
-    protected TestMissingWorkbook(String MAIN_WORKBOOK_FILENAME, 
-            String SOURCE_DUMMY_WORKBOOK_FILENAME, String SOURCE_WORKBOOK_FILENAME) {
-        this.MAIN_WORKBOOK_FILENAME = MAIN_WORKBOOK_FILENAME; 
-        this.SOURCE_DUMMY_WORKBOOK_FILENAME = SOURCE_DUMMY_WORKBOOK_FILENAME;
-        this.SOURCE_WORKBOOK_FILENAME = SOURCE_WORKBOOK_FILENAME;
-    }
-       
-       @Before
-       public void setUp() throws Exception {
-               mainWorkbook = HSSFTestDataSamples.openSampleWorkbook(MAIN_WORKBOOK_FILENAME);
-               sourceWorkbook = HSSFTestDataSamples.openSampleWorkbook(SOURCE_WORKBOOK_FILENAME);
-               
-               assertNotNull(mainWorkbook);
-               assertNotNull(sourceWorkbook);
-       }
-
-       @After
-       public void tearDown() throws Exception {
-               if(mainWorkbook != null) {
-                       mainWorkbook.close();
-               }
-
-               if(sourceWorkbook != null) {
-                       sourceWorkbook.close();
-               }
-       }
-
-       @Test
-       public void testMissingWorkbookMissing() {
-               FormulaEvaluator evaluator = mainWorkbook.getCreationHelper().createFormulaEvaluator();
-               
-               Sheet lSheet = mainWorkbook.getSheetAt(0);
-               Row lARow = lSheet.getRow(0);
-               Cell lA1Cell = lARow.getCell(0);
-               
-               assertEquals(CellType.FORMULA, lA1Cell.getCellType());
-               try {
-                       evaluator.evaluateFormulaCell(lA1Cell);
-                       fail("Missing external workbook reference exception expected!");
-               } catch(RuntimeException re) {
-                       assertTrue("Unexpected exception: " + re, re.getMessage().contains(SOURCE_DUMMY_WORKBOOK_FILENAME));
-               }
-       }
-
-       @Test
-       public void testMissingWorkbookMissingOverride() {
-               Sheet lSheet = mainWorkbook.getSheetAt(0);
-               Cell lA1Cell = lSheet.getRow(0).getCell(0);
-               Cell lB1Cell = lSheet.getRow(1).getCell(0);
-               Cell lC1Cell = lSheet.getRow(2).getCell(0);
-               
-               assertEquals(CellType.FORMULA, lA1Cell.getCellType());
-               assertEquals(CellType.FORMULA, lB1Cell.getCellType());
-               assertEquals(CellType.FORMULA, lC1Cell.getCellType());
-
-               // Check cached values
-        assertEquals(10.0d, lA1Cell.getNumericCellValue(), 0.00001d);
-        assertEquals("POI rocks!", lB1Cell.getStringCellValue());
-               assertTrue(lC1Cell.getBooleanCellValue());
-               
-        // Evaluate
-               FormulaEvaluator evaluator = mainWorkbook.getCreationHelper().createFormulaEvaluator();
-        evaluator.setIgnoreMissingWorkbooks(true);
-
-               assertEquals(CellType.NUMERIC, evaluator.evaluateFormulaCell(lA1Cell));
-               assertEquals(CellType.STRING,  evaluator.evaluateFormulaCell(lB1Cell));
-               assertEquals(CellType.BOOLEAN, evaluator.evaluateFormulaCell(lC1Cell));
-
-               assertEquals(10.0d, lA1Cell.getNumericCellValue(), 0.00001d);
-               assertEquals("POI rocks!", lB1Cell.getStringCellValue());
-               assertTrue(lC1Cell.getBooleanCellValue());
-       }
-
-       @Test
-       public void testExistingWorkbook() {
-               Sheet lSheet = mainWorkbook.getSheetAt(0);
-               Cell lA1Cell = lSheet.getRow(0).getCell(0);
-               Cell lB1Cell = lSheet.getRow(1).getCell(0);
-               Cell lC1Cell = lSheet.getRow(2).getCell(0);
-               
-               assertEquals(CellType.FORMULA, lA1Cell.getCellType());
-               assertEquals(CellType.FORMULA, lB1Cell.getCellType());
-               assertEquals(CellType.FORMULA, lC1Cell.getCellType());
-
-               FormulaEvaluator lMainWorkbookEvaluator = mainWorkbook.getCreationHelper().createFormulaEvaluator();
-               FormulaEvaluator lSourceEvaluator = sourceWorkbook.getCreationHelper().createFormulaEvaluator();
-               Map<String,FormulaEvaluator> workbooks = new HashMap<>();
-               workbooks.put(MAIN_WORKBOOK_FILENAME, lMainWorkbookEvaluator);
-               workbooks.put(SOURCE_DUMMY_WORKBOOK_FILENAME, lSourceEvaluator);
-               lMainWorkbookEvaluator.setupReferencedWorkbooks(workbooks);
-               
-               assertEquals(CellType.NUMERIC, lMainWorkbookEvaluator.evaluateFormulaCell(lA1Cell));
-               assertEquals(CellType.STRING, lMainWorkbookEvaluator.evaluateFormulaCell(lB1Cell));
-               assertEquals(CellType.BOOLEAN, lMainWorkbookEvaluator.evaluateFormulaCell(lC1Cell));
-
-               assertEquals(20.0d, lA1Cell.getNumericCellValue(), 0.00001d);
-               assertEquals("Apache rocks!", lB1Cell.getStringCellValue());
-               assertFalse(lC1Cell.getBooleanCellValue());
-       }
-}
diff --git a/src/testcases/org/apache/poi/ss/formula/eval/forked/BaseTestForkedEvaluator.java b/src/testcases/org/apache/poi/ss/formula/eval/forked/BaseTestForkedEvaluator.java
new file mode 100644 (file)
index 0000000..578452f
--- /dev/null
@@ -0,0 +1,120 @@
+/* ====================================================================
+   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.ss.formula.eval.forked;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.IStabilityClassifier;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class BaseTestForkedEvaluator {
+
+    @Rule
+    public ExpectedException expectedEx = ExpectedException.none();
+
+    protected Workbook newWorkbook() {
+        return new HSSFWorkbook();
+    }
+
+       /**
+        * set up a calculation workbook with input cells nicely segregated on a
+        * sheet called "Inputs"
+        */
+       protected Workbook createWorkbook() {
+               Workbook wb = newWorkbook();
+               Sheet sheet1 = wb.createSheet("Inputs");
+               Sheet sheet2 = wb.createSheet("Calculations");
+               Row row;
+               row = sheet2.createRow(0);
+               row.createCell(0).setCellFormula("B1*Inputs!A1-Inputs!B1");
+               row.createCell(1).setCellValue(5.0); // Calculations!B1
+
+               // some default input values
+               row = sheet1.createRow(0);
+               row.createCell(0).setCellValue(2.0); // Inputs!A1
+               row.createCell(1).setCellValue(3.0); // Inputs!B1
+               return wb;
+       }
+
+       /**
+        * Shows a basic use-case for {@link ForkedEvaluator}
+        */
+       @Test
+       public void testBasic() throws IOException {
+               Workbook wb = createWorkbook();
+
+               // The stability classifier is useful to reduce memory consumption of caching logic
+               IStabilityClassifier stabilityClassifier = (sheetIndex, rowIndex, columnIndex) -> sheetIndex == 1;
+
+               ForkedEvaluator fe1 = ForkedEvaluator.create(wb, stabilityClassifier, null);
+               ForkedEvaluator fe2 = ForkedEvaluator.create(wb, stabilityClassifier, null);
+
+               // fe1 and fe2 can be used concurrently on separate threads
+
+               fe1.updateCell("Inputs", 0, 0, new NumberEval(4.0));
+               fe1.updateCell("Inputs", 0, 1, new NumberEval(1.1));
+
+               fe2.updateCell("Inputs", 0, 0, new NumberEval(1.2));
+               fe2.updateCell("Inputs", 0, 1, new NumberEval(2.0));
+
+               NumberEval eval1 = (NumberEval) fe1.evaluate("Calculations", 0, 0);
+               assertNotNull(eval1);
+               assertEquals(18.9, eval1.getNumberValue(), 0.0);
+               NumberEval eval2 = (NumberEval) fe2.evaluate("Calculations", 0, 0);
+               assertNotNull(eval2);
+               assertEquals(4.0, eval2.getNumberValue(), 0.0);
+               fe1.updateCell("Inputs", 0, 0, new NumberEval(3.0));
+               eval1 = (NumberEval) fe1.evaluate("Calculations", 0, 0);
+               assertNotNull(eval1);
+               assertEquals(13.9, eval1.getNumberValue(), 0.0);
+
+               wb.close();
+       }
+
+       /**
+        * As of Sep 2009, the Forked evaluator can update values from existing cells (this is because
+        * the underlying 'master' cell is used as a key into the calculation cache.  Prior to the fix
+        * for this bug, an attempt to update a missing cell would result in NPE.  This junit tests for
+        * a more meaningful error message.<br>
+        *
+        * An alternate solution might involve allowing empty cells to be created as necessary.  That
+        * was considered less desirable because so far, the underlying 'master' workbook is strictly
+        * <i>read-only</i> with respect to the ForkedEvaluator.
+        */
+       @Test
+       public void testMissingInputCellH() throws IOException {
+           expectedEx.expect(UnsupportedOperationException.class);
+           expectedEx.expectMessage("Underlying cell 'A2' is missing in master sheet.");
+
+               try (Workbook wb = createWorkbook()) {
+                       ForkedEvaluator fe = ForkedEvaluator.create(wb, null, null);
+                       // attempt update input at cell A2 (which is missing)
+                       fe.updateCell("Inputs", 1, 0, new NumberEval(4.0));
+               }
+       }
+}
diff --git a/src/testcases/org/apache/poi/ss/formula/eval/forked/TestForkedEvaluator.java b/src/testcases/org/apache/poi/ss/formula/eval/forked/TestForkedEvaluator.java
deleted file mode 100644 (file)
index e27499c..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.formula.eval.forked;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.io.IOException;
-
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.formula.IStabilityClassifier;
-import org.apache.poi.ss.formula.eval.NumberEval;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-public class TestForkedEvaluator {
-    
-    @Rule
-    public ExpectedException expectedEx = ExpectedException.none();
-    
-    protected Workbook newWorkbook() {
-        return new HSSFWorkbook();
-    }
-    
-       /**
-        * set up a calculation workbook with input cells nicely segregated on a
-        * sheet called "Inputs"
-        */
-       protected Workbook createWorkbook() {
-               Workbook wb = newWorkbook();
-               Sheet sheet1 = wb.createSheet("Inputs");
-               Sheet sheet2 = wb.createSheet("Calculations");
-               Row row;
-               row = sheet2.createRow(0);
-               row.createCell(0).setCellFormula("B1*Inputs!A1-Inputs!B1");
-               row.createCell(1).setCellValue(5.0); // Calculations!B1
-
-               // some default input values
-               row = sheet1.createRow(0);
-               row.createCell(0).setCellValue(2.0); // Inputs!A1
-               row.createCell(1).setCellValue(3.0); // Inputs!B1
-               return wb;
-       }
-
-       /**
-        * Shows a basic use-case for {@link ForkedEvaluator}
-        */
-       @Test
-       public void testBasic() throws IOException {
-               Workbook wb = createWorkbook();
-
-               // The stability classifier is useful to reduce memory consumption of caching logic
-               IStabilityClassifier stabilityClassifier = (sheetIndex, rowIndex, columnIndex) -> sheetIndex == 1;
-
-               ForkedEvaluator fe1 = ForkedEvaluator.create(wb, stabilityClassifier, null);
-               ForkedEvaluator fe2 = ForkedEvaluator.create(wb, stabilityClassifier, null);
-
-               // fe1 and fe2 can be used concurrently on separate threads
-
-               fe1.updateCell("Inputs", 0, 0, new NumberEval(4.0));
-               fe1.updateCell("Inputs", 0, 1, new NumberEval(1.1));
-
-               fe2.updateCell("Inputs", 0, 0, new NumberEval(1.2));
-               fe2.updateCell("Inputs", 0, 1, new NumberEval(2.0));
-
-               NumberEval eval1 = (NumberEval) fe1.evaluate("Calculations", 0, 0);
-               assertNotNull(eval1);
-               assertEquals(18.9, eval1.getNumberValue(), 0.0);
-               NumberEval eval2 = (NumberEval) fe2.evaluate("Calculations", 0, 0);
-               assertNotNull(eval2);
-               assertEquals(4.0, eval2.getNumberValue(), 0.0);
-               fe1.updateCell("Inputs", 0, 0, new NumberEval(3.0));
-               eval1 = (NumberEval) fe1.evaluate("Calculations", 0, 0);
-               assertNotNull(eval1);
-               assertEquals(13.9, eval1.getNumberValue(), 0.0);
-               
-               wb.close();
-       }
-
-       /**
-        * As of Sep 2009, the Forked evaluator can update values from existing cells (this is because
-        * the underlying 'master' cell is used as a key into the calculation cache.  Prior to the fix
-        * for this bug, an attempt to update a missing cell would result in NPE.  This junit tests for
-        * a more meaningful error message.<br>
-        *
-        * An alternate solution might involve allowing empty cells to be created as necessary.  That
-        * was considered less desirable because so far, the underlying 'master' workbook is strictly
-        * <i>read-only</i> with respect to the ForkedEvaluator.
-        */
-       @Test
-       public void testMissingInputCellH() throws IOException {
-           expectedEx.expect(UnsupportedOperationException.class);
-           expectedEx.expectMessage("Underlying cell 'A2' is missing in master sheet.");
-
-               try (Workbook wb = createWorkbook()) {
-                       ForkedEvaluator fe = ForkedEvaluator.create(wb, null, null);
-                       // attempt update input at cell A2 (which is missing)
-                       fe.updateCell("Inputs", 1, 0, new NumberEval(4.0));
-               }
-       }
-}
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/AbstractNumericTestCase.java b/src/testcases/org/apache/poi/ss/formula/functions/AbstractNumericTestCase.java
deleted file mode 100644 (file)
index 7d0fd5e..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 29, 2005
- *
- */
-package org.apache.poi.ss.formula.functions;
-
-import static org.junit.Assert.assertTrue;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public abstract class AbstractNumericTestCase {
-
-    public static final double POS_ZERO = 1E-4;
-    public static final double DIFF_TOLERANCE_FACTOR = 1E-8;
-
-    /**
-     * Why doesnt JUnit have a method like this for doubles?
-     * The current impl (3.8.1) of Junit has a retar*** method
-     * for comparing doubles. DO NOT use that.
-     * TODO: This class should really be in an abstract super class
-     * to avoid code duplication across this project.
-     * @param message
-     * @param baseval
-     * @param checkval
-     */
-    public static void assertEquals(String message, double baseval, double checkval, double almostZero, double diffToleranceFactor) {
-        double posZero = Math.abs(almostZero);
-        double negZero = -1 * posZero;
-        if (Double.isNaN(baseval)) {
-            assertTrue(message+": Expected " + baseval + " but was " + checkval
-                    , Double.isNaN(baseval));
-        }
-        else if (Double.isInfinite(baseval)) {
-            assertTrue(message+": Expected " + baseval + " but was " + checkval
-                    , Double.isInfinite(baseval) && ((baseval<0) == (checkval<0)));
-        }
-        else {
-            assertTrue(message+": Expected " + baseval + " but was " + checkval
-                ,baseval != 0
-                    ? Math.abs(baseval - checkval) <= Math.abs(diffToleranceFactor * baseval)
-                    : checkval < posZero && checkval > negZero);
-        }
-    }
-
-    public static void assertEquals(String msg, double baseval, double checkval) {
-        assertEquals(msg, baseval, checkval, POS_ZERO, DIFF_TOLERANCE_FACTOR);
-    }
-
-
-    public static void assertEquals(double baseval, double checkval) {
-        assertEquals("", baseval, checkval, POS_ZERO, DIFF_TOLERANCE_FACTOR);
-    }
-}
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/BaseTestNumeric.java b/src/testcases/org/apache/poi/ss/formula/functions/BaseTestNumeric.java
new file mode 100644 (file)
index 0000000..ea1055c
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Created on May 29, 2005
+ *
+ */
+package org.apache.poi.ss.formula.functions;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
+ *
+ */
+public abstract class BaseTestNumeric {
+
+    public static final double POS_ZERO = 1E-4;
+    public static final double DIFF_TOLERANCE_FACTOR = 1E-8;
+
+    /**
+     * Why doesnt JUnit have a method like this for doubles?
+     * The current impl (3.8.1) of Junit has a retar*** method
+     * for comparing doubles. DO NOT use that.
+     * TODO: This class should really be in an abstract super class
+     * to avoid code duplication across this project.
+     * @param message
+     * @param baseval
+     * @param checkval
+     */
+    public static void assertEquals(String message, double baseval, double checkval, double almostZero, double diffToleranceFactor) {
+        double posZero = Math.abs(almostZero);
+        double negZero = -1 * posZero;
+        if (Double.isNaN(baseval)) {
+            assertTrue(message+": Expected " + baseval + " but was " + checkval
+                    , Double.isNaN(baseval));
+        }
+        else if (Double.isInfinite(baseval)) {
+            assertTrue(message+": Expected " + baseval + " but was " + checkval
+                    , Double.isInfinite(baseval) && ((baseval<0) == (checkval<0)));
+        }
+        else {
+            assertTrue(message+": Expected " + baseval + " but was " + checkval
+                ,baseval != 0
+                    ? Math.abs(baseval - checkval) <= Math.abs(diffToleranceFactor * baseval)
+                    : checkval < posZero && checkval > negZero);
+        }
+    }
+
+    public static void assertEquals(String msg, double baseval, double checkval) {
+        assertEquals(msg, baseval, checkval, POS_ZERO, DIFF_TOLERANCE_FACTOR);
+    }
+
+
+    public static void assertEquals(double baseval, double checkval) {
+        assertEquals("", baseval, checkval, POS_ZERO, DIFF_TOLERANCE_FACTOR);
+    }
+}
index 212c8acc62564ca624be2ff0654083869da9311f..2e08083ca2dde7388d371d05cd4dbc9103ce651c 100644 (file)
@@ -27,7 +27,7 @@ import org.junit.Test;
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  *
  */
-public class TestFinanceLib extends AbstractNumericTestCase {
+public class TestFinanceLib extends BaseTestNumeric {
 
     @Test
     public void testFv() {
index 43a7d48cc90f040f53cf421df7199a10fbbbee2f..22506bd00ecef044a2520698c559a11c6539a8e1 100644 (file)
@@ -30,7 +30,7 @@ import org.junit.Test;
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  *
  */
-public class TestMathX extends AbstractNumericTestCase {
+public class TestMathX extends BaseTestNumeric {
 
     @Test
     public void testAcosh() {
index b489cdcb4b24ddd87f3cca3de1166969f0428636..bb8b8e62bb42274f1e5e43c3ec49f40cbc62056f 100644 (file)
@@ -29,7 +29,7 @@ import org.junit.Ignore;
 import org.junit.Test;
 
 
-public class TestStatsLib extends AbstractNumericTestCase {
+public class TestStatsLib extends BaseTestNumeric {
 
     @Test
     public void testDevsq() {
index b11fd45ad2a0669edcdd19765f4820c91f9c669e..a501435616429cd7c0d4ed72ffa317bbc501b8c0 100644 (file)
@@ -29,7 +29,7 @@ import org.junit.Test;
  *
  * @author Stephen Wolke (smwolke at geistig.com)
  */
-public final class TestTrunc extends AbstractNumericTestCase {
+public final class TestTrunc extends BaseTestNumeric {
        private static final NumericFunction F = null;
 
        @Test
diff --git a/src/testcases/org/apache/poi/ss/formula/ptg/AbstractPtgTestCase.java b/src/testcases/org/apache/poi/ss/formula/ptg/AbstractPtgTestCase.java
deleted file mode 100644 (file)
index d03a4e2..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.ss.formula.ptg;
-
-import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-
-/**
- * Convenient abstract class to reduce the amount of boilerplate code needed
- * in ptg-related unit tests.
- */
-public abstract class AbstractPtgTestCase {
-
-    /**
-     * Loads a workbook from the given filename in the test data dir.
-     *
-     * @param sampleFileName the filename.
-     * @return the loaded workbook.
-     */
-    protected static HSSFWorkbook loadWorkbook(String sampleFileName) {
-        return HSSFTestDataSamples.openSampleWorkbook(sampleFileName);
-    }
-
-    /**
-     * Creates a new Workbook and adds one sheet with the specified name
-     */
-    protected static HSSFWorkbook createWorkbookWithSheet(String sheetName) {
-        HSSFWorkbook book = new HSSFWorkbook();
-        book.createSheet(sheetName);
-        return book;
-    }
-}
diff --git a/src/testcases/org/apache/poi/ss/formula/ptg/BaseTestPtg.java b/src/testcases/org/apache/poi/ss/formula/ptg/BaseTestPtg.java
new file mode 100644 (file)
index 0000000..8e566bf
--- /dev/null
@@ -0,0 +1,47 @@
+/* ====================================================================
+   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.ss.formula.ptg;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Convenient abstract class to reduce the amount of boilerplate code needed
+ * in ptg-related unit tests.
+ */
+public abstract class BaseTestPtg {
+
+    /**
+     * Loads a workbook from the given filename in the test data dir.
+     *
+     * @param sampleFileName the filename.
+     * @return the loaded workbook.
+     */
+    protected static HSSFWorkbook loadWorkbook(String sampleFileName) {
+        return HSSFTestDataSamples.openSampleWorkbook(sampleFileName);
+    }
+
+    /**
+     * Creates a new Workbook and adds one sheet with the specified name
+     */
+    protected static HSSFWorkbook createWorkbookWithSheet(String sheetName) {
+        HSSFWorkbook book = new HSSFWorkbook();
+        book.createSheet(sheetName);
+        return book;
+    }
+}
index c06f7f7b35258a918b89106f43b80d3802f6f278..481d7c50519c8ef6776b9fbaf506bd6f3a8d97db 100644 (file)
@@ -28,7 +28,7 @@ import org.junit.Test;
 /**
  * Tests for Area3DPtg
  */
-public final class TestArea3DPtg extends AbstractPtgTestCase {
+public final class TestArea3DPtg extends BaseTestPtg {
 
        /**
         * confirms that sheet names get properly escaped
index 028ed03d3f8ece89798ce7be18df10cfce224758..3d04da1db56cf194ef359b6e485c1560e86ba221 100644 (file)
@@ -27,7 +27,7 @@ import org.junit.Test;
 /**
  * Tests for {@link AreaErrPtg}.
  */
-public final class TestAreaErrPtg extends AbstractPtgTestCase {
+public final class TestAreaErrPtg extends BaseTestPtg {
     /**
      * Tests reading a file containing this ptg.
      */
index b7b058007a8eba6bf277ce7871fab6db37421198..d957a956aa558ab6006a3570fa9030b3b38968eb 100644 (file)
@@ -27,7 +27,7 @@ import org.junit.Test;
 /**
  * Tests for {@link AttrPtg}.
  */
-public final class TestAttrPtg extends AbstractPtgTestCase {
+public final class TestAttrPtg extends BaseTestPtg {
 
        /**
         * Fix for bug visible around svn r706772.
index 5f9af4784672f14727c8cb9f4d575a3a352dafd1..0ff6ad78b68fabeda802c1a31ee4829cd73783bb 100644 (file)
@@ -28,7 +28,7 @@ import org.junit.Test;
 /**
  * Tests for {@link ErrPtg}.
  */
-public final class TestErrPtg extends AbstractPtgTestCase {
+public final class TestErrPtg extends BaseTestPtg {
     /**
      * Tests reading a file containing this ptg.
      */
index c13bf638a9c8e6c0ce0cea0772abf267c83b5bff..729920cb8a52a4f704b4e1148ae624ca181e6e86 100644 (file)
@@ -28,7 +28,7 @@ import org.junit.Test;
 /**
  * Tests for {@link IntersectionPtg}.
  */
-public final class TestIntersectionPtg extends AbstractPtgTestCase {
+public final class TestIntersectionPtg extends BaseTestPtg {
     /**
      * Tests reading a file containing this ptg.
      */
index 84ede5baa6d1eb42fe3525da41967a3220d14627..4b69d0743bf1c70b9c033246accedc40239a9050 100644 (file)
@@ -28,7 +28,7 @@ import org.junit.Test;
 /**
  * Tests for {@link PercentPtg}.
  */
-public final class TestPercentPtg extends AbstractPtgTestCase {
+public final class TestPercentPtg extends BaseTestPtg {
     /**
      * Tests reading a file containing this ptg.
      */
index 55438777fac63bb4a0393f253a176d78f3ed7670..5389538ab25f00c6e1026308ffb31262d9da88a4 100644 (file)
@@ -28,7 +28,7 @@ import org.junit.Test;
 /**
  * Tests for {@link RangePtg}.
  */
-public final class TestRangePtg extends AbstractPtgTestCase {
+public final class TestRangePtg extends BaseTestPtg {
     /**
      * Tests reading a file containing this ptg.
      */
index 2bea126dab6aa658af7397f3134188de1dc78d96..04de2cb6e3b016aba1ab1c6be5ae131c9a9a6eef 100644 (file)
@@ -28,7 +28,7 @@ import org.junit.Test;
 /**
  * Tests for Ref3DPtg
  */
-public final class TestRef3DPtg extends AbstractPtgTestCase {
+public final class TestRef3DPtg extends BaseTestPtg {
        @Test
        public void testToFormulaString() throws IOException {
 
index 7d6fc3151c4b41e58165d487fa86e2122c959302..446700f78d5c9c147cb6f767b9c813e3e95f2a14 100644 (file)
@@ -28,7 +28,7 @@ import org.junit.Test;
 /**
  * Tests for {@link UnionPtg}.
  */
-public final class TestUnionPtg extends AbstractPtgTestCase {
+public final class TestUnionPtg extends BaseTestPtg {
     /**
      * Tests reading a file containing this ptg.
      */
diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestRangeCopier.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestRangeCopier.java
new file mode 100644 (file)
index 0000000..f044b6f
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *  ====================================================================
+ *    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.ss.usermodel;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.poi.ss.ITestDataProvider;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.junit.Ignore;
+import org.junit.Test;
+
+@Ignore
+public abstract class BaseTestRangeCopier {
+    protected Sheet sheet1;
+    protected Sheet sheet2;
+    protected Workbook workbook;
+    protected RangeCopier rangeCopier;
+    protected RangeCopier transSheetRangeCopier;
+    protected ITestDataProvider testDataProvider;
+
+    protected void initSheets() {
+        sheet1 = workbook.getSheet("sheet1");
+        sheet2 = workbook.getSheet("sheet2");
+    }
+
+    @Test
+    public void copySheetRangeWithoutFormulas() {
+        CellRangeAddress rangeToCopy = CellRangeAddress.valueOf("B1:C2");   //2x2
+        CellRangeAddress destRange = CellRangeAddress.valueOf("C2:D3");     //2x2
+        rangeCopier.copyRange(rangeToCopy, destRange);
+        assertEquals("1.1", sheet1.getRow(2).getCell(2).toString());
+        assertEquals("2.1", sheet1.getRow(2).getCell(3).toString());
+    }
+
+    @Test
+    public void tileTheRangeAway() {
+        CellRangeAddress tileRange = CellRangeAddress.valueOf("C4:D5");
+        CellRangeAddress destRange = CellRangeAddress.valueOf("F4:K5");
+        rangeCopier.copyRange(tileRange, destRange);
+        assertEquals("1.3", getCellContent(sheet1, "H4"));
+        assertEquals("1.3", getCellContent(sheet1, "J4"));
+        assertEquals("$C1+G$2", getCellContent(sheet1, "G5"));
+        assertEquals("SUM(G3:I3)", getCellContent(sheet1, "H5"));
+        assertEquals("$C1+I$2", getCellContent(sheet1, "I5"));
+        assertEquals("", getCellContent(sheet1, "L5"));  //out of borders
+        assertEquals("", getCellContent(sheet1, "G7")); //out of borders
+    }
+
+    @Test
+    public void tileTheRangeOver() {
+        CellRangeAddress tileRange = CellRangeAddress.valueOf("C4:D5");
+        CellRangeAddress destRange = CellRangeAddress.valueOf("A4:C5");
+        rangeCopier.copyRange(tileRange, destRange);
+        assertEquals("1.3", getCellContent(sheet1, "A4"));
+        assertEquals("$C1+B$2", getCellContent(sheet1, "B5"));
+        assertEquals("SUM(B3:D3)", getCellContent(sheet1, "C5"));
+    }
+
+    @Test
+    public void copyRangeToOtherSheet() {
+        Sheet destSheet = sheet2;
+        CellRangeAddress tileRange = CellRangeAddress.valueOf("C4:D5"); // on sheet1
+        CellRangeAddress destRange = CellRangeAddress.valueOf("F4:J6"); // on sheet2
+        transSheetRangeCopier.copyRange(tileRange, destRange);
+        assertEquals("1.3", getCellContent(destSheet, "H4"));
+        assertEquals("1.3", getCellContent(destSheet, "J4"));
+        assertEquals("$C1+G$2", getCellContent(destSheet, "G5"));
+        assertEquals("SUM(G3:I3)", getCellContent(destSheet, "H5"));
+        assertEquals("$C1+I$2", getCellContent(destSheet, "I5"));
+    }
+
+    @Test
+    public void testEmptyRow() {
+        // leave some rows empty in-between
+        Row row = sheet1.createRow(23);
+        row.createCell(0).setCellValue(1.2);
+
+        Sheet destSheet = sheet2;
+        CellRangeAddress tileRange = CellRangeAddress.valueOf("A1:A100"); // on sheet1
+        CellRangeAddress destRange = CellRangeAddress.valueOf("G1:G100"); // on sheet2
+        transSheetRangeCopier.copyRange(tileRange, destRange);
+
+        assertEquals("1.2", getCellContent(destSheet, "G24"));
+    }
+
+    @Test
+    public void testSameSheet() {
+        // leave some rows empty in-between
+        Row row = sheet1.createRow(23);
+        row.createCell(0).setCellValue(1.2);
+
+        CellRangeAddress tileRange = CellRangeAddress.valueOf("A1:A100"); // on sheet1
+        CellRangeAddress destRange = CellRangeAddress.valueOf("G1:G100"); // on sheet2
+
+        // use the a RangeCopier with the same Sheet for source and dest
+        rangeCopier.copyRange(tileRange, destRange);
+
+        assertEquals("1.2", getCellContent(sheet1, "G24"));
+    }
+
+    @Test
+    public void testCopyStyles() {
+        String cellContent = "D6 aligned to the right";
+        HorizontalAlignment toTheRight = HorizontalAlignment.RIGHT;
+        // create cell with content aligned to the right
+        CellStyle style = workbook.createCellStyle();
+        style.setAlignment(toTheRight);
+        Cell cell = sheet1.createRow(5).createCell(3);
+        cell.setCellValue(cellContent);
+        cell.setCellStyle(style);
+
+        Sheet destSheet = sheet2;
+        CellRangeAddress tileRange = CellRangeAddress.valueOf("D6:D6"); // on sheet1
+        CellRangeAddress destRange = CellRangeAddress.valueOf("J6:J6"); // on sheet2
+        transSheetRangeCopier.copyRange(tileRange, destRange, true, false);
+        assertEquals(cellContent, getCellContent(destSheet, "J6"));
+        assertEquals(toTheRight, getCell(destSheet, "J6").getCellStyle().getAlignment());
+    }
+
+    @Test
+    public void testMergedRanges() {
+        String cellContent = "D6 merged to E7";
+
+        // create cell merged from D6 to E7
+        CellRangeAddress mergedRangeAddress = new CellRangeAddress(5,6,3,4);
+        Cell cell = sheet1.createRow(5).createCell(3);
+        cell.setCellValue(cellContent);
+        sheet1.addMergedRegion(mergedRangeAddress);
+
+        Sheet destSheet = sheet2;
+        CellRangeAddress tileRange = CellRangeAddress.valueOf("D6:E7"); // on sheet1
+        transSheetRangeCopier.copyRange(tileRange, tileRange, false, true);
+        assertEquals(cellContent, getCellContent(destSheet, "D6"));
+        assertFalse(destSheet.getMergedRegions().isEmpty());
+        destSheet.getMergedRegions().forEach((mergedRegion) -> {
+            assertTrue(mergedRegion.equals(mergedRangeAddress));
+        });
+    }
+
+   protected static String getCellContent(Sheet sheet, String coordinates) {
+        Cell cell = getCell(sheet, coordinates);
+        return cell == null ? "" : cell.toString();
+   }
+
+   protected static Cell getCell(Sheet sheet, String coordinates) {
+        try {
+            CellReference p = new CellReference(coordinates);
+            return sheet.getRow(p.getRow()).getCell(p.getCol());
+        }
+        catch (NullPointerException e) { // row or cell does not exist
+            return null;
+        }
+    }
+}
diff --git a/src/testcases/org/apache/poi/ss/usermodel/TestRangeCopier.java b/src/testcases/org/apache/poi/ss/usermodel/TestRangeCopier.java
deleted file mode 100644 (file)
index 929abc3..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- *  ====================================================================
- *    Licensed to the Apache Software Foundation (ASF) under one or more
- *    contributor license agreements.  See the NOTICE file distributed with
- *    this work for additional information regarding copyright ownership.
- *    The ASF licenses this file to You under the Apache License, Version 2.0
- *    (the "License"); you may not use this file except in compliance with
- *    the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- * ====================================================================
- */
-
-package org.apache.poi.ss.usermodel;
-
-import org.junit.Ignore;
-import org.junit.Test;
-import org.apache.poi.ss.ITestDataProvider;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.CellReference;
-
-import static org.junit.Assert.*;
-
-@Ignore
-public abstract class TestRangeCopier {
-    protected Sheet sheet1;
-    protected Sheet sheet2;
-    protected Workbook workbook;
-    protected RangeCopier rangeCopier;
-    protected RangeCopier transSheetRangeCopier;
-    protected ITestDataProvider testDataProvider;
-
-    protected void initSheets() {
-        sheet1 = workbook.getSheet("sheet1");
-        sheet2 = workbook.getSheet("sheet2");
-    }
-
-    @Test
-    public void copySheetRangeWithoutFormulas() {
-        CellRangeAddress rangeToCopy = CellRangeAddress.valueOf("B1:C2");   //2x2
-        CellRangeAddress destRange = CellRangeAddress.valueOf("C2:D3");     //2x2
-        rangeCopier.copyRange(rangeToCopy, destRange);
-        assertEquals("1.1", sheet1.getRow(2).getCell(2).toString());
-        assertEquals("2.1", sheet1.getRow(2).getCell(3).toString());
-    }
-
-    @Test
-    public void tileTheRangeAway() {
-        CellRangeAddress tileRange = CellRangeAddress.valueOf("C4:D5");
-        CellRangeAddress destRange = CellRangeAddress.valueOf("F4:K5");
-        rangeCopier.copyRange(tileRange, destRange);
-        assertEquals("1.3", getCellContent(sheet1, "H4"));
-        assertEquals("1.3", getCellContent(sheet1, "J4"));
-        assertEquals("$C1+G$2", getCellContent(sheet1, "G5"));
-        assertEquals("SUM(G3:I3)", getCellContent(sheet1, "H5"));
-        assertEquals("$C1+I$2", getCellContent(sheet1, "I5"));
-        assertEquals("", getCellContent(sheet1, "L5"));  //out of borders
-        assertEquals("", getCellContent(sheet1, "G7")); //out of borders
-    }
-
-    @Test
-    public void tileTheRangeOver() {
-        CellRangeAddress tileRange = CellRangeAddress.valueOf("C4:D5");
-        CellRangeAddress destRange = CellRangeAddress.valueOf("A4:C5");
-        rangeCopier.copyRange(tileRange, destRange);
-        assertEquals("1.3", getCellContent(sheet1, "A4"));
-        assertEquals("$C1+B$2", getCellContent(sheet1, "B5"));
-        assertEquals("SUM(B3:D3)", getCellContent(sheet1, "C5"));
-    }
-
-    @Test
-    public void copyRangeToOtherSheet() {
-        Sheet destSheet = sheet2;
-        CellRangeAddress tileRange = CellRangeAddress.valueOf("C4:D5"); // on sheet1
-        CellRangeAddress destRange = CellRangeAddress.valueOf("F4:J6"); // on sheet2
-        transSheetRangeCopier.copyRange(tileRange, destRange);
-        assertEquals("1.3", getCellContent(destSheet, "H4"));
-        assertEquals("1.3", getCellContent(destSheet, "J4"));
-        assertEquals("$C1+G$2", getCellContent(destSheet, "G5"));
-        assertEquals("SUM(G3:I3)", getCellContent(destSheet, "H5"));
-        assertEquals("$C1+I$2", getCellContent(destSheet, "I5"));
-    }
-
-    @Test
-    public void testEmptyRow() {
-        // leave some rows empty in-between
-        Row row = sheet1.createRow(23);
-        row.createCell(0).setCellValue(1.2);
-
-        Sheet destSheet = sheet2;
-        CellRangeAddress tileRange = CellRangeAddress.valueOf("A1:A100"); // on sheet1
-        CellRangeAddress destRange = CellRangeAddress.valueOf("G1:G100"); // on sheet2
-        transSheetRangeCopier.copyRange(tileRange, destRange);
-
-        assertEquals("1.2", getCellContent(destSheet, "G24"));
-    }
-
-    @Test
-    public void testSameSheet() {
-        // leave some rows empty in-between
-        Row row = sheet1.createRow(23);
-        row.createCell(0).setCellValue(1.2);
-
-        CellRangeAddress tileRange = CellRangeAddress.valueOf("A1:A100"); // on sheet1
-        CellRangeAddress destRange = CellRangeAddress.valueOf("G1:G100"); // on sheet2
-
-        // use the a RangeCopier with the same Sheet for source and dest
-        rangeCopier.copyRange(tileRange, destRange);
-
-        assertEquals("1.2", getCellContent(sheet1, "G24"));
-    }
-
-    @Test
-    public void testCopyStyles() {
-        String cellContent = "D6 aligned to the right";
-        HorizontalAlignment toTheRight = HorizontalAlignment.RIGHT;
-        // create cell with content aligned to the right
-        CellStyle style = workbook.createCellStyle();
-        style.setAlignment(toTheRight);
-        Cell cell = sheet1.createRow(5).createCell(3);
-        cell.setCellValue(cellContent);
-        cell.setCellStyle(style);
-
-        Sheet destSheet = sheet2;
-        CellRangeAddress tileRange = CellRangeAddress.valueOf("D6:D6"); // on sheet1
-        CellRangeAddress destRange = CellRangeAddress.valueOf("J6:J6"); // on sheet2
-        transSheetRangeCopier.copyRange(tileRange, destRange, true, false);
-        assertEquals(cellContent, getCellContent(destSheet, "J6"));
-        assertEquals(toTheRight, getCell(destSheet, "J6").getCellStyle().getAlignment());
-    }
-
-    @Test
-    public void testMergedRanges() {
-        String cellContent = "D6 merged to E7";
-
-        // create cell merged from D6 to E7
-        CellRangeAddress mergedRangeAddress = new CellRangeAddress(5,6,3,4);
-        Cell cell = sheet1.createRow(5).createCell(3);
-        cell.setCellValue(cellContent);
-        sheet1.addMergedRegion(mergedRangeAddress);
-
-        Sheet destSheet = sheet2;
-        CellRangeAddress tileRange = CellRangeAddress.valueOf("D6:E7"); // on sheet1
-        transSheetRangeCopier.copyRange(tileRange, tileRange, false, true);
-        assertEquals(cellContent, getCellContent(destSheet, "D6"));
-        assertFalse(destSheet.getMergedRegions().isEmpty());
-        destSheet.getMergedRegions().forEach((mergedRegion) -> {
-            assertTrue(mergedRegion.equals(mergedRangeAddress));
-        });
-    }
-
-   protected static String getCellContent(Sheet sheet, String coordinates) {
-        Cell cell = getCell(sheet, coordinates);
-        return cell == null ? "" : cell.toString();
-   }
-
-   protected static Cell getCell(Sheet sheet, String coordinates) {
-        try {
-            CellReference p = new CellReference(coordinates);
-            return sheet.getRow(p.getRow()).getCell(p.getCol());
-        }
-        catch (NullPointerException e) { // row or cell does not exist
-            return null;
-        }
-    }
-}