Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-653891,653893-653944,653946-654055,654057-654355,654357-654365,654367-654648,654651-655215,655217-655277,655279-655281,655283-655911,655913-656212,656214,656216-656251,656253-656698,656700-656756,656758-656892,656894-657135,657137-657165,657168-657179,657181-657354,657356-657357,657359-658312 via svnmerge from

https://svn.apache.org/repos/asf/poi/trunk

........
  r657702 | josh | 2008-05-19 02:06:54 +0100 (Mon, 19 May 2008) | 1 line
  
  Bug 44306 - fixed reading/writing of AttrPtg and rendering of CHOOSE formulas
........
  r657875 | yegor | 2008-05-19 18:29:55 +0100 (Mon, 19 May 2008) | 1 line
  
  updated release date and started a new section for 3.1-final
........
  r658033 | josh | 2008-05-20 00:07:27 +0100 (Tue, 20 May 2008) | 1 line
  
  Minor patch to improve FormulaParser error messages like those from bug 45041
........
  r658285 | nick | 2008-05-20 16:42:16 +0100 (Tue, 20 May 2008) | 1 line
  
  Fix bug 44898 - Correctly handle short last blocks in POIFS
........
  r658287 | nick | 2008-05-20 16:46:54 +0100 (Tue, 20 May 2008) | 1 line
  
  Fix #44824 - Avoid an infinite loop when reading some HWPF pictures
........
  r658302 | nick | 2008-05-20 17:01:53 +0100 (Tue, 20 May 2008) | 1 line
  
  Patch from bug #44937 from Squeeself- Partial support for extracting Escher images from HWPF files
........
  r658308 | nick | 2008-05-20 17:30:19 +0100 (Tue, 20 May 2008) | 1 line
  
  Support for specifying a policy to HSSF on missing / blank cells when fetching
........


git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@658333 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2008-05-20 16:49:41 +00:00
parent 937d2700ed
commit 81550a63a9
25 changed files with 915 additions and 114 deletions

View File

@ -43,7 +43,14 @@
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1-beta2" date="2008-05-??">
<release version="3.1-final" date="2008-06-??">
<action dev="POI-DEVELOPERS" type="add">Support for specifying a policy to HSSF on missing / blank cells when fetching</action>
<action dev="POI-DEVELOPERS" type="add">44937 - Partial support for extracting Escher images from HWPF files</action>
<action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action>
<action dev="POI-DEVELOPERS" type="fix">44898 - Correctly handle short last blocks in POIFS</action>
</release>
<release version="3.1-beta2" date="2008-05-26">
<action dev="POI-DEVELOPERS" type="fix">44306 - fixed reading/writing of AttrPtg(type=choose) and method toFormulaString() for CHOOSE formulas</action>
<action dev="POI-DEVELOPERS" type="fix">24207 - added HSSFName.isDeleted() to check if the name points to cell that no longer exists</action>
<action dev="POI-DEVELOPERS" type="fix">40414 - fixed selected/active sheet after removing sheet from workbook</action>
<action dev="POI-DEVELOPERS" type="fix">44523 - fixed workbook sheet selection and focus</action>

View File

@ -40,7 +40,14 @@
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1-beta2" date="2008-05-??">
<release version="3.1-final" date="2008-06-??">
<action dev="POI-DEVELOPERS" type="add">Support for specifying a policy to HSSF on missing / blank cells when fetching</action>
<action dev="POI-DEVELOPERS" type="add">44937 - Partial support for extracting Escher images from HWPF files</action>
<action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action>
<action dev="POI-DEVELOPERS" type="fix">44898 - Correctly handle short last blocks in POIFS</action>
</release>
<release version="3.1-beta2" date="2008-05-26">
<action dev="POI-DEVELOPERS" type="fix">44306 - fixed reading/writing of AttrPtg(type=choose) and method toFormulaString() for CHOOSE formulas</action>
<action dev="POI-DEVELOPERS" type="fix">24207 - added HSSFName.isDeleted() to check if the name points to cell that no longer exists</action>
<action dev="POI-DEVELOPERS" type="fix">40414 - fixed selected/active sheet after removing sheet from workbook</action>
<action dev="POI-DEVELOPERS" type="fix">44523 - fixed workbook sheet selection and focus</action>

View File

@ -65,20 +65,27 @@ public class EscherClientAnchorRecord
int size = 0;
// Always find 4 two byte entries. Sometimes find 9
field_1_flag = LittleEndian.getShort( data, pos + size ); size += 2;
field_2_col1 = LittleEndian.getShort( data, pos + size ); size += 2;
field_3_dx1 = LittleEndian.getShort( data, pos + size ); size += 2;
field_4_row1 = LittleEndian.getShort( data, pos + size ); size += 2;
if(bytesRemaining >= 18) {
field_5_dy1 = LittleEndian.getShort( data, pos + size ); size += 2;
field_6_col2 = LittleEndian.getShort( data, pos + size ); size += 2;
field_7_dx2 = LittleEndian.getShort( data, pos + size ); size += 2;
field_8_row2 = LittleEndian.getShort( data, pos + size ); size += 2;
field_9_dy2 = LittleEndian.getShort( data, pos + size ); size += 2;
shortRecord = false;
} else {
shortRecord = true;
}
if (bytesRemaining == 4) // Word format only 4 bytes
{
// Not sure exactly what the format is quite yet, likely a reference to a PLC
}
else
{
field_1_flag = LittleEndian.getShort( data, pos + size ); size += 2;
field_2_col1 = LittleEndian.getShort( data, pos + size ); size += 2;
field_3_dx1 = LittleEndian.getShort( data, pos + size ); size += 2;
field_4_row1 = LittleEndian.getShort( data, pos + size ); size += 2;
if(bytesRemaining >= 18) {
field_5_dy1 = LittleEndian.getShort( data, pos + size ); size += 2;
field_6_col2 = LittleEndian.getShort( data, pos + size ); size += 2;
field_7_dx2 = LittleEndian.getShort( data, pos + size ); size += 2;
field_8_row2 = LittleEndian.getShort( data, pos + size ); size += 2;
field_9_dy2 = LittleEndian.getShort( data, pos + size ); size += 2;
shortRecord = false;
} else {
shortRecord = true;
}
}
bytesRemaining -= size;
remainingData = new byte[bytesRemaining];
System.arraycopy( data, pos + size, remainingData, 0, bytesRemaining );

View File

