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
This commit is contained in:
parent
66d67ccab5
commit
dbd8b08654
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -603,29 +603,30 @@ public class HSSFCell implements Cell
|
||||
if (hvalue == null)
|
||||
{
|
||||
setCellType(CELL_TYPE_BLANK, false, row, col, styleIndex);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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_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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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())
|
||||
{
|
||||
|
71
src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/PercentEval.java
Executable file
71
src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/PercentEval.java
Executable file
@ -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();
|
||||
}
|
||||
}
|
@ -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];
|
||||
@ -557,25 +502,6 @@ public class HSSFFormulaEvaluator {
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
|
165
src/scratchpad/src/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java
Executable file
165
src/scratchpad/src/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java
Executable file
@ -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;
|
||||
}
|
||||
}
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
BIN
src/scratchpad/testcases/org/apache/poi/hwpf/data/Bug28627.doc
Normal file
BIN
src/scratchpad/testcases/org/apache/poi/hwpf/data/Bug28627.doc
Normal file
Binary file not shown.
@ -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);
|
||||
}
|
||||
}
|
||||
|
BIN
src/testcases/org/apache/poi/hssf/data/27349-vlookupAcrossSheets.xls
Executable file
BIN
src/testcases/org/apache/poi/hssf/data/27349-vlookupAcrossSheets.xls
Executable file
Binary file not shown.
BIN
src/testcases/org/apache/poi/hssf/data/Bug44593.xls
Normal file
BIN
src/testcases/org/apache/poi/hssf/data/Bug44593.xls
Normal file
Binary file not shown.
Binary file not shown.
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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");
|
||||
|
52
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFTextbox.java
Executable file
52
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFTextbox.java
Executable file
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user