aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNick Burch <nick@apache.org>2008-03-29 16:41:25 +0000
committerNick Burch <nick@apache.org>2008-03-29 16:41:25 +0000
commit1684f36a8f87471be7cab1a045e7bda9f0bee427 (patch)
treee8f301b355a0bf57f0250146b70a543a81d90fb5 /src
parent4bdf3c6de2563256b6ba072eb5ba71310d269b5f (diff)
downloadpoi-1684f36a8f87471be7cab1a045e7bda9f0bee427.tar.gz
poi-1684f36a8f87471be7cab1a045e7bda9f0bee427.zip
Merge changes from trunk to the ooxml branch - revisions 634630 to
638000 git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@642554 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r--src/documentation/content/xdocs/changes.xml6
-rw-r--r--src/documentation/content/xdocs/status.xml6
-rw-r--r--src/java/org/apache/poi/hssf/model/FormulaParser.java39
-rw-r--r--src/java/org/apache/poi/hssf/model/TextboxShape.java4
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/AttrPtg.java93
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFCell.java43
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFTextbox.java58
-rw-r--r--src/java/org/apache/poi/hssf/util/HSSFCellRangeAddress.java20
-rw-r--r--src/java/org/apache/poi/poifs/common/POIFSConstants.java4
-rw-r--r--src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java2
-rw-r--r--src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java26
-rw-r--r--src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java63
-rw-r--r--src/java/org/apache/poi/poifs/storage/RawDataBlockList.java5
-rwxr-xr-xsrc/scratchpad/src/org/apache/poi/hssf/record/formula/eval/PercentEval.java71
-rw-r--r--src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java76
-rwxr-xr-xsrc/scratchpad/src/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java165
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java14
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java7
-rwxr-xr-xsrc/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java2
-rwxr-xr-xsrc/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java217
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java261
-rwxr-xr-xsrc/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java82
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hwpf/data/Bug28627.docbin0 -> 19968 bytes
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java62
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/data/27349-vlookupAcrossSheets.xlsbin0 -> 13824 bytes
-rw-r--r--src/testcases/org/apache/poi/hssf/data/Bug44593.xlsbin0 -> 2586112 bytes
-rw-r--r--src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xlsbin136704 -> 136704 bytes
-rw-r--r--src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java44
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java41
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java23
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/usermodel/TestHSSFTextbox.java52
-rw-r--r--src/testcases/org/apache/poi/poifs/property/TestPropertyTable.java3
-rw-r--r--src/testcases/org/apache/poi/poifs/storage/LocalRawDataBlockList.java4
-rw-r--r--src/testcases/org/apache/poi/poifs/storage/TestRawDataBlockList.java7
-rw-r--r--src/testcases/org/apache/poi/poifs/storage/TestSmallBlockTableReader.java3
35 files changed, 1167 insertions, 336 deletions
diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml
index fdead9b9b5..4bfd32b0e6 100644
--- a/src/documentation/content/xdocs/changes.xml
+++ b/src/documentation/content/xdocs/changes.xml
@@ -36,6 +36,12 @@
<!-- Don't forget to update status.xml too! -->
<release version="3.1-beta1" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="fix">44609 - Handle leading spaces in formulas, such as '= 4'</action>
+ <action dev="POI-DEVELOPERS" type="add">44608 - Support for PercentPtg in the formula evaluator</action>
+ <action dev="POI-DEVELOPERS" type="fix">44606 - Support calculated string values for evaluated formulas</action>
+ <action dev="POI-DEVELOPERS" type="add">Add accessors to horizontal and vertical alignment in HSSFTextbox</action>
+ <action dev="POI-DEVELOPERS" type="add">44593 - Improved handling of short DVRecords</action>
+ <action dev="POI-DEVELOPERS" type="add">28627 / 44580 - Fix Range.delete() in HWPF</action>
<action dev="POI-DEVELOPERS" type="add">44539 - Support for area references in formulas of rows >= 32768</action>
<action dev="POI-DEVELOPERS" type="add">44536 - Improved support for detecting read-only recommended files</action>
<action dev="POI-DEVELOPERS" type="fix">43901 - Correctly update the internal last cell number when adding and removing cells (previously sometimes off-by-one)</action>
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml
index c59cae1a3d..a6467d5164 100644
--- a/src/documentation/content/xdocs/status.xml
+++ b/src/documentation/content/xdocs/status.xml
@@ -33,6 +33,12 @@
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.1-beta1" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="fix">44609 - Handle leading spaces in formulas, such as '= 4'</action>
+ <action dev="POI-DEVELOPERS" type="add">44608 - Support for PercentPtg in the formula evaluator</action>
+ <action dev="POI-DEVELOPERS" type="fix">44606 - Support calculated string values for evaluated formulas</action>
+ <action dev="POI-DEVELOPERS" type="add">Add accessors to horizontal and vertical alignment in HSSFTextbox</action>
+ <action dev="POI-DEVELOPERS" type="add">44593 - Improved handling of short DVRecords</action>
+ <action dev="POI-DEVELOPERS" type="add">28627 / 44580 - Fix Range.delete() in HWPF</action>
<action dev="POI-DEVELOPERS" type="add">44539 - Support for area references in formulas of rows >= 32768</action>
<action dev="POI-DEVELOPERS" type="add">44536 - Improved support for detecting read-only recommended files</action>
<action dev="POI-DEVELOPERS" type="fix">43901 - Correctly update the internal last cell number when adding and removing cells (previously sometimes off-by-one)</action>
diff --git a/src/java/org/apache/poi/hssf/model/FormulaParser.java b/src/java/org/apache/poi/hssf/model/FormulaParser.java
index 7b89b90d81..07bb51483c 100644
--- a/src/java/org/apache/poi/hssf/model/FormulaParser.java
+++ b/src/java/org/apache/poi/hssf/model/FormulaParser.java
@@ -943,23 +943,7 @@ end;
}
Stack stack = new Stack();
- // Excel allows to have AttrPtg at position 0 (such as Blanks) which
- // do not have any operands. Skip them.
- int i;
- if(ptgs[0] instanceof AttrPtg) {
- AttrPtg attrPtg0 = (AttrPtg) ptgs[0];
- if(attrPtg0.isSemiVolatile()) {
- // no visible formula for semi-volatile
- } else {
- // TODO -this requirement is unclear and is not addressed by any junits
- stack.push(ptgs[0].toFormulaString(book));
- }
- i=1;
- } else {
- i=0;
- }
-
- for ( ; i < ptgs.length; i++) {
+ for (int i=0 ; i < ptgs.length; i++) {
Ptg ptg = ptgs[i];
// TODO - what about MemNoMemPtg?
if(ptg instanceof MemAreaPtg || ptg instanceof MemFuncPtg || ptg instanceof MemErrPtg) {
@@ -973,21 +957,30 @@ end;
continue;
}
- if (ptg instanceof AttrPtg && ((AttrPtg) ptg).isOptimizedIf()) {
- continue;
+ if (ptg instanceof AttrPtg) {
+ AttrPtg attrPtg = ((AttrPtg) ptg);
+ if (attrPtg.isOptimizedIf()) {
+ continue;
+ }
+ if (attrPtg.isSpace()) {
+ // POI currently doesn't render spaces in formulas
+ continue;
+ // but if it ever did, care must be taken:
+ // tAttrSpace comes *before* the operand it applies to, which may be consistent
+ // with how the formula text appears but is against the RPN ordering assumed here
+ }
}
final OperationPtg o = (OperationPtg) ptg;
int nOperands = o.getNumberOfOperands();
final String[] operands = new String[nOperands];
- for (int j = nOperands-1; j >= 0; j--) {
+ for (int j = nOperands-1; j >= 0; j--) { // reverse iteration because args were pushed in-order
if(stack.isEmpty()) {
- //TODO: write junit to prove this works
String msg = "Too few arguments suppled to operation token ("
+ o.getClass().getName() + "). Expected (" + nOperands
- + " but got " + (nOperands - j + 1);
- throw new FormulaParseException(msg);
+ + ") operands but got (" + (nOperands - j + 1) + ")";
+ throw new IllegalStateException(msg);
}
operands[j] = (String) stack.pop();
}
diff --git a/src/java/org/apache/poi/hssf/model/TextboxShape.java b/src/java/org/apache/poi/hssf/model/TextboxShape.java
index 4b10278091..e55fcacbc3 100644
--- a/src/java/org/apache/poi/hssf/model/TextboxShape.java
+++ b/src/java/org/apache/poi/hssf/model/TextboxShape.java
@@ -133,8 +133,8 @@ public class TextboxShape
HSSFTextbox shape = hssfShape;
TextObjectRecord obj = new TextObjectRecord();
- obj.setHorizontalTextAlignment( TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED );
- obj.setVerticalTextAlignment( TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_TOP );
+ obj.setHorizontalTextAlignment( hssfShape.getHorizontalAlignment() );
+ obj.setVerticalTextAlignment( hssfShape.getVerticalAlignment());
obj.setTextLocked( true );
obj.setTextOrientation( TextObjectRecord.TEXT_ORIENTATION_NONE );
int frLength = ( shape.getString().numFormattingRuns() + 1 ) * 8;
diff --git a/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java b/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java
index 2ba4723804..d355fbfa1f 100644
--- a/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java
@@ -33,20 +33,42 @@ import org.apache.poi.util.BitFieldFactory;
* @author Jason Height (jheight at chariot dot net dot au)
*/
-public class AttrPtg
- extends OperationPtg
-{
+public final class AttrPtg extends OperationPtg {
public final static byte sid = 0x19;
private final static int SIZE = 4;
private byte field_1_options;
private short field_2_data;
- private BitField semiVolatile = BitFieldFactory.getInstance(0x01);
- private BitField optiIf = BitFieldFactory.getInstance(0x02);
- private BitField optiChoose = BitFieldFactory.getInstance(0x04);
- private BitField optGoto = BitFieldFactory.getInstance(0x08);
- private BitField sum = BitFieldFactory.getInstance(0x10);
- private BitField baxcel = BitFieldFactory.getInstance(0x20);
- private BitField space = BitFieldFactory.getInstance(0x40);
+
+ // 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);
+ private static final BitField optiIf = BitFieldFactory.getInstance(0x02);
+ private static final BitField optiChoose = BitFieldFactory.getInstance(0x04);
+ private static final BitField optGoto = BitFieldFactory.getInstance(0x08); // skip
+ private static final BitField sum = BitFieldFactory.getInstance(0x10);
+ private static final BitField baxcel = BitFieldFactory.getInstance(0x20); // 'assignment-style formula in a macro sheet'
+ private static final BitField space = BitFieldFactory.getInstance(0x40);
+
+ public static final class SpaceType {
+ private SpaceType() {
+ // no instances of this class
+ }
+
+ /** 00H = Spaces before the next token (not allowed before tParen token) */
+ public static final int SPACE_BEFORE = 0x00;
+ /** 01H = Carriage returns before the next token (not allowed before tParen token) */
+ public static final int CR_BEFORE = 0x01;
+ /** 02H = Spaces before opening parenthesis (only allowed before tParen token) */
+ public static final int SPACE_BEFORE_OPEN_PAREN = 0x02;
+ /** 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;
+ /** 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) */
+ public static final int SPACE_AFTER_EQUALITY = 0x06;
+ }
public AttrPtg() {
}
@@ -56,6 +78,19 @@ public class AttrPtg
field_1_options = in.readByte();
field_2_data = in.readShort();
}
+ private AttrPtg(int options, int data) {
+ field_1_options = (byte) options;
+ field_2_data = (short) data;
+ }
+
+ /**
+ * @param type a constant from <tt>SpaceType</tt>
+ * @param count the number of space characters
+ */
+ public static AttrPtg createSpace(int type, int count) {
+ int data = type & 0x00FF | (count << 8) & 0x00FFFF;
+ return new AttrPtg(space.set(0), data);
+ }
public void setOptions(byte options)
{
@@ -131,21 +166,31 @@ public class AttrPtg
return field_2_data;
}
- public String toString()
- {
- StringBuffer buffer = new StringBuffer();
+ public String toString() {
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(getClass().getName()).append(" [");
- buffer.append("AttrPtg\n");
- buffer.append("options=").append(field_1_options).append("\n");
- buffer.append("data =").append(field_2_data).append("\n");
- buffer.append("semi =").append(isSemiVolatile()).append("\n");
- buffer.append("optimif=").append(isOptimizedIf()).append("\n");
- buffer.append("optchos=").append(isOptimizedChoose()).append("\n");
- buffer.append("isGoto =").append(isGoto()).append("\n");
- buffer.append("isSum =").append(isSum()).append("\n");
- buffer.append("isBaxce=").append(isBaxcel()).append("\n");
- buffer.append("isSpace=").append(isSpace()).append("\n");
- return buffer.toString();
+ if(isSemiVolatile()) {
+ sb.append("volatile ");
+ }
+ if(isSpace()) {
+ sb.append("space count=").append((field_2_data >> 8) & 0x00FF);
+ sb.append(" type=").append(field_2_data & 0x00FF).append(" ");
+ }
+ // the rest seem to be mutually exclusive
+ if(isOptimizedIf()) {
+ sb.append("if dist=").append(getData());
+ } else if(isOptimizedChoose()) {
+ sb.append("choose dist=").append(getData());
+ } else if(isGoto()) {
+ sb.append("skip dist=").append(getData());
+ } else if(isSum()) {
+ sb.append("sum ");
+ } else if(isBaxcel()) {
+ sb.append("assign ");
+ }
+ sb.append("]");
+ return sb.toString();
}
public void writeBytes(byte [] array, int offset)
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
index ae8a8253e6..ededf0d648 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
@@ -603,29 +603,30 @@ public class HSSFCell implements Cell
if (hvalue == null)
{
setCellType(CELL_TYPE_BLANK, false, row, col, styleIndex);
+ return;
}
- else
- {
- if ((cellType != CELL_TYPE_STRING ) && ( cellType != CELL_TYPE_FORMULA))
- {
- setCellType(CELL_TYPE_STRING, false, row, col, styleIndex);
- }
- int index = 0;
-
- UnicodeString str = hvalue.getUnicodeString();
-// jmh if (encoding == ENCODING_COMPRESSED_UNICODE)
-// jmh {
-// jmh str.setCompressedUnicode();
-// jmh } else if (encoding == ENCODING_UTF_16)
-// jmh {
-// jmh str.setUncompressedUnicode();
-// jmh }
- index = book.addSSTString(str);
- (( LabelSSTRecord ) record).setSSTIndex(index);
- stringValue = hvalue;
- stringValue.setWorkbookReferences(book, (( LabelSSTRecord ) record));
- stringValue.setUnicodeString(book.getSSTString(index));
+ if (cellType == CELL_TYPE_FORMULA) {
+ // Set the 'pre-evaluated result' for the formula
+ // note - formulas do not preserve text formatting.
+ FormulaRecordAggregate fr = (FormulaRecordAggregate) record;
+ // must make new sr because fr.getStringRecord() may be null
+ StringRecord sr = new StringRecord();
+ sr.setString(hvalue.getString()); // looses format
+ fr.setStringRecord(sr);
+ return;
+ }
+
+ if (cellType != CELL_TYPE_STRING) {
+ setCellType(CELL_TYPE_STRING, false, row, col, styleIndex);
}
+ int index = 0;
+
+ UnicodeString str = hvalue.getUnicodeString();
+ index = book.addSSTString(str);
+ (( LabelSSTRecord ) record).setSSTIndex(index);
+ stringValue = hvalue;
+ stringValue.setWorkbookReferences(book, (( LabelSSTRecord ) record));
+ stringValue.setUnicodeString(book.getSSTString(index));
}
public void setCellFormula(String formula) {
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFTextbox.java b/src/java/org/apache/poi/hssf/usermodel/HSSFTextbox.java
index ac86b2d8dd..48816131a4 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFTextbox.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFTextbox.java
@@ -19,6 +19,9 @@ package org.apache.poi.hssf.usermodel;
import org.apache.poi.ss.usermodel.RichTextString;
+import org.apache.poi.util.BitField;
+import org.apache.poi.util.BitFieldFactory;
+
/**
* A textbox is a shape that may hold a rich text string.
*
@@ -29,7 +32,27 @@ public class HSSFTextbox
{
public final static short OBJECT_TYPE_TEXT = 6;
+ /**
+ * How to align text horizontally
+ */
+ public final static short HORIZONTAL_ALIGNMENT_LEFT = 1;
+ public final static short HORIZONTAL_ALIGNMENT_CENTERED = 2;
+ public final static short HORIZONTAL_ALIGNMENT_RIGHT = 3;
+ public final static short HORIZONTAL_ALIGNMENT_JUSTIFIED = 4;
+ public final static short HORIZONTAL_ALIGNMENT_DISTRIBUTED = 7;
+
+ /**
+ * How to align text vertically
+ */
+ public final static short VERTICAL_ALIGNMENT_TOP = 1;
+ public final static short VERTICAL_ALIGNMENT_CENTER = 2;
+ public final static short VERTICAL_ALIGNMENT_BOTTOM = 3;
+ public final static short VERTICAL_ALIGNMENT_JUSTIFY = 4;
+ public final static short VERTICAL_ALIGNMENT_DISTRIBUTED= 7;
+
+
int marginLeft, marginRight, marginTop, marginBottom;
+ short halign, valign;
HSSFRichTextString string = new HSSFRichTextString("");
@@ -42,6 +65,9 @@ public class HSSFTextbox
{
super( parent, anchor );
setShapeType(OBJECT_TYPE_TEXT);
+
+ halign = HORIZONTAL_ALIGNMENT_LEFT;
+ valign = VERTICAL_ALIGNMENT_TOP;
}
/**
@@ -123,4 +149,36 @@ public class HSSFTextbox
{
this.marginBottom = marginBottom;
}
+
+ /**
+ * Gets the horizontal alignment.
+ */
+ public short getHorizontalAlignment()
+ {
+ return halign;
+ }
+
+ /**
+ * Sets the horizontal alignment.
+ */
+ public void setHorizontalAlignment( short align )
+ {
+ this.halign = align;
+ }
+
+ /**
+ * Gets the vertical alignment.
+ */
+ public short getVerticalAlignment()
+ {
+ return valign;
+ }
+
+ /**
+ * Sets the vertical alignment.
+ */
+ public void setVerticalAlignment( short align )
+ {
+ this.valign = align;
+ }
}
diff --git a/src/java/org/apache/poi/hssf/util/HSSFCellRangeAddress.java b/src/java/org/apache/poi/hssf/util/HSSFCellRangeAddress.java
index 438f5e5968..73804966fb 100644
--- a/src/java/org/apache/poi/hssf/util/HSSFCellRangeAddress.java
+++ b/src/java/org/apache/poi/hssf/util/HSSFCellRangeAddress.java
@@ -18,6 +18,9 @@ package org.apache.poi.hssf.util;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
import java.util.ArrayList;
/**
@@ -38,6 +41,8 @@ import java.util.ArrayList;
public class HSSFCellRangeAddress
{
+ private static POILogger logger = POILogFactory.getLogger(HSSFCellRangeAddress.class);
+
/**
* Number of following ADDR structures
*/
@@ -74,8 +79,19 @@ public class HSSFCellRangeAddress
{
short first_row = in.readShort();
short first_col = in.readShort();
- short last_row = in.readShort();
- short last_col = in.readShort();
+
+ short last_row = first_row;
+ short last_col = first_col;
+ if(in.remaining() >= 4) {
+ last_row = in.readShort();
+ last_col = in.readShort();
+ } else {
+ // Ran out of data
+ // For now, issue a warning, finish, and
+ // hope for the best....
+ logger.log(POILogger.WARN, "Ran out of data reading cell references for DVRecord");
+ k = this.field_addr_number;
+ }
AddrStructure region = new AddrStructure(first_row, first_col, last_row, last_col);
this.field_regions_list.add(region);
diff --git a/src/java/org/apache/poi/poifs/common/POIFSConstants.java b/src/java/org/apache/poi/poifs/common/POIFSConstants.java
index 399f52be4b..ff2050274d 100644
--- a/src/java/org/apache/poi/poifs/common/POIFSConstants.java
+++ b/src/java/org/apache/poi/poifs/common/POIFSConstants.java
@@ -27,7 +27,11 @@ package org.apache.poi.poifs.common;
public interface POIFSConstants
{
+ /** Most files use 512 bytes as their big block size */
public static final int BIG_BLOCK_SIZE = 0x0200;
+ /** Some use 4096 bytes */
+ public static final int LARGER_BIG_BLOCK_SIZE = 0x1000;
+
public static final int END_OF_CHAIN = -2;
public static final int PROPERTY_SIZE = 0x0080;
public static final int UNUSED_BLOCK = -1;
diff --git a/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java b/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java
index fe94b4aaf9..73911e6b0e 100644
--- a/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java
+++ b/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java
@@ -78,7 +78,7 @@ public class POIFSReader
HeaderBlockReader header_block_reader = new HeaderBlockReader(stream);
// read the rest of the stream into blocks
- RawDataBlockList data_blocks = new RawDataBlockList(stream);
+ RawDataBlockList data_blocks = new RawDataBlockList(stream, header_block_reader.getBigBlockSize());
// set up the block allocation table (necessary for the
// data_blocks to be manageable
diff --git a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
index ef9acfe60b..61774dc676 100644
--- a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
+++ b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
@@ -33,6 +33,7 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.dev.POIFSViewable;
import org.apache.poi.poifs.property.DirectoryProperty;
import org.apache.poi.poifs.property.Property;
@@ -63,7 +64,6 @@ public class POIFSFileSystem
{
private static final Log _logger = LogFactory.getLog(POIFSFileSystem.class);
-
private static final class CloseIgnoringInputStream extends InputStream {
private final InputStream _is;
@@ -91,11 +91,16 @@ public class POIFSFileSystem
private PropertyTable _property_table;
private List _documents;
private DirectoryNode _root;
+
+ /**
+ * What big block size the file uses. Most files
+ * use 512 bytes, but a few use 4096
+ */
+ private int bigBlockSize = POIFSConstants.BIG_BLOCK_SIZE;
/**
* Constructor, intended for writing
*/
-
public POIFSFileSystem()
{
_property_table = new PropertyTable();
@@ -138,13 +143,15 @@ public class POIFSFileSystem
this();
boolean success = false;
- // read the header block from the stream
HeaderBlockReader header_block_reader;
- // read the rest of the stream into blocks
RawDataBlockList data_blocks;
try {
+ // read the header block from the stream
header_block_reader = new HeaderBlockReader(stream);
- data_blocks = new RawDataBlockList(stream);
+ bigBlockSize = header_block_reader.getBigBlockSize();
+
+ // read the rest of the stream into blocks
+ data_blocks = new RawDataBlockList(stream, bigBlockSize);
success = true;
} finally {
closeInputStream(stream, success);
@@ -307,7 +314,7 @@ public class POIFSFileSystem
// create a list of BATManaged objects: the documents plus the
// property table and the small block table
- List bm_objects = new ArrayList();
+ List bm_objects = new ArrayList();
bm_objects.addAll(_documents);
bm_objects.add(_property_table);
@@ -602,6 +609,13 @@ public class POIFSFileSystem
return "POIFS FileSystem";
}
+ /**
+ * @return The Big Block size, normally 512 bytes, sometimes 4096 bytes
+ */
+ public int getBigBlockSize() {
+ return bigBlockSize;
+ }
+
/* ********** END begin implementation of POIFSViewable ********** */
} // end public class POIFSFileSystem
diff --git a/src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java b/src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java
index 0d5bb817b4..b001b81058 100644
--- a/src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java
+++ b/src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java
@@ -21,8 +21,6 @@ package org.apache.poi.poifs.storage;
import java.io.*;
-import java.util.*;
-
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
import org.apache.poi.util.IOUtils;
@@ -30,7 +28,6 @@ import org.apache.poi.util.IntegerField;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LongField;
-import org.apache.poi.util.ShortField;
/**
* The block containing the archive header
@@ -41,6 +38,11 @@ import org.apache.poi.util.ShortField;
public class HeaderBlockReader
implements HeaderBlockConstants
{
+ /**
+ * What big block size the file uses. Most files
+ * use 512 bytes, but a few use 4096
+ */
+ private int bigBlockSize = POIFSConstants.BIG_BLOCK_SIZE;
// number of big block allocation table blocks (int)
private IntegerField _bat_count;
@@ -69,20 +71,27 @@ public class HeaderBlockReader
public HeaderBlockReader(final InputStream stream)
throws IOException
{
- _data = new byte[ POIFSConstants.BIG_BLOCK_SIZE ];
- int byte_count = IOUtils.readFully(stream, _data);
-
- if (byte_count != POIFSConstants.BIG_BLOCK_SIZE)
- {
- if (byte_count == -1)
- //Cant have -1 bytes read in the error message!
- byte_count = 0;
- String type = " byte" + ((byte_count == 1) ? ("")
- : ("s"));
-
- throw new IOException("Unable to read entire header; "
- + byte_count + type + " read; expected "
- + POIFSConstants.BIG_BLOCK_SIZE + " bytes");
+ // At this point, we don't know how big our
+ // block sizes are
+ // So, read the first 32 bytes to check, then
+ // read the rest of the block
+ byte[] blockStart = new byte[32];
+ int bsCount = IOUtils.readFully(stream, blockStart);
+ if(bsCount != 32) {
+ alertShortRead(bsCount);
+ }
+
+ // Figure out our block size
+ if(blockStart[30] == 12) {
+ bigBlockSize = POIFSConstants.LARGER_BIG_BLOCK_SIZE;
+ }
+ _data = new byte[ bigBlockSize ];
+ System.arraycopy(blockStart, 0, _data, 0, blockStart.length);
+
+ // Now we can read the rest of our header
+ int byte_count = IOUtils.readFully(stream, _data, blockStart.length, _data.length - blockStart.length);
+ if (byte_count+bsCount != bigBlockSize) {
+ alertShortRead(byte_count);
}
// verify signature
@@ -110,13 +119,24 @@ public class HeaderBlockReader
_xbat_start = new IntegerField(_xbat_start_offset, _data);
_xbat_count = new IntegerField(_xbat_count_offset, _data);
}
+
+ private void alertShortRead(int read) throws IOException {
+ if (read == -1)
+ //Cant have -1 bytes read in the error message!
+ read = 0;
+ String type = " byte" + ((read == 1) ? ("")
+ : ("s"));
+
+ throw new IOException("Unable to read entire header; "
+ + read + type + " read; expected "
+ + bigBlockSize + " bytes");
+ }
/**
* get start of Property Table
*
* @return the index of the first block of the Property Table
*/
-
public int getPropertyStart()
{
return _property_start.get();
@@ -174,5 +194,12 @@ public class HeaderBlockReader
{
return _xbat_start.get();
}
+
+ /**
+ * @return The Big Block size, normally 512 bytes, sometimes 4096 bytes
+ */
+ public int getBigBlockSize() {
+ return bigBlockSize;
+ }
} // end public class HeaderBlockReader
diff --git a/src/java/org/apache/poi/poifs/storage/RawDataBlockList.java b/src/java/org/apache/poi/poifs/storage/RawDataBlockList.java
index eed318fb55..76ab219562 100644
--- a/src/java/org/apache/poi/poifs/storage/RawDataBlockList.java
+++ b/src/java/org/apache/poi/poifs/storage/RawDataBlockList.java
@@ -37,19 +37,20 @@ public class RawDataBlockList
* Constructor RawDataBlockList
*
* @param stream the InputStream from which the data will be read
+ * @param bigBlockSize The big block size, either 512 bytes or 4096 bytes
*
* @exception IOException on I/O errors, and if an incomplete
* block is read
*/
- public RawDataBlockList(final InputStream stream)
+ public RawDataBlockList(final InputStream stream, int bigBlockSize)
throws IOException
{
List blocks = new ArrayList();
while (true)
{
- RawDataBlock block = new RawDataBlock(stream);
+ RawDataBlock block = new RawDataBlock(stream, bigBlockSize);
if (block.eof())
{
diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/PercentEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/PercentEval.java
new file mode 100755
index 0000000000..c698a4e502
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/PercentEval.java
@@ -0,0 +1,71 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record.formula.eval;
+
+import org.apache.poi.hssf.record.formula.PercentPtg;
+import org.apache.poi.hssf.record.formula.Ptg;
+
+/**
+ * Implementation of Excel formula token '%'. <p/>
+ * @author Josh Micich
+ */
+public final class PercentEval extends NumericOperationEval {
+
+ private PercentPtg _delegate;
+
+ private static final ValueEvalToNumericXlator NUM_XLATOR = new ValueEvalToNumericXlator(
+ (short) (ValueEvalToNumericXlator.BOOL_IS_PARSED
+ | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
+ | ValueEvalToNumericXlator.STRING_IS_PARSED | ValueEvalToNumericXlator.REF_STRING_IS_PARSED));
+
+ public PercentEval(Ptg ptg) {
+ _delegate = (PercentPtg) ptg;
+ }
+
+ protected ValueEvalToNumericXlator getXlator() {
+ return NUM_XLATOR;
+ }
+
+ public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
+ if (args.length != 1) {
+ return ErrorEval.VALUE_INVALID;
+ }
+
+ ValueEval ve = singleOperandEvaluate(args[0], srcRow, srcCol);
+ if (ve instanceof NumericValueEval) {
+ double d0 = ((NumericValueEval) ve).getNumberValue();
+ return new NumberEval(d0 / 100);
+ }
+
+ if (ve instanceof BlankEval) {
+ return NumberEval.ZERO;
+ }
+ if (ve instanceof ErrorEval) {
+ return ve;
+ }
+ return ErrorEval.VALUE_INVALID;
+ }
+
+ public int getNumberOfOperands() {
+ return _delegate.getNumberOfOperands();
+ }
+
+ public int getType() {
+ return _delegate.getType();
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
index 3fce306557..58ab5b47ae 100644
--- a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
+++ b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
@@ -24,71 +24,40 @@ import java.util.Stack;
import org.apache.poi.hssf.model.FormulaParser;
import org.apache.poi.hssf.model.Workbook;
-import org.apache.poi.hssf.record.formula.AddPtg;
import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.BoolPtg;
-import org.apache.poi.hssf.record.formula.ConcatPtg;
import org.apache.poi.hssf.record.formula.ControlPtg;
-import org.apache.poi.hssf.record.formula.DividePtg;
-import org.apache.poi.hssf.record.formula.EqualPtg;
-import org.apache.poi.hssf.record.formula.FuncPtg;
-import org.apache.poi.hssf.record.formula.FuncVarPtg;
-import org.apache.poi.hssf.record.formula.GreaterEqualPtg;
-import org.apache.poi.hssf.record.formula.GreaterThanPtg;
import org.apache.poi.hssf.record.formula.IntPtg;
-import org.apache.poi.hssf.record.formula.LessEqualPtg;
-import org.apache.poi.hssf.record.formula.LessThanPtg;
import org.apache.poi.hssf.record.formula.MemErrPtg;
import org.apache.poi.hssf.record.formula.MissingArgPtg;
-import org.apache.poi.hssf.record.formula.MultiplyPtg;
import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.NameXPtg;
-import org.apache.poi.hssf.record.formula.NotEqualPtg;
import org.apache.poi.hssf.record.formula.NumberPtg;
import org.apache.poi.hssf.record.formula.OperationPtg;
import org.apache.poi.hssf.record.formula.ParenthesisPtg;
-import org.apache.poi.hssf.record.formula.PowerPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.ReferencePtg;
import org.apache.poi.hssf.record.formula.StringPtg;
-import org.apache.poi.hssf.record.formula.SubtractPtg;
-import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
-import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.record.formula.UnknownPtg;
-import org.apache.poi.hssf.record.formula.eval.AddEval;
import org.apache.poi.hssf.record.formula.eval.Area2DEval;
import org.apache.poi.hssf.record.formula.eval.Area3DEval;
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.BlankEval;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
-import org.apache.poi.hssf.record.formula.eval.ConcatEval;
-import org.apache.poi.hssf.record.formula.eval.DivideEval;
-import org.apache.poi.hssf.record.formula.eval.EqualEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.FuncVarEval;
import org.apache.poi.hssf.record.formula.eval.FunctionEval;
-import org.apache.poi.hssf.record.formula.eval.GreaterEqualEval;
-import org.apache.poi.hssf.record.formula.eval.GreaterThanEval;
-import org.apache.poi.hssf.record.formula.eval.LessEqualEval;
-import org.apache.poi.hssf.record.formula.eval.LessThanEval;
-import org.apache.poi.hssf.record.formula.eval.MultiplyEval;
import org.apache.poi.hssf.record.formula.eval.NameEval;
-import org.apache.poi.hssf.record.formula.eval.NotEqualEval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.OperationEval;
-import org.apache.poi.hssf.record.formula.eval.PowerEval;
import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
import org.apache.poi.hssf.record.formula.eval.Ref3DEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.SubtractEval;
-import org.apache.poi.hssf.record.formula.eval.UnaryMinusEval;
-import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
@@ -98,8 +67,6 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
public class HSSFFormulaEvaluator {
// params to lookup the right constructor using reflection
- private static final Class[] OPERATION_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
-
private static final Class[] VALUE_CONTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
private static final Class[] AREA3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval[].class };
@@ -111,8 +78,6 @@ public class HSSFFormulaEvaluator {
// Maps for mapping *Eval to *Ptg
private static final Map VALUE_EVALS_MAP = new HashMap();
- private static final Map OPERATION_EVALS_MAP = new HashMap();
-
/*
* Following is the mapping between the Ptg tokens returned
* by the FormulaParser and the *Eval classes that are used
@@ -124,26 +89,6 @@ public class HSSFFormulaEvaluator {
VALUE_EVALS_MAP.put(NumberPtg.class, NumberEval.class);
VALUE_EVALS_MAP.put(StringPtg.class, StringEval.class);
- OPERATION_EVALS_MAP.put(AddPtg.class, AddEval.class);
- OPERATION_EVALS_MAP.put(ConcatPtg.class, ConcatEval.class);
- OPERATION_EVALS_MAP.put(DividePtg.class, DivideEval.class);
- OPERATION_EVALS_MAP.put(EqualPtg.class, EqualEval.class);
- //OPERATION_EVALS_MAP.put(ExpPtg.class, ExpEval.class); // TODO: check
- // this
- OPERATION_EVALS_MAP.put(FuncPtg.class, FuncVarEval.class); // TODO:
- // check this
- OPERATION_EVALS_MAP.put(FuncVarPtg.class, FuncVarEval.class);
- OPERATION_EVALS_MAP.put(GreaterEqualPtg.class, GreaterEqualEval.class);
- OPERATION_EVALS_MAP.put(GreaterThanPtg.class, GreaterThanEval.class);
- OPERATION_EVALS_MAP.put(LessEqualPtg.class, LessEqualEval.class);
- OPERATION_EVALS_MAP.put(LessThanPtg.class, LessThanEval.class);
- OPERATION_EVALS_MAP.put(MultiplyPtg.class, MultiplyEval.class);
- OPERATION_EVALS_MAP.put(NotEqualPtg.class, NotEqualEval.class);
- OPERATION_EVALS_MAP.put(PowerPtg.class, PowerEval.class);
- OPERATION_EVALS_MAP.put(SubtractPtg.class, SubtractEval.class);
- OPERATION_EVALS_MAP.put(UnaryMinusPtg.class, UnaryMinusEval.class);
- OPERATION_EVALS_MAP.put(UnaryPlusPtg.class, UnaryPlusEval.class);
-
}
@@ -402,7 +347,7 @@ public class HSSFFormulaEvaluator {
if (optg instanceof AttrPtg) { continue; }
if (optg instanceof UnionPtg) { continue; }
- OperationEval operation = (OperationEval) getOperationEvalForPtg(optg);
+ OperationEval operation = OperationEvaluatorFactory.create(optg);
int numops = operation.getNumberOfOperands();
Eval[] ops = new Eval[numops];
@@ -558,25 +503,6 @@ public class HSSFFormulaEvaluator {
}
/**
- * returns the OperationEval concrete impl instance corresponding
- * to the suplied operationPtg
- * @param ptg
- */
- protected static Eval getOperationEvalForPtg(OperationPtg ptg) {
- Eval retval = null;
-
- Class clazz = (Class) OPERATION_EVALS_MAP.get(ptg.getClass());
- try {
- Constructor constructor = clazz.getConstructor(OPERATION_CONSTRUCTOR_CLASS_ARRAY);
- retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
- }
- catch (Exception e) {
- throw new RuntimeException("Fatal Error: ", e);
- }
- return retval;
- }
-
- /**
* returns an appropriate Eval impl instance for the Ptg. The Ptg must be
* one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg,
* StringPtg, BoolPtg <br/>special Note: OperationPtg subtypes cannot be
diff --git a/src/scratchpad/src/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java b/src/scratchpad/src/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java
new file mode 100755
index 0000000000..1292009699
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java
@@ -0,0 +1,165 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.usermodel;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hssf.record.formula.AddPtg;
+import org.apache.poi.hssf.record.formula.ConcatPtg;
+import org.apache.poi.hssf.record.formula.DividePtg;
+import org.apache.poi.hssf.record.formula.EqualPtg;
+import org.apache.poi.hssf.record.formula.ExpPtg;
+import org.apache.poi.hssf.record.formula.FuncPtg;
+import org.apache.poi.hssf.record.formula.FuncVarPtg;
+import org.apache.poi.hssf.record.formula.GreaterEqualPtg;
+import org.apache.poi.hssf.record.formula.GreaterThanPtg;
+import org.apache.poi.hssf.record.formula.LessEqualPtg;
+import org.apache.poi.hssf.record.formula.LessThanPtg;
+import org.apache.poi.hssf.record.formula.MultiplyPtg;
+import org.apache.poi.hssf.record.formula.NotEqualPtg;
+import org.apache.poi.hssf.record.formula.OperationPtg;
+import org.apache.poi.hssf.record.formula.PercentPtg;
+import org.apache.poi.hssf.record.formula.PowerPtg;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.formula.SubtractPtg;
+import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
+import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
+import org.apache.poi.hssf.record.formula.eval.AddEval;
+import org.apache.poi.hssf.record.formula.eval.ConcatEval;
+import org.apache.poi.hssf.record.formula.eval.DivideEval;
+import org.apache.poi.hssf.record.formula.eval.EqualEval;
+import org.apache.poi.hssf.record.formula.eval.FuncVarEval;
+import org.apache.poi.hssf.record.formula.eval.GreaterEqualEval;
+import org.apache.poi.hssf.record.formula.eval.GreaterThanEval;
+import org.apache.poi.hssf.record.formula.eval.LessEqualEval;
+import org.apache.poi.hssf.record.formula.eval.LessThanEval;
+import org.apache.poi.hssf.record.formula.eval.MultiplyEval;
+import org.apache.poi.hssf.record.formula.eval.NotEqualEval;
+import org.apache.poi.hssf.record.formula.eval.OperationEval;
+import org.apache.poi.hssf.record.formula.eval.PercentEval;
+import org.apache.poi.hssf.record.formula.eval.PowerEval;
+import org.apache.poi.hssf.record.formula.eval.SubtractEval;
+import org.apache.poi.hssf.record.formula.eval.UnaryMinusEval;
+import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval;
+
+/**
+ * This class creates <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt>
+ * formula tokens.
+ *
+ * @author Josh Micich
+ */
+final class OperationEvaluatorFactory {
+ private static final Class[] OPERATION_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
+
+ private static final Map _constructorsByPtgClass = initialiseConstructorsMap();
+
+ private OperationEvaluatorFactory() {
+ // no instances of this class
+ }
+
+ private static Map initialiseConstructorsMap() {
+ Map m = new HashMap(32);
+ add(m, AddPtg.class, AddEval.class);
+ add(m, ConcatPtg.class, ConcatEval.class);
+ add(m, DividePtg.class, DivideEval.class);
+ add(m, EqualPtg.class, EqualEval.class);
+ add(m, FuncPtg.class, FuncVarEval.class);
+ add(m, FuncVarPtg.class, FuncVarEval.class);
+ add(m, GreaterEqualPtg.class, GreaterEqualEval.class);
+ add(m, GreaterThanPtg.class, GreaterThanEval.class);
+ add(m, LessEqualPtg.class, LessEqualEval.class);
+ add(m, LessThanPtg.class, LessThanEval.class);
+ add(m, MultiplyPtg.class, MultiplyEval.class);
+ add(m, NotEqualPtg.class, NotEqualEval.class);
+ add(m, PercentPtg.class, PercentEval.class);
+ add(m, PowerPtg.class, PowerEval.class);
+ add(m, SubtractPtg.class, SubtractEval.class);
+ add(m, UnaryMinusPtg.class, UnaryMinusEval.class);
+ add(m, UnaryPlusPtg.class, UnaryPlusEval.class);
+ return m;
+ }
+
+ private static void add(Map m, Class ptgClass, Class evalClass) {
+
+ // perform some validation now, to keep later exception handlers simple
+ if(!Ptg.class.isAssignableFrom(ptgClass)) {
+ throw new IllegalArgumentException("Expected Ptg subclass");
+ }
+ if(!OperationEval.class.isAssignableFrom(evalClass)) {
+ throw new IllegalArgumentException("Expected OperationEval subclass");
+ }
+ if (!Modifier.isPublic(evalClass.getModifiers())) {
+ throw new RuntimeException("Eval class must be public");
+ }
+ if (Modifier.isAbstract(evalClass.getModifiers())) {
+ throw new RuntimeException("Eval class must not be abstract");
+ }
+
+ Constructor constructor;
+ try {
+ constructor = evalClass.getDeclaredConstructor(OPERATION_CONSTRUCTOR_CLASS_ARRAY);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Missing constructor");
+ }
+ if (!Modifier.isPublic(constructor.getModifiers())) {
+ throw new RuntimeException("Eval constructor must be public");
+ }
+ m.put(ptgClass, constructor);
+ }
+
+ /**
+ * returns the OperationEval concrete impl instance corresponding
+ * to the supplied operationPtg
+ */
+ public static OperationEval create(OperationPtg ptg) {
+ if(ptg == null) {
+ throw new IllegalArgumentException("ptg must not be null");
+ }
+
+ Class ptgClass = ptg.getClass();
+
+ Constructor constructor = (Constructor) _constructorsByPtgClass.get(ptgClass);
+ if(constructor == null) {
+ if(ptgClass == ExpPtg.class) {
+ // ExpPtg is used for array formulas and shared formulas.
+ // it is currently unsupported, and may not even get implemented here
+ throw new RuntimeException("ExpPtg currently not supported");
+ }
+ throw new RuntimeException("Unexpected operation ptg class (" + ptgClass.getName() + ")");
+ }
+
+ Object result;
+ Object[] initargs = { ptg };
+ try {
+ result = constructor.newInstance(initargs);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ return (OperationEval) result;
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java
index 593214b180..67c634d9f6 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java
@@ -90,7 +90,19 @@ public class TextPiece extends PropertyNode implements Comparable
public void adjustForDelete(int start, int length)
{
-
+ int myStart = getStart();
+ int myEnd = getEnd();
+ int end = start + length;
+
+ /* do we have to delete from this text piece? */
+ if (start <= myEnd && end >= myStart) {
+ /* find where the deleted area overlaps with this text piece */
+ int overlapStart = Math.max(myStart, start);
+ int overlapEnd = Math.min(myEnd, end);
+ ((StringBuffer)_buf).delete(overlapStart, overlapEnd);
+
+ super.adjustForDelete(start, length);
+ }
}
public int characterLength()
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
index 60e00f3256..f2d9a615f8 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
@@ -494,6 +494,7 @@ public class Range
int numSections = _sections.size();
int numRuns = _characters.size();
int numParagraphs = _paragraphs.size();
+ int numTextPieces = _text.size();
for (int x = _charStart; x < numRuns; x++)
{
@@ -512,6 +513,12 @@ public class Range
SEPX sepx = (SEPX)_sections.get(x);
sepx.adjustForDelete(_start, _end - _start);
}
+
+ for (int x = _textStart; x < numTextPieces; x++)
+ {
+ TextPiece piece = (TextPiece)_text.get(x);
+ piece.adjustForDelete(_start, _end - _start);
+ }
}
/**
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java
index 3260c371c6..5098c789a7 100755
--- a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java
+++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java
@@ -31,7 +31,9 @@ public class AllFormulaEvalTests {
TestSuite result = new TestSuite("Tests for org.apache.poi.hssf.record.formula.eval");
result.addTestSuite(TestCircularReferences.class);
result.addTestSuite(TestExternalFunction.class);
+ result.addTestSuite(TestFormulaBugs.class);
result.addTestSuite(TestFormulasFromSpreadsheet.class);
+ result.addTestSuite(TestPercentEval.class);
result.addTestSuite(TestUnaryPlusEval.class);
return result;
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java
new file mode 100755
index 0000000000..617f5d0d4e
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java
@@ -0,0 +1,217 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record.formula.eval;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue;
+
+/**
+ * Miscellaneous tests for bugzilla entries.<p/> The test name contains the
+ * bugzilla bug id.
+ *
+ *
+ * @author Josh Micich
+ */
+public final class TestFormulaBugs extends TestCase {
+
+ private static final String TEST_DATA_DIR_SYS_PROPERTY_NAME = "HSSF.testdata.path";
+
+ /**
+ * Opens a sample file from the standard HSSF test data directory
+ *
+ * @return an open <tt>InputStream</tt> for the specified sample file
+ */
+ private static InputStream openSampleFileStream(String sampleFileName) {
+ // TODO - move this method somewhere common
+ String dataDirName = System
+ .getProperty(TEST_DATA_DIR_SYS_PROPERTY_NAME);
+ if (dataDirName == null) {
+ throw new RuntimeException("Must set system property '"
+ + TEST_DATA_DIR_SYS_PROPERTY_NAME
+ + "' before running tests");
+ }
+ File dataDir = new File(dataDirName);
+ if (!dataDir.exists()) {
+ throw new RuntimeException("Data dir '" + dataDirName
+ + "' specified by system property '"
+ + TEST_DATA_DIR_SYS_PROPERTY_NAME + "' does not exist");
+ }
+ File f = new File(dataDir, sampleFileName);
+ if (!f.exists()) {
+ throw new RuntimeException("Sample file '" + sampleFileName
+ + "' not found in data dir '" + dataDirName + "'");
+ }
+ InputStream is;
+ try {
+ is = new FileInputStream(f);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ return is;
+ }
+
+ /**
+ * Bug 27349 - VLOOKUP with reference to another sheet.<p/> This test was
+ * added <em>long</em> after the relevant functionality was fixed.
+ */
+ public void test27349() {
+ // 27349-vlookupAcrossSheets.xls is bugzilla/attachment.cgi?id=10622
+ InputStream is = openSampleFileStream("27349-vlookupAcrossSheets.xls");
+ HSSFWorkbook wb;
+ try {
+ // original bug may have thrown exception here, or output warning to
+ // stderr
+ wb = new HSSFWorkbook(is);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ HSSFSheet sheet = wb.getSheetAt(0);
+ HSSFRow row = sheet.getRow(1);
+ HSSFCell cell = row.getCell(0);
+
+ // this definitely would have failed due to 27349
+ assertEquals("VLOOKUP(1,'DATA TABLE'!$A$8:'DATA TABLE'!$B$10,2)", cell
+ .getCellFormula());
+
+ // We might as well evaluate the formula
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ fe.setCurrentRow(row);
+ CellValue cv = fe.evaluate(cell);
+
+ assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
+ assertEquals(3.0, cv.getNumberValue(), 0.0);
+ }
+
+ /**
+ * Bug 27405 - isnumber() formula always evaluates to false in if statement<p/>
+ *
+ * seems to be a duplicate of 24925
+ */
+ public void test27405() {
+
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.createSheet("input");
+ // input row 0
+ HSSFRow row = sheet.createRow((short) 0);
+ HSSFCell cell = row.createCell((short) 0);
+ cell = row.createCell((short) 1);
+ cell.setCellValue(1); // B1
+ // input row 1
+ row = sheet.createRow((short) 1);
+ cell = row.createCell((short) 1);
+ cell.setCellValue(999); // B2
+
+ int rno = 4;
+ row = sheet.createRow(rno);
+ cell = row.createCell((short) 1); // B5
+ cell.setCellFormula("isnumber(b1)");
+ cell = row.createCell((short) 3); // D5
+ cell.setCellFormula("IF(ISNUMBER(b1),b1,b2)");
+
+ if (false) { // set true to check excel file manually
+ // bug report mentions 'Editing the formula in excel "fixes" the problem.'
+ try {
+ FileOutputStream fileOut = new FileOutputStream("27405output.xls");
+ wb.write(fileOut);
+ fileOut.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // use POI's evaluator as an extra sanity check
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ fe.setCurrentRow(row);
+ CellValue cv;
+ cv = fe.evaluate(cell);
+ assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
+ assertEquals(1.0, cv.getNumberValue(), 0.0);
+
+ cv = fe.evaluate(row.getCell(1));
+ assertEquals(HSSFCell.CELL_TYPE_BOOLEAN, cv.getCellType());
+ assertEquals(true, cv.getBooleanValue());
+ }
+
+ /**
+ * Bug 42448 - Can't parse SUMPRODUCT(A!C7:A!C67, B8:B68) / B69 <p/>
+ */
+ public void test42448() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet1 = wb.createSheet("Sheet1");
+
+ HSSFRow row = sheet1.createRow(0);
+ HSSFCell cell = row.createCell((short) 0);
+
+ // it's important to create the referenced sheet first
+ HSSFSheet sheet2 = wb.createSheet("A"); // note name 'A'
+ // TODO - POI crashes if the formula is added before this sheet
+ // RuntimeException("Zero length string is an invalid sheet name")
+ // Excel doesn't crash but the formula doesn't work until it is
+ // re-entered
+
+ String inputFormula = "SUMPRODUCT(A!C7:A!C67, B8:B68) / B69"; // as per bug report
+ try {
+ cell.setCellFormula(inputFormula);
+ } catch (StringIndexOutOfBoundsException e) {
+ throw new AssertionFailedError("Identified bug 42448");
+ }
+
+ assertEquals("SUMPRODUCT(A!C7:C67,B8:B68)/B69", cell.getCellFormula());
+
+ // might as well evaluate the sucker...
+
+ addCell(sheet2, 5, 2, 3.0); // A!C6
+ addCell(sheet2, 6, 2, 4.0); // A!C7
+ addCell(sheet2, 66, 2, 5.0); // A!C67
+ addCell(sheet2, 67, 2, 6.0); // A!C68
+
+ addCell(sheet1, 6, 1, 7.0); // B7
+ addCell(sheet1, 7, 1, 8.0); // B8
+ addCell(sheet1, 67, 1, 9.0); // B68
+ addCell(sheet1, 68, 1, 10.0); // B69
+
+ double expectedResult = (4.0 * 8.0 + 5.0 * 9.0) / 10.0;
+
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet1, wb);
+ fe.setCurrentRow(row);
+ CellValue cv = fe.evaluate(cell);
+
+ assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
+ assertEquals(expectedResult, cv.getNumberValue(), 0.0);
+ }
+
+ private static void addCell(HSSFSheet sheet, int rowIx, int colIx,
+ double value) {
+ sheet.createRow(rowIx).createCell((short) colIx).setCellValue(value);
+ }
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java
index f57221c9b0..2d5408c76a 100644
--- a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java
+++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-
package org.apache.poi.hssf.record.formula.eval;
import java.io.FileInputStream;
@@ -59,36 +58,36 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
* Name of the test spreadsheet (found in the standard test data folder)
*/
public final static String FILENAME = "FormulaEvalTestData.xls";
- /**
- * Row (zero-based) in the test spreadsheet where the operator examples start.
- */
+ /**
+ * Row (zero-based) in the test spreadsheet where the operator examples start.
+ */
public static final int START_OPERATORS_ROW_INDEX = 22; // Row '23'
- /**
- * Row (zero-based) in the test spreadsheet where the function examples start.
- */
- public static final int START_FUNCTIONS_ROW_INDEX = 83; // Row '84'
+ /**
+ * Row (zero-based) in the test spreadsheet where the function examples start.
+ */
+ public static final int START_FUNCTIONS_ROW_INDEX = 87; // Row '88'
/**
* Index of the column that contains the function names
*/
- public static final short COLUMN_INDEX_FUNCTION_NAME = 1; // Column 'B'
+ public static final short COLUMN_INDEX_FUNCTION_NAME = 1; // Column 'B'
- /**
- * Used to indicate when there are no more functions left
- */
+ /**
+ * Used to indicate when there are no more functions left
+ */
public static final String FUNCTION_NAMES_END_SENTINEL = "<END-OF-FUNCTIONS>";
/**
* Index of the column where the test values start (for each function)
*/
- public static final short COLUMN_INDEX_FIRST_TEST_VALUE = 3; // Column 'D'
-
- /**
- * Each function takes 4 rows in the test spreadsheet
- */
+ public static final short COLUMN_INDEX_FIRST_TEST_VALUE = 3; // Column 'D'
+
+ /**
+ * Each function takes 4 rows in the test spreadsheet
+ */
public static final int NUMBER_OF_ROWS_PER_FUNCTION = 4;
}
- private HSSFWorkbook workbook;
+ private HSSFWorkbook workbook;
private HSSFSheet sheet;
// Note - multiple failures are aggregated before ending.
// If one or more functions fail, a single AssertionFailedError is thrown at the end
@@ -97,138 +96,138 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
private int _evaluationFailureCount;
private int _evaluationSuccessCount;
- private static final HSSFCell getExpectedValueCell(HSSFRow row, short columnIndex) {
- if (row == null) {
- return null;
- }
- return row.getCell(columnIndex);
- }
+ private static final HSSFCell getExpectedValueCell(HSSFRow row, short columnIndex) {
+ if (row == null) {
+ return null;
+ }
+ return row.getCell(columnIndex);
+ }
- private static void confirmExpectedResult(String msg, HSSFCell expected, HSSFFormulaEvaluator.CellValue actual) {
- if (expected == null) {
+ private static void confirmExpectedResult(String msg, HSSFCell expected, HSSFFormulaEvaluator.CellValue actual) {
+ if (expected == null) {
throw new AssertionFailedError(msg + " - Bad setup data expected value is null");
}
if(actual == null) {
throw new AssertionFailedError(msg + " - actual value was null");
}
-
+
if (expected.getCellType() == HSSFCell.CELL_TYPE_STRING) {
- String value = expected.getRichStringCellValue().getString();
- if (value.startsWith("#")) {
- // TODO - this code never called
- expected.setCellType(HSSFCell.CELL_TYPE_ERROR);
- // expected.setCellErrorValue(...?);
- }
+ String value = expected.getRichStringCellValue().getString();
+ if (value.startsWith("#")) {
+ // TODO - this code never called
+ expected.setCellType(HSSFCell.CELL_TYPE_ERROR);
+ // expected.setCellErrorValue(...?);
+ }
}
switch (expected.getCellType()) {
case HSSFCell.CELL_TYPE_BLANK:
- assertEquals(msg, HSSFCell.CELL_TYPE_BLANK, actual.getCellType());
- break;
+ assertEquals(msg, HSSFCell.CELL_TYPE_BLANK, actual.getCellType());
+ break;
case HSSFCell.CELL_TYPE_BOOLEAN:
- assertEquals(msg, HSSFCell.CELL_TYPE_BOOLEAN, actual.getCellType());
- assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue());
- break;
+ assertEquals(msg, HSSFCell.CELL_TYPE_BOOLEAN, actual.getCellType());
+ assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue());
+ break;
case HSSFCell.CELL_TYPE_ERROR:
- assertEquals(msg, HSSFCell.CELL_TYPE_ERROR, actual.getCellType());
- if(false) { // TODO: fix ~45 functions which are currently returning incorrect error values
- assertEquals(msg, expected.getErrorCellValue(), actual.getErrorValue());
- }
- break;
+ assertEquals(msg, HSSFCell.CELL_TYPE_ERROR, actual.getCellType());
+ if(false) { // TODO: fix ~45 functions which are currently returning incorrect error values
+ assertEquals(msg, expected.getErrorCellValue(), actual.getErrorValue());
+ }
+ break;
case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation
- throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg);
+ throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg);
case HSSFCell.CELL_TYPE_NUMERIC:
- assertEquals(msg, HSSFCell.CELL_TYPE_NUMERIC, actual.getCellType());
- TestMathX.assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR);
-// double delta = Math.abs(expected.getNumericCellValue()-actual.getNumberValue());
-// double pctExpected = Math.abs(0.00001*expected.getNumericCellValue());
-// assertTrue(msg, delta <= pctExpected);
- break;
+ assertEquals(msg, HSSFCell.CELL_TYPE_NUMERIC, actual.getCellType());
+ TestMathX.assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR);
+// double delta = Math.abs(expected.getNumericCellValue()-actual.getNumberValue());
+// double pctExpected = Math.abs(0.00001*expected.getNumericCellValue());
+// assertTrue(msg, delta <= pctExpected);
+ break;
case HSSFCell.CELL_TYPE_STRING:
- assertEquals(msg, HSSFCell.CELL_TYPE_STRING, actual.getCellType());
- assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getRichTextStringValue().getString());
- break;
+ assertEquals(msg, HSSFCell.CELL_TYPE_STRING, actual.getCellType());
+ assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getRichTextStringValue().getString());
+ break;
}
- }
+ }
protected void setUp() throws Exception {
- if (workbook == null) {
- String filePath = System.getProperty("HSSF.testdata.path")+ "/" + SS.FILENAME;
- FileInputStream fin = new FileInputStream( filePath );
- workbook = new HSSFWorkbook( fin );
- sheet = workbook.getSheetAt( 0 );
- }
- _functionFailureCount = 0;
- _functionSuccessCount = 0;
- _evaluationFailureCount = 0;
- _evaluationSuccessCount = 0;
- }
-
- public void testFunctionsFromTestSpreadsheet() {
-
- processFunctionGroup(SS.START_OPERATORS_ROW_INDEX, null);
- processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, null);
- // example for debugging individual functions/operators:
-// processFunctionGroup(SS.START_OPERATORS_ROW_INDEX, "ConcatEval");
-// processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, "AVERAGE");
-
- // confirm results
- String successMsg = "There were "
- + _evaluationSuccessCount + " successful evaluation(s) and "
+ if (workbook == null) {
+ String filePath = System.getProperty("HSSF.testdata.path")+ "/" + SS.FILENAME;
+ FileInputStream fin = new FileInputStream( filePath );
+ workbook = new HSSFWorkbook( fin );
+ sheet = workbook.getSheetAt( 0 );
+ }
+ _functionFailureCount = 0;
+ _functionSuccessCount = 0;
+ _evaluationFailureCount = 0;
+ _evaluationSuccessCount = 0;
+ }
+
+ public void testFunctionsFromTestSpreadsheet() {
+
+ processFunctionGroup(SS.START_OPERATORS_ROW_INDEX, null);
+ processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, null);
+ // example for debugging individual functions/operators:
+// processFunctionGroup(SS.START_OPERATORS_ROW_INDEX, "ConcatEval");
+// processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, "AVERAGE");
+
+ // confirm results
+ String successMsg = "There were "
+ + _evaluationSuccessCount + " successful evaluation(s) and "
+ _functionSuccessCount + " function(s) without error";
if(_functionFailureCount > 0) {
String msg = _functionFailureCount + " function(s) failed in "
+ _evaluationFailureCount + " evaluation(s). " + successMsg;
- throw new AssertionFailedError(msg);
- }
+ throw new AssertionFailedError(msg);
+ }
if(false) { // normally no output for successful tests
System.out.println(getClass().getName() + ": " + successMsg);
}
}
- /**
- * @param startRowIndex row index in the spreadsheet where the first function/operator is found
- * @param testFocusFunctionName name of a single function/operator to test alone.
- * Typically pass <code>null</code> to test all functions
- */
+ /**
+ * @param startRowIndex row index in the spreadsheet where the first function/operator is found
+ * @param testFocusFunctionName name of a single function/operator to test alone.
+ * Typically pass <code>null</code> to test all functions
+ */
private void processFunctionGroup(int startRowIndex, String testFocusFunctionName) {
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, workbook);
- int rowIndex = startRowIndex;
- while (true) {
- HSSFRow r = sheet.getRow(rowIndex);
- String targetFunctionName = getTargetFunctionName(r);
- if(targetFunctionName == null) {
- throw new AssertionFailedError("Test spreadsheet cell empty on row ("
- + (rowIndex+1) + "). Expected function name or '"
- + SS.FUNCTION_NAMES_END_SENTINEL + "'");
- }
- if(targetFunctionName.equals(SS.FUNCTION_NAMES_END_SENTINEL)) {
- // found end of functions list
- break;
- }
- if(testFocusFunctionName == null || targetFunctionName.equalsIgnoreCase(testFocusFunctionName)) {
-
- // expected results are on the row below
- HSSFRow expectedValuesRow = sheet.getRow(rowIndex + 1);
- if(expectedValuesRow == null) {
- int missingRowNum = rowIndex + 2; //+1 for 1-based, +1 for next row
- throw new AssertionFailedError("Missing expected values row for function '"
- + targetFunctionName + " (row " + missingRowNum + ")");
- }
- switch(processFunctionRow(evaluator, targetFunctionName, r, expectedValuesRow)) {
- case Result.ALL_EVALUATIONS_SUCCEEDED: _functionSuccessCount++; break;
- case Result.SOME_EVALUATIONS_FAILED: _functionFailureCount++; break;
- default:
- throw new RuntimeException("unexpected result");
- case Result.NO_EVALUATIONS_FOUND: // do nothing
- }
- }
- rowIndex += SS.NUMBER_OF_ROWS_PER_FUNCTION;
- }
+ int rowIndex = startRowIndex;
+ while (true) {
+ HSSFRow r = sheet.getRow(rowIndex);
+ String targetFunctionName = getTargetFunctionName(r);
+ if(targetFunctionName == null) {
+ throw new AssertionFailedError("Test spreadsheet cell empty on row ("
+ + (rowIndex+1) + "). Expected function name or '"
+ + SS.FUNCTION_NAMES_END_SENTINEL + "'");
+ }
+ if(targetFunctionName.equals(SS.FUNCTION_NAMES_END_SENTINEL)) {
+ // found end of functions list
+ break;
+ }
+ if(testFocusFunctionName == null || targetFunctionName.equalsIgnoreCase(testFocusFunctionName)) {
+
+ // expected results are on the row below
+ HSSFRow expectedValuesRow = sheet.getRow(rowIndex + 1);
+ if(expectedValuesRow == null) {
+ int missingRowNum = rowIndex + 2; //+1 for 1-based, +1 for next row
+ throw new AssertionFailedError("Missing expected values row for function '"
+ + targetFunctionName + " (row " + missingRowNum + ")");
+ }
+ switch(processFunctionRow(evaluator, targetFunctionName, r, expectedValuesRow)) {
+ case Result.ALL_EVALUATIONS_SUCCEEDED: _functionSuccessCount++; break;
+ case Result.SOME_EVALUATIONS_FAILED: _functionFailureCount++; break;
+ default:
+ throw new RuntimeException("unexpected result");
+ case Result.NO_EVALUATIONS_FOUND: // do nothing
+ }
+ }
+ rowIndex += SS.NUMBER_OF_ROWS_PER_FUNCTION;
+ }
}
/**
@@ -236,16 +235,16 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
* @return a constant from the local Result class denoting whether there were any evaluation
* cases, and whether they all succeeded.
*/
- private int processFunctionRow(HSSFFormulaEvaluator evaluator, String targetFunctionName,
- HSSFRow formulasRow, HSSFRow expectedValuesRow) {
-
- int result = Result.NO_EVALUATIONS_FOUND; // so far
- short endcolnum = formulasRow.getLastCellNum();
- evaluator.setCurrentRow(formulasRow);
+ private int processFunctionRow(HSSFFormulaEvaluator evaluator, String targetFunctionName,
+ HSSFRow formulasRow, HSSFRow expectedValuesRow) {
+
+ int result = Result.NO_EVALUATIONS_FOUND; // so far
+ short endcolnum = formulasRow.getLastCellNum();
+ evaluator.setCurrentRow(formulasRow);
- // iterate across the row for all the evaluation cases
- for (short colnum=SS.COLUMN_INDEX_FIRST_TEST_VALUE; colnum < endcolnum; colnum++) {
- HSSFCell c = formulasRow.getCell(colnum);
+ // iterate across the row for all the evaluation cases
+ for (short colnum=SS.COLUMN_INDEX_FIRST_TEST_VALUE; colnum < endcolnum; colnum++) {
+ HSSFCell c = formulasRow.getCell(colnum);
if (c == null || c.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
continue;
}
@@ -265,13 +264,13 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
printShortStackTrace(System.err, e);
result = Result.SOME_EVALUATIONS_FAILED;
}
- }
+ }
return result;
}
- /**
- * Useful to keep output concise when expecting many failures to be reported by this test case
- */
+ /**
+ * Useful to keep output concise when expecting many failures to be reported by this test case
+ */
private static void printShortStackTrace(PrintStream ps, AssertionFailedError e) {
StackTraceElement[] stes = e.getStackTrace();
@@ -304,8 +303,8 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
}
/**
- * @return <code>null</code> if cell is missing, empty or blank
- */
+ * @return <code>null</code> if cell is missing, empty or blank
+ */
private static String getTargetFunctionName(HSSFRow r) {
if(r == null) {
System.err.println("Warning - given null row, can't figure out function name");
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java
new file mode 100755
index 0000000000..be8cef13fa
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java
@@ -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.hssf.record.formula.eval;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.record.formula.PercentPtg;
+import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue;
+
+/**
+ * Test for percent operator evaluator.
+ *
+ * @author Josh Micich
+ */
+public final class TestPercentEval extends TestCase {
+
+ private static void confirm(ValueEval arg, double expectedResult) {
+ Eval[] args = {
+ arg,
+ };
+
+ PercentEval opEval = new PercentEval(new PercentPtg());
+ double result = NumericFunctionInvoker.invoke(opEval, args, -1, (short)-1);
+
+ assertEquals(expectedResult, result, 0);
+ }
+
+ public void testBasic() {
+ confirm(new NumberEval(5), 0.05);
+ confirm(new NumberEval(3000), 30.0);
+ confirm(new NumberEval(-150), -1.5);
+ confirm(new StringEval("0.2"), 0.002);
+ confirm(BoolEval.TRUE, 0.01);
+ }
+
+ public void testInSpreadSheet() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.createSheet("Sheet1");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell((short)0);
+ cell.setCellFormula("B1%");
+ row.createCell((short)1).setCellValue(50.0);
+
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ fe.setCurrentRow(row);
+ CellValue cv;
+ try {
+ cv = fe.evaluate(cell);
+ } catch (RuntimeException e) {
+ if(e.getCause() instanceof NullPointerException) {
+ throw new AssertionFailedError("Identified bug 44608");
+ }
+ // else some other unexpected error
+ throw e;
+ }
+ assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
+ assertEquals(0.5, cv.getNumberValue(), 0.0);
+ }
+
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/Bug28627.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/Bug28627.doc
new file mode 100644
index 0000000000..91b031d1d7
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/data/Bug28627.doc
Binary files differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java
index e82c4d1304..23681486f3 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java
@@ -16,19 +16,14 @@
*/
package org.apache.poi.hwpf.usermodel;
-import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.io.FileInputStream;
-import java.util.Iterator;
-import java.util.List;
+import java.io.FileOutputStream;
+
+import junit.framework.TestCase;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.model.StyleSheet;
-import org.apache.poi.hwpf.model.TextPiece;
-import org.apache.poi.hwpf.usermodel.Paragraph;
-import org.apache.poi.hwpf.usermodel.Range;
-import org.apache.poi.util.LittleEndian;
-
-import junit.framework.TestCase;
/**
* Test various problem documents
@@ -36,16 +31,18 @@ import junit.framework.TestCase;
* @author Nick Burch (nick at torchbox dot com)
*/
public class TestProblems extends TestCase {
+
private String dirname = System.getProperty("HWPF.testdata.path");
protected void setUp() throws Exception {
- }
-
+ }
+
/**
* ListEntry passed no ListTable
*/
public void testListEntryNoListTable() throws Exception {
- HWPFDocument doc = new HWPFDocument(new FileInputStream(dirname + "/ListEntryNoListTable.doc"));
+ HWPFDocument doc = new HWPFDocument(new FileInputStream(
+ new File(dirname, "ListEntryNoListTable.doc")));
Range r = doc.getRange();
StyleSheet styleSheet = doc.getStyleSheet();
@@ -62,7 +59,8 @@ public class TestProblems extends TestCase {
* AIOOB for TableSprmUncompressor.unCompressTAPOperation
*/
public void testSprmAIOOB() throws Exception {
- HWPFDocument doc = new HWPFDocument(new FileInputStream(dirname + "/AIOOB-Tap.doc"));
+ HWPFDocument doc = new HWPFDocument(new FileInputStream(
+ new File(dirname, "AIOOB-Tap.doc")));
Range r = doc.getRange();
StyleSheet styleSheet = doc.getStyleSheet();
@@ -79,7 +77,8 @@ public class TestProblems extends TestCase {
* Test for TableCell not skipping the last paragraph
*/
public void testTableCellLastParagraph() throws Exception {
- HWPFDocument doc = new HWPFDocument(new FileInputStream(dirname + "/Bug44292.doc"));
+ HWPFDocument doc = new HWPFDocument(new FileInputStream(
+ new File(dirname, "Bug44292.doc")));
Range r = doc.getRange();
//get the table
@@ -104,4 +103,39 @@ public class TestProblems extends TestCase {
// Last cell should have one paragraph
assertEquals(1, cell.numParagraphs());
}
+
+ public void testRangeDelete() throws Exception {
+ HWPFDocument doc = new HWPFDocument(new FileInputStream(
+ new File(dirname, "Bug28627.doc")));
+
+ Range range = doc.getRange();
+ int numParagraphs = range.numParagraphs();
+
+ int totalLength = 0, deletedLength = 0;
+
+ for (int i = 0; i < numParagraphs; i++) {
+ Paragraph para = range.getParagraph(i);
+ String text = para.text();
+
+ totalLength += text.length();
+ if (text.indexOf("{delete me}") > -1) {
+ para.delete();
+ deletedLength = text.length();
+ }
+ }
+
+ // check the text length after deletion
+ int newLength = 0;
+ range = doc.getRange();
+ numParagraphs = range.numParagraphs();
+
+ for (int i = 0; i < numParagraphs; i++) {
+ Paragraph para = range.getParagraph(i);
+ String text = para.text();
+
+ newLength += text.length();
+ }
+
+ assertEquals(newLength, totalLength - deletedLength);
+ }
}
diff --git a/src/testcases/org/apache/poi/hssf/data/27349-vlookupAcrossSheets.xls b/src/testcases/org/apache/poi/hssf/data/27349-vlookupAcrossSheets.xls
new file mode 100755
index 0000000000..c21d434a70
--- /dev/null
+++ b/src/testcases/org/apache/poi/hssf/data/27349-vlookupAcrossSheets.xls
Binary files differ
diff --git a/src/testcases/org/apache/poi/hssf/data/Bug44593.xls b/src/testcases/org/apache/poi/hssf/data/Bug44593.xls
new file mode 100644
index 0000000000..84d1311441
--- /dev/null
+++ b/src/testcases/org/apache/poi/hssf/data/Bug44593.xls
Binary files differ
diff --git a/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls b/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
index 6260d878bc..aaaf958a9d 100644
--- a/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
+++ b/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
Binary files differ
diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
index f922e75d82..b79236ff08 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
@@ -844,4 +844,48 @@ public final class TestFormulaParser extends TestCase {
}
assertEquals("SUM(A32769:A32770)", cell.getCellFormula());
}
+
+ public void testSpaceAtStartOfFormula() {
+ // Simulating cell formula of "= 4" (note space)
+ // The same Ptg array can be observed if an excel file is saved with that exact formula
+
+ AttrPtg spacePtg = AttrPtg.createSpace(AttrPtg.SpaceType.SPACE_BEFORE, 1);
+ Ptg[] ptgs = { spacePtg, new IntPtg(4), };
+ String formulaString;
+ try {
+ formulaString = FormulaParser.toFormulaString(null, ptgs);
+ } catch (IllegalStateException e) {
+ if(e.getMessage().equalsIgnoreCase("too much stuff left on the stack")) {
+ throw new AssertionFailedError("Identified bug 44609");
+ }
+ // else some unexpected error
+ throw e;
+ }
+ // FormulaParser strips spaces anyway
+ assertEquals("4", formulaString);
+
+ ptgs = new Ptg[] { new IntPtg(3), spacePtg, new IntPtg(4), spacePtg, new AddPtg()};
+ formulaString = FormulaParser.toFormulaString(null, ptgs);
+ assertEquals("3+4", formulaString);
+ }
+
+ /**
+ * Checks some internal error detecting logic ('stack underflow error' in toFormulaString)
+ */
+ public void testTooFewOperandArgs() {
+ // Simulating badly encoded cell formula of "=/1"
+ // Not sure if Excel could ever produce this
+ Ptg[] ptgs = {
+ // Excel would probably have put tMissArg here
+ new IntPtg(1),
+ new DividePtg(),
+ };
+ try {
+ FormulaParser.toFormulaString(null, ptgs);
+ fail("Expected exception was not thrown");
+ } catch (IllegalStateException e) {
+ // expected during successful test
+ assertTrue(e.getMessage().startsWith("Too few arguments suppled to operation token"));
+ }
+ }
}
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
index f9bb362c7b..f06f591c42 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
@@ -508,6 +508,30 @@ extends TestCase {
}
assertTrue("No Exceptions till here!", true);
}
+
+ public void test28031() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.createSheet();
+ wb.setSheetName(0, "Sheet1");
+
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell((short)0);
+ String formulaText =
+ "IF(ROUND(A2*B2*C2,2)>ROUND(B2*D2,2),ROUND(A2*B2*C2,2),ROUND(B2*D2,2))";
+ cell.setCellFormula(formulaText);
+
+ assertEquals(formulaText, cell.getCellFormula());
+ if(false) {
+ // this file can be inspected manually
+ try {
+ OutputStream os = new FileOutputStream("/tmp/output28031.xls");
+ wb.write(os);
+ os.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
public void test33082() throws java.io.IOException {
String filename = System.getProperty("HSSF.testdata.path");
@@ -1127,6 +1151,23 @@ extends TestCase {
in.close();
assertFalse(wb.isWriteProtected());
}
+
+ /**
+ * Some files were having problems with the DVRecord,
+ * probably due to dropdowns
+ */
+ public void test44593() throws Exception {
+ FileInputStream in = new FileInputStream(new File(cwd, "Bug44593.xls"));
+
+ // Used to blow up with an IllegalArgumentException
+ // when creating a DVRecord
+ // Now won't, but no idea if this means we have
+ // rubbish in the DVRecord or not...
+ HSSFWorkbook wb = new HSSFWorkbook(in);
+ in.close();
+
+ assertEquals(2, wb.getNumberOfSheets());
+ }
}
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java
index 6c604d1b4d..38d3b89295 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java
@@ -1,4 +1,3 @@
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,7 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.hssf.usermodel;
@@ -24,12 +22,11 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Date;
import java.util.GregorianCalendar;
-import java.util.List;
+import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.model.Sheet;
-import org.apache.poi.hssf.record.HyperlinkRecord;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.TempFile;
@@ -41,12 +38,7 @@ import org.apache.poi.util.TempFile;
* @author Dan Sherman (dsherman at isisph.com)
* @author Alex Jacoby (ajacoby at gmail.com)
*/
-
-public class TestHSSFCell
-extends TestCase {
- public TestHSSFCell(String s) {
- super(s);
- }
+public final class TestHSSFCell extends TestCase {
/**
* test that Boolean and Error types (BoolErrRecord) are supported properly.
@@ -388,6 +380,17 @@ extends TestCase {
assertEquals("Formula", "A1+B1", c.toString());
}
+ public void testSetStringInFormulaCell_bug44606() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFCell cell = wb.createSheet("Sheet1").createRow(0).createCell((short)0);
+ cell.setCellFormula("B1&C1");
+ try {
+ cell.setCellValue(new HSSFRichTextString("hello"));
+ } catch (ClassCastException e) {
+ throw new AssertionFailedError("Identified bug 44606");
+ }
+ }
+
public static void main(String [] args) {
System.out
.println("Testing org.apache.poi.hssf.usermodel.TestHSSFCell");
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFTextbox.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFTextbox.java
new file mode 100755
index 0000000000..f7ce61faf2
--- /dev/null
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFTextbox.java
@@ -0,0 +1,52 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.poi.hssf.usermodel;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+/**
+ * Test <code>HSSFTextbox</code>.
+ *
+ * @author Yegor Kozlov (yegor at apache.org)
+ */
+public final class TestHSSFTextbox extends TestCase{
+
+ /**
+ * Test that accessors to horizontal and vertical alignment work properly
+ */
+ public void testAlignment() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sh1 = wb.createSheet();
+ HSSFPatriarch patriarch = sh1.createDrawingPatriarch();
+
+ HSSFTextbox textbox = patriarch.createTextbox(new HSSFClientAnchor(0, 0, 0, 0, (short) 1, 1, (short) 6, 4));
+ HSSFRichTextString str = new HSSFRichTextString("Hello, World");
+ textbox.setString(str);
+ textbox.setHorizontalAlignment(HSSFTextbox.HORIZONTAL_ALIGNMENT_CENTERED);
+ textbox.setVerticalAlignment(HSSFTextbox.VERTICAL_ALIGNMENT_CENTER);
+
+ assertEquals(HSSFTextbox.HORIZONTAL_ALIGNMENT_CENTERED, textbox.getHorizontalAlignment());
+ assertEquals(HSSFTextbox.VERTICAL_ALIGNMENT_CENTER, textbox.getVerticalAlignment());
+ }
+
+ }
diff --git a/src/testcases/org/apache/poi/poifs/property/TestPropertyTable.java b/src/testcases/org/apache/poi/poifs/property/TestPropertyTable.java
index 895c40f704..008504fb00 100644
--- a/src/testcases/org/apache/poi/poifs/property/TestPropertyTable.java
+++ b/src/testcases/org/apache/poi/poifs/property/TestPropertyTable.java
@@ -25,6 +25,7 @@ import java.util.*;
import junit.framework.*;
+import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.storage.BlockAllocationTableReader;
import org.apache.poi.poifs.storage.RawDataBlockList;
@@ -2598,7 +2599,7 @@ public class TestPropertyTable
( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF
};
RawDataBlockList data_blocks =
- new RawDataBlockList(new ByteArrayInputStream(raw_data_array));
+ new RawDataBlockList(new ByteArrayInputStream(raw_data_array), POIFSConstants.BIG_BLOCK_SIZE);
int[] bat_array =
{
15
diff --git a/src/testcases/org/apache/poi/poifs/storage/LocalRawDataBlockList.java b/src/testcases/org/apache/poi/poifs/storage/LocalRawDataBlockList.java
index ed3e8d9259..21049ebf18 100644
--- a/src/testcases/org/apache/poi/poifs/storage/LocalRawDataBlockList.java
+++ b/src/testcases/org/apache/poi/poifs/storage/LocalRawDataBlockList.java
@@ -19,6 +19,8 @@
package org.apache.poi.poifs.storage;
+import org.apache.poi.poifs.common.POIFSConstants;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
@@ -47,7 +49,7 @@ public class LocalRawDataBlockList
public LocalRawDataBlockList()
throws IOException
{
- super(new ByteArrayInputStream(new byte[ 0 ]));
+ super(new ByteArrayInputStream(new byte[ 0 ]), POIFSConstants.BIG_BLOCK_SIZE);
_list = new ArrayList();
_array = null;
}
diff --git a/src/testcases/org/apache/poi/poifs/storage/TestRawDataBlockList.java b/src/testcases/org/apache/poi/poifs/storage/TestRawDataBlockList.java
index ac6fc08c05..d151029762 100644
--- a/src/testcases/org/apache/poi/poifs/storage/TestRawDataBlockList.java
+++ b/src/testcases/org/apache/poi/poifs/storage/TestRawDataBlockList.java
@@ -21,6 +21,7 @@ package org.apache.poi.poifs.storage;
import java.io.*;
+import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.util.DummyPOILogger;
import org.apache.poi.util.POILogFactory;
@@ -69,7 +70,7 @@ public class TestRawDataBlockList
{
data[ j ] = ( byte ) j;
}
- new RawDataBlockList(new ByteArrayInputStream(data));
+ new RawDataBlockList(new ByteArrayInputStream(data), POIFSConstants.BIG_BLOCK_SIZE);
}
/**
@@ -81,7 +82,7 @@ public class TestRawDataBlockList
public void testEmptyConstructor()
throws IOException
{
- new RawDataBlockList(new ByteArrayInputStream(new byte[ 0 ]));
+ new RawDataBlockList(new ByteArrayInputStream(new byte[ 0 ]), POIFSConstants.BIG_BLOCK_SIZE);
}
/**
@@ -108,7 +109,7 @@ public class TestRawDataBlockList
// Check we logged the error
logger.reset();
- new RawDataBlockList(new ByteArrayInputStream(data));
+ new RawDataBlockList(new ByteArrayInputStream(data), POIFSConstants.BIG_BLOCK_SIZE);
assertEquals(1, logger.logged.size());
}
}
diff --git a/src/testcases/org/apache/poi/poifs/storage/TestSmallBlockTableReader.java b/src/testcases/org/apache/poi/poifs/storage/TestSmallBlockTableReader.java
index bb2e3c4c0e..4d4254a91e 100644
--- a/src/testcases/org/apache/poi/poifs/storage/TestSmallBlockTableReader.java
+++ b/src/testcases/org/apache/poi/poifs/storage/TestSmallBlockTableReader.java
@@ -25,6 +25,7 @@ import java.util.*;
import junit.framework.*;
+import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.property.PropertyTable;
import org.apache.poi.poifs.property.RootProperty;
@@ -2112,7 +2113,7 @@ public class TestSmallBlockTableReader
( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF
};
RawDataBlockList data_blocks =
- new RawDataBlockList(new ByteArrayInputStream(raw_data_array));
+ new RawDataBlockList(new ByteArrayInputStream(raw_data_array), POIFSConstants.BIG_BLOCK_SIZE);
int[] bat_array =
{
15