@ -134,7 +134,10 @@ public final class FormulaParser {
/** Report What Was Expected */
private RuntimeException expected(String s) {
return new FormulaParseException(s + " Expected");
String msg = "Parse error near char " + (pointer-1) + "'" + look + "'"
+ " in specified formula '" + formulaString + "'. Expected "
+ s;
return new FormulaParseException(msg);
}
@ -1000,7 +1003,7 @@ end;
if (ptg instanceof AttrPtg) {
AttrPtg attrPtg = ((AttrPtg) ptg);
if (attrPtg.isOptimizedIf()) {
if (attrPtg.isOptimizedIf() || attrPtg.isOptimizedChoose() || attrPtg.isGoto()) {
continue;
}
if (attrPtg.isSpace()) {
@ -1014,6 +1017,9 @@ end;
// similar to tAttrSpace - RPN is violated
continue;
}
if (!attrPtg.isSum()) {
throw new RuntimeException("Unexpected tAttr: " + attrPtg.toString());
}
}
final OperationPtg o = (OperationPtg) ptg;

View File

@ -39,6 +39,11 @@ public final class AttrPtg extends OperationPtg {
private byte field_1_options;
private short field_2_data;
/** only used for tAttrChoose: table of offsets to starts of args */
private final int[] _jumpTable;
/** only used for tAttrChoose: offset to the tFuncVar for CHOOSE() */
private final int _chooseFuncOffset;
// flags 'volatile' and 'space', can be combined.
// OOO spec says other combinations are theoretically possible but not likely to occur.
private static final BitField semiVolatile = BitFieldFactory.getInstance(0x01);
@ -63,7 +68,7 @@ public final class AttrPtg extends OperationPtg {
/** 03H = Carriage returns before opening parenthesis (only allowed before tParen token) */
public static final int CR_BEFORE_OPEN_PAREN = 0x03;
/** 04H = Spaces before closing parenthesis (only allowed before tParen, tFunc, and tFuncVar tokens) */
public static final int SPACE_BEFORE_CLOSE_PAERN = 0x04;
public static final int SPACE_BEFORE_CLOSE_PAREN = 0x04;
/** 05H = Carriage returns before closing parenthesis (only allowed before tParen, tFunc, and tFuncVar tokens) */
public static final int CR_BEFORE_CLOSE_PAREN = 0x05;
/** 06H = Spaces following the equality sign (only in macro sheets) */
@ -71,16 +76,33 @@ public final class AttrPtg extends OperationPtg {
}
public AttrPtg() {
_jumpTable = null;
_chooseFuncOffset = -1;
}
public AttrPtg(RecordInputStream in)
{
field_1_options = in.readByte();
field_2_data = in.readShort();
if (isOptimizedChoose()) {
int nCases = field_2_data;
int[] jumpTable = new int[nCases];
for (int i = 0; i < jumpTable.length; i++) {
jumpTable[i] = in.readUShort();
}
_jumpTable = jumpTable;
_chooseFuncOffset = in.readUShort();
} else {
_jumpTable = null;
_chooseFuncOffset = -1;
}
}
private AttrPtg(int options, int data) {
private AttrPtg(int options, int data, int[] jt, int chooseFuncOffset) {
field_1_options = (byte) options;
field_2_data = (short) data;
_jumpTable = jt;
_chooseFuncOffset = chooseFuncOffset;
}
/**
@ -89,7 +111,7 @@ public final class AttrPtg extends OperationPtg {
*/
public static AttrPtg createSpace(int type, int count) {
int data = type & 0x00FF | (count << 8) & 0x00FFFF;
return new AttrPtg(space.set(0), data);
return new AttrPtg(space.set(0), data, null, -1);
}
public void setOptions(byte options)
@ -136,14 +158,14 @@ public final class AttrPtg extends OperationPtg {
field_1_options=optiIf.setByteBoolean(field_1_options,bif);
}
/**
* Flags this ptg as a goto/jump
* @param isGoto
*/
public void setGoto(boolean isGoto) {
field_1_options=optGoto.setByteBoolean(field_1_options, isGoto);
}
/**
* Flags this ptg as a goto/jump
* @param isGoto
*/
public void setGoto(boolean isGoto) {
field_1_options=optGoto.setByteBoolean(field_1_options, isGoto);
}
// lets hope no one uses this anymore
public boolean isBaxcel()
{
@ -181,7 +203,7 @@ public final class AttrPtg extends OperationPtg {
if(isOptimizedIf()) {
sb.append("if dist=").append(getData());
} else if(isOptimizedChoose()) {
sb.append("choose dist=").append(getData());
sb.append("choose nCases=").append(getData());
} else if(isGoto()) {
sb.append("skip dist=").append(getData());
} else if(isSum()) {
@ -195,13 +217,28 @@ public final class AttrPtg extends OperationPtg {
public void writeBytes(byte [] array, int offset)
{
array[offset]=sid;
array[offset+1]=field_1_options;
LittleEndian.putShort(array,offset+2,field_2_data);
LittleEndian.putByte(array, offset+0, sid);
LittleEndian.putByte(array, offset+1, field_1_options);
LittleEndian.putShort(array,offset+2, field_2_data);
int[] jt = _jumpTable;
if (jt != null) {
int joff = offset+4;
LittleEndian.putUShort(array, joff, _chooseFuncOffset);
joff+=2;
for (int i = 0; i < jt.length; i++) {
LittleEndian.putUShort(array, joff, jt[i]);
joff+=2;
}
LittleEndian.putUShort(array, joff, _chooseFuncOffset);
}
}
public int getSize()
{
if (_jumpTable != null) {
return SIZE + (_jumpTable.length + 1) * LittleEndian.SHORT_SIZE;
}
return SIZE;
}
@ -255,12 +292,17 @@ public final class AttrPtg extends OperationPtg {
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
public Object clone() {
AttrPtg ptg = new AttrPtg();
ptg.field_1_options = field_1_options;
ptg.field_2_data = field_2_data;
return ptg;
int[] jt;
if (_jumpTable == null) {
jt = null;
} else {
jt = (int[]) _jumpTable.clone();
}
return new AttrPtg(field_1_options, field_2_data, jt, _chooseFuncOffset);
}
}

View File

@ -319,6 +319,36 @@ public final class HSSFRow implements Comparable, Row {
if(cellnum<0||cellnum>=cells.length) return null;
return cells[cellnum];
}
/**
* Get the hssfcell representing a given column (logical cell)
* 0-based. If you ask for a cell that is not defined, then
* your supplied policy says what to do
*
* @param cellnum 0 based column number
* @param policy Policy on blank / missing cells
* @return representing that column or null if undefined + policy allows.
*/
public HSSFCell getCell(int cellnum, MissingCellPolicy policy) {
HSSFCell cell = getCell(cellnum);
if(policy == RETURN_NULL_AND_BLANK) {
return cell;
}
if(policy == RETURN_BLANK_AS_NULL) {
if(cell == null) return cell;
if(cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
return null;
}
return cell;
}
if(policy == CREATE_NULL_AS_BLANK) {
if(cell == null) {
return createCell((short)cellnum, HSSFCell.CELL_TYPE_BLANK);
}
return cell;
}
throw new IllegalArgumentException("Illegal policy " + policy + " (" + policy.id + ")");
}
/**
* get the number of the first cell contained in this row.
@ -485,6 +515,7 @@ public final class HSSFRow implements Comparable, Row {
return cellnum;
}
/**
* @return cell iterator of the physically defined cells.
* Note that the 4th element might well not be cell 4, as the iterator
@ -503,6 +534,9 @@ public final class HSSFRow implements Comparable, Row {
return cellIterator();
}
/**
* An iterator over the (physical) cells in the row.
*/
private class CellIterator implements Iterator
{
int thisId=-1;

View File

@ -37,6 +37,7 @@ public class RawDataBlock
{
private byte[] _data;
private boolean _eof;
private boolean _hasData;
private static POILogger log = POILogFactory.getLogger(RawDataBlock.class);
/**
@ -66,6 +67,7 @@ public class RawDataBlock
throws IOException {
_data = new byte[ blockSize ];
int count = IOUtils.readFully(stream, _data);
_hasData = (count > 0);
if (count == -1) {
_eof = true;
@ -94,16 +96,21 @@ public class RawDataBlock
/**
* When we read the data, did we hit end of file?
*
* @return true if no data was read because we were at the end of
* the file, else false
*
* @exception IOException
* @return true if the EoF was hit during this block, or
* false if not. If you have a dodgy short last block, then
* it's possible to both have data, and also hit EoF...
*/
public boolean eof()
throws IOException
{
public boolean eof() {
return _eof;
}
/**
* Did we actually find any data to read? It's possible,
* in the event of a short last block, to both have hit
* the EoF, but also to have data
*/
public boolean hasData() {
return _hasData;
}
/* ********** START implementation of ListManagedBlock ********** */
@ -117,7 +124,7 @@ public class RawDataBlock
public byte [] getData()
throws IOException
{
if (eof())
if (! hasData())
{
throw new IOException("Cannot return empty data");
}

View File

@ -51,12 +51,16 @@ public class RawDataBlockList
while (true)
{
RawDataBlock block = new RawDataBlock(stream, bigBlockSize);
// If there was data, add the block to the list
if(block.hasData()) {
blocks.add(block);
}
if (block.eof())
{
// If the stream is now at the End Of File, we're done
if (block.eof()) {
break;
}
blocks.add(block);
}
setBlocks(( RawDataBlock [] ) blocks.toArray(new RawDataBlock[ 0 ]));
}

View File

@ -33,4 +33,22 @@ public interface Row {
HSSFCell getCell(int cellnum);
Iterator cellIterator();
/**
* Used to specify the different possible policies
* if for the case of null and blank cells
*/
public static class MissingCellPolicy {
private static int NEXT_ID = 1;
public final int id;
private MissingCellPolicy() {
this.id = NEXT_ID++;
}
}
/** Missing cells are returned as null, Blank cells are returned as normal */
public static final MissingCellPolicy RETURN_NULL_AND_BLANK = new MissingCellPolicy();
/** Missing cells are returned as null, as are blank cells */
public static final MissingCellPolicy RETURN_BLANK_AS_NULL = new MissingCellPolicy();
/** A new, blank cell is created for missing cells. Blank cells are returned as normal */
public static final MissingCellPolicy CREATE_NULL_AS_BLANK = new MissingCellPolicy();
}

View File

@ -88,9 +88,20 @@ public interface Row extends Iterable<Cell> {
* ask for a cell that is not defined....you get a null.
*
* @param cellnum 0 based column number
* @return HSSFCell representing that column or null if undefined.
* @return Cell representing that column or null if undefined.
*/
Cell getCell(int cellnum);
/**
* Get the hssfcell representing a given column (logical cell)
* 0-based. If you ask for a cell that is not defined, then
* your supplied policy says what to do
*
* @param cellnum 0 based column number
* @param policy Policy on blank / missing cells
* @return representing that column or null if undefined + policy allows.
*/
public Cell getCell(int cellnum, MissingCellPolicy policy);
/**
* get the number of the first cell contained in this row.
@ -170,4 +181,22 @@ public interface Row extends Iterable<Cell> {
boolean equals(Object obj);
/**
* Used to specify the different possible policies
* if for the case of null and blank cells
*/
public static class MissingCellPolicy {
private static int NEXT_ID = 1;
public final int id;
private MissingCellPolicy() {
this.id = NEXT_ID++;
}
}
/** Missing cells are returned as null, Blank cells are returned as normal */
public static final MissingCellPolicy RETURN_NULL_AND_BLANK = new MissingCellPolicy();
/** Missing cells are returned as null, as are blank cells */
public static final MissingCellPolicy RETURN_BLANK_AS_NULL = new MissingCellPolicy();
/** A new, blank cell is created for missing cells. Blank cells are returned as normal */
public static final MissingCellPolicy CREATE_NULL_AS_BLANK = new MissingCellPolicy();
}

View File

@ -21,6 +21,7 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
@ -138,6 +139,27 @@ public class XSSFRow implements Row {
}
return null;
}
public Cell getCell(int cellnum, MissingCellPolicy policy) {
Cell cell = getCell(cellnum);
if(policy == RETURN_NULL_AND_BLANK) {
return cell;
}
if(policy == RETURN_BLANK_AS_NULL) {
if(cell == null) return cell;
if(cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
return null;
}
return cell;
}
if(policy == CREATE_NULL_AS_BLANK) {
if(cell == null) {
return createCell((short)cellnum, HSSFCell.CELL_TYPE_BLANK);
}
return cell;
}
throw new IllegalArgumentException("Illegal policy " + policy + " (" + policy.id + ")");
}
public short getFirstCellNum() {
for (Iterator<Cell> it = cellIterator() ; it.hasNext() ; ) {

View File

@ -22,6 +22,7 @@ import java.util.Iterator;
import junit.framework.TestCase;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.TestXSSFCell.DummySharedStringSource;
/**
@ -166,6 +167,64 @@ public final class TestXSSFRow extends TestCase {
row.setZeroHeight(true);
assertTrue(row.getZeroHeight());
}
/**
* Tests for the missing/blank cell policy stuff
*/
public void testGetCellPolicy() throws Exception {
XSSFRow row = new XSSFRow(createParentObjects());
// 0 -> string
// 1 -> num
// 2 missing
// 3 missing
// 4 -> blank
// 5 -> num
row.createCell((short)0).setCellValue(new XSSFRichTextString("test"));
row.createCell((short)1).setCellValue(3.2);
row.createCell((short)4, Cell.CELL_TYPE_BLANK);
row.createCell((short)5).setCellValue(4);
// First up, no policy
assertEquals(Cell.CELL_TYPE_STRING, row.getCell(0).getCellType());
assertEquals(Cell.CELL_TYPE_NUMERIC, row.getCell(1).getCellType());
assertEquals(null, row.getCell(2));
assertEquals(null, row.getCell(3));
assertEquals(Cell.CELL_TYPE_BLANK, row.getCell(4).getCellType());
assertEquals(Cell.CELL_TYPE_NUMERIC, row.getCell(5).getCellType());
// RETURN_NULL_AND_BLANK - same as default
assertEquals(Cell.CELL_TYPE_STRING, row.getCell(0, Row.RETURN_NULL_AND_BLANK).getCellType());
assertEquals(Cell.CELL_TYPE_NUMERIC, row.getCell(1, Row.RETURN_NULL_AND_BLANK).getCellType());
assertEquals(null, row.getCell(2, Row.RETURN_NULL_AND_BLANK));
assertEquals(null, row.getCell(3, Row.RETURN_NULL_AND_BLANK));
assertEquals(Cell.CELL_TYPE_BLANK, row.getCell(4, Row.RETURN_NULL_AND_BLANK).getCellType());
assertEquals(Cell.CELL_TYPE_NUMERIC, row.getCell(5, Row.RETURN_NULL_AND_BLANK).getCellType());
// RETURN_BLANK_AS_NULL - nearly the same
assertEquals(Cell.CELL_TYPE_STRING, row.getCell(0, XSSFRow.RETURN_BLANK_AS_NULL).getCellType());
assertEquals(Cell.CELL_TYPE_NUMERIC, row.getCell(1, XSSFRow.RETURN_BLANK_AS_NULL).getCellType());
assertEquals(null, row.getCell(2, XSSFRow.RETURN_BLANK_AS_NULL));
assertEquals(null, row.getCell(3, XSSFRow.RETURN_BLANK_AS_NULL));
assertEquals(null, row.getCell(4, XSSFRow.RETURN_BLANK_AS_NULL));
assertEquals(Cell.CELL_TYPE_NUMERIC, row.getCell(5, XSSFRow.RETURN_BLANK_AS_NULL).getCellType());
// CREATE_NULL_AS_BLANK - creates as needed
assertEquals(Cell.CELL_TYPE_STRING, row.getCell(0, XSSFRow.CREATE_NULL_AS_BLANK).getCellType());
assertEquals(Cell.CELL_TYPE_NUMERIC, row.getCell(1, XSSFRow.CREATE_NULL_AS_BLANK).getCellType());
assertEquals(Cell.CELL_TYPE_BLANK, row.getCell(2, XSSFRow.CREATE_NULL_AS_BLANK).getCellType());
assertEquals(Cell.CELL_TYPE_BLANK, row.getCell(3, XSSFRow.CREATE_NULL_AS_BLANK).getCellType());
assertEquals(Cell.CELL_TYPE_BLANK, row.getCell(4, XSSFRow.CREATE_NULL_AS_BLANK).getCellType());
assertEquals(Cell.CELL_TYPE_NUMERIC, row.getCell(5, XSSFRow.CREATE_NULL_AS_BLANK).getCellType());
// Check created ones get the right column
assertEquals((short)0, row.getCell(0, XSSFRow.CREATE_NULL_AS_BLANK).getCellNum());
assertEquals((short)1, row.getCell(1, XSSFRow.CREATE_NULL_AS_BLANK).getCellNum());
assertEquals((short)2, row.getCell(2, XSSFRow.CREATE_NULL_AS_BLANK).getCellNum());
assertEquals((short)3, row.getCell(3, XSSFRow.CREATE_NULL_AS_BLANK).getCellNum());
assertEquals((short)4, row.getCell(4, XSSFRow.CREATE_NULL_AS_BLANK).getCellNum());
assertEquals((short)5, row.getCell(5, XSSFRow.CREATE_NULL_AS_BLANK).getCellNum());
}
/**
* Method that returns a row with some sample cells

View File

@ -53,10 +53,10 @@ public class HWPFDocument extends POIDocument
protected FileInformationBlock _fib;
/** main document stream buffer*/
private byte[] _mainStream;
protected byte[] _mainStream;
/** table stream buffer*/
private byte[] _tableStream;
protected byte[] _tableStream;
/** data stream buffer*/
protected byte[] _dataStream;
@ -93,6 +93,12 @@ public class HWPFDocument extends POIDocument
/** Holds pictures table */
protected PicturesTable _pictures;
/** Holds FSBA (shape) information */
protected FSPATable _fspa;
/** Escher Drawing Group information */
protected EscherRecordHolder _dgg;
protected HWPFDocument()
{
@ -204,9 +210,6 @@ public class HWPFDocument extends POIDocument
{
_dataStream = new byte[0];
}
// read in the pictures stream
_pictures = new PicturesTable(this, _dataStream);
// get the start of text in the main stream
int fcMin = _fib.getFcMin();
@ -226,6 +229,20 @@ public class HWPFDocument extends POIDocument
_cbt.adjustForDelete(0, 0, cpMin);
_pbt.adjustForDelete(0, 0, cpMin);
}
// Read FSPA and Escher information
_fspa = new FSPATable(_tableStream, _fib.getFcPlcspaMom(), _fib.getLcbPlcspaMom(), getTextTable().getTextPieces());
if (_fib.getFcDggInfo() != 0)
{
_dgg = new EscherRecordHolder(_tableStream, _fib.getFcDggInfo(), _fib.getLcbDggInfo());
} else
{
_dgg = new EscherRecordHolder();
}
// read in the pictures stream
_pictures = new PicturesTable(this, _dataStream, _mainStream, _fspa, _dgg);
_st = new SectionTable(_mainStream, _tableStream, _fib.getFcPlcfsed(), _fib.getLcbPlcfsed(), fcMin, getTextTable().getTextPieces());
_ss = new StyleSheet(_tableStream, _fib.getFcStshf());

View File

@ -0,0 +1,116 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.apache.poi.hwpf.model;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.poi.ddf.DefaultEscherRecordFactory;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherRecordFactory;
/**
* Based on AbstractEscherRecordHolder fomr HSSF.
*
* @author Squeeself
*/
public class EscherRecordHolder
{
protected ArrayList escherRecords = new ArrayList();
public EscherRecordHolder()
{
}
public EscherRecordHolder(byte[] data, int offset, int size)
{
fillEscherRecords(data, offset, size);
}
private void fillEscherRecords(byte[] data, int offset, int size)
{
EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
int pos = offset;
while ( pos < offset + size)
{
EscherRecord r = recordFactory.createRecord(data, pos);
escherRecords.add(r);
int bytesRead = r.fillFields(data, pos, recordFactory);
pos += bytesRead + 1; // There is an empty byte between each top-level record in a Word doc
}
}
public List getEscherRecords()
{
return escherRecords;
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
final String nl = System.getProperty("line.separator");
if (escherRecords.size() == 0)
buffer.append("No Escher Records Decoded" + nl);
for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); )
{
EscherRecord r = (EscherRecord) iterator.next();
buffer.append(r.toString());
}
return buffer.toString();
}
/**
* If we have a EscherContainerRecord as one of our
* children (and most top level escher holders do),
* then return that.
*/
public EscherContainerRecord getEscherContainer() {
for(Iterator it = escherRecords.iterator(); it.hasNext();) {
Object er = it.next();
if(er instanceof EscherContainerRecord) {
return (EscherContainerRecord)er;
}
}
return null;
}
/**
* Descends into all our children, returning the
* first EscherRecord with the given id, or null
* if none found
*/
public EscherRecord findFirstWithId(short id) {
return findFirstWithId(id, getEscherRecords());
}
private EscherRecord findFirstWithId(short id, List records) {
// Check at our level
for(Iterator it = records.iterator(); it.hasNext();) {
EscherRecord r = (EscherRecord)it.next();
if(r.getRecordId() == id) {
return r;
}
}
// Then check our children in turn
for(Iterator it = records.iterator(); it.hasNext();) {
EscherRecord r = (EscherRecord)it.next();
if(r.isContainerRecord()) {
EscherRecord found =
findFirstWithId(id, r.getChildRecords());
if(found != null) {
return found;
}
}
}
// Not found in this lot
return null;
}
}

View File

@ -0,0 +1,182 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwpf.model;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndian;
/**
* File Shape Address structure
*
* @author Squeeself
*/
public class FSPA
{
public static final int FSPA_SIZE = 26;
private int spid; // Shape identifier. Used to get data position
private int xaLeft; // Enclosing rectangle
private int yaTop; // Enclosing rectangle
private int xaRight; // Enclosing rectangle
private int yaBottom; // Enclosing rectangle
private short options;
private static BitField fHdr = BitFieldFactory.getInstance(0x0001); // 1 in undo when in header
private static BitField bx = BitFieldFactory.getInstance(0x0006); // x pos relative to anchor CP: 0 - page margin, 1 - top of page, 2 - text, 3 - reserved
private static BitField by = BitFieldFactory.getInstance(0x0018); // y pos relative to anchor CP: ditto
private static BitField wr = BitFieldFactory.getInstance(0x01E0); // Text wrapping mode: 0 - like 2 w/o absolute, 1 - no text next to shape, 2 - wrap around absolute object, 3 - wrap as if no object, 4 - wrap tightly around object, 5 - wrap tightly, allow holes, 6-15 - reserved
private static BitField wrk = BitFieldFactory.getInstance(0x1E00); // Text wrapping mode type (for modes 2&4): 0 - wrap both sides, 1 - wrap only left, 2 - wrap only right, 3 - wrap largest side
private static BitField fRcaSimple = BitFieldFactory.getInstance(0x2000); // Overwrites bx if set, forcing rectangle to be page relative
private static BitField fBelowText = BitFieldFactory.getInstance(0x4000); // if true, shape is below text, otherwise above
private static BitField fAnchorLock = BitFieldFactory.getInstance(0x8000); // if true, anchor is locked
private int cTxbx; // Count of textboxes in shape (undo doc only)
public FSPA()
{
}
public FSPA(byte[] bytes, int offset)
{
spid = LittleEndian.getInt(bytes, offset);
offset += LittleEndian.INT_SIZE;
xaLeft = LittleEndian.getInt(bytes, offset);
offset += LittleEndian.INT_SIZE;
yaTop = LittleEndian.getInt(bytes, offset);
offset += LittleEndian.INT_SIZE;
xaRight = LittleEndian.getInt(bytes, offset);
offset += LittleEndian.INT_SIZE;
yaBottom = LittleEndian.getInt(bytes, offset);
offset += LittleEndian.INT_SIZE;
options = LittleEndian.getShort(bytes, offset);
offset += LittleEndian.SHORT_SIZE;
cTxbx = LittleEndian.getInt(bytes, offset);
}
public int getSpid()
{
return spid;
}
public int getXaLeft()
{
return xaLeft;
}
public int getYaTop()
{
return yaTop;
}
public int getXaRight()
{
return xaRight;
}
public int getYaBottom()
{
return yaBottom;
}
public boolean isFHdr()
{
return fHdr.isSet(options);
}
public short getBx()
{
return bx.getShortValue(options);
}
public short getBy()
{
return by.getShortValue(options);
}
public short getWr()
{
return wr.getShortValue(options);
}
public short getWrk()
{
return wrk.getShortValue(options);
}
public boolean isFRcaSimple()
{
return fRcaSimple.isSet(options);
}
public boolean isFBelowText()
{
return fBelowText.isSet(options);
}
public boolean isFAnchorLock()
{
return fAnchorLock.isSet(options);
}
public int getCTxbx()
{
return cTxbx;
}
public byte[] toByteArray()
{
int offset = 0;
byte[] buf = new byte[FSPA_SIZE];
LittleEndian.putInt(buf, offset, spid);
offset += LittleEndian.INT_SIZE;
LittleEndian.putInt(buf, offset, xaLeft);
offset += LittleEndian.INT_SIZE;
LittleEndian.putInt(buf, offset, yaTop);
offset += LittleEndian.INT_SIZE;
LittleEndian.putInt(buf, offset, xaRight);
offset += LittleEndian.INT_SIZE;
LittleEndian.putInt(buf, offset, yaBottom);
offset += LittleEndian.INT_SIZE;
LittleEndian.putShort(buf, offset, options);
offset += LittleEndian.SHORT_SIZE;
LittleEndian.putInt(buf, offset, cTxbx);
offset += LittleEndian.INT_SIZE;
return buf;
}
public String toString()
{
StringBuffer buf = new StringBuffer();
buf.append("spid: ").append(spid);
buf.append(", xaLeft: ").append(xaLeft);
buf.append(", yaTop: ").append(yaTop);
buf.append(", xaRight: ").append(xaRight);
buf.append(", yaBottom: ").append(yaBottom);
buf.append(", options: ").append(options);
buf.append(" (fHdr: ").append(isFHdr());
buf.append(", bx: ").append(getBx());
buf.append(", by: ").append(getBy());
buf.append(", wr: ").append(getWr());
buf.append(", wrk: ").append(getWrk());
buf.append(", fRcaSimple: ").append(isFRcaSimple());
buf.append(", fBelowText: ").append(isFBelowText());
buf.append(", fAnchorLock: ").append(isFAnchorLock());
buf.append("), cTxbx: ").append(cTxbx);
return buf.toString();
}
}

View File

@ -0,0 +1,82 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwpf.model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
/**
* This class holds all the FSPA (File Shape Address) structures.
*
* @author Squeeself
*/
public class FSPATable
{
protected ArrayList shapes = new ArrayList();
protected HashMap cps = new HashMap();
protected List _text;
public FSPATable(byte[] tableStream, int fcPlcspa, int lcbPlcspa, List tpt)
{
_text = tpt;
// Will be 0 if no drawing objects in document
if (fcPlcspa == 0)
return;
PlexOfCps plex = new PlexOfCps(tableStream, fcPlcspa, lcbPlcspa, FSPA.FSPA_SIZE);
for (int i=0; i < plex.length(); i++)
{
GenericPropertyNode property = plex.getProperty(i);
FSPA fspa = new FSPA(property.getBytes(), 0);
shapes.add(fspa);
cps.put(Integer.valueOf(property.getStart()), Integer.valueOf(i));
}
}
public FSPA getFspaFromCp(int cp)
{
Integer idx = (Integer)cps.get(Integer.valueOf(cp));
if (idx == null)
return null;
return (FSPA)shapes.get(idx.intValue());
}
public List getShapes()
{
return shapes;
}
public String toString()
{
StringBuffer buf = new StringBuffer();
buf.append("[FPSA PLC size=").append(shapes.size()).append("]\n");
for (Iterator it = cps.keySet().iterator(); it.hasNext(); )
{
Integer i = (Integer) it.next();
FSPA fspa = (FSPA) shapes.get(((Integer)cps.get(i)).intValue());
buf.append(" [FC: ").append(i.toString()).append("] ");
buf.append(fspa.toString());
buf.append("\n");
}
buf.append("[/FSPA PLC]");
return buf.toString();
}
}

View File

@ -308,6 +308,26 @@ public class FileInformationBlock extends FIBAbstractType
{
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDMOM);
}
public int getFcPlcspaMom()
{
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCSPAMOM);
}
public int getLcbPlcspaMom()
{
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCSPAMOM);
}
public int getFcDggInfo()
{
return _fieldHandler.getFieldOffset(FIBFieldHandler.DGGINFO);
}
public int getLcbDggInfo()
{
return _fieldHandler.getFieldSize(FIBFieldHandler.DGGINFO);
}
public void writeTo (byte[] mainStream, HWPFOutputStream tableStream)
throws IOException

View File

@ -26,7 +26,12 @@ import org.apache.poi.hwpf.usermodel.Range;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.poi.ddf.DefaultEscherRecordFactory;
import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.ddf.EscherBlipRecord;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherRecordFactory;
/**
* Holds information about all pictures embedded in Word Document either via "Insert -> Picture -> From File" or via
@ -57,6 +62,9 @@ public class PicturesTable
private HWPFDocument _document;
private byte[] _dataStream;
private byte[] _mainStream;
private FSPATable _fspa;
private EscherRecordHolder _dgg;
/** @link dependency
* @stereotype instantiate*/
@ -67,10 +75,13 @@ public class PicturesTable
* @param document
* @param _dataStream
*/
public PicturesTable(HWPFDocument _document, byte[] _dataStream)
public PicturesTable(HWPFDocument _document, byte[] _dataStream, byte[] _mainStream, FSPATable fspa, EscherRecordHolder dgg)
{
this._document = _document;
this._document = _document;
this._dataStream = _dataStream;
this._mainStream = _mainStream;
this._fspa = fspa;
this._dgg = dgg;
}
/**
@ -83,6 +94,13 @@ public class PicturesTable
}
return false;
}
public boolean hasEscherPicture(CharacterRun run) {
if (run.isSpecialCharacter() && !run.isObj() && !run.isOle2() && !run.isData() && run.text().startsWith("\u0008")) {
return true;
}
return false;
}
/**
* determines whether specified CharacterRun contains reference to a picture
@ -122,6 +140,46 @@ public class PicturesTable
}
return null;
}
/**
* Performs a recursive search for pictures in the given list of escher records.
*
* @param escherRecords the escher records.
* @param pictures the list to populate with the pictures.
*/
private void searchForPictures(List escherRecords, List pictures)
{
Iterator recordIter = escherRecords.iterator();
while (recordIter.hasNext())
{
Object obj = recordIter.next();
if (obj instanceof EscherRecord)
{
EscherRecord escherRecord = (EscherRecord) obj;
if (escherRecord instanceof EscherBSERecord)
{
EscherBSERecord bse = (EscherBSERecord) escherRecord;
EscherBlipRecord blip = bse.getBlipRecord();
if (blip != null)
{
pictures.add(new Picture(blip.getPicturedata()));
}
else if (bse.getOffset() > 0)
{
// Blip stored in delay stream, which in a word doc, is the main stream
EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
blip = (EscherBlipRecord) recordFactory.createRecord(_mainStream, bse.getOffset());
blip.fillFields(_mainStream, bse.getOffset(), recordFactory);
pictures.add(new Picture(blip.getPicturedata()));
}
}
// Recursive call.
searchForPictures(escherRecord.getChildRecords(), pictures);
}
}
}
/**
* Not all documents have all the images concatenated in the data stream
@ -136,12 +194,13 @@ public class PicturesTable
for (int i = 0; i < range.numCharacterRuns(); i++) {
CharacterRun run = range.getCharacterRun(i);
String text = run.text();
int j = text.charAt(0);
Picture picture = extractPicture(run, false);
if (picture != null) {
pictures.add(picture);
}
}
searchForPictures(_dgg.getEscherRecords(), pictures);
return pictures;
}

View File

@ -98,6 +98,15 @@ public class Picture
fillImageContent();
}
}
public Picture(byte[] _dataStream)
{
this._dataStream = _dataStream;
this.dataBlockStartOfsset = 0;
this.dataBlockSize = _dataStream.length;
this.pictureBytesStartOffset = 0;
this.size = _dataStream.length;
}
private void fillWidthHeight()
{
@ -363,6 +372,7 @@ public class Picture
do {
firstByte = _dataStream[pointer];
secondByte = _dataStream[pointer+1];
pointer += 2;
} while (!(firstByte==(byte)0xFF) && pointer<endOfPicture-1);
if (firstByte==((byte)0xFF) && pointer<endOfPicture-1) {

View File

@ -35,10 +35,12 @@ public class TestHWPFPictures extends TestCase {
private String docAFile;
private String docBFile;
private String docCFile;
private String docDFile;
private String imgAFile;
private String imgBFile;
private String imgCFile;
private String imgDFile;
protected void setUp() throws Exception {
String dirname = System.getProperty("HWPF.testdata.path");
@ -46,10 +48,12 @@ public class TestHWPFPictures extends TestCase {
docAFile = dirname + "/testPictures.doc";
docBFile = dirname + "/two_images.doc";
docCFile = dirname + "/vector_image.doc";
docDFile = dirname + "/GaiaTest.doc";
imgAFile = dirname + "/simple_image.jpg";
imgBFile = dirname + "/simple_image.png";
imgCFile = dirname + "/vector_image.emf";
imgDFile = dirname + "/GaiaTestImg.png";
}
/**
@ -126,7 +130,26 @@ public class TestHWPFPictures extends TestCase {
assertEquals(picBytes.length, pic.getContent().length);
assertBytesSame(picBytes, pic.getContent());
}
/**
* Pending the missing files being uploaded to
* bug #44937
*/
public void BROKENtestEscherDrawing() throws Exception
{
HWPFDocument docD = new HWPFDocument(new FileInputStream(docDFile));
List allPictures = docD.getPicturesTable().getAllPictures();
assertEquals(1, allPictures.size());
Picture pic = (Picture) allPictures.get(0);
assertNotNull(pic);
byte[] picD = readFile(imgDFile);
assertEquals(picD.length, pic.getContent().length);
assertBytesSame(picD, pic.getContent());
}
private void assertBytesSame(byte[] a, byte[] b) {
assertEquals(a.length, b.length);

View File

@ -38,6 +38,8 @@ public final class TestExternalNameRecord extends TestCase {
// data taken from bugzilla 44774 att 21790
private static final byte[] dataPlainName = {
0, 0, 0, 0, 0, 0, 9, 0, 82, 97, 116, 101, 95, 68, 97, 116, 101, 9, 0, 58, 0, 0, 0, 0, 4, 0, 8, 0
// TODO - the last 2 bytes of formula data (8,0) seem weird. They encode to ConcatPtg, UnknownPtg
// UnknownPtg is otherwise not created by any other test cases
};
private static ExternalNameRecord createSimpleENR(byte[] data) {

View File

@ -19,17 +19,15 @@ package org.apache.poi.hssf.record;
import java.io.ByteArrayInputStream;
import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.ConcatPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.record.formula.IntPtg;
import org.apache.poi.hssf.record.formula.RangePtg;
import org.apache.poi.hssf.record.formula.ReferencePtg;
import org.apache.poi.hssf.record.formula.UnknownPtg;
import java.util.List;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.record.formula.IntPtg;
import org.apache.poi.hssf.record.formula.ReferencePtg;
/**
* Tests the serialization and deserialization of the FormulaRecord
* class works correctly.
@ -57,7 +55,7 @@ public final class TestFormulaRecord extends TestCase {
*/
public void testCheckNanPreserve() {
byte[] formulaByte = new byte[29];
for (int i = 0; i < formulaByte.length; i++) formulaByte[i] = (byte)0;
formulaByte[4] = (byte)0x0F;
formulaByte[6] = (byte)0x02;
formulaByte[8] = (byte)0x07;
@ -91,8 +89,6 @@ public final class TestFormulaRecord extends TestCase {
public void testExpFormula() {
byte[] formulaByte = new byte[27];
for (int i = 0; i < formulaByte.length; i++) formulaByte[i] = (byte)0;
formulaByte[4] =(byte)0x0F;
formulaByte[14]=(byte)0x08;
formulaByte[18]=(byte)0xE0;
@ -109,15 +105,14 @@ public final class TestFormulaRecord extends TestCase {
public void testWithConcat() throws Exception {
// =CHOOSE(2,A2,A3,A4)
byte[] data = new byte[] {
byte[] data = {
6, 0, 68, 0,
1, 0, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 57,
64, 0, 0, 12, 0, 12, -4, 46, 0,
30, 2, 0, // Int - 2
25, 4, 3, 0, // Attr
8, 0, // Concat
17, 0, // Range
26, 0, 35, 0, // Bit like an attr
8, 0, 17, 0, 26, 0, // jumpTable
35, 0, // chooseOffset
36, 1, 0, 0, -64, // Ref - A2
25, 8, 21, 0, // Attr
36, 2, 0, 0, -64, // Ref - A3
@ -126,30 +121,24 @@ public final class TestFormulaRecord extends TestCase {
25, 8, 3, 0, // Attr
66, 4, 100, 0 // CHOOSE
};
RecordInputStream inp = new RecordInputStream(
new ByteArrayInputStream(data)
);
RecordInputStream inp = new RecordInputStream( new ByteArrayInputStream(data));
inp.nextRecord();
FormulaRecord fr = new FormulaRecord(inp);
assertEquals(14, fr.getNumberOfExpressionTokens());
assertEquals(IntPtg.class, fr.getParsedExpression().get(0).getClass());
assertEquals(AttrPtg.class, fr.getParsedExpression().get(1).getClass());
assertEquals(ConcatPtg.class, fr.getParsedExpression().get(2).getClass());
assertEquals(UnknownPtg.class, fr.getParsedExpression().get(3).getClass());
assertEquals(RangePtg.class, fr.getParsedExpression().get(4).getClass());
assertEquals(UnknownPtg.class, fr.getParsedExpression().get(5).getClass());
assertEquals(AttrPtg.class, fr.getParsedExpression().get(6).getClass());
assertEquals(ReferencePtg.class, fr.getParsedExpression().get(7).getClass());
assertEquals(AttrPtg.class, fr.getParsedExpression().get(8).getClass());
assertEquals(ReferencePtg.class, fr.getParsedExpression().get(9).getClass());
assertEquals(AttrPtg.class, fr.getParsedExpression().get(10).getClass());
assertEquals(ReferencePtg.class, fr.getParsedExpression().get(11).getClass());
assertEquals(AttrPtg.class, fr.getParsedExpression().get(12).getClass());
assertEquals(FuncVarPtg.class, fr.getParsedExpression().get(13).getClass());
List ptgs = fr.getParsedExpression();
assertEquals(9, ptgs.size());
assertEquals(IntPtg.class, ptgs.get(0).getClass());
assertEquals(AttrPtg.class, ptgs.get(1).getClass());
assertEquals(ReferencePtg.class, ptgs.get(2).getClass());
assertEquals(AttrPtg.class, ptgs.get(3).getClass());
assertEquals(ReferencePtg.class, ptgs.get(4).getClass());
assertEquals(AttrPtg.class, ptgs.get(5).getClass());
assertEquals(ReferencePtg.class, ptgs.get(6).getClass());
assertEquals(AttrPtg.class, ptgs.get(7).getClass());
assertEquals(FuncVarPtg.class, ptgs.get(8).getClass());
FuncVarPtg choose = (FuncVarPtg)fr.getParsedExpression().get(13);
FuncVarPtg choose = (FuncVarPtg)ptgs.get(8);
assertEquals("CHOOSE", choose.getName());
}

View File

@ -17,18 +17,19 @@
package org.apache.poi.hssf.usermodel;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.ss.util.Region;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.util.TempFile;
import java.io.*;
import java.util.Iterator;
/**
* Testcases for bugs entered in bugzilla
* the Test name contains the bugzilla bug id
@ -81,13 +82,7 @@ public final class TestBugs extends TestCase {
HSSFRow r = s.createRow(0);
HSSFCell c = r.createCell((short)0);
c.setCellValue(10);
try {
writeOutAndReadBack(wb);
} catch (RecordFormatException e) {
if (false) { // TODO (Apr-2008) this file does not read back ok. create bugzilla bug & fix.
throw new AssertionFailedError("Identified bug XXXX");
}
}
writeOutAndReadBack(wb);
}
/**Test writing a hyperlink
* Open resulting sheet in Excel and check that A1 contains a hyperlink*/
@ -758,9 +753,13 @@ public final class TestBugs extends TestCase {
HSSFCell c2 = r2.getCell((short)1);
assertEquals(25, (int)c2.getNumericCellValue());
if (false) { // TODO (Apr-2008) This will blow up with IllegalStateException (stack underflow)
// excel function "CHOOSE" probably needs some special handling in FormulaParser.toFormulaString()
assertEquals("=CHOOSE(2,A2,A3,A4)", c2.getCellFormula());
try {
assertEquals("CHOOSE(2,A2,A3,A4)", c2.getCellFormula());
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("Too few arguments")
&& e.getMessage().indexOf("ConcatPtg") > 0) {
throw new AssertionFailedError("identified bug 44306");
}
}
}
@ -888,13 +887,13 @@ public final class TestBugs extends TestCase {
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);
}
/**
* Had a problem apparently, not sure what as it
* works just fine...
*/
public void test44891() throws Exception {
HSSFWorkbook wb = openSample("44891.xls");
HSSFWorkbook wb = openSample("44891.xls");
assertTrue("no errors reading sample xls", true);
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);
@ -906,7 +905,7 @@ public final class TestBugs extends TestCase {
* Works fine with poi-3.1-beta1.
*/
public void test44235() throws Exception {
HSSFWorkbook wb = openSample("44235.xls");
HSSFWorkbook wb = openSample("44235.xls");
assertTrue("no errors reading sample xls", true);
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);
@ -930,7 +929,7 @@ public final class TestBugs extends TestCase {
}
public void test36947() throws Exception {
HSSFWorkbook wb = openSample("36947.xls");
HSSFWorkbook wb = openSample("36947.xls");
assertTrue("no errors reading sample xls", true);
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);
@ -947,7 +946,7 @@ public final class TestBugs extends TestCase {
}
public void test39634() throws Exception {
HSSFWorkbook wb = openSample("39634.xls");
HSSFWorkbook wb = openSample("39634.xls");
assertTrue("no errors reading sample xls", true);
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);

View File

@ -204,4 +204,64 @@ public final class TestHSSFRow extends TestCase {
row.createCell((short) 255);
assertEquals(256, row.getLastCellNum());
}
/**
* Tests for the missing/blank cell policy stuff
*/
public void testGetCellPolicy() throws Exception {
HSSFWorkbook book = new HSSFWorkbook();
HSSFSheet sheet = book.createSheet("test");
HSSFRow row = sheet.createRow(0);
// 0 -> string
// 1 -> num
// 2 missing
// 3 missing
// 4 -> blank
// 5 -> num
row.createCell((short)0).setCellValue(new HSSFRichTextString("test"));
row.createCell((short)1).setCellValue(3.2);
row.createCell((short)4, HSSFCell.CELL_TYPE_BLANK);
row.createCell((short)5).setCellValue(4);
// First up, no policy
assertEquals(HSSFCell.CELL_TYPE_STRING, row.getCell(0).getCellType());
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, row.getCell(1).getCellType());
assertEquals(null, row.getCell(2));
assertEquals(null, row.getCell(3));
assertEquals(HSSFCell.CELL_TYPE_BLANK, row.getCell(4).getCellType());
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, row.getCell(5).getCellType());
// RETURN_NULL_AND_BLANK - same as default
assertEquals(HSSFCell.CELL_TYPE_STRING, row.getCell(0, HSSFRow.RETURN_NULL_AND_BLANK).getCellType());
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, row.getCell(1, HSSFRow.RETURN_NULL_AND_BLANK).getCellType());
assertEquals(null, row.getCell(2, HSSFRow.RETURN_NULL_AND_BLANK));
assertEquals(null, row.getCell(3, HSSFRow.RETURN_NULL_AND_BLANK));
assertEquals(HSSFCell.CELL_TYPE_BLANK, row.getCell(4, HSSFRow.RETURN_NULL_AND_BLANK).getCellType());
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, row.getCell(5, HSSFRow.RETURN_NULL_AND_BLANK).getCellType());
// RETURN_BLANK_AS_NULL - nearly the same
assertEquals(HSSFCell.CELL_TYPE_STRING, row.getCell(0, HSSFRow.RETURN_BLANK_AS_NULL).getCellType());
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, row.getCell(1, HSSFRow.RETURN_BLANK_AS_NULL).getCellType());
assertEquals(null, row.getCell(2, HSSFRow.RETURN_BLANK_AS_NULL));
assertEquals(null, row.getCell(3, HSSFRow.RETURN_BLANK_AS_NULL));
assertEquals(null, row.getCell(4, HSSFRow.RETURN_BLANK_AS_NULL));
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, row.getCell(5, HSSFRow.RETURN_BLANK_AS_NULL).getCellType());
// CREATE_NULL_AS_BLANK - creates as needed
assertEquals(HSSFCell.CELL_TYPE_STRING, row.getCell(0, HSSFRow.CREATE_NULL_AS_BLANK).getCellType());
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, row.getCell(1, HSSFRow.CREATE_NULL_AS_BLANK).getCellType());
assertEquals(HSSFCell.CELL_TYPE_BLANK, row.getCell(2, HSSFRow.CREATE_NULL_AS_BLANK).getCellType());
assertEquals(HSSFCell.CELL_TYPE_BLANK, row.getCell(3, HSSFRow.CREATE_NULL_AS_BLANK).getCellType());
assertEquals(HSSFCell.CELL_TYPE_BLANK, row.getCell(4, HSSFRow.CREATE_NULL_AS_BLANK).getCellType());
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, row.getCell(5, HSSFRow.CREATE_NULL_AS_BLANK).getCellType());
// Check created ones get the right column
assertEquals((short)0, row.getCell(0, HSSFRow.CREATE_NULL_AS_BLANK).getCellNum());
assertEquals((short)1, row.getCell(1, HSSFRow.CREATE_NULL_AS_BLANK).getCellNum());
assertEquals((short)2, row.getCell(2, HSSFRow.CREATE_NULL_AS_BLANK).getCellNum());
assertEquals((short)3, row.getCell(3, HSSFRow.CREATE_NULL_AS_BLANK).getCellNum());
assertEquals((short)4, row.getCell(4, HSSFRow.CREATE_NULL_AS_BLANK).getCellNum());
assertEquals((short)5, row.getCell(5, HSSFRow.CREATE_NULL_AS_BLANK).getCellNum());
}
}

View File

@ -130,7 +130,7 @@ public final class TestPOIFSFileSystem extends TestCase {
* The other is to fix the handling of the last block in
* POIFS, since it seems to be slight wrong
*/
public void DISABLEDtestShortLastBlock() throws Exception {
public void testShortLastBlock() throws Exception {
String[] files = new String[] {
"ShortLastBlock.qwp", "ShortLastBlock.wps"
};