HyperlinkRecord
wraps an HLINK-record
+ * from the Excel-97 format.
+ * Supports only external links for now (eg http://)
+ *
+ * @author Mark Hissink Muller (in.remaining()/2) ? (in.remaining()/2) : field_7_url_len;
+ field_12_url = in.readUnicodeLEString(strlen);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.poi.hssf.record.Record#getSid()
+ */
+ public short getSid()
+ {
+ return HyperlinkRecord.sid;
+ }
+
+ protected void validateSid(short id)
+ {
+ if (id != sid)
+ {
+ throw new RecordFormatException("NOT A HYPERLINKRECORD!");
+ }
+ }
+
+ public int serialize(int offset, byte[] data)
+ {
+ LittleEndian.putShort(data, 0 + offset, sid);
+ LittleEndian.putShort(data, 2 + offset,
+ ( short )(getRecordSize()-4));
+ LittleEndian.putShort(data, 4 + offset, field_1_unknown);
+ LittleEndian.putUShort(data, 6 + offset, field_2_row);
+ LittleEndian.putShort(data, 8 + offset, field_3_column);
+ LittleEndian.putShort(data, 10 + offset, field_4_xf_index);
+
+ offset += 12;
+ for(int i=0; iPtg
+ * tokens into human readable text form. In formula expressions, a sheet name always has a
+ * trailing '!' so there is little chance for ambiguity. It doesn't matter too much what this
+ * method returns but it is worth noting the likely consumers of these formula text strings:
+ * + * POI currently targets BIFF8 (Excel 97-2003), so the following behaviour can be observed for + * this method: + *+ *
+ * Version File Format + *Last Column Last Row + * 97-2003 BIFF8 "IV" (2^8) 65536 (2^14) + * 2007 BIFF12 "XFD" (2^14) 1048576 (2^20)
+ */ + /* package */ static boolean cellReferenceIsWithinRange(String rawSheetName, int numberOfLetters) { + + if(numberOfLetters > BIFF8_LAST_COLUMN_TEXT_LEN) { + // "Sheet1" case etc + return false; // that was easy + } + int nDigits = rawSheetName.length() - numberOfLetters; + if(nDigits > BIFF8_LAST_ROW_TEXT_LEN) { + return false; + } + if(numberOfLetters == BIFF8_LAST_COLUMN_TEXT_LEN) { + String colStr = rawSheetName.substring(0, BIFF8_LAST_COLUMN_TEXT_LEN).toUpperCase(); + if(colStr.compareTo(BIFF8_LAST_COLUMN) > 0) { + return false; + } + } else { + // apparent column name has less chars than max + // no need to check range + } + + if(nDigits == BIFF8_LAST_ROW_TEXT_LEN) { + String colStr = rawSheetName.substring(numberOfLetters); + // ASCII comparison is valid if digit count is same + if(colStr.compareTo(BIFF8_LAST_ROW) > 0) { + return false; + } + } else { + // apparent row has less chars than max + // no need to check range + } + + return true; + } + + /** + * Note - this method assumes the specified rawSheetName has only letters and digits. It + * cannot be used to match absolute or range references (using the dollar or colon char). + * + * Some notable cases: + *+ *
+ * Input + *Result + * "A1", 1 true + * "a111", 1 true + * "A65536", 1 true + * "A65537", 1 false + * "iv1", 2 true + * "IW1", 2 false + * "AAA1", 3 false + * "a111", 1 true + * "Sheet1", 6 false
+ * + * @return+ *
+ * Input Result Comments + * "A1" true + * "a111" true + * "AA" false + * "aa1" true + * "A1A" false + * "A1A1" false + * "A$1:$C$20" false Not a plain cell reference + * "SALES20080101" true + *Still needs delimiting even though well out of range
true
if there is any possible ambiguity that the specified rawSheetName
+ * could be interpreted as a valid cell name.
+ */
+ /* package */ static boolean nameLooksLikePlainCellReference(String rawSheetName) {
+ Matcher matcher = CELL_REF_PATTERN.matcher(rawSheetName);
+ if(!matcher.matches()) {
+ return false;
+ }
+
+ // rawSheetName == "Sheet1" gets this far.
+ String lettersPrefix = matcher.group(1);
+ return cellReferenceIsWithinRange(rawSheetName, lettersPrefix.length());
+ }
+
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/UnknownPtg.java b/src/java/org/apache/poi/hssf/record/formula/UnknownPtg.java
index 9cc515832..1badf5197 100644
--- a/src/java/org/apache/poi/hssf/record/formula/UnknownPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/UnknownPtg.java
@@ -28,7 +28,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
public class UnknownPtg
extends Ptg
{
- private short size;
+ private short size = 1;
/** Creates new UnknownPtg */
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
index 33417dad7..19ead33f0 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
@@ -34,20 +34,7 @@ import java.util.Iterator;
import org.apache.poi.hssf.model.FormulaParser;
import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.model.Workbook;
-import org.apache.poi.hssf.record.BlankRecord;
-import org.apache.poi.hssf.record.BoolErrRecord;
-import org.apache.poi.hssf.record.CellValueRecordInterface;
-import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
-import org.apache.poi.hssf.record.ExtendedFormatRecord;
-import org.apache.poi.hssf.record.FormulaRecord;
-import org.apache.poi.hssf.record.LabelSSTRecord;
-import org.apache.poi.hssf.record.NoteRecord;
-import org.apache.poi.hssf.record.NumberRecord;
-import org.apache.poi.hssf.record.ObjRecord;
-import org.apache.poi.hssf.record.Record;
-import org.apache.poi.hssf.record.SubRecord;
-import org.apache.poi.hssf.record.TextObjectRecord;
-import org.apache.poi.hssf.record.UnicodeString;
+import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.ss.usermodel.Cell;
@@ -1073,4 +1060,31 @@ public class HSSFCell implements Cell
}
return comment;
}
+
+ /**
+ * Returns hyperlink associated with this cell
+ *
+ * @return hyperlink associated with this cell or null if not found
+ */
+ public HSSFHyperlink getHyperlink(){
+ for (Iterator it = sheet.getRecords().iterator(); it.hasNext(); ) {
+ Record rec = ( Record ) it.next();
+ if (rec instanceof HyperlinkRecord){
+ HyperlinkRecord link = (HyperlinkRecord)rec;
+ if(link.getColumn() == record.getColumn() && link.getRow() == record.getRow()){
+ return new HSSFHyperlink(link);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Assign a hypelrink to this cell
+ *
+ * @param link hypelrink associated with this cell
+ */
+ public void setHyperlink(HSSFHyperlink link){
+
+ }
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFDataFormat.java b/src/java/org/apache/poi/hssf/usermodel/HSSFDataFormat.java
index 547ec8303..fb7ac49f3 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFDataFormat.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFDataFormat.java
@@ -206,12 +206,12 @@ public class HSSFDataFormat implements DataFormat
}
/**
- * get the format index that matches the given format string.
- * Creates a new format if one is not found. Aliases text to the proper format.
+ * Get the format index that matches the given format
+ * string, creating a new format entry if required.
+ * Aliases text to the proper format as required.
* @param format string matching a built in format
* @return index of format.
*/
-
public short getFormat( String format )
{
ListIterator i;
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFHyperlink.java b/src/java/org/apache/poi/hssf/usermodel/HSSFHyperlink.java
new file mode 100755
index 000000000..e1bd28af6
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFHyperlink.java
@@ -0,0 +1,128 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.hssf.usermodel;
+
+import org.apache.poi.hssf.record.EscherAggregate;
+import org.apache.poi.hssf.record.NoteRecord;
+import org.apache.poi.hssf.record.TextObjectRecord;
+import org.apache.poi.hssf.record.HyperlinkRecord;
+import org.apache.poi.ddf.*;
+
+import java.util.Map;
+import java.util.List;
+import java.util.Iterator;
+
+/**
+ * Represents a hyperlink.
+ *
+ * @author Yegor Kozlov
+ */
+public class HSSFHyperlink {
+
+ /**
+ * Link to a existing file or web page
+ */
+ public static final int LINK_URL = 1;
+
+ /**
+ * Link to a place in this document
+ */
+ public static final int LINK_DOCUMENT = 2;
+
+ /**
+ * Link to an E-mail address
+ */
+ public static final int LINK_EMAIL = 3;
+
+ /**
+ * Unknown type
+ */
+ public static final int LINK_UNKNOWN = 4;
+
+ /**
+ * Low-level record object that stores the actual hyperlink data
+ */
+ private HyperlinkRecord record = null;
+
+ protected HSSFHyperlink( HyperlinkRecord record )
+ {
+ this.record = record;
+ }
+
+ /**
+ * Return the row of the cell that contains the hyperlink
+ *
+ * @return the 0-based row of the cell that contains the hyperlink
+ */
+ public int getRow(){
+ return record.getRow();
+ }
+
+ /**
+ * Set the row of the cell that contains the hyperlink
+ *
+ * @param row the 0-based row of the cell that contains the hyperlink
+ */
+ public void setRow(int row){
+ record.setRow(row);
+ }
+
+ /**
+ * Return the column of the cell that contains the hyperlink
+ *
+ * @return the 0-based column of the cell that contains the hyperlink
+ */
+ public short getColumn(){
+ return record.getColumn();
+ }
+
+ /**
+ * Set the column of the cell that contains the hyperlink
+ *
+ * @param col the 0-based column of the cell that contains the hyperlink
+ */
+ public void setColumn(short col){
+ record.setColumn(col);
+ }
+
+ /**
+ * Hypelink address. Depending on the hyperlink type it can be URL, e-mail, etc.
+ *
+ * @return the address of this hyperlink
+ */
+ public String getAddress(){
+ return record.getUrlString();
+ }
+
+ /**
+ * Return text to display for this hyperlink
+ *
+ * @return text to display
+ */
+ public String getLabel(){
+ return record.getLabel();
+ }
+
+ /**
+ * Return the type of this hyperlink
+ *
+ * @return the type of this hyperlink
+ */
+ public int getType(){
+ throw new RuntimeException("Not implemented");
+ }
+}
diff --git a/src/java/org/apache/poi/util/CommonsLogger.java b/src/java/org/apache/poi/util/CommonsLogger.java
index 4265a88af..16a48f28f 100644
--- a/src/java/org/apache/poi/util/CommonsLogger.java
+++ b/src/java/org/apache/poi/util/CommonsLogger.java
@@ -22,8 +22,6 @@ package org.apache.poi.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import java.util.*;
-
/**
* A logger class that strives to make it as easy as possible for
* developers to write log calls, while simultaneously making those
@@ -53,7 +51,6 @@ public class CommonsLogger extends POILogger
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
* @param obj1 The object to log.
*/
-
public void log(final int level, final Object obj1)
{
if(level==FATAL)
@@ -98,6 +95,78 @@ public class CommonsLogger extends POILogger
log.trace(obj1);
}
}
+ }
+
+ /**
+ * Log a message
+ *
+ * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
+ * @param obj1 The object to log. This is converted to a string.
+ * @param exception An exception to be logged
+ */
+ public void log(final int level, final Object obj1,
+ final Throwable exception)
+ {
+ if(level==FATAL)
+ {
+ if(log.isFatalEnabled())
+ {
+ if(obj1 != null)
+ log.fatal(obj1, exception);
+ else
+ log.fatal(exception);
+ }
+ }
+ else if(level==ERROR)
+ {
+ if(log.isErrorEnabled())
+ {
+ if(obj1 != null)
+ log.error(obj1, exception);
+ else
+ log.error(exception);
+ }
+ }
+ else if(level==WARN)
+ {
+ if(log.isWarnEnabled())
+ {
+ if(obj1 != null)
+ log.warn(obj1, exception);
+ else
+ log.warn(exception);
+ }
+ }
+ else if(level==INFO)
+ {
+ if(log.isInfoEnabled())
+ {
+ if(obj1 != null)
+ log.info(obj1, exception);
+ else
+ log.info(exception);
+ }
+ }
+ else if(level==DEBUG)
+ {
+ if(log.isDebugEnabled())
+ {
+ if(obj1 != null)
+ log.debug(obj1, exception);
+ else
+ log.debug(exception);
+ }
+ }
+ else
+ {
+ if(log.isTraceEnabled())
+ {
+ if(obj1 != null)
+ log.trace(obj1, exception);
+ else
+ log.trace(exception);
+ }
+ }
}
diff --git a/src/java/org/apache/poi/util/POILogger.java b/src/java/org/apache/poi/util/POILogger.java
index b2d358d4d..514edf90c 100644
--- a/src/java/org/apache/poi/util/POILogger.java
+++ b/src/java/org/apache/poi/util/POILogger.java
@@ -51,7 +51,24 @@ public abstract class POILogger
abstract public void initialize(final String cat);
+ /**
+ * Log a message
+ *
+ * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
+ * @param obj1 The object to log. This is converted to a string.
+ */
abstract public void log(final int level, final Object obj1);
+
+ /**
+ * Log a message
+ *
+ * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
+ * @param obj1 The object to log. This is converted to a string.
+ * @param exception An exception to be logged
+ */
+ abstract public void log(final int level, final Object obj1,
+ final Throwable exception);
+
/**
* Check if a logger is enabled to log at the specified level
@@ -237,17 +254,15 @@ public abstract class POILogger
}
/**
- * Log a message
+ * Log an exception, without a message
*
* @param level One of DEBUG, INFO, WARN, ERROR, FATAL
- * @param obj1 The object to log. This is converted to a string.
* @param exception An exception to be logged
*/
- public void log(final int level, final Object obj1,
- final Throwable exception)
+ public void log(final int level, final Throwable exception)
{
- log(level , obj1, exception);
+ log(level, null, exception);
}
/**
diff --git a/src/java/org/apache/poi/util/SystemOutLogger.java b/src/java/org/apache/poi/util/SystemOutLogger.java
index 8b3dc50d9..af678e186 100644
--- a/src/java/org/apache/poi/util/SystemOutLogger.java
+++ b/src/java/org/apache/poi/util/SystemOutLogger.java
@@ -49,8 +49,24 @@ public class SystemOutLogger extends POILogger
public void log(final int level, final Object obj1)
{
- if (check(level))
+ log(level, obj1, null);
+ }
+
+ /**
+ * Log a message
+ *
+ * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
+ * @param obj1 The object to log. This is converted to a string.
+ * @param exception An exception to be logged
+ */
+ public void log(final int level, final Object obj1,
+ final Throwable exception) {
+ if (check(level)) {
System.out.println("["+cat+"] "+obj1);
+ if(exception != null) {
+ exception.printStackTrace(System.out);
+ }
+ }
}
/**
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java b/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java
index 7eae4edc4..f9cc43a7e 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java
@@ -23,6 +23,8 @@ import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.usermodel.PictureData;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hslf.exceptions.HSLFException;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.util.POILogFactory;
import java.awt.*;
import java.util.*;
@@ -33,6 +35,9 @@ import java.util.*;
* @author Yegor Kozlov
*/
public class Fill {
+ // For logging
+ protected POILogger logger = POILogFactory.getLogger(this.getClass());
+
/**
* Fill with a solid color
*/
@@ -208,15 +213,18 @@ public class Fill {
java.util.List lst = bstore.getChildRecords();
int idx = p.getPropertyValue();
- EscherBSERecord bse = (EscherBSERecord)lst.get(idx);
- for ( int i = 0; i < pict.length; i++ ) {
- if (pict[i].getOffset() == bse.getOffset()){
- return pict[i];
+ if (idx == 0){
+ logger.log(POILogger.ERROR, "no reference to picture data found ");
+ } else {
+ EscherBSERecord bse = (EscherBSERecord)lst.get(idx - 1);
+ for ( int i = 0; i < pict.length; i++ ) {
+ if (pict[i].getOffset() == bse.getOffset()){
+ return pict[i];
+ }
}
}
- throw new HSLFException("Picture data not found: \n" +
- " bse: " + bse + " at " + bse.getOffset() );
+ return null;
}
/**
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java b/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java
index 0740e23bc..90efd5f3e 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java
@@ -109,7 +109,7 @@ public class Picture extends SimpleShape {
*/
public int getPictureIndex(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
- EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.BLIP__BLIPTODISPLAY + 0x4000);
+ EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.BLIP__BLIPTODISPLAY);
return prop == null ? 0 : prop.getPropertyValue();
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java b/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java
index 56d77764e..5cff81a8d 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java
@@ -227,7 +227,7 @@ public abstract class Shape {
for ( Iterator iterator = opt.getEscherProperties().iterator(); iterator.hasNext(); )
{
EscherProperty prop = (EscherProperty) iterator.next();
- if (prop.getId() == propId)
+ if (prop.getPropertyNumber() == propId)
return prop;
}
return null;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java b/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java
index 201a069fc..ea7201751 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java
@@ -262,4 +262,11 @@ public class Slide extends Sheet
SlideAtom sa = getSlideRecord().getSlideAtom();
return sa.getFollowMasterBackground();
}
+
+ public Background getBackground() {
+ if(getFollowMasterBackground())
+ return getMasterSheet().getBackground();
+ else
+ return super.getBackground();
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Columns.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Columns.java
index e25fad66e..b75864e72 100644
--- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Columns.java
+++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Columns.java
@@ -14,12 +14,46 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * Created on May 15, 2005
- *
- */
+
+
package org.apache.poi.hssf.record.formula.functions;
-public class Columns extends NotImplementedFunction {
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+/**
+ * Implementation for Excel COLUMNS function.
+ *
+ * @author Josh Micich
+ */
+public final class Columns implements Function {
+
+ public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ switch(args.length) {
+ case 1:
+ // expected
+ break;
+ case 0:
+ // too few arguments
+ return ErrorEval.VALUE_INVALID;
+ default:
+ // too many arguments
+ return ErrorEval.VALUE_INVALID;
+ }
+ Eval firstArg = args[0];
+
+ int result;
+ if (firstArg instanceof AreaEval) {
+ AreaEval ae = (AreaEval) firstArg;
+ result = ae.getLastColumn() - ae.getFirstColumn() + 1;
+ } else if (firstArg instanceof RefEval) {
+ result = 1;
+ } else { // anything else is not valid argument
+ return ErrorEval.VALUE_INVALID;
+ }
+ return new NumberEval(result);
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Counta.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Counta.java
index 6c6b30574..9061e77e5 100644
--- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Counta.java
+++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Counta.java
@@ -14,12 +14,107 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * Created on May 15, 2005
- *
- */
+
+
package org.apache.poi.hssf.record.formula.functions;
-public class Counta extends NotImplementedFunction {
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+/**
+ * Counts the number of cells that contain data within the list of arguments.
+ *
+ * Excel Syntax
+ * COUNTA(value1,value2,...)
+ * Value1, value2, ... are 1 to 30 arguments representing the values or ranges to be counted.
+ *
+ * @author Josh Micich
+ */
+public final class Counta implements Function {
+
+ public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ int nArgs = args.length;
+ if (nArgs < 1) {
+ // too few arguments
+ return ErrorEval.VALUE_INVALID;
+ }
+
+ if (nArgs > 30) {
+ // too many arguments
+ return ErrorEval.VALUE_INVALID;
+ }
+
+ int temp = 0;
+ // Note - observed behavior of Excel:
+ // Error values like #VALUE!, #REF!, #DIV/0!, #NAME? etc don't cause this COUNTA to return an error
+ // in fact, they seem to get counted
+
+ for(int i=0; irange | is the range of cells to be counted based on the criteria |
---|---|
criteria | is used to determine which cells to count |
reference | typically an area reference, possibly a union of areas |
---|---|
array | a literal array value (currently not supported) |
row_num | selects the row within the array or area reference |
column_num | selects column within the array or area reference. default is 1 |
area_num | used when reference is a union of areas |
Function
.
+ *
+ * @author Josh Micich
+ */
+public final class AllIndividualFunctionEvaluationTests {
+
+ // TODO - have this suite incorporated into a higher level one
+ public static Test suite() {
+ TestSuite result = new TestSuite("Tests for org.apache.poi.hssf.record.formula.functions");
+ result.addTestSuite(TestCountFuncs.class);
+ result.addTestSuite(TestDate.class);
+ result.addTestSuite(TestFinanceLib.class);
+ result.addTestSuite(TestIndex.class);
+ result.addTestSuite(TestMathX.class);
+ result.addTestSuite(TestRowCol.class);
+ result.addTestSuite(TestStatsLib.class);
+ return result;
+ }
+
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java
new file mode 100755
index 000000000..958c48664
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java
@@ -0,0 +1,63 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.ReferencePtg;
+import org.apache.poi.hssf.record.formula.eval.Area2DEval;
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Test helper class for creating mock Eval
objects
+ *
+ * @author Josh Micich
+ */
+final class EvalFactory {
+ private static final NumberEval ZERO = new NumberEval(0);
+
+ private EvalFactory() {
+ // no instances of this class
+ }
+
+ /**
+ * Creates a dummy AreaEval (filled with zeros)
+ *
+ * nCols and nRows could have been derived
+ */
+ public static AreaEval createAreaEval(String areaRefStr, int nCols, int nRows) {
+ int nValues = nCols * nRows;
+ ValueEval[] values = new ValueEval[nValues];
+ for (int i = 0; i < nValues; i++) {
+ values[i] = ZERO;
+ }
+
+ return new Area2DEval(new AreaPtg(areaRefStr), values);
+ }
+
+ /**
+ * Creates a single RefEval (with value zero)
+ */
+ public static RefEval createRefEval(String refStr) {
+ return new Ref2DEval(new ReferencePtg(refStr), ZERO, true);
+ }
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java
new file mode 100755
index 000000000..87405a491
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java
@@ -0,0 +1,101 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import junit.framework.AssertionFailedError;
+
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
+
+/**
+ * Test helper class for invoking functions with numeric results.
+ *
+ * @author Josh Micich
+ */
+final class NumericFunctionInvoker {
+
+ private NumericFunctionInvoker() {
+ // no instances of this class
+ }
+
+ private static final class NumericEvalEx extends Exception {
+ public NumericEvalEx(String msg) {
+ super(msg);
+ }
+ }
+
+ /**
+ * Invokes the specified function with the arguments.
+ *
+ * Assumes that the cell coordinate parameters of
+ * Function.evaluate(args, srcCellRow, srcCellCol)
+ * are not required.
+ *
+ * This method cannot be used for confirming error return codes. Any non-numeric evaluation
+ * result causes the current junit test to fail.
+ */
+ public static double invoke(Function f, Eval[] args) {
+ try {
+ return invokeInternal(f, args, -1, -1);
+ } catch (NumericEvalEx e) {
+ throw new AssertionFailedError("Evaluation of function (" + f.getClass().getName()
+ + ") failed: " + e.getMessage());
+ }
+
+ }
+ /**
+ * Formats nicer error messages for the junit output
+ */
+ private static double invokeInternal(Function f, Eval[] args, int srcCellRow, int srcCellCol)
+ throws NumericEvalEx {
+ Eval evalResult = f.evaluate(args, srcCellRow, (short)srcCellCol);
+ if(evalResult == null) {
+ throw new NumericEvalEx("Result object was null");
+ }
+ if(evalResult instanceof ErrorEval) {
+ ErrorEval ee = (ErrorEval) evalResult;
+ throw new NumericEvalEx(formatErrorMessage(ee));
+ }
+ if(!(evalResult instanceof NumericValueEval)) {
+ throw new NumericEvalEx("Result object type (" + evalResult.getClass().getName()
+ + ") is invalid. Expected implementor of ("
+ + NumericValueEval.class.getName() + ")");
+ }
+
+ NumericValueEval result = (NumericValueEval) evalResult;
+ return result.getNumberValue();
+ }
+ private static String formatErrorMessage(ErrorEval ee) {
+ if(errorCodesAreEqual(ee, ErrorEval.FUNCTION_NOT_IMPLEMENTED)) {
+ return "Function not implemented";
+ }
+ if(errorCodesAreEqual(ee, ErrorEval.UNKNOWN_ERROR)) {
+ return "Unknown error";
+ }
+ return "Error code=" + ee.getErrorCode();
+ }
+ private static boolean errorCodesAreEqual(ErrorEval a, ErrorEval b) {
+ if(a==b) {
+ return true;
+ }
+ return a.getErrorCode() == b.getErrorCode();
+ }
+
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
new file mode 100755
index 000000000..fbaace921
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
@@ -0,0 +1,150 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.ReferencePtg;
+import org.apache.poi.hssf.record.formula.eval.Area2DEval;
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+import org.apache.poi.hssf.record.formula.eval.BoolEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Test cases for COUNT(), COUNTA() COUNTIF(), COUNTBLANK()
+ *
+ * @author Josh Micich
+ */
+public final class TestCountFuncs extends TestCase {
+
+ public TestCountFuncs(String testName) {
+ super(testName);
+ }
+
+ public void testCountA() {
+
+ Eval[] args;
+
+ args = new Eval[] {
+ new NumberEval(0),
+ };
+ confirmCountA(1, args);
+
+ args = new Eval[] {
+ new NumberEval(0),
+ new NumberEval(0),
+ new StringEval(""),
+ };
+ confirmCountA(3, args);
+
+ args = new Eval[] {
+ EvalFactory.createAreaEval("D2:F5", 3, 4),
+ };
+ confirmCountA(12, args);
+
+ args = new Eval[] {
+ EvalFactory.createAreaEval("D1:F5", 3, 5), // 15
+ EvalFactory.createRefEval("A1"),
+ EvalFactory.createAreaEval("A1:F6", 7, 6), // 42
+ new NumberEval(0),
+ };
+ confirmCountA(59, args);
+ }
+
+ public void testCountIf() {
+
+ AreaEval range;
+ ValueEval[] values;
+
+ // when criteria is a boolean value
+ values = new ValueEval[] {
+ new NumberEval(0),
+ new StringEval("TRUE"), // note - does not match boolean TRUE
+ BoolEval.TRUE,
+ BoolEval.FALSE,
+ BoolEval.TRUE,
+ BlankEval.INSTANCE,
+ };
+ range = createAreaEval("A1:B2", values);
+ confirmCountIf(2, range, BoolEval.TRUE);
+
+ // when criteria is numeric
+ values = new ValueEval[] {
+ new NumberEval(0),
+ new StringEval("2"),
+ new StringEval("2.001"),
+ new NumberEval(2),
+ new NumberEval(2),
+ BoolEval.TRUE,
+ BlankEval.INSTANCE,
+ };
+ range = createAreaEval("A1:B2", values);
+ confirmCountIf(3, range, new NumberEval(2));
+ // note - same results when criteria is a string that parses as the number with the same value
+ confirmCountIf(3, range, new StringEval("2.00"));
+
+ if (false) { // not supported yet:
+ // when criteria is an expression (starting with a comparison operator)
+ confirmCountIf(4, range, new StringEval(">1"));
+ }
+ }
+ /**
+ * special case where the criteria argument is a cell reference
+ */
+ public void testCountIfWithCriteriaReference() {
+
+ ValueEval[] values = {
+ new NumberEval(22),
+ new NumberEval(25),
+ new NumberEval(21),
+ new NumberEval(25),
+ new NumberEval(25),
+ new NumberEval(25),
+ };
+ Area2DEval arg0 = new Area2DEval(new AreaPtg("C1:C6"), values);
+
+ Ref2DEval criteriaArg = new Ref2DEval(new ReferencePtg("A1"), new NumberEval(25), true);
+ Eval[] args= { arg0, criteriaArg, };
+
+ double actual = NumericFunctionInvoker.invoke(new Countif(), args);
+ assertEquals(4, actual, 0D);
+ }
+
+
+ private static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) {
+ return new Area2DEval(new AreaPtg(areaRefStr), values);
+ }
+
+ private static void confirmCountA(int expected, Eval[] args) {
+ double result = NumericFunctionInvoker.invoke(new Counta(), args);
+ assertEquals(expected, result, 0);
+ }
+ private static void confirmCountIf(int expected, AreaEval range, Eval criteria) {
+
+ Eval[] args = { range, criteria, };
+ double result = NumericFunctionInvoker.invoke(new Countif(), args);
+ assertEquals(expected, result, 0);
+ }
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java
new file mode 100755
index 000000000..902c4122e
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java
@@ -0,0 +1,89 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.eval.Area2DEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Tests for the INDEX() function
+ *
+ * @author Josh Micich
+ */
+public final class TestIndex extends TestCase {
+
+ public TestIndex(String testName) {
+ super(testName);
+ }
+
+ private static final double[] TEST_VALUES0 = {
+ 1, 2,
+ 3, 4,
+ 5, 6,
+ 7, 8,
+ 9, 10,
+ 11, 12,
+ 13, // excess array element. TODO - Area2DEval currently has no validation to ensure correct size of values array
+ };
+
+ /**
+ * For the case when the first argument to INDEX() is an area reference
+ */
+ public void testEvaluateAreaReference() {
+
+ double[] values = TEST_VALUES0;
+ confirmAreaEval("C1:D6", values, 4, 1, 7);
+ confirmAreaEval("C1:D6", values, 6, 2, 12);
+ confirmAreaEval("C1:D6", values, 3, -1, 5);
+
+ // now treat same data as 3 columns, 4 rows
+ confirmAreaEval("C10:E13", values, 2, 2, 5);
+ confirmAreaEval("C10:E13", values, 4, -1, 10);
+ }
+
+ /**
+ * @param areaRefString in Excel notation e.g. 'D2:E97'
+ * @param dValues array of evaluated values for the area reference
+ * @param rowNum 1-based
+ * @param colNum 1-based, pass -1 to signify argument not present
+ */
+ private static void confirmAreaEval(String areaRefString, double[] dValues,
+ int rowNum, int colNum, double expectedResult) {
+ ValueEval[] values = new ValueEval[dValues.length];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = new NumberEval(dValues[i]);
+ }
+ Area2DEval arg0 = new Area2DEval(new AreaPtg(areaRefString), values);
+
+ Eval[] args;
+ if (colNum > 0) {
+ args = new Eval[] { arg0, new NumberEval(rowNum), new NumberEval(colNum), };
+ } else {
+ args = new Eval[] { arg0, new NumberEval(rowNum), };
+ }
+
+ double actual = NumericFunctionInvoker.invoke(new Index(), args);
+ assertEquals(expectedResult, actual, 0D);
+ }
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java
new file mode 100755
index 000000000..4002c30d0
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java
@@ -0,0 +1,102 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.record.formula.eval.Eval;
+
+/**
+ * Tests for ROW(), ROWS(), COLUMN(), COLUMNS()
+ *
+ * @author Josh Micich
+ */
+public final class TestRowCol extends TestCase {
+
+ public TestRowCol(String testName) {
+ super(testName);
+ }
+
+ public void testCol() {
+ Function target = new Column();
+ {
+ Eval[] args = { EvalFactory.createRefEval("C5"), };
+ double actual = NumericFunctionInvoker.invoke(target, args);
+ assertEquals(3, actual, 0D);
+ }
+ {
+ Eval[] args = { EvalFactory.createAreaEval("E2:H12", 4, 11), };
+ double actual = NumericFunctionInvoker.invoke(target, args);
+ assertEquals(5, actual, 0D);
+ }
+ }
+
+ public void testRow() {
+ Function target = new Row();
+ {
+ Eval[] args = { EvalFactory.createRefEval("C5"), };
+ double actual = NumericFunctionInvoker.invoke(target, args);
+ assertEquals(5, actual, 0D);
+ }
+ {
+ Eval[] args = { EvalFactory.createAreaEval("E2:H12", 4, 11), };
+ double actual = NumericFunctionInvoker.invoke(target, args);
+ assertEquals(2, actual, 0D);
+ }
+ }
+
+ public void testColumns() {
+
+ confirmColumnsFunc("A1:F1", 6, 1);
+ confirmColumnsFunc("A1:C2", 3, 2);
+ confirmColumnsFunc("A1:B3", 2, 3);
+ confirmColumnsFunc("A1:A6", 1, 6);
+
+ Eval[] args = { EvalFactory.createRefEval("C5"), };
+ double actual = NumericFunctionInvoker.invoke(new Columns(), args);
+ assertEquals(1, actual, 0D);
+ }
+
+ public void testRows() {
+
+ confirmRowsFunc("A1:F1", 6, 1);
+ confirmRowsFunc("A1:C2", 3, 2);
+ confirmRowsFunc("A1:B3", 2, 3);
+ confirmRowsFunc("A1:A6", 1, 6);
+
+ Eval[] args = { EvalFactory.createRefEval("C5"), };
+ double actual = NumericFunctionInvoker.invoke(new Rows(), args);
+ assertEquals(1, actual, 0D);
+ }
+
+ private static void confirmRowsFunc(String areaRefStr, int nCols, int nRows) {
+ Eval[] args = { EvalFactory.createAreaEval(areaRefStr, nCols, nRows), };
+
+ double actual = NumericFunctionInvoker.invoke(new Rows(), args);
+ assertEquals(nRows, actual, 0D);
+ }
+
+
+ private static void confirmColumnsFunc(String areaRefStr, int nCols, int nRows) {
+ Eval[] args = { EvalFactory.createAreaEval(areaRefStr, nCols, nRows), };
+
+ double actual = NumericFunctionInvoker.invoke(new Columns(), args);
+ assertEquals(nCols, actual, 0D);
+ }
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug44297.java b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug44297.java
new file mode 100755
index 000000000..ce4afd36f
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug44297.java
@@ -0,0 +1,103 @@
+package org.apache.poi.hssf.usermodel;
+/* ====================================================================
+ 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.
+==================================================================== */
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.File;
+
+/**
+ * Bug 44297: 32767+32768 is evaluated to -1
+ * Fix: IntPtg must operate with unsigned short. Reading signed short results in incorrect formula calculation
+ * if a formula has values in the interval [Short.MAX_VALUE, (Short.MAX_VALUE+1)*2]
+ *
+ * @author Yegor Kozlov
+ */
+
+public class TestBug44297 extends TestCase {
+ protected String cwd = System.getProperty("HSSF.testdata.path");
+
+ public void test44297() throws IOException {
+ FileInputStream in = new FileInputStream(new File(cwd, "44297.xls"));
+ HSSFWorkbook wb = new HSSFWorkbook(in);
+ in.close();
+
+ HSSFRow row;
+ HSSFCell cell;
+
+ HSSFSheet sheet = wb.getSheetAt(0);
+
+ HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(sheet, wb);
+
+ row = (HSSFRow)sheet.getRow(0);
+ cell = row.getCell((short)0);
+ assertEquals("31+46", cell.getCellFormula());
+ eva.setCurrentRow(row);
+ assertEquals(77, eva.evaluate(cell).getNumberValue(), 0);
+
+ row = (HSSFRow)sheet.getRow(1);
+ cell = row.getCell((short)0);
+ assertEquals("30+53", cell.getCellFormula());
+ eva.setCurrentRow(row);
+ assertEquals(83, eva.evaluate(cell).getNumberValue(), 0);
+
+ row = (HSSFRow)sheet.getRow(2);
+ cell = row.getCell((short)0);
+ assertEquals("SUM(A1:A2)", cell.getCellFormula());
+ eva.setCurrentRow(row);
+ assertEquals(160, eva.evaluate(cell).getNumberValue(), 0);
+
+ row = (HSSFRow)sheet.getRow(4);
+ cell = row.getCell((short)0);
+ assertEquals("32767+32768", cell.getCellFormula());
+ eva.setCurrentRow(row);
+ assertEquals(65535, eva.evaluate(cell).getNumberValue(), 0);
+
+ row = (HSSFRow)sheet.getRow(7);
+ cell = row.getCell((short)0);
+ assertEquals("32744+42333", cell.getCellFormula());
+ eva.setCurrentRow(row);
+ assertEquals(75077, eva.evaluate(cell).getNumberValue(), 0);
+
+ row = (HSSFRow)sheet.getRow(8);
+ cell = row.getCell((short)0);
+ assertEquals("327680.0/32768", cell.getCellFormula());
+ eva.setCurrentRow(row);
+ assertEquals(10, eva.evaluate(cell).getNumberValue(), 0);
+
+ row = (HSSFRow)sheet.getRow(9);
+ cell = row.getCell((short)0);
+ assertEquals("32767+32769", cell.getCellFormula());
+ eva.setCurrentRow(row);
+ assertEquals(65536, eva.evaluate(cell).getNumberValue(), 0);
+
+ row = (HSSFRow)sheet.getRow(10);
+ cell = row.getCell((short)0);
+ assertEquals("35000+36000", cell.getCellFormula());
+ eva.setCurrentRow(row);
+ assertEquals(71000, eva.evaluate(cell).getNumberValue(), 0);
+
+ row = (HSSFRow)sheet.getRow(11);
+ cell = row.getCell((short)0);
+ assertEquals("-1000000.0-3000000.0", cell.getCellFormula());
+ eva.setCurrentRow(row);
+ assertEquals(-4000000, eva.evaluate(cell).getNumberValue(), 0);
+ }
+
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java
index cd2acc7ea..6c2e3b641 100644
--- a/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java
+++ b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java
@@ -82,7 +82,7 @@ public class TestFormulaEvaluatorDocs extends TestCase {
assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(0).getRow(1).getCell((short)2).getCellType());
assertEquals(22.3, wb.getSheetAt(1).getRow(0).getCell((short)0).getNumericCellValue(), 0);
- assertEquals("S1!A1", wb.getSheetAt(1).getRow(0).getCell((short)0).getCellFormula());
+ assertEquals("'S1'!A1", wb.getSheetAt(1).getRow(0).getCell((short)0).getCellFormula());
assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(1).getRow(0).getCell((short)0).getCellType());
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/Bug44292.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/Bug44292.doc
new file mode 100644
index 000000000..fd7ca6cc3
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hwpf/data/Bug44292.doc differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java
index 8e7f47ed9..e82c4d130 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java
@@ -74,4 +74,34 @@ public class TestProblems extends TestCase {
}
}
}
+
+ /**
+ * Test for TableCell not skipping the last paragraph
+ */
+ public void testTableCellLastParagraph() throws Exception {
+ HWPFDocument doc = new HWPFDocument(new FileInputStream(dirname + "/Bug44292.doc"));
+ Range r = doc.getRange();
+
+ //get the table
+ Paragraph p = r.getParagraph(0);
+ Table t = r.getTable(p);
+
+ //get the only row
+ TableRow row = t.getRow(0);
+
+ //get the first cell
+ TableCell cell = row.getCell(0);
+ // First cell should have one paragraph
+ assertEquals(1, cell.numParagraphs());
+
+ //get the second
+ cell = row.getCell(1);
+ // Second cell should be detected as having two paragraphs
+ assertEquals(2, cell.numParagraphs());
+
+ //get the last cell
+ cell = row.getCell(2);
+ // Last cell should have one paragraph
+ assertEquals(1, cell.numParagraphs());
+ }
}
diff --git a/src/testcases/org/apache/poi/hssf/HSSFTests.java b/src/testcases/org/apache/poi/hssf/HSSFTests.java
index 1bc9df179..1e0edd682 100644
--- a/src/testcases/org/apache/poi/hssf/HSSFTests.java
+++ b/src/testcases/org/apache/poi/hssf/HSSFTests.java
@@ -75,13 +75,7 @@ import org.apache.poi.hssf.record.TestUnitsRecord;
import org.apache.poi.hssf.record.TestValueRangeRecord;
import org.apache.poi.hssf.record.aggregates.TestRowRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.TestValueRecordsAggregate;
-import org.apache.poi.hssf.record.formula.TestAreaErrPtg;
-import org.apache.poi.hssf.record.formula.TestErrPtg;
-import org.apache.poi.hssf.record.formula.TestFuncPtg;
-import org.apache.poi.hssf.record.formula.TestIntersectionPtg;
-import org.apache.poi.hssf.record.formula.TestPercentPtg;
-import org.apache.poi.hssf.record.formula.TestRangePtg;
-import org.apache.poi.hssf.record.formula.TestUnionPtg;
+import org.apache.poi.hssf.record.formula.AllFormulaTests;
import org.apache.poi.hssf.usermodel.TestBugs;
import org.apache.poi.hssf.usermodel.TestCellStyle;
import org.apache.poi.hssf.usermodel.TestCloneSheet;
@@ -215,13 +209,7 @@ public class HSSFTests
suite.addTest(new TestSuite(TestSheetReferences.class));
- suite.addTest(new TestSuite(TestAreaErrPtg.class));
- suite.addTest(new TestSuite(TestErrPtg.class));
- suite.addTest(new TestSuite(TestFuncPtg.class));
- suite.addTest(new TestSuite(TestIntersectionPtg.class));
- suite.addTest(new TestSuite(TestPercentPtg.class));
- suite.addTest(new TestSuite(TestRangePtg.class));
- suite.addTest(new TestSuite(TestUnionPtg.class));
+ suite.addTest(AllFormulaTests.suite());
suite.addTest(new TestSuite(TestValueRecordsAggregate.class));
suite.addTest(new TestSuite(TestNameRecord.class));
suite.addTest(new TestSuite(TestEventRecordFactory.class));
diff --git a/src/testcases/org/apache/poi/hssf/data/HyperlinksOnManySheets.xls b/src/testcases/org/apache/poi/hssf/data/HyperlinksOnManySheets.xls
new file mode 100755
index 000000000..1884e57c5
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/HyperlinksOnManySheets.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/data/SimpleWithChoose.xls b/src/testcases/org/apache/poi/hssf/data/SimpleWithChoose.xls
new file mode 100755
index 000000000..96a8e743a
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/SimpleWithChoose.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/data/TestDataValidation.xls b/src/testcases/org/apache/poi/hssf/data/TestDataValidation.xls
index a9460375c..0b2a86948 100644
Binary files a/src/testcases/org/apache/poi/hssf/data/TestDataValidation.xls and b/src/testcases/org/apache/poi/hssf/data/TestDataValidation.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/data/WithHyperlink.xls b/src/testcases/org/apache/poi/hssf/data/WithHyperlink.xls
new file mode 100644
index 000000000..e136506c2
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/WithHyperlink.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/data/WithTwoHyperLinks.xls b/src/testcases/org/apache/poi/hssf/data/WithTwoHyperLinks.xls
new file mode 100644
index 000000000..6ee60b535
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/WithTwoHyperLinks.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/eventusermodel/TestHSSFEventFactory.java b/src/testcases/org/apache/poi/hssf/eventusermodel/TestHSSFEventFactory.java
index bd936a0af..049b43ef9 100644
--- a/src/testcases/org/apache/poi/hssf/eventusermodel/TestHSSFEventFactory.java
+++ b/src/testcases/org/apache/poi/hssf/eventusermodel/TestHSSFEventFactory.java
@@ -23,8 +23,13 @@ import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
+import org.apache.poi.hssf.record.DVALRecord;
+import org.apache.poi.hssf.record.DVRecord;
+import org.apache.poi.hssf.record.EOFRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.ContinueRecord;
+import org.apache.poi.hssf.record.SelectionRecord;
+import org.apache.poi.hssf.record.WindowTwoRecord;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import junit.framework.TestCase;
@@ -48,7 +53,15 @@ public class TestHSSFEventFactory extends TestCase {
factory.processWorkbookEvents(req, fs);
// Check we got the records
+ System.out.println("Processed, found " + mockListen.records.size() + " records");
assertTrue( mockListen.records.size() > 100 );
+
+ // Check that the last few records are as we expect
+ // (Makes sure we don't accidently skip the end ones)
+ int numRec = mockListen.records.size();
+ assertEquals(WindowTwoRecord.class, mockListen.records.get(numRec-3).getClass());
+ assertEquals(SelectionRecord.class, mockListen.records.get(numRec-2).getClass());
+ assertEquals(EOFRecord.class, mockListen.records.get(numRec-1).getClass());
}
public void testWithCrazyContinueRecords() throws Exception {
@@ -66,6 +79,7 @@ public class TestHSSFEventFactory extends TestCase {
factory.processWorkbookEvents(req, fs);
// Check we got the records
+ System.out.println("Processed, found " + mockListen.records.size() + " records");
assertTrue( mockListen.records.size() > 100 );
// And none of them are continue ones
@@ -74,6 +88,13 @@ public class TestHSSFEventFactory extends TestCase {
for(int i=0; i