merged with trunk
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/gsoc2012@1369572 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
commit
0625b0bb8a
@ -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>
|
||||
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.
|
||||
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 (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,
|
||||
|
@ -272,28 +272,41 @@ for(int sheetNum = 0; sheetNum < 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>
|
||||
|
@ -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");
|
||||
Workbook wb = new HSSFWorkbook(); // or new XSSFWorkbook();
|
||||
Sheet sheet1 = wb.createSheet("Sheet1");
|
||||
Sheet sheet2 = wb.createSheet("Sheet2");
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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()) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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");
|
||||
int startRow, int endRow) {
|
||||
HSSFSheet sheet = getSheetAt(sheetIndex);
|
||||
|
||||
HSSFSheet sheet = getSheetAt(sheetIndex);
|
||||
short externSheetIndex = getWorkbook().checkExternSheet(sheetIndex);
|
||||
CellRangeAddress rows = null;
|
||||
CellRangeAddress cols = null;
|
||||
|
||||
boolean settingRowAndColumn =
|
||||
startColumn != -1 && endColumn != -1 && startRow != -1 && endRow != -1;
|
||||
boolean removingRange =
|
||||
startColumn == -1 && endColumn == -1 && startRow == -1 && endRow == -1;
|
||||
if (startRow != -1) {
|
||||
rows = new CellRangeAddress(startRow, endRow, -1, -1);
|
||||
}
|
||||
if (startColumn != -1) {
|
||||
cols = new CellRangeAddress(-1, -1, startColumn, endColumn);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (isNewRecord)
|
||||
{
|
||||
HSSFName newName = new HSSFName(this, nameRecord, nameRecord.isBuiltInName() ? null : workbook.getNameCommentRecord(nameRecord));
|
||||
names.add(newName);
|
||||
}
|
||||
|
||||
HSSFPrintSetup printSetup = sheet.getPrintSetup();
|
||||
printSetup.setValidSettings(false);
|
||||
|
||||
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());
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(":");
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
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( convertNumToColString(_colIndex));
|
||||
if(_isRowAbs) {
|
||||
sb.append(ABSOLUTE_REFERENCE_MARKER);
|
||||
}
|
||||
sb.append(_rowIndex+1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
57
src/java/org/apache/poi/util/PngUtils.java
Normal file
57
src/java/org/apache/poi/util/PngUtils.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
*
|
||||
|
@ -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);
|
||||
/**
|
||||
* 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;
|
||||
ZipFile zipFile = null;
|
||||
|
||||
try {
|
||||
zipFile = ZipHelper.openZipFile(path);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidOperationException(
|
||||
"Can't open the specified file: '" + path + "'", e);
|
||||
}
|
||||
try {
|
||||
zipFile = ZipHelper.openZipFile(path);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidOperationException(
|
||||
"Can't open the specified file: '" + path + "'", e);
|
||||
}
|
||||
|
||||
this.zipArchive = new ZipFileZipEntrySource(zipFile);
|
||||
}
|
||||
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
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -352,6 +352,39 @@ public class XSLFTextRun {
|
||||
return fetcher.getValue() == null ? false : fetcher.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -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())
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 org.apache.poi.ss.SpreadsheetVersion;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
|
||||
import org.apache.poi.ss.util.SheetUtil;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.poi.hssf.util.PaneInformation;
|
||||
import org.apache.poi.ss.SpreadsheetVersion;
|
||||
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.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;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
sheet.setRepeatingRows(rows);
|
||||
sheet.setRepeatingColumns(cols);
|
||||
}
|
||||
|
||||
private static String getReferencePrintArea(String sheetName, int startC, int endC, int startR, int endR) {
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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(){
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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(){
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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"));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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()]);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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()]);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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>();
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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 "0x" + Integer.toHexString(type);
|
||||
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 type;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
break;
|
||||
case Types.ASCII_STRING:
|
||||
case Types.UNICODE_STRING:
|
||||
chunk = new StringChunk(namePrefix, chunkId, type);
|
||||
break;
|
||||
// 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...
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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});
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,6 +46,24 @@ public class TestDataFormatter extends TestCase {
|
||||
assertEquals("12,34", dfFR.formatRawCellContents(12.34, -1, "@"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
BIN
test-data/diagram/v6-non-utf16le.vsd
Normal file
BIN
test-data/diagram/v6-non-utf16le.vsd
Normal file
Binary file not shown.
BIN
test-data/document/53446.doc
Normal file
BIN
test-data/document/53446.doc
Normal file
Binary file not shown.
BIN
test-data/slideshow/53446.ppt
Normal file
BIN
test-data/slideshow/53446.ppt
Normal file
Binary file not shown.
BIN
test-data/spreadsheet/53446.xls
Normal file
BIN
test-data/spreadsheet/53446.xls
Normal file
Binary file not shown.
BIN
test-data/spreadsheet/RepeatingRowsCols.xls
Normal file
BIN
test-data/spreadsheet/RepeatingRowsCols.xls
Normal file
Binary file not shown.
BIN
test-data/spreadsheet/RepeatingRowsCols.xlsx
Normal file
BIN
test-data/spreadsheet/RepeatingRowsCols.xlsx
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user