summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeniy Berlog <berlog@apache.org>2012-08-05 13:05:44 +0000
committerEvgeniy Berlog <berlog@apache.org>2012-08-05 13:05:44 +0000
commitde70938945b079b631bc94c7c5bf6943be22898c (patch)
treee01695e6f0c8fb26b9213af977a03819419d6a0b
parent3786b5d599afa60e320b8ef3e20f03650dbc9a07 (diff)
parent02678b307325a5bfd8bc4329e48a21f7639a7414 (diff)
downloadpoi-de70938945b079b631bc94c7c5bf6943be22898c.tar.gz
poi-de70938945b079b631bc94c7c5bf6943be22898c.zip
merged with trunk
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/gsoc2012@1369572 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/documentation/content/xdocs/casestudies.xml35
-rw-r--r--src/documentation/content/xdocs/spreadsheet/eval.xml61
-rw-r--r--src/documentation/content/xdocs/spreadsheet/quick-guide.xml37
-rw-r--r--src/documentation/content/xdocs/status.xml14
-rw-r--r--src/documentation/skinconf.xml4
-rw-r--r--src/java/org/apache/poi/hssf/model/InternalSheet.java2
-rw-r--r--src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java1215
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFName.java12
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java14
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java190
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java144
-rw-r--r--src/java/org/apache/poi/ss/format/CellDateFormatter.java7
-rw-r--r--src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java8
-rw-r--r--src/java/org/apache/poi/ss/usermodel/DataFormatter.java25
-rw-r--r--src/java/org/apache/poi/ss/usermodel/Sheet.java91
-rw-r--r--src/java/org/apache/poi/ss/usermodel/Workbook.java4
-rw-r--r--src/java/org/apache/poi/ss/util/CellRangeAddress.java13
-rw-r--r--src/java/org/apache/poi/ss/util/CellRangeAddressBase.java6
-rw-r--r--src/java/org/apache/poi/ss/util/CellReference.java45
-rw-r--r--src/java/org/apache/poi/util/LittleEndian.java18
-rw-r--r--src/java/org/apache/poi/util/PngUtils.java57
-rw-r--r--src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java39
-rw-r--r--src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java73
-rw-r--r--src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java20
-rw-r--r--src/ooxml/java/org/apache/poi/ss/usermodel/WorkbookFactory.java2
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java6
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java8
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java33
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java4
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFRow.java1
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java50
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java6
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java4
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java159
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java118
-rw-r--r--src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFColor.java21
-rw-r--r--src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java28
-rw-r--r--src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java6
-rw-r--r--src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java11
-rw-r--r--src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextRun.java11
-rw-r--r--src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbook.java8
-rw-r--r--src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFName.java25
-rw-r--r--src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java6
-rw-r--r--src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java36
-rw-r--r--src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java126
-rw-r--r--src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeader.java3
-rw-r--r--src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV11.java7
-rw-r--r--src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV4V5.java7
-rw-r--r--src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV6.java7
-rw-r--r--src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java26
-rw-r--r--src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIAttribute.java56
-rw-r--r--src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIStringAttribute.java4
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java30
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java3
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java4
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/AttachmentChunks.java33
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/ByteChunk.java5
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunk.java13
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/DirectoryChunk.java3
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/MAPIProperty.java147
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessagePropertiesChunk.java89
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessageSubmissionChunk.java5
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/NameIdChunks.java2
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertiesChunk.java87
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertyValue.java75
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java53
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/StringChunk.java24
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java168
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/dev/HSMFDump.java42
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/dev/TypesLister.java11
-rw-r--r--src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java155
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java10
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hdgf/TestHDGFCore.java25
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java40
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestChunkData.java19
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestMAPIProperty.java8
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestTypes.java24
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java28
-rw-r--r--src/testcases/org/apache/poi/hssf/model/TestSheet.java41
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPictureData.java23
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java16
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java14
-rw-r--r--src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java46
-rw-r--r--src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java74
-rw-r--r--src/testcases/org/apache/poi/ss/usermodel/BaseTestWorkbook.java13
-rw-r--r--src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java18
-rw-r--r--test-data/diagram/v6-non-utf16le.vsdbin0 -> 35840 bytes
-rw-r--r--test-data/document/53446.docbin0 -> 77312 bytes
-rw-r--r--test-data/slideshow/53446.pptbin0 -> 1110528 bytes
-rw-r--r--test-data/spreadsheet/53446.xlsbin0 -> 1799680 bytes
-rw-r--r--test-data/spreadsheet/RepeatingRowsCols.xlsbin0 -> 58368 bytes
-rw-r--r--test-data/spreadsheet/RepeatingRowsCols.xlsxbin0 -> 20758 bytes
92 files changed, 2968 insertions, 1293 deletions
diff --git a/src/documentation/content/xdocs/casestudies.xml b/src/documentation/content/xdocs/casestudies.xml
index a9f796fb02..d1deb60bb5 100644
--- a/src/documentation/content/xdocs/casestudies.xml
+++ b/src/documentation/content/xdocs/casestudies.xml
@@ -217,8 +217,13 @@ format,
<section>
<title>iDATA Development Ltd (IDD)</title>
<p>
- <link href="http://www.iexlsoftware.com/">IDD</link> have developed the iEXL product to generate Excel spreadsheets
- directly on the Iseries/AS400 IBM platform. Using RPG, SQL, QUERY, JAVA, COBOL etc. In other words your existing staffs knowledge.
+ <link href="http://www.iexlsoftware.com/">IDD</link> have developed the iEXL product to
+ generate Excel spreadsheets directly on the Iseries/AS400 IBM I on Power platform.
+ </p>
+ <p>
+ Professional spreadsheets created via a menu system. Some basic programming is required for more complex options.
+ When programming is required it can be carried out using RPG, SQL, QUERY, JAVA, COBOL etc.
+ In other words your existing staffs knowledge
</p>
<p>
Design spreadsheets with:
@@ -236,26 +241,34 @@ format,
<li>Page breaks</li>
<li>Sheet breaks</li>
<li>Text insertion and much more</li>
+ <li>Functions/Formula</li>
+ <li>Merge cells</li>
+ <li>Row Height</li>
+ <li>Cell text alignment</li>
+ <li>Text Rotation </li>
+ <li>50 Database files per workbook.</li>
<li>E-mail the spreadsheet</li>
</ul>
<p>
- The product name is ‘iEXL’ and has been live on both European and North American systems for over three years.
- It is being used in preference to more established commercial products which my clients have already purchased.
+ The product name is 'iEXL' and has been live on both European and North American systems for over four years.
+ It is being used in preference to more established commercial products which our clients have already purchased.
This is due to cost and ease of use.
</p>
<p>
- All spreadsheets can be archived if required so that historical spreadsheets can be retrieved and in the case
- of one client a full external company audit can be approved. The system has benefits for all departments within an organisation.
- Examples of this are accounts department for things such as aged trial balance, distribution department for ASN’s,
- warehousing for stock figures, IS for security reporting etc.
+ All spreadsheets can be archived if required so that historical spreadsheets can be retrieved.
+ </p>
+ <p>
+ The system has benefits for all departments within an organisation.
+ Examples of this are accounts department for things such as aged trial balance,
+ distribution department for ASN’s, warehousing for stock figures, IS for security reporting etc.
</p>
<p>
- Clients have at this point (Nov 2010) created over 200 spreadsheets
- which in turn have generated over 120,000 E-mails. iEXL has a menu driven email system.
+ Clients have at this point (June 2012) created over 300 spreadsheets which in turn have generated over
+ 500,000 E-mails. iEXL has a menu driven email system.
</p>
<p>
Due to the Apache-POI project IDD have been able to create the IEXL product.
- This is a well priced product which allows companies of all sizes access to a product that opens up their reporting capabilities.
+ This is a well priced product which allows companies of all sizes access to a product that opens up their reporting capabilities
</p>
<p>
Within the <link href="http://www.iexlsoftware.com/">iEXLSOFTWARE.COM</link> website you will find a full user manual,
diff --git a/src/documentation/content/xdocs/spreadsheet/eval.xml b/src/documentation/content/xdocs/spreadsheet/eval.xml
index 0eb54411a9..5ff76effb5 100644
--- a/src/documentation/content/xdocs/spreadsheet/eval.xml
+++ b/src/documentation/content/xdocs/spreadsheet/eval.xml
@@ -272,28 +272,41 @@ for(int sheetNum = 0; sheetNum &lt; wb.getNumberOfSheets(); sheetNum++) {
</source>
</section>
- <anchor id="Performance"/>
- <section><title>Performance Notes</title>
- <ul>
- <li>Generally you should have to create only one FormulaEvaluator
- instance per sheet, but there really is no overhead in creating
- multiple FormulaEvaluators per sheet other than that of the
- FormulaEvaluator object creation.
- </li>
- <li>Also note that FormulaEvaluator maintains a reference to
- the sheet and workbook, so ensure that the evaluator instance
- is available for garbage collection when you are done with it
- (in other words don't maintain long lived reference to
- FormulaEvaluator if you don't really need to - unless
- all references to the sheet and workbook are removed, these
- don't get garbage collected and continue to occupy potentially
- large amounts of memory).
- </li>
- <li>CellValue instances however do not maintain reference to the
- Cell or the sheet or workbook, so these can be long-lived
- objects without any adverse effect on performance.
- </li>
- </ul>
- </section>
- </body>
+ <anchor id="Performance"/>
+ <section><title>Performance Notes</title>
+ <ul>
+ <li>Generally you should have to create only one FormulaEvaluator
+ instance per Workbook. The FormulaEvaluator will cache
+ evaluations of dependent cells, so if you have multiple
+ formulas all depending on a cell then subsequent evaluations
+ will be faster.
+ </li>
+ <li>You should normally perform all of your updates to cells,
+ before triggering the evaluation, rather than doing one
+ cell at a time. By waiting until all the updates/sets are
+ performed, you'll be able to take best advantage of the caching
+ for complex formulas.
+ </li>
+ <li>If you do end up making changes to cells part way through
+ evaluation, you should call <em>notifySetFormula</em> or
+ <em>notifyUpdateCell</em> to trigger suitable cache clearance.
+ Alternately, you could instantiate a new FormulaEvaluator,
+ which will start with empty caches.
+ </li>
+ <li>Also note that FormulaEvaluator maintains a reference to
+ the sheet and workbook, so ensure that the evaluator instance
+ is available for garbage collection when you are done with it
+ (in other words don't maintain long lived reference to
+ FormulaEvaluator if you don't really need to - unless
+ all references to the sheet and workbook are removed, these
+ don't get garbage collected and continue to occupy potentially
+ large amounts of memory).
+ </li>
+ <li>CellValue instances however do not maintain reference to the
+ Cell or the sheet or workbook, so these can be long-lived
+ objects without any adverse effect on performance.
+ </li>
+ </ul>
+ </section>
+ </body>
</document>
diff --git a/src/documentation/content/xdocs/spreadsheet/quick-guide.xml b/src/documentation/content/xdocs/spreadsheet/quick-guide.xml
index 2140cda6ea..b4dc72eba1 100644
--- a/src/documentation/content/xdocs/spreadsheet/quick-guide.xml
+++ b/src/documentation/content/xdocs/spreadsheet/quick-guide.xml
@@ -865,26 +865,31 @@ Examples:
<section><title>Repeating rows and columns</title>
<p>
It's possible to set up repeating rows and columns in
- your printouts by using the setRepeatingRowsAndColumns()
- function in the HSSFWorkbook class.
+ your printouts by using the setRepeatingRows() and
+ setRepeatingColumns() methods in the Sheet class.
</p>
<p>
- 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.
+ These methods expect a CellRangeAddress parameter
+ which specifies the range for the rows or columns to
+ repeat.
+ For setRepeatingRows(), it should specify a range of
+ rows to repeat, with the column part spanning all
+ columns.
+ For setRepeatingColums(), it should specify a range of
+ columns to repeat, with the row part spanning all
+ rows.
+ If the parameter is null, the repeating rows or columns
+ will be removed.
</p>
<source>
- Workbook wb = new HSSFWorkbook();
- 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
- wb.setRepeatingRowsAndColumns(0,0,2,-1,-1);
- // Set the the repeating rows and columns on the second sheet.
- wb.setRepeatingRowsAndColumns(1,4,5,1,2);
+ Workbook wb = new HSSFWorkbook(); // or new XSSFWorkbook();
+ Sheet sheet1 = wb.createSheet("Sheet1");
+ Sheet sheet2 = wb.createSheet("Sheet2");
+
+ // Set the rows to repeat from row 4 to 5 on the first sheet.
+ sheet1.setRepeatingRows(CellRangeAddress.valueOf("4:5"));
+ // Set the columns to repeat from column A to C on the second sheet
+ sheet2.setRepeatingColumns(CellRangeAddress.valueOf("A:C"));
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml
index d27c150ac1..d3a744b48e 100644
--- a/src/documentation/content/xdocs/status.xml
+++ b/src/documentation/content/xdocs/status.xml
@@ -34,7 +34,19 @@
<changes>
<release version="3.9-beta1" date="2012-??-??">
- <action dev="poi-developers" type="add">53302 - Fixed EscherAggregate to correctly handle Continue records in drawing blocks </action>
+ <action dev="poi-developers" type="add">53446 - Fixed some problems extracting PNGs </action>
+ <action dev="poi-developers" type="fix">53205 - Fixed some parsing errors and encoding issues in HDGF </action>
+ <action dev="poi-developers" type="add">53204 - Improved performanceof PageSettingsBlock in HSSF </action>
+ <action dev="poi-developers" type="add">53500 - Getter for repeating rows and columns</action>
+ <action dev="poi-developers" type="fix">53369 - Fixed tests failing on JDK 1.7</action>
+ <action dev="poi-developers" type="fix">53360 - Fixed SXSSF to correctly write text before escaped Unicode control character</action>
+ <action dev="poi-developers" type="add">Change HSMF Types to have full data on ID, Name and Length, rather than just being a simple ID</action>
+ <action dev="poi-developers" type="add">48469 - Updated case study</action>
+ <action dev="poi-developers" type="add">53476 - Support Complex Name in formulas </action>
+ <action dev="poi-developers" type="fix">53414 - properly update sheet dimensions when adding column </action>
+ <action dev="poi-developers" type="add">Add File based constructor to OPCPackage, alongside existing String one (which constructed a File from the string internally)</action>
+ <action dev="poi-developers" type="fix">53389 - Handle formatting General and @ formats even if a locale is prefixed to them</action>
+ <action dev="poi-developers" type="fix">53271 - Removed unconditional asserts in SXSSF</action>
<action dev="poi-developers" type="add">53025 - Updatad documentation and example on using Data Validations </action>
<action dev="poi-developers" type="add">53227 - Corrected AddDimensionedImage.java to support XSSF/SXSSF </action>
<action dev="poi-developers" type="add">53058 - Utility for representing drawings contained in a binary Excel file as a XML tree</action>
diff --git a/src/documentation/skinconf.xml b/src/documentation/skinconf.xml
index bcec8209c8..9f34b88b61 100644
--- a/src/documentation/skinconf.xml
+++ b/src/documentation/skinconf.xml
@@ -82,7 +82,7 @@ be used to configure the chosen Forrest skin.
<!-- Do we want to disable the print link? If enabled, invalid HTML 4.0.1 -->
<disable-print-link>false</disable-print-link>
<!-- Do we want to disable the PDF link? -->
- <disable-pdf-link>false</disable-pdf-link>
+ <disable-pdf-link>true</disable-pdf-link>
<!-- Do we want to disable the xml source link? yes, it avoids disclosing author emails -->
<disable-xml-link>true</disable-xml-link>
<!-- Do we want to disable w3c compliance links? -->
@@ -114,7 +114,7 @@ be used to configure the chosen Forrest skin.
<host-logo></host-logo>
<!-- The following are used to construct a copyright statement -->
- <year>2002-2011</year>
+ <year>2002-2012</year>
<vendor>The Apache Software Foundation</vendor>
<!-- Some skins use this to form a 'breadcrumb trail' of links. If you don't
diff --git a/src/java/org/apache/poi/hssf/model/InternalSheet.java b/src/java/org/apache/poi/hssf/model/InternalSheet.java
index 62da2bb1ad..bb4ce3fb3d 100644
--- a/src/java/org/apache/poi/hssf/model/InternalSheet.java
+++ b/src/java/org/apache/poi/hssf/model/InternalSheet.java
@@ -597,7 +597,7 @@ public final class InternalSheet {
}
DimensionsRecord d = _dimensions;
- if (col.getColumn() > d.getLastCol()) {
+ if (col.getColumn() >= d.getLastCol()) {
d.setLastCol(( short ) (col.getColumn() + 1));
}
if (col.getColumn() < d.getFirstCol()) {
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java b/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java
index 5236e184b8..c183b5070a 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java
@@ -18,13 +18,15 @@
package org.apache.poi.hssf.record.aggregates;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-import java.util.Arrays;
+import java.util.Map;
import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.model.InternalSheet;
import org.apache.poi.hssf.record.*;
+import org.apache.poi.util.HexDump;
/**
* Groups the page settings records for a worksheet.<p/>
@@ -35,59 +37,59 @@ import org.apache.poi.hssf.record.*;
*/
public final class PageSettingsBlock extends RecordAggregate {
- /**
- * PLS is potentially a <i>continued</i> record, but is currently uninterpreted by POI
- */
- private static final class PLSAggregate extends RecordAggregate {
- private static final ContinueRecord[] EMPTY_CONTINUE_RECORD_ARRAY = { };
- private final Record _pls;
- /**
- * holds any continue records found after the PLS record.<br/>
- * This would not be required if PLS was properly interpreted.
- * Currently, PLS is an {@link UnknownRecord} and does not automatically
- * include any trailing {@link ContinueRecord}s.
- */
- private ContinueRecord[] _plsContinues;
-
- public PLSAggregate(RecordStream rs) {
- _pls = rs.getNext();
- if (rs.peekNextSid()==ContinueRecord.sid) {
- List<ContinueRecord> temp = new ArrayList<ContinueRecord>();
- while (rs.peekNextSid()==ContinueRecord.sid) {
- temp.add((ContinueRecord)rs.getNext());
- }
- _plsContinues = new ContinueRecord[temp.size()];
- temp.toArray(_plsContinues);
- } else {
- _plsContinues = EMPTY_CONTINUE_RECORD_ARRAY;
- }
- }
-
- @Override
- public void visitContainedRecords(RecordVisitor rv) {
- rv.visitRecord(_pls);
- for (int i = 0; i < _plsContinues.length; i++) {
- rv.visitRecord(_plsContinues[i]);
- }
- }
- }
-
- // Every one of these component records is optional
- // (The whole PageSettingsBlock may not be present)
- private PageBreakRecord _rowBreaksRecord;
- private PageBreakRecord _columnBreaksRecord;
- private HeaderRecord _header;
- private FooterRecord _footer;
- private HCenterRecord _hCenter;
- private VCenterRecord _vCenter;
- private LeftMarginRecord _leftMargin;
- private RightMarginRecord _rightMargin;
- private TopMarginRecord _topMargin;
- private BottomMarginRecord _bottomMargin;
- private final List<PLSAggregate> _plsRecords;
- private PrintSetupRecord _printSetup;
- private Record _bitmap;
- private HeaderFooterRecord _headerFooter;
+ /**
+ * PLS is potentially a <i>continued</i> record, but is currently uninterpreted by POI
+ */
+ private static final class PLSAggregate extends RecordAggregate {
+ private static final ContinueRecord[] EMPTY_CONTINUE_RECORD_ARRAY = { };
+ private final Record _pls;
+ /**
+ * holds any continue records found after the PLS record.<br/>
+ * This would not be required if PLS was properly interpreted.
+ * Currently, PLS is an {@link UnknownRecord} and does not automatically
+ * include any trailing {@link ContinueRecord}s.
+ */
+ private ContinueRecord[] _plsContinues;
+
+ public PLSAggregate(RecordStream rs) {
+ _pls = rs.getNext();
+ if (rs.peekNextSid()==ContinueRecord.sid) {
+ List<ContinueRecord> temp = new ArrayList<ContinueRecord>();
+ while (rs.peekNextSid()==ContinueRecord.sid) {
+ temp.add((ContinueRecord)rs.getNext());
+ }
+ _plsContinues = new ContinueRecord[temp.size()];
+ temp.toArray(_plsContinues);
+ } else {
+ _plsContinues = EMPTY_CONTINUE_RECORD_ARRAY;
+ }
+ }
+
+ @Override
+ public void visitContainedRecords(RecordVisitor rv) {
+ rv.visitRecord(_pls);
+ for (int i = 0; i < _plsContinues.length; i++) {
+ rv.visitRecord(_plsContinues[i]);
+ }
+ }
+ }
+
+ // Every one of these component records is optional
+ // (The whole PageSettingsBlock may not be present)
+ private PageBreakRecord _rowBreaksRecord;
+ private PageBreakRecord _columnBreaksRecord;
+ private HeaderRecord _header;
+ private FooterRecord _footer;
+ private HCenterRecord _hCenter;
+ private VCenterRecord _vCenter;
+ private LeftMarginRecord _leftMargin;
+ private RightMarginRecord _rightMargin;
+ private TopMarginRecord _topMargin;
+ private BottomMarginRecord _bottomMargin;
+ private final List<PLSAggregate> _plsRecords;
+ private PrintSetupRecord _printSetup;
+ private Record _bitmap;
+ private HeaderFooterRecord _headerFooter;
/**
* HeaderFooterRecord records belonging to preceding CustomViewSettingsRecordAggregates.
* The indicator of such records is a non-zero GUID,
@@ -96,546 +98,546 @@ public final class PageSettingsBlock extends RecordAggregate {
private List<HeaderFooterRecord> _sviewHeaderFooters = new ArrayList<HeaderFooterRecord>();
private Record _printSize;
- public PageSettingsBlock(RecordStream rs) {
- _plsRecords = new ArrayList<PLSAggregate>();
- while(true) {
- if (!readARecord(rs)) {
- break;
- }
- }
- }
-
- /**
- * Creates a PageSettingsBlock with default settings
- */
- public PageSettingsBlock() {
- _plsRecords = new ArrayList<PLSAggregate>();
- _rowBreaksRecord = new HorizontalPageBreakRecord();
- _columnBreaksRecord = new VerticalPageBreakRecord();
- _header = new HeaderRecord("");
- _footer = new FooterRecord("");
- _hCenter = createHCenter();
- _vCenter = createVCenter();
- _printSetup = createPrintSetup();
- }
-
- /**
- * @return <code>true</code> if the specified Record sid is one belonging to the
- * 'Page Settings Block'.
- */
- public static boolean isComponentRecord(int sid) {
- switch (sid) {
- case HorizontalPageBreakRecord.sid:
- case VerticalPageBreakRecord.sid:
- case HeaderRecord.sid:
- case FooterRecord.sid:
- case HCenterRecord.sid:
- case VCenterRecord.sid:
- case LeftMarginRecord.sid:
- case RightMarginRecord.sid:
- case TopMarginRecord.sid:
- case BottomMarginRecord.sid:
- case UnknownRecord.PLS_004D:
- case PrintSetupRecord.sid:
- case UnknownRecord.BITMAP_00E9:
- case UnknownRecord.PRINTSIZE_0033:
- case HeaderFooterRecord.sid: // extra header/footer settings supported by Excel 2007
- return true;
- }
- return false;
- }
-
- private boolean readARecord(RecordStream rs) {
- switch (rs.peekNextSid()) {
- case HorizontalPageBreakRecord.sid:
- checkNotPresent(_rowBreaksRecord);
- _rowBreaksRecord = (PageBreakRecord) rs.getNext();
- break;
- case VerticalPageBreakRecord.sid:
- checkNotPresent(_columnBreaksRecord);
- _columnBreaksRecord = (PageBreakRecord) rs.getNext();
- break;
- case HeaderRecord.sid:
- checkNotPresent(_header);
- _header = (HeaderRecord) rs.getNext();
- break;
- case FooterRecord.sid:
- checkNotPresent(_footer);
- _footer = (FooterRecord) rs.getNext();
- break;
- case HCenterRecord.sid:
- checkNotPresent(_hCenter);
- _hCenter = (HCenterRecord) rs.getNext();
- break;
- case VCenterRecord.sid:
- checkNotPresent(_vCenter);
- _vCenter = (VCenterRecord) rs.getNext();
- break;
- case LeftMarginRecord.sid:
- checkNotPresent(_leftMargin);
- _leftMargin = (LeftMarginRecord) rs.getNext();
- break;
- case RightMarginRecord.sid:
- checkNotPresent(_rightMargin);
- _rightMargin = (RightMarginRecord) rs.getNext();
- break;
- case TopMarginRecord.sid:
- checkNotPresent(_topMargin);
- _topMargin = (TopMarginRecord) rs.getNext();
- break;
- case BottomMarginRecord.sid:
- checkNotPresent(_bottomMargin);
- _bottomMargin = (BottomMarginRecord) rs.getNext();
- break;
- case UnknownRecord.PLS_004D:
- _plsRecords.add(new PLSAggregate(rs));
- break;
- case PrintSetupRecord.sid:
- checkNotPresent(_printSetup);
- _printSetup = (PrintSetupRecord)rs.getNext();
- break;
- case UnknownRecord.BITMAP_00E9:
- checkNotPresent(_bitmap);
- _bitmap = rs.getNext();
- break;
- case UnknownRecord.PRINTSIZE_0033:
- checkNotPresent(_printSize);
- _printSize = rs.getNext();
- break;
- case HeaderFooterRecord.sid:
- //there can be multiple HeaderFooterRecord records belonging to different sheet views
- HeaderFooterRecord hf = (HeaderFooterRecord)rs.getNext();
+ public PageSettingsBlock(RecordStream rs) {
+ _plsRecords = new ArrayList<PLSAggregate>();
+ while(true) {
+ if (!readARecord(rs)) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Creates a PageSettingsBlock with default settings
+ */
+ public PageSettingsBlock() {
+ _plsRecords = new ArrayList<PLSAggregate>();
+ _rowBreaksRecord = new HorizontalPageBreakRecord();
+ _columnBreaksRecord = new VerticalPageBreakRecord();
+ _header = new HeaderRecord("");
+ _footer = new FooterRecord("");
+ _hCenter = createHCenter();
+ _vCenter = createVCenter();
+ _printSetup = createPrintSetup();
+ }
+
+ /**
+ * @return <code>true</code> if the specified Record sid is one belonging to the
+ * 'Page Settings Block'.
+ */
+ public static boolean isComponentRecord(int sid) {
+ switch (sid) {
+ case HorizontalPageBreakRecord.sid:
+ case VerticalPageBreakRecord.sid:
+ case HeaderRecord.sid:
+ case FooterRecord.sid:
+ case HCenterRecord.sid:
+ case VCenterRecord.sid:
+ case LeftMarginRecord.sid:
+ case RightMarginRecord.sid:
+ case TopMarginRecord.sid:
+ case BottomMarginRecord.sid:
+ case UnknownRecord.PLS_004D:
+ case PrintSetupRecord.sid:
+ case UnknownRecord.BITMAP_00E9:
+ case UnknownRecord.PRINTSIZE_0033:
+ case HeaderFooterRecord.sid: // extra header/footer settings supported by Excel 2007
+ return true;
+ }
+ return false;
+ }
+
+ private boolean readARecord(RecordStream rs) {
+ switch (rs.peekNextSid()) {
+ case HorizontalPageBreakRecord.sid:
+ checkNotPresent(_rowBreaksRecord);
+ _rowBreaksRecord = (PageBreakRecord) rs.getNext();
+ break;
+ case VerticalPageBreakRecord.sid:
+ checkNotPresent(_columnBreaksRecord);
+ _columnBreaksRecord = (PageBreakRecord) rs.getNext();
+ break;
+ case HeaderRecord.sid:
+ checkNotPresent(_header);
+ _header = (HeaderRecord) rs.getNext();
+ break;
+ case FooterRecord.sid:
+ checkNotPresent(_footer);
+ _footer = (FooterRecord) rs.getNext();
+ break;
+ case HCenterRecord.sid:
+ checkNotPresent(_hCenter);
+ _hCenter = (HCenterRecord) rs.getNext();
+ break;
+ case VCenterRecord.sid:
+ checkNotPresent(_vCenter);
+ _vCenter = (VCenterRecord) rs.getNext();
+ break;
+ case LeftMarginRecord.sid:
+ checkNotPresent(_leftMargin);
+ _leftMargin = (LeftMarginRecord) rs.getNext();
+ break;
+ case RightMarginRecord.sid:
+ checkNotPresent(_rightMargin);
+ _rightMargin = (RightMarginRecord) rs.getNext();
+ break;
+ case TopMarginRecord.sid:
+ checkNotPresent(_topMargin);
+ _topMargin = (TopMarginRecord) rs.getNext();
+ break;
+ case BottomMarginRecord.sid:
+ checkNotPresent(_bottomMargin);
+ _bottomMargin = (BottomMarginRecord) rs.getNext();
+ break;
+ case UnknownRecord.PLS_004D:
+ _plsRecords.add(new PLSAggregate(rs));
+ break;
+ case PrintSetupRecord.sid:
+ checkNotPresent(_printSetup);
+ _printSetup = (PrintSetupRecord)rs.getNext();
+ break;
+ case UnknownRecord.BITMAP_00E9:
+ checkNotPresent(_bitmap);
+ _bitmap = rs.getNext();
+ break;
+ case UnknownRecord.PRINTSIZE_0033:
+ checkNotPresent(_printSize);
+ _printSize = rs.getNext();
+ break;
+ case HeaderFooterRecord.sid:
+ //there can be multiple HeaderFooterRecord records belonging to different sheet views
+ HeaderFooterRecord hf = (HeaderFooterRecord)rs.getNext();
if(hf.isCurrentSheet()) _headerFooter = hf;
else {
_sviewHeaderFooters.add(hf);
}
break;
- default:
- // all other record types are not part of the PageSettingsBlock
- return false;
- }
- return true;
- }
-
- private void checkNotPresent(Record rec) {
- if (rec != null) {
- throw new RecordFormatException("Duplicate PageSettingsBlock record (sid=0x"
- + Integer.toHexString(rec.getSid()) + ")");
- }
- }
-
- private PageBreakRecord getRowBreaksRecord() {
- if (_rowBreaksRecord == null) {
- _rowBreaksRecord = new HorizontalPageBreakRecord();
- }
- return _rowBreaksRecord;
- }
-
- private PageBreakRecord getColumnBreaksRecord() {
- if (_columnBreaksRecord == null) {
- _columnBreaksRecord = new VerticalPageBreakRecord();
- }
- return _columnBreaksRecord;
- }
-
-
- /**
- * Sets a page break at the indicated column
- *
- */
- public void setColumnBreak(short column, short fromRow, short toRow) {
- getColumnBreaksRecord().addBreak(column, fromRow, toRow);
- }
-
- /**
- * Removes a page break at the indicated column
- *
- */
- public void removeColumnBreak(int column) {
- getColumnBreaksRecord().removeBreak(column);
- }
-
-
-
-
- public void visitContainedRecords(RecordVisitor rv) {
- // Replicates record order from Excel 2007, though this is not critical
-
- visitIfPresent(_rowBreaksRecord, rv);
- visitIfPresent(_columnBreaksRecord, rv);
- // Write out empty header / footer records if these are missing
- if (_header == null) {
- rv.visitRecord(new HeaderRecord(""));
- } else {
- rv.visitRecord(_header);
- }
- if (_footer == null) {
- rv.visitRecord(new FooterRecord(""));
- } else {
- rv.visitRecord(_footer);
- }
- visitIfPresent(_hCenter, rv);
- visitIfPresent(_vCenter, rv);
- visitIfPresent(_leftMargin, rv);
- visitIfPresent(_rightMargin, rv);
- visitIfPresent(_topMargin, rv);
- visitIfPresent(_bottomMargin, rv);
- for (RecordAggregate pls : _plsRecords) {
- pls.visitContainedRecords(rv);
- }
- visitIfPresent(_printSetup, rv);
- visitIfPresent(_printSize, rv);
- visitIfPresent(_headerFooter, rv);
+ default:
+ // all other record types are not part of the PageSettingsBlock
+ return false;
+ }
+ return true;
+ }
+
+ private void checkNotPresent(Record rec) {
+ if (rec != null) {
+ throw new RecordFormatException("Duplicate PageSettingsBlock record (sid=0x"
+ + Integer.toHexString(rec.getSid()) + ")");
+ }
+ }
+
+ private PageBreakRecord getRowBreaksRecord() {
+ if (_rowBreaksRecord == null) {
+ _rowBreaksRecord = new HorizontalPageBreakRecord();
+ }
+ return _rowBreaksRecord;
+ }
+
+ private PageBreakRecord getColumnBreaksRecord() {
+ if (_columnBreaksRecord == null) {
+ _columnBreaksRecord = new VerticalPageBreakRecord();
+ }
+ return _columnBreaksRecord;
+ }
+
+
+ /**
+ * Sets a page break at the indicated column
+ *
+ */
+ public void setColumnBreak(short column, short fromRow, short toRow) {
+ getColumnBreaksRecord().addBreak(column, fromRow, toRow);
+ }
+
+ /**
+ * Removes a page break at the indicated column
+ *
+ */
+ public void removeColumnBreak(int column) {
+ getColumnBreaksRecord().removeBreak(column);
+ }
+
+
+
+
+ public void visitContainedRecords(RecordVisitor rv) {
+ // Replicates record order from Excel 2007, though this is not critical
+
+ visitIfPresent(_rowBreaksRecord, rv);
+ visitIfPresent(_columnBreaksRecord, rv);
+ // Write out empty header / footer records if these are missing
+ if (_header == null) {
+ rv.visitRecord(new HeaderRecord(""));
+ } else {
+ rv.visitRecord(_header);
+ }
+ if (_footer == null) {
+ rv.visitRecord(new FooterRecord(""));
+ } else {
+ rv.visitRecord(_footer);
+ }
+ visitIfPresent(_hCenter, rv);
+ visitIfPresent(_vCenter, rv);
+ visitIfPresent(_leftMargin, rv);
+ visitIfPresent(_rightMargin, rv);
+ visitIfPresent(_topMargin, rv);
+ visitIfPresent(_bottomMargin, rv);
+ for (RecordAggregate pls : _plsRecords) {
+ pls.visitContainedRecords(rv);
+ }
+ visitIfPresent(_printSetup, rv);
+ visitIfPresent(_printSize, rv);
+ visitIfPresent(_headerFooter, rv);
visitIfPresent(_bitmap, rv);
- }
- private static void visitIfPresent(Record r, RecordVisitor rv) {
- if (r != null) {
- rv.visitRecord(r);
- }
- }
- private static void visitIfPresent(PageBreakRecord r, RecordVisitor rv) {
- if (r != null) {
- if (r.isEmpty()) {
- // its OK to not serialize empty page break records
- return;
- }
- rv.visitRecord(r);
- }
- }
-
- /**
- * creates the HCenter Record and sets it to false (don't horizontally center)
- */
- private static HCenterRecord createHCenter() {
- HCenterRecord retval = new HCenterRecord();
-
- retval.setHCenter(false);
- return retval;
- }
-
- /**
- * creates the VCenter Record and sets it to false (don't horizontally center)
- */
- private static VCenterRecord createVCenter() {
- VCenterRecord retval = new VCenterRecord();
-
- retval.setVCenter(false);
- return retval;
- }
-
- /**
- * creates the PrintSetup Record and sets it to defaults and marks it invalid
- * @see org.apache.poi.hssf.record.PrintSetupRecord
- * @see org.apache.poi.hssf.record.Record
- * @return record containing a PrintSetupRecord
- */
- private static PrintSetupRecord createPrintSetup() {
- PrintSetupRecord retval = new PrintSetupRecord();
-
- retval.setPaperSize(( short ) 1);
- retval.setScale(( short ) 100);
- retval.setPageStart(( short ) 1);
- retval.setFitWidth(( short ) 1);
- retval.setFitHeight(( short ) 1);
- retval.setOptions(( short ) 2);
- retval.setHResolution(( short ) 300);
- retval.setVResolution(( short ) 300);
- retval.setHeaderMargin( 0.5);
- retval.setFooterMargin( 0.5);
- retval.setCopies(( short ) 1);
- return retval;
- }
-
-
- /**
- * Returns the HeaderRecord.
- * @return HeaderRecord for the sheet.
- */
- public HeaderRecord getHeader ()
- {
- return _header;
- }
-
- /**
- * Sets the HeaderRecord.
- * @param newHeader The new HeaderRecord for the sheet.
- */
- public void setHeader (HeaderRecord newHeader)
- {
- _header = newHeader;
- }
-
- /**
- * Returns the FooterRecord.
- * @return FooterRecord for the sheet.
- */
- public FooterRecord getFooter ()
- {
- return _footer;
- }
-
- /**
- * Sets the FooterRecord.
- * @param newFooter The new FooterRecord for the sheet.
- */
- public void setFooter (FooterRecord newFooter)
- {
- _footer = newFooter;
- }
-
- /**
- * Returns the PrintSetupRecord.
- * @return PrintSetupRecord for the sheet.
- */
- public PrintSetupRecord getPrintSetup ()
- {
- return _printSetup;
- }
-
- /**
- * Sets the PrintSetupRecord.
- * @param newPrintSetup The new PrintSetupRecord for the sheet.
- */
- public void setPrintSetup (PrintSetupRecord newPrintSetup)
- {
- _printSetup = newPrintSetup;
- }
-
-
- private Margin getMarginRec(int marginIndex) {
- switch (marginIndex) {
- case InternalSheet.LeftMargin: return _leftMargin;
- case InternalSheet.RightMargin: return _rightMargin;
- case InternalSheet.TopMargin: return _topMargin;
- case InternalSheet.BottomMargin: return _bottomMargin;
- }
- throw new IllegalArgumentException( "Unknown margin constant: " + marginIndex );
- }
-
-
- /**
- * Gets the size of the margin in inches.
- * @param margin which margin to get
- * @return the size of the margin
- */
- public double getMargin(short margin) {
- Margin m = getMarginRec(margin);
- if (m != null) {
- return m.getMargin();
- }
- switch (margin) {
- case InternalSheet.LeftMargin: return .75;
- case InternalSheet.RightMargin: return .75;
- case InternalSheet.TopMargin: return 1.0;
- case InternalSheet.BottomMargin: return 1.0;
- }
- throw new IllegalArgumentException( "Unknown margin constant: " + margin );
- }
-
- /**
- * Sets the size of the margin in inches.
- * @param margin which margin to get
- * @param size the size of the margin
- */
- public void setMargin(short margin, double size) {
- Margin m = getMarginRec(margin);
- if (m == null) {
- switch (margin) {
- case InternalSheet.LeftMargin:
- _leftMargin = new LeftMarginRecord();
- m = _leftMargin;
- break;
- case InternalSheet.RightMargin:
- _rightMargin = new RightMarginRecord();
- m = _rightMargin;
- break;
- case InternalSheet.TopMargin:
- _topMargin = new TopMarginRecord();
- m = _topMargin;
- break;
- case InternalSheet.BottomMargin:
- _bottomMargin = new BottomMarginRecord();
- m = _bottomMargin;
- break;
- default :
- throw new IllegalArgumentException( "Unknown margin constant: " + margin );
- }
- }
- m.setMargin( size );
- }
-
- /**
- * Shifts all the page breaks in the range "count" number of rows/columns
- * @param breaks The page record to be shifted
- * @param start Starting "main" value to shift breaks
- * @param stop Ending "main" value to shift breaks
- * @param count number of units (rows/columns) to shift by
- */
- private static void shiftBreaks(PageBreakRecord breaks, int start, int stop, int count) {
-
- Iterator<PageBreakRecord.Break> iterator = breaks.getBreaksIterator();
- List<PageBreakRecord.Break> shiftedBreak = new ArrayList<PageBreakRecord.Break>();
- while(iterator.hasNext())
- {
- PageBreakRecord.Break breakItem = iterator.next();
- int breakLocation = breakItem.main;
- boolean inStart = (breakLocation >= start);
- boolean inEnd = (breakLocation <= stop);
- if(inStart && inEnd)
- shiftedBreak.add(breakItem);
- }
-
- iterator = shiftedBreak.iterator();
- while (iterator.hasNext()) {
- PageBreakRecord.Break breakItem = iterator.next();
- breaks.removeBreak(breakItem.main);
- breaks.addBreak((short)(breakItem.main+count), breakItem.subFrom, breakItem.subTo);
- }
- }
-
-
- /**
- * Sets a page break at the indicated row
- * @param row
- */
- public void setRowBreak(int row, short fromCol, short toCol) {
- getRowBreaksRecord().addBreak((short)row, fromCol, toCol);
- }
-
- /**
- * Removes a page break at the indicated row
- * @param row
- */
- public void removeRowBreak(int row) {
- if (getRowBreaksRecord().getBreaks().length < 1)
- throw new IllegalArgumentException("Sheet does not define any row breaks");
- getRowBreaksRecord().removeBreak((short)row);
- }
-
- /**
- * Queries if the specified row has a page break
- * @param row
- * @return true if the specified row has a page break
- */
- public boolean isRowBroken(int row) {
- return getRowBreaksRecord().getBreak(row) != null;
- }
-
-
- /**
- * Queries if the specified column has a page break
- *
- * @return <code>true</code> if the specified column has a page break
- */
- public boolean isColumnBroken(int column) {
- return getColumnBreaksRecord().getBreak(column) != null;
- }
-
- /**
- * Shifts the horizontal page breaks for the indicated count
- * @param startingRow
- * @param endingRow
- * @param count
- */
- public void shiftRowBreaks(int startingRow, int endingRow, int count) {
- shiftBreaks(getRowBreaksRecord(), startingRow, endingRow, count);
- }
-
- /**
- * Shifts the vertical page breaks for the indicated count
- * @param startingCol
- * @param endingCol
- * @param count
- */
- public void shiftColumnBreaks(short startingCol, short endingCol, short count) {
- shiftBreaks(getColumnBreaksRecord(), startingCol, endingCol, count);
- }
-
- /**
- * @return all the horizontal page breaks, never <code>null</code>
- */
- public int[] getRowBreaks() {
- return getRowBreaksRecord().getBreaks();
- }
-
- /**
- * @return the number of row page breaks
- */
- public int getNumRowBreaks(){
- return getRowBreaksRecord().getNumBreaks();
- }
-
- /**
- * @return all the column page breaks, never <code>null</code>
- */
- public int[] getColumnBreaks(){
- return getColumnBreaksRecord().getBreaks();
- }
-
- /**
- * @return the number of column page breaks
- */
- public int getNumColumnBreaks(){
- return getColumnBreaksRecord().getNumBreaks();
- }
-
- public VCenterRecord getVCenter() {
- return _vCenter;
- }
-
- public HCenterRecord getHCenter() {
- return _hCenter;
- }
-
- /**
- * HEADERFOOTER is new in 2007. Some apps seem to have scattered this record long after
- * the {@link PageSettingsBlock} where it belongs.
- */
- public void addLateHeaderFooter(HeaderFooterRecord rec) {
- if (_headerFooter != null) {
- throw new IllegalStateException("This page settings block already has a header/footer record");
- }
- if (rec.getSid() != HeaderFooterRecord.sid) {
- throw new RecordFormatException("Unexpected header-footer record sid: 0x" + Integer.toHexString(rec.getSid()));
- }
- _headerFooter = rec;
- }
-
- /**
- * This method reads PageSettingsBlock records from the supplied RecordStream until the first
- * non-PageSettingsBlock record is encountered. As each record is read, it is incorporated
- * into this PageSettingsBlock.
- * <p/>
- * The latest Excel version seems to write the PageSettingsBlock uninterrupted. However there
- * are several examples (that Excel reads OK) where these records are not written together:
- * <ul>
- * <li><b>HEADER_FOOTER(0x089C) after WINDOW2</b> - This record is new in 2007. Some apps
- * seem to have scattered this record long after the PageSettingsBlock where it belongs
- * test samples: SharedFormulaTest.xls, ex44921-21902.xls, ex42570-20305.xls</li>
- * <li><b>PLS, WSBOOL, PageSettingsBlock</b> - WSBOOL is not a PSB record.
- * This happens in the test sample file "NoGutsRecords.xls" and "WORKBOOK_in_capitals.xls"</li>
- * <li><b>Margins after DIMENSION</b> - All of PSB should be before DIMENSION. (Bug-47199)</li>
- * </ul>
- * These were probably written by other applications (or earlier versions of Excel). It was
- * decided to not write specific code for detecting each of these cases. POI now tolerates
- * PageSettingsBlock records scattered all over the sheet record stream, and in any order, but
- * does not allow duplicates of any of those records.
- *
- * <p/>
- * <b>Note</b> - when POI writes out this PageSettingsBlock, the records will always be written
- * in one consolidated block (in the standard ordering) regardless of how scattered the records
- * were when they were originally read.
- *
- * @throws RecordFormatException if any PSB record encountered has the same type (sid) as
- * a record that is already part of this PageSettingsBlock
- */
- public void addLateRecords(RecordStream rs) {
- while(true) {
- if (!readARecord(rs)) {
- break;
- }
- }
- }
+ }
+ private static void visitIfPresent(Record r, RecordVisitor rv) {
+ if (r != null) {
+ rv.visitRecord(r);
+ }
+ }
+ private static void visitIfPresent(PageBreakRecord r, RecordVisitor rv) {
+ if (r != null) {
+ if (r.isEmpty()) {
+ // its OK to not serialize empty page break records
+ return;
+ }
+ rv.visitRecord(r);
+ }
+ }
+
+ /**
+ * creates the HCenter Record and sets it to false (don't horizontally center)
+ */
+ private static HCenterRecord createHCenter() {
+ HCenterRecord retval = new HCenterRecord();
+
+ retval.setHCenter(false);
+ return retval;
+ }
+
+ /**
+ * creates the VCenter Record and sets it to false (don't horizontally center)
+ */
+ private static VCenterRecord createVCenter() {
+ VCenterRecord retval = new VCenterRecord();
+
+ retval.setVCenter(false);
+ return retval;
+ }
+
+ /**
+ * creates the PrintSetup Record and sets it to defaults and marks it invalid
+ * @see org.apache.poi.hssf.record.PrintSetupRecord
+ * @see org.apache.poi.hssf.record.Record
+ * @return record containing a PrintSetupRecord
+ */
+ private static PrintSetupRecord createPrintSetup() {
+ PrintSetupRecord retval = new PrintSetupRecord();
+
+ retval.setPaperSize(( short ) 1);
+ retval.setScale(( short ) 100);
+ retval.setPageStart(( short ) 1);
+ retval.setFitWidth(( short ) 1);
+ retval.setFitHeight(( short ) 1);
+ retval.setOptions(( short ) 2);
+ retval.setHResolution(( short ) 300);
+ retval.setVResolution(( short ) 300);
+ retval.setHeaderMargin( 0.5);
+ retval.setFooterMargin( 0.5);
+ retval.setCopies(( short ) 1);
+ return retval;
+ }
+
+
+ /**
+ * Returns the HeaderRecord.
+ * @return HeaderRecord for the sheet.
+ */
+ public HeaderRecord getHeader ()
+ {
+ return _header;
+ }
+
+ /**
+ * Sets the HeaderRecord.
+ * @param newHeader The new HeaderRecord for the sheet.
+ */
+ public void setHeader (HeaderRecord newHeader)
+ {
+ _header = newHeader;
+ }
+
+ /**
+ * Returns the FooterRecord.
+ * @return FooterRecord for the sheet.
+ */
+ public FooterRecord getFooter ()
+ {
+ return _footer;
+ }
+
+ /**
+ * Sets the FooterRecord.
+ * @param newFooter The new FooterRecord for the sheet.
+ */
+ public void setFooter (FooterRecord newFooter)
+ {
+ _footer = newFooter;
+ }
+
+ /**
+ * Returns the PrintSetupRecord.
+ * @return PrintSetupRecord for the sheet.
+ */
+ public PrintSetupRecord getPrintSetup ()
+ {
+ return _printSetup;
+ }
+
+ /**
+ * Sets the PrintSetupRecord.
+ * @param newPrintSetup The new PrintSetupRecord for the sheet.
+ */
+ public void setPrintSetup (PrintSetupRecord newPrintSetup)
+ {
+ _printSetup = newPrintSetup;
+ }
+
+
+ private Margin getMarginRec(int marginIndex) {
+ switch (marginIndex) {
+ case InternalSheet.LeftMargin: return _leftMargin;
+ case InternalSheet.RightMargin: return _rightMargin;
+ case InternalSheet.TopMargin: return _topMargin;
+ case InternalSheet.BottomMargin: return _bottomMargin;
+ }
+ throw new IllegalArgumentException( "Unknown margin constant: " + marginIndex );
+ }
+
+
+ /**
+ * Gets the size of the margin in inches.
+ * @param margin which margin to get
+ * @return the size of the margin
+ */
+ public double getMargin(short margin) {
+ Margin m = getMarginRec(margin);
+ if (m != null) {
+ return m.getMargin();
+ }
+ switch (margin) {
+ case InternalSheet.LeftMargin: return .75;
+ case InternalSheet.RightMargin: return .75;
+ case InternalSheet.TopMargin: return 1.0;
+ case InternalSheet.BottomMargin: return 1.0;
+ }
+ throw new IllegalArgumentException( "Unknown margin constant: " + margin );
+ }
+
+ /**
+ * Sets the size of the margin in inches.
+ * @param margin which margin to get
+ * @param size the size of the margin
+ */
+ public void setMargin(short margin, double size) {
+ Margin m = getMarginRec(margin);
+ if (m == null) {
+ switch (margin) {
+ case InternalSheet.LeftMargin:
+ _leftMargin = new LeftMarginRecord();
+ m = _leftMargin;
+ break;
+ case InternalSheet.RightMargin:
+ _rightMargin = new RightMarginRecord();
+ m = _rightMargin;
+ break;
+ case InternalSheet.TopMargin:
+ _topMargin = new TopMarginRecord();
+ m = _topMargin;
+ break;
+ case InternalSheet.BottomMargin:
+ _bottomMargin = new BottomMarginRecord();
+ m = _bottomMargin;
+ break;
+ default :
+ throw new IllegalArgumentException( "Unknown margin constant: " + margin );
+ }
+ }
+ m.setMargin( size );
+ }
+
+ /**
+ * Shifts all the page breaks in the range "count" number of rows/columns
+ * @param breaks The page record to be shifted
+ * @param start Starting "main" value to shift breaks
+ * @param stop Ending "main" value to shift breaks
+ * @param count number of units (rows/columns) to shift by
+ */
+ private static void shiftBreaks(PageBreakRecord breaks, int start, int stop, int count) {
+
+ Iterator<PageBreakRecord.Break> iterator = breaks.getBreaksIterator();
+ List<PageBreakRecord.Break> shiftedBreak = new ArrayList<PageBreakRecord.Break>();
+ while(iterator.hasNext())
+ {
+ PageBreakRecord.Break breakItem = iterator.next();
+ int breakLocation = breakItem.main;
+ boolean inStart = (breakLocation >= start);
+ boolean inEnd = (breakLocation <= stop);
+ if(inStart && inEnd)
+ shiftedBreak.add(breakItem);
+ }
+
+ iterator = shiftedBreak.iterator();
+ while (iterator.hasNext()) {
+ PageBreakRecord.Break breakItem = iterator.next();
+ breaks.removeBreak(breakItem.main);
+ breaks.addBreak((short)(breakItem.main+count), breakItem.subFrom, breakItem.subTo);
+ }
+ }
+
+
+ /**
+ * Sets a page break at the indicated row
+ * @param row
+ */
+ public void setRowBreak(int row, short fromCol, short toCol) {
+ getRowBreaksRecord().addBreak((short)row, fromCol, toCol);
+ }
+
+ /**
+ * Removes a page break at the indicated row
+ * @param row
+ */
+ public void removeRowBreak(int row) {
+ if (getRowBreaksRecord().getBreaks().length < 1)
+ throw new IllegalArgumentException("Sheet does not define any row breaks");
+ getRowBreaksRecord().removeBreak((short)row);
+ }
+
+ /**
+ * Queries if the specified row has a page break
+ * @param row
+ * @return true if the specified row has a page break
+ */
+ public boolean isRowBroken(int row) {
+ return getRowBreaksRecord().getBreak(row) != null;
+ }
+
+
+ /**
+ * Queries if the specified column has a page break
+ *
+ * @return <code>true</code> if the specified column has a page break
+ */
+ public boolean isColumnBroken(int column) {
+ return getColumnBreaksRecord().getBreak(column) != null;
+ }
+
+ /**
+ * Shifts the horizontal page breaks for the indicated count
+ * @param startingRow
+ * @param endingRow
+ * @param count
+ */
+ public void shiftRowBreaks(int startingRow, int endingRow, int count) {
+ shiftBreaks(getRowBreaksRecord(), startingRow, endingRow, count);
+ }
+
+ /**
+ * Shifts the vertical page breaks for the indicated count
+ * @param startingCol
+ * @param endingCol
+ * @param count
+ */
+ public void shiftColumnBreaks(short startingCol, short endingCol, short count) {
+ shiftBreaks(getColumnBreaksRecord(), startingCol, endingCol, count);
+ }
+
+ /**
+ * @return all the horizontal page breaks, never <code>null</code>
+ */
+ public int[] getRowBreaks() {
+ return getRowBreaksRecord().getBreaks();
+ }
+
+ /**
+ * @return the number of row page breaks
+ */
+ public int getNumRowBreaks(){
+ return getRowBreaksRecord().getNumBreaks();
+ }
+
+ /**
+ * @return all the column page breaks, never <code>null</code>
+ */
+ public int[] getColumnBreaks(){
+ return getColumnBreaksRecord().getBreaks();
+ }
+
+ /**
+ * @return the number of column page breaks
+ */
+ public int getNumColumnBreaks(){
+ return getColumnBreaksRecord().getNumBreaks();
+ }
+
+ public VCenterRecord getVCenter() {
+ return _vCenter;
+ }
+
+ public HCenterRecord getHCenter() {
+ return _hCenter;
+ }
+
+ /**
+ * HEADERFOOTER is new in 2007. Some apps seem to have scattered this record long after
+ * the {@link PageSettingsBlock} where it belongs.
+ */
+ public void addLateHeaderFooter(HeaderFooterRecord rec) {
+ if (_headerFooter != null) {
+ throw new IllegalStateException("This page settings block already has a header/footer record");
+ }
+ if (rec.getSid() != HeaderFooterRecord.sid) {
+ throw new RecordFormatException("Unexpected header-footer record sid: 0x" + Integer.toHexString(rec.getSid()));
+ }
+ _headerFooter = rec;
+ }
+
+ /**
+ * This method reads PageSettingsBlock records from the supplied RecordStream until the first
+ * non-PageSettingsBlock record is encountered. As each record is read, it is incorporated
+ * into this PageSettingsBlock.
+ * <p/>
+ * The latest Excel version seems to write the PageSettingsBlock uninterrupted. However there
+ * are several examples (that Excel reads OK) where these records are not written together:
+ * <ul>
+ * <li><b>HEADER_FOOTER(0x089C) after WINDOW2</b> - This record is new in 2007. Some apps
+ * seem to have scattered this record long after the PageSettingsBlock where it belongs
+ * test samples: SharedFormulaTest.xls, ex44921-21902.xls, ex42570-20305.xls</li>
+ * <li><b>PLS, WSBOOL, PageSettingsBlock</b> - WSBOOL is not a PSB record.
+ * This happens in the test sample file "NoGutsRecords.xls" and "WORKBOOK_in_capitals.xls"</li>
+ * <li><b>Margins after DIMENSION</b> - All of PSB should be before DIMENSION. (Bug-47199)</li>
+ * </ul>
+ * These were probably written by other applications (or earlier versions of Excel). It was
+ * decided to not write specific code for detecting each of these cases. POI now tolerates
+ * PageSettingsBlock records scattered all over the sheet record stream, and in any order, but
+ * does not allow duplicates of any of those records.
+ *
+ * <p/>
+ * <b>Note</b> - when POI writes out this PageSettingsBlock, the records will always be written
+ * in one consolidated block (in the standard ordering) regardless of how scattered the records
+ * were when they were originally read.
+ *
+ * @throws RecordFormatException if any PSB record encountered has the same type (sid) as
+ * a record that is already part of this PageSettingsBlock
+ */
+ public void addLateRecords(RecordStream rs) {
+ while(true) {
+ if (!readARecord(rs)) {
+ break;
+ }
+ }
+ }
/**
* Some apps can define multiple HeaderFooterRecord records for a sheet.
@@ -652,26 +654,31 @@ public final class PageSettingsBlock extends RecordAggregate {
// Take a copy to loop over, so we can update the real one
// without concurrency issues
List<HeaderFooterRecord> hfRecordsToIterate = new ArrayList<HeaderFooterRecord>(_sviewHeaderFooters);
-
+
+ final Map<String, HeaderFooterRecord> hfGuidMap = new HashMap<String, HeaderFooterRecord>();
+
+ for(final HeaderFooterRecord hf : hfRecordsToIterate) {
+ hfGuidMap.put(HexDump.toHex(hf.getGuid()), hf);
+ }
+
// loop through HeaderFooterRecord records having not-empty GUID and match them with
// CustomViewSettingsRecordAggregate blocks having UserSViewBegin with the same GUID
- for(final HeaderFooterRecord hf : hfRecordsToIterate) {
- for (RecordBase rb : sheetRecords) {
- if (rb instanceof CustomViewSettingsRecordAggregate) {
- final CustomViewSettingsRecordAggregate cv = (CustomViewSettingsRecordAggregate) rb;
- cv.visitContainedRecords(new RecordVisitor() {
- public void visitRecord(Record r) {
- if (r.getSid() == UserSViewBegin.sid) {
- byte[] guid1 = ((UserSViewBegin) r).getGuid();
- byte[] guid2 = hf.getGuid();
- if (Arrays.equals(guid1, guid2)) {
- cv.append(hf);
- _sviewHeaderFooters.remove(hf);
- }
+ for (RecordBase rb : sheetRecords) {
+ if (rb instanceof CustomViewSettingsRecordAggregate) {
+ final CustomViewSettingsRecordAggregate cv = (CustomViewSettingsRecordAggregate) rb;
+ cv.visitContainedRecords(new RecordVisitor() {
+ public void visitRecord(Record r) {
+ if (r.getSid() == UserSViewBegin.sid) {
+ String guid = HexDump.toHex(((UserSViewBegin) r).getGuid());
+ HeaderFooterRecord hf = hfGuidMap.get(guid);
+
+ if (hf != null) {
+ cv.append(hf);
+ _sviewHeaderFooters.remove(hf);
}
}
- });
- }
+ }
+ });
}
}
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java
index 9309bd7165..d6d041430b 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java
@@ -200,6 +200,18 @@ public final class HSSFName implements Name {
return HSSFFormulaParser.toFormulaString(_book, ptgs);
}
+
+ /**
+ * Sets the NameParsedFormula structure that specifies the formula for the
+ * defined name.
+ *
+ * @param ptgs the sequence of {@link Ptg}s for the formula.
+ */
+ void setNameDefinition(Ptg[] ptgs) {
+ _definedNameRec.setNameDefinition(ptgs);
+ }
+
+
public boolean isDeleted(){
Ptg[] ptgs = _definedNameRec.getNameDefinition();
return Ptg.doesFormulaReferToDeletedCell(ptgs);
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java
index 0516cccf6b..69bdae1521 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java
@@ -22,6 +22,7 @@ import org.apache.poi.ddf.EscherBitmapBlip;
import org.apache.poi.ddf.EscherBlipRecord;
import org.apache.poi.ddf.EscherMetafileBlip;
import org.apache.poi.ss.usermodel.PictureData;
+import org.apache.poi.util.PngUtils;
/**
* Represents binary data stored in the file. Eg. A GIF, JPEG etc...
@@ -60,7 +61,18 @@ public class HSSFPictureData implements PictureData
*/
public byte[] getData()
{
- return blip.getPicturedata();
+ byte[] pictureData = blip.getPicturedata();
+
+ //PNG created on MAC may have a 16-byte prefix which prevents successful reading.
+ //Just cut it off!.
+ if (PngUtils.matchesPngHeader(pictureData, 16))
+ {
+ byte[] png = new byte[pictureData.length-16];
+ System.arraycopy(pictureData, 16, png, 0, png.length);
+ pictureData = png;
+ }
+
+ return pictureData;
}
/**
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
index f0ec2d6804..bb3c92ced0 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
@@ -33,8 +33,10 @@ import org.apache.poi.hssf.record.aggregates.DataValidityTable;
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock;
import org.apache.poi.ss.formula.FormulaShifter;
+import org.apache.poi.ss.formula.ptg.MemFuncPtg;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.ptg.Area3DPtg;
+import org.apache.poi.ss.formula.ptg.UnionPtg;
import org.apache.poi.hssf.util.PaneInformation;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.formula.FormulaType;
@@ -371,6 +373,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* Creates a data validation object
+ *
* @param dataValidation The Data validation object settings
*/
public void addValidationData(DataValidation dataValidation) {
@@ -522,6 +525,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* get the default row height for the sheet (if the rows do not define their own height) in
* twips (1/20 of a point)
+ *
* @return default row height
*/
public short getDefaultRowHeight() {
@@ -531,6 +535,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* get the default row height for the sheet (if the rows do not define their own height) in
* points.
+ *
* @return default row height in points
*/
@@ -813,6 +818,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* used internally in the API to get the low level Sheet record represented by this
* Object.
+ *
* @return Sheet - low level representation of this HSSFSheet.
*/
InternalSheet getSheet() {
@@ -821,6 +827,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* whether alternate expression evaluation is on
+ *
* @param b alternative expression evaluation or not
*/
public void setAlternativeExpression(boolean b) {
@@ -832,6 +839,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* whether alternative formula entry is on
+ *
* @param b alternative formulas or not
*/
public void setAlternativeFormula(boolean b) {
@@ -843,6 +851,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* show automatic page breaks or not
+ *
* @param b whether to show auto page breaks
*/
public void setAutobreaks(boolean b) {
@@ -854,6 +863,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* set whether sheet is a dialog sheet or not
+ *
* @param b isDialog or not
*/
public void setDialog(boolean b) {
@@ -877,6 +887,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* fit to page option is on
+ *
* @param b fit or not
*/
public void setFitToPage(boolean b) {
@@ -888,6 +899,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* set if row summaries appear below detail in the outline
+ *
* @param b below or not
*/
public void setRowSumsBelow(boolean b) {
@@ -901,6 +913,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* set if col summaries appear right of the detail in the outline
+ *
* @param b right or not
*/
public void setRowSumsRight(boolean b) {
@@ -912,6 +925,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* whether alternate expression evaluation is on
+ *
* @return alternative expression evaluation or not
*/
public boolean getAlternateExpression() {
@@ -921,6 +935,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* whether alternative formula entry is on
+ *
* @return alternative formulas or not
*/
public boolean getAlternateFormula() {
@@ -930,6 +945,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* show automatic page breaks or not
+ *
* @return whether to show auto page breaks
*/
public boolean getAutobreaks() {
@@ -939,6 +955,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* get whether sheet is a dialog sheet or not
+ *
* @return isDialog or not
*/
public boolean getDialog() {
@@ -963,6 +980,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
* <p>
* In Excel 2003 this option can be changed in the Options dialog on the View tab.
* </p>
+ *
* @return whether all zero values on the worksheet are displayed
*/
public boolean isDisplayZeros() {
@@ -975,6 +993,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
* <p>
* In Excel 2003 this option can be set in the Options dialog on the View tab.
* </p>
+ *
* @param value whether to display or hide all zero values on the worksheet
*/
public void setDisplayZeros(boolean value) {
@@ -983,6 +1002,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* fit to page option is on
+ *
* @return fit or not
*/
public boolean getFitToPage() {
@@ -992,6 +1012,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* get if row summaries appear below detail in the outline
+ *
* @return below or not
*/
public boolean getRowSumsBelow() {
@@ -1001,6 +1022,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* get if col summaries appear right of the detail in the outline
+ *
* @return right or not
*/
public boolean getRowSumsRight() {
@@ -1010,6 +1032,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* Returns whether gridlines are printed.
+ *
* @return Gridlines are printed
*/
public boolean isPrintGridlines() {
@@ -1018,8 +1041,9 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* Turns on or off the printing of gridlines.
+ *
* @param newPrintGridlines boolean to turn on or off the printing of
- * gridlines
+ * gridlines
*/
public void setPrintGridlines(boolean newPrintGridlines) {
getSheet().getPrintGridlines().setPrintGridlines(newPrintGridlines);
@@ -1027,6 +1051,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
/**
* Gets the print setup object.
+ *
* @return The user model for the print setup object.
*/
public HSSFPrintSetup getPrintSetup() {
@@ -1799,10 +1824,9 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
return new HSSFPatriarch(this, agg);
}
- /**
- * @deprecated (Sep 2008) use {@link #setColumnGroupCollapsed(int, boolean)}
- */
-
+ /**
+ * @deprecated (Sep 2008) use {@link #setColumnGroupCollapsed(int, boolean)}
+ */
public void setColumnGroupCollapsed(short columnNumber, boolean collapsed) {
setColumnGroupCollapsed(columnNumber & 0xFFFF, collapsed);
}
@@ -2070,4 +2094,160 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
}
return null;
}
+
+
+ public CellRangeAddress getRepeatingRows() {
+ return getRepeatingRowsOrColums(true);
+ }
+
+
+ public CellRangeAddress getRepeatingColumns() {
+ return getRepeatingRowsOrColums(false);
+ }
+
+
+ public void setRepeatingRows(CellRangeAddress rowRangeRef) {
+ CellRangeAddress columnRangeRef = getRepeatingColumns();
+ setRepeatingRowsAndColumns(rowRangeRef, columnRangeRef);
+ }
+
+
+ public void setRepeatingColumns(CellRangeAddress columnRangeRef) {
+ CellRangeAddress rowRangeRef = getRepeatingRows();
+ setRepeatingRowsAndColumns(rowRangeRef, columnRangeRef);
+ }
+
+
+ private void setRepeatingRowsAndColumns(
+ CellRangeAddress rowDef, CellRangeAddress colDef) {
+ int sheetIndex = _workbook.getSheetIndex(this);
+ int maxRowIndex = SpreadsheetVersion.EXCEL97.getLastRowIndex();
+ int maxColIndex = SpreadsheetVersion.EXCEL97.getLastColumnIndex();
+
+ int col1 = -1;
+ int col2 = -1;
+ int row1 = -1;
+ int row2 = -1;
+
+ if (rowDef != null) {
+ row1 = rowDef.getFirstRow();
+ row2 = rowDef.getLastRow();
+ if ((row1 == -1 && row2 != -1) || (row1 > row2)
+ || (row1 < 0 || row1 > maxRowIndex)
+ || (row2 < 0 || row2 > maxRowIndex)) {
+ throw new IllegalArgumentException("Invalid row range specification");
+ }
+ }
+ if (colDef != null) {
+ col1 = colDef.getFirstColumn();
+ col2 = colDef.getLastColumn();
+ if ((col1 == -1 && col2 != -1) || (col1 > col2)
+ || (col1 < 0 || col1 > maxColIndex)
+ || (col2 < 0 || col2 > maxColIndex)) {
+ throw new IllegalArgumentException("Invalid column range specification");
+ }
+ }
+
+ short externSheetIndex =
+ _workbook.getWorkbook().checkExternSheet(sheetIndex);
+
+ boolean setBoth = rowDef != null && colDef != null;
+ boolean removeAll = rowDef == null && colDef == null;
+
+ HSSFName name = _workbook.getBuiltInName(
+ NameRecord.BUILTIN_PRINT_TITLE, sheetIndex);
+ if (removeAll) {
+ if (name != null) {
+ _workbook.removeName(name);
+ }
+ return;
+ }
+ if (name == null) {
+ name = _workbook.createBuiltInName(
+ NameRecord.BUILTIN_PRINT_TITLE, sheetIndex);
+ }
+
+ List<Ptg> ptgList = new ArrayList<Ptg>();
+ if (setBoth) {
+ final int exprsSize = 2 * 11 + 1; // 2 * Area3DPtg.SIZE + UnionPtg.SIZE
+ ptgList.add(new MemFuncPtg(exprsSize));
+ }
+ if (colDef != null) {
+ Area3DPtg colArea = new Area3DPtg(0, maxRowIndex, col1, col2,
+ false, false, false, false, externSheetIndex);
+ ptgList.add(colArea);
+ }
+ if (rowDef != null) {
+ Area3DPtg rowArea = new Area3DPtg(row1, row2, 0, maxColIndex,
+ false, false, false, false, externSheetIndex);
+ ptgList.add(rowArea);
+ }
+ if (setBoth) {
+ ptgList.add(UnionPtg.instance);
+ }
+
+ Ptg[] ptgs = new Ptg[ptgList.size()];
+ ptgList.toArray(ptgs);
+ name.setNameDefinition(ptgs);
+
+ HSSFPrintSetup printSetup = getPrintSetup();
+ printSetup.setValidSettings(false);
+ setActive(true);
+ }
+
+
+ private CellRangeAddress getRepeatingRowsOrColums(boolean rows) {
+ NameRecord rec = getBuiltinNameRecord(NameRecord.BUILTIN_PRINT_TITLE);
+ if (rec == null) {
+ return null;
+ }
+
+ Ptg[] nameDefinition = rec.getNameDefinition();
+ if (nameDefinition == null) {
+ return null;
+ }
+
+ int maxRowIndex = SpreadsheetVersion.EXCEL97.getLastRowIndex();
+ int maxColIndex = SpreadsheetVersion.EXCEL97.getLastColumnIndex();
+
+ for (Ptg ptg : nameDefinition) {
+
+ if (ptg instanceof Area3DPtg) {
+ Area3DPtg areaPtg = (Area3DPtg) ptg;
+
+ if (areaPtg.getFirstColumn() == 0
+ && areaPtg.getLastColumn() == maxColIndex) {
+ if (rows) {
+ CellRangeAddress rowRange = new CellRangeAddress(
+ areaPtg.getFirstRow(), areaPtg.getLastRow(), -1, -1);
+ return rowRange;
+ }
+ } else if (areaPtg.getFirstRow() == 0
+ && areaPtg.getLastRow() == maxRowIndex) {
+ if (!rows) {
+ CellRangeAddress columnRange = new CellRangeAddress(-1, -1,
+ areaPtg.getFirstColumn(), areaPtg.getLastColumn());
+ return columnRange;
+ }
+ }
+
+ }
+
+ }
+
+ return null;
+ }
+
+
+ private NameRecord getBuiltinNameRecord(byte builtinCode) {
+ int sheetIndex = _workbook.getSheetIndex(this);
+ int recIndex =
+ _workbook.findExistingBuiltinNameRecordIdx(sheetIndex, builtinCode);
+ if (recIndex == -1) {
+ return null;
+ }
+ return _workbook.getNameRecord(recIndex);
+ }
+
+
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index cc6e40c271..f1828fa387 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -49,13 +49,10 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.ss.formula.SheetNameFormatter;
-import org.apache.poi.ss.formula.ptg.Area3DPtg;
-import org.apache.poi.ss.formula.ptg.MemFuncPtg;
-import org.apache.poi.ss.formula.ptg.Ptg;
-import org.apache.poi.ss.formula.ptg.UnionPtg;
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
+import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.WorkbookUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@@ -75,8 +72,6 @@ import org.apache.commons.codec.digest.DigestUtils;
*/
public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook {
private static final Pattern COMMA_PATTERN = Pattern.compile(",");
- private static final int MAX_ROW = 0xFFFF;
- private static final short MAX_COLUMN = (short)0x00FF;
/**
* The maximum number of cell styles in a .xls workbook.
@@ -957,84 +952,31 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
* @param endColumn 0 based end of repeating columns.
* @param startRow 0 based start of repeating rows.
* @param endRow 0 based end of repeating rows.
+ *
+ * @deprecated use {@link HSSFSheet#setRepeatingRows(CellRangeAddress)}
+ * or {@link HSSFSheet#setRepeatingColumns(CellRangeAddress)}
*/
public void setRepeatingRowsAndColumns(int sheetIndex,
int startColumn, int endColumn,
- int startRow, int endRow)
- {
- // Check arguments
- if (startColumn == -1 && endColumn != -1) throw new IllegalArgumentException("Invalid column range specification");
- if (startRow == -1 && endRow != -1) throw new IllegalArgumentException("Invalid row range specification");
- if (startColumn < -1 || startColumn >= MAX_COLUMN) throw new IllegalArgumentException("Invalid column range specification");
- if (endColumn < -1 || endColumn >= MAX_COLUMN) throw new IllegalArgumentException("Invalid column range specification");
- if (startRow < -1 || startRow > MAX_ROW) throw new IllegalArgumentException("Invalid row range specification");
- if (endRow < -1 || endRow > MAX_ROW) throw new IllegalArgumentException("Invalid row range specification");
- if (startColumn > endColumn) throw new IllegalArgumentException("Invalid column range specification");
- if (startRow > endRow) throw new IllegalArgumentException("Invalid row range specification");
-
- HSSFSheet sheet = getSheetAt(sheetIndex);
- short externSheetIndex = getWorkbook().checkExternSheet(sheetIndex);
-
- boolean settingRowAndColumn =
- startColumn != -1 && endColumn != -1 && startRow != -1 && endRow != -1;
- boolean removingRange =
- startColumn == -1 && endColumn == -1 && startRow == -1 && endRow == -1;
-
- int rowColHeaderNameIndex = findExistingBuiltinNameRecordIdx(sheetIndex, NameRecord.BUILTIN_PRINT_TITLE);
- if (removingRange) {
- if (rowColHeaderNameIndex >= 0) {
- workbook.removeName(rowColHeaderNameIndex);
- }
- return;
- }
- boolean isNewRecord;
- NameRecord nameRecord;
- if (rowColHeaderNameIndex < 0) {
- //does a lot of the house keeping for builtin records, like setting lengths to zero etc
- nameRecord = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_TITLE, sheetIndex+1);
- isNewRecord = true;
- } else {
- nameRecord = workbook.getNameRecord(rowColHeaderNameIndex);
- isNewRecord = false;
- }
-
- List temp = new ArrayList();
-
- if (settingRowAndColumn) {
- final int exprsSize = 2 * 11 + 1; // 2 * Area3DPtg.SIZE + UnionPtg.SIZE
- temp.add(new MemFuncPtg(exprsSize));
- }
- if (startColumn >= 0) {
- Area3DPtg colArea = new Area3DPtg(0, MAX_ROW, startColumn, endColumn,
- false, false, false, false, externSheetIndex);
- temp.add(colArea);
- }
- if (startRow >= 0) {
- Area3DPtg rowArea = new Area3DPtg(startRow, endRow, 0, MAX_COLUMN,
- false, false, false, false, externSheetIndex);
- temp.add(rowArea);
- }
- if (settingRowAndColumn) {
- temp.add(UnionPtg.instance);
- }
- Ptg[] ptgs = new Ptg[temp.size()];
- temp.toArray(ptgs);
- nameRecord.setNameDefinition(ptgs);
+ int startRow, int endRow) {
+ HSSFSheet sheet = getSheetAt(sheetIndex);
- if (isNewRecord)
- {
- HSSFName newName = new HSSFName(this, nameRecord, nameRecord.isBuiltInName() ? null : workbook.getNameCommentRecord(nameRecord));
- names.add(newName);
- }
+ CellRangeAddress rows = null;
+ CellRangeAddress cols = null;
- HSSFPrintSetup printSetup = sheet.getPrintSetup();
- printSetup.setValidSettings(false);
+ if (startRow != -1) {
+ rows = new CellRangeAddress(startRow, endRow, -1, -1);
+ }
+ if (startColumn != -1) {
+ cols = new CellRangeAddress(-1, -1, startColumn, endColumn);
+ }
- sheet.setActive(true);
+ sheet.setRepeatingRows(rows);
+ sheet.setRepeatingColumns(cols);
}
- private int findExistingBuiltinNameRecordIdx(int sheetIndex, byte builtinCode) {
+ int findExistingBuiltinNameRecordIdx(int sheetIndex, byte builtinCode) {
for(int defNameIndex =0; defNameIndex<names.size(); defNameIndex++) {
NameRecord r = workbook.getNameRecord(defNameIndex);
if (r == null) {
@@ -1050,6 +992,26 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
return -1;
}
+
+ HSSFName createBuiltInName(byte builtinCode, int sheetIndex) {
+ NameRecord nameRecord =
+ workbook.createBuiltInName(builtinCode, sheetIndex + 1);
+ HSSFName newName = new HSSFName(this, nameRecord, null);
+ names.add(newName);
+ return newName;
+ }
+
+
+ HSSFName getBuiltInName(byte builtinCode, int sheetIndex) {
+ int index = findExistingBuiltinNameRecordIdx(sheetIndex, builtinCode);
+ if (index < 0) {
+ return null;
+ } else {
+ return names.get(index);
+ }
+ }
+
+
/**
* create a new Font and add it to the workbook's font table
* @return new font object
@@ -1477,6 +1439,25 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
}
+ /**
+ * As {@link #getNameIndex(String)} is not necessarily unique
+ * (name + sheet index is unique), this method is more accurate.
+ *
+ * @param name the name whose index in the list of names of this workbook
+ * should be looked up.
+ * @return an index value >= 0 if the name was found; -1, if the name was
+ * not found
+ */
+ int getNameIndex(HSSFName name) {
+ for (int k = 0; k < names.size(); k++) {
+ if (name == names.get(k)) {
+ return k;
+ }
+ }
+ return -1;
+ }
+
+
public void removeName(int index){
names.remove(index);
workbook.removeName(index);
@@ -1497,10 +1478,21 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
public void removeName(String name) {
int index = getNameIndex(name);
-
removeName(index);
}
+
+ /**
+ * As {@link #removeName(String)} is not necessarily unique
+ * (name + sheet index is unique), this method is more accurate.
+ *
+ * @param name the name to remove.
+ */
+ void removeName(HSSFName name) {
+ int index = getNameIndex(name);
+ removeName(index);
+ }
+
public HSSFPalette getCustomPalette()
{
return new HSSFPalette(workbook.getCustomPalette());
diff --git a/src/java/org/apache/poi/ss/format/CellDateFormatter.java b/src/java/org/apache/poi/ss/format/CellDateFormatter.java
index 33a9118b15..e45fa267df 100644
--- a/src/java/org/apache/poi/ss/format/CellDateFormatter.java
+++ b/src/java/org/apache/poi/ss/format/CellDateFormatter.java
@@ -150,7 +150,10 @@ public class CellDateFormatter extends CellFormatter {
StringBuffer descBuf = CellFormatPart.parseFormat(format,
CellFormatType.DATE, partHandler);
partHandler.finish(descBuf);
- dateFmt = new SimpleDateFormat(descBuf.toString());
+ // tweak the format pattern to pass tests on JDK 1.7,
+ // See https://issues.apache.org/bugzilla/show_bug.cgi?id=53369
+ String ptrn = descBuf.toString().replaceAll("((y)(?!y))(?<!yy)", "yy");
+ dateFmt = new SimpleDateFormat(ptrn, LOCALE);
}
/** {@inheritDoc} */
@@ -214,4 +217,4 @@ public class CellDateFormatter extends CellFormatter {
public void simpleValue(StringBuffer toAppendTo, Object value) {
SIMPLE_DATE.formatValue(toAppendTo, value);
}
-} \ No newline at end of file
+}
diff --git a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
index 4e45a76a39..79676d6a07 100644
--- a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
+++ b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
@@ -637,10 +637,10 @@ public final class WorkbookEvaluator {
* YK: Used by OperationEvaluationContext to resolve indirect names.
*/
/*package*/ ValueEval evaluateNameFormula(Ptg[] ptgs, OperationEvaluationContext ec) {
- if (ptgs.length > 1) {
- throw new RuntimeException("Complex name formulas not supported yet");
- }
- return getEvalForPtg(ptgs[0], ec);
+ if (ptgs.length == 1) {
+ return getEvalForPtg(ptgs[0], ec);
+ }
+ return evaluateFormula(ec, ptgs);
}
/**
diff --git a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java
index 3f09aafa2b..cfa20914f8 100644
--- a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java
+++ b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java
@@ -111,8 +111,11 @@ public class DataFormatter {
/** Pattern to find "AM/PM" marker */
private static final Pattern amPmPattern = Pattern.compile("((A|P)[M/P]*)", Pattern.CASE_INSENSITIVE);
- /** A regex to find patterns like [$$-1009] and [$?-452]. */
- private static final Pattern specialPatternGroup = Pattern.compile("(\\[\\$[^-\\]]*-[0-9A-Z]+\\])");
+ /**
+ * A regex to find locale patterns like [$$-1009] and [$?-452].
+ * Note that we don't currently process these into locales
+ */
+ private static final Pattern localePatternGroup = Pattern.compile("(\\[\\$[^-\\]]*-[0-9A-Z]+\\])");
/**
* A regex to match the colour formattings rules.
@@ -278,12 +281,16 @@ public class DataFormatter {
if (format != null) {
return format;
}
+
+ // Is it one of the special built in types, General or @?
if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) {
if (isWholeNumber(cellValue)) {
return generalWholeNumFormat;
}
return generalDecimalNumFormat;
}
+
+ // Build a formatter, and cache it
format = createFormat(cellValue, formatIndex, formatStr);
formats.put(formatStr, format);
return format;
@@ -323,8 +330,8 @@ public class DataFormatter {
colourM = colorPattern.matcher(formatStr);
}
- // try to extract special characters like currency
- Matcher m = specialPatternGroup.matcher(formatStr);
+ // Strip off the locale information, we use an instance-wide locale for everything
+ Matcher m = localePatternGroup.matcher(formatStr);
while(m.find()) {
String match = m.group();
String symbol = match.substring(match.indexOf('$') + 1, match.indexOf('-'));
@@ -336,12 +343,20 @@ public class DataFormatter {
symbol = sb.toString();
}
formatStr = m.replaceAll(symbol);
- m = specialPatternGroup.matcher(formatStr);
+ m = localePatternGroup.matcher(formatStr);
}
+ // Check for special cases
if(formatStr == null || formatStr.trim().length() == 0) {
return getDefaultFormat(cellValue);
}
+
+ if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) {
+ if (isWholeNumber(cellValue)) {
+ return generalWholeNumFormat;
+ }
+ return generalDecimalNumFormat;
+ }
if(DateUtil.isADateFormat(formatIndex,formatStr) &&
DateUtil.isValidExcelDate(cellValue)) {
diff --git a/src/java/org/apache/poi/ss/usermodel/Sheet.java b/src/java/org/apache/poi/ss/usermodel/Sheet.java
index 5be4f1f5e6..8b6b41678f 100644
--- a/src/java/org/apache/poi/ss/usermodel/Sheet.java
+++ b/src/java/org/apache/poi/ss/usermodel/Sheet.java
@@ -927,4 +927,95 @@ public interface Sheet extends Iterable<Row> {
*/
SheetConditionalFormatting getSheetConditionalFormatting();
+
+ /**
+ * Gets the repeating rows used when printing the sheet, as found in
+ * File->PageSetup->Sheet.
+ * <p/>
+ * Repeating rows cover a range of contiguous rows, e.g.:
+ * <pre>
+ * Sheet1!$1:$1
+ * Sheet2!$5:$8
+ * </pre>
+ * The {@link CellRangeAddress} returned contains a column part which spans
+ * all columns, and a row part which specifies the contiguous range of
+ * repeating rows.
+ * <p/>
+ * If the Sheet does not have any repeating rows defined, null is returned.
+ *
+ * @return an {@link CellRangeAddress} containing the repeating rows for the
+ * Sheet, or null.
+ */
+ CellRangeAddress getRepeatingRows();
+
+
+ /**
+ * Gets the repeating columns used when printing the sheet, as found in
+ * File->PageSetup->Sheet.
+ * <p/>
+ * Repeating columns cover a range of contiguous columns, e.g.:
+ * <pre>
+ * Sheet1!$A:$A
+ * Sheet2!$C:$F
+ * </pre>
+ * The {@link CellRangeAddress} returned contains a row part which spans all
+ * rows, and a column part which specifies the contiguous range of
+ * repeating columns.
+ * <p/>
+ * If the Sheet does not have any repeating columns defined, null is
+ * returned.
+ *
+ * @return an {@link CellRangeAddress} containing the repeating columns for
+ * the Sheet, or null.
+ */
+ CellRangeAddress getRepeatingColumns();
+
+
+ /**
+ * Sets the repeating rows used when printing the sheet, as found in
+ * File->PageSetup->Sheet.
+ * <p/>
+ * Repeating rows cover a range of contiguous rows, e.g.:
+ * <pre>
+ * Sheet1!$1:$1
+ * Sheet2!$5:$8</pre>
+ * The parameter {@link CellRangeAddress} should specify a column part
+ * which spans all columns, and a row part which specifies the contiguous
+ * range of repeating rows, e.g.:
+ * <pre>
+ * sheet.setRepeatingRows(CellRangeAddress.valueOf("2:3"));</pre>
+ * A null parameter value indicates that repeating rows should be removed
+ * from the Sheet:
+ * <pre>
+ * sheet.setRepeatingRows(null);</pre>
+ *
+ * @param rowRangeRef a {@link CellRangeAddress} containing the repeating
+ * rows for the Sheet, or null.
+ */
+ void setRepeatingRows(CellRangeAddress rowRangeRef);
+
+
+ /**
+ * Sets the repeating columns used when printing the sheet, as found in
+ * File->PageSetup->Sheet.
+ * <p/>
+ * Repeating columns cover a range of contiguous columns, e.g.:
+ * <pre>
+ * Sheet1!$A:$A
+ * Sheet2!$C:$F</pre>
+ * The parameter {@link CellRangeAddress} should specify a row part
+ * which spans all rows, and a column part which specifies the contiguous
+ * range of repeating columns, e.g.:
+ * <pre>
+ * sheet.setRepeatingColumns(CellRangeAddress.valueOf("B:C"));</pre>
+ * A null parameter value indicates that repeating columns should be removed
+ * from the Sheet:
+ * <pre>
+ * sheet.setRepeatingColumns(null);</pre>
+ *
+ * @param columnRangeRef a {@link CellRangeAddress} containing the repeating
+ * columns for the Sheet, or null.
+ */
+ void setRepeatingColumns(CellRangeAddress columnRangeRef);
+
}
diff --git a/src/java/org/apache/poi/ss/usermodel/Workbook.java b/src/java/org/apache/poi/ss/usermodel/Workbook.java
index ce117f4cde..a476a74f8c 100644
--- a/src/java/org/apache/poi/ss/usermodel/Workbook.java
+++ b/src/java/org/apache/poi/ss/usermodel/Workbook.java
@@ -23,6 +23,7 @@ import java.util.List;
import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
+import org.apache.poi.ss.util.CellRangeAddress;
/**
* High level representation of a Excel workbook. This is the first object most users
@@ -284,6 +285,9 @@ public interface Workbook {
* @param endColumn 0 based end of repeating columns.
* @param startRow 0 based start of repeating rows.
* @param endRow 0 based end of repeating rows.
+ *
+ * @deprecated use {@link Sheet#setRepeatingRows(CellRangeAddress)}
+ * or {@link Sheet#setRepeatingColumns(CellRangeAddress)}
*/
void setRepeatingRowsAndColumns(int sheetIndex, int startColumn, int endColumn, int startRow, int endRow);
diff --git a/src/java/org/apache/poi/ss/util/CellRangeAddress.java b/src/java/org/apache/poi/ss/util/CellRangeAddress.java
index 4a44a6c8a5..b69476ea24 100644
--- a/src/java/org/apache/poi/ss/util/CellRangeAddress.java
+++ b/src/java/org/apache/poi/ss/util/CellRangeAddress.java
@@ -100,7 +100,10 @@ public class CellRangeAddress extends CellRangeAddressBase {
sb.append(cellRefFrom.formatAsString());
//for a single-cell reference return A1 instead of A1:A1
- if(!cellRefFrom.equals(cellRefTo)){
+ //for full-column ranges or full-row ranges return A:A instead of A,
+ //and 1:1 instead of 1
+ if(!cellRefFrom.equals(cellRefTo)
+ || isFullColumnRange() || isFullRowRange()){
sb.append(':');
sb.append(cellRefTo.formatAsString());
}
@@ -108,8 +111,12 @@ public class CellRangeAddress extends CellRangeAddressBase {
}
/**
- * @param ref usually a standard area ref (e.g. "B1:D8"). May be a single cell
- * ref (e.g. "B5") in which case the result is a 1 x 1 cell range.
+ * Creates a CellRangeAddress from a cell range reference string.
+ *
+ * @param ref usually a standard area ref (e.g. "B1:D8"). May be a single
+ * cell ref (e.g. "B5") in which case the result is a 1 x 1 cell
+ * range. May also be a whole row range (e.g. "3:5"), or a whole
+ * column range (e.g. "C:F")
*/
public static CellRangeAddress valueOf(String ref) {
int sep = ref.indexOf(":");
diff --git a/src/java/org/apache/poi/ss/util/CellRangeAddressBase.java b/src/java/org/apache/poi/ss/util/CellRangeAddressBase.java
index e8d9c9100a..12aaa6f629 100644
--- a/src/java/org/apache/poi/ss/util/CellRangeAddressBase.java
+++ b/src/java/org/apache/poi/ss/util/CellRangeAddressBase.java
@@ -76,11 +76,13 @@ public abstract class CellRangeAddressBase {
//TODO use the correct SpreadsheetVersion
public final boolean isFullColumnRange() {
- return _firstRow == 0 && _lastRow == SpreadsheetVersion.EXCEL97.getLastRowIndex();
+ return (_firstRow == 0 && _lastRow == SpreadsheetVersion.EXCEL97.getLastRowIndex())
+ || (_firstRow == -1 && _lastRow == -1);
}
//TODO use the correct SpreadsheetVersion
public final boolean isFullRowRange() {
- return _firstCol == 0 && _lastCol == SpreadsheetVersion.EXCEL97.getLastColumnIndex();
+ return (_firstCol == 0 && _lastCol == SpreadsheetVersion.EXCEL97.getLastColumnIndex())
+ || (_firstCol == -1 && _lastCol == -1);
}
/**
diff --git a/src/java/org/apache/poi/ss/util/CellReference.java b/src/java/org/apache/poi/ss/util/CellReference.java
index 12120b7489..f7c37e3005 100644
--- a/src/java/org/apache/poi/ss/util/CellReference.java
+++ b/src/java/org/apache/poi/ss/util/CellReference.java
@@ -91,25 +91,28 @@ public class CellReference {
String[] parts = separateRefParts(cellRef);
_sheetName = parts[0];
+
String colRef = parts[1];
- if (colRef.length() < 1) {
- throw new IllegalArgumentException("Invalid Formula cell reference: '"+cellRef+"'");
- }
- _isColAbs = colRef.charAt(0) == '$';
+ _isColAbs = (colRef.length() > 0) && colRef.charAt(0) == '$';
if (_isColAbs) {
- colRef=colRef.substring(1);
+ colRef = colRef.substring(1);
+ }
+ if (colRef.length() == 0) {
+ _colIndex = -1;
+ } else {
+ _colIndex = convertColStringToIndex(colRef);
}
- _colIndex = convertColStringToIndex(colRef);
String rowRef=parts[2];
- if (rowRef.length() < 1) {
- throw new IllegalArgumentException("Invalid Formula cell reference: '"+cellRef+"'");
- }
- _isRowAbs = rowRef.charAt(0) == '$';
+ _isRowAbs = (rowRef.length() > 0) && rowRef.charAt(0) == '$';
if (_isRowAbs) {
- rowRef=rowRef.substring(1);
+ rowRef = rowRef.substring(1);
+ }
+ if (rowRef.length() == 0) {
+ _rowIndex = -1;
+ } else {
+ _rowIndex = Integer.parseInt(rowRef)-1; // -1 to convert 1-based to zero-based
}
- _rowIndex = Integer.parseInt(rowRef)-1; // -1 to convert 1-based to zero-based
}
public CellReference(int pRow, int pCol) {
@@ -482,14 +485,18 @@ public class CellReference {
* Sheet name is not included.
*/
/* package */ void appendCellReference(StringBuffer sb) {
- if(_isColAbs) {
- sb.append(ABSOLUTE_REFERENCE_MARKER);
- }
- sb.append( convertNumToColString(_colIndex));
- if(_isRowAbs) {
- sb.append(ABSOLUTE_REFERENCE_MARKER);
+ if (_colIndex != -1) {
+ if(_isColAbs) {
+ sb.append(ABSOLUTE_REFERENCE_MARKER);
+ }
+ sb.append( convertNumToColString(_colIndex));
+ }
+ if (_rowIndex != -1) {
+ if(_isRowAbs) {
+ sb.append(ABSOLUTE_REFERENCE_MARKER);
+ }
+ sb.append(_rowIndex+1);
}
- sb.append(_rowIndex+1);
}
/**
diff --git a/src/java/org/apache/poi/util/LittleEndian.java b/src/java/org/apache/poi/util/LittleEndian.java
index c07c4beb30..6ceb12a4a1 100644
--- a/src/java/org/apache/poi/util/LittleEndian.java
+++ b/src/java/org/apache/poi/util/LittleEndian.java
@@ -724,6 +724,24 @@ public class LittleEndian implements LittleEndianConsts
}
return ( ch4 << 24 ) + ( ch3 << 16 ) + ( ch2 << 8 ) + ( ch1 << 0 );
}
+
+ /**
+ * get an unsigned int value from an InputStream
+ *
+ * @param stream
+ * the InputStream from which the int is to be read
+ * @return the unsigned int (32-bit) value
+ * @exception IOException
+ * will be propagated back to the caller
+ * @exception BufferUnderrunException
+ * if the stream cannot provide enough bytes
+ */
+ public static long readUInt( InputStream stream ) throws IOException,
+ BufferUnderrunException
+ {
+ long retNum = readInt(stream);
+ return retNum & 0x00FFFFFFFFl;
+ }
/**
* get a long value from an InputStream
diff --git a/src/java/org/apache/poi/util/PngUtils.java b/src/java/org/apache/poi/util/PngUtils.java
new file mode 100644
index 0000000000..785675830b
--- /dev/null
+++ b/src/java/org/apache/poi/util/PngUtils.java
@@ -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.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public final class PngUtils {
+
+ /**
+ * File header for PNG format.
+ */
+ private static final byte[] PNG_FILE_HEADER =
+ new byte[] { (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
+
+ private PngUtils() {
+ // no instances of this class
+ }
+
+ /**
+ * Checks if the offset matches the PNG header.
+ *
+ * @param data the data to check.
+ * @param offset the offset to check at.
+ * @return {@code true} if the offset matches.
+ */
+ public static boolean matchesPngHeader(byte[] data, int offset) {
+ if (data == null || data.length - offset < PNG_FILE_HEADER.length) {
+ return false;
+ }
+
+ for (int i = 0; i < PNG_FILE_HEADER.length; i++) {
+ if (PNG_FILE_HEADER[i] != data[i + offset]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
index 7a0da815b7..26c17c5404 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
@@ -186,6 +186,20 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
return open(path, defaultPackageAccess);
}
+ /**
+ * Open a package with read/write permission.
+ *
+ * @param file
+ * The file to open.
+ * @return A Package object, else <b>null</b>.
+ * @throws InvalidFormatException
+ * If the specified file doesn't exist, and a parsing error
+ * occur.
+ */
+ public static OPCPackage open(File file) throws InvalidFormatException {
+ return open(file, defaultPackageAccess);
+ }
+
/**
* Open a package.
*
@@ -212,6 +226,31 @@ public abstract class OPCPackage implements RelationshipSource, Closeable {
return pack;
}
+ /**
+ * Open a package.
+ *
+ * @param file
+ * The file to open.
+ * @param access
+ * PackageBase access.
+ * @return A PackageBase object, else <b>null</b>.
+ * @throws InvalidFormatException
+ * If the specified file doesn't exist, and a parsing error
+ * occur.
+ */
+ public static OPCPackage open(File file, PackageAccess access)
+ throws InvalidFormatException {
+ if (file == null|| (file.exists() && file.isDirectory()))
+ throw new IllegalArgumentException("file");
+
+ OPCPackage pack = new ZipPackage(file, access);
+ if (pack.partList == null && access != PackageAccess.WRITE) {
+ pack.getParts();
+ }
+ pack.originalPackagePath = file.getAbsolutePath();
+ return pack;
+ }
+
/**
* Open a package.
*
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java
index 5ac16d3a0b..bf98cdd29b 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java
@@ -85,30 +85,55 @@ public final class ZipPackage extends Package {
);
}
- /**
- * Constructor. Opens a Zip based Open XML document.
- *
- * @param path
- * The path of the file to open or create.
- * @param access
- * The package access mode.
- * @throws InvalidFormatException
- * If the content type part parsing encounters an error.
- */
- ZipPackage(String path, PackageAccess access) {
- super(access);
-
- ZipFile zipFile = null;
-
- try {
- zipFile = ZipHelper.openZipFile(path);
- } catch (IOException e) {
- throw new InvalidOperationException(
- "Can't open the specified file: '" + path + "'", e);
- }
-
- this.zipArchive = new ZipFileZipEntrySource(zipFile);
- }
+ /**
+ * Constructor. Opens a Zip based Open XML document.
+ *
+ * @param path
+ * The path of the file to open or create.
+ * @param access
+ * The package access mode.
+ * @throws InvalidFormatException
+ * If the content type part parsing encounters an error.
+ */
+ ZipPackage(String path, PackageAccess access) {
+ super(access);
+
+ ZipFile zipFile = null;
+
+ try {
+ zipFile = ZipHelper.openZipFile(path);
+ } catch (IOException e) {
+ throw new InvalidOperationException(
+ "Can't open the specified file: '" + path + "'", e);
+ }
+
+ this.zipArchive = new ZipFileZipEntrySource(zipFile);
+ }
+
+ /**
+ * Constructor. Opens a Zip based Open XML document.
+ *
+ * @param file
+ * The file to open or create.
+ * @param access
+ * The package access mode.
+ * @throws InvalidFormatException
+ * If the content type part parsing encounters an error.
+ */
+ ZipPackage(File file, PackageAccess access) {
+ super(access);
+
+ ZipFile zipFile = null;
+
+ try {
+ zipFile = ZipHelper.openZipFile(file);
+ } catch (IOException e) {
+ throw new InvalidOperationException(
+ "Can't open the specified file: '" + file + "'", e);
+ }
+
+ this.zipArchive = new ZipFileZipEntrySource(zipFile);
+ }
/**
* Retrieves the parts from this package. We assume that the package has not
diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java
index e808dc61e9..9598b05cbe 100644
--- a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java
+++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java
@@ -72,11 +72,12 @@ public final class ZipHelper {
* Retrieve the Zip entry of the content types part.
*/
public static ZipEntry getContentTypeZipEntry(ZipPackage pkg) {
- Enumeration entries = pkg.getZipArchive().getEntries();
+ Enumeration<? extends ZipEntry> entries = pkg.getZipArchive().getEntries();
+
// Enumerate through the Zip entries until we find the one named
// '[Content_Types].xml'.
while (entries.hasMoreElements()) {
- ZipEntry entry = (ZipEntry) entries.nextElement();
+ ZipEntry entry = entries.nextElement();
if (entry.getName().equals(
ContentTypeManager.CONTENT_TYPES_PART_NAME))
return entry;
@@ -141,6 +142,21 @@ public final class ZipHelper {
}
}
+ /**
+ * Opens the specified file as a zip, or returns null if no such file exists
+ *
+ * @param file
+ * The file to open.
+ * @return The zip archive freshly open.
+ */
+ public static ZipFile openZipFile(File file) throws IOException {
+ if (!file.exists()) {
+ return null;
+ }
+
+ return new ZipFile(file);
+ }
+
/**
* Retrieve and open a zip file with the specified path.
*
diff --git a/src/ooxml/java/org/apache/poi/ss/usermodel/WorkbookFactory.java b/src/ooxml/java/org/apache/poi/ss/usermodel/WorkbookFactory.java
index 41f70d92bb..56a9f89028 100644
--- a/src/ooxml/java/org/apache/poi/ss/usermodel/WorkbookFactory.java
+++ b/src/ooxml/java/org/apache/poi/ss/usermodel/WorkbookFactory.java
@@ -87,7 +87,7 @@ public class WorkbookFactory {
NPOIFSFileSystem fs = new NPOIFSFileSystem(file);
return new HSSFWorkbook(fs.getRoot(), true);
} catch(OfficeXmlFileException e) {
- OPCPackage pkg = OPCPackage.openOrCreate(file);
+ OPCPackage pkg = OPCPackage.open(file);
return new XSSFWorkbook(pkg);
}
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
index 6e4768399b..d6cfa7fba3 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
@@ -299,7 +299,7 @@ public abstract class XSLFSimpleShape extends XSLFShape {
public void setLineWidth(double width) {
CTShapeProperties spPr = getSpPr();
if (width == 0.) {
- if (spPr.isSetLn())
+ if (spPr.isSetLn() && spPr.getLn().isSetW())
spPr.getLn().unsetW();
} else {
CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr
@@ -353,7 +353,7 @@ public abstract class XSLFSimpleShape extends XSLFShape {
public void setLineDash(LineDash dash) {
CTShapeProperties spPr = getSpPr();
if (dash == null) {
- if (spPr.isSetLn())
+ if (spPr.isSetLn() && spPr.getLn().isSetPrstDash())
spPr.getLn().unsetPrstDash();
} else {
CTPresetLineDashProperties val = CTPresetLineDashProperties.Factory
@@ -406,7 +406,7 @@ public abstract class XSLFSimpleShape extends XSLFShape {
public void setLineCap(LineCap cap) {
CTShapeProperties spPr = getSpPr();
if (cap == null) {
- if (spPr.isSetLn())
+ if (spPr.isSetLn() && spPr.getLn().isSetCap())
spPr.getLn().unsetCap();
} else {
CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
index 73c2e52d99..a932fb5cd3 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
@@ -425,7 +425,13 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
}
};
fetchParagraphProperty(fetcher);
- return fetcher.getValue() == null ? getDefaultTabSize() : fetcher.getValue();
+ return fetcher.getValue() == null ? 0. : fetcher.getValue();
+ }
+
+ public void addTabStop(double value){
+ CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+ CTTextTabStopList tabStops = pr.isSetTabLst() ? pr.getTabLst() : pr.addNewTabLst();
+ tabStops.addNewTab().setPos(Units.toEMU(value));
}
/**
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
index d7a10c20c8..c6f0591704 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
@@ -353,6 +353,39 @@ public class XSLFTextRun {
}
/**
+ * Set the baseline for both the superscript and subscript fonts.
+ * <p>
+ * The size is specified using a percentage.
+ * Positive values indicate superscript, negative values indicate subscript.
+ * </p>
+ *
+ * @param baselineOffset
+ */
+ public void setBaselineOffset(double baselineOffset){
+ getRPr().setBaseline((int) baselineOffset * 1000);
+ }
+
+ /**
+ * Set whether the text in this run is formatted as superscript.
+ * Default base line offset is 30%
+ *
+ * @see #setBaselineOffset(double)
+ */
+ public void setSuperscript(boolean flag){
+ setBaselineOffset(flag ? 30. : 0.);
+ }
+
+ /**
+ * Set whether the text in this run is formatted as subscript.
+ * Default base line offset is -25%.
+ *
+ * @see #setBaselineOffset(double)
+ */
+ public void setSubscript(boolean flag){
+ setBaselineOffset(flag ? -25.0 : 0.);
+ }
+
+ /**
* @return whether a run of text will be formatted as a superscript text. Default is false.
*/
public boolean isSubscript() {
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java
index bd57fc3ded..46ca95fcf7 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java
@@ -728,10 +728,6 @@ public class SXSSFCell implements Cell
}
void ensureTypeOrFormulaType(int type)
{
- assert type==CELL_TYPE_NUMERIC||
- type==CELL_TYPE_STRING||
- type==CELL_TYPE_BOOLEAN||
- type==CELL_TYPE_ERROR;
if(_value.getType()==type)
{
if(type==CELL_TYPE_STRING&&((StringValue)_value).isRichText())
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFRow.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFRow.java
index 1bd53bc8b2..a762de822b 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFRow.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFRow.java
@@ -212,7 +212,6 @@ public class SXSSFRow implements Row
*/
public Cell getCell(int cellnum, MissingCellPolicy policy)
{
- assert false;
Cell cell = getCell(cellnum);
if(policy == RETURN_NULL_AND_BLANK)
{
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java
index afe8612002..77ae26f76a 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java
@@ -17,19 +17,32 @@
package org.apache.poi.xssf.streaming;
-import java.io.*;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.Iterator;
-import java.util.TreeMap;
import java.util.Map;
+import java.util.TreeMap;
+import org.apache.poi.hssf.util.PaneInformation;
import org.apache.poi.ss.SpreadsheetVersion;
-import org.apache.poi.ss.usermodel.*;
-
+import org.apache.poi.ss.usermodel.AutoFilter;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellRange;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Comment;
+import org.apache.poi.ss.usermodel.DataValidation;
+import org.apache.poi.ss.usermodel.DataValidationHelper;
+import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.Footer;
+import org.apache.poi.ss.usermodel.Header;
+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.SheetConditionalFormatting;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.SheetUtil;
import org.apache.poi.xssf.usermodel.XSSFSheet;
-
-import org.apache.poi.hssf.util.PaneInformation;
-import org.apache.poi.ss.util.CellRangeAddress;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
@@ -1263,7 +1276,27 @@ public class SXSSFSheet implements Sheet, Cloneable
public SheetConditionalFormatting getSheetConditionalFormatting(){
return _sh.getSheetConditionalFormatting();
}
-
+
+
+ public CellRangeAddress getRepeatingRows() {
+ return _sh.getRepeatingRows();
+ }
+
+
+ public CellRangeAddress getRepeatingColumns() {
+ return _sh.getRepeatingColumns();
+ }
+
+ public void setRepeatingRows(CellRangeAddress rowRangeRef) {
+ _sh.setRepeatingRows(rowRangeRef);
+ }
+
+ public void setRepeatingColumns(CellRangeAddress columnRangeRef) {
+ _sh.setRepeatingColumns(columnRangeRef);
+ }
+
+
+
//end of interface implementation
/**
* Specifies how many rows can be accessed at most via getRow().
@@ -1330,7 +1363,6 @@ public class SXSSFSheet implements Sheet, Cloneable
if(entry.getValue()==row)
return entry.getKey().intValue();
}
- assert false;
return -1;
}
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
index a79f1aad02..73c4b934cf 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
@@ -42,6 +42,7 @@ import java.util.zip.ZipEntry;
import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
+import org.apache.poi.ss.util.CellRangeAddress;
/**
* Streaming version of XSSFWorkbook implementing the "BigGridDemo" strategy.
@@ -244,7 +245,6 @@ public class SXSSFWorkbook implements Workbook
XSSFSheet getXSSFSheet(SXSSFSheet sheet)
{
XSSFSheet result=_sxFromXHash.get(sheet);
- assert result!=null;
return result;
}
@@ -543,7 +543,6 @@ public class SXSSFWorkbook implements Workbook
*/
public int getSheetIndex(Sheet sheet)
{
- assert sheet instanceof SXSSFSheet;
return _wb.getSheetIndex(getXSSFSheet((SXSSFSheet)sheet));
}
@@ -664,6 +663,9 @@ public class SXSSFWorkbook implements Workbook
* @param endColumn 0 based end of repeating columns.
* @param startRow 0 based start of repeating rows.
* @param endRow 0 based end of repeating rows.
+ *
+ * @deprecated use {@link SXSSFSheet#setRepeatingRows(CellRangeAddress)}
+ * or {@link SXSSFSheet#setRepeatingColumns(CellRangeAddress)}
*/
public void setRepeatingRowsAndColumns(int sheetIndex, int startColumn, int endColumn, int startRow, int endRow)
{
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java
index 1823fec798..f6c98317f5 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SheetDataWriter.java
@@ -204,7 +204,6 @@ public class SheetDataWriter {
break;
}
default: {
- assert false;
throw new RuntimeException("Huh?");
}
}
@@ -279,6 +278,9 @@ public class SheetDataWriter {
// the same rule applies to unicode surrogates and "not a character" symbols.
if( c < ' ' || Character.isLowSurrogate(c) || Character.isHighSurrogate(c) ||
('\uFFFE' <= c && c <= '\uFFFF')) {
+ if (counter > last) {
+ _out.write(chars, last, counter - last);
+ }
_out.write('?');
last = counter + 1;
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
index fbed5b06dd..ccf2419873 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
@@ -41,6 +41,7 @@ import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.formula.FormulaShifter;
+import org.apache.poi.ss.formula.SheetNameFormatter;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
@@ -3185,4 +3186,162 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
color.setIndexed(colorIndex);
pr.setTabColor(color);
}
+
+
+ public CellRangeAddress getRepeatingRows() {
+ return getRepeatingRowsOrColums(true);
+ }
+
+
+ public CellRangeAddress getRepeatingColumns() {
+ return getRepeatingRowsOrColums(false);
+ }
+
+ public void setRepeatingRows(CellRangeAddress rowRangeRef) {
+ CellRangeAddress columnRangeRef = getRepeatingColumns();
+ setRepeatingRowsAndColumns(rowRangeRef, columnRangeRef);
+ }
+
+
+ public void setRepeatingColumns(CellRangeAddress columnRangeRef) {
+ CellRangeAddress rowRangeRef = getRepeatingRows();
+ setRepeatingRowsAndColumns(rowRangeRef, columnRangeRef);
+ }
+
+
+ private void setRepeatingRowsAndColumns(
+ CellRangeAddress rowDef, CellRangeAddress colDef) {
+ int col1 = -1;
+ int col2 = -1;
+ int row1 = -1;
+ int row2 = -1;
+
+ if (rowDef != null) {
+ row1 = rowDef.getFirstRow();
+ row2 = rowDef.getLastRow();
+ if ((row1 == -1 && row2 != -1)
+ || row1 < -1 || row2 < -1 || row1 > row2) {
+ throw new IllegalArgumentException("Invalid row range specification");
+ }
+ }
+ if (colDef != null) {
+ col1 = colDef.getFirstColumn();
+ col2 = colDef.getLastColumn();
+ if ((col1 == -1 && col2 != -1)
+ || col1 < -1 || col2 < -1 || col1 > col2) {
+ throw new IllegalArgumentException(
+ "Invalid column range specification");
+ }
+ }
+
+ int sheetIndex = getWorkbook().getSheetIndex(this);
+
+ boolean removeAll = rowDef == null && colDef == null;
+
+ XSSFName name = getWorkbook().getBuiltInName(
+ XSSFName.BUILTIN_PRINT_TITLE, sheetIndex);
+ if (removeAll) {
+ if (name != null) {
+ getWorkbook().removeName(name);
+ }
+ return;
+ }
+ if (name == null) {
+ name = getWorkbook().createBuiltInName(
+ XSSFName.BUILTIN_PRINT_TITLE, sheetIndex);
+ }
+
+ String reference = getReferenceBuiltInRecord(
+ name.getSheetName(), col1, col2, row1, row2);
+ name.setRefersToFormula(reference);
+
+ // If the print setup isn't currently defined, then add it
+ // in but without printer defaults
+ // If it's already there, leave it as-is!
+ if (worksheet.isSetPageSetup() && worksheet.isSetPageMargins()) {
+ // Everything we need is already there
+ } else {
+ // Have initial ones put in place
+ getPrintSetup().setValidSettings(false);
+ }
+ }
+
+ private static String getReferenceBuiltInRecord(
+ String sheetName, int startC, int endC, int startR, int endR) {
+ // Excel example for built-in title:
+ // 'second sheet'!$E:$F,'second sheet'!$2:$3
+
+ CellReference colRef =
+ new CellReference(sheetName, 0, startC, true, true);
+ CellReference colRef2 =
+ new CellReference(sheetName, 0, endC, true, true);
+ CellReference rowRef =
+ new CellReference(sheetName, startR, 0, true, true);
+ CellReference rowRef2 =
+ new CellReference(sheetName, endR, 0, true, true);
+
+ String escapedName = SheetNameFormatter.format(sheetName);
+
+ String c = "";
+ String r = "";
+
+ if(startC == -1 && endC == -1) {
+ } else {
+ c = escapedName + "!$" + colRef.getCellRefParts()[2]
+ + ":$" + colRef2.getCellRefParts()[2];
+ }
+
+ if (startR == -1 && endR == -1) {
+
+ } else if (!rowRef.getCellRefParts()[1].equals("0")
+ && !rowRef2.getCellRefParts()[1].equals("0")) {
+ r = escapedName + "!$" + rowRef.getCellRefParts()[1]
+ + ":$" + rowRef2.getCellRefParts()[1];
+ }
+
+ StringBuffer rng = new StringBuffer();
+ rng.append(c);
+ if(rng.length() > 0 && r.length() > 0) {
+ rng.append(',');
+ }
+ rng.append(r);
+ return rng.toString();
+ }
+
+
+ private CellRangeAddress getRepeatingRowsOrColums(boolean rows) {
+ int sheetIndex = getWorkbook().getSheetIndex(this);
+ XSSFName name = getWorkbook().getBuiltInName(
+ XSSFName.BUILTIN_PRINT_TITLE, sheetIndex);
+ if (name == null ) {
+ return null;
+ }
+ String refStr = name.getRefersToFormula();
+ if (refStr == null) {
+ return null;
+ }
+ String[] parts = refStr.split(",");
+ int maxRowIndex = SpreadsheetVersion.EXCEL2007.getLastRowIndex();
+ int maxColIndex = SpreadsheetVersion.EXCEL2007.getLastColumnIndex();
+ for (String part : parts) {
+ CellRangeAddress range = CellRangeAddress.valueOf(part);
+ if ((range.getFirstColumn() == 0
+ && range.getLastColumn() == maxColIndex)
+ || (range.getFirstColumn() == -1
+ && range.getLastColumn() == -1)) {
+ if (rows) {
+ return range;
+ }
+ } else if (range.getFirstRow() == 0
+ && range.getLastRow() == maxRowIndex
+ || (range.getFirstRow() == -1
+ && range.getLastRow() == -1)) {
+ if (!rows) {
+ return range;
+ }
+ }
+ }
+ return null;
+ }
+
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
index 0c40d26fb1..639a78d423 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
@@ -19,6 +19,7 @@ package org.apache.poi.xssf.usermodel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -51,6 +52,7 @@ 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.Row.MissingCellPolicy;
+import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.WorkbookUtil;
import org.apache.poi.util.*;
@@ -172,9 +174,15 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
/**
* Constructs a XSSFWorkbook object given a OpenXML4J <code>Package</code> object,
- * see <a href="http://openxml4j.org/">www.openxml4j.org</a>.
+ * see <a href="http://poi.apache.org/oxml4j/">http://poi.apache.org/oxml4j/</a>.
+ *
+ * Once you have finished working with the Workbook, you should close the package
+ * by calling pkg.close, to avoid leaving file handles open.
+ *
+ * Creating a XSSFWorkbook from a file-backed OPC Package has a lower memory
+ * footprint than an InputStream backed one.
*
- * @param pkg the OpenXML4J <code>Package</code> object.
+ * @param pkg the OpenXML4J <code>OPC Package</code> object.
*/
public XSSFWorkbook(OPCPackage pkg) throws IOException {
super(pkg);
@@ -183,6 +191,20 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
load(XSSFFactory.getInstance());
}
+ /**
+ * Constructs a XSSFWorkbook object, by buffering the whole stream into memory
+ * and then opening an {@link OPCPackage} object for it.
+ *
+ * Using an {@link InputStream} requires more memory than using a File, so
+ * if a {@link File} is available then you should instead do something like
+ * <pre><code>
+ * OPCPackage pkg = OPCPackage.open(path);
+ * XSSFWorkbook wb = new XSSFWorkbook(pkg);
+ * // work with the wb object
+ * ......
+ * pkg.close(); // gracefully closes the underlying zip file
+ * </code></pre>
+ */
public XSSFWorkbook(InputStream is) throws IOException {
super(PackageHelper.open(is));
@@ -904,6 +926,20 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
throw new IllegalArgumentException("Named range was not found: " + name);
}
+
+ /**
+ * As {@link #removeName(String)} is not necessarily unique
+ * (name + sheet index is unique), this method is more accurate.
+ *
+ * @param name the name to remove.
+ */
+ void removeName(XSSFName name) {
+ if (!namedRanges.remove(name)) {
+ throw new IllegalArgumentException("Name was not found: " + name);
+ }
+ }
+
+
/**
* Delete the printarea for the sheet specified
*
@@ -1108,71 +1144,27 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
* @param endColumn 0 based end of repeating columns.
* @param startRow 0 based start of repeating rows.
* @param endRow 0 based end of repeating rows.
+ *
+ * @deprecated use {@link XSSFSheet#setRepeatingRows(CellRangeAddress)}
+ * or {@link XSSFSheet#setRepeatingColumns(CellRangeAddress)}
*/
public void setRepeatingRowsAndColumns(int sheetIndex,
int startColumn, int endColumn,
int startRow, int endRow) {
- // Check arguments
- if ((startColumn == -1 && endColumn != -1) || startColumn < -1 || endColumn < -1 || startColumn > endColumn)
- throw new IllegalArgumentException("Invalid column range specification");
- if ((startRow == -1 && endRow != -1) || startRow < -1 || endRow < -1 || startRow > endRow)
- throw new IllegalArgumentException("Invalid row range specification");
-
- XSSFSheet sheet = getSheetAt(sheetIndex);
- boolean removingRange = startColumn == -1 && endColumn == -1 && startRow == -1 && endRow == -1;
-
- XSSFName name = getBuiltInName(XSSFName.BUILTIN_PRINT_TITLE, sheetIndex);
- if (removingRange) {
- if(name != null)namedRanges.remove(name);
- return;
- }
- if (name == null) {
- name = createBuiltInName(XSSFName.BUILTIN_PRINT_TITLE, sheetIndex);
- }
-
- String reference = getReferenceBuiltInRecord(name.getSheetName(), startColumn, endColumn, startRow, endRow);
- name.setRefersToFormula(reference);
-
- // If the print setup isn't currently defined, then add it
- // in but without printer defaults
- // If it's already there, leave it as-is!
- CTWorksheet ctSheet = sheet.getCTWorksheet();
- if(ctSheet.isSetPageSetup() && ctSheet.isSetPageMargins()) {
- // Everything we need is already there
- } else {
- // Have initial ones put in place
- XSSFPrintSetup printSetup = sheet.getPrintSetup();
- printSetup.setValidSettings(false);
- }
- }
-
- private static String getReferenceBuiltInRecord(String sheetName, int startC, int endC, int startR, int endR) {
- //windows excel example for built-in title: 'second sheet'!$E:$F,'second sheet'!$2:$3
- CellReference colRef = new CellReference(sheetName, 0, startC, true, true);
- CellReference colRef2 = new CellReference(sheetName, 0, endC, true, true);
-
- String escapedName = SheetNameFormatter.format(sheetName);
-
- String c;
- if(startC == -1 && endC == -1) c= "";
- else c = escapedName + "!$" + colRef.getCellRefParts()[2] + ":$" + colRef2.getCellRefParts()[2];
-
- CellReference rowRef = new CellReference(sheetName, startR, 0, true, true);
- CellReference rowRef2 = new CellReference(sheetName, endR, 0, true, true);
-
- String r = "";
- if(startR == -1 && endR == -1) r = "";
- else {
- if (!rowRef.getCellRefParts()[1].equals("0") && !rowRef2.getCellRefParts()[1].equals("0")) {
- r = escapedName + "!$" + rowRef.getCellRefParts()[1] + ":$" + rowRef2.getCellRefParts()[1];
- }
- }
-
- StringBuffer rng = new StringBuffer();
- rng.append(c);
- if(rng.length() > 0 && r.length() > 0) rng.append(',');
- rng.append(r);
- return rng.toString();
+ XSSFSheet sheet = getSheetAt(sheetIndex);
+
+ CellRangeAddress rows = null;
+ CellRangeAddress cols = null;
+
+ if (startRow != -1) {
+ rows = new CellRangeAddress(startRow, endRow, -1, -1);
+ }
+ if (startColumn != -1) {
+ cols = new CellRangeAddress(-1, -1, startColumn, endColumn);
+ }
+
+ sheet.setRepeatingRows(rows);
+ sheet.setRepeatingColumns(cols);
}
private static String getReferencePrintArea(String sheetName, int startC, int endC, int startR, int endR) {
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFColor.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFColor.java
index a08faf0e38..b335983d09 100644
--- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFColor.java
+++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFColor.java
@@ -17,11 +17,7 @@
package org.apache.poi.xslf.usermodel;
import junit.framework.TestCase;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTHslColor;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
-import org.openxmlformats.schemas.drawingml.x2006.main.STPresetColorVal;
-import org.openxmlformats.schemas.drawingml.x2006.main.STSchemeColorVal;
+import org.openxmlformats.schemas.drawingml.x2006.main.*;
import java.awt.Color;
@@ -149,4 +145,19 @@ public class TestXSLFColor extends TestCase {
assertEquals(XSLFColor.presetColors.get(colorName), color.getColor());
}
}
+
+ public void testSys() {
+ CTColor xml = CTColor.Factory.newInstance();
+ CTSystemColor sys = xml.addNewSysClr();
+ sys.setVal(STSystemColorVal.GRAY_TEXT);
+ XSLFColor color = new XSLFColor(xml, null, null);
+ assertEquals(Color.black, color.getColor());
+
+ xml = CTColor.Factory.newInstance();
+ sys = xml.addNewSysClr();
+ sys.setLastClr(new byte[]{(byte)0xFF, 0, 0});
+ color = new XSLFColor(xml, null, null);
+ assertEquals(Color.red, color.getColor());
+ }
+
} \ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java
index f5839fd778..f0d57241db 100644
--- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java
+++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java
@@ -19,9 +19,7 @@ package org.apache.poi.xslf.usermodel;
import junit.framework.TestCase;
import org.apache.poi.util.Units;
import org.apache.poi.xslf.XSLFTestDataSamples;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
-import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap;
-import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal;
+import org.openxmlformats.schemas.drawingml.x2006.main.*;
import java.awt.Color;
@@ -102,6 +100,20 @@ public class TestXSLFSimpleShape extends TestCase {
assertEquals(null, shape.getLineColor());
// setting dash width to null unsets the SolidFill element
assertFalse(shape.getSpPr().getLn().isSetSolidFill());
+
+ XSLFSimpleShape ln2 = slide.createAutoShape();
+ ln2.setLineDash(LineDash.DOT);
+ assertEquals(LineDash.DOT, ln2.getLineDash());
+ ln2.setLineWidth(0.);
+ assertEquals(0., ln2.getLineWidth());
+
+ XSLFSimpleShape ln3 = slide.createAutoShape();
+ ln3.setLineWidth(1.);
+ assertEquals(1., ln3.getLineWidth());
+ ln3.setLineDash(null);
+ assertEquals(null, ln3.getLineDash());
+ ln3.setLineCap(null);
+ assertEquals(null, ln3.getLineDash());
}
public void testFill() {
@@ -231,4 +243,14 @@ public class TestXSLFSimpleShape extends TestCase {
}
+ public void testShadowEffects(){
+ XMLSlideShow ppt = new XMLSlideShow();
+ XSLFSlide slide = ppt.createSlide();
+ CTStyleMatrix styleMatrix = slide.getTheme().getXmlObject().getThemeElements().getFmtScheme();
+ CTEffectStyleList lst = styleMatrix.getEffectStyleLst();
+ assertNotNull(lst);
+ for(CTEffectStyleItem ef : lst.getEffectStyleList()){
+ CTOuterShadowEffect obj = ef.getEffectLst().getOuterShdw();
+ }
+ }
} \ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java
index 0feff27d25..3ce6c3b6d2 100644
--- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java
+++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java
@@ -17,6 +17,7 @@
package org.apache.poi.xslf.usermodel;
import junit.framework.TestCase;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyle;
/**
* @author Yegor Kozlov
@@ -30,4 +31,9 @@ public class TestXSLFTableStyles extends TestCase {
assertEquals(0, tblStyles.getStyles().size());
}
+
+ public void testStyle(){
+ CTTableStyle obj = CTTableStyle.Factory.newInstance();
+ XSLFTableStyle style = new XSLFTableStyle(obj);
+ }
} \ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java
index 2a44c058bb..00b4cbdcce 100644
--- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java
+++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java
@@ -289,6 +289,17 @@ public class TestXSLFTextParagraph extends TestCase {
p.setBullet(false);
assertFalse(p.isBullet());
+
+ p.setBulletAutoNumber(ListAutoNumber.ALPHA_LC_PARENT_BOTH, 1);
+
+ double tabStop = p.getTabStop(0);
+ assertEquals(0.0, tabStop);
+
+ p.addTabStop(100.);
+ assertEquals(100., p.getTabStop(0));
+
+ assertEquals(72.0, p.getDefaultTabSize());
+
}
public void testLineBreak(){
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextRun.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextRun.java
index 256c9eaecb..eb7553ecc4 100644
--- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextRun.java
+++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextRun.java
@@ -56,5 +56,16 @@ public class TestXSLFTextRun extends TestCase {
r.setFontSize(13.0);
assertEquals(13.0, r.getFontSize());
+ assertEquals(false, r.isSuperscript());
+ r.setSuperscript(true);
+ assertEquals(true, r.isSuperscript());
+ r.setSuperscript(false);
+ assertEquals(false, r.isSuperscript());
+
+ assertEquals(false, r.isSubscript());
+ r.setSubscript(true);
+ assertEquals(true, r.isSubscript());
+ r.setSubscript(false);
+ assertEquals(false, r.isSubscript());
}
}
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbook.java b/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbook.java
index 72258e411c..ef9149cbf8 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbook.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbook.java
@@ -154,6 +154,14 @@ public final class TestSXSSFWorkbook extends BaseTestWorkbook {
tmp = wr.getTempFile();
assertTrue(tmp.getName().startsWith("poi-sxssf-sheet-xml"));
assertTrue(tmp.getName().endsWith(".gz"));
+
+ //Test escaping of Unicode control characters
+ wb = new SXSSFWorkbook();
+ wb.createSheet("S1").createRow(0).createCell(0).setCellValue("value\u0019");
+ XSSFWorkbook xssfWorkbook = (XSSFWorkbook) SXSSFITestDataProvider.instance.writeOutAndReadBack(wb);
+ Cell cell = xssfWorkbook.getSheet("S1").getRow(0).getCell(0);
+ assertEquals("value?", cell.getStringCellValue());
+
}
public void testGZipSheetdataWriter(){
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFName.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFName.java
index 1c640b4177..21b74ae11f 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFName.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFName.java
@@ -20,6 +20,7 @@ package org.apache.poi.xssf.usermodel;
import org.apache.poi.xssf.XSSFTestDataSamples;
import org.apache.poi.xssf.XSSFITestDataProvider;
import org.apache.poi.ss.usermodel.BaseTestNamedRange;
+import org.apache.poi.ss.util.CellRangeAddress;
/**
* @author Yegor Kozlov
@@ -35,13 +36,15 @@ public final class TestXSSFName extends BaseTestNamedRange {
// First test that setting RR&C for same sheet more than once only creates a
// single Print_Titles built-in record
XSSFWorkbook wb = new XSSFWorkbook();
- wb.createSheet("First Sheet");
+ XSSFSheet sheet1 = wb.createSheet("First Sheet");
- wb.setRepeatingRowsAndColumns(0, -1, -1, -1, -1);
+ sheet1.setRepeatingRows(null);
+ sheet1.setRepeatingColumns(null);
// set repeating rows and columns twice for the first sheet
for (int i = 0; i < 2; i++) {
- wb.setRepeatingRowsAndColumns(0, 0, 0, 0, 3);
+ sheet1.setRepeatingRows(CellRangeAddress.valueOf("1:4"));
+ sheet1.setRepeatingColumns(CellRangeAddress.valueOf("A:A"));
//sheet.createFreezePane(0, 3);
}
assertEquals(1, wb.getNumberOfNames());
@@ -51,18 +54,18 @@ public final class TestXSSFName extends BaseTestNamedRange {
assertEquals("'First Sheet'!$A:$A,'First Sheet'!$1:$4", nr1.getRefersToFormula());
//remove the columns part
- wb.setRepeatingRowsAndColumns(0, -1, -1, 0, 3);
+ sheet1.setRepeatingColumns(null);
assertEquals("'First Sheet'!$1:$4", nr1.getRefersToFormula());
//revert
- wb.setRepeatingRowsAndColumns(0, 0, 0, 0, 3);
+ sheet1.setRepeatingColumns(CellRangeAddress.valueOf("A:A"));
//remove the rows part
- wb.setRepeatingRowsAndColumns(0, 0, 0, -1, -1);
+ sheet1.setRepeatingRows(null);
assertEquals("'First Sheet'!$A:$A", nr1.getRefersToFormula());
//revert
- wb.setRepeatingRowsAndColumns(0, 0, 0, 0, 3);
+ sheet1.setRepeatingRows(CellRangeAddress.valueOf("1:4"));
// Save and re-open
XSSFWorkbook nwb = XSSFTestDataSamples.writeOutAndReadBack(wb);
@@ -75,8 +78,9 @@ public final class TestXSSFName extends BaseTestNamedRange {
// check that setting RR&C on a second sheet causes a new Print_Titles built-in
// name to be created
- nwb.createSheet("SecondSheet");
- nwb.setRepeatingRowsAndColumns(1, 1, 2, 0, 0);
+ XSSFSheet sheet2 = nwb.createSheet("SecondSheet");
+ sheet2.setRepeatingRows(CellRangeAddress.valueOf("1:1"));
+ sheet2.setRepeatingColumns(CellRangeAddress.valueOf("B:C"));
assertEquals(2, nwb.getNumberOfNames());
XSSFName nr2 = nwb.getNameAt(1);
@@ -84,6 +88,7 @@ public final class TestXSSFName extends BaseTestNamedRange {
assertEquals(XSSFName.BUILTIN_PRINT_TITLE, nr2.getNameName());
assertEquals("SecondSheet!$B:$C,SecondSheet!$1:$1", nr2.getRefersToFormula());
- nwb.setRepeatingRowsAndColumns(1, -1, -1, -1, -1);
+ sheet2.setRepeatingRows(null);
+ sheet2.setRepeatingColumns(null);
}
}
diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java
index 7f87bff921..09c1c1636f 100644
--- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java
+++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java
@@ -337,4 +337,10 @@ public final class TestXWPFDocument extends TestCase {
doc.getPackage().revert();
}
+
+ public void testSettings(){
+ XWPFSettings settings = new XWPFSettings();
+ settings.setZoomPercent(50);
+ assertEquals(50, settings.getZoomPercent());
+ }
}
diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java
index 3c13504cdf..5d13185cfc 100644
--- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java
+++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java
@@ -26,7 +26,11 @@ import junit.framework.TestCase;
import org.apache.poi.xwpf.XWPFTestDataSamples;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLatentStyles;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STStyleType;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLsdException;
public class TestXWPFStyles extends TestCase {
@@ -82,4 +86,36 @@ public class TestXWPFStyles extends TestCase {
assertNotNull(styles);
}
+
+ /**
+ * YK: tests below don't make much sense,
+ * they exist only to copy xml beans to pi-ooxml-schemas.jar
+ */
+ public void testLanguages(){
+ XWPFDocument docOut = new XWPFDocument();
+ XWPFStyles styles = docOut.createStyles();
+ styles.setEastAsia("Chinese");
+
+ styles.setSpellingLanguage("English");
+
+ CTFonts def = CTFonts.Factory.newInstance();
+ styles.setDefaultFonts(def);
+ }
+
+ public void testType() {
+ CTStyle ctStyle = CTStyle.Factory.newInstance();
+ XWPFStyle style = new XWPFStyle(ctStyle);
+
+ style.setType(STStyleType.PARAGRAPH);
+ assertEquals(STStyleType.PARAGRAPH, style.getType());
+ }
+
+ public void testLatentStyles() {
+ CTLatentStyles latentStyles = CTLatentStyles.Factory.newInstance();
+ CTLsdException ex = latentStyles.addNewLsdException();
+ ex.setName("ex1");
+ XWPFLatentStyles ls = new XWPFLatentStyles(latentStyles);
+ assertEquals(true, ls.isLatentStyle("ex1"));
+
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java
index fc880d5db3..b2a42536c3 100644
--- a/src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java
+++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java
@@ -161,70 +161,76 @@ public final class Chunk {
continue;
}
- // Process
- switch(type) {
- // Types 0->7 = a flat at bit 0->7
- case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
- int val = contents[offset] & (1<<type);
- command.value = Boolean.valueOf(val > 0);
- break;
- case 8:
- command.value = Byte.valueOf(contents[offset]);
- break;
- case 9:
- command.value = new Double(
- LittleEndian.getDouble(contents, offset)
- );
- break;
- case 12:
- // A Little Endian String
- // Starts 8 bytes into the data segment
- // Ends at end of data, or 00 00
-
- // Ensure we have enough data
- if(contents.length < 8) {
- command.value = "";
+ try {
+ // Process
+ switch(type) {
+ // Types 0->7 = a flat at bit 0->7
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ int val = contents[offset] & (1<<type);
+ command.value = Boolean.valueOf(val > 0);
break;
- }
-
- // Find the end point
- int startsAt = 8;
- int endsAt = startsAt;
- for(int j=startsAt; j<contents.length-1 && endsAt == startsAt; j++) {
- if(contents[j] == 0 && contents[j+1] == 0) {
- endsAt = j;
+ case 8:
+ command.value = Byte.valueOf(contents[offset]);
+ break;
+ case 9:
+ command.value = new Double(
+ LittleEndian.getDouble(contents, offset)
+ );
+ break;
+ case 12:
+ // A Little Endian String
+ // Starts 8 bytes into the data segment
+ // Ends at end of data, or 00 00
+
+ // Ensure we have enough data
+ if(contents.length < 8) {
+ command.value = "";
+ break;
}
- }
- if(endsAt == startsAt) {
- endsAt = contents.length;
- }
-
- int strLen = (endsAt-startsAt) / 2;
- command.value = StringUtil.getFromUnicodeLE(contents, startsAt, strLen);
- break;
- case 25:
- command.value = Short.valueOf(
- LittleEndian.getShort(contents, offset)
- );
- break;
- case 26:
- command.value = Integer.valueOf(
- LittleEndian.getInt(contents, offset)
- );
- break;
- // Types 11 and 21 hold the offset to the blocks
- case 11: case 21:
- if(offset < contents.length - 3) {
- int bOffset = (int)LittleEndian.getUInt(contents, offset);
- BlockOffsetCommand bcmd = (BlockOffsetCommand)command;
- bcmd.setOffset(bOffset);
- }
- break;
+ // Find the end point
+ int startsAt = 8;
+ int endsAt = startsAt;
+ for(int j=startsAt; j<contents.length-1 && endsAt == startsAt; j++) {
+ if(contents[j] == 0 && contents[j+1] == 0) {
+ endsAt = j;
+ }
+ }
+ if(endsAt == startsAt) {
+ endsAt = contents.length;
+ }
- default:
- logger.log(POILogger.INFO,
- "Command of type " + type + " not processed!");
+ int strLen = endsAt - startsAt;
+ command.value = new String(contents, startsAt, strLen, header.getChunkCharset().name());
+ break;
+ case 25:
+ command.value = Short.valueOf(
+ LittleEndian.getShort(contents, offset)
+ );
+ break;
+ case 26:
+ command.value = Integer.valueOf(
+ LittleEndian.getInt(contents, offset)
+ );
+ break;
+
+ // Types 11 and 21 hold the offset to the blocks
+ case 11: case 21:
+ if(offset < contents.length - 3) {
+ int bOffset = (int)LittleEndian.getUInt(contents, offset);
+ BlockOffsetCommand bcmd = (BlockOffsetCommand)command;
+ bcmd.setOffset(bOffset);
+ }
+ break;
+
+ default:
+ logger.log(POILogger.INFO,
+ "Command of type " + type + " not processed!");
+ }
+ }
+ catch (Exception e) {
+ logger.log(POILogger.ERROR, "Unexpected error processing command, ignoring and continuing. Command: " +
+ command, e);
}
// Add to the array
diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeader.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeader.java
index 1565074de9..fc8c0a30eb 100644
--- a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeader.java
+++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeader.java
@@ -19,6 +19,8 @@ package org.apache.poi.hdgf.chunks;
import org.apache.poi.util.LittleEndian;
+import java.nio.charset.Charset;
+
/**
* A chunk header
*/
@@ -80,6 +82,7 @@ public abstract class ChunkHeader {
public abstract int getSizeInBytes();
public abstract boolean hasTrailer();
public abstract boolean hasSeparator();
+ public abstract Charset getChunkCharset();
/**
* Returns the ID/IX of the chunk
diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV11.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV11.java
index df68ea5849..b3d84aa503 100644
--- a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV11.java
+++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV11.java
@@ -17,6 +17,8 @@
package org.apache.poi.hdgf.chunks;
+import java.nio.charset.Charset;
+
/**
* A chunk header from v11+
*/
@@ -42,4 +44,9 @@ public final class ChunkHeaderV11 extends ChunkHeaderV6 {
return false;
}
+
+ @Override
+ public Charset getChunkCharset() {
+ return Charset.forName("UTF-16LE");
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV4V5.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV4V5.java
index 7162f5056f..bba6a87ddd 100644
--- a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV4V5.java
+++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV4V5.java
@@ -17,6 +17,8 @@
package org.apache.poi.hdgf.chunks;
+import java.nio.charset.Charset;
+
/**
* A chunk header from v4 or v5
*/
@@ -54,4 +56,9 @@ public final class ChunkHeaderV4V5 extends ChunkHeader {
// V4 and V5 never has separators
return false;
}
+
+ @Override
+ public Charset getChunkCharset() {
+ return Charset.forName("ASCII");
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV6.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV6.java
index cfbae6e04c..96546c780b 100644
--- a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV6.java
+++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV6.java
@@ -17,6 +17,8 @@
package org.apache.poi.hdgf.chunks;
+import java.nio.charset.Charset;
+
/**
* A chunk header from v6
*/
@@ -59,4 +61,9 @@ public class ChunkHeaderV6 extends ChunkHeader {
// V6 never has separators
return false;
}
+
+ @Override
+ public Charset getChunkCharset() {
+ return Charset.forName("ASCII");
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java b/src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java
index 34399ee501..5956334800 100644
--- a/src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java
+++ b/src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java
@@ -52,19 +52,25 @@ public final class ChunkStream extends Stream {
int pos = 0;
byte[] contents = getStore().getContents();
- while(pos < contents.length) {
- // Ensure we have enough data to create a chunk from
- int headerSize = ChunkHeader.getHeaderSize(chunkFactory.getVersion());
- if(pos+headerSize <= contents.length) {
- Chunk chunk = chunkFactory.createChunk(contents, pos);
- chunksA.add(chunk);
+ try {
+ while(pos < contents.length) {
+ // Ensure we have enough data to create a chunk from
+ int headerSize = ChunkHeader.getHeaderSize(chunkFactory.getVersion());
+ if(pos+headerSize <= contents.length) {
+ Chunk chunk = chunkFactory.createChunk(contents, pos);
+ chunksA.add(chunk);
- pos += chunk.getOnDiskSize();
- } else {
- System.err.println("Needed " + headerSize + " bytes to create the next chunk header, but only found " + (contents.length-pos) + " bytes, ignoring rest of data");
- pos = contents.length;
+ pos += chunk.getOnDiskSize();
+ } else {
+ System.err.println("Needed " + headerSize + " bytes to create the next chunk header, but only found " + (contents.length-pos) + " bytes, ignoring rest of data");
+ pos = contents.length;
+ }
}
}
+ catch (Exception e)
+ {
+ System.err.println("Failed to create chunk at " + pos + ", ignoring rest of data." + e);
+ }
chunks = chunksA.toArray(new Chunk[chunksA.size()]);
}
diff --git a/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIAttribute.java b/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIAttribute.java
index 31c3cbb885..f4e9fab559 100644
--- a/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIAttribute.java
+++ b/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIAttribute.java
@@ -27,6 +27,7 @@ import org.apache.poi.hmef.Attachment;
import org.apache.poi.hmef.HMEFMessage;
import org.apache.poi.hsmf.datatypes.MAPIProperty;
import org.apache.poi.hsmf.datatypes.Types;
+import org.apache.poi.hsmf.datatypes.Types.MAPIType;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@@ -109,16 +110,22 @@ public class MAPIAttribute {
// Is it either Multi-Valued or Variable-Length?
boolean isMV = false;
boolean isVL = false;
- int type = typeAndMV;
+ int typeId = typeAndMV;
if( (typeAndMV & Types.MULTIVALUED_FLAG) > 0 ) {
isMV = true;
- type -= Types.MULTIVALUED_FLAG;
+ typeId -= Types.MULTIVALUED_FLAG;
}
- if(type == Types.ASCII_STRING || type == Types.UNICODE_STRING ||
- type == Types.BINARY || type == Types.DIRECTORY) {
+ if(typeId == Types.ASCII_STRING.getId() || typeId == Types.UNICODE_STRING.getId() ||
+ typeId == Types.BINARY.getId() || typeId == Types.DIRECTORY.getId()) {
isVL = true;
}
+ // Turn the type ID into a strongly typed thing
+ MAPIType type = Types.getById(typeId);
+ if (type == null) {
+ type = Types.createCustom(typeId);
+ }
+
// If it's a named property, rather than a standard
// MAPI property, grab the details of it
MAPIProperty prop = MAPIProperty.get(id);
@@ -164,13 +171,13 @@ public class MAPIAttribute {
// Create
MAPIAttribute attr;
if(type == Types.UNICODE_STRING || type == Types.ASCII_STRING) {
- attr = new MAPIStringAttribute(prop, type, data);
+ attr = new MAPIStringAttribute(prop, typeId, data);
} else if(type == Types.APP_TIME || type == Types.TIME) {
- attr = new MAPIDateAttribute(prop, type, data);
+ attr = new MAPIDateAttribute(prop, typeId, data);
} else if(id == MAPIProperty.RTF_COMPRESSED.id) {
- attr = new MAPIRtfAttribute(prop, type, data);
+ attr = new MAPIRtfAttribute(prop, typeId, data);
} else {
- attr = new MAPIAttribute(prop, type, data);
+ attr = new MAPIAttribute(prop, typeId, data);
}
attrs.add(attr);
}
@@ -179,32 +186,17 @@ public class MAPIAttribute {
// All done
return attrs;
}
- private static int getLength(int type, InputStream inp) throws IOException {
- switch(type) {
- case Types.NULL:
- return 0;
- case Types.BOOLEAN:
- case Types.SHORT:
- return 2;
- case Types.LONG:
- case Types.FLOAT:
- case Types.ERROR:
- return 4;
- case Types.LONG_LONG:
- case Types.DOUBLE:
- case Types.APP_TIME:
- case Types.TIME:
- case Types.CURRENCY:
- return 8;
- case Types.CLS_ID:
- return 16;
- case Types.ASCII_STRING:
- case Types.UNICODE_STRING:
- case Types.DIRECTORY:
- case Types.BINARY:
+ private static int getLength(MAPIType type, InputStream inp) throws IOException {
+ if (type.isFixedLength()) {
+ return type.getLength();
+ }
+ if (type == Types.ASCII_STRING ||
+ type == Types.UNICODE_STRING ||
+ type == Types.DIRECTORY ||
+ type == Types.BINARY) {
// Need to read the length, as it varies
return LittleEndian.readInt(inp);
- default:
+ } else {
throw new IllegalArgumentException("Unknown type " + type);
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIStringAttribute.java b/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIStringAttribute.java
index d53e59c7d5..b48651c094 100644
--- a/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIStringAttribute.java
+++ b/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIStringAttribute.java
@@ -37,13 +37,13 @@ public final class MAPIStringAttribute extends MAPIAttribute {
super(property, type, data);
String tmpData = null;
- if(type == Types.ASCII_STRING) {
+ if(type == Types.ASCII_STRING.getId()) {
try {
tmpData = new String(data, CODEPAGE);
} catch(UnsupportedEncodingException e) {
throw new RuntimeException("JVM Broken - core encoding " + CODEPAGE + " missing");
}
- } else if(type == Types.UNICODE_STRING) {
+ } else if(type == Types.UNICODE_STRING.getId()) {
tmpData = StringUtil.getFromUnicodeLE(data);
} else {
throw new IllegalArgumentException("Not a string type " + type);
diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java b/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java
index 20016fd6b3..12b98f1802 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java
@@ -17,6 +17,7 @@
package org.apache.poi.hslf.blip;
+import org.apache.poi.util.PngUtils;
import org.apache.poi.hslf.model.Picture;
import org.apache.poi.hslf.exceptions.HSLFException;
@@ -35,22 +36,19 @@ public final class PNG extends Bitmap {
/**
* @return PNG data
*/
- public byte[] getData(){
- byte[] data = super.getData();
- try {
- //PNG created on MAC may have a 16-byte prefix which prevents successful reading.
- //Just cut it off!.
- BufferedImage bi = ImageIO.read(new ByteArrayInputStream(data));
- if (bi == null){
- byte[] png = new byte[data.length-16];
- System.arraycopy(data, 16, png, 0, png.length);
- data = png;
- }
- } catch (IOException e){
- throw new HSLFException(e);
- }
- return data;
- }
+ public byte[] getData() {
+ byte[] data = super.getData();
+
+ //PNG created on MAC may have a 16-byte prefix which prevents successful reading.
+ //Just cut it off!.
+ if (PngUtils.matchesPngHeader(data, 16)) {
+ byte[] png = new byte[data.length-16];
+ System.arraycopy(data, 16, png, 0, png.length);
+ data = png;
+ }
+
+ return data;
+ }
/**
* @return type of this picture
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java b/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java
index 747c903970..86c67dcebd 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java
@@ -218,6 +218,9 @@ public final class PPGraphics2D extends Graphics2D implements Cloneable {
p.setPath(path);
p.getFill().setForegroundColor(null);
applyStroke(p);
+ if (_paint instanceof Color) {
+ p.setLineColor((Color)_paint);
+ }
_group.addShape(p);
}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java b/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java
index 7c600e7014..8e26b48c94 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java
@@ -39,9 +39,9 @@ import org.apache.poi.hsmf.datatypes.Chunks;
import org.apache.poi.hsmf.datatypes.MAPIProperty;
import org.apache.poi.hsmf.datatypes.NameIdChunks;
import org.apache.poi.hsmf.datatypes.RecipientChunks;
-import org.apache.poi.hsmf.datatypes.Types;
import org.apache.poi.hsmf.datatypes.RecipientChunks.RecipientChunksSorter;
import org.apache.poi.hsmf.datatypes.StringChunk;
+import org.apache.poi.hsmf.datatypes.Types;
import org.apache.poi.hsmf.exceptions.ChunkNotFoundException;
import org.apache.poi.hsmf.parsers.POIFSChunkParser;
import org.apache.poi.poifs.filesystem.DirectoryNode;
@@ -214,7 +214,7 @@ public class MAPIMessage extends POIDocument {
try {
MAPIRtfAttribute rtf = new MAPIRtfAttribute(
- MAPIProperty.RTF_COMPRESSED, Types.BINARY, chunk.getValue()
+ MAPIProperty.RTF_COMPRESSED, Types.BINARY.getId(), chunk.getValue()
);
return rtf.getDataString();
} catch(IOException e) {
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/AttachmentChunks.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/AttachmentChunks.java
index af2ea642a5..55f8a5f254 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/AttachmentChunks.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/AttachmentChunks.java
@@ -31,10 +31,13 @@ import static org.apache.poi.hsmf.datatypes.MAPIProperty.ATTACH_MIME_TAG;
import static org.apache.poi.hsmf.datatypes.MAPIProperty.ATTACH_RENDERING;
import static org.apache.poi.hsmf.datatypes.MAPIProperty.ATTACH_SIZE;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
+import org.apache.poi.hsmf.MAPIMessage;
+
/**
* Collection of convenence chunks for standard parts of the MSG file attachment.
*/
@@ -68,6 +71,36 @@ public class AttachmentChunks implements ChunkGroup {
this.poifsName = poifsName;
}
+
+ /**
+ * Is this Attachment an embedded MAPI message?
+ */
+ public boolean isEmbeddedMessage() {
+ return (attachmentDirectory != null);
+ }
+ /**
+ * Returns the embedded MAPI message, if the attachment
+ * is an embedded message, or null otherwise
+ */
+ public MAPIMessage getEmbeddedMessage() throws IOException {
+ if (attachmentDirectory != null) {
+ return attachmentDirectory.getAsEmbededMessage();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the embedded object, if the attachment is an
+ * object based embedding (image, document etc), or null
+ * if it's an embedded message
+ */
+ public byte[] getEmbeddedAttachmentObject() {
+ if (attachData != null) {
+ return attachData.getValue();
+ }
+ return null;
+ }
+
public Chunk[] getAll() {
return allChunks.toArray(new Chunk[allChunks.size()]);
}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/ByteChunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/ByteChunk.java
index fc84d3731b..d8b26b3952 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/ByteChunk.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/ByteChunk.java
@@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import org.apache.poi.hsmf.datatypes.Types.MAPIType;
import org.apache.poi.util.IOUtils;
/**
@@ -36,14 +37,14 @@ public class ByteChunk extends Chunk {
/**
* Creates a Byte Chunk.
*/
- public ByteChunk(String namePrefix, int chunkId, int type) {
+ public ByteChunk(String namePrefix, int chunkId, MAPIType type) {
super(namePrefix, chunkId, type);
}
/**
* Create a Byte Chunk, with the specified
* type.
*/
- public ByteChunk(int chunkId, int type) {
+ public ByteChunk(int chunkId, MAPIType type) {
super(chunkId, type);
}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunk.java
index 7fcb252c96..a111eb32a5 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunk.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunk.java
@@ -21,19 +21,21 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import org.apache.poi.hsmf.datatypes.Types.MAPIType;
+
abstract public class Chunk {
public static final String DEFAULT_NAME_PREFIX = "__substg1.0_";
protected int chunkId;
- protected int type;
+ protected MAPIType type;
protected String namePrefix;
- protected Chunk(String namePrefix, int chunkId, int type) {
+ protected Chunk(String namePrefix, int chunkId, MAPIType type) {
this.namePrefix = namePrefix;
this.chunkId = chunkId;
this.type = type;
}
- protected Chunk(int chunkId, int type) {
+ protected Chunk(int chunkId, MAPIType type) {
this(DEFAULT_NAME_PREFIX, chunkId, type);
}
@@ -47,7 +49,7 @@ abstract public class Chunk {
/**
* Gets the numeric type of this chunk.
*/
- public int getType() {
+ public MAPIType getType() {
return this.type;
}
@@ -55,8 +57,7 @@ abstract public class Chunk {
* Creates a string to use to identify this chunk in the POI file system object.
*/
public String getEntryName() {
- String type = Integer.toHexString(this.type);
- while(type.length() < 4) type = "0" + type;
+ String type = this.type.asFileEnding();
String chunkId = Integer.toHexString(this.chunkId);
while(chunkId.length() < 4) chunkId = "0" + chunkId;
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/DirectoryChunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/DirectoryChunk.java
index 156c6f2602..5365a63259 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/DirectoryChunk.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/DirectoryChunk.java
@@ -21,6 +21,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import org.apache.poi.hsmf.MAPIMessage;
+import org.apache.poi.hsmf.datatypes.Types.MAPIType;
import org.apache.poi.poifs.filesystem.DirectoryNode;
/**
@@ -33,7 +34,7 @@ import org.apache.poi.poifs.filesystem.DirectoryNode;
public class DirectoryChunk extends Chunk {
private DirectoryNode dir;
- public DirectoryChunk(DirectoryNode dir, String namePrefix, int chunkId, int type) {
+ public DirectoryChunk(DirectoryNode dir, String namePrefix, int chunkId, MAPIType type) {
super(namePrefix, chunkId, type);
this.dir = dir;
}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MAPIProperty.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MAPIProperty.java
index d5b274a498..a5ee6cdca5 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MAPIProperty.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MAPIProperty.java
@@ -20,8 +20,11 @@ package org.apache.poi.hsmf.datatypes;
import static org.apache.poi.hsmf.datatypes.Types.ASCII_STRING;
import static org.apache.poi.hsmf.datatypes.Types.BINARY;
import static org.apache.poi.hsmf.datatypes.Types.BOOLEAN;
+import static org.apache.poi.hsmf.datatypes.Types.CLS_ID;
import static org.apache.poi.hsmf.datatypes.Types.DIRECTORY;
import static org.apache.poi.hsmf.datatypes.Types.LONG;
+import static org.apache.poi.hsmf.datatypes.Types.LONG_LONG;
+import static org.apache.poi.hsmf.datatypes.Types.SHORT;
import static org.apache.poi.hsmf.datatypes.Types.TIME;
import java.util.Collection;
@@ -29,6 +32,8 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import org.apache.poi.hsmf.datatypes.Types.MAPIType;
+
/**
* Holds the list of MAPI Attributes, and allows lookup
* by friendly name, ID and MAPI Property Name.
@@ -49,7 +54,7 @@ public class MAPIProperty {
public static final MAPIProperty AB_PROVIDERS =
new MAPIProperty(0x3d01, BINARY, "AbProviders", "PR_AB_PROVIDERS");
public static final MAPIProperty AB_SEARCH_PATH =
- new MAPIProperty(0x3d05, 4354, "AbSearchPath", "PR_AB_SEARCH_PATH");
+ new MAPIProperty(0x3d05, Types.createCustom(4354), "AbSearchPath", "PR_AB_SEARCH_PATH");
public static final MAPIProperty AB_SEARCH_PATH_UPDATE =
new MAPIProperty(0x3d11, BINARY, "AbSearchPathUpdate", "PR_AB_SEARCH_PATH_UPDATE");
public static final MAPIProperty ACCESS =
@@ -75,15 +80,15 @@ public class MAPIProperty {
public static final MAPIProperty ATTACH_ADDITIONAL_INFO =
new MAPIProperty(0x370f, BINARY, "AttachAdditionalInfo", "PR_ATTACH_ADDITIONAL_INFO");
public static final MAPIProperty ATTACH_CONTENT_BASE =
- new MAPIProperty(0x3711, -1, "AttachContentBase", "PR_ATTACH_CONTENT_BASE");
+ new MAPIProperty(0x3711, Types.UNKNOWN, "AttachContentBase", "PR_ATTACH_CONTENT_BASE");
public static final MAPIProperty ATTACH_CONTENT_ID =
- new MAPIProperty(0x3712, -1, "AttachContentId", "PR_ATTACH_CONTENT_ID");
+ new MAPIProperty(0x3712, Types.UNKNOWN, "AttachContentId", "PR_ATTACH_CONTENT_ID");
public static final MAPIProperty ATTACH_CONTENT_LOCATION =
- new MAPIProperty(0x3713, -1, "AttachContentLocation", "PR_ATTACH_CONTENT_LOCATION");
+ new MAPIProperty(0x3713, Types.UNKNOWN, "AttachContentLocation", "PR_ATTACH_CONTENT_LOCATION");
public static final MAPIProperty ATTACH_DATA =
new MAPIProperty(0x3701, BINARY, "AttachData", "PR_ATTACH_DATA_OBJ");
public static final MAPIProperty ATTACH_DISPOSITION =
- new MAPIProperty(0x3716, -1, "AttachDisposition", "PR_ATTACH_DISPOSITION");
+ new MAPIProperty(0x3716, Types.UNKNOWN, "AttachDisposition", "PR_ATTACH_DISPOSITION");
public static final MAPIProperty ATTACH_ENCODING =
new MAPIProperty(0x3702, BINARY, "AttachEncoding", "PR_ATTACH_ENCODING");
public static final MAPIProperty ATTACH_EXTENSION =
@@ -91,7 +96,7 @@ public class MAPIProperty {
public static final MAPIProperty ATTACH_FILENAME =
new MAPIProperty(0x3704, ASCII_STRING, "AttachFilename", "PR_ATTACH_FILENAME");
public static final MAPIProperty ATTACH_FLAGS =
- new MAPIProperty(0x3714, -1, "AttachFlags", "PR_ATTACH_FLAGS");
+ new MAPIProperty(0x3714, Types.UNKNOWN, "AttachFlags", "PR_ATTACH_FLAGS");
public static final MAPIProperty ATTACH_LONG_FILENAME =
new MAPIProperty(0x3707, ASCII_STRING, "AttachLongFilename", "PR_ATTACH_LONG_FILENAME");
public static final MAPIProperty ATTACH_LONG_PATHNAME =
@@ -99,11 +104,11 @@ public class MAPIProperty {
public static final MAPIProperty ATTACH_METHOD =
new MAPIProperty(0x3705, LONG, "AttachMethod", "PR_ATTACH_METHOD");
public static final MAPIProperty ATTACH_MIME_SEQUENCE =
- new MAPIProperty(0x3710, -1, "AttachMimeSequence", "PR_ATTACH_MIME_SEQUENCE");
+ new MAPIProperty(0x3710, Types.UNKNOWN, "AttachMimeSequence", "PR_ATTACH_MIME_SEQUENCE");
public static final MAPIProperty ATTACH_MIME_TAG =
new MAPIProperty(0x370e, ASCII_STRING, "AttachMimeTag", "PR_ATTACH_MIME_TAG");
public static final MAPIProperty ATTACH_NETSCAPE_MAC_INFO =
- new MAPIProperty(0x3715, -1, "AttachNetscapeMacInfo", "PR_ATTACH_NETSCAPE_MAC_INFO");
+ new MAPIProperty(0x3715, Types.UNKNOWN, "AttachNetscapeMacInfo", "PR_ATTACH_NETSCAPE_MAC_INFO");
public static final MAPIProperty ATTACH_NUM =
new MAPIProperty(0xe21, LONG, "AttachNum", "PR_ATTACH_NUM");
public static final MAPIProperty ATTACH_PATHNAME =
@@ -125,19 +130,19 @@ public class MAPIProperty {
public static final MAPIProperty AUTO_FORWARDED =
new MAPIProperty(5, BOOLEAN, "AutoForwarded", "PR_AUTO_FORWARDED");
public static final MAPIProperty AUTO_RESPONSE_SUPPRESS =
- new MAPIProperty(0x3fdf, -1, "AutoResponseSuppress", "PR_AUTO_RESPONSE_SUPPRESS");
+ new MAPIProperty(0x3fdf, Types.UNKNOWN, "AutoResponseSuppress", "PR_AUTO_RESPONSE_SUPPRESS");
public static final MAPIProperty BIRTHDAY =
new MAPIProperty(0x3a42, TIME, "Birthday", "PR_BIRTHDAY");
public static final MAPIProperty BODY =
new MAPIProperty(0x1000, ASCII_STRING, "Body", "PR_BODY");
public static final MAPIProperty BODY_CONTENT_ID =
- new MAPIProperty(0x1015, -1, "BodyContentId", "PR_BODY_CONTENT_ID");
+ new MAPIProperty(0x1015, Types.UNKNOWN, "BodyContentId", "PR_BODY_CONTENT_ID");
public static final MAPIProperty BODY_CONTENT_LOCATION =
- new MAPIProperty(0x1014, -1, "BodyContentLocation", "PR_BODY_CONTENT_LOCATION");
+ new MAPIProperty(0x1014, Types.UNKNOWN, "BodyContentLocation", "PR_BODY_CONTENT_LOCATION");
public static final MAPIProperty BODY_CRC =
new MAPIProperty(0xe1c, LONG, "BodyCrc", "PR_BODY_CRC");
public static final MAPIProperty BODY_HTML =
- new MAPIProperty(0x1013, -1, "BodyHtml", "data");
+ new MAPIProperty(0x1013, Types.UNKNOWN, "BodyHtml", "data");
public static final MAPIProperty BUSINESS_FAX_NUMBER =
new MAPIProperty(0x3a24, ASCII_STRING, "BusinessFaxNumber", "PR_BUSINESS_FAX_NUMBER");
public static final MAPIProperty BUSINESS_HOME_PAGE =
@@ -147,7 +152,7 @@ public class MAPIProperty {
public static final MAPIProperty CAR_TELEPHONE_NUMBER =
new MAPIProperty(0x3a1e, ASCII_STRING, "CarTelephoneNumber", "PR_CAR_TELEPHONE_NUMBER");
public static final MAPIProperty CHILDRENS_NAMES =
- new MAPIProperty(0x3a58, 4126, "ChildrensNames", "PR_CHILDRENS_NAMES");
+ new MAPIProperty(0x3a58, Types.createCustom(4126), "ChildrensNames", "PR_CHILDRENS_NAMES");
public static final MAPIProperty CLIENT_SUBMIT_TIME =
new MAPIProperty(0x39, TIME, "ClientSubmitTime", "PR_CLIENT_SUBMIT_TIME");
public static final MAPIProperty COMMENT =
@@ -161,15 +166,15 @@ public class MAPIProperty {
public static final MAPIProperty COMPUTER_NETWORK_NAME =
new MAPIProperty(0x3a49, ASCII_STRING, "ComputerNetworkName", "PR_COMPUTER_NETWORK_NAME");
public static final MAPIProperty CONTACT_ADDRTYPES =
- new MAPIProperty(0x3a54, 4126, "ContactAddrtypes", "PR_CONTACT_ADDRTYPES");
+ new MAPIProperty(0x3a54, Types.createCustom(4126), "ContactAddrtypes", "PR_CONTACT_ADDRTYPES");
public static final MAPIProperty CONTACT_DEFAULT_ADDRESS_INDEX =
new MAPIProperty(0x3a55, LONG, "ContactDefaultAddressIndex", "PR_CONTACT_DEFAULT_ADDRESS_INDEX");
public static final MAPIProperty CONTACT_EMAIL_ADDRESSES =
- new MAPIProperty(0x3a56, 4126, "ContactEmailAddresses", "PR_CONTACT_EMAIL_ADDRESSES");
+ new MAPIProperty(0x3a56, Types.createCustom(4126), "ContactEmailAddresses", "PR_CONTACT_EMAIL_ADDRESSES");
public static final MAPIProperty CONTACT_ENTRY_IDS =
- new MAPIProperty(0x3a53, 4354, "ContactEntryIds", "PR_CONTACT_ENTRYIDS");
+ new MAPIProperty(0x3a53, Types.createCustom(4354), "ContactEntryIds", "PR_CONTACT_ENTRYIDS");
public static final MAPIProperty CONTACT_VERSION =
- new MAPIProperty(0x3a52, 72, "ContactVersion", "PR_CONTACT_VERSION");
+ new MAPIProperty(0x3a52, CLS_ID, "ContactVersion", "PR_CONTACT_VERSION");
public static final MAPIProperty CONTAINER_CLASS =
new MAPIProperty(0x3613, ASCII_STRING, "ContainerClass", "PR_CONTAINER_CLASS");
public static final MAPIProperty CONTAINER_CONTENTS =
@@ -179,7 +184,7 @@ public class MAPIProperty {
public static final MAPIProperty CONTAINER_HIERARCHY =
new MAPIProperty(0x360e, DIRECTORY, "ContainerHierarchy", "PR_CONTAINER_HIERARCHY");
public static final MAPIProperty CONTAINER_MODIFY_VERSION =
- new MAPIProperty(0x3614, 20, "ContainerModifyVersion", "PR_CONTAINER_MODIFY_VERSION");
+ new MAPIProperty(0x3614, LONG_LONG, "ContainerModifyVersion", "PR_CONTAINER_MODIFY_VERSION");
public static final MAPIProperty CONTENT_CONFIDENTIALITY_ALGORITHM_ID =
new MAPIProperty(6, BINARY, "ContentConfidentialityAlgorithmId", "PR_CONTENT_CONFIDENTIALITY_ALGORITHM_ID");
public static final MAPIProperty CONTENT_CORRELATOR =
@@ -197,7 +202,7 @@ public class MAPIProperty {
public static final MAPIProperty CONTENT_UNREAD =
new MAPIProperty(0x3603, LONG, "ContentUnread", "PR_CONTENT_UNREAD");
public static final MAPIProperty CONTENTS_SORT_ORDER =
- new MAPIProperty(0x360d, 4099, "ContentsSortOrder", "PR_CONTENTS_SORT_ORDER");
+ new MAPIProperty(0x360d, Types.createCustom(4099), "ContentsSortOrder", "PR_CONTENTS_SORT_ORDER");
public static final MAPIProperty CONTROL_FLAGS =
new MAPIProperty(0x3f00, LONG, "ControlFlags", "PR_CONTROL_FLAGS");
public static final MAPIProperty CONTROL_ID =
@@ -231,9 +236,9 @@ public class MAPIProperty {
public static final MAPIProperty CREATION_TIME =
new MAPIProperty(0x3007, TIME, "CreationTime", "PR_CREATION_TIME");
public static final MAPIProperty CREATION_VERSION =
- new MAPIProperty(0xe19, 20, "CreationVersion", "PR_CREATION_VERSION");
+ new MAPIProperty(0xe19, LONG_LONG, "CreationVersion", "PR_CREATION_VERSION");
public static final MAPIProperty CURRENT_VERSION =
- new MAPIProperty(0xe00, 20, "CurrentVersion", "PR_CURRENT_VERSION");
+ new MAPIProperty(0xe00, LONG_LONG, "CurrentVersion", "PR_CURRENT_VERSION");
public static final MAPIProperty CUSTOMER_ID =
new MAPIProperty(0x3a4a, ASCII_STRING, "CustomerId", "PR_CUSTOMER_ID");
public static final MAPIProperty DEF_CREATE_DL =
@@ -299,13 +304,13 @@ public class MAPIProperty {
public static final MAPIProperty ENTRY_ID =
new MAPIProperty(0xfff, BINARY, "EntryId", "PR_ENTRYID");
public static final MAPIProperty EXPAND_BEGIN_TIME =
- new MAPIProperty(0x3618, -1, "ExpandBeginTime", "PR_EXPAND_BEGIN_TIME");
+ new MAPIProperty(0x3618, Types.UNKNOWN, "ExpandBeginTime", "PR_EXPAND_BEGIN_TIME");
public static final MAPIProperty EXPAND_END_TIME =
- new MAPIProperty(0x3619, -1, "ExpandEndTime", "PR_EXPAND_END_TIME");
+ new MAPIProperty(0x3619, Types.UNKNOWN, "ExpandEndTime", "PR_EXPAND_END_TIME");
public static final MAPIProperty EXPANDED_BEGIN_TIME =
- new MAPIProperty(0x361a, -1, "ExpandedBeginTime", "PR_EXPANDED_BEGIN_TIME");
+ new MAPIProperty(0x361a, Types.UNKNOWN, "ExpandedBeginTime", "PR_EXPANDED_BEGIN_TIME");
public static final MAPIProperty EXPANDED_END_TIME =
- new MAPIProperty(0x361b, -1, "ExpandedEndTime", "PR_EXPANDED_END_TIME");
+ new MAPIProperty(0x361b, Types.UNKNOWN, "ExpandedEndTime", "PR_EXPANDED_END_TIME");
public static final MAPIProperty EXPIRY_TIME =
new MAPIProperty(0x15, TIME, "ExpiryTime", "PR_EXPIRY_TIME");
public static final MAPIProperty EXPLICIT_CONVERSION =
@@ -323,17 +328,17 @@ public class MAPIProperty {
public static final MAPIProperty FORM_CATEGORY_SUB =
new MAPIProperty(0x3305, ASCII_STRING, "FormCategorySub", "PR_FORM_CATEGORY_SUB");
public static final MAPIProperty FORM_CLSID =
- new MAPIProperty(0x3302, 72, "FormClsid", "PR_FORM_ClsID");
+ new MAPIProperty(0x3302, CLS_ID, "FormClsid", "PR_FORM_ClsID");
public static final MAPIProperty FORM_CONTACT_NAME =
new MAPIProperty(0x3303, ASCII_STRING, "FormContactName", "PR_FORM_CONTACT_NAME");
public static final MAPIProperty FORM_DESIGNER_GUID =
- new MAPIProperty(0x3309, 72, "FormDesignerGuid", "PR_FORM_DESIGNER_GUID");
+ new MAPIProperty(0x3309, CLS_ID, "FormDesignerGuid", "PR_FORM_DESIGNER_GUID");
public static final MAPIProperty FORM_DESIGNER_NAME =
new MAPIProperty(0x3308, ASCII_STRING, "FormDesignerName", "PR_FORM_DESIGNER_NAME");
public static final MAPIProperty FORM_HIDDEN =
new MAPIProperty(0x3307, BOOLEAN, "FormHidden", "PR_FORM_HIDDEN");
public static final MAPIProperty FORM_HOST_MAP =
- new MAPIProperty(0x3306, 4099, "FormHostMap", "PR_FORM_HOST_MAP");
+ new MAPIProperty(0x3306, Types.createCustom(4099), "FormHostMap", "PR_FORM_HOST_MAP");
public static final MAPIProperty FORM_MESSAGE_BEHAVIOR =
new MAPIProperty(0x330a, LONG, "FormMessageBehavior", "PR_FORM_MESSAGE_BEHAVIOR");
public static final MAPIProperty FORM_VERSION =
@@ -341,7 +346,7 @@ public class MAPIProperty {
public static final MAPIProperty FTP_SITE =
new MAPIProperty(0x3a4c, ASCII_STRING, "FtpSite", "PR_FTP_SITE");
public static final MAPIProperty GENDER =
- new MAPIProperty(0x3a4d, 2, "Gender", "PR_GENDER");
+ new MAPIProperty(0x3a4d, SHORT, "Gender", "PR_GENDER");
public static final MAPIProperty GENERATION =
new MAPIProperty(0x3a05, ASCII_STRING, "Generation", "PR_GENERATION");
public static final MAPIProperty GIVEN_NAME =
@@ -373,9 +378,9 @@ public class MAPIProperty {
public static final MAPIProperty HOME_TELEPHONE_NUMBER =
new MAPIProperty(0x3a09, ASCII_STRING, "HomeTelephoneNumber", "PR_HOME_TELEPHONE_NUMBER");
public static final MAPIProperty INET_MAIL_OVERRIDE_CHARSET =
- new MAPIProperty(0x5903, -1, "INetMailOverrideCharset", "Charset");
+ new MAPIProperty(0x5903, Types.UNKNOWN, "INetMailOverrideCharset", "Charset");
public static final MAPIProperty INET_MAIL_OVERRIDE_FORMAT =
- new MAPIProperty(0x5902, -1, "INetMailOverrideFormat", "Format");
+ new MAPIProperty(0x5902, Types.UNKNOWN, "INetMailOverrideFormat", "Format");
public static final MAPIProperty ICON =
new MAPIProperty(0xffd, BINARY, "Icon", "PR_ICON");
public static final MAPIProperty IDENTITY_DISPLAY =
@@ -389,7 +394,7 @@ public class MAPIProperty {
public static final MAPIProperty IMPORTANCE =
new MAPIProperty(0x17, LONG, "Importance", "PR_IMPORTANCE");
public static final MAPIProperty IN_REPLY_TO_ID =
- new MAPIProperty(0x1042, -1, "InReplyToId", "PR_IN_REPLY_TO_ID");
+ new MAPIProperty(0x1042, Types.UNKNOWN, "InReplyToId", "PR_IN_REPLY_TO_ID");
public static final MAPIProperty INCOMPLETE_COPY =
new MAPIProperty(0x35, BOOLEAN, "IncompleteCopy", "PR_INCOMPLETE_COPY");
public static final MAPIProperty INITIAL_DETAILS_PANE =
@@ -403,7 +408,7 @@ public class MAPIProperty {
public static final MAPIProperty INTERNET_ARTICLE_NUMBER =
new MAPIProperty(0xe23, LONG, "InternetArticleNumber", "PR_INTERNET_ARTICLE_NUMBER");
public static final MAPIProperty INTERNET_CPID =
- new MAPIProperty(0x3fde, -1, "InternetCPID", "PR_INTERNET_CPID");
+ new MAPIProperty(0x3fde, Types.UNKNOWN, "InternetCPID", "PR_INTERNET_CPID");
public static final MAPIProperty INTERNET_CONTROL =
new MAPIProperty(0x1031, ASCII_STRING, "InternetControl", "PR_INTERNET_CONTROL");
public static final MAPIProperty INTERNET_DISTRIBUTION =
@@ -457,39 +462,39 @@ public class MAPIProperty {
public static final MAPIProperty LATEST_DELIVERY_TIME =
new MAPIProperty(0x19, TIME, "LatestDeliveryTime", "PR_LATEST_DELIVERY_TIME");
public static final MAPIProperty LIST_HELP =
- new MAPIProperty(0x1043, -1, "ListHelp", "PR_LIST_HELP");
+ new MAPIProperty(0x1043, Types.UNKNOWN, "ListHelp", "PR_LIST_HELP");
public static final MAPIProperty LIST_SUBSCRIBE =
- new MAPIProperty(0x1044, -1, "ListSubscribe", "PR_LIST_SUBSCRIBE");
+ new MAPIProperty(0x1044, Types.UNKNOWN, "ListSubscribe", "PR_LIST_SUBSCRIBE");
public static final MAPIProperty LIST_UNSUBSCRIBE =
- new MAPIProperty(0x1045, -1, "ListUnsubscribe", "PR_LIST_UNSUBSCRIBE");
+ new MAPIProperty(0x1045, Types.UNKNOWN, "ListUnsubscribe", "PR_LIST_UNSUBSCRIBE");
public static final MAPIProperty LOCALITY =
new MAPIProperty(0x3a27, ASCII_STRING, "Locality", "PR_LOCALITY");
public static final MAPIProperty LOCALLY_DELIVERED =
- new MAPIProperty(0x6745, -1, "LocallyDelivered", "ptagLocallyDelivered");
+ new MAPIProperty(0x6745, Types.UNKNOWN, "LocallyDelivered", "ptagLocallyDelivered");
public static final MAPIProperty LOCATION =
new MAPIProperty(0x3a0d, ASCII_STRING, "Location", "PR_LOCATION");
public static final MAPIProperty LOCK_BRANCH_ID =
- new MAPIProperty(0x3800, -1, "LockBranchId", "PR_LOCK_BRANCH_ID");
+ new MAPIProperty(0x3800, Types.UNKNOWN, "LockBranchId", "PR_LOCK_BRANCH_ID");
public static final MAPIProperty LOCK_DEPTH =
- new MAPIProperty(0x3808, -1, "LockDepth", "PR_LOCK_DEPTH");
+ new MAPIProperty(0x3808, Types.UNKNOWN, "LockDepth", "PR_LOCK_DEPTH");
public static final MAPIProperty LOCK_ENLISTMENT_CONTEXT =
- new MAPIProperty(0x3804, -1, "LockEnlistmentContext", "PR_LOCK_ENLISTMENT_CONTEXT");
+ new MAPIProperty(0x3804, Types.UNKNOWN, "LockEnlistmentContext", "PR_LOCK_ENLISTMENT_CONTEXT");
public static final MAPIProperty LOCK_EXPIRY_TIME =
- new MAPIProperty(0x380a, -1, "LockExpiryTime", "PR_LOCK_EXPIRY_TIME");
+ new MAPIProperty(0x380a, Types.UNKNOWN, "LockExpiryTime", "PR_LOCK_EXPIRY_TIME");
public static final MAPIProperty LOCK_PERSISTENT =
- new MAPIProperty(0x3807, -1, "LockPersistent", "PR_LOCK_PERSISTENT");
+ new MAPIProperty(0x3807, Types.UNKNOWN, "LockPersistent", "PR_LOCK_PERSISTENT");
public static final MAPIProperty LOCK_RESOURCE_DID =
- new MAPIProperty(0x3802, -1, "LockResourceDid", "PR_LOCK_RESOURCE_DID");
+ new MAPIProperty(0x3802, Types.UNKNOWN, "LockResourceDid", "PR_LOCK_RESOURCE_DID");
public static final MAPIProperty LOCK_RESOURCE_FID =
- new MAPIProperty(0x3801, -1, "LockResourceFid", "PR_LOCK_RESOURCE_FID");
+ new MAPIProperty(0x3801, Types.UNKNOWN, "LockResourceFid", "PR_LOCK_RESOURCE_FID");
public static final MAPIProperty LOCK_RESOURCE_MID =
- new MAPIProperty(0x3803, -1, "LockResourceMid", "PR_LOCK_RESOURCE_MID");
+ new MAPIProperty(0x3803, Types.UNKNOWN, "LockResourceMid", "PR_LOCK_RESOURCE_MID");
public static final MAPIProperty LOCK_SCOPE =
- new MAPIProperty(0x3806, -1, "LockScope", "PR_LOCK_SCOPE");
+ new MAPIProperty(0x3806, Types.UNKNOWN, "LockScope", "PR_LOCK_SCOPE");
public static final MAPIProperty LOCK_TIMEOUT =
- new MAPIProperty(0x3809, -1, "LockTimeout", "PR_LOCK_TIMEOUT");
+ new MAPIProperty(0x3809, Types.UNKNOWN, "LockTimeout", "PR_LOCK_TIMEOUT");
public static final MAPIProperty LOCK_TYPE =
- new MAPIProperty(0x3805, -1, "LockType", "PR_LOCK_TYPE");
+ new MAPIProperty(0x3805, Types.UNKNOWN, "LockType", "PR_LOCK_TYPE");
public static final MAPIProperty MAIL_PERMISSION =
new MAPIProperty(0x3a0e, BOOLEAN, "MailPermission", "PR_MAIL_PERMISSION");
public static final MAPIProperty MANAGER_NAME =
@@ -505,7 +510,7 @@ public class MAPIProperty {
public static final MAPIProperty MESSAGE_CLASS =
new MAPIProperty(0x1a, ASCII_STRING, "MessageClass", "PR_MESSAGE_CLASS");
public static final MAPIProperty MESSAGE_CODEPAGE =
- new MAPIProperty(0x3ffd, -1, "MessageCodepage", "PR_MESSAGE_CODEPAGE");
+ new MAPIProperty(0x3ffd, Types.UNKNOWN, "MessageCodepage", "PR_MESSAGE_CODEPAGE");
public static final MAPIProperty MESSAGE_DELIVERY_ID =
new MAPIProperty(0x1b, BINARY, "MessageDeliveryId", "PR_MESSAGE_DELIVERY_ID");
public static final MAPIProperty MESSAGE_DELIVERY_TIME =
@@ -537,7 +542,7 @@ public class MAPIProperty {
public static final MAPIProperty MOBILE_TELEPHONE_NUMBER =
new MAPIProperty(0x3a1c, ASCII_STRING, "MobileTelephoneNumber", "PR_MOBILE_TELEPHONE_NUMBER");
public static final MAPIProperty MODIFY_VERSION =
- new MAPIProperty(0xe1a, 20, "ModifyVersion", "PR_MODIFY_VERSION");
+ new MAPIProperty(0xe1a, LONG_LONG, "ModifyVersion", "PR_MODIFY_VERSION");
public static final MAPIProperty MSG_STATUS =
new MAPIProperty(0xe17, LONG, "MsgStatus", "PR_MSG_STATUS");
public static final MAPIProperty NDR_DIAG_CODE =
@@ -545,7 +550,7 @@ public class MAPIProperty {
public static final MAPIProperty NDR_REASON_CODE =
new MAPIProperty(0xc04, LONG, "NdrReasonCode", "PR_NDR_REASON_CODE");
public static final MAPIProperty NDR_STATUS_CODE =
- new MAPIProperty(0xc20, -1, "NdrStatusCode", "PR_NDR_STATUS_CODE");
+ new MAPIProperty(0xc20, Types.UNKNOWN, "NdrStatusCode", "PR_NDR_STATUS_CODE");
public static final MAPIProperty NEWSGROUP_NAME =
new MAPIProperty(0xe24, ASCII_STRING, "NewsgroupName", "PR_NEWSGROUP_NAME");
public static final MAPIProperty NICKNAME =
@@ -559,7 +564,7 @@ public class MAPIProperty {
public static final MAPIProperty NORMALIZED_SUBJECT =
new MAPIProperty(0xe1d, ASCII_STRING, "NormalizedSubject", "PR_NORMALIZED_SUBJECT");
public static final MAPIProperty NT_SECURITY_DESCRIPTOR =
- new MAPIProperty(0xe27, -1, "NtSecurityDescriptor", "PR_NT_SECURITY_DESCRIPTOR");
+ new MAPIProperty(0xe27, Types.UNKNOWN, "NtSecurityDescriptor", "PR_NT_SECURITY_DESCRIPTOR");
public static final MAPIProperty NULL =
new MAPIProperty(1, LONG, "Null", "PR_NULL");
public static final MAPIProperty OBJECT_TYPE =
@@ -573,11 +578,11 @@ public class MAPIProperty {
public static final MAPIProperty OFFICE_TELEPHONE_NUMBER =
new MAPIProperty(0x3a08, ASCII_STRING, "OfficeTelephoneNumber", "PR_OFFICE_TELEPHONE_NUMBER");
public static final MAPIProperty OOF_REPLY_TYPE =
- new MAPIProperty(0x4080, -1, "OofReplyType", "PR_OOF_REPLY_TYPE");
+ new MAPIProperty(0x4080, Types.UNKNOWN, "OofReplyType", "PR_OOF_REPLY_TYPE");
public static final MAPIProperty ORGANIZATIONAL_ID_NUMBER =
new MAPIProperty(0x3a10, ASCII_STRING, "OrganizationalIdNumber", "PR_ORGANIZATIONAL_ID_NUMBER");
public static final MAPIProperty ORIG_ENTRY_ID =
- new MAPIProperty(0x300f, -1, "OrigEntryId", "PR_ORIG_ENTRYID");
+ new MAPIProperty(0x300f, Types.UNKNOWN, "OrigEntryId", "PR_ORIG_ENTRYID");
public static final MAPIProperty ORIG_MESSAGE_CLASS =
new MAPIProperty(0x4b, ASCII_STRING, "OrigMessageClass", "PR_ORIG_MESSAGE_CLASS");
public static final MAPIProperty ORIGIN_CHECK =
@@ -737,9 +742,9 @@ public class MAPIProperty {
public static final MAPIProperty PROOF_OF_SUBMISSION_REQUESTED =
new MAPIProperty(40, BOOLEAN, "ProofOfSubmissionRequested", "PR_PROOF_OF_SUBMISSION_REQUESTED");
public static final MAPIProperty PROP_ID_SECURE_MAX =
- new MAPIProperty(0x67ff, -1, "PropIdSecureMax", "PROP_ID_SECURE_MAX");
+ new MAPIProperty(0x67ff, Types.UNKNOWN, "PropIdSecureMax", "PROP_ID_SECURE_MAX");
public static final MAPIProperty PROP_ID_SECURE_MIN =
- new MAPIProperty(0x67f0, -1, "PropIdSecureMin", "PROP_ID_SECURE_MIN");
+ new MAPIProperty(0x67f0, Types.UNKNOWN, "PropIdSecureMin", "PROP_ID_SECURE_MIN");
public static final MAPIProperty PROVIDER_DISPLAY =
new MAPIProperty(0x3006, ASCII_STRING, "ProviderDisplay", "PR_PROVIDER_DISPLAY");
public static final MAPIProperty PROVIDER_DLL_NAME =
@@ -751,7 +756,7 @@ public class MAPIProperty {
public static final MAPIProperty PROVIDER_UID =
new MAPIProperty(0x300c, BINARY, "ProviderUid", "PR_PROVIDER_UID");
public static final MAPIProperty PUID =
- new MAPIProperty(0x300e, -1, "Puid", "PR_PUID");
+ new MAPIProperty(0x300e, Types.UNKNOWN, "Puid", "PR_PUID");
public static final MAPIProperty RADIO_TELEPHONE_NUMBER =
new MAPIProperty(0x3a1d, ASCII_STRING, "RadioTelephoneNumber", "PR_RADIO_TELEPHONE_NUMBER");
public static final MAPIProperty RCVD_REPRESENTING_ADDRTYPE =
@@ -783,11 +788,11 @@ public class MAPIProperty {
public static final MAPIProperty RECEIVED_BY_NAME =
new MAPIProperty(0x40, ASCII_STRING, "ReceivedByName", "PR_RECEIVED_BY_NAME");
public static final MAPIProperty RECIPIENT_DISPLAY_NAME =
- new MAPIProperty(0x5ff6, -1, "RecipientDisplayName", null);
+ new MAPIProperty(0x5ff6, Types.UNKNOWN, "RecipientDisplayName", null);
public static final MAPIProperty RECIPIENT_ENTRY_ID =
- new MAPIProperty(0x5ff7, -1, "RecipientEntryId", null);
+ new MAPIProperty(0x5ff7, Types.UNKNOWN, "RecipientEntryId", null);
public static final MAPIProperty RECIPIENT_FLAGS =
- new MAPIProperty(0x5ffd, -1, "RecipientFlags", null);
+ new MAPIProperty(0x5ffd, Types.UNKNOWN, "RecipientFlags", null);
public static final MAPIProperty RECEIVED_BY_SEARCH_KEY =
new MAPIProperty(0x51, BINARY, "ReceivedBySearchKey", "PR_RECEIVED_BY_SEARCH_KEY");
public static final MAPIProperty RECIPIENT_CERTIFICATE =
@@ -887,7 +892,7 @@ public class MAPIProperty {
public static final MAPIProperty SEND_INTERNET_ENCODING =
new MAPIProperty(0x3a71, LONG, "SendInternetEncoding", "PR_SEND_INTERNET_ENCODING");
public static final MAPIProperty SEND_RECALL_REPORT =
- new MAPIProperty(0x6803, -1, "SendRecallReport", "messages");
+ new MAPIProperty(0x6803, Types.UNKNOWN, "SendRecallReport", "messages");
public static final MAPIProperty SEND_RICH_INFO =
new MAPIProperty(0x3a40, BOOLEAN, "SendRichInfo", "PR_SEND_RICH_INFO");
public static final MAPIProperty SENDER_ADDRTYPE =
@@ -915,7 +920,7 @@ public class MAPIProperty {
public static final MAPIProperty SENTMAIL_ENTRY_ID =
new MAPIProperty(0xe0a, BINARY, "SentmailEntryId", "PR_SENTMAIL_ENTRYID");
public static final MAPIProperty SERVICE_DELETE_FILES =
- new MAPIProperty(0x3d10, 4126, "ServiceDeleteFiles", "PR_SERVICE_DELETE_FILES");
+ new MAPIProperty(0x3d10, Types.createCustom(4126), "ServiceDeleteFiles", "PR_SERVICE_DELETE_FILES");
public static final MAPIProperty SERVICE_DLL_NAME =
new MAPIProperty(0x3d0a, ASCII_STRING, "ServiceDllName", "PR_SERVICE_DLL_NAME");
public static final MAPIProperty SERVICE_ENTRY_NAME =
@@ -925,7 +930,7 @@ public class MAPIProperty {
public static final MAPIProperty SERVICE_NAME =
new MAPIProperty(0x3d09, ASCII_STRING, "ServiceName", "PR_SERVICE_NAME");
public static final MAPIProperty SERVICE_SUPPORT_FILES =
- new MAPIProperty(0x3d0f, 4126, "ServiceSupportFiles", "PR_SERVICE_SUPPORT_FILES");
+ new MAPIProperty(0x3d0f, Types.createCustom(4126), "ServiceSupportFiles", "PR_SERVICE_SUPPORT_FILES");
public static final MAPIProperty SERVICE_UID =
new MAPIProperty(0x3d0c, BINARY, "ServiceUid", "PR_SERVICE_UID");
public static final MAPIProperty SERVICES =
@@ -933,7 +938,7 @@ public class MAPIProperty {
public static final MAPIProperty SEVEN_BIT_DISPLAY_NAME =
new MAPIProperty(0x39ff, ASCII_STRING, "SevenBitDisplayName", "PR_SEVEN_BIT_DISPLAY_NAME");
public static final MAPIProperty SMTP_ADDRESS =
- new MAPIProperty(0x39fe, -1, "SmtpAddress", "PR_SMTP_ADDRESS");
+ new MAPIProperty(0x39fe, Types.UNKNOWN, "SmtpAddress", "PR_SMTP_ADDRESS");
public static final MAPIProperty SPOOLER_STATUS =
new MAPIProperty(0xe10, LONG, "SpoolerStatus", "PR_SPOOLER_STATUS");
public static final MAPIProperty SPOUSE_NAME =
@@ -1001,7 +1006,7 @@ public class MAPIProperty {
public static final MAPIProperty USER_CERTIFICATE =
new MAPIProperty(0x3a22, BINARY, "UserCertificate", "PR_USER_CERTIFICATE");
public static final MAPIProperty USER_X509_CERTIFICATE =
- new MAPIProperty(0x3a70, 4354, "UserX509Certificate", "PR_USER_X509_CERTIFICATE");
+ new MAPIProperty(0x3a70, Types.createCustom(4354), "UserX509Certificate", "PR_USER_X509_CERTIFICATE");
public static final MAPIProperty VALID_FOLDER_MASK =
new MAPIProperty(0x35df, LONG, "ValidFolderMask", "PR_VALID_FOLDER_MASK");
public static final MAPIProperty VIEWS_ENTRY_ID =
@@ -1018,20 +1023,22 @@ public class MAPIProperty {
new MAPIProperty(0x3f06, LONG, "Ypos", "PR_YPOS");
public static final MAPIProperty UNKNOWN =
- new MAPIProperty(-1, -1, "Unknown", null);
+ new MAPIProperty(-1, Types.UNKNOWN, "Unknown", null);
// 0x8??? ones are outlook specific, and not standard MAPI
+ // TODO See http://msdn.microsoft.com/en-us/library/ee157150%28v=exchg.80%29 for some
+ // info on how we might decode them properly in the future
private static final int ID_FIRST_CUSTOM = 0x8000;
private static final int ID_LAST_CUSTOM = 0xFFFE;
/* --------------------------------------------------------------------- */
public final int id;
- public final int usualType;
+ public final MAPIType usualType;
public final String name;
public final String mapiProperty;
- private MAPIProperty(int id, int usualType, String name, String mapiProperty) {
+ private MAPIProperty(int id, MAPIType usualType, String name, String mapiProperty) {
this.id = id;
this.usualType = usualType;
this.name = name;
@@ -1077,12 +1084,12 @@ public class MAPIProperty {
return Collections.unmodifiableCollection( attributes.values() );
}
- public static MAPIProperty createCustom(int id, int type, String name) {
+ public static MAPIProperty createCustom(int id, MAPIType type, String name) {
return new CustomMAPIProperty(id, type, name, null);
}
private static class CustomMAPIProperty extends MAPIProperty {
- private CustomMAPIProperty(int id, int usualType, String name, String mapiProperty) {
+ private CustomMAPIProperty(int id, MAPIType usualType, String name, String mapiProperty) {
super(id, usualType, name, mapiProperty);
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessagePropertiesChunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessagePropertiesChunk.java
new file mode 100644
index 0000000000..ab9b1bfaf5
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessagePropertiesChunk.java
@@ -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.hsmf.datatypes;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * A {@link PropertiesChunk} for a Message or Embedded-Message.
+ * This has a 32 byte header
+ */
+public class MessagePropertiesChunk extends PropertiesChunk {
+ private long nextRecipientId;
+ private long nextAttachmentId;
+ private long recipientCount;
+ private long attachmentCount;
+
+ public MessagePropertiesChunk() {
+ super();
+ }
+
+ public long getNextRecipientId() {
+ return nextRecipientId;
+ }
+ public long getNextAttachmentId() {
+ return nextAttachmentId;
+ }
+
+ public long getRecipientCount() {
+ return recipientCount;
+ }
+ public long getAttachmentCount() {
+ return attachmentCount;
+ }
+
+ @Override
+ public void readValue(InputStream stream) throws IOException {
+ // 8 bytes of reserved zeros
+ LittleEndian.readLong(stream);
+
+ // Nexts and counts
+ nextRecipientId = LittleEndian.readUInt(stream);
+ nextAttachmentId = LittleEndian.readUInt(stream);
+ recipientCount = LittleEndian.readUInt(stream);
+ attachmentCount = LittleEndian.readUInt(stream);
+
+ // 8 bytes of reserved zeros
+ LittleEndian.readLong(stream);
+
+ // Now properties
+ readProperties(stream);
+ }
+
+ @Override
+ public void writeValue(OutputStream out) throws IOException {
+ // 8 bytes of reserved zeros
+ out.write(new byte[8]);
+
+ // Nexts and counts
+ LittleEndian.putUInt(nextRecipientId, out);
+ LittleEndian.putUInt(nextAttachmentId, out);
+ LittleEndian.putUInt(recipientCount, out);
+ LittleEndian.putUInt(attachmentCount, out);
+
+ // 8 bytes of reserved zeros
+ out.write(new byte[8]);
+
+ // Now properties
+ writeProperties(out);
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessageSubmissionChunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessageSubmissionChunk.java
index 902549c1f0..397717c7fa 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessageSubmissionChunk.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessageSubmissionChunk.java
@@ -24,6 +24,7 @@ import java.util.Calendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.apache.poi.hsmf.datatypes.Types.MAPIType;
import org.apache.poi.util.IOUtils;
/**
@@ -44,7 +45,7 @@ public class MessageSubmissionChunk extends Chunk {
/**
* Creates a Byte Chunk.
*/
- public MessageSubmissionChunk(String namePrefix, int chunkId, int type) {
+ public MessageSubmissionChunk(String namePrefix, int chunkId, MAPIType type) {
super(namePrefix, chunkId, type);
}
@@ -52,7 +53,7 @@ public class MessageSubmissionChunk extends Chunk {
* Create a Byte Chunk, with the specified
* type.
*/
- public MessageSubmissionChunk(int chunkId, int type) {
+ public MessageSubmissionChunk(int chunkId, MAPIType type) {
super(chunkId, type);
}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/NameIdChunks.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/NameIdChunks.java
index cbcce93d12..bb78ea308e 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/NameIdChunks.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/NameIdChunks.java
@@ -26,7 +26,7 @@ import java.util.List;
* NameID part of an outlook file
*/
public final class NameIdChunks implements ChunkGroup {
- public static final String PREFIX = "__nameid_version1.0";
+ public static final String NAME = "__nameid_version1.0";
/** Holds all the chunks that were found. */
private List<Chunk> allChunks = new ArrayList<Chunk>();
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertiesChunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertiesChunk.java
new file mode 100644
index 0000000000..b83ae7eb46
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertiesChunk.java
@@ -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.hsmf.datatypes;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A Chunk which holds fixed-length properties, and pointer
+ * to the variable length ones (which get their own chunk).
+ * There are two kinds of PropertiesChunks, which differ only in
+ * their headers.
+ */
+public abstract class PropertiesChunk extends Chunk {
+ public static final String NAME = "__properties_version1.0";
+
+ /**
+ * Holds properties, indexed by type. Properties can be multi-valued
+ */
+ private Map<MAPIProperty, List<PropertyValue>> properties =
+ new HashMap<MAPIProperty, List<PropertyValue>>();
+
+ /**
+ * Creates a Properties Chunk.
+ */
+ protected PropertiesChunk() {
+ super(NAME, -1, Types.UNKNOWN);
+ }
+
+ @Override
+ public String getEntryName() {
+ return NAME;
+ }
+
+ /**
+ * Returns all the properties in the chunk
+ */
+ public Map<MAPIProperty, List<PropertyValue>> getProperties() {
+ return properties;
+ }
+
+ /**
+ * Returns all values for the given property, of null if none exist
+ */
+ public List<PropertyValue> getValues(MAPIProperty property) {
+ return properties.get(property);
+ }
+
+ /**
+ * Returns the (first/only) value for the given property, or
+ * null if none exist
+ */
+ public PropertyValue getValue(MAPIProperty property) {
+ List<PropertyValue> values = properties.get(property);
+ if (values != null && values.size() > 0) {
+ return values.get(0);
+ }
+ return null;
+ }
+
+ protected void readProperties(InputStream value) throws IOException {
+ // TODO
+ }
+
+ protected void writeProperties(OutputStream out) throws IOException {
+ // TODO
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertyValue.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertyValue.java
new file mode 100644
index 0000000000..1468c094d9
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertyValue.java
@@ -0,0 +1,75 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF 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.datatypes;
+
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * An instance of a {@link MAPIProperty} inside a {@link PropertiesChunk}.
+ * Where the {@link Types} type is a fixed length one, this will contain the
+ * actual value.
+ * Where the {@link Types} type is a variable length one, this will contain
+ * the length of the property, and the value will be in the associated {@link Chunk}.
+ */
+public class PropertyValue {
+ private MAPIProperty property;
+ private long flags;
+ protected byte[] data;
+
+ public PropertyValue(MAPIProperty property, long flags, byte[] data) {
+ this.property = property;
+ this.flags = flags;
+ this.data = data;
+ }
+
+ public MAPIProperty getProperty() {
+ return property;
+ }
+
+ /**
+ * Get the raw value flags.
+ * TODO Also provide getters for the flag meanings
+ */
+ public long getFlags() {
+ return flags;
+ }
+
+ public Object getValue() {
+ return data;
+ }
+ public void setRawValue(byte[] value) {
+ this.data = value;
+ }
+
+ // TODO classes for the other important value types
+ public static class LongLongPropertyValue extends PropertyValue {
+ public LongLongPropertyValue(MAPIProperty property, long flags, byte[] data) {
+ super(property, flags, data);
+ }
+
+ public Long getValue() {
+ return LittleEndian.getLong(data);
+ }
+ public void setValue(long value) {
+ if (data.length != 8) {
+ data = new byte[8];
+ }
+ LittleEndian.putLong(data, 0, value);
+ }
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java
new file mode 100644
index 0000000000..166d38ba9c
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java
@@ -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.hsmf.datatypes;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * A {@link PropertiesChunk} for a Storage Properties, such as
+ * Attachments and Recipients.
+ * This only has a 8 byte header
+ */
+public class StoragePropertiesChunk extends PropertiesChunk {
+ public StoragePropertiesChunk() {
+ super();
+ }
+
+ @Override
+ public void readValue(InputStream stream) throws IOException {
+ // 8 bytes of reserved zeros
+ LittleEndian.readLong(stream);
+
+ // Now properties
+ readProperties(stream);
+ }
+
+ @Override
+ public void writeValue(OutputStream out) throws IOException {
+ // 8 bytes of reserved zeros
+ out.write(new byte[8]);
+
+ // Now properties
+ writeProperties(out);
+ }
+} \ No newline at end of file
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StringChunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StringChunk.java
index 133389bbcc..2051f44c28 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StringChunk.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StringChunk.java
@@ -22,7 +22,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
-import org.apache.poi.hsmf.datatypes.Types;
+import org.apache.poi.hsmf.datatypes.Types.MAPIType;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.StringUtil;
@@ -38,7 +38,7 @@ public class StringChunk extends Chunk {
/**
* Creates a String Chunk.
*/
- public StringChunk(String namePrefix, int chunkId, int type) {
+ public StringChunk(String namePrefix, int chunkId, MAPIType type) {
super(namePrefix, chunkId, type);
}
@@ -46,7 +46,7 @@ public class StringChunk extends Chunk {
* Create a String Chunk, with the specified
* type.
*/
- public StringChunk(int chunkId, int type) {
+ public StringChunk(int chunkId, MAPIType type) {
super(chunkId, type);
}
@@ -81,14 +81,11 @@ public class StringChunk extends Chunk {
}
private void parseString() {
String tmpValue;
- switch(type) {
- case Types.ASCII_STRING:
+ if (type == Types.ASCII_STRING) {
tmpValue = parseAs7BitData(rawValue, encoding7Bit);
- break;
- case Types.UNICODE_STRING:
+ } else if (type == Types.UNICODE_STRING) {
tmpValue = StringUtil.getFromUnicodeLE(rawValue);
- break;
- default:
+ } else {
throw new IllegalArgumentException("Invalid type " + type + " for String Chunk");
}
@@ -100,19 +97,16 @@ public class StringChunk extends Chunk {
out.write(rawValue);
}
private void storeString() {
- switch(type) {
- case Types.ASCII_STRING:
+ if (type == Types.ASCII_STRING) {
try {
rawValue = value.getBytes(encoding7Bit);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Encoding not found - " + encoding7Bit, e);
}
- break;
- case Types.UNICODE_STRING:
+ } else if (type == Types.UNICODE_STRING) {
rawValue = new byte[value.length()*2];
StringUtil.putUnicodeLE(value, rawValue, 0);
- break;
- default:
+ } else {
throw new IllegalArgumentException("Invalid type " + type + " for String Chunk");
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java
index bd76e14f9c..a4732f081f 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java
@@ -17,56 +17,121 @@
package org.apache.poi.hsmf.datatypes;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* The types list and details are available from
* http://msdn.microsoft.com/en-us/library/microsoft.exchange.data.contenttypes.tnef.tnefpropertytype%28v=EXCHG.140%29.aspx
*/
public final class Types {
+ private static Map<Integer, MAPIType> builtInTypes = new HashMap<Integer, MAPIType>();
+ private static Map<Integer, MAPIType> customTypes = new HashMap<Integer, Types.MAPIType>();
+
/** Unspecified */
- public static final int UNSPECIFIED = 0x0000;
+ public static final MAPIType UNSPECIFIED = new MAPIType(0x0000, "Unspecified", -1);
+ /** Unknown */
+ public static final MAPIType UNKNOWN = new MAPIType(-1, "Unknown", -1);
/** Null - NULL property value */
- public static final int NULL = 0x0001;
+ public static final MAPIType NULL = new MAPIType(0x0001, "Null", 0);
/** I2 - signed 16-bit value */
- public static final int SHORT = 0x0002;
+ public static final MAPIType SHORT = new MAPIType(0x0002, "Short", 2);
/** Long - signed 32-bit value */
- public static final int LONG = 0x0003;
+ public static final MAPIType LONG = new MAPIType(0x0003, "Long", 4);
/** R4 - 4-byte floating point value */
- public static final int FLOAT = 0x0004;
+ public static final MAPIType FLOAT = new MAPIType(0x0004, "Float", 4);
/** Double - floating point double */
- public static final int DOUBLE = 0x0005;
+ public static final MAPIType DOUBLE = new MAPIType(0x0005, "Double", 8);
/** Currency - signed 64-bit integer that represents a base ten decimal with four digits to the right of the decimal point */
- public static final int CURRENCY = 0x0006;
+ public static final MAPIType CURRENCY = new MAPIType(0x0006, "Currency", 8);
/** AppTime - application time value */
- public static final int APP_TIME = 0x0007;
+ public static final MAPIType APP_TIME = new MAPIType(0x0007, "Application Time", 8);
/** Error - 32-bit error value */
- public static final int ERROR = 0x000A;
+ public static final MAPIType ERROR = new MAPIType(0x000A, "Error", 4);
/** Boolean - 16-bit Boolean value. '0' is false. Non-zero is true */
- public static final int BOOLEAN = 0x000B;
+ public static final MAPIType BOOLEAN = new MAPIType(0x000B, "Boolean", 2);
/** Object/Directory - embedded object in a property */
- public static final int DIRECTORY = 0x000D;
+ public static final MAPIType DIRECTORY = new MAPIType(0x000D, "Directory", -1);
/** I8 - 8-byte signed integer */
- public static final int LONG_LONG = 0x0014;
+ public static final MAPIType LONG_LONG = new MAPIType(0x0014, "Long Long", 8);
/** SysTime - FILETIME 64-bit integer specifying the number of 100ns periods since Jan 1, 1601 */
- public static final int TIME = 0x0040;
+ public static final MAPIType TIME = new MAPIType(0x0040, "Time", 8);
/** ClassId - OLE GUID */
- public static final int CLS_ID = 0x0048;
+ public static final MAPIType CLS_ID = new MAPIType(0x0048, "CLS ID GUID", 16);
/** Binary - counted byte array */
- public static final int BINARY = 0x0102;
+ public static final MAPIType BINARY = new MAPIType(0x0102, "Binary", -1);
/**
* An 8-bit string, probably in CP1252, but don't quote us...
* Normally used for everything before Outlook 3.0, and some
* fields in Outlook 3.0.
*/
- public static final int ASCII_STRING = 0x001E;
+ public static final MAPIType ASCII_STRING = new MAPIType(0x001E, "ASCII String", -1);
/** A string, from Outlook 3.0 onwards. Normally unicode */
- public static final int UNICODE_STRING = 0x001F;
+ public static final MAPIType UNICODE_STRING = new MAPIType(0x001F, "Unicode String", -1);
/** MultiValued - Value part contains multiple values */
public static final int MULTIVALUED_FLAG = 0x1000;
+ public static final class MAPIType {
+ private final int id;
+ private final String name;
+ private final int length;
+
+ /**
+ * Creates a standard, built-in type
+ */
+ private MAPIType(int id, String name, int length) {
+ this.id = id;
+ this.name = name;
+ this.length = length;
+ builtInTypes.put(id, this);
+ }
+ /**
+ * Creates a custom type
+ */
+ private MAPIType(int id, int length) {
+ this.id = id;
+ this.name = asCustomName(id);
+ this.length = length;
+ customTypes.put(id, this);
+ }
+
+ /**
+ * Returns the length, in bytes, of values of this type, or
+ * -1 if it is a variable length type.
+ */
+ public int getLength() {
+ return length;
+ }
+ /**
+ * Is this type a fixed-length type, or a variable-length one?
+ */
+ public boolean isFixedLength() {
+ return (length != -1);
+ }
+
+ public int getId() {
+ return id;
+ }
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Return the 4 character hex encoded version,
+ * as used in file endings
+ */
+ public String asFileEnding() {
+ return Types.asFileEnding(id);
+ }
+ }
+
+ public static MAPIType getById(int typeId) {
+ return builtInTypes.get(typeId);
+ }
public static String asFileEnding(int type) {
String str = Integer.toHexString(type).toUpperCase();
@@ -75,45 +140,36 @@ public final class Types {
}
return str;
}
- public static String asName(int type) {
- switch(type) {
- case BINARY:
- return "Binary";
- case ASCII_STRING:
- return "ASCII String";
- case UNICODE_STRING:
- return "Unicode String";
- case UNSPECIFIED:
- return "Unspecified";
- case NULL:
- return "Null";
- case SHORT:
- return "Short";
- case LONG:
- return "Long";
- case LONG_LONG:
- return "Long Long";
- case FLOAT:
- return "Float";
- case DOUBLE:
- return "Double";
- case CURRENCY:
- return "Currency";
- case APP_TIME:
- return "Application Time";
- case ERROR:
- return "Error";
- case TIME:
- return "Time";
- case BOOLEAN:
- return "Boolean";
- case CLS_ID:
- return "CLS ID GUID";
- case DIRECTORY:
- return "Directory";
- case -1:
- return "Unknown";
+ public static String asName(int typeId) {
+ MAPIType type = builtInTypes.get(typeId);
+ if (type != null) {
+ return type.name;
+ }
+ return asCustomName(typeId);
+ }
+ private static String asCustomName(int typeId) {
+ return "0x" + Integer.toHexString(typeId);
+ }
+
+ public static MAPIType createCustom(int typeId) {
+ // Check they're not being silly, and asking for a built-in one...
+ if (getById(typeId) != null) {
+ return getById(typeId);
+ }
+
+ // Try to get an existing definition of this
+ MAPIType type = customTypes.get(typeId);
+
+ // If none, do a thread-safe creation
+ if (type == null) {
+ synchronized (customTypes) {
+ type = customTypes.get(typeId);
+ if (type == null) {
+ type = new MAPIType(typeId, -1);
+ }
+ }
}
- return "0x" + Integer.toHexString(type);
+
+ return type;
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/dev/HSMFDump.java b/src/scratchpad/src/org/apache/poi/hsmf/dev/HSMFDump.java
index 43edf92121..436298de45 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/dev/HSMFDump.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/dev/HSMFDump.java
@@ -23,7 +23,8 @@ import java.io.IOException;
import org.apache.poi.hsmf.datatypes.Chunk;
import org.apache.poi.hsmf.datatypes.ChunkGroup;
import org.apache.poi.hsmf.datatypes.MAPIProperty;
-import org.apache.poi.hsmf.datatypes.Types;
+import org.apache.poi.hsmf.datatypes.PropertiesChunk;
+import org.apache.poi.hsmf.datatypes.PropertyValue;
import org.apache.poi.hsmf.parsers.POIFSChunkParser;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
@@ -43,18 +44,35 @@ public class HSMFDump {
for(Chunk chunk : chunks.getChunks()) {
MAPIProperty attr = MAPIProperty.get(chunk.getChunkId());
- String idName = attr.id + " - " + attr.name;
- if(attr == MAPIProperty.UNKNOWN) {
- idName = chunk.getChunkId() + " - (unknown)";
+ if (chunk instanceof PropertiesChunk) {
+ PropertiesChunk props = (PropertiesChunk)chunk;
+ System.out.println(
+ " Properties - " + props.getProperties().size() + ":"
+ );
+
+ for (MAPIProperty prop : props.getProperties().keySet()) {
+ System.out.println(
+ " * " + prop
+ );
+ for (PropertyValue v : props.getValues(prop)) {
+ System.out.println(
+ " = " + v.toString()
+ );
+ }
+ }
+ } else {
+ String idName = attr.id + " - " + attr.name;
+ if(attr == MAPIProperty.UNKNOWN) {
+ idName = chunk.getChunkId() + " - (unknown)";
+ }
+
+ System.out.println(
+ " " + idName + " - " + chunk.getType().getName()
+ );
+ System.out.println(
+ " " + chunk.toString()
+ );
}
-
- System.out.println(
- " " + idName + " - " +
- Types.asName(chunk.getType())
- );
- System.out.println(
- " " + chunk.toString()
- );
}
System.out.println();
}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/dev/TypesLister.java b/src/scratchpad/src/org/apache/poi/hsmf/dev/TypesLister.java
index fda6513d61..39b0ebce5a 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/dev/TypesLister.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/dev/TypesLister.java
@@ -23,7 +23,6 @@ import java.util.Collections;
import java.util.Comparator;
import org.apache.poi.hsmf.datatypes.MAPIProperty;
-import org.apache.poi.hsmf.datatypes.Types;
/**
* Lists the different MAPI types
@@ -56,9 +55,15 @@ public class TypesLister {
String id = Integer.toHexString(attr.id);
while(id.length() < 4) { id = "0"+id; }
+ int typeId = attr.usualType.getId();
+ String typeIdStr = Integer.toString(typeId);
+ if (typeId > 0) {
+ typeIdStr = typeIdStr + " / 0x" + Integer.toHexString(typeId);
+ }
+
out.println("0x" + id + " - " + attr.name);
- out.println(" " + attr.id + " - " + Types.asName(attr.usualType) +
- " (" + attr.usualType + ") - " + attr.mapiProperty);
+ out.println(" " + attr.id + " - " + attr.usualType.getName() +
+ " (" + typeIdStr + ") - " + attr.mapiProperty);
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java b/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java
index 6f542c5ed7..6800b0ac77 100644
--- a/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java
+++ b/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java
@@ -27,11 +27,15 @@ import org.apache.poi.hsmf.datatypes.ChunkGroup;
import org.apache.poi.hsmf.datatypes.Chunks;
import org.apache.poi.hsmf.datatypes.DirectoryChunk;
import org.apache.poi.hsmf.datatypes.MAPIProperty;
+import org.apache.poi.hsmf.datatypes.MessagePropertiesChunk;
import org.apache.poi.hsmf.datatypes.MessageSubmissionChunk;
import org.apache.poi.hsmf.datatypes.NameIdChunks;
+import org.apache.poi.hsmf.datatypes.PropertiesChunk;
import org.apache.poi.hsmf.datatypes.RecipientChunks;
+import org.apache.poi.hsmf.datatypes.StoragePropertiesChunk;
import org.apache.poi.hsmf.datatypes.StringChunk;
import org.apache.poi.hsmf.datatypes.Types;
+import org.apache.poi.hsmf.datatypes.Types.MAPIType;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.poifs.filesystem.DocumentNode;
@@ -65,7 +69,7 @@ public final class POIFSChunkParser {
if(dir.getName().startsWith(AttachmentChunks.PREFIX)) {
group = new AttachmentChunks(dir.getName());
}
- if(dir.getName().startsWith(NameIdChunks.PREFIX)) {
+ if(dir.getName().startsWith(NameIdChunks.NAME)) {
group = new NameIdChunks();
}
if(dir.getName().startsWith(RecipientChunks.PREFIX)) {
@@ -97,7 +101,7 @@ public final class POIFSChunkParser {
if(entry instanceof DocumentNode) {
process(entry, grouping);
} else if(entry instanceof DirectoryNode) {
- if(entry.getName().endsWith(Types.asFileEnding(Types.DIRECTORY))) {
+ if(entry.getName().endsWith(Types.DIRECTORY.asFileEnding())) {
process(entry, grouping);
}
}
@@ -109,81 +113,98 @@ public final class POIFSChunkParser {
*/
protected static void process(Entry entry, ChunkGroup grouping) {
String entryName = entry.getName();
+ Chunk chunk = null;
- if(entryName.length() < 9) {
- // Name in the wrong format
- return;
- }
- if(entryName.indexOf('_') == -1) {
- // Name in the wrong format
- return;
- }
-
- // Split it into its parts
- int splitAt = entryName.lastIndexOf('_');
- String namePrefix = entryName.substring(0, splitAt+1);
- String ids = entryName.substring(splitAt+1);
-
- // Make sure we got what we expected, should be of
- // the form __<name>_<id><type>
- if(namePrefix.equals("Olk10SideProps") ||
- namePrefix.equals("Olk10SideProps_")) {
- // This is some odd Outlook 2002 thing, skip
- return;
- } else if(splitAt <= entryName.length()-8) {
- // In the right form for a normal chunk
- // We'll process this further in a little bit
+ // Is it a properties chunk? (They have special names)
+ if (entryName.equals(PropertiesChunk.NAME)) {
+ if (grouping instanceof Chunks) {
+ // These should be the properties for the message itself
+ chunk = new MessagePropertiesChunk();
+ } else {
+ // Will be properties on an attachment or recipient
+ chunk = new StoragePropertiesChunk();
+ }
} else {
- // Underscores not the right place, something's wrong
- throw new IllegalArgumentException("Invalid chunk name " + entryName);
- }
-
- // Now try to turn it into id + type
- try {
- int chunkId = Integer.parseInt(ids.substring(0, 4), 16);
- int type = Integer.parseInt(ids.substring(4, 8), 16);
+ // Check it's a regular chunk
+ if(entryName.length() < 9) {
+ // Name in the wrong format
+ return;
+ }
+ if(entryName.indexOf('_') == -1) {
+ // Name in the wrong format
+ return;
+ }
- Chunk chunk = null;
+ // Split it into its parts
+ int splitAt = entryName.lastIndexOf('_');
+ String namePrefix = entryName.substring(0, splitAt+1);
+ String ids = entryName.substring(splitAt+1);
- // Special cases based on the ID
- if(chunkId == MAPIProperty.MESSAGE_SUBMISSION_ID.id) {
- chunk = new MessageSubmissionChunk(namePrefix, chunkId, type);
- }
- else {
- // Nothing special about this ID
- // So, do the usual thing which is by type
- switch(type) {
- case Types.BINARY:
- chunk = new ByteChunk(namePrefix, chunkId, type);
- break;
- case Types.DIRECTORY:
- if(entry instanceof DirectoryNode) {
- chunk = new DirectoryChunk((DirectoryNode)entry, namePrefix, chunkId, type);
+ // Make sure we got what we expected, should be of
+ // the form __<name>_<id><type>
+ if(namePrefix.equals("Olk10SideProps") ||
+ namePrefix.equals("Olk10SideProps_")) {
+ // This is some odd Outlook 2002 thing, skip
+ return;
+ } else if(splitAt <= entryName.length()-8) {
+ // In the right form for a normal chunk
+ // We'll process this further in a little bit
+ } else {
+ // Underscores not the right place, something's wrong
+ throw new IllegalArgumentException("Invalid chunk name " + entryName);
+ }
+
+ // Now try to turn it into id + type
+ try {
+ int chunkId = Integer.parseInt(ids.substring(0, 4), 16);
+ int typeId = Integer.parseInt(ids.substring(4, 8), 16);
+
+ MAPIType type = Types.getById(typeId);
+ if (type == null) {
+ type = Types.createCustom(typeId);
+ }
+
+ // Special cases based on the ID
+ if(chunkId == MAPIProperty.MESSAGE_SUBMISSION_ID.id) {
+ chunk = new MessageSubmissionChunk(namePrefix, chunkId, type);
+ }
+ else {
+ // Nothing special about this ID
+ // So, do the usual thing which is by type
+ if (type == Types.BINARY) {
+ chunk = new ByteChunk(namePrefix, chunkId, type);
+ }
+ else if (type == Types.DIRECTORY) {
+ if(entry instanceof DirectoryNode) {
+ chunk = new DirectoryChunk((DirectoryNode)entry, namePrefix, chunkId, type);
+ }
+ }
+ else if (type == Types.ASCII_STRING ||
+ type == Types.UNICODE_STRING) {
+ chunk = new StringChunk(namePrefix, chunkId, type);
+ }
+ else {
+ // Type of an unsupported type! Skipping...
}
- break;
- case Types.ASCII_STRING:
- case Types.UNICODE_STRING:
- chunk = new StringChunk(namePrefix, chunkId, type);
- break;
}
+ } catch(NumberFormatException e) {
+ // Name in the wrong format
+ return;
}
+ }
- if(chunk != null) {
- if(entry instanceof DocumentNode) {
- try {
- DocumentInputStream inp = new DocumentInputStream((DocumentNode)entry);
- chunk.readValue(inp);
- grouping.record(chunk);
- } catch(IOException e) {
- System.err.println("Error reading from part " + entry.getName() + " - " + e.toString());
- }
- } else {
+ if(chunk != null) {
+ if(entry instanceof DocumentNode) {
+ try {
+ DocumentInputStream inp = new DocumentInputStream((DocumentNode)entry);
+ chunk.readValue(inp);
grouping.record(chunk);
+ } catch(IOException e) {
+ System.err.println("Error reading from part " + entry.getName() + " - " + e.toString());
}
- }
- } catch(NumberFormatException e) {
- // Name in the wrong format
- return;
+ } else {
+ grouping.record(chunk);
+ }
}
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
index ff7af7cf21..670755dbf5 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
@@ -34,6 +34,7 @@ import org.apache.poi.ddf.EscherProperty;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.hwpf.model.PICF;
import org.apache.poi.hwpf.model.PICFAndOfficeArtData;
+import org.apache.poi.util.PngUtils;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.StringUtil;
@@ -191,6 +192,15 @@ public final class Picture
{
// Raw data is not compressed.
content = rawContent;
+
+ //PNG created on MAC may have a 16-byte prefix which prevents successful reading.
+ //Just cut it off!.
+ if (PngUtils.matchesPngHeader(content, 16))
+ {
+ byte[] png = new byte[content.length-16];
+ System.arraycopy(content, 16, png, 0, png.length);
+ content = png;
+ }
}
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hdgf/TestHDGFCore.java b/src/scratchpad/testcases/org/apache/poi/hdgf/TestHDGFCore.java
index 25a513872b..c617341698 100644
--- a/src/scratchpad/testcases/org/apache/poi/hdgf/TestHDGFCore.java
+++ b/src/scratchpad/testcases/org/apache/poi/hdgf/TestHDGFCore.java
@@ -17,6 +17,7 @@
package org.apache.poi.hdgf;
+import org.apache.poi.hdgf.extractor.VisioTextExtractor;
import org.apache.poi.hdgf.streams.PointerContainingStream;
import org.apache.poi.hdgf.streams.TrailerStream;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
@@ -88,4 +89,28 @@ public final class TestHDGFCore extends TestCase {
HDGFDiagram hdgf = new HDGFDiagram(fs);
assertNotNull(hdgf);
}
+
+ public void testV6NonUtf16LE() throws Exception {
+ fs = new POIFSFileSystem(_dgTests.openResourceAsStream("v6-non-utf16le.vsd"));
+
+ HDGFDiagram hdgf = new HDGFDiagram(fs);
+ assertNotNull(hdgf);
+
+ VisioTextExtractor textExtractor = new VisioTextExtractor(hdgf);
+ String text = textExtractor.getText().replace("\u0000", "").trim();
+
+ assertEquals("Table\n\n\nPropertySheet\n\n\n\nPropertySheetField", text);
+ }
+
+ public void testUtf16LE() throws Exception {
+ fs = new POIFSFileSystem(_dgTests.openResourceAsStream("Test_Visio-Some_Random_Text.vsd"));
+
+ HDGFDiagram hdgf = new HDGFDiagram(fs);
+ assertNotNull(hdgf);
+
+ VisioTextExtractor textExtractor = new VisioTextExtractor(hdgf);
+ String text = textExtractor.getText().trim();
+
+ assertEquals("text\nView\nTest View\nI am a test view\nSome random text, on a page", text);
+ }
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java
index 871893210a..3444ae5fe8 100644
--- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java
@@ -20,10 +20,13 @@ package org.apache.poi.hslf.model;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import javax.imageio.ImageIO;
import junit.framework.TestCase;
import org.apache.poi.ddf.EscherBSERecord;
+import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.PictureData;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.POIDataSamples;
@@ -88,4 +91,41 @@ public final class TestPicture extends TestCase {
Graphics2D graphics = img.createGraphics();
pict.draw(graphics);
}
+
+ public void testMacImages() throws Exception {
+ HSLFSlideShow hss = new HSLFSlideShow(_slTests.openResourceAsStream("53446.ppt"));
+
+ PictureData[] pictures = hss.getPictures();
+ assertEquals(15, pictures.length);
+
+ int[][] expectedSizes = {
+ null, // WMF
+ { 427, 428 }, // PNG
+ { 371, 370 }, // PNG
+ { 288, 183 }, // PNG
+ { 285, 97 }, // PNG
+ { 288, 168 }, // PNG
+ null, // WMF
+ null, // WMF
+ { 199, 259 }, // PNG
+ { 432, 244 }, // PNG
+ { 261, 258 }, // PNG
+ null, // WMF
+ null, // WMF
+ null, // WMF
+ null // EMF
+ };
+
+ for (int i = 0; i < pictures.length; i++) {
+ BufferedImage image = ImageIO.read(new ByteArrayInputStream(pictures[i].getData()));
+
+ if (pictures[i].getType() != Picture.WMF && pictures[i].getType() != Picture.EMF) {
+ assertNotNull(image);
+
+ int[] dimensions = expectedSizes[i];
+ assertEquals(dimensions[0], image.getWidth());
+ assertEquals(dimensions[1], image.getHeight());
+ }
+ }
+ }
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestChunkData.java b/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestChunkData.java
index 2303ccc0d0..ea6f8be81b 100644
--- a/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestChunkData.java
+++ b/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestChunkData.java
@@ -30,24 +30,29 @@ public final class TestChunkData extends TestCase {
public void testChunkCreate() {
Chunk chunk;
- chunk = new StringChunk(0x0200, 0x001E);
+ chunk = new StringChunk(0x0200, Types.createCustom(0x001E));
assertEquals("__substg1.0_0200001E", chunk.getEntryName());
assertEquals(0x0200, chunk.getChunkId());
- assertEquals(0x001E, chunk.getType());
+ assertEquals(0x001E, chunk.getType().getId());
- chunk = new StringChunk("__substg1.0_", 0x0200, 0x001E);
+ chunk = new StringChunk("__substg1.0_", 0x0200, Types.createCustom(0x001E));
assertEquals("__substg1.0_0200001E", chunk.getEntryName());
assertEquals(0x0200, chunk.getChunkId());
- assertEquals(0x001E, chunk.getType());
+ assertEquals(0x001E, chunk.getType().getId());
+
+ chunk = new StringChunk("__substg1.0_", 0x0200, Types.getById(0x001E));
+ assertEquals("__substg1.0_0200001E", chunk.getEntryName());
+ assertEquals(0x0200, chunk.getChunkId());
+ assertEquals(0x001E, chunk.getType().getId());
/* test the lower and upper limits of the chunk ids */
- chunk = new StringChunk(0x0000, 0x001E);
+ chunk = new StringChunk(0x0000, Types.createCustom(0x001E));
assertEquals("__substg1.0_0000001E", chunk.getEntryName());
- chunk = new StringChunk(0xFFFF, 0x001E);
+ chunk = new StringChunk(0xFFFF, Types.createCustom(0x001E));
assertEquals("__substg1.0_FFFF001E", chunk.getEntryName());
- chunk = new StringChunk(0xFFFF, 0x001F);
+ chunk = new StringChunk(0xFFFF, Types.createCustom(0x001F));
assertEquals("__substg1.0_FFFF001F", chunk.getEntryName());
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestMAPIProperty.java b/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestMAPIProperty.java
index 56c8859cca..55369e8dcd 100644
--- a/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestMAPIProperty.java
+++ b/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestMAPIProperty.java
@@ -37,16 +37,16 @@ public final class TestMAPIProperty extends TestCase {
assertEquals(true, all.contains(MAPIProperty.DISPLAY_CC));
// Won't contain custom
- assertEquals(false, all.contains(MAPIProperty.createCustom(1, 1, "")));
+ assertEquals(false, all.contains(MAPIProperty.createCustom(1, Types.UNSPECIFIED, "")));
// Won't contain unknown
assertEquals(false, all.contains(MAPIProperty.UNKNOWN));
}
public void testCustom() throws Exception {
- MAPIProperty c1 = MAPIProperty.createCustom(1, 1, "");
- MAPIProperty c2a = MAPIProperty.createCustom(2, 1, "2");
- MAPIProperty c2b = MAPIProperty.createCustom(2, 1, "2");
+ MAPIProperty c1 = MAPIProperty.createCustom(1, Types.UNSPECIFIED, "");
+ MAPIProperty c2a = MAPIProperty.createCustom(2, Types.UNSPECIFIED, "2");
+ MAPIProperty c2b = MAPIProperty.createCustom(2, Types.UNSPECIFIED, "2");
// New object each time
assertNotSame(c1, c2a);
diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestTypes.java b/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestTypes.java
index 152ca4dee0..8a58639d79 100644
--- a/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestTypes.java
+++ b/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestTypes.java
@@ -28,13 +28,21 @@ import junit.framework.TestCase;
*/
public final class TestTypes extends TestCase {
public void testTypeIds() {
- assertEquals(0x1e, Types.ASCII_STRING);
- assertEquals(0x1f, Types.UNICODE_STRING);
+ assertEquals(0x1e, Types.ASCII_STRING.getId());
+ assertEquals(0x1f, Types.UNICODE_STRING.getId());
- assertEquals(0x0102, Types.BINARY);
- assertEquals(0x000B, Types.BOOLEAN);
- assertEquals(0x0003, Types.LONG);
- assertEquals(0x0040, Types.TIME);
+ assertEquals(0x0102, Types.BINARY.getId());
+ assertEquals(0x000B, Types.BOOLEAN.getId());
+ assertEquals(0x0003, Types.LONG.getId());
+ assertEquals(0x0040, Types.TIME.getId());
+
+ assertEquals(Types.ASCII_STRING, Types.getById(0x1e));
+ assertEquals(Types.UNICODE_STRING, Types.getById(0x1f));
+
+ assertEquals(Types.BINARY, Types.getById(0x0102));
+ assertEquals(Types.BOOLEAN, Types.getById(0x000B));
+ assertEquals(Types.LONG, Types.getById(0x0003));
+ assertEquals(Types.TIME, Types.getById(0x0040));
}
public void testTypeFormatting() {
@@ -45,7 +53,7 @@ public final class TestTypes extends TestCase {
}
public void testName() {
- assertEquals("ASCII String", Types.asName(Types.ASCII_STRING));
- assertEquals("Boolean", Types.asName(Types.BOOLEAN));
+ assertEquals("ASCII String", Types.ASCII_STRING.getName());
+ assertEquals("Boolean", Types.BOOLEAN.getName());
}
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java b/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java
index f650f0d890..ae7cc3df24 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java
@@ -17,10 +17,14 @@
package org.apache.poi.hwpf;
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
import java.util.List;
import junit.framework.TestCase;
+import org.apache.poi.POIDataSamples;
import org.apache.poi.hwpf.model.PicturesTable;
import org.apache.poi.hwpf.usermodel.Picture;
import org.apache.poi.POIDataSamples;
@@ -128,6 +132,30 @@ public final class TestHWPFPictures extends TestCase {
assertBytesSame(picBytes, pic.getContent());
}
+ public void testMacImages() throws Exception {
+ HWPFDocument docC = HWPFTestDataSamples.openSampleFile("53446.doc");
+ PicturesTable picturesTable = docC.getPicturesTable();
+ List<Picture> pictures = picturesTable.getAllPictures();
+
+ assertEquals(4, pictures.size());
+
+ int[][] expectedSizes = {
+ { 185, 42 }, // PNG
+ { 260, 114 }, // PNG
+ { 185, 42 }, // PNG
+ { 260, 114 }, // PNG
+ };
+
+ for (int i = 0; i < pictures.size(); i++) {
+ BufferedImage image = ImageIO.read(new ByteArrayInputStream(pictures.get(i).getContent()));
+ assertNotNull(image);
+
+ int[] dimensions = expectedSizes[i];
+ assertEquals(dimensions[0], image.getWidth());
+ assertEquals(dimensions[1], image.getHeight());
+ }
+ }
+
/**
* Pending the missing files being uploaded to
* bug #44937
diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheet.java b/src/testcases/org/apache/poi/hssf/model/TestSheet.java
index d3248edffe..d898a999ad 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestSheet.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestSheet.java
@@ -35,6 +35,8 @@ import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.HexRead;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -773,4 +775,43 @@ public final class TestSheet extends TestCase {
assertEquals(WindowTwoRecord.sid, ((Record)sheetRecords.get(2)).getSid());
assertEquals(EOFRecord.sid, ((Record)sheetRecords.get(3)).getSid());
}
+
+ public void testSheetDimensions() throws IOException{
+ InternalSheet sheet = InternalSheet.createSheet();
+ DimensionsRecord dimensions = (DimensionsRecord)sheet.findFirstRecordBySid(DimensionsRecord.sid);
+ assertEquals(0, dimensions.getFirstCol());
+ assertEquals(0, dimensions.getFirstRow());
+ assertEquals(1, dimensions.getLastCol()); // plus pne
+ assertEquals(1, dimensions.getLastRow()); // plus pne
+
+ RowRecord rr = new RowRecord(0);
+ sheet.addRow(rr);
+
+ assertEquals(0, dimensions.getFirstCol());
+ assertEquals(0, dimensions.getFirstRow());
+ assertEquals(1, dimensions.getLastCol());
+ assertEquals(1, dimensions.getLastRow());
+
+ CellValueRecordInterface cvr;
+
+ cvr = new BlankRecord();
+ cvr.setColumn((short)0);
+ cvr.setRow(0);
+ sheet.addValueRecord(0, cvr);
+
+ assertEquals(0, dimensions.getFirstCol());
+ assertEquals(0, dimensions.getFirstRow());
+ assertEquals(1, dimensions.getLastCol());
+ assertEquals(1, dimensions.getLastRow());
+
+ cvr = new BlankRecord();
+ cvr.setColumn((short)1);
+ cvr.setRow(0);
+ sheet.addValueRecord(0, cvr);
+
+ assertEquals(0, dimensions.getFirstCol());
+ assertEquals(0, dimensions.getFirstRow());
+ assertEquals(2, dimensions.getLastCol()); //YK: failed until Bugzilla 53414 was fixed
+ assertEquals(1, dimensions.getLastRow());
+ }
}
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPictureData.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPictureData.java
index 99f4ad8068..b9ff69543a 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPictureData.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPictureData.java
@@ -71,6 +71,29 @@ public final class TestHSSFPictureData extends TestCase{
}
}
}
+
+ public void testMacPicture() throws IOException {
+ HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("53446.xls");
+
+ @SuppressWarnings("unchecked")
+ List<HSSFPictureData> lst = (List<HSSFPictureData>)(List<?>)wb.getAllPictures();
+ assertEquals(1, lst.size());
+
+ HSSFPictureData pict = lst.get(0);
+ String ext = pict.suggestFileExtension();
+ if (!ext.equals("png")) {
+ fail("Expected a PNG.");
+ }
+
+ //try to read image data using javax.imageio.* (JDK 1.4+)
+ byte[] data = pict.getData();
+ BufferedImage png = ImageIO.read(new ByteArrayInputStream(data));
+ assertNotNull(png);
+ assertEquals(78, png.getWidth());
+ assertEquals(76, png.getHeight());
+ assertEquals(HSSFWorkbook.PICTURE_TYPE_PNG, pict.getFormat());
+ assertEquals("image/png", pict.getMimeType());
+ }
public void testNotNullPictures() throws IOException {
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java
index d05f048771..a640ce971d 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java
@@ -57,6 +57,22 @@ public final class TestHSSFSheet extends BaseTestSheet {
super(HSSFITestDataProvider.instance);
}
+
+ /**
+ * Test for Bugzilla #29747.
+ * Moved from TestHSSFWorkbook#testSetRepeatingRowsAndColumns().
+ */
+ public void testSetRepeatingRowsAndColumnsBug29747() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ wb.createSheet();
+ wb.createSheet();
+ HSSFSheet sheet2 = wb.createSheet();
+ sheet2.setRepeatingRows(CellRangeAddress.valueOf("1:2"));
+ NameRecord nameRecord = wb.getWorkbook().getNameRecord(0);
+ assertEquals(3, nameRecord.getSheetNumber());
+ }
+
+
public void testTestGetSetMargin() {
baseTestGetSetMargin(new double[]{0.75, 0.75, 1.0, 1.0, 0.3, 0.3});
}
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java
index 68462a2e2f..b1e36af747 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java
@@ -56,17 +56,6 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
return wb.getWorkbook();
}
- public void testSetRepeatingRowsAndColumns() {
- // Test bug 29747
- HSSFWorkbook b = new HSSFWorkbook( );
- b.createSheet();
- b.createSheet();
- b.createSheet();
- b.setRepeatingRowsAndColumns( 2, 0,1,-1,-1 );
- NameRecord nameRecord = b.getWorkbook().getNameRecord( 0 );
- assertEquals(3, nameRecord.getSheetNumber());
- }
-
public void testWindowOneDefaults() {
HSSFWorkbook b = new HSSFWorkbook( );
try {
@@ -501,7 +490,8 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
assertEquals("Sheet2!$A$1:$IV$1", HSSFFormulaParser.toFormulaString(wb, nr.getNameDefinition())); // 1:1
try {
- wb.setRepeatingRowsAndColumns(3, 4, 5, 8, 11);
+ wb.getSheetAt(3).setRepeatingRows(CellRangeAddress.valueOf("9:12"));
+ wb.getSheetAt(3).setRepeatingColumns(CellRangeAddress.valueOf("E:F"));
} catch (RuntimeException e) {
if (e.getMessage().equals("Builtin (7) already exists for sheet (4)")) {
// there was a problem in the code which locates the existing print titles name record
diff --git a/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java b/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java
index 8303e08600..712335f85c 100644
--- a/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java
+++ b/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java
@@ -42,6 +42,9 @@ import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.ErrorConstants;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
+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;
/**
@@ -235,4 +238,47 @@ public class TestWorkbookEvaluator extends TestCase {
assertEquals(Cell.CELL_TYPE_ERROR, cv.getCellType());
assertEquals(ErrorEval.CIRCULAR_REF_ERROR.getErrorCode(), cv.getErrorValue());
}
+
+
+ /**
+ * formulas with defined names.
+ */
+ public void testNamesInFormulas() {
+ Workbook wb = new HSSFWorkbook();
+ Sheet sheet = wb.createSheet("Sheet1");
+
+ Name name1 = wb.createName();
+ name1.setNameName("aConstant");
+ name1.setRefersToFormula("3.14");
+
+ Name name2 = wb.createName();
+ name2.setNameName("aFormula");
+ name2.setRefersToFormula("SUM(Sheet1!$A$1:$A$3)");
+
+ Name name3 = wb.createName();
+ name3.setNameName("aSet");
+ name3.setRefersToFormula("Sheet1!$A$2:$A$4");
+
+
+ Row row0 = sheet.createRow(0);
+ Row row1 = sheet.createRow(1);
+ Row row2 = sheet.createRow(2);
+ Row row3 = sheet.createRow(3);
+ row0.createCell(0).setCellValue(2);
+ row1.createCell(0).setCellValue(5);
+ row2.createCell(0).setCellValue(3);
+ row3.createCell(0).setCellValue(7);
+
+ row0.createCell(2).setCellFormula("aConstant");
+ row1.createCell(2).setCellFormula("aFormula");
+ row2.createCell(2).setCellFormula("SUM(aSet)");
+ row3.createCell(2).setCellFormula("aConstant+aFormula+SUM(aSet)");
+
+ FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
+ assertEquals(3.14, fe.evaluate(row0.getCell(2)).getNumberValue());
+ assertEquals(10.0, fe.evaluate(row1.getCell(2)).getNumberValue());
+ assertEquals(15.0, fe.evaluate(row2.getCell(2)).getNumberValue());
+ assertEquals(28.14, fe.evaluate(row3.getCell(2)).getNumberValue());
+ }
+
}
diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java
index 7a3c213bab..d879e1b6a1 100644
--- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java
+++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java
@@ -712,4 +712,78 @@ public abstract class BaseTestSheet extends TestCase {
assertNull(sheet.getPaneInformation());
}
+
+ public void testGetRepeatingRowsAndColumns() {
+ Workbook wb = _testDataProvider.openSampleWorkbook(
+ "RepeatingRowsCols."
+ + _testDataProvider.getStandardFileNameExtension());
+
+ checkRepeatingRowsAndColumns(wb.getSheetAt(0), null, null);
+ checkRepeatingRowsAndColumns(wb.getSheetAt(1), "1:1", null);
+ checkRepeatingRowsAndColumns(wb.getSheetAt(2), null, "A:A");
+ checkRepeatingRowsAndColumns(wb.getSheetAt(3), "2:3", "A:B");
+ }
+
+
+ public void testSetRepeatingRowsAndColumnsBug47294(){
+ Workbook wb = _testDataProvider.createWorkbook();
+ Sheet sheet1 = wb.createSheet();
+ sheet1.setRepeatingRows(CellRangeAddress.valueOf("1:4"));
+ assertEquals("1:4", sheet1.getRepeatingRows().formatAsString());
+
+ //must handle sheets with quotas, see Bugzilla #47294
+ Sheet sheet2 = wb.createSheet("My' Sheet");
+ sheet2.setRepeatingRows(CellRangeAddress.valueOf("1:4"));
+ assertEquals("1:4", sheet2.getRepeatingRows().formatAsString());
+ }
+
+ public void testSetRepeatingRowsAndColumns() {
+ Workbook wb = _testDataProvider.createWorkbook();
+ Sheet sheet1 = wb.createSheet("Sheet1");
+ Sheet sheet2 = wb.createSheet("Sheet2");
+ Sheet sheet3 = wb.createSheet("Sheet3");
+
+ checkRepeatingRowsAndColumns(sheet1, null, null);
+
+ sheet1.setRepeatingRows(CellRangeAddress.valueOf("4:5"));
+ sheet2.setRepeatingColumns(CellRangeAddress.valueOf("A:C"));
+ sheet3.setRepeatingRows(CellRangeAddress.valueOf("1:4"));
+ sheet3.setRepeatingColumns(CellRangeAddress.valueOf("A:A"));
+
+ checkRepeatingRowsAndColumns(sheet1, "4:5", null);
+ checkRepeatingRowsAndColumns(sheet2, null, "A:C");
+ checkRepeatingRowsAndColumns(sheet3, "1:4", "A:A");
+
+ // write out, read back, and test refrain...
+ wb = _testDataProvider.writeOutAndReadBack(wb);
+ sheet1 = wb.getSheetAt(0);
+ sheet2 = wb.getSheetAt(1);
+ sheet3 = wb.getSheetAt(2);
+
+ checkRepeatingRowsAndColumns(sheet1, "4:5", null);
+ checkRepeatingRowsAndColumns(sheet2, null, "A:C");
+ checkRepeatingRowsAndColumns(sheet3, "1:4", "A:A");
+
+ // check removing repeating rows and columns
+ sheet3.setRepeatingRows(null);
+ checkRepeatingRowsAndColumns(sheet3, null, "A:A");
+
+ sheet3.setRepeatingColumns(null);
+ checkRepeatingRowsAndColumns(sheet3, null, null);
+ }
+
+ private void checkRepeatingRowsAndColumns(
+ Sheet s, String expectedRows, String expectedCols) {
+ if (expectedRows == null) {
+ assertNull(s.getRepeatingRows());
+ } else {
+ assertEquals(expectedRows, s.getRepeatingRows().formatAsString());
+ }
+ if (expectedCols == null) {
+ assertNull(s.getRepeatingColumns());
+ } else {
+ assertEquals(expectedCols, s.getRepeatingColumns().formatAsString());
+ }
+ }
+
}
diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestWorkbook.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestWorkbook.java
index 347eded973..15181245bc 100644
--- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestWorkbook.java
+++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestWorkbook.java
@@ -359,14 +359,27 @@ public abstract class BaseTestWorkbook extends TestCase {
assertSame(row, cell.getRow());
}
+
+ /**
+ * Test is kept to ensure stub for deprecated business method passes test.
+ *
+ * @Deprecated remove this test when
+ * {@link Workbook#setRepeatingRowsAndColumns(int, int, int, int, int)}
+ * is removed
+ */
+ @Deprecated
public void testSetRepeatingRowsAnsColumns(){
Workbook wb = _testDataProvider.createWorkbook();
Sheet sheet1 = wb.createSheet();
wb.setRepeatingRowsAndColumns(wb.getSheetIndex(sheet1), 0, 0, 0, 3);
+ assertEquals("1:4", sheet1.getRepeatingRows().formatAsString());
+ assertEquals("A:A", sheet1.getRepeatingColumns().formatAsString());
//must handle sheets with quotas, see Bugzilla #47294
Sheet sheet2 = wb.createSheet("My' Sheet");
wb.setRepeatingRowsAndColumns(wb.getSheetIndex(sheet2), 0, 0, 0, 3);
+ assertEquals("1:4", sheet2.getRepeatingRows().formatAsString());
+ assertEquals("A:A", sheet1.getRepeatingColumns().formatAsString());
}
/**
diff --git a/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java b/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java
index 499fe5442b..b8c3a78a26 100644
--- a/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java
+++ b/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java
@@ -47,6 +47,24 @@ public class TestDataFormatter extends TestCase {
}
/**
+ * At the moment, we don't decode the locale strings into
+ * a specific locale, but we should format things as if
+ * the locale (eg '[$-1010409]') isn't there
+ */
+ public void testLocaleBasedFormats() {
+ DataFormatter dfUS = new DataFormatter(Locale.US);
+
+ // Standard formats
+ assertEquals("63", dfUS.formatRawCellContents(63.0, -1, "[$-1010409]General"));
+ assertEquals("63", dfUS.formatRawCellContents(63.0, -1, "[$-1010409]@"));
+
+ // Regular numeric style formats
+ assertEquals("63", dfUS.formatRawCellContents(63.0, -1, "[$-1010409]##"));
+ assertEquals("63", dfUS.formatRawCellContents(63.0, -1, "[$-1010409]00"));
+
+ }
+
+ /**
* Ensure that colours get correctly
* zapped from within the format strings
*/
diff --git a/test-data/diagram/v6-non-utf16le.vsd b/test-data/diagram/v6-non-utf16le.vsd
new file mode 100644
index 0000000000..8d4fdb89fe
--- /dev/null
+++ b/test-data/diagram/v6-non-utf16le.vsd
Binary files differ
diff --git a/test-data/document/53446.doc b/test-data/document/53446.doc
new file mode 100644
index 0000000000..4844cc937a
--- /dev/null
+++ b/test-data/document/53446.doc
Binary files differ
diff --git a/test-data/slideshow/53446.ppt b/test-data/slideshow/53446.ppt
new file mode 100644
index 0000000000..55333fc359
--- /dev/null
+++ b/test-data/slideshow/53446.ppt
Binary files differ
diff --git a/test-data/spreadsheet/53446.xls b/test-data/spreadsheet/53446.xls
new file mode 100644
index 0000000000..b33bd7aeca
--- /dev/null
+++ b/test-data/spreadsheet/53446.xls
Binary files differ
diff --git a/test-data/spreadsheet/RepeatingRowsCols.xls b/test-data/spreadsheet/RepeatingRowsCols.xls
new file mode 100644
index 0000000000..95f4e50192
--- /dev/null
+++ b/test-data/spreadsheet/RepeatingRowsCols.xls
Binary files differ
diff --git a/test-data/spreadsheet/RepeatingRowsCols.xlsx b/test-data/spreadsheet/RepeatingRowsCols.xlsx
new file mode 100644
index 0000000000..a8a5edf7db
--- /dev/null
+++ b/test-data/spreadsheet/RepeatingRowsCols.xlsx
Binary files differ