<path id="examples.classpath">
<path refid="main.classpath"/>
<pathelement location="${main.output.dir}"/>
+ <pathelement location="${scratchpad.output.dir}"/>
</path>
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1-final" date="2008-06-??">
+ <action dev="POI-DEVELOPERS" type="add">45025 - improved FormulaParser parse error messages</action>
+ <action dev="POI-DEVELOPERS" type="add">45046 - allowed EXTERNALBOOK(0x01AE) to be optional in the LinkTable</action>
+ <action dev="POI-DEVELOPERS" type="add">45066 - fixed sheet encoding size mismatch problems</action>
+ <action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action>
+ <action dev="POI-DEVELOPERS" type="fix">45001 - Partial fix for HWPF Range.insertBefore() and Range.delete() with unicode characters</action>
+ <action dev="POI-DEVELOPERS" type="fix">44977 - Support for AM/PM in excel date formats</action>
<action dev="POI-DEVELOPERS" type="add">Support for specifying a policy to HSSF on missing / blank cells when fetching</action>
<action dev="POI-DEVELOPERS" type="add">44937 - Partial support for extracting Escher images from HWPF files</action>
<action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action>
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1-final" date="2008-06-??">
+ <action dev="POI-DEVELOPERS" type="add">45025 - improved FormulaParser parse error messages</action>
+ <action dev="POI-DEVELOPERS" type="add">45046 - allowed EXTERNALBOOK(0x01AE) to be optional in the LinkTable</action>
+ <action dev="POI-DEVELOPERS" type="add">45066 - fixed sheet encoding size mismatch problems</action>
+ <action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action>
+ <action dev="POI-DEVELOPERS" type="fix">45001 - Partial fix for HWPF Range.insertBefore() and Range.delete() with unicode characters</action>
+ <action dev="POI-DEVELOPERS" type="fix">44977 - Support for AM/PM in excel date formats</action>
<action dev="POI-DEVELOPERS" type="add">Support for specifying a policy to HSSF on missing / blank cells when fetching</action>
<action dev="POI-DEVELOPERS" type="add">44937 - Partial support for extracting Escher images from HWPF files</action>
<action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action>
--- /dev/null
+/* ====================================================================
+ 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.hslf.usermodel.examples;
+import org.apache.poi.ddf.*;
+import org.apache.poi.hslf.model.*;
+import org.apache.poi.hslf.record.InteractiveInfo;
+import org.apache.poi.hslf.record.InteractiveInfoAtom;
+import org.apache.poi.hslf.record.Record;
+import org.apache.poi.hslf.usermodel.*;
+import java.io.FileInputStream;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * For each slide iterate over shapes and found associated sound data.
+ *
+ * @author Yegor Kozlov
+ */
+public class SoundFinder {
+ public static void main(String[] args) throws Exception {
+ SlideShow ppt = new SlideShow(new FileInputStream(args[0]));
+ SoundData[] sounds = ppt.getSoundData();
+
+ Slide[] slide = ppt.getSlides();
+ for (int i = 0; i < slide.length; i++) {
+ Shape[] shape = slide[i].getShapes();
+ for (int j = 0; j < shape.length; j++) {
+ int soundRef = getSoundReference(shape[j]);
+ if(soundRef != -1) {
+ System.out.println("Slide["+i+"], shape["+j+"], soundRef: "+soundRef);
+ System.out.println(" " + sounds[soundRef].getSoundName());
+ System.out.println(" " + sounds[soundRef].getSoundType());
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if a given shape is associated with a sound.
+ * @return 0-based reference to a sound in the sound collection
+ * or -1 if the shape is not associated with a sound
+ */
+ protected static int getSoundReference(Shape shape){
+ int soundRef = -1;
+ //dive into the shape container and search for InteractiveInfoAtom
+ EscherContainerRecord spContainer = shape.getSpContainer();
+ List spchild = spContainer.getChildRecords();
+ for (Iterator it = spchild.iterator(); it.hasNext();) {
+ EscherRecord obj = (EscherRecord) it.next();
+ if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) {
+ byte[] data = obj.serialize();
+ Record[] records = Record.findChildRecords(data, 8,
+data.length - 8);
+ for (int j = 0; j < records.length; j++) {
+ if (records[j] instanceof InteractiveInfo) {
+ InteractiveInfoAtom info = ((InteractiveInfo)records[j]).getInteractiveInfoAtom();
+ if (info.getAction() == InteractiveInfoAtom.ACTION_MEDIA) {
+ soundRef = info.getSoundRef();
+ }
+ }
+ }
+ }
+ }
+ return soundRef;
+ }
+}
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
System.err.println("Couldn't write property set with name " + name + " as not supported by HPSF yet");
}
}
+
+ /**
+ * Writes the document out to the specified output stream
+ */
+ public abstract void write(OutputStream out) throws IOException;
/**
* Copies nodes from one POIFS to the other minus the excepts
*/
static final class FormulaParseException extends RuntimeException {
// This class was given package scope until it would become clear that it is useful to
- // general client code.
+ // general client code.
public FormulaParseException(String msg) {
super(msg);
}
// Just return if so and reset 'look' to something to keep
// SkipWhitespace from spinning
look = (char)0;
- }
+ }
pointer++;
//System.out.println("Got char: "+ look);
}
/** Report What Was Expected */
private RuntimeException expected(String s) {
- String msg = "Parse error near char " + (pointer-1) + "'" + look + "'"
+ String msg = "Parse error near char " + (pointer-1) + " '" + look + "'"
+ " in specified formula '" + formulaString + "'. Expected "
+ s;
return new FormulaParseException(msg);
}
-
-
/** Recognize an Alpha Character */
private boolean IsAlpha(char c) {
return Character.isLetter(c) || c == '$' || c=='_';
}
-
-
/** Recognize a Decimal Digit */
private boolean IsDigit(char c) {
- //System.out.println("Checking digit for"+c);
return Character.isDigit(c);
}
-
-
/** Recognize an Alphanumeric */
private boolean IsAlNum(char c) {
return (IsAlpha(c) || IsDigit(c));
}
-
/** Recognize White Space */
private boolean IsWhite( char c) {
return (c ==' ' || c== TAB);
/**
* Consumes the next input character if it is equal to the one specified otherwise throws an
* unchecked exception. This method does <b>not</b> consume whitespace (before or after the
- * matched character).
+ * matched character).
*/
private void Match(char x) {
if (look != x) {
return Token.toString();
}
-
/** Get a Number */
private String GetNum() {
StringBuffer value = new StringBuffer();
// This can be either a cell ref or a named range
// Try to spot which it is
boolean cellRef = CELL_REFERENCE_PATTERN.matcher(name).matches();
-
+
if (cellRef) {
return new ReferencePtg(name);
}
for(int i = 0; i < book.getNumberOfNames(); i++) {
// named range name matching is case insensitive
- if(book.getNameAt(i).getNameName().equalsIgnoreCase(name)) {
+ if(book.getNameAt(i).getNameName().equalsIgnoreCase(name)) {
return new NamePtg(name, book);
}
}
- throw new FormulaParseException("Found reference to named range \""
+ throw new FormulaParseException("Found reference to named range \""
+ name + "\", but that named range wasn't defined!");
}
/**
* Note - Excel function names are 'case aware but not case sensitive'. This method may end
* up creating a defined name record in the workbook if the specified name is not an internal
- * Excel function, and has not been encountered before.
- *
- * @param name case preserved function name (as it was entered/appeared in the formula).
+ * Excel function, and has not been encountered before.
+ *
+ * @param name case preserved function name (as it was entered/appeared in the formula).
*/
private Ptg function(String name) {
int numArgs =0 ;
- // Note regarding parameter -
+ // Note regarding parameter -
if(!AbstractFunctionPtg.isInternalFunctionName(name)) {
// external functions get a Name token which points to a defined name record
NamePtg nameToken = new NamePtg(name, this.book);
-
+
// in the token tree, the name is more or less the first argument
- numArgs++;
+ numArgs++;
tokens.add(nameToken);
}
//average 2 args per function
private static boolean isArgumentDelimiter(char ch) {
return ch == ',' || ch == ')';
}
-
+
/** get arguments to a function */
private int Arguments(List argumentPointers) {
SkipWhite();
if(look == ')') {
return 0;
}
-
+
boolean missedPrevArg = true;
-
int numArgs = 0;
- while(true) {
+ while (true) {
SkipWhite();
- if(isArgumentDelimiter(look)) {
- if(missedPrevArg) {
+ if (isArgumentDelimiter(look)) {
+ if (missedPrevArg) {
tokens.add(new MissingArgPtg());
addArgumentPointer(argumentPointers);
numArgs++;
}
- if(look == ')') {
+ if (look == ')') {
break;
}
Match(',');
addArgumentPointer(argumentPointers);
numArgs++;
missedPrevArg = false;
+ SkipWhite();
+ if (!isArgumentDelimiter(look)) {
+ throw expected("',' or ')'");
+ }
}
return numArgs;
}
tokens.add(new PowerPtg());
}
}
-
+
private void percentFactor() {
tokens.add(parseSimpleFactor());
while(true) {
tokens.add(new PercentPtg());
}
}
-
-
+
+
/**
* factors (without ^ or % )
*/
return new ParenthesisPtg();
case '"':
return parseStringLiteral();
- case ',':
- case ')':
- return new MissingArgPtg(); // TODO - not quite the right place to recognise a missing arg
}
if (IsAlpha(look) || look == '\''){
return parseIdent();
}
- private StringPtg parseStringLiteral()
- {
+ private StringPtg parseStringLiteral() {
Match('"');
-
+
StringBuffer token = new StringBuffer();
while (true) {
if (look == '"') {
return; // finished with Term
}
}
-
+
private void comparisonExpression() {
concatExpression();
while (true) {
}
return new LessThanPtg();
}
-
+
private void concatExpression() {
additiveExpression();
tokens.add(new ConcatPtg());
}
}
-
+
/** Parse and Translate an Expression */
private void additiveExpression() {
**/
- /** API call to execute the parsing of the formula
- *
+ /**
+ * API call to execute the parsing of the formula
+ * @deprecated use Ptg[] FormulaParser.parse(String, HSSFWorkbook) directly
*/
public void parse() {
pointer=0;
comparisonExpression();
if(pointer <= formulaLength) {
- String msg = "Unused input [" + formulaString.substring(pointer-1)
- + "] after attempting to parse the formula [" + formulaString + "]";
+ String msg = "Unused input [" + formulaString.substring(pointer-1)
+ + "] after attempting to parse the formula [" + formulaString + "]";
throw new FormulaParseException(msg);
}
}
* a result of the parsing
*/
public Ptg[] getRPNPtg() {
- return getRPNPtg(FORMULA_TYPE_CELL);
+ return getRPNPtg(FORMULA_TYPE_CELL);
}
public Ptg[] getRPNPtg(int formulaType) {
Node node = createTree();
+ // RVA is for 'operand class': 'reference', 'value', 'array'
setRootLevelRVA(node, formulaType);
setParameterRVA(node,formulaType);
return (Ptg[]) tokens.toArray(new Ptg[0]);
}
}
/**
- * Convience method which takes in a list then passes it to the
+ * Convenience method which takes in a list then passes it to the
* other toFormulaString signature.
* @param book workbook for 3D and named references
* @param lptgs list of Ptg, can be null or empty
return retval;
}
/**
- * Convience method which takes in a list then passes it to the
+ * Convenience method which takes in a list then passes it to the
* other toFormulaString signature. Works on the current
* workbook for 3D and named references
* @param lptgs list of Ptg, can be null or empty
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
+ // with how the formula text appears but is against the RPN ordering assumed here
}
if (attrPtg.isSemiVolatile()) {
// similar to tAttrSpace - RPN is violated
stack.push(o.toFormulaString(operands));
}
if(stack.isEmpty()) {
- // inspection of the code above reveals that every stack.pop() is followed by a
+ // inspection of the code above reveals that every stack.pop() is followed by a
// stack.push(). So this is either an internal error or impossible.
throw new IllegalStateException("Stack underflow");
}
*
* In BIFF8 the Link Table consists of
* <ul>
- * <li>one or more EXTERNALBOOK Blocks<p/>
+ * <li>zero or more EXTERNALBOOK Blocks<p/>
* each consisting of
* <ul>
* <li>exactly one EXTERNALBOOK (0x01AE) record</li>
* </li>
* </ul>
* </li>
- * <li>exactly one EXTERNSHEET (0x0017) record</li>
+ * <li>zero or one EXTERNSHEET (0x0017) record</li>
* <li>zero or more DEFINEDNAME (0x0018) records</li>
* </ul>
*
* @author Josh Micich
*/
final class LinkTable {
+ // TODO make this class into a record aggregate
private static final class CRNBlock {
_crns = crns;
}
public CRNRecord[] getCrns() {
- return (CRNRecord[]) _crns.clone();
- }
+ return (CRNRecord[]) _crns.clone();
+ }
}
private static final class ExternalBookBlock {
while(rs.peekNextClass() == SupBookRecord.class) {
temp.add(new ExternalBookBlock(rs));
}
- if(temp.size() < 1) {
- throw new RuntimeException("Need at least one EXTERNALBOOK blocks");
- }
+
_externalBookBlocks = new ExternalBookBlock[temp.size()];
temp.toArray(_externalBookBlocks);
temp.clear();
-
- // If link table is present, there is always 1 of ExternSheetRecord
- Record next = rs.getNext();
- _externSheetRecord = (ExternSheetRecord)next;
+
+ if (_externalBookBlocks.length > 0) {
+ // If any ExternalBookBlock present, there is always 1 of ExternSheetRecord
+ Record next = rs.getNext();
+ _externSheetRecord = (ExternSheetRecord) next;
+ } else {
+ _externSheetRecord = null;
+ }
+
_definedNames = new ArrayList();
// collect zero or more DEFINEDNAMEs id=0x18
while(rs.peekNextClass() == NameRecord.class) {
public void addName(NameRecord name) {
_definedNames.add(name);
- // TODO - this is messy
+ // TODO - this is messy
// Not the most efficient way but the other way was causing too many bugs
int idx = findFirstRecordLocBySid(ExternSheetRecord.sid);
if (idx == -1) idx = findFirstRecordLocBySid(SupBookRecord.sid);
public int getSheetIndexFromExternSheetIndex(int externSheetNumber) {
if (externSheetNumber >= _externSheetRecord.getNumOfREFStructures()) {
- return -1;
- }
+ return -1;
+ }
return _externSheetRecord.getREFRecordAt(externSheetNumber).getIndexToFirstSupBook();
}
ExternSheetSubRecord esr = _externSheetRecord.getREFRecordAt(i);
if (esr.getIndexToFirstSupBook() == sheetNumber
- && esr.getIndexToLastSupBook() == sheetNumber){
+ && esr.getIndexToLastSupBook() == sheetNumber){
return i;
}
}
protected List condFormatting = new ArrayList();
/** Add an UncalcedRecord if not true indicating formulas have not been calculated */
- protected boolean uncalced = false;
-
+ protected boolean _isUncalced = false;
+
public static final byte PANE_LOWER_RIGHT = (byte)0;
public static final byte PANE_UPPER_RIGHT = (byte)1;
public static final byte PANE_LOWER_LEFT = (byte)2;
}
}
else if (rec.getSid() == UncalcedRecord.sid) {
- retval.uncalced = true;
+ retval._isUncalced = true;
}
else if (rec.getSid() == DimensionsRecord.sid)
{
}
}
retval.records = records;
-// if (retval.rows == null)
-// {
-// retval.rows = new RowRecordsAggregate();
-// }
retval.checkCells();
retval.checkRows();
-// if (retval.cells == null)
-// {
-// retval.cells = new ValueRecordsAggregate();
-// }
if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited");
return retval;
// Once the rows have been found in the list of records, start
// writing out the blocked row information. This includes the DBCell references
if (record instanceof RowRecordsAggregate) {
- pos += ((RowRecordsAggregate)record).serialize(pos, data, cells); // rec.length;
+ pos += ((RowRecordsAggregate)record).serialize(pos, data, cells);
} else if (record instanceof ValueRecordsAggregate) {
//Do nothing here. The records were serialized during the RowRecordAggregate block serialization
} else {
- pos += record.serialize(pos, data ); // rec.length;
+ pos += record.serialize(pos, data );
}
// If the BOF record was just serialized then add the IndexRecord
if (record.getSid() == BOFRecord.sid) {
// Add an optional UncalcedRecord
- if (uncalced) {
+ if (_isUncalced) {
UncalcedRecord rec = new UncalcedRecord();
pos += rec.serialize(pos, data);
}
pos += serializeIndexRecord(k, pos, data);
}
}
-
- //// uncomment to test record sizes ////
-// System.out.println( record.getClass().getName() );
-// byte[] data2 = new byte[record.getRecordSize()];
-// record.serialize(0, data2 ); // rec.length;
-// if (LittleEndian.getUShort(data2, 2) != record.getRecordSize() - 4
-// && record instanceof RowRecordsAggregate == false
-// && record instanceof ValueRecordsAggregate == false
-// && record instanceof EscherAggregate == false)
-// {
-// throw new RuntimeException("Blah!!! Size off by " + ( LittleEndian.getUShort(data2, 2) - record.getRecordSize() - 4) + " records.");
-// }
-
-//asd: int len = record.serialize(pos + offset, data );
-
- ///// DEBUG BEGIN /////
-//asd: if (len != record.getRecordSize())
-//asd: throw new IllegalStateException("Record size does not match serialized bytes. Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize() + ". Record object is " + record.getClass());
- ///// DEBUG END /////
-
-//asd: pos += len; // rec.length;
-
}
- if (log.check( POILogger.DEBUG ))
+ if (log.check( POILogger.DEBUG )) {
log.log(POILogger.DEBUG, "Sheet.serialize returning ");
+ }
return pos-offset;
}
for (int j = BOFRecordIndex+1; j < records.size(); j++)
{
Record tmpRec = (( Record ) records.get(j));
- if (tmpRec instanceof RowRecordsAggregate)
- break;
+ if (tmpRec instanceof UncalcedRecord) {
+ continue;
+ }
+ if (tmpRec instanceof RowRecordsAggregate) {
+ break;
+ }
sheetRecSize+= tmpRec.getRecordSize();
}
+ if (_isUncalced) {
+ sheetRecSize += UncalcedRecord.getStaticRecordSize();
+ }
//Add the references to the DBCells in the IndexRecord (one for each block)
int blockCount = rows.getRowBlockCount();
//Calculate the size of this IndexRecord
{
int retval = 0;
- for ( int k = 0; k < records.size(); k++ )
- {
- retval += ( (Record) records.get( k ) ).getRecordSize();
+ for ( int k = 0; k < records.size(); k++) {
+ Record record = (Record) records.get(k);
+ if (record instanceof UncalcedRecord) {
+ // skip the UncalcedRecord if present, it's only encoded if the isUncalced flag is set
+ continue;
+ }
+ retval += record.getRecordSize();
}
- //Add space for the IndexRecord
if (rows != null) {
- final int blocks = rows.getRowBlockCount();
- retval += IndexRecord.getRecordSizeForBlockCount(blocks);
-
- //Add space for the DBCell records
- //Once DBCell per block.
- //8 bytes per DBCell (non variable section)
- //2 bytes per row reference
- retval += (8 * blocks);
- for (Iterator itr = rows.getIterator(); itr.hasNext();) {
- RowRecord row = (RowRecord)itr.next();
- if (cells != null && cells.rowHasCells(row.getRowNumber()))
- retval += 2;
+ // Add space for the IndexRecord and DBCell records
+ final int nBlocks = rows.getRowBlockCount();
+ int nRows = 0;
+ if (cells != null) {
+ for (Iterator itr = rows.getIterator(); itr.hasNext();) {
+ RowRecord row = (RowRecord)itr.next();
+ if (cells.rowHasCells(row.getRowNumber())) {
+ nRows++;
+ }
+ }
}
+ retval += IndexRecord.getRecordSizeForBlockCount(nBlocks);
+ retval += DBCellRecord.calculateSizeOfRecords(nBlocks, nRows);
}
// Add space for UncalcedRecord
- if (uncalced) {
+ if (_isUncalced) {
retval += UncalcedRecord.getStaticRecordSize();
}
-
return retval;
}
* @return whether an uncalced record must be inserted or not at generation
*/
public boolean getUncalced() {
- return uncalced;
+ return _isUncalced;
}
/**
* @param uncalced whether an uncalced record must be inserted or not at generation
*/
public void setUncalced(boolean uncalced) {
- this.uncalced = uncalced;
+ this._isUncalced = uncalced;
}
/**
case ExternSheetRecord.sid :
throw new RuntimeException("Extern sheet is part of LinkTable");
case NameRecord.sid :
- throw new RuntimeException("DEFINEDNAME is part of LinkTable");
case SupBookRecord.sid :
+ // LinkTable can start with either of these
if (log.check( POILogger.DEBUG ))
log.log(DEBUG, "found SupBook record at " + k);
retval.linkTable = new LinkTable(recs, k, retval.records);
- // retval.records.supbookpos = k;
k+=retval.linkTable.getRecordCount() - 1;
continue;
case FormatRecord.sid :
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.hssf.record;
* @author Jason Height
* @version 2.0-pre
*/
-
-public class DBCellRecord
- extends Record
-{
+public final class DBCellRecord extends Record {
public final static int BLOCK_SIZE = 32;
public final static short sid = 0xd7;
private int field_1_row_offset;
* Constructs a DBCellRecord and sets its fields appropriately
* @param in the RecordInputstream to read the record from
*/
-
public DBCellRecord(RecordInputStream in)
{
super(in);
*
* @param offset offset to the start of the first cell in the next DBCell block
*/
-
public void setRowOffset(int offset)
{
field_1_row_offset = offset;
*
* @return rowoffset to the start of the first cell in the next DBCell block
*/
-
public int getRowOffset()
{
return field_1_row_offset;
* @param index of the cell offset to retrieve
* @return celloffset from the celloffset array
*/
-
public short getCellOffsetAt(int index)
{
return field_2_cell_offsets[ index ];
*
* @return number of cell offsets
*/
-
public int getNumCellOffsets()
{
return field_2_cell_offsets.length;
return 8 + (getNumCellOffsets() * 2);
}
- /** Returns the size of a DBCellRecord when it needs to reference a certain number of rows*/
- public static int getRecordSizeForRows(int rows) {
- return 8 + (rows * 2);
+ /**
+ * @returns the size of the group of <tt>DBCellRecord</tt>s needed to encode
+ * the specified number of blocks and rows
+ */
+ public static int calculateSizeOfRecords(int nBlocks, int nRows) {
+ // One DBCell per block.
+ // 8 bytes per DBCell (non variable section)
+ // 2 bytes per row reference
+ return nBlocks * 8 + nRows * 2;
}
public short getSid()
/**
- * Title: Area 3D Ptg - 3D referecnce (Sheet + Area)<P>
+ * Title: Area 3D Ptg - 3D reference (Sheet + Area)<P>
* Description: Defined a area in Extern Sheet. <P>
* REFERENCE: <P>
* @author Libin Roman (Vista Portal LDT. Developer)
* @author Jason Height (jheight at chariot dot net dot au)
* @version 1.0-pre
*/
-
public class Area3DPtg extends Ptg implements AreaI
{
public final static byte sid = 0x3b;
setExternSheetIndex(externalSheetIndex);
}
- public String toString()
- {
- StringBuffer buffer = new StringBuffer();
-
- buffer.append( "AreaPtg\n" );
- buffer.append( "Index to Extern Sheet = " + getExternSheetIndex() ).append( "\n" );
- buffer.append( "firstRow = " + getFirstRow() ).append( "\n" );
- buffer.append( "lastRow = " + getLastRow() ).append( "\n" );
- buffer.append( "firstCol = " + getFirstColumn() ).append( "\n" );
- buffer.append( "lastCol = " + getLastColumn() ).append( "\n" );
- buffer.append( "firstColRel= "
- + isFirstRowRelative() ).append( "\n" );
- buffer.append( "lastColRowRel = "
- + isLastRowRelative() ).append( "\n" );
- buffer.append( "firstColRel = " + isFirstColRelative() ).append( "\n" );
- buffer.append( "lastColRel = " + isLastColRelative() ).append( "\n" );
- return buffer.toString();
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(getClass().getName());
+ sb.append(" [");
+ sb.append("sheetIx=").append(getExternSheetIndex());
+ sb.append(" ! ");
+ sb.append(AreaReference.formatAsString(this));
+ sb.append("]");
+ return sb.toString();
}
public void writeBytes( byte[] array, int offset )
}
// Now the normal area bit
- retval.append( AreaPtg.toFormulaString(this, book) );
+ retval.append(AreaReference.formatAsString(this));
// All done
return retval.toString();
public int hashCode()
{
+ // TODO - hashCode seems to be unused
int result;
result = (int) field_1_index_extern_sheet;
result = 29 * result + (int) field_2_first_row;
return "AreaPtg";
}
- public String toString()
- {
- StringBuffer buffer = new StringBuffer();
-
- buffer.append(getAreaPtgName());
- buffer.append("\n");
- buffer.append("firstRow = " + getFirstRow()).append("\n");
- buffer.append("lastRow = " + getLastRow()).append("\n");
- buffer.append("firstCol = " + getFirstColumn()).append("\n");
- buffer.append("lastCol = " + getLastColumn()).append("\n");
- buffer.append("firstColRowRel= "
- + isFirstRowRelative()).append("\n");
- buffer.append("lastColRowRel = "
- + isLastRowRelative()).append("\n");
- buffer.append("firstColRel = " + isFirstColRelative()).append("\n");
- buffer.append("lastColRel = " + isLastColRelative()).append("\n");
- return buffer.toString();
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(getClass().getName());
+ sb.append(" [");
+ sb.append(AreaReference.formatAsString(this));
+ sb.append("]");
+ return sb.toString();
}
public void writeBytes(byte [] array, int offset) {
field_4_last_column = column;
}
- public String toFormulaString(Workbook book)
- {
- return toFormulaString(this, book);
- }
- protected static String toFormulaString(AreaI area, Workbook book) {
- CellReference topLeft = new CellReference(area.getFirstRow(),area.getFirstColumn(),!area.isFirstRowRelative(),!area.isFirstColRelative());
- CellReference botRight = new CellReference(area.getLastRow(),area.getLastColumn(),!area.isLastRowRelative(),!area.isLastColRelative());
-
- if(AreaReference.isWholeColumnReference(topLeft, botRight)) {
- return (new AreaReference(topLeft, botRight)).formatAsString();
- } else {
- return topLeft.formatAsString() + ":" + botRight.formatAsString();
- }
+ public String toFormulaString(Workbook book) {
+ return AreaReference.formatAsString(this);
}
public byte getDefaultOperandClass() {
limitations under the License.
==================================================================== */
-
-/*
- * HSSFWorkbook.java
- *
- * Created on September 30, 2001, 3:37 PM
- */
package org.apache.poi.hssf.usermodel;
import java.io.ByteArrayInputStream;
* @author Shawn Laubach (slaubach at apache dot org)
* @version 2.0-pre
*/
-
public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook
{
private static final int DEBUG = POILogger.DEBUG;
* this holds the HSSFSheet objects attached to this workbook
*/
- protected ArrayList sheets;
+ protected List _sheets;
/**
* this holds the HSSFName objects attached to this workbook
{
super(null, null);
workbook = book;
- sheets = new ArrayList( INITIAL_CAPACITY );
+ _sheets = new ArrayList( INITIAL_CAPACITY );
names = new ArrayList( INITIAL_CAPACITY );
}
this.directory = null;
}
- sheets = new ArrayList(INITIAL_CAPACITY);
+ _sheets = new ArrayList(INITIAL_CAPACITY);
names = new ArrayList(INITIAL_CAPACITY);
// Grab the data from the workbook stream, however
HSSFSheet hsheet = new HSSFSheet(this, sheet);
- sheets.add(hsheet);
+ _sheets.add(hsheet);
// workbook.setSheetName(sheets.size() -1, "Sheet"+sheets.size());
}
*/
public void setSheetOrder(String sheetname, int pos ) {
- sheets.add(pos,sheets.remove(getSheetIndex(sheetname)));
+ _sheets.add(pos,_sheets.remove(getSheetIndex(sheetname)));
workbook.setSheetOrder(sheetname, pos);
}
private void validateSheetIndex(int index) {
- int lastSheetIx = sheets.size() - 1;
+ int lastSheetIx = _sheets.size() - 1;
if (index < 0 || index > lastSheetIx) {
throw new IllegalArgumentException("Sheet index ("
+ index +") is out of range (0.." + lastSheetIx + ")");
public void setSelectedTab(int index) {
validateSheetIndex(index);
- int nSheets = sheets.size();
+ int nSheets = _sheets.size();
for (int i=0; i<nSheets; i++) {
getSheetAt(i).setSelected(i == index);
}
for (int i = 0; i < indexes.length; i++) {
validateSheetIndex(indexes[i]);
}
- int nSheets = sheets.size();
+ int nSheets = _sheets.size();
for (int i=0; i<nSheets; i++) {
boolean bSelect = false;
for (int j = 0; j < indexes.length; j++) {
public void setActiveSheet(int index) {
validateSheetIndex(index);
- int nSheets = sheets.size();
+ int nSheets = _sheets.size();
for (int i=0; i<nSheets; i++) {
getSheetAt(i).setActive(i == index);
}
* set the sheet name.
* Will throw IllegalArgumentException if the name is greater than 31 chars
* or contains /\?*[]
- * @param sheet number (0 based)
+ * @param sheetIx number (0 based)
*/
- public void setSheetName(int sheet, String name)
+ public void setSheetName(int sheetIx, String name)
{
- if (workbook.doesContainsSheetName( name, sheet ))
+ if (workbook.doesContainsSheetName( name, sheetIx )) {
throw new IllegalArgumentException( "The workbook already contains a sheet with this name" );
-
- if (sheet > (sheets.size() - 1))
- {
- throw new RuntimeException("Sheet out of bounds");
}
-
- workbook.setSheetName( sheet, name);
+ validateSheetIndex(sheetIx);
+ workbook.setSheetName(sheetIx, name);
}
* or contains /\?*[]
* @param sheet number (0 based)
*/
- public void setSheetName( int sheet, String name, short encoding )
+ public void setSheetName(int sheetIx, String name, short encoding)
{
- if (workbook.doesContainsSheetName( name, sheet ))
+ if (workbook.doesContainsSheetName( name, sheetIx )) {
throw new IllegalArgumentException( "The workbook already contains a sheet with this name" );
-
- if (sheet > (sheets.size() - 1))
- {
- throw new RuntimeException("Sheet out of bounds");
}
+ validateSheetIndex(sheetIx);
switch ( encoding ) {
case ENCODING_COMPRESSED_UNICODE:
throw new RuntimeException( "Unsupported encoding" );
}
- workbook.setSheetName( sheet, name, encoding );
+ workbook.setSheetName( sheetIx, name, encoding );
}
/**
* get the sheet name
- * @param sheet Number
+ * @param sheetIx Number
* @return Sheet name
*/
-
- public String getSheetName(int sheet)
+ public String getSheetName(int sheetIx)
{
- if (sheet > (sheets.size() - 1))
- {
- throw new RuntimeException("Sheet out of bounds");
- }
- return workbook.getSheetName(sheet);
+ validateSheetIndex(sheetIx);
+ return workbook.getSheetName(sheetIx);
}
/**
* check whether a sheet is hidden
- * @param sheet Number
+ * @param sheetIx Number
* @return True if sheet is hidden
*/
-
- public boolean isSheetHidden(int sheet) {
- if (sheet > (sheets.size() - 1))
- {
- throw new RuntimeException("Sheet out of bounds");
- }
- return workbook.isSheetHidden(sheet);
+ public boolean isSheetHidden(int sheetIx) {
+ validateSheetIndex(sheetIx);
+ return workbook.isSheetHidden(sheetIx);
}
/**
* Hide or unhide a sheet
*
- * @param sheetnum The sheet number
+ * @param sheetIx The sheet index
* @param hidden True to mark the sheet as hidden, false otherwise
*/
-
- public void setSheetHidden(int sheet, boolean hidden) {
- if (sheet > (sheets.size() - 1))
- {
- throw new RuntimeException("Sheet out of bounds");
- }
- workbook.setSheetHidden(sheet,hidden);
+ public void setSheetHidden(int sheetIx, boolean hidden) {
+ validateSheetIndex(sheetIx);
+ workbook.setSheetHidden(sheetIx, hidden);
}
/*
/** Returns the index of the given sheet
* @param sheet the sheet to look up
- * @return index of the sheet (0 based)
+ * @return index of the sheet (0 based). <tt>-1</tt> if not found
*/
public int getSheetIndex(org.apache.poi.ss.usermodel.Sheet sheet)
{
- for(int i=0; i<sheets.size(); i++) {
- if(sheets.get(i) == sheet) {
+ for(int i=0; i<_sheets.size(); i++) {
+ if(_sheets.get(i) == sheet) {
return i;
}
}
{
HSSFSheet sheet = new HSSFSheet(this);
- sheets.add(sheet);
- workbook.setSheetName(sheets.size() - 1, "Sheet" + (sheets.size() - 1));
- boolean isOnlySheet = sheets.size() == 1;
+ _sheets.add(sheet);
+ workbook.setSheetName(_sheets.size() - 1, "Sheet" + (_sheets.size() - 1));
+ boolean isOnlySheet = _sheets.size() == 1;
sheet.setSelected(isOnlySheet);
sheet.setActive(isOnlySheet);
return sheet;
public HSSFSheet cloneSheet(int sheetNum) {
validateSheetIndex(sheetNum);
- HSSFSheet srcSheet = (HSSFSheet) sheets.get(sheetNum);
+ HSSFSheet srcSheet = (HSSFSheet) _sheets.get(sheetNum);
String srcName = workbook.getSheetName(sheetNum);
HSSFSheet clonedSheet = srcSheet.cloneSheet(this);
clonedSheet.setSelected(false);
clonedSheet.setActive(false);
- sheets.add(clonedSheet);
+ _sheets.add(clonedSheet);
int i = 1;
while (true) {
// Try and find the next sheet name that is unique
//If the sheet name is unique, then set it otherwise move on to the next number.
if (workbook.getSheetIndex(name) == -1) {
- workbook.setSheetName(sheets.size()-1, name);
+ workbook.setSheetName(_sheets.size()-1, name);
break;
}
}
public HSSFSheet createSheet(String sheetname)
{
- if (workbook.doesContainsSheetName( sheetname, sheets.size() ))
+ if (workbook.doesContainsSheetName( sheetname, _sheets.size() ))
throw new IllegalArgumentException( "The workbook already contains a sheet of this name" );
HSSFSheet sheet = new HSSFSheet(this);
- sheets.add(sheet);
- workbook.setSheetName(sheets.size() - 1, sheetname);
- boolean isOnlySheet = sheets.size() == 1;
+ _sheets.add(sheet);
+ workbook.setSheetName(_sheets.size() - 1, sheetname);
+ boolean isOnlySheet = _sheets.size() == 1;
sheet.setSelected(isOnlySheet);
sheet.setActive(isOnlySheet);
return sheet;
public int getNumberOfSheets()
{
- return sheets.size();
+ return _sheets.size();
}
public int getSheetIndexFromExternSheetIndex(int externSheetNumber) {
return workbook.getSheetIndexFromExternSheetIndex(externSheetNumber);
}
+ private HSSFSheet[] getSheets() {
+ HSSFSheet[] result = new HSSFSheet[_sheets.size()];
+ _sheets.toArray(result);
+ return result;
+ }
+
/**
* Get the HSSFSheet object at the given index.
* @param index of the sheet number (0-based physical & logical)
public HSSFSheet getSheetAt(int index)
{
- return (HSSFSheet) sheets.get(index);
+ return (HSSFSheet) _sheets.get(index);
}
/**
{
HSSFSheet retval = null;
- for (int k = 0; k < sheets.size(); k++)
+ for (int k = 0; k < _sheets.size(); k++)
{
String sheetname = workbook.getSheetName(k);
if (sheetname.equalsIgnoreCase(name))
{
- retval = (HSSFSheet) sheets.get(k);
+ retval = (HSSFSheet) _sheets.get(k);
}
}
return retval;
boolean wasActive = getSheetAt(index).isActive();
boolean wasSelected = getSheetAt(index).isSelected();
- sheets.remove(index);
+ _sheets.remove(index);
workbook.removeSheet(index);
// set the remaining active/selected sheet
- int nSheets = sheets.size();
+ int nSheets = _sheets.size();
if (nSheets < 1) {
// nothing more to do if there are no sheets left
return;
public byte[] getBytes()
{
- if (log.check( POILogger.DEBUG ))
+ if (log.check( POILogger.DEBUG )) {
log.log(DEBUG, "HSSFWorkbook.getBytes()");
+ }
+
+ HSSFSheet[] sheets = getSheets();
+ int nSheets = sheets.length;
// before getting the workbook size we must tell the sheets that
// serialization is about to occur.
- for (int k = 0; k < sheets.size(); k++)
- ((HSSFSheet) sheets.get(k)).getSheet().preSerialize();
-
- int wbsize = workbook.getSize();
+ for (int i = 0; i < nSheets; i++) {
+ sheets[i].getSheet().preSerialize();
+ }
- // log.debug("REMOVEME: old sizing method "+workbook.serialize().length);
- // ArrayList sheetbytes = new ArrayList(sheets.size());
- int totalsize = wbsize;
+ int totalsize = workbook.getSize();
- for (int k = 0; k < sheets.size(); k++)
- {
+ // pre-calculate all the sheet sizes and set BOF indexes
+ int[] estimatedSheetSizes = new int[nSheets];
+ for (int k = 0; k < nSheets; k++) {
workbook.setSheetBof(k, totalsize);
- totalsize += ((HSSFSheet) sheets.get(k)).getSheet().getSize();
+ int sheetSize = sheets[k].getSheet().getSize();
+ estimatedSheetSizes[k] = sheetSize;
+ totalsize += sheetSize;
}
-/* if (totalsize < 4096)
- {
- totalsize = 4096;
- }*/
byte[] retval = new byte[totalsize];
int pos = workbook.serialize(0, retval);
- // System.arraycopy(wb, 0, retval, 0, wb.length);
- for (int k = 0; k < sheets.size(); k++)
- {
-
- // byte[] sb = (byte[])sheetbytes.get(k);
- // System.arraycopy(sb, 0, retval, pos, sb.length);
- int len = ((HSSFSheet) sheets.get(k)).getSheet().serialize(pos,
- retval);
- pos += len; // sb.length;
+ for (int k = 0; k < nSheets; k++) {
+ int serializedSize = sheets[k].getSheet().serialize(pos, retval);
+ if (serializedSize != estimatedSheetSizes[k]) {
+ // Wrong offset values have been passed in the call to setSheetBof() above.
+ // For books with more than one sheet, this discrepancy would cause excel
+ // to report errors and loose data while reading the workbook
+ throw new IllegalStateException("Actual serialized sheet size (" + serializedSize
+ + ") differs from pre-calculated size (" + estimatedSheetSizes[k]
+ + ") for sheet (" + k + ")");
+ // TODO - add similar sanity check to ensure that Sheet.serializeIndexRecord() does not write mis-aligned offsets either
+ }
+ pos += serializedSize;
}
-/* for (int k = pos; k < totalsize; k++)
- {
- retval[k] = 0;
- }*/
return retval;
}
limitations under the License.
==================================================================== */
-
package org.apache.poi.hssf.util;
import java.util.ArrayList;
import java.util.StringTokenizer;
+import org.apache.poi.hssf.record.formula.AreaI;
+
public final class AreaReference {
/** The character (!) that separates sheet names from cell references */
// Special handling for whole-column references
if(parts.length == 2 && parts[0].length() == 1 &&
- parts[1].length() == 1 &&
- parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
- parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
- // Represented internally as x$1 to x$65536
- // which is the maximum range of rows
- parts[0] = parts[0] + "$1";
- parts[1] = parts[1] + "$65536";
+ parts[1].length() == 1 &&
+ parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
+ parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
+ // Represented internally as x$1 to x$65536
+ // which is the maximum range of rows
+ parts[0] = parts[0] + "$1";
+ parts[1] = parts[1] + "$65536";
}
_firstCell = new CellReference(parts[0]);
* Creates an area ref from a pair of Cell References.
*/
public AreaReference(CellReference topLeft, CellReference botRight) {
- _firstCell = topLeft;
- _lastCell = botRight;
- _isSingleCell = false;
+ _firstCell = topLeft;
+ _lastCell = botRight;
+ _isSingleCell = false;
}
/**
* such as C:C or D:G ?
*/
public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) {
- // These are represented as something like
- // C$1:C$65535 or D$1:F$0
- // i.e. absolute from 1st row to 0th one
- if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() &&
- botRight.getRow() == 65535 && botRight.isRowAbsolute()) {
- return true;
- }
- return false;
+ // These are represented as something like
+ // C$1:C$65535 or D$1:F$0
+ // i.e. absolute from 1st row to 0th one
+ if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() &&
+ botRight.getRow() == 65535 && botRight.isRowAbsolute()) {
+ return true;
+ }
+ return false;
}
public boolean isWholeColumnReference() {
- return isWholeColumnReference(_firstCell, _lastCell);
+ return isWholeColumnReference(_firstCell, _lastCell);
}
/**
* Returns a reference to every cell covered by this area
*/
public CellReference[] getAllReferencedCells() {
- // Special case for single cell reference
- if(_isSingleCell) {
- return new CellReference[] { _firstCell, };
- }
+ // Special case for single cell reference
+ if(_isSingleCell) {
+ return new CellReference[] { _firstCell, };
+ }
- // Interpolate between the two
+ // Interpolate between the two
int minRow = Math.min(_firstCell.getRow(), _lastCell.getRow());
- int maxRow = Math.max(_firstCell.getRow(), _lastCell.getRow());
- int minCol = Math.min(_firstCell.getCol(), _lastCell.getCol());
- int maxCol = Math.max(_firstCell.getCol(), _lastCell.getCol());
+ int maxRow = Math.max(_firstCell.getRow(), _lastCell.getRow());
+ int minCol = Math.min(_firstCell.getCol(), _lastCell.getCol());
+ int maxCol = Math.max(_firstCell.getCol(), _lastCell.getCol());
String sheetName = _firstCell.getSheetName();
-
- ArrayList refs = new ArrayList();
- for(int row=minRow; row<=maxRow; row++) {
- for(int col=minCol; col<=maxCol; col++) {
- CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute());
- refs.add(ref);
- }
- }
- return (CellReference[])refs.toArray(new CellReference[refs.size()]);
+
+ ArrayList refs = new ArrayList();
+ for(int row=minRow; row<=maxRow; row++) {
+ for(int col=minCol; col<=maxCol; col++) {
+ CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute());
+ refs.add(ref);
+ }
+ }
+ return (CellReference[])refs.toArray(new CellReference[refs.size()]);
}
/**
* @return the text representation of this area reference as it would appear in a formula.
*/
public String formatAsString() {
- // Special handling for whole-column references
- if(isWholeColumnReference()) {
- return
- CellReference.convertNumToColString(_firstCell.getCol())
- + ":" +
- CellReference.convertNumToColString(_lastCell.getCol());
- }
-
+ // Special handling for whole-column references
+ if(isWholeColumnReference()) {
+ return
+ CellReference.convertNumToColString(_firstCell.getCol())
+ + ":" +
+ CellReference.convertNumToColString(_lastCell.getCol());
+ }
+
StringBuffer sb = new StringBuffer(32);
sb.append(_firstCell.formatAsString());
if(!_isSingleCell) {
}
return sb.toString();
}
+ /**
+ * Formats a 2-D area as it would appear in a formula. See formatAsString() (no-arg)
+ */
+ public static String formatAsString(AreaI area) {
+ CellReference topLeft = new CellReference(area.getFirstRow(),area.getFirstColumn(),!area.isFirstRowRelative(),!area.isFirstColRelative());
+ CellReference botRight = new CellReference(area.getLastRow(),area.getLastColumn(),!area.isLastRowRelative(),!area.isLastColRelative());
+
+ if(isWholeColumnReference(topLeft, botRight)) {
+ return (new AreaReference(topLeft, botRight)).formatAsString();
+ }
+ return topLeft.formatAsString() + ":" + botRight.formatAsString();
+ }
public String toString() {
StringBuffer sb = new StringBuffer(64);
sb.append(getClass().getName()).append(" [");
limitations under the License.
==================================================================== */
-
package org.apache.poi.hssf.util;
+import java.lang.reflect.Field;
import java.util.Hashtable;
import org.apache.poi.ss.usermodel.Color;
/**
* Intends to provide support for the very evil index to triplet issue and
- * will likely replace the color contants interface for HSSF 2.0.
+ * will likely replace the color constants interface for HSSF 2.0.
* This class contains static inner class members for representing colors.
* Each color has an index (for the standard palette in Excel (tm) ),
* native (RGB) triplet and string triplet. The string triplet is as the
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Brian Sanders (bsanders at risklabs dot com) - full default color palette
*/
-
-public class HSSFColor implements Color
-{
- private final static int PALETTE_SIZE = 56;
- private final static int DISTINCT_COLOR_COUNT = 46;
+public class HSSFColor implements Color {
+ // TODO make subclass instances immutable
/** Creates a new instance of HSSFColor */
-
public HSSFColor()
{
}
* it takes to create it once per request but you will not hold onto it
* if you have none of those requests.
*
- * @return a hashtable containing all colors mapped to their excel-style
- * pallette index
+ * @return a hashtable containing all colors keyed by <tt>Integer</tt> excel-style palette indexes
*/
public final static Hashtable getIndexHash() {
- Hashtable hash = new Hashtable(PALETTE_SIZE);
-
- hash.put(new Integer(HSSFColor.BLACK.index), new HSSFColor.BLACK());
- hash.put(new Integer(HSSFColor.BROWN.index), new HSSFColor.BROWN());
- hash.put(new Integer(HSSFColor.OLIVE_GREEN.index),
- new HSSFColor.OLIVE_GREEN());
- hash.put(new Integer(HSSFColor.DARK_GREEN.index), new HSSFColor.DARK_GREEN());
- hash.put(new Integer(HSSFColor.DARK_TEAL.index), new HSSFColor.DARK_TEAL());
- hash.put(new Integer(HSSFColor.DARK_BLUE.index), new HSSFColor.DARK_BLUE());
- hash.put(new Integer(HSSFColor.DARK_BLUE.index2), new HSSFColor.DARK_BLUE());
- hash.put(new Integer(HSSFColor.INDIGO.index), new HSSFColor.INDIGO());
- hash.put(new Integer(HSSFColor.GREY_80_PERCENT.index),
- new HSSFColor.GREY_80_PERCENT());
- hash.put(new Integer(HSSFColor.ORANGE.index), new HSSFColor.ORANGE());
- hash.put(new Integer(HSSFColor.DARK_YELLOW.index),
- new HSSFColor.DARK_YELLOW());
- hash.put(new Integer(HSSFColor.GREEN.index), new HSSFColor.GREEN());
- hash.put(new Integer(HSSFColor.TEAL.index), new HSSFColor.TEAL());
- hash.put(new Integer(HSSFColor.TEAL.index2), new HSSFColor.TEAL());
- hash.put(new Integer(HSSFColor.BLUE.index), new HSSFColor.BLUE());
- hash.put(new Integer(HSSFColor.BLUE.index2), new HSSFColor.BLUE());
- hash.put(new Integer(HSSFColor.BLUE_GREY.index), new HSSFColor.BLUE_GREY());
- hash.put(new Integer(HSSFColor.GREY_50_PERCENT.index),
- new HSSFColor.GREY_50_PERCENT());
- hash.put(new Integer(HSSFColor.RED.index), new HSSFColor.RED());
- hash.put(new Integer(HSSFColor.LIGHT_ORANGE.index),
- new HSSFColor.LIGHT_ORANGE());
- hash.put(new Integer(HSSFColor.LIME.index), new HSSFColor.LIME());
- hash.put(new Integer(HSSFColor.SEA_GREEN.index), new HSSFColor.SEA_GREEN());
- hash.put(new Integer(HSSFColor.AQUA.index), new HSSFColor.AQUA());
- hash.put(new Integer(HSSFColor.LIGHT_BLUE.index), new HSSFColor.LIGHT_BLUE());
- hash.put(new Integer(HSSFColor.VIOLET.index), new HSSFColor.VIOLET());
- hash.put(new Integer(HSSFColor.VIOLET.index2), new HSSFColor.VIOLET());
- hash.put(new Integer(HSSFColor.GREY_40_PERCENT.index),
- new HSSFColor.GREY_40_PERCENT());
- hash.put(new Integer(HSSFColor.PINK.index), new HSSFColor.PINK());
- hash.put(new Integer(HSSFColor.PINK.index2), new HSSFColor.PINK());
- hash.put(new Integer(HSSFColor.GOLD.index), new HSSFColor.GOLD());
- hash.put(new Integer(HSSFColor.YELLOW.index), new HSSFColor.YELLOW());
- hash.put(new Integer(HSSFColor.YELLOW.index2), new HSSFColor.YELLOW());
- hash.put(new Integer(HSSFColor.BRIGHT_GREEN.index),
- new HSSFColor.BRIGHT_GREEN());
- hash.put(new Integer(HSSFColor.BRIGHT_GREEN.index2),
- new HSSFColor.BRIGHT_GREEN());
- hash.put(new Integer(HSSFColor.TURQUOISE.index), new HSSFColor.TURQUOISE());
- hash.put(new Integer(HSSFColor.TURQUOISE.index2), new HSSFColor.TURQUOISE());
- hash.put(new Integer(HSSFColor.DARK_RED.index), new HSSFColor.DARK_RED());
- hash.put(new Integer(HSSFColor.DARK_RED.index2), new HSSFColor.DARK_RED());
- hash.put(new Integer(HSSFColor.SKY_BLUE.index), new HSSFColor.SKY_BLUE());
- hash.put(new Integer(HSSFColor.PLUM.index), new HSSFColor.PLUM());
- hash.put(new Integer(HSSFColor.PLUM.index2), new HSSFColor.PLUM());
- hash.put(new Integer(HSSFColor.GREY_25_PERCENT.index),
- new HSSFColor.GREY_25_PERCENT());
- hash.put(new Integer(HSSFColor.ROSE.index), new HSSFColor.ROSE());
- hash.put(new Integer(HSSFColor.LIGHT_YELLOW.index),
- new HSSFColor.LIGHT_YELLOW());
- hash.put(new Integer(HSSFColor.LIGHT_GREEN.index),
- new HSSFColor.LIGHT_GREEN());
- hash.put(new Integer(HSSFColor.LIGHT_TURQUOISE.index),
- new HSSFColor.LIGHT_TURQUOISE());
- hash.put(new Integer(HSSFColor.LIGHT_TURQUOISE.index2),
- new HSSFColor.LIGHT_TURQUOISE());
- hash.put(new Integer(HSSFColor.PALE_BLUE.index), new HSSFColor.PALE_BLUE());
- hash.put(new Integer(HSSFColor.LAVENDER.index), new HSSFColor.LAVENDER());
- hash.put(new Integer(HSSFColor.WHITE.index), new HSSFColor.WHITE());
- hash.put(new Integer(HSSFColor.CORNFLOWER_BLUE.index),
- new HSSFColor.CORNFLOWER_BLUE());
- hash.put(new Integer(HSSFColor.LEMON_CHIFFON.index),
- new HSSFColor.LEMON_CHIFFON());
- hash.put(new Integer(HSSFColor.MAROON.index), new HSSFColor.MAROON());
- hash.put(new Integer(HSSFColor.ORCHID.index), new HSSFColor.ORCHID());
- hash.put(new Integer(HSSFColor.CORAL.index), new HSSFColor.CORAL());
- hash.put(new Integer(HSSFColor.ROYAL_BLUE.index), new HSSFColor.ROYAL_BLUE());
- hash.put(new Integer(HSSFColor.LIGHT_CORNFLOWER_BLUE.index),
- new HSSFColor.LIGHT_CORNFLOWER_BLUE());
- return hash;
+ return createColorsByIndexMap();
+ }
+
+ private static Hashtable createColorsByIndexMap() {
+ HSSFColor[] colors = getAllColors();
+ Hashtable result = new Hashtable(colors.length * 3 / 2);
+
+ for (int i = 0; i < colors.length; i++) {
+ HSSFColor color = colors[i];
+
+ Integer index1 = new Integer(color.getIndex());
+ if (result.containsKey(index1)) {
+ HSSFColor prevColor = (HSSFColor)result.get(index1);
+ throw new RuntimeException("Dup color index (" + index1
+ + ") for colors (" + prevColor.getClass().getName()
+ + "),(" + color.getClass().getName() + ")");
+ }
+ result.put(index1, color);
+ }
+
+ for (int i = 0; i < colors.length; i++) {
+ HSSFColor color = colors[i];
+ Integer index2 = getIndex2(color);
+ if (index2 == null) {
+ // most colors don't have a second index
+ continue;
+ }
+ if (result.containsKey(index2)) {
+ if (false) { // Many of the second indexes clash
+ HSSFColor prevColor = (HSSFColor)result.get(index2);
+ throw new RuntimeException("Dup color index (" + index2
+ + ") for colors (" + prevColor.getClass().getName()
+ + "),(" + color.getClass().getName() + ")");
+ }
+ }
+ result.put(index2, color);
+ }
+ return result;
+ }
+
+ private static Integer getIndex2(HSSFColor color) {
+
+ Field f;
+ try {
+ f = color.getClass().getDeclaredField("index2");
+ } catch (NoSuchFieldException e) {
+ // can happen because not all colors have a second index
+ return null;
+ }
+
+ Short s;
+ try {
+ s = (Short) f.get(color);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ return new Integer(s.intValue());
+ }
+
+ private static HSSFColor[] getAllColors() {
+
+ return new HSSFColor[] {
+ new BLACK(), new BROWN(), new OLIVE_GREEN(), new DARK_GREEN(),
+ new DARK_TEAL(), new DARK_BLUE(), new INDIGO(), new GREY_80_PERCENT(),
+ new ORANGE(), new DARK_YELLOW(), new GREEN(), new TEAL(), new BLUE(),
+ new BLUE_GREY(), new GREY_50_PERCENT(), new RED(), new LIGHT_ORANGE(), new LIME(),
+ new SEA_GREEN(), new AQUA(), new LIGHT_BLUE(), new VIOLET(), new GREY_40_PERCENT(),
+ new PINK(), new GOLD(), new YELLOW(), new BRIGHT_GREEN(), new TURQUOISE(),
+ new DARK_RED(), new SKY_BLUE(), new PLUM(), new GREY_25_PERCENT(), new ROSE(),
+ new LIGHT_YELLOW(), new LIGHT_GREEN(), new LIGHT_TURQUOISE(), new PALE_BLUE(),
+ new LAVENDER(), new WHITE(), new CORNFLOWER_BLUE(), new LEMON_CHIFFON(),
+ new MAROON(), new ORCHID(), new CORAL(), new ROYAL_BLUE(),
+ new LIGHT_CORNFLOWER_BLUE(), new TAN(),
+ };
}
/**
* it takes to create it once per request but you will not hold onto it
* if you have none of those requests.
*
- * @return a hashtable containing all colors mapped to their gnumeric-like
- * triplet string
+ * @return a hashtable containing all colors keyed by String gnumeric-like triplets
*/
-
public final static Hashtable getTripletHash()
{
- Hashtable hash = new Hashtable(DISTINCT_COLOR_COUNT);
-
- hash.put(HSSFColor.BLACK.hexString, new HSSFColor.BLACK());
- hash.put(HSSFColor.BROWN.hexString, new HSSFColor.BROWN());
- hash.put(HSSFColor.OLIVE_GREEN.hexString,
- new HSSFColor.OLIVE_GREEN());
- hash.put(HSSFColor.DARK_GREEN.hexString, new HSSFColor.DARK_GREEN());
- hash.put(HSSFColor.DARK_TEAL.hexString, new HSSFColor.DARK_TEAL());
- hash.put(HSSFColor.DARK_BLUE.hexString, new HSSFColor.DARK_BLUE());
- hash.put(HSSFColor.INDIGO.hexString, new HSSFColor.INDIGO());
- hash.put(HSSFColor.GREY_80_PERCENT.hexString,
- new HSSFColor.GREY_80_PERCENT());
- hash.put(HSSFColor.ORANGE.hexString, new HSSFColor.ORANGE());
- hash.put(HSSFColor.DARK_YELLOW.hexString,
- new HSSFColor.DARK_YELLOW());
- hash.put(HSSFColor.GREEN.hexString, new HSSFColor.GREEN());
- hash.put(HSSFColor.TEAL.hexString, new HSSFColor.TEAL());
- hash.put(HSSFColor.BLUE.hexString, new HSSFColor.BLUE());
- hash.put(HSSFColor.BLUE_GREY.hexString, new HSSFColor.BLUE_GREY());
- hash.put(HSSFColor.GREY_50_PERCENT.hexString,
- new HSSFColor.GREY_50_PERCENT());
- hash.put(HSSFColor.RED.hexString, new HSSFColor.RED());
- hash.put(HSSFColor.LIGHT_ORANGE.hexString,
- new HSSFColor.LIGHT_ORANGE());
- hash.put(HSSFColor.LIME.hexString, new HSSFColor.LIME());
- hash.put(HSSFColor.SEA_GREEN.hexString, new HSSFColor.SEA_GREEN());
- hash.put(HSSFColor.AQUA.hexString, new HSSFColor.AQUA());
- hash.put(HSSFColor.LIGHT_BLUE.hexString, new HSSFColor.LIGHT_BLUE());
- hash.put(HSSFColor.VIOLET.hexString, new HSSFColor.VIOLET());
- hash.put(HSSFColor.GREY_40_PERCENT.hexString,
- new HSSFColor.GREY_40_PERCENT());
- hash.put(HSSFColor.PINK.hexString, new HSSFColor.PINK());
- hash.put(HSSFColor.GOLD.hexString, new HSSFColor.GOLD());
- hash.put(HSSFColor.YELLOW.hexString, new HSSFColor.YELLOW());
- hash.put(HSSFColor.BRIGHT_GREEN.hexString,
- new HSSFColor.BRIGHT_GREEN());
- hash.put(HSSFColor.TURQUOISE.hexString, new HSSFColor.TURQUOISE());
- hash.put(HSSFColor.DARK_RED.hexString, new HSSFColor.DARK_RED());
- hash.put(HSSFColor.SKY_BLUE.hexString, new HSSFColor.SKY_BLUE());
- hash.put(HSSFColor.PLUM.hexString, new HSSFColor.PLUM());
- hash.put(HSSFColor.GREY_25_PERCENT.hexString,
- new HSSFColor.GREY_25_PERCENT());
- hash.put(HSSFColor.ROSE.hexString, new HSSFColor.ROSE());
- hash.put(HSSFColor.LIGHT_YELLOW.hexString,
- new HSSFColor.LIGHT_YELLOW());
- hash.put(HSSFColor.LIGHT_GREEN.hexString,
- new HSSFColor.LIGHT_GREEN());
- hash.put(HSSFColor.LIGHT_TURQUOISE.hexString,
- new HSSFColor.LIGHT_TURQUOISE());
- hash.put(HSSFColor.PALE_BLUE.hexString, new HSSFColor.PALE_BLUE());
- hash.put(HSSFColor.LAVENDER.hexString, new HSSFColor.LAVENDER());
- hash.put(HSSFColor.WHITE.hexString, new HSSFColor.WHITE());
- hash.put(HSSFColor.CORNFLOWER_BLUE.hexString, new HSSFColor.CORNFLOWER_BLUE());
- hash.put(HSSFColor.LEMON_CHIFFON.hexString, new HSSFColor.LEMON_CHIFFON());
- hash.put(HSSFColor.MAROON.hexString, new HSSFColor.MAROON());
- hash.put(HSSFColor.ORCHID.hexString, new HSSFColor.ORCHID());
- hash.put(HSSFColor.CORAL.hexString, new HSSFColor.CORAL());
- hash.put(HSSFColor.ROYAL_BLUE.hexString, new HSSFColor.ROYAL_BLUE());
- hash.put(HSSFColor.LIGHT_CORNFLOWER_BLUE.hexString,
- new HSSFColor.LIGHT_CORNFLOWER_BLUE());
- return hash;
+ return createColorsByHexStringMap();
+ }
+
+ private static Hashtable createColorsByHexStringMap() {
+ HSSFColor[] colors = getAllColors();
+ Hashtable result = new Hashtable(colors.length * 3 / 2);
+
+ for (int i = 0; i < colors.length; i++) {
+ HSSFColor color = colors[i];
+
+ String hexString = color.getHexString();
+ if (result.containsKey(hexString)) {
+ throw new RuntimeException("Dup color hexString (" + hexString
+ + ") for color (" + color.getClass().getName() + ")");
+ }
+ result.put(hexString, color);
+ }
+ return result;
}
/**
return hexString;
}
}
-
+
/**
* Class CORNFLOWER_BLUE
*/
return hexString;
}
}
-
-
+
+
/**
* Class LEMON_CHIFFON
*/
return hexString;
}
}
-
+
/**
* Class MAROON
*/
return hexString;
}
}
-
+
/**
* Class ORCHID
*/
return hexString;
}
}
-
+
/**
* Class CORAL
*/
return hexString;
}
}
-
+
/**
* Class ROYAL_BLUE
*/
return hexString;
}
}
-
+
/**
* Class LIGHT_CORNFLOWER_BLUE
*/
return hexString;
}
}
-
+
/**
* Special Default/Normal/Automatic color.
* <p><i>Note:</i> This class is NOT in the default HashTables returned by HSSFColor.
* The index is a special case which is interpreted in the various setXXXColor calls.
- *
+ *
* @author Jason
*
*/
public final static class AUTOMATIC extends HSSFColor
{
- private static HSSFColor instance = new AUTOMATIC();
-
+ private static HSSFColor instance = new AUTOMATIC();
+
public final static short index = 0x40;
public short getIndex()
{
return BLACK.hexString;
}
-
+
public static HSSFColor getInstance() {
return instance;
}
// Otherwise, check it's only made up, in any case, of:
// y m d h s - / , . :
- if(fs.matches("^[yYmMdDhHsS\\-/,. :]+$")) {
+ // optionally followed by AM/PM
+ // optionally followed by AM/PM
+ if(fs.matches("^[yYmMdDhHsS\\-/,. :]+[ampAMP]*$")) {
return true;
}
# limitations under the License.\r
\r
# Created by (org.apache.poi.hssf.record.formula.function.ExcelFileFormatDocFunctionExtractor)\r
-# from source file 'excelfileformat.odt' (size=355750, crc=0x2FAEA65A)\r
+# from source file 'excelfileformat.odt' (size=356107, md5=0x8f789cb6e75594caf068f8e193004ef4)\r
#\r
#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )\r
\r
15 SIN 1 1 V V \r
16 COS 1 1 V V \r
17 TAN 1 1 V V \r
-18 ARCTAN 1 1 V V \r
+18 ATAN 1 1 V V \r
19 PI 0 0 V - \r
20 SQRT 1 1 V V \r
21 EXP 1 1 V V \r
169 COUNTA 0 30 V R \r
183 PRODUCT 0 30 V R \r
184 FACT 1 1 V V \r
-191 DPRODUCT 3 3 V R R R \r
-192 ISNONTEXT 1 1 V V \r
+189 DPRODUCT 3 3 V R R R \r
+190 ISNONTEXT 1 1 V V \r
193 STDEVP 1 30 V R \r
194 VARP 1 30 V R \r
195 DSTDEVP 3 3 V R R R \r
244 INFO 1 1 V V \r
# New Built-In Sheet Functions in BIFF4\r
14 FIXED 2 3 V V V V x\r
+204 USDOLLAR 1 2 V V V x\r
+215 DBCS 1 1 V V x\r
216 RANK 2 3 V V R V \r
247 DB 4 5 V V V V V V \r
252 FREQUENCY 2 2 A R R \r
# limitations under the License.\r
\r
# Created by (org.apache.poi.hssf.record.formula.function.ExcelFileFormatDocFunctionExtractor)\r
-# from source file 'excelfileformat.odt' (size=355750, crc=0x2FAEA65A)\r
+# from source file 'excelfileformat.odt' (size=356107, md5=0x8f789cb6e75594caf068f8e193004ef4)\r
#\r
#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )\r
-#\r
-# + some manual edits !\r
\r
# Built-In Sheet Functions in BIFF2\r
0 COUNT 0 30 V R \r
244 INFO 1 1 V V \r
# New Built-In Sheet Functions in BIFF4\r
14 FIXED 2 3 V V V V x\r
-204 USDOLLAR 1 1 V V x\r
+204 USDOLLAR 1 2 V V V x\r
215 DBCS 1 1 V V x\r
216 RANK 2 3 V V R V \r
247 DB 4 5 V V V V V V \r
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.OutputStream;
import org.apache.poi.POIDocument;
import org.apache.poi.hdgf.chunks.ChunkFactory;
import org.apache.poi.hdgf.streams.Stream;
import org.apache.poi.hdgf.streams.StringsStream;
import org.apache.poi.hdgf.streams.TrailerStream;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.LittleEndian;
private PointerFactory ptrFactory;
public HDGFDiagram(POIFSFileSystem fs) throws IOException {
- super(fs);
+ this(fs.getRoot(), fs);
+ }
+ public HDGFDiagram(DirectoryNode dir, POIFSFileSystem fs) throws IOException {
+ super(dir, fs);
DocumentEntry docProps =
- (DocumentEntry)filesystem.getRoot().getEntry("VisioDocument");
+ (DocumentEntry)dir.getEntry("VisioDocument");
// Grab the document stream
_docstream = new byte[docProps.getSize()];
- filesystem.createDocumentInputStream("VisioDocument").read(_docstream);
+ dir.createDocumentInputStream("VisioDocument").read(_docstream);
// Read in the common POI streams
readProperties();
}
}
+ public void write(OutputStream out) {
+ throw new IllegalStateException("Writing is not yet implemented, see http://poi.apache.org/hdgf/");
+ }
+
/**
* For testing only
*/
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
/**
* This class holds all the FSPA (File Shape Address) structures.
*
* @author Squeeself
*/
-public class FSPATable
+public final class FSPATable
{
- protected ArrayList shapes = new ArrayList();
- protected HashMap cps = new HashMap();
- protected List _text;
+ private final List _shapes = new ArrayList();
+ private final Map _shapeIndexesByPropertyStart = new HashMap();
+ private final List _text;
public FSPATable(byte[] tableStream, int fcPlcspa, int lcbPlcspa, List tpt)
{
GenericPropertyNode property = plex.getProperty(i);
FSPA fspa = new FSPA(property.getBytes(), 0);
- shapes.add(fspa);
- cps.put(Integer.valueOf(property.getStart()), Integer.valueOf(i));
+ _shapes.add(fspa);
+ _shapeIndexesByPropertyStart.put(new Integer(property.getStart()), new Integer(i));
}
}
public FSPA getFspaFromCp(int cp)
{
- Integer idx = (Integer)cps.get(Integer.valueOf(cp));
- if (idx == null)
+ Integer idx = (Integer)_shapeIndexesByPropertyStart.get(new Integer(cp));
+ if (idx == null) {
return null;
- return (FSPA)shapes.get(idx.intValue());
+ }
+ return (FSPA)_shapes.get(idx.intValue());
}
- public List getShapes()
+ public FSPA[] getShapes()
{
- return shapes;
+ FSPA[] result = new FSPA[_shapes.size()];
+ _shapes.toArray(result);
+ return result;
}
public String toString()
{
StringBuffer buf = new StringBuffer();
- buf.append("[FPSA PLC size=").append(shapes.size()).append("]\n");
- for (Iterator it = cps.keySet().iterator(); it.hasNext(); )
+ buf.append("[FPSA PLC size=").append(_shapes.size()).append("]\n");
+ for (Iterator it = _shapeIndexesByPropertyStart.keySet().iterator(); it.hasNext(); )
{
Integer i = (Integer) it.next();
- FSPA fspa = (FSPA) shapes.get(((Integer)cps.get(i)).intValue());
+ FSPA fspa = (FSPA) _shapes.get(((Integer)_shapeIndexesByPropertyStart.get(i)).intValue());
buf.append(" [FC: ").append(i.toString()).append("] ");
buf.append(fspa.toString());
buf.append("\n");
_longHandler.setLong(FIBLongHandler.CBMAC, cbMac);
}
+ public int getCcpText()
+ {
+ return _longHandler.getLong(FIBLongHandler.CCPTEXT);
+ }
+
+ public void setCcpText(int ccpText)
+ {
+ _longHandler.setLong(FIBLongHandler.CCPTEXT, ccpText);
+ }
+
public void clearOffsetsSizes()
{
_fieldHandler.clearFields();
public void adjustForDelete(int start, int length)
{
+
+ if (usesUnicode()) {
+
+ start /= 2;
+ length /= 2;
+ }
+
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);
}
}
+ /**
+ * Does any <code>TextPiece</code> in this Range use unicode?
+ *
+ * @return true if it does and false if it doesn't
+ */
+ public boolean usesUnicode() {
+
+ initText();
+
+ for (int i = _textStart; i < _textEnd; i++)
+ {
+ TextPiece piece = (TextPiece)_text.get(i);
+ if (piece.usesUnicode())
+ return true;
+ }
+
+ return false;
+ }
+
/**
* Gets the text that this Range contains.
*
// Since this is the first item in our list, it is safe to assume that
// _start >= tp.getStart()
int insertIndex = _start - tp.getStart();
+ if (tp.usesUnicode())
+ insertIndex /= 2;
sb.insert(insertIndex, text);
+
int adjustedLength = _doc.getTextTable().adjustForInsert(_textStart, text.length());
_doc.getCharacterTable().adjustForInsert(_charStart, adjustedLength);
_doc.getParagraphTable().adjustForInsert(_parStart, adjustedLength);
_doc.getSectionTable().adjustForInsert(_sectionStart, adjustedLength);
adjustForInsert(text.length());
+ // update the FIB.CCPText field
+ adjustFIB(text.length());
+
return getCharacterRun(0);
}
public void delete()
{
+
initAll();
int numSections = _sections.size();
TextPiece piece = (TextPiece)_text.get(x);
piece.adjustForDelete(_start, _end - _start);
}
+
+ // update the FIB.CCPText field
+ if (usesUnicode())
+ adjustFIB(-((_end - _start) / 2));
+ else
+ adjustFIB(-(_end - _start));
}
/**
_sectionRangeFound = false;
}
+ /**
+ * Adjust the value of <code>FIB.CCPText</code> after an insert or a delete...
+ *
+ * @param adjustment The (signed) value that should be added to <code>FIB.CCPText</code>
+ */
+ protected void adjustFIB(int adjustment) {
+
+ // update the FIB.CCPText field (this should happen once per adjustment, so we don't want it in
+ // adjustForInsert() or it would get updated multiple times if the range has a parent)
+ // without this, OpenOffice.org (v. 2.2.x) does not see all the text in the document
+ _doc.getFileInformationBlock().setCcpText(_doc.getFileInformationBlock().getCcpText() + adjustment);
+ }
+
/**
* adjust this range after an insert happens.
* @param length the length to adjust for
private void adjustForInsert(int length)
{
_end += length;
+
reset();
Range parent = (Range)_parent.get();
if (parent != null)
}
}
+
+ public int getStartOffset() {
+
+ return _start;
+ }
+
+ public int getEndOffset() {
+
+ return _end;
+ }
}
/**
* Test the low level formula parser functionality. High level tests are to
- * be done via usermodel/HSSFCell.setFormulaValue() .
- * Some tests are also done in scratchpad, if they need
- * HSSFFormulaEvaluator, which is there
+ * be done via usermodel/HSSFCell.setFormulaValue().
*/
public final class TestFormulaParser extends TestCase {
- /**
- * @return parsed token array already confirmed not <code>null</code>
- */
- private static Ptg[] parseFormula(String s) {
- // TODO - replace multiple copies of this code with calls to this method
- FormulaParser fp = new FormulaParser(s, null);
- fp.parse();
- Ptg[] result = fp.getRPNPtg();
- assertNotNull("Ptg array should not be null", result);
- return result;
- }
-
- public void testSimpleFormula() {
- FormulaParser fp = new FormulaParser("2+2",null);
- fp.parse();
- Ptg[] ptgs = fp.getRPNPtg();
- assertTrue("three tokens expected, got "+ptgs.length,ptgs.length == 3);
- }
- public void testFormulaWithSpace1() {
- FormulaParser fp = new FormulaParser(" 2 + 2 ",null);
- fp.parse();
- Ptg[] ptgs = fp.getRPNPtg();
- assertTrue("three tokens expected, got "+ptgs.length,ptgs.length == 3);
- assertTrue("",(ptgs[0] instanceof IntPtg));
- assertTrue("",(ptgs[1] instanceof IntPtg));
- assertTrue("",(ptgs[2] instanceof AddPtg));
- }
-
- public void testFormulaWithSpace2() {
- Ptg[] ptgs;
- FormulaParser fp;
- fp = new FormulaParser("2+ sum( 3 , 4) ",null);
- fp.parse();
- ptgs = fp.getRPNPtg();
- assertTrue("five tokens expected, got "+ptgs.length,ptgs.length == 5);
- }
-
- public void testFormulaWithSpaceNRef() {
- Ptg[] ptgs;
- FormulaParser fp;
- fp = new FormulaParser("sum( A2:A3 )",null);
- fp.parse();
- ptgs = fp.getRPNPtg();
- assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2);
- }
-
- public void testFormulaWithString() {
- Ptg[] ptgs;
- FormulaParser fp;
- fp = new FormulaParser("\"hello\" & \"world\" ",null);
- fp.parse();
- ptgs = fp.getRPNPtg();
- assertTrue("three token expected, got " + ptgs.length, ptgs.length == 3);
- }
-
- public void testTRUE() throws Exception {
- FormulaParser fp = new FormulaParser("TRUE", null);
- fp.parse();
- Ptg[] asts = fp.getRPNPtg();
- assertEquals(1, asts.length);
- BoolPtg flag = (BoolPtg) asts[0];
- assertEquals(true, flag.getValue());
- }
-
- public void testYN() throws Exception {
- final String yn = "IF(TRUE,\"Y\",\"N\")";
- FormulaParser fp = new FormulaParser(yn, null);
- fp.parse();
- Ptg[] asts = fp.getRPNPtg();
- assertEquals(7, asts.length);
-
- BoolPtg flag = (BoolPtg) asts[0];
- AttrPtg funif = (AttrPtg) asts[1];
- StringPtg y = (StringPtg) asts[2];
- AttrPtg goto1 = (AttrPtg) asts[3];
- StringPtg n = (StringPtg) asts[4];
-
-
- assertEquals(true, flag.getValue());
- assertEquals("Y", y.getValue());
- assertEquals("N", n.getValue());
- assertEquals("IF", funif.toFormulaString((HSSFWorkbook) null));
- assertTrue("Goto ptg exists", goto1.isGoto());
- }
-
- public void testSimpleIf() throws Exception {
- final String simpleif = "IF(1=1,0,1)";
- FormulaParser fp = new FormulaParser(simpleif, null);
+ /**
+ * @return parsed token array already confirmed not <code>null</code>
+ */
+ private static Ptg[] parseFormula(String s) {
+ FormulaParser fp = new FormulaParser(s, null);
fp.parse();
- Ptg[] asts = fp.getRPNPtg();
- assertEquals(9, asts.length);
-
- IntPtg op1 = (IntPtg) asts[0];
- IntPtg op2 = (IntPtg) asts[1];
- EqualPtg eq = (EqualPtg) asts[2];
- AttrPtg ifPtg = (AttrPtg) asts[3];
- IntPtg res1 = (IntPtg) asts[4];
-
- AttrPtg ptgGoto= (AttrPtg) asts[5];
- assertEquals("Goto 1 Length", (short)10, ptgGoto.getData());
-
- IntPtg res2 = (IntPtg) asts[6];
- AttrPtg ptgGoto2 = (AttrPtg) asts[7];
- assertEquals("Goto 2 Length", (short)3, ptgGoto2.getData());
-
- assertEquals("If FALSE offset", (short)7, ifPtg.getData());
+ Ptg[] result = fp.getRPNPtg();
+ assertNotNull("Ptg array should not be null", result);
+ return result;
+ }
+
+ public void testSimpleFormula() {
+ Ptg[] ptgs = parseFormula("2+2");
+ assertEquals(3, ptgs.length);
+ }
+
+ public void testFormulaWithSpace1() {
+ Ptg[] ptgs = parseFormula(" 2 + 2 ");
+ assertEquals(3, ptgs.length);
+ assertTrue("",(ptgs[0] instanceof IntPtg));
+ assertTrue("",(ptgs[1] instanceof IntPtg));
+ assertTrue("",(ptgs[2] instanceof AddPtg));
+ }
+
+ public void testFormulaWithSpace2() {
+ Ptg[] ptgs = parseFormula("2+ sum( 3 , 4) ");
+ assertEquals(5, ptgs.length);
+ }
+
+ public void testFormulaWithSpaceNRef() {
+ Ptg[] ptgs = parseFormula("sum( A2:A3 )");
+ assertEquals(2, ptgs.length);
+ }
+
+ public void testFormulaWithString() {
+ Ptg[] ptgs = parseFormula("\"hello\" & \"world\" ");
+ assertEquals(3, ptgs.length);
+ }
+
+ public void testTRUE() {
+ Ptg[] ptgs = parseFormula("TRUE");
+ assertEquals(1, ptgs.length);
+ BoolPtg flag = (BoolPtg) ptgs[0];
+ assertEquals(true, flag.getValue());
+ }
+
+ public void testYN() {
+ Ptg[] ptgs = parseFormula("IF(TRUE,\"Y\",\"N\")");
+ assertEquals(7, ptgs.length);
+
+ BoolPtg flag = (BoolPtg) ptgs[0];
+ AttrPtg funif = (AttrPtg) ptgs[1];
+ StringPtg y = (StringPtg) ptgs[2];
+ AttrPtg goto1 = (AttrPtg) ptgs[3];
+ StringPtg n = (StringPtg) ptgs[4];
+
+
+ assertEquals(true, flag.getValue());
+ assertEquals("Y", y.getValue());
+ assertEquals("N", n.getValue());
+ assertEquals("IF", funif.toFormulaString((HSSFWorkbook) null));
+ assertTrue("Goto ptg exists", goto1.isGoto());
+ }
+
+ public void testSimpleIf() {
+ String formula = "IF(1=1,0,1)";
+
+ Class[] expectedClasses = {
+ IntPtg.class,
+ IntPtg.class,
+ EqualPtg.class,
+ AttrPtg.class,
+ IntPtg.class,
+ AttrPtg.class,
+ IntPtg.class,
+ AttrPtg.class,
+ FuncVarPtg.class,
+ };
+ confirmTokenClasses(formula, expectedClasses);
- FuncVarPtg funcPtg = (FuncVarPtg)asts[8];
+ Ptg[] ptgs = parseFormula(formula);
+
+ AttrPtg ifPtg = (AttrPtg) ptgs[3];
+ AttrPtg ptgGoto= (AttrPtg) ptgs[5];
+ assertEquals("Goto 1 Length", 10, ptgGoto.getData());
+
+ AttrPtg ptgGoto2 = (AttrPtg) ptgs[7];
+ assertEquals("Goto 2 Length", 3, ptgGoto2.getData());
+ assertEquals("If FALSE offset", 7, ifPtg.getData());
}
/**
*
*/
public void testNestedFunctionIf() {
- String function = "IF(A1=B1,AVERAGE(A1:B1),AVERAGE(A2:B2))";
+ Ptg[] ptgs = parseFormula("IF(A1=B1,AVERAGE(A1:B1),AVERAGE(A2:B2))");
+ assertEquals(11, ptgs.length);
- FormulaParser fp = new FormulaParser(function, null);
- fp.parse();
- Ptg[] asts = fp.getRPNPtg();
- assertEquals("11 Ptgs expected", 11, asts.length);
-
- assertTrue("IF Attr set correctly", (asts[3] instanceof AttrPtg));
- AttrPtg ifFunc = (AttrPtg)asts[3];
+ assertTrue("IF Attr set correctly", (ptgs[3] instanceof AttrPtg));
+ AttrPtg ifFunc = (AttrPtg)ptgs[3];
assertTrue("It is not an if", ifFunc.isOptimizedIf());
-
- assertTrue("Average Function set correctly", (asts[5] instanceof FuncVarPtg));
+
+ assertTrue("Average Function set correctly", (ptgs[5] instanceof FuncVarPtg));
}
-
- public void testIfSingleCondition(){
- String function = "IF(1=1,10)";
- FormulaParser fp = new FormulaParser(function, null);
- fp.parse();
- Ptg[] asts = fp.getRPNPtg();
- assertEquals("7 Ptgs expected", 7, asts.length);
+ public void testIfSingleCondition(){
+ Ptg[] ptgs = parseFormula("IF(1=1,10)");
+ assertEquals(7, ptgs.length);
- assertTrue("IF Attr set correctly", (asts[3] instanceof AttrPtg));
- AttrPtg ifFunc = (AttrPtg)asts[3];
+ assertTrue("IF Attr set correctly", (ptgs[3] instanceof AttrPtg));
+ AttrPtg ifFunc = (AttrPtg)ptgs[3];
assertTrue("It is not an if", ifFunc.isOptimizedIf());
-
- assertTrue("Single Value is not an IntPtg", (asts[4] instanceof IntPtg));
- IntPtg intPtg = (IntPtg)asts[4];
+
+ assertTrue("Single Value is not an IntPtg", (ptgs[4] instanceof IntPtg));
+ IntPtg intPtg = (IntPtg)ptgs[4];
assertEquals("Result", (short)10, intPtg.getValue());
-
- assertTrue("Ptg is not a Variable Function", (asts[6] instanceof FuncVarPtg));
- FuncVarPtg funcPtg = (FuncVarPtg)asts[6];
+
+ assertTrue("Ptg is not a Variable Function", (ptgs[6] instanceof FuncVarPtg));
+ FuncVarPtg funcPtg = (FuncVarPtg)ptgs[6];
assertEquals("Arguments", 2, funcPtg.getNumberOfOperands());
}
public void testSumIf() {
- String function ="SUMIF(A1:A5,\">4000\",B1:B5)";
- FormulaParser fp = new FormulaParser(function, null);
- fp.parse();
- Ptg[] asts = fp.getRPNPtg();
- assertEquals("4 Ptgs expected", 4, asts.length);
+ Ptg[] ptgs = parseFormula("SUMIF(A1:A5,\">4000\",B1:B5)");
+ assertEquals(4, ptgs.length);
}
-
+
/**
* Bug Reported by xt-jens.riis@nokia.com (Jens Riis)
* Refers to Bug <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=17582">#17582</a>
*
*/
- public void testNonAlphaFormula(){
+ public void testNonAlphaFormula() {
String currencyCell = "F3";
- String function="\"TOTAL[\"&"+currencyCell+"&\"]\"";
+ Ptg[] ptgs = parseFormula("\"TOTAL[\"&"+currencyCell+"&\"]\"");
+ assertEquals(5, ptgs.length);
+ assertTrue ("Ptg[0] is a string", (ptgs[0] instanceof StringPtg));
+ StringPtg firstString = (StringPtg)ptgs[0];
- Ptg[] asts = parseFormula(function);
- assertEquals("5 ptgs expected", 5, asts.length);
- assertTrue ("Ptg[0] is a string", (asts[0] instanceof StringPtg));
- StringPtg firstString = (StringPtg)asts[0];
-
assertEquals("TOTAL[", firstString.getValue());
//the PTG order isn't 100% correct but it still works - dmui
}
public void testSimpleLogical() {
- Ptg[] ptgs = parseFormula("IF(A1<A2,B1,B2)");
- assertEquals("Ptg array length", 9, ptgs.length);
- assertEquals("3rd Ptg is less than", LessThanPtg.class, ptgs[2].getClass());
+ Ptg[] ptgs = parseFormula("IF(A1<A2,B1,B2)");
+ assertEquals(9, ptgs.length);
+ assertEquals("3rd Ptg is less than", LessThanPtg.class, ptgs[2].getClass());
}
-
+
public void testParenIf() {
Ptg[] ptgs = parseFormula("IF((A1+A2)<=3,\"yes\",\"no\")");
- assertEquals("Ptg array length", 12, ptgs.length);
+ assertEquals(12, ptgs.length);
assertEquals("6th Ptg is less than equal",LessEqualPtg.class,ptgs[5].getClass());
assertEquals("11th Ptg is not a goto (Attr) ptg",AttrPtg.class,ptgs[10].getClass());
}
-
+
public void testEmbeddedIf() {
Ptg[] ptgs = parseFormula("IF(3>=1,\"*\",IF(4<>1,\"first\",\"second\"))");
- assertEquals("Ptg array length", 17, ptgs.length);
-
+ assertEquals(17, ptgs.length);
+
assertEquals("6th Ptg is not a goto (Attr) ptg",AttrPtg.class,ptgs[5].getClass());
assertEquals("9th Ptg is not a not equal ptg",NotEqualPtg.class,ptgs[8].getClass());
assertEquals("15th Ptg is not the inner IF variable function ptg",FuncVarPtg.class,ptgs[14].getClass());
}
-
- public void testMacroFunction() {
- HSSFWorkbook w = new HSSFWorkbook();
- FormulaParser fp = new FormulaParser("FOO()", w);
- fp.parse();
- Ptg[] ptg = fp.getRPNPtg();
-
- // the name gets encoded as the first arg
- NamePtg tname = (NamePtg) ptg[0];
- assertEquals("FOO", tname.toFormulaString(w));
-
- AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[1];
- assertTrue(tfunc.isExternalFunction());
- }
-
- public void testEmbeddedSlash() {
- FormulaParser fp = new FormulaParser("HYPERLINK(\"http://www.jakarta.org\",\"Jakarta\")",null);
- fp.parse();
- Ptg[] ptg = fp.getRPNPtg();
- assertTrue("first ptg is string",ptg[0] instanceof StringPtg);
- assertTrue("second ptg is string",ptg[1] instanceof StringPtg);
- }
-
- public void testConcatenate() {
- FormulaParser fp = new FormulaParser("CONCATENATE(\"first\",\"second\")", null);
- fp.parse();
- Ptg[] ptg = fp.getRPNPtg();
- assertTrue("first ptg is string", ptg[0] instanceof StringPtg);
- assertTrue("second ptg is string", ptg[1] instanceof StringPtg);
- }
-
- public void testWorksheetReferences()
- {
- HSSFWorkbook wb = new HSSFWorkbook();
-
- wb.createSheet("NoQuotesNeeded");
- wb.createSheet("Quotes Needed Here &#$@");
-
- HSSFSheet sheet = wb.createSheet("Test");
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell;
-
- cell = row.createCell((short)0);
- cell.setCellFormula("NoQuotesNeeded!A1");
-
- cell = row.createCell((short)1);
- cell.setCellFormula("'Quotes Needed Here &#$@'!A1");
- }
-
- public void testUnaryMinus()
- {
- FormulaParser fp = new FormulaParser("-A1", null);
- fp.parse();
- Ptg[] ptg = fp.getRPNPtg();
- assertTrue("got 2 ptgs", ptg.length == 2);
- assertTrue("first ptg is reference",ptg[0] instanceof ReferencePtg);
- assertTrue("second ptg is Minus",ptg[1] instanceof UnaryMinusPtg);
- }
-
- public void testUnaryPlus()
- {
- FormulaParser fp = new FormulaParser("+A1", null);
+
+ public void testMacroFunction() {
+ HSSFWorkbook w = new HSSFWorkbook();
+ FormulaParser fp = new FormulaParser("FOO()", w);
fp.parse();
Ptg[] ptg = fp.getRPNPtg();
- assertTrue("got 2 ptgs", ptg.length == 2);
- assertTrue("first ptg is reference",ptg[0] instanceof ReferencePtg);
- assertTrue("second ptg is Plus",ptg[1] instanceof UnaryPlusPtg);
- }
- public void testLeadingSpaceInString()
- {
+ // the name gets encoded as the first arg
+ NamePtg tname = (NamePtg) ptg[0];
+ assertEquals("FOO", tname.toFormulaString(w));
+
+ AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[1];
+ assertTrue(tfunc.isExternalFunction());
+ }
+
+ public void testEmbeddedSlash() {
+ Ptg[] ptgs = parseFormula("HYPERLINK(\"http://www.jakarta.org\",\"Jakarta\")");
+ assertTrue("first ptg is string", ptgs[0] instanceof StringPtg);
+ assertTrue("second ptg is string", ptgs[1] instanceof StringPtg);
+ }
+
+ public void testConcatenate() {
+ Ptg[] ptgs = parseFormula("CONCATENATE(\"first\",\"second\")");
+ assertTrue("first ptg is string", ptgs[0] instanceof StringPtg);
+ assertTrue("second ptg is string", ptgs[1] instanceof StringPtg);
+ }
+
+ public void testWorksheetReferences() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+
+ wb.createSheet("NoQuotesNeeded");
+ wb.createSheet("Quotes Needed Here &#$@");
+
+ HSSFSheet sheet = wb.createSheet("Test");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell;
+
+ cell = row.createCell((short)0);
+ cell.setCellFormula("NoQuotesNeeded!A1");
+
+ cell = row.createCell((short)1);
+ cell.setCellFormula("'Quotes Needed Here &#$@'!A1");
+ }
+
+ public void testUnaryMinus() {
+ Ptg[] ptgs = parseFormula("-A1");
+ assertEquals(2, ptgs.length);
+ assertTrue("first ptg is reference",ptgs[0] instanceof ReferencePtg);
+ assertTrue("second ptg is Minus",ptgs[1] instanceof UnaryMinusPtg);
+ }
+
+ public void testUnaryPlus() {
+ Ptg[] ptgs = parseFormula("+A1");
+ assertEquals(2, ptgs.length);
+ assertTrue("first ptg is reference",ptgs[0] instanceof ReferencePtg);
+ assertTrue("second ptg is Plus",ptgs[1] instanceof UnaryPlusPtg);
+ }
+
+ public void testLeadingSpaceInString() {
String value = " hi ";
- FormulaParser fp = new FormulaParser("\"" + value + "\"", null);
- fp.parse();
- Ptg[] ptg = fp.getRPNPtg();
+ Ptg[] ptgs = parseFormula("\"" + value + "\"");
- assertTrue("got 1 ptg", ptg.length == 1);
- assertTrue("ptg0 is a StringPtg", ptg[0] instanceof StringPtg);
- assertTrue("ptg0 contains exact value", ((StringPtg)ptg[0]).getValue().equals(value));
+ assertEquals(1, ptgs.length);
+ assertTrue("ptg0 is a StringPtg", ptgs[0] instanceof StringPtg);
+ assertTrue("ptg0 contains exact value", ((StringPtg)ptgs[0]).getValue().equals(value));
}
-
- public void testLookupAndMatchFunctionArgs()
- {
- FormulaParser fp = new FormulaParser("lookup(A1, A3:A52, B3:B52)", null);
- fp.parse();
- Ptg[] ptg = fp.getRPNPtg();
- assertTrue("got 4 ptg", ptg.length == 4);
- assertTrue("ptg0 has Value class", ptg[0].getPtgClass() == Ptg.CLASS_VALUE);
-
- fp = new FormulaParser("match(A1, A3:A52)", null);
- fp.parse();
- ptg = fp.getRPNPtg();
+ public void testLookupAndMatchFunctionArgs() {
+ Ptg[] ptgs = parseFormula("lookup(A1, A3:A52, B3:B52)");
+
+ assertEquals(4, ptgs.length);
+ assertTrue("ptg0 has Value class", ptgs[0].getPtgClass() == Ptg.CLASS_VALUE);
- assertTrue("got 3 ptg", ptg.length == 3);
- assertTrue("ptg0 has Value class", ptg[0].getPtgClass() == Ptg.CLASS_VALUE);
+ ptgs = parseFormula("match(A1, A3:A52)");
+
+ assertEquals(3, ptgs.length);
+ assertTrue("ptg0 has Value class", ptgs[0].getPtgClass() == Ptg.CLASS_VALUE);
}
-
+
/** bug 33160*/
public void testLargeInt() {
- FormulaParser fp = new FormulaParser("40", null);
- fp.parse();
- Ptg[] ptg=fp.getRPNPtg();
- assertTrue("ptg is Int, is "+ptg[0].getClass(),ptg[0] instanceof IntPtg);
-
- fp = new FormulaParser("40000", null);
- fp.parse();
- ptg=fp.getRPNPtg();
- assertTrue("ptg should be IntPtg, is "+ptg[0].getClass(), ptg[0] instanceof IntPtg);
+ Ptg[] ptgs = parseFormula("40");
+ assertTrue("ptg is Int, is "+ptgs[0].getClass(),ptgs[0] instanceof IntPtg);
+
+ ptgs = parseFormula("40000");
+ assertTrue("ptg should be IntPtg, is "+ptgs[0].getClass(), ptgs[0] instanceof IntPtg);
}
/** bug 33160, testcase by Amol Deshmukh*/
public void testSimpleLongFormula() {
- FormulaParser fp = new FormulaParser("40000/2", null);
- fp.parse();
- Ptg[] ptgs = fp.getRPNPtg();
- assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
+ Ptg[] ptgs = parseFormula("40000/2");
+ assertEquals(3, ptgs.length);
assertTrue("IntPtg", (ptgs[0] instanceof IntPtg));
assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
}
-
+
/** bug 35027, underscore in sheet name */
public void testUnderscore() {
HSSFWorkbook wb = new HSSFWorkbook();
-
- wb.createSheet("Cash_Flow");
-
- HSSFSheet sheet = wb.createSheet("Test");
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell;
-
- cell = row.createCell((short)0);
- cell.setCellFormula("Cash_Flow!A1");
-
+
+ wb.createSheet("Cash_Flow");
+
+ HSSFSheet sheet = wb.createSheet("Test");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell;
+
+ cell = row.createCell((short)0);
+ cell.setCellFormula("Cash_Flow!A1");
+ }
+
+ // bug 38396 : Formula with exponential numbers not parsed correctly.
+ public void testExponentialParsing() {
+ Ptg[] ptgs;
+ ptgs = parseFormula("1.3E21/2");
+ assertEquals(3, ptgs.length);
+ assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
+ assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
+ assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
+
+ ptgs = parseFormula("1322E21/2");
+ assertEquals(3, ptgs.length);
+ assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
+ assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
+ assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
+
+ ptgs = parseFormula("1.3E1/2");
+ assertEquals(3, ptgs.length);
+ assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
+ assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
+ assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
}
- // bug 38396 : Formula with exponential numbers not parsed correctly.
- public void testExponentialParsing() {
- FormulaParser fp = new FormulaParser("1.3E21/2", null);
- fp.parse();
- Ptg[] ptgs = fp.getRPNPtg();
- assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
- assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
- assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
- assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
-
- fp = new FormulaParser("1322E21/2", null);
- fp.parse();
- ptgs = fp.getRPNPtg();
- assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
- assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
- assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
- assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
-
- fp = new FormulaParser("1.3E1/2", null);
- fp.parse();
- ptgs = fp.getRPNPtg();
- assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
- assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
- assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
- assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
-
- }
- public void testExponentialInSheet() throws Exception {
- HSSFWorkbook wb = new HSSFWorkbook();
-
- wb.createSheet("Cash_Flow");
-
- HSSFSheet sheet = wb.createSheet("Test");
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell = row.createCell((short)0);
- String formula = null;
+ public void testExponentialInSheet() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+
+ wb.createSheet("Cash_Flow");
+
+ HSSFSheet sheet = wb.createSheet("Test");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell((short)0);
+ String formula = null;
+
+ cell.setCellFormula("1.3E21/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "1.3E21/3", formula);
+
+ cell.setCellFormula("-1.3E21/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1.3E21/3", formula);
+
+ cell.setCellFormula("1322E21/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "1.322E24/3", formula);
+
+ cell.setCellFormula("-1322E21/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1.322E24/3", formula);
+
+ cell.setCellFormula("1.3E1/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "13.0/3", formula);
+
+ cell.setCellFormula("-1.3E1/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-13.0/3", formula);
+
+ cell.setCellFormula("1.3E-4/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "1.3E-4/3", formula);
- cell.setCellFormula("1.3E21/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "1.3E21/3", formula);
-
- cell.setCellFormula("-1.3E21/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1.3E21/3", formula);
+ cell.setCellFormula("-1.3E-4/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1.3E-4/3", formula);
- cell.setCellFormula("1322E21/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "1.322E24/3", formula);
+ cell.setCellFormula("13E-15/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "1.3E-14/3", formula);
- cell.setCellFormula("-1322E21/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1.322E24/3", formula);
+ cell.setCellFormula("-13E-15/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1.3E-14/3", formula);
- cell.setCellFormula("1.3E1/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "13.0/3", formula);
+ cell.setCellFormula("1.3E3/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "1300.0/3", formula);
- cell.setCellFormula("-1.3E1/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-13.0/3", formula);
+ cell.setCellFormula("-1.3E3/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1300.0/3", formula);
- cell.setCellFormula("1.3E-4/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "1.3E-4/3", formula);
+ cell.setCellFormula("1300000000000000/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "1.3E15/3", formula);
- cell.setCellFormula("-1.3E-4/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1.3E-4/3", formula);
-
- cell.setCellFormula("13E-15/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "1.3E-14/3", formula);
-
- cell.setCellFormula("-13E-15/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1.3E-14/3", formula);
-
- cell.setCellFormula("1.3E3/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "1300.0/3", formula);
-
- cell.setCellFormula("-1.3E3/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1300.0/3", formula);
-
- cell.setCellFormula("1300000000000000/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "1.3E15/3", formula);
-
- cell.setCellFormula("-1300000000000000/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1.3E15/3", formula);
-
- cell.setCellFormula("-10E-1/3.1E2*4E3/3E4");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1.0/310.0*4000.0/30000.0", formula);
- }
-
- public static void main(String [] args) {
- System.out.println("Testing org.apache.poi.hssf.record.formula.FormulaParser");
- junit.textui.TestRunner.run(TestFormulaParser.class);
- }
-
- public void testNumbers() {
- HSSFWorkbook wb = new HSSFWorkbook();
-
- wb.createSheet("Cash_Flow");
-
- HSSFSheet sheet = wb.createSheet("Test");
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell = row.createCell((short)0);
- String formula = null;
-
- // starts from decimal point
-
- cell.setCellFormula(".1");
- formula = cell.getCellFormula();
- assertEquals("0.1", formula);
-
- cell.setCellFormula("+.1");
- formula = cell.getCellFormula();
- assertEquals("+0.1", formula);
-
- cell.setCellFormula("-.1");
- formula = cell.getCellFormula();
- assertEquals("-0.1", formula);
-
- // has exponent
-
- cell.setCellFormula("10E1");
- formula = cell.getCellFormula();
- assertEquals("100.0", formula);
-
- cell.setCellFormula("10E+1");
- formula = cell.getCellFormula();
- assertEquals("100.0", formula);
-
- cell.setCellFormula("10E-1");
- formula = cell.getCellFormula();
- assertEquals("1.0", formula);
- }
-
- public void testRanges() {
- HSSFWorkbook wb = new HSSFWorkbook();
-
- wb.createSheet("Cash_Flow");
-
- HSSFSheet sheet = wb.createSheet("Test");
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell = row.createCell((short)0);
- String formula = null;
-
- cell.setCellFormula("A1.A2");
- formula = cell.getCellFormula();
- assertEquals("A1:A2", formula);
-
- cell.setCellFormula("A1..A2");
- formula = cell.getCellFormula();
- assertEquals("A1:A2", formula);
-
- cell.setCellFormula("A1...A2");
- formula = cell.getCellFormula();
- assertEquals("A1:A2", formula);
- }
-
- /**
- * Test for bug observable at svn revision 618865 (5-Feb-2008)<br/>
- * a formula consisting of a single no-arg function got rendered without the function braces
- */
- public void testToFormulaStringZeroArgFunction() {
- HSSFWorkbook book = new HSSFWorkbook();
-
- Ptg[] ptgs = {
- new FuncPtg(10),
- };
- assertEquals("NA()", FormulaParser.toFormulaString(book, ptgs));
- }
-
- public void testPercent() {
- Ptg[] ptgs;
- ptgs = parseFormula("5%");
- assertEquals(2, ptgs.length);
- assertEquals(ptgs[0].getClass(), IntPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
-
- // spaces OK
- ptgs = parseFormula(" 250 % ");
- assertEquals(2, ptgs.length);
- assertEquals(ptgs[0].getClass(), IntPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
-
-
- // double percent OK
- ptgs = parseFormula("12345.678%%");
- assertEquals(3, ptgs.length);
- assertEquals(ptgs[0].getClass(), NumberPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
- assertEquals(ptgs[2].getClass(), PercentPtg.class);
-
- // percent of a bracketed expression
- ptgs = parseFormula("(A1+35)%*B1%");
- assertEquals(8, ptgs.length);
- assertEquals(ptgs[4].getClass(), PercentPtg.class);
- assertEquals(ptgs[6].getClass(), PercentPtg.class);
-
- // percent of a text quantity
- ptgs = parseFormula("\"8.75\"%");
- assertEquals(2, ptgs.length);
- assertEquals(ptgs[0].getClass(), StringPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
-
- // percent to the power of
- ptgs = parseFormula("50%^3");
- assertEquals(4, ptgs.length);
- assertEquals(ptgs[0].getClass(), IntPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
- assertEquals(ptgs[2].getClass(), IntPtg.class);
- assertEquals(ptgs[3].getClass(), PowerPtg.class);
-
- //
- // things that parse OK but would *evaluate* to an error
-
- ptgs = parseFormula("\"abc\"%");
- assertEquals(2, ptgs.length);
- assertEquals(ptgs[0].getClass(), StringPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
-
- ptgs = parseFormula("#N/A%");
- assertEquals(2, ptgs.length);
- assertEquals(ptgs[0].getClass(), ErrPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
- }
-
- /**
- * Tests combinations of various operators in the absence of brackets
- */
- public void testPrecedenceAndAssociativity() {
-
- Class[] expClss;
-
- // TRUE=TRUE=2=2 evaluates to FALSE
- expClss = new Class[] { BoolPtg.class, BoolPtg.class, EqualPtg.class,
- IntPtg.class, EqualPtg.class, IntPtg.class, EqualPtg.class, };
- confirmTokenClasses("TRUE=TRUE=2=2", expClss);
-
-
- // 2^3^2 evaluates to 64 not 512
- expClss = new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class,
- IntPtg.class, PowerPtg.class, };
- confirmTokenClasses("2^3^2", expClss);
-
- // "abc" & 2 + 3 & "def" evaluates to "abc5def"
- expClss = new Class[] { StringPtg.class, IntPtg.class, IntPtg.class,
- AddPtg.class, ConcatPtg.class, StringPtg.class, ConcatPtg.class, };
- confirmTokenClasses("\"abc\"&2+3&\"def\"", expClss);
-
-
- // (1 / 2) - (3 * 4)
- expClss = new Class[] { IntPtg.class, IntPtg.class, DividePtg.class,
- IntPtg.class, IntPtg.class, MultiplyPtg.class, SubtractPtg.class, };
- confirmTokenClasses("1/2-3*4", expClss);
-
- // 2 * (2^2)
- expClss = new Class[] { IntPtg.class, IntPtg.class, IntPtg.class, PowerPtg.class, MultiplyPtg.class, };
- // NOT: (2 *2) ^ 2 -> int int multiply int power
- confirmTokenClasses("2*2^2", expClss);
-
- // 2^200% -> 2 not 1.6E58
- expClss = new Class[] { IntPtg.class, IntPtg.class, PercentPtg.class, PowerPtg.class, };
- confirmTokenClasses("2^200%", expClss);
- }
-
- private static void confirmTokenClasses(String formula, Class[] expectedClasses) {
- Ptg[] ptgs = parseFormula(formula);
- assertEquals(expectedClasses.length, ptgs.length);
- for (int i = 0; i < expectedClasses.length; i++) {
- if(expectedClasses[i] != ptgs[i].getClass()) {
- fail("difference at token[" + i + "]: expected ("
- + expectedClasses[i].getName() + ") but got ("
- + ptgs[i].getClass().getName() + ")");
- }
- }
- }
-
- public void testPower() {
- confirmTokenClasses("2^5", new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class, });
- }
-
- private static Ptg parseSingleToken(String formula, Class ptgClass) {
- Ptg[] ptgs = parseFormula(formula);
- assertEquals(1, ptgs.length);
- Ptg result = ptgs[0];
- assertEquals(ptgClass, result.getClass());
- return result;
- }
-
- public void testParseNumber() {
- IntPtg ip;
-
- // bug 33160
- ip = (IntPtg) parseSingleToken("40", IntPtg.class);
- assertEquals(40, ip.getValue());
- ip = (IntPtg) parseSingleToken("40000", IntPtg.class);
- assertEquals(40000, ip.getValue());
-
- // check the upper edge of the IntPtg range:
- ip = (IntPtg) parseSingleToken("65535", IntPtg.class);
- assertEquals(65535, ip.getValue());
- NumberPtg np = (NumberPtg) parseSingleToken("65536", NumberPtg.class);
- assertEquals(65536, np.getValue(), 0);
-
- np = (NumberPtg) parseSingleToken("65534.6", NumberPtg.class);
- assertEquals(65534.6, np.getValue(), 0);
- }
-
- public void testMissingArgs() {
-
- Class[] expClss;
-
- expClss = new Class[] { ReferencePtg.class, MissingArgPtg.class, ReferencePtg.class,
- FuncVarPtg.class, };
- confirmTokenClasses("if(A1, ,C1)", expClss);
-
- expClss = new Class[] { MissingArgPtg.class, AreaPtg.class, MissingArgPtg.class,
- FuncVarPtg.class, };
- confirmTokenClasses("counta( , A1:B2, )", expClss);
- }
-
- public void testParseErrorLiterals() {
-
- confirmParseErrorLiteral(ErrPtg.NULL_INTERSECTION, "#NULL!");
- confirmParseErrorLiteral(ErrPtg.DIV_ZERO, "#DIV/0!");
- confirmParseErrorLiteral(ErrPtg.VALUE_INVALID, "#VALUE!");
- confirmParseErrorLiteral(ErrPtg.REF_INVALID, "#REF!");
- confirmParseErrorLiteral(ErrPtg.NAME_INVALID, "#NAME?");
- confirmParseErrorLiteral(ErrPtg.NUM_ERROR, "#NUM!");
- confirmParseErrorLiteral(ErrPtg.N_A, "#N/A");
- }
-
- private static void confirmParseErrorLiteral(ErrPtg expectedToken, String formula) {
- assertEquals(expectedToken, parseSingleToken(formula, ErrPtg.class));
- }
-
- /**
- * To aid readability the parameters have been encoded with single quotes instead of double
- * quotes. This method converts single quotes to double quotes before performing the parse
- * and result check.
- */
- private static void confirmStringParse(String singleQuotedValue) {
- // formula: internal quotes become double double, surround with double quotes
- String formula = '"' + singleQuotedValue.replaceAll("'", "\"\"") + '"';
- String expectedValue = singleQuotedValue.replace('\'', '"');
-
- StringPtg sp = (StringPtg) parseSingleToken(formula, StringPtg.class);
- assertEquals(expectedValue, sp.getValue());
- }
- public void testParseStringLiterals_bug28754() {
-
- StringPtg sp;
- try {
- sp = (StringPtg) parseSingleToken("\"test\"\"ing\"", StringPtg.class);
- } catch (RuntimeException e) {
- if(e.getMessage().startsWith("Cannot Parse")) {
- throw new AssertionFailedError("Identified bug 28754a");
- }
- throw e;
- }
- assertEquals("test\"ing", sp.getValue());
-
- HSSFWorkbook wb = new HSSFWorkbook();
- HSSFSheet sheet = wb.createSheet();
- wb.setSheetName(0, "Sheet1");
-
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell = row.createCell((short)0);
- cell.setCellFormula("right(\"test\"\"ing\", 3)");
- String actualCellFormula = cell.getCellFormula();
- if("RIGHT(\"test\"ing\",3)".equals(actualCellFormula)) {
- throw new AssertionFailedError("Identified bug 28754b");
- }
- assertEquals("RIGHT(\"test\"\"ing\",3)", actualCellFormula);
- }
-
- public void testParseStringLiterals() {
- confirmStringParse("goto considered harmful");
-
- confirmStringParse("goto 'considered' harmful");
-
- confirmStringParse("");
- confirmStringParse("'");
- confirmStringParse("''");
- confirmStringParse("' '");
- confirmStringParse(" ' ");
- }
-
- public void testParseSumIfSum() {
- String formulaString;
- Ptg[] ptgs;
- ptgs = parseFormula("sum(5, 2, if(3>2, sum(A1:A2), 6))");
- formulaString = FormulaParser.toFormulaString(null, ptgs);
- assertEquals("SUM(5,2,IF(3>2,SUM(A1:A2),6))", formulaString);
-
- ptgs = parseFormula("if(1<2,sum(5, 2, if(3>2, sum(A1:A2), 6)),4)");
- formulaString = FormulaParser.toFormulaString(null, ptgs);
- assertEquals("IF(1<2,SUM(5,2,IF(3>2,SUM(A1:A2),6)),4)", formulaString);
- }
- public void testParserErrors() {
- parseExpectedException("1 2");
- parseExpectedException(" 12 . 345 ");
- parseExpectedException("1 .23 ");
-
- parseExpectedException("sum(#NAME)");
- parseExpectedException("1 + #N / A * 2");
- parseExpectedException("#value?");
- parseExpectedException("#DIV/ 0+2");
-
-
- parseExpectedException("IF(TRUE)");
- parseExpectedException("countif(A1:B5, C1, D1)");
- }
-
- private static void parseExpectedException(String formula) {
- try {
- parseFormula(formula);
- throw new AssertionFailedError("expected parse exception");
- } catch (FormulaParseException e) {
- // expected during successful test
- assertNotNull(e.getMessage());
- } catch (RuntimeException e) {
- e.printStackTrace();
- fail("Wrong exception:" + e.getMessage());
- }
- }
-
- public void testSetFormulaWithRowBeyond32768_Bug44539() {
-
- HSSFWorkbook wb = new HSSFWorkbook();
- HSSFSheet sheet = wb.createSheet();
- wb.setSheetName(0, "Sheet1");
-
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell = row.createCell((short)0);
- cell.setCellFormula("SUM(A32769:A32770)");
- if("SUM(A-32767:A-32766)".equals(cell.getCellFormula())) {
- fail("Identified bug 44539");
- }
- 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"));
- }
- }
- /**
- * Make sure that POI uses the right Func Ptg when encoding formulas. Functions with variable
- * number of args should get FuncVarPtg, functions with fixed args should get FuncPtg.<p/>
- *
- * Prior to the fix for bug 44675 POI would encode FuncVarPtg for all functions. In many cases
- * Excel tolerates the wrong Ptg and evaluates the formula OK (e.g. SIN), but in some cases
- * (e.g. COUNTIF) Excel fails to evaluate the formula, giving '#VALUE!' instead.
- */
- public void testFuncPtgSelection() {
- HSSFWorkbook book = new HSSFWorkbook();
- Ptg[] ptgs;
- ptgs = FormulaParser.parse("countif(A1:A2, 1)", book);
- assertEquals(3, ptgs.length);
- if(FuncVarPtg.class == ptgs[2].getClass()) {
- throw new AssertionFailedError("Identified bug 44675");
- }
- assertEquals(FuncPtg.class, ptgs[2].getClass());
- ptgs = FormulaParser.parse("sin(1)", book);
- assertEquals(2, ptgs.length);
- assertEquals(FuncPtg.class, ptgs[1].getClass());
- }
-
- public void testWrongNumberOfFunctionArgs() {
- confirmArgCountMsg("sin()", "Too few arguments to function 'SIN'. Expected 1 but got 0.");
- confirmArgCountMsg("countif(1, 2, 3, 4)", "Too many arguments to function 'COUNTIF'. Expected 2 but got 4.");
- confirmArgCountMsg("index(1, 2, 3, 4, 5, 6)", "Too many arguments to function 'INDEX'. At most 4 were expected but got 6.");
- confirmArgCountMsg("vlookup(1, 2)", "Too few arguments to function 'VLOOKUP'. At least 3 were expected but got 2.");
- }
-
- private static void confirmArgCountMsg(String formula, String expectedMessage) {
- HSSFWorkbook book = new HSSFWorkbook();
- try {
- FormulaParser.parse(formula, book);
- throw new AssertionFailedError("Didn't get parse exception as expected");
- } catch (FormulaParseException e) {
- assertEquals(expectedMessage, e.getMessage());
- }
- }
+ cell.setCellFormula("-1300000000000000/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1.3E15/3", formula);
+
+ cell.setCellFormula("-10E-1/3.1E2*4E3/3E4");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1.0/310.0*4000.0/30000.0", formula);
+ }
+
+ public void testNumbers() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+
+ wb.createSheet("Cash_Flow");
+
+ HSSFSheet sheet = wb.createSheet("Test");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell((short)0);
+ String formula = null;
+
+ // starts from decimal point
+
+ cell.setCellFormula(".1");
+ formula = cell.getCellFormula();
+ assertEquals("0.1", formula);
+
+ cell.setCellFormula("+.1");
+ formula = cell.getCellFormula();
+ assertEquals("+0.1", formula);
+
+ cell.setCellFormula("-.1");
+ formula = cell.getCellFormula();
+ assertEquals("-0.1", formula);
+
+ // has exponent
+
+ cell.setCellFormula("10E1");
+ formula = cell.getCellFormula();
+ assertEquals("100.0", formula);
+
+ cell.setCellFormula("10E+1");
+ formula = cell.getCellFormula();
+ assertEquals("100.0", formula);
+
+ cell.setCellFormula("10E-1");
+ formula = cell.getCellFormula();
+ assertEquals("1.0", formula);
+ }
+
+ public void testRanges() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+
+ wb.createSheet("Cash_Flow");
+
+ HSSFSheet sheet = wb.createSheet("Test");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell((short)0);
+ String formula = null;
+
+ cell.setCellFormula("A1.A2");
+ formula = cell.getCellFormula();
+ assertEquals("A1:A2", formula);
+
+ cell.setCellFormula("A1..A2");
+ formula = cell.getCellFormula();
+ assertEquals("A1:A2", formula);
+
+ cell.setCellFormula("A1...A2");
+ formula = cell.getCellFormula();
+ assertEquals("A1:A2", formula);
+ }
+
+ /**
+ * Test for bug observable at svn revision 618865 (5-Feb-2008)<br/>
+ * a formula consisting of a single no-arg function got rendered without the function braces
+ */
+ public void testToFormulaStringZeroArgFunction() {
+ HSSFWorkbook book = new HSSFWorkbook();
+
+ Ptg[] ptgs = {
+ new FuncPtg(10),
+ };
+ assertEquals("NA()", FormulaParser.toFormulaString(book, ptgs));
+ }
+
+ public void testPercent() {
+ Ptg[] ptgs;
+ ptgs = parseFormula("5%");
+ assertEquals(2, ptgs.length);
+ assertEquals(ptgs[0].getClass(), IntPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+
+ // spaces OK
+ ptgs = parseFormula(" 250 % ");
+ assertEquals(2, ptgs.length);
+ assertEquals(ptgs[0].getClass(), IntPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+
+
+ // double percent OK
+ ptgs = parseFormula("12345.678%%");
+ assertEquals(3, ptgs.length);
+ assertEquals(ptgs[0].getClass(), NumberPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+ assertEquals(ptgs[2].getClass(), PercentPtg.class);
+
+ // percent of a bracketed expression
+ ptgs = parseFormula("(A1+35)%*B1%");
+ assertEquals(8, ptgs.length);
+ assertEquals(ptgs[4].getClass(), PercentPtg.class);
+ assertEquals(ptgs[6].getClass(), PercentPtg.class);
+
+ // percent of a text quantity
+ ptgs = parseFormula("\"8.75\"%");
+ assertEquals(2, ptgs.length);
+ assertEquals(ptgs[0].getClass(), StringPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+
+ // percent to the power of
+ ptgs = parseFormula("50%^3");
+ assertEquals(4, ptgs.length);
+ assertEquals(ptgs[0].getClass(), IntPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+ assertEquals(ptgs[2].getClass(), IntPtg.class);
+ assertEquals(ptgs[3].getClass(), PowerPtg.class);
+
+ //
+ // things that parse OK but would *evaluate* to an error
+
+ ptgs = parseFormula("\"abc\"%");
+ assertEquals(2, ptgs.length);
+ assertEquals(ptgs[0].getClass(), StringPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+
+ ptgs = parseFormula("#N/A%");
+ assertEquals(2, ptgs.length);
+ assertEquals(ptgs[0].getClass(), ErrPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+ }
+
+ /**
+ * Tests combinations of various operators in the absence of brackets
+ */
+ public void testPrecedenceAndAssociativity() {
+
+ Class[] expClss;
+
+ // TRUE=TRUE=2=2 evaluates to FALSE
+ expClss = new Class[] { BoolPtg.class, BoolPtg.class, EqualPtg.class,
+ IntPtg.class, EqualPtg.class, IntPtg.class, EqualPtg.class, };
+ confirmTokenClasses("TRUE=TRUE=2=2", expClss);
+
+
+ // 2^3^2 evaluates to 64 not 512
+ expClss = new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class,
+ IntPtg.class, PowerPtg.class, };
+ confirmTokenClasses("2^3^2", expClss);
+
+ // "abc" & 2 + 3 & "def" evaluates to "abc5def"
+ expClss = new Class[] { StringPtg.class, IntPtg.class, IntPtg.class,
+ AddPtg.class, ConcatPtg.class, StringPtg.class, ConcatPtg.class, };
+ confirmTokenClasses("\"abc\"&2+3&\"def\"", expClss);
+
+
+ // (1 / 2) - (3 * 4)
+ expClss = new Class[] { IntPtg.class, IntPtg.class, DividePtg.class,
+ IntPtg.class, IntPtg.class, MultiplyPtg.class, SubtractPtg.class, };
+ confirmTokenClasses("1/2-3*4", expClss);
+
+ // 2 * (2^2)
+ expClss = new Class[] { IntPtg.class, IntPtg.class, IntPtg.class, PowerPtg.class, MultiplyPtg.class, };
+ // NOT: (2 *2) ^ 2 -> int int multiply int power
+ confirmTokenClasses("2*2^2", expClss);
+
+ // 2^200% -> 2 not 1.6E58
+ expClss = new Class[] { IntPtg.class, IntPtg.class, PercentPtg.class, PowerPtg.class, };
+ confirmTokenClasses("2^200%", expClss);
+ }
+
+ private static void confirmTokenClasses(String formula, Class[] expectedClasses) {
+ Ptg[] ptgs = parseFormula(formula);
+ assertEquals(expectedClasses.length, ptgs.length);
+ for (int i = 0; i < expectedClasses.length; i++) {
+ if(expectedClasses[i] != ptgs[i].getClass()) {
+ fail("difference at token[" + i + "]: expected ("
+ + expectedClasses[i].getName() + ") but got ("
+ + ptgs[i].getClass().getName() + ")");
+ }
+ }
+ }
+
+ public void testPower() {
+ confirmTokenClasses("2^5", new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class, });
+ }
+
+ private static Ptg parseSingleToken(String formula, Class ptgClass) {
+ Ptg[] ptgs = parseFormula(formula);
+ assertEquals(1, ptgs.length);
+ Ptg result = ptgs[0];
+ assertEquals(ptgClass, result.getClass());
+ return result;
+ }
+
+ public void testParseNumber() {
+ IntPtg ip;
+
+ // bug 33160
+ ip = (IntPtg) parseSingleToken("40", IntPtg.class);
+ assertEquals(40, ip.getValue());
+ ip = (IntPtg) parseSingleToken("40000", IntPtg.class);
+ assertEquals(40000, ip.getValue());
+
+ // check the upper edge of the IntPtg range:
+ ip = (IntPtg) parseSingleToken("65535", IntPtg.class);
+ assertEquals(65535, ip.getValue());
+ NumberPtg np = (NumberPtg) parseSingleToken("65536", NumberPtg.class);
+ assertEquals(65536, np.getValue(), 0);
+
+ np = (NumberPtg) parseSingleToken("65534.6", NumberPtg.class);
+ assertEquals(65534.6, np.getValue(), 0);
+ }
+
+ public void testMissingArgs() {
+
+ Class[] expClss;
+
+ expClss = new Class[] { ReferencePtg.class, MissingArgPtg.class, ReferencePtg.class,
+ FuncVarPtg.class, };
+ confirmTokenClasses("if(A1, ,C1)", expClss);
+
+ expClss = new Class[] { MissingArgPtg.class, AreaPtg.class, MissingArgPtg.class,
+ FuncVarPtg.class, };
+ confirmTokenClasses("counta( , A1:B2, )", expClss);
+ }
+
+ public void testParseErrorLiterals() {
+
+ confirmParseErrorLiteral(ErrPtg.NULL_INTERSECTION, "#NULL!");
+ confirmParseErrorLiteral(ErrPtg.DIV_ZERO, "#DIV/0!");
+ confirmParseErrorLiteral(ErrPtg.VALUE_INVALID, "#VALUE!");
+ confirmParseErrorLiteral(ErrPtg.REF_INVALID, "#REF!");
+ confirmParseErrorLiteral(ErrPtg.NAME_INVALID, "#NAME?");
+ confirmParseErrorLiteral(ErrPtg.NUM_ERROR, "#NUM!");
+ confirmParseErrorLiteral(ErrPtg.N_A, "#N/A");
+ }
+
+ private static void confirmParseErrorLiteral(ErrPtg expectedToken, String formula) {
+ assertEquals(expectedToken, parseSingleToken(formula, ErrPtg.class));
+ }
+
+ /**
+ * To aid readability the parameters have been encoded with single quotes instead of double
+ * quotes. This method converts single quotes to double quotes before performing the parse
+ * and result check.
+ */
+ private static void confirmStringParse(String singleQuotedValue) {
+ // formula: internal quotes become double double, surround with double quotes
+ String formula = '"' + singleQuotedValue.replaceAll("'", "\"\"") + '"';
+ String expectedValue = singleQuotedValue.replace('\'', '"');
+
+ StringPtg sp = (StringPtg) parseSingleToken(formula, StringPtg.class);
+ assertEquals(expectedValue, sp.getValue());
+ }
+ public void testParseStringLiterals_bug28754() {
+
+ StringPtg sp;
+ try {
+ sp = (StringPtg) parseSingleToken("\"test\"\"ing\"", StringPtg.class);
+ } catch (RuntimeException e) {
+ if(e.getMessage().startsWith("Cannot Parse")) {
+ throw new AssertionFailedError("Identified bug 28754a");
+ }
+ throw e;
+ }
+ assertEquals("test\"ing", sp.getValue());
+
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.createSheet();
+ wb.setSheetName(0, "Sheet1");
+
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell((short)0);
+ cell.setCellFormula("right(\"test\"\"ing\", 3)");
+ String actualCellFormula = cell.getCellFormula();
+ if("RIGHT(\"test\"ing\",3)".equals(actualCellFormula)) {
+ throw new AssertionFailedError("Identified bug 28754b");
+ }
+ assertEquals("RIGHT(\"test\"\"ing\",3)", actualCellFormula);
+ }
+
+ public void testParseStringLiterals() {
+ confirmStringParse("goto considered harmful");
+
+ confirmStringParse("goto 'considered' harmful");
+
+ confirmStringParse("");
+ confirmStringParse("'");
+ confirmStringParse("''");
+ confirmStringParse("' '");
+ confirmStringParse(" ' ");
+ }
+
+ public void testParseSumIfSum() {
+ String formulaString;
+ Ptg[] ptgs;
+ ptgs = parseFormula("sum(5, 2, if(3>2, sum(A1:A2), 6))");
+ formulaString = FormulaParser.toFormulaString(null, ptgs);
+ assertEquals("SUM(5,2,IF(3>2,SUM(A1:A2),6))", formulaString);
+
+ ptgs = parseFormula("if(1<2,sum(5, 2, if(3>2, sum(A1:A2), 6)),4)");
+ formulaString = FormulaParser.toFormulaString(null, ptgs);
+ assertEquals("IF(1<2,SUM(5,2,IF(3>2,SUM(A1:A2),6)),4)", formulaString);
+ }
+ public void testParserErrors() {
+ parseExpectedException("1 2");
+ parseExpectedException(" 12 . 345 ");
+ parseExpectedException("1 .23 ");
+
+ parseExpectedException("sum(#NAME)");
+ parseExpectedException("1 + #N / A * 2");
+ parseExpectedException("#value?");
+ parseExpectedException("#DIV/ 0+2");
+
+
+ parseExpectedException("IF(TRUE)");
+ parseExpectedException("countif(A1:B5, C1, D1)");
+ }
+
+ private static void parseExpectedException(String formula) {
+ try {
+ parseFormula(formula);
+ throw new AssertionFailedError("expected parse exception");
+ } catch (FormulaParseException e) {
+ // expected during successful test
+ assertNotNull(e.getMessage());
+ } catch (RuntimeException e) {
+ e.printStackTrace();
+ fail("Wrong exception:" + e.getMessage());
+ }
+ }
+
+ public void testSetFormulaWithRowBeyond32768_Bug44539() {
+
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.createSheet();
+ wb.setSheetName(0, "Sheet1");
+
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell((short)0);
+ cell.setCellFormula("SUM(A32769:A32770)");
+ if("SUM(A-32767:A-32766)".equals(cell.getCellFormula())) {
+ fail("Identified bug 44539");
+ }
+ 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"));
+ }
+ }
+ /**
+ * Make sure that POI uses the right Func Ptg when encoding formulas. Functions with variable
+ * number of args should get FuncVarPtg, functions with fixed args should get FuncPtg.<p/>
+ *
+ * Prior to the fix for bug 44675 POI would encode FuncVarPtg for all functions. In many cases
+ * Excel tolerates the wrong Ptg and evaluates the formula OK (e.g. SIN), but in some cases
+ * (e.g. COUNTIF) Excel fails to evaluate the formula, giving '#VALUE!' instead.
+ */
+ public void testFuncPtgSelection() {
+
+ Ptg[] ptgs;
+ ptgs = parseFormula("countif(A1:A2, 1)");
+ assertEquals(3, ptgs.length);
+ if(FuncVarPtg.class == ptgs[2].getClass()) {
+ throw new AssertionFailedError("Identified bug 44675");
+ }
+ assertEquals(FuncPtg.class, ptgs[2].getClass());
+ ptgs = parseFormula("sin(1)");
+ assertEquals(2, ptgs.length);
+ assertEquals(FuncPtg.class, ptgs[1].getClass());
+ }
+
+ public void testWrongNumberOfFunctionArgs() {
+ confirmArgCountMsg("sin()", "Too few arguments to function 'SIN'. Expected 1 but got 0.");
+ confirmArgCountMsg("countif(1, 2, 3, 4)", "Too many arguments to function 'COUNTIF'. Expected 2 but got 4.");
+ confirmArgCountMsg("index(1, 2, 3, 4, 5, 6)", "Too many arguments to function 'INDEX'. At most 4 were expected but got 6.");
+ confirmArgCountMsg("vlookup(1, 2)", "Too few arguments to function 'VLOOKUP'. At least 3 were expected but got 2.");
+ }
+
+ private static void confirmArgCountMsg(String formula, String expectedMessage) {
+ HSSFWorkbook book = new HSSFWorkbook();
+ try {
+ FormulaParser.parse(formula, book);
+ throw new AssertionFailedError("Didn't get parse exception as expected");
+ } catch (FormulaParseException e) {
+ assertEquals(expectedMessage, e.getMessage());
+ }
+ }
+
+ public void testParseErrorExpecteMsg() {
+
+ try {
+ parseFormula("round(3.14;2)");
+ throw new AssertionFailedError("Didn't get parse exception as expected");
+ } catch (FormulaParseException e) {
+ assertEquals("Parse error near char 10 ';' in specified formula 'round(3.14;2)'. Expected ',' or ')'", e.getMessage());
+ }
+ }
}
package org.apache.poi.hssf.model;
+import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
xfindex = sheet.getXFIndexForColAt((short) 10);
assertEquals(DEFAULT_IDX, xfindex);
}
+
+ /**
+ * Prior to bug 45066, POI would get the estimated sheet size wrong
+ * when an <tt>UncalcedRecord</tt> was present.<p/>
+ */
+ public void testUncalcSize_bug45066() {
+
+ List records = new ArrayList();
+ records.add(new BOFRecord());
+ records.add(new UncalcedRecord());
+ records.add(new EOFRecord());
+ Sheet sheet = Sheet.createSheet( records, 0, 0 );
+
+ int estimatedSize = sheet.getSize();
+ int serializedSize = sheet.serialize(0, new byte[estimatedSize]);
+ if (serializedSize != estimatedSize) {
+ throw new AssertionFailedError("Identified bug 45066 b");
+ }
+ assertEquals(50, serializedSize);
+ }
}
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
-import java.util.zip.CRC32;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
private static final class FunctionDataCollector {
-
private final Map _allFunctionsByIndex;
private final Map _allFunctionsByName;
private final Set _groupFunctionIndexes;
_allFunctionsByName.put(funcName, fd);
}
+ /**
+ * Some extra validation here.
+ * Any function which changes definition will have a footnote in the source document
+ */
private void checkRedefinedFunction(boolean hasNote, String funcName, Integer funcIxKey) {
FunctionData fdPrev;
+ // check by index
fdPrev = (FunctionData) _allFunctionsByIndex.get(funcIxKey);
if(fdPrev != null) {
- if(fdPrev.hasFootnote() && hasNote) {
- // func def can change if both have a foot-note
- _allFunctionsByName.remove(fdPrev.getName());
- } else {
- throw new RuntimeException("changing function definition without foot-note");
+ if(!fdPrev.hasFootnote() || !hasNote) {
+ throw new RuntimeException("changing function ["
+ + funcIxKey + "] definition without foot-note");
}
+ _allFunctionsByName.remove(fdPrev.getName());
}
+ // check by name
fdPrev = (FunctionData) _allFunctionsByName.get(funcName);
if(fdPrev != null) {
- if(fdPrev.hasFootnote() && hasNote) {
- // func def can change if both have a foot-note
- _allFunctionsByIndex.remove(new Integer(fdPrev.getIndex()));
- } else {
- throw new RuntimeException("changing function definition without foot-note");
+ if(!fdPrev.hasFootnote() || !hasNote) {
+ throw new RuntimeException("changing function '"
+ + funcName + "' definition without foot-note");
}
+ _allFunctionsByIndex.remove(new Integer(fdPrev.getIndex()));
}
}
private static final String[] TABLE_CELL_RELPATH_NAMES = {
"table:table-row", "table:table-cell", "text:p",
};
- private static final String[] NOTE_REF_RELPATH_NAMES = {
+ // after May 2008 there was one more style applied to the footnotes
+ private static final String[] NOTE_REF_RELPATH_NAMES_OLD = {
"table:table-row", "table:table-cell", "text:p", "text:span", "text:note-ref",
};
+ private static final String[] NOTE_REF_RELPATH_NAMES = {
+ "table:table-row", "table:table-cell", "text:p", "text:span", "text:span", "text:note-ref",
+ };
private final Stack _elemNameStack;
} else if(matchesRelPath(TABLE_CELL_RELPATH_NAMES)) {
_textNodeBuffer.setLength(0);
_cellHasNote = false;
+ } else if(matchesRelPath(NOTE_REF_RELPATH_NAMES_OLD)) {
+ _cellHasNote = true;
} else if(matchesRelPath(NOTE_REF_RELPATH_NAMES)) {
_cellHasNote = true;
}
}
private static void processFile(File effDocFile, File outFile) {
+ if(!effDocFile.exists()) {
+ throw new RuntimeException("file '" + effDocFile.getAbsolutePath() + "' does not exist");
+ }
OutputStream os;
try {
os = new FileOutputStream(outFile);
ps.println("# Created by (" + genClass.getName() + ")");
// identify the source file
ps.print("# from source file '" + SOURCE_DOC_FILE_NAME + "'");
- ps.println(" (size=" + effDocFile.length() + ", crc=" + getFileCRC(effDocFile) + ")");
+ ps.println(" (size=" + effDocFile.length() + ", md5=" + getFileMD5(effDocFile) + ")");
ps.println("#");
ps.println("#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )");
ps.println("");
throw new RuntimeException(e);
}
ps.close();
+
+ String canonicalOutputFileName;
+ try {
+ canonicalOutputFileName = outFile.getCanonicalPath();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ System.out.println("Successfully output to '" + canonicalOutputFileName + "'");
}
private static void outputLicenseHeader(PrintStream ps) {
/**
* Helps identify the source file
*/
- private static String getFileCRC(File f) {
- CRC32 crc = new CRC32();
+ private static String getFileMD5(File f) {
+ MessageDigest m;
+ try {
+ m = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+
byte[]buf = new byte[2048];
try {
InputStream is = new FileInputStream(f);
if(bytesRead<1) {
break;
}
- crc.update(buf, 0, bytesRead);
+ m.update(buf, 0, bytesRead);
}
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
- return "0x" + Long.toHexString(crc.getValue()).toUpperCase();
+
+ return "0x" + new BigInteger(1, m.digest()).toString(16);
}
- private static File getSourceFile() {
- if (false) {
- File dir = new File("c:/temp");
- File effDocFile = new File(dir, SOURCE_DOC_FILE_NAME);
- return effDocFile;
- }
+ private static File downloadSourceFile() {
URL url;
try {
url = new URL("http://sc.openoffice.org/" + SOURCE_DOC_FILE_NAME);
URLConnection conn = url.openConnection();
InputStream is = conn.getInputStream();
System.out.println("downloading " + url.toExternalForm());
- result = File.createTempFile("excelfileformat", "odt");
+ result = File.createTempFile("excelfileformat", ".odt");
OutputStream os = new FileOutputStream(result);
while(true) {
int bytesRead = is.read(buf);
public static void main(String[] args) {
- File effDocFile = getSourceFile();
- if(!effDocFile.exists()) {
- throw new RuntimeException("file '" + effDocFile.getAbsolutePath() + "' does not exist");
- }
-
File outFile = new File("functionMetadata-asGenerated.txt");
- processFile(effDocFile, outFile);
+
+ if (false) { // set true to use local file
+ File dir = new File("c:/temp");
+ File effDocFile = new File(dir, SOURCE_DOC_FILE_NAME);
+ processFile(effDocFile, outFile);
+ return;
+ }
+
+ File tempEFFDocFile = downloadSourceFile();
+ processFile(tempEFFDocFile, outFile);
+ tempEFFDocFile.delete();
}
}
import junit.framework.TestCase;
import org.apache.poi.hssf.model.FormulaParser;
-import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.FuncPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* Tests parsing of some built-in functions that were not properly
- * registered in POI as bug #44675, #44733 (March/April 2008).
+ * registered in POI as of bug #44675, #44733 (March/April 2008).
*
* @author Josh Micich
*/
}
public void testUsdollar() {
- confirmFunc("USDOLLAR(1)", 2, false, 204);
+ confirmFunc("USDOLLAR(1)", 2, true, 204);
}
public void testDBCS() {
package org.apache.poi.hssf.record.formula.function;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
/**
* Tests reading from a sample spreadsheet some built-in functions that were not properly
- * registered in POI as bug #44675, #44733 (March/April 2008).
+ * registered in POI as of bug #44675, #44733 (March/April 2008).
*
* @author Josh Micich
*/
public class AllUserModelTests {
public static Test suite() {
- TestSuite result = new TestSuite("Tests for org.apache.poi.hssf.usermodel");
+ TestSuite result = new TestSuite(AllUserModelTests.class.getName());
result.addTestSuite(TestBugs.class);
result.addTestSuite(TestCellStyle.class);
result.addTestSuite(TestHSSFSheetSetOrder.class);
result.addTestSuite(TestHSSFTextbox.class);
result.addTestSuite(TestHSSFWorkbook.class);
+ result.addTestSuite(TestLinkTable.class);
result.addTestSuite(TestNamedRange.class);
result.addTestSuite(TestOLE2Embeding.class);
result.addTestSuite(TestPOIFSProperties.class);
}
}
+ public void testSetValues() throws Exception {
+ HSSFWorkbook book = new HSSFWorkbook();
+ HSSFSheet sheet = book.createSheet("test");
+ HSSFRow row = sheet.createRow(0);
+
+ HSSFCell cell = row.createCell((short)0);
+
+ cell.setCellValue(1.2);
+ assertEquals(1.2, cell.getNumericCellValue(), 0.0001);
+ assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cell.getCellType());
+
+ cell.setCellValue(false);
+ assertEquals(false, cell.getBooleanCellValue());
+ assertEquals(HSSFCell.CELL_TYPE_BOOLEAN, cell.getCellType());
+
+ cell.setCellValue(new HSSFRichTextString("Foo"));
+ assertEquals("Foo", cell.getRichStringCellValue().getString());
+ assertEquals(HSSFCell.CELL_TYPE_STRING, cell.getCellType());
+
+ cell.setCellValue(new HSSFRichTextString("345"));
+ assertEquals("345", cell.getRichStringCellValue().getString());
+ assertEquals(HSSFCell.CELL_TYPE_STRING, cell.getCellType());
+ }
+
/**
* test that Boolean and Error types (BoolErrRecord) are supported properly.
*/
formats = new String[] {
"yyyy-mm-dd hh:mm:ss", "yyyy/mm/dd HH:MM:SS",
"mm/dd HH:MM", "yy/mmm/dd SS",
+ "mm/dd HH:MM AM", "mm/dd HH:MM am",
+ "mm/dd HH:MM PM", "mm/dd HH:MM pm"
};
for(int i=0; i<formats.length; i++) {
assertTrue( HSSFDateUtil.isADateFormat(formatId, formats[i]) );
import org.apache.poi.hssf.record.WSBoolRecord;
import org.apache.poi.hssf.record.WindowTwoRecord;
import org.apache.poi.ss.util.Region;
-import org.apache.poi.util.TempFile;
/**
* Tests HSSFSheet. This test case is very incomplete at the moment.
/**
* Test the gridset field gets set as expected.
*/
-
- public void testBackupRecord()
- throws Exception
- {
+ public void testBackupRecord() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
Sheet sheet = s.getSheet();
/**
* Test vertically centered output.
*/
-
- public void testVerticallyCenter()
- throws Exception
- {
+ public void testVerticallyCenter() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
Sheet sheet = s.getSheet();
/**
* Test horizontally centered output.
*/
-
- public void testHorizontallyCenter()
- throws Exception
- {
+ public void testHorizontallyCenter() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
Sheet sheet = s.getSheet();
assertEquals(false, record.getHCenter());
s.setHorizontallyCenter(true);
assertEquals(true, record.getHCenter());
-
}
/**
* Test WSBboolRecord fields get set in the user model.
*/
-
- public void testWSBool()
- {
+ public void testWSBool() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
Sheet sheet = s.getSheet();
assertEquals(true, s.getRowSumsRight());
}
- public void testReadBooleans()
- throws Exception
- {
+ public void testReadBooleans() {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Test boolean");
HSSFRow row = sheet.createRow((short) 2);
cell.setCellValue(true);
cell = row.createCell((short) 11);
cell.setCellValue(true);
- File tempFile = TempFile.createTempFile("bool", "test.xls");
- FileOutputStream stream = new FileOutputStream(tempFile);
- workbook.write(stream);
- stream.close();
+
+ workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
- FileInputStream readStream = new FileInputStream(tempFile);
- workbook = new HSSFWorkbook(readStream);
sheet = workbook.getSheetAt(0);
row = sheet.getRow(2);
- stream.close();
- tempFile.delete();
assertNotNull(row);
assertEquals(2, row.getPhysicalNumberOfCells());
}
- public void testRemoveRow()
- {
+ public void testRemoveRow() {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Test boolean");
HSSFRow row = sheet.createRow((short) 2);
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell((short) 0);
HSSFCell cell2 = row.createCell((short) 1);
- cell.setCellValue(new HSSFRichTextString("clone_test"));
- cell2.setCellFormula("sin(1)");
+ cell.setCellValue(new HSSFRichTextString("clone_test"));
+ cell2.setCellFormula("sin(1)");
HSSFSheet clonedSheet = workbook.cloneSheet(0);
HSSFRow clonedRow = clonedSheet.getRow(0);
assertNotNull(workbook.getSheet("Test Clone"));
assertNotNull(workbook.getSheet("Test Clone(1)"));
- assertNotNull(workbook.getSheet("Test Clone(2)"));
+ assertNotNull(workbook.getSheet("Test Clone(2)"));
}
/**
/**
* Setting landscape and portrait stuff on existing sheets
*/
- public void testPrintSetupLandscapeExisting() throws Exception {
+ public void testPrintSetupLandscapeExisting() {
HSSFWorkbook workbook = openSample("SimpleWithPageBreaks.xls");
assertEquals(3, workbook.getNumberOfSheets());
assertEquals(1, sheetLS.getPrintSetup().getCopies());
// Save and re-load, and check still there
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- workbook.write(baos);
- workbook = new HSSFWorkbook(new ByteArrayInputStream(baos.toByteArray()));
+ workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
assertTrue(sheetL.getPrintSetup().getLandscape());
assertFalse(sheetPM.getPrintSetup().getLandscape());
assertEquals(1, sheetLS.getPrintSetup().getCopies());
}
- public void testGroupRows() throws Exception {
+ public void testGroupRows() {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet s = workbook.createSheet();
HSSFRow r1 = s.createRow(0);
assertEquals(0, r5.getOutlineLevel());
// Save and re-open
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- workbook.write(baos);
- workbook = new HSSFWorkbook(
- new ByteArrayInputStream(baos.toByteArray())
- );
+ workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
s = workbook.getSheetAt(0);
r1 = s.getRow(0);
assertEquals(0, r5.getOutlineLevel());
}
- public void testGroupRowsExisting() throws Exception {
+ public void testGroupRowsExisting() {
HSSFWorkbook workbook = openSample("NoGutsRecords.xls");
HSSFSheet s = workbook.getSheetAt(0);
assertEquals(0, r6.getOutlineLevel());
// Save and re-open
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- workbook.write(baos);
- workbook = new HSSFWorkbook(
- new ByteArrayInputStream(baos.toByteArray())
- );
+ try {
+ workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
+ } catch (OutOfMemoryError e) {
+ throw new AssertionFailedError("Identified bug 39903");
+ }
s = workbook.getSheetAt(0);
r1 = s.getRow(0);
assertEquals(0, r6.getOutlineLevel());
}
- public void testGetDrawings() throws Exception {
+ public void testGetDrawings() {
HSSFWorkbook wb1c = openSample("WithChart.xls");
HSSFWorkbook wb2c = openSample("WithTwoCharts.xls");
HSSFSheet hssfSheet = workbook.createSheet();
Sheet sheet = hssfSheet.getSheet();
ProtectRecord protect = sheet.getProtect();
-
+
assertFalse(protect.getProtect());
// This will tell us that cloneSheet, and by extension,
public void testProtectSheet() {
short expected = (short)0xfef1;
- HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
s.protectSheet("abcdefghij");
Sheet sheet = s.getSheet();
- ProtectRecord protect = sheet.getProtect();
- PasswordRecord pass = sheet.getPassword();
+ ProtectRecord protect = sheet.getProtect();
+ PasswordRecord pass = sheet.getPassword();
assertTrue("protection should be on",protect.getProtect());
assertTrue("object protection should be on",sheet.isProtected()[1]);
assertTrue("scenario protection should be on",sheet.isProtected()[2]);
}
- public void testZoom()
- throws Exception
- {
+ public void testZoom() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
assertEquals(-1, sheet.getSheet().findFirstRecordLocBySid(SCLRecord.sid));
int sclLoc = sheet.getSheet().findFirstRecordLocBySid(SCLRecord.sid);
int window2Loc = sheet.getSheet().findFirstRecordLocBySid(WindowTwoRecord.sid);
assertTrue(sclLoc == window2Loc + 1);
-
}
public void testRemoveMerged() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
- Region region = new Region(0, (short)0, 1, (short)1);
+ Region region = new Region(0, (short)0, 1, (short)1);
sheet.addMergedRegion(region);
region = new Region(1, (short)0, 2, (short)1);
sheet.addMergedRegion(region);
assertTrue("there isn't more than one merged region in there", 1 <= sheet.getNumMergedRegions());
region = sheet.getMergedRegionAt(0);
assertEquals("the merged row to doesnt match the one we put in ", 4, region.getRowTo());
-
}
public void testShiftMerged() {
cell = row.createCell((short)1);
cell.setCellValue(new HSSFRichTextString("second row, second cell"));
- Region region = new Region(1, (short)0, 1, (short)1);
+ Region region = new Region(1, (short)0, 1, (short)1);
sheet.addMergedRegion(region);
sheet.shiftRows(1, 1, 1);
region = sheet.getMergedRegionAt(0);
assertEquals("Merged region not moved over to row 2", 2, region.getRowFrom());
-
}
/**
* Tests the display of gridlines, formulas, and rowcolheadings.
* @author Shawn Laubach (slaubach at apache dot org)
*/
- public void testDisplayOptions() throws Exception {
+ public void testDisplayOptions() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
- File tempFile = TempFile.createTempFile("display", "test.xls");
- FileOutputStream stream = new FileOutputStream(tempFile);
- wb.write(stream);
- stream.close();
-
- FileInputStream readStream = new FileInputStream(tempFile);
- wb = new HSSFWorkbook(readStream);
+ wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
sheet = wb.getSheetAt(0);
- readStream.close();
assertEquals(sheet.isDisplayGridlines(), true);
assertEquals(sheet.isDisplayRowColHeadings(), true);
sheet.setDisplayRowColHeadings(false);
sheet.setDisplayFormulas(true);
- tempFile = TempFile.createTempFile("display", "test.xls");
- stream = new FileOutputStream(tempFile);
- wb.write(stream);
- stream.close();
-
- readStream = new FileInputStream(tempFile);
- wb = new HSSFWorkbook(readStream);
+ wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
sheet = wb.getSheetAt(0);
- readStream.close();
-
assertEquals(sheet.isDisplayGridlines(), false);
assertEquals(sheet.isDisplayRowColHeadings(), false);
* Make sure the excel file loads work
*
*/
- public void testPageBreakFiles() throws Exception{
+ public void testPageBreakFiles() {
HSSFWorkbook wb = openSample("SimpleWithPageBreaks.xls");
HSSFSheet sheet = wb.getSheetAt(0);
assertEquals("row breaks number", 2, sheet.getRowBreaks().length);
assertEquals("column breaks number", 2, sheet.getColumnBreaks().length);
- File tempFile = TempFile.createTempFile("display", "testPagebreaks.xls");
- FileOutputStream stream = new FileOutputStream(tempFile);
- wb.write(stream);
- stream.close();
-
- wb = new HSSFWorkbook(new FileInputStream(tempFile));
+ wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
sheet = wb.getSheetAt(0);
assertTrue("No row page break", sheet.isRowBroken(22));
assertTrue("No column page break", sheet.isColumnBroken((short)4));
-
assertEquals("row breaks number", 2, sheet.getRowBreaks().length);
assertEquals("column breaks number", 2, sheet.getColumnBreaks().length);
-
-
}
- public void testDBCSName () throws Exception {
+ public void testDBCSName () {
HSSFWorkbook wb = openSample("DBCSSheetName.xls");
- HSSFSheet s= wb.getSheetAt(1);
+ wb.getSheetAt(1);
assertEquals ("DBCS Sheet Name 2", wb.getSheetName(1),"\u090f\u0915" );
assertEquals("DBCS Sheet Name 1", wb.getSheetName(0),"\u091c\u093e");
}
/**
*
*/
- public void testAddEmptyRow() throws Exception {
+ public void testAddEmptyRow() {
//try to add 5 empty rows to a new sheet
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();
- for (int i = 0; i < 5; i++) sheet.createRow(i);
-
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- workbook.write(out);
- out.close();
+ for (int i = 0; i < 5; i++) {
+ sheet.createRow(i);
+ }
- workbook = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
+ workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
//try adding empty rows in an existing worksheet
workbook = openSample("Simple.xls");
sheet = workbook.getSheetAt(0);
for (int i = 3; i < 10; i++) sheet.createRow(i);
- out = new ByteArrayOutputStream();
- workbook.write(out);
- out.close();
-
- workbook = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
+ workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
}
- public void testAutoSizeColumn() throws Exception {
+ public void testAutoSizeColumn() {
HSSFWorkbook wb = openSample("43902.xls");
String sheetName = "my sheet";
HSSFSheet sheet = wb.getSheet(sheetName);
// machines based on the fonts available.
// So, we use ranges, which are pretty large, but
// thankfully don't overlap!
- int minWithRow1And2 = 6400;
+ int minWithRow1And2 = 6400;
int maxWithRow1And2 = 7800;
int minWithRow1Only = 2750;
int maxWithRow1Only = 3300;
//create a region over the 2nd row and auto size the first column
sheet.addMergedRegion(new Region(1,(short)0,1,(short)1));
sheet.autoSizeColumn((short)0);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- wb.write(out);
- out.close();
+ HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb);
- // check that the autoSized column width has ignored the 2nd row
+ // check that the autoSized column width has ignored the 2nd row
// because it is included in a merged region (Excel like behavior)
- HSSFWorkbook wb2 = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
HSSFSheet sheet2 = wb2.getSheet(sheetName);
assertTrue(sheet2.getColumnWidth((short)0) >= minWithRow1Only);
assertTrue(sheet2.getColumnWidth((short)0) <= maxWithRow1Only);
// remove the 2nd row merged region and check that the 2nd row value is used to the autoSizeColumn width
sheet2.removeMergedRegion(1);
sheet2.autoSizeColumn((short)0);
- out = new ByteArrayOutputStream();
- wb2.write(out);
- out.close();
- HSSFWorkbook wb3 = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
+ HSSFWorkbook wb3 = HSSFTestDataSamples.writeOutAndReadBack(wb2);
HSSFSheet sheet3 = wb3.getSheet(sheetName);
assertTrue(sheet3.getColumnWidth((short)0) >= minWithRow1And2);
assertTrue(sheet3.getColumnWidth((short)0) <= maxWithRow1And2);
assertTrue(wb3.getSheetAt(3).getForceFormulaRecalculation());
}
- public void testColumnWidth() throws Exception {
+ public void testColumnWidth() {
//check we can correctly read column widths from a reference workbook
HSSFWorkbook wb = openSample("colwidth.xls");
}
//serialize and read again
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- wb.write(out);
- out.close();
+ wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
- wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
sh = wb.getSheetAt(0);
assertEquals(10, sh.getDefaultColumnWidth());
//columns A-C have default width
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.List;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.record.NameRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.TempFile;
/**
*
assertEquals("active", expectedActive, sheet.isActive());
assertEquals("selected", expectedSelected, sheet.isSelected());
}
-}
+
+ /**
+ * If Sheet.getSize() returns a different result to Sheet.serialize(), this will cause the BOF
+ * records to be written with invalid offset indexes. Excel does not like this, and such
+ * errors are particularly hard to track down. This test ensures that HSSFWorkbook throws
+ * a specific exception as soon as the situation is detected. See bugzilla 45066
+ */
+ public void testSheetSerializeSizeMismatch_bug45066() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ Sheet sheet = wb.createSheet("Sheet1").getSheet();
+ List sheetRecords = sheet.getRecords();
+ // one way (of many) to cause the discrepancy is with a badly behaved record:
+ sheetRecords.add(new BadlyBehavedRecord());
+ // There is also much logic inside Sheet that (if buggy) might also cause the discrepancy
+ try {
+ wb.getBytes();
+ throw new AssertionFailedError("Identified bug 45066 a");
+ } catch (IllegalStateException e) {
+ // Expected badly behaved sheet record to cause exception
+ assertTrue(e.getMessage().startsWith("Actual serialized sheet size"));
+ }
+ }
+ /**
+ * result returned by getRecordSize() differs from result returned by serialize()
+ */
+ private static final class BadlyBehavedRecord extends Record {
+ public BadlyBehavedRecord() {
+ //
+ }
+ protected void fillFields(RecordInputStream in) {
+ throw new RuntimeException("Should not be called");
+ }
+ public short getSid() {
+ return 0x777;
+ }
+ public int serialize(int offset, byte[] data) {
+ return 4;
+ }
+ protected void validateSid(short id) {
+ throw new RuntimeException("Should not be called");
+ }
+ public int getRecordSize() {
+ return 8;
+ }
+ }
+ }
--- /dev/null
+package org.apache.poi.hssf.usermodel;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+/**
+ * Tests for LinkTable
+ *
+ * @author Josh Micich
+ */
+public final class TestLinkTable extends TestCase {
+
+ /**
+ * The example file attached to bugzilla 45046 is a clear example of Name records being present
+ * without an External Book (SupBook) record. Excel has no trouble reading this file.<br/>
+ * TODO get OOO documentation updated to reflect this (that EXTERNALBOOK is optional).
+ *
+ * It's not clear what exact steps need to be taken in Excel to create such a workbook
+ */
+ public void testLinkTableWithoutExternalBookRecord_bug45046() {
+ HSSFWorkbook wb;
+
+ try {
+ wb = HSSFTestDataSamples.openSampleWorkbook("ex45046-21984.xls");
+ } catch (RuntimeException e) {
+ if ("DEFINEDNAME is part of LinkTable".equals(e.getMessage())) {
+ throw new AssertionFailedError("Identified bug 45046 b");
+ }
+ throw e;
+ }
+ // some other sanity checks
+ assertEquals(3, wb.getNumberOfSheets());
+ String formula = wb.getSheetAt(0).getRow(4).getCell(13).getCellFormula();
+
+ if ("ipcSummenproduktIntern($P5,N$6,$A$9,N$5)".equals(formula)) {
+ // The reported symptom of this bugzilla is an earlier bug (already fixed)
+ throw new AssertionFailedError("Identified bug 41726");
+ // This is observable in version 3.0
+ }
+
+ assertEquals("ipcSummenproduktIntern($C5,N$2,$A$9,N$1)", formula);
+ }
+}
*/
public void testTextSheets() throws Exception {
// Both should have two sheets
- assertEquals(2, wbH.sheets.size());
- assertEquals(2, wbU.sheets.size());
+ assertEquals(2, wbH.getNumberOfSheets());
+ assertEquals(2, wbU.getNumberOfSheets());
// All sheets should have one row
assertEquals(0, wbH.getSheetAt(0).getLastRowNum());