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:
Evgeniy Berlog 2012-08-05 13:05:44 +00:00
commit 0625b0bb8a
92 changed files with 2911 additions and 1236 deletions

View File

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

View File

@ -272,28 +272,41 @@ for(int sheetNum = 0; sheetNum &lt; wb.getNumberOfSheets(); sheetNum++) {
</source>
</section>
<anchor id="Performance"/>
<section><title>Performance Notes</title>
<ul>
<li>Generally you should have to create only one FormulaEvaluator
instance per sheet, but there really is no overhead in creating
multiple FormulaEvaluators per sheet other than that of the
FormulaEvaluator object creation.
</li>
<li>Also note that FormulaEvaluator maintains a reference to
the sheet and workbook, so ensure that the evaluator instance
is available for garbage collection when you are done with it
(in other words don't maintain long lived reference to
FormulaEvaluator if you don't really need to - unless
all references to the sheet and workbook are removed, these
don't get garbage collected and continue to occupy potentially
large amounts of memory).
</li>
<li>CellValue instances however do not maintain reference to the
Cell or the sheet or workbook, so these can be long-lived
objects without any adverse effect on performance.
</li>
</ul>
</section>
</body>
<anchor id="Performance"/>
<section><title>Performance Notes</title>
<ul>
<li>Generally you should have to create only one FormulaEvaluator
instance per Workbook. The FormulaEvaluator will cache
evaluations of dependent cells, so if you have multiple
formulas all depending on a cell then subsequent evaluations
will be faster.
</li>
<li>You should normally perform all of your updates to cells,
before triggering the evaluation, rather than doing one
cell at a time. By waiting until all the updates/sets are
performed, you'll be able to take best advantage of the caching
for complex formulas.
</li>
<li>If you do end up making changes to cells part way through
evaluation, you should call <em>notifySetFormula</em> or
<em>notifyUpdateCell</em> to trigger suitable cache clearance.
Alternately, you could instantiate a new FormulaEvaluator,
which will start with empty caches.
</li>
<li>Also note that FormulaEvaluator maintains a reference to
the sheet and workbook, so ensure that the evaluator instance
is available for garbage collection when you are done with it
(in other words don't maintain long lived reference to
FormulaEvaluator if you don't really need to - unless
all references to the sheet and workbook are removed, these
don't get garbage collected and continue to occupy potentially
large amounts of memory).
</li>
<li>CellValue instances however do not maintain reference to the
Cell or the sheet or workbook, so these can be long-lived
objects without any adverse effect on performance.
</li>
</ul>
</section>
</body>
</document>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.