<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.1-alpha1" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="add">Made HSSFFormulaEvaluator no longer require initialisation with sheet or row</action>
+ <action dev="POI-DEVELOPERS" type="add">Extended support for cached results of formula cells</action>
+ <action dev="POI-DEVELOPERS" type="fix">45639 - Fixed AIOOBE due to bad index logic in ColumnInfoRecordsAggregate</action>
+ <action dev="POI-DEVELOPERS" type="fix">Fixed special cases of INDEX function (single column/single row, errors)</action>
<action dev="POI-DEVELOPERS" type="add">45761 - Support for Very Hidden excel sheets in HSSF</action>
<action dev="POI-DEVELOPERS" type="add">45738 - Initial HWPF support for Office Art Shapes</action>
<action dev="POI-DEVELOPERS" type="fix">45720 - Fixed HSSFWorkbook.cloneSheet to correctly clone sheets with drawings</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.1-alpha1" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="add">Made HSSFFormulaEvaluator no longer require initialisation with sheet or row</action>
+ <action dev="POI-DEVELOPERS" type="add">Extended support for cached results of formula cells</action>
+ <action dev="POI-DEVELOPERS" type="fix">45639 - Fixed AIOOBE due to bad index logic in ColumnInfoRecordsAggregate</action>
+ <action dev="POI-DEVELOPERS" type="fix">Fixed special cases of INDEX function (single column/single row, errors)</action>
<action dev="POI-DEVELOPERS" type="add">45761 - Support for Very Hidden excel sheets in HSSF</action>
<action dev="POI-DEVELOPERS" type="add">45738 - Initial HWPF support for Office Art Shapes</action>
<action dev="POI-DEVELOPERS" type="fix">45720 - Fixed HSSFWorkbook.cloneSheet to correctly clone sheets with drawings</action>
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
+
package org.apache.poi.hssf.extractor;
import java.io.IOException;
/**
* A text extractor for Excel files, that is based
* on the hssf eventusermodel api.
- * It will typically use less memory than
+ * It will typically use less memory than
* {@link ExcelExtractor}, but may not provide
* the same richness of formatting.
- * Returns the textual content of the file, suitable for
+ * Returns the textual content of the file, suitable for
* indexing by something like Lucene, but not really
* intended for display to the user.
* To turn an excel file into a CSV or similar, then see
private POIFSFileSystem fs;
private boolean includeSheetNames = true;
private boolean formulasNotResults = false;
-
- public EventBasedExcelExtractor(POIFSFileSystem fs) throws IOException {
+
+ public EventBasedExcelExtractor(POIFSFileSystem fs) {
super(null);
this.fs = fs;
}
public void setFormulasNotResults(boolean formulasNotResults) {
this.formulasNotResults = formulasNotResults;
}
-
-
+
+
/**
* Retreives the text contents of the file
*/
String text = null;
try {
TextListener tl = triggerExtraction();
-
+
text = tl.text.toString();
if(! text.endsWith("\n")) {
text = text + "\n";
} catch(IOException e) {
throw new RuntimeException(e);
}
-
+
return text;
}
-
+
private TextListener triggerExtraction() throws IOException {
TextListener tl = new TextListener();
FormatTrackingHSSFListener ft = new FormatTrackingHSSFListener(tl);
tl.ft = ft;
-
+
// Register and process
HSSFEventFactory factory = new HSSFEventFactory();
HSSFRequest request = new HSSFRequest();
request.addListenerForAllRecords(ft);
-
+
factory.processWorkbookEvents(request, fs);
-
+
return tl;
}
-
+
private class TextListener implements HSSFListener {
private FormatTrackingHSSFListener ft;
private SSTRecord sstRecord;
-
+
private List sheetNames = new ArrayList();
private StringBuffer text = new StringBuffer();
private int sheetNum = -1;
private int rowNum;
-
+
private boolean outputNextStringValue = false;
private int nextRow = -1;
-
+
public void processRecord(Record record) {
String thisText = null;
int thisRow = -1;
if(bof.getType() == BOFRecord.TYPE_WORKSHEET) {
sheetNum++;
rowNum = -1;
-
+
if(includeSheetNames) {
if(text.length() > 0) text.append("\n");
text.append(sheetNames.get(sheetNum));
case SSTRecord.sid:
sstRecord = (SSTRecord)record;
break;
-
- case FormulaRecord.sid:
- FormulaRecord frec = (FormulaRecord) record;
- thisRow = frec.getRow();
-
- if(formulasNotResults) {
- thisText = FormulaParser.toFormulaString(null, frec.getParsedExpression());
- } else {
- if(Double.isNaN( frec.getValue() )) {
- // Formula result is a string
- // This is stored in the next record
- outputNextStringValue = true;
- nextRow = frec.getRow();
- } else {
- thisText = formatNumberDateCell(frec, frec.getValue());
- }
- }
- break;
- case StringRecord.sid:
- if(outputNextStringValue) {
- // String for formula
- StringRecord srec = (StringRecord)record;
- thisText = srec.getString();
- thisRow = nextRow;
- outputNextStringValue = false;
- }
- break;
- case LabelRecord.sid:
- LabelRecord lrec = (LabelRecord) record;
- thisRow = lrec.getRow();
- thisText = lrec.getValue();
- break;
- case LabelSSTRecord.sid:
- LabelSSTRecord lsrec = (LabelSSTRecord) record;
- thisRow = lsrec.getRow();
- if(sstRecord == null) {
- throw new IllegalStateException("No SST record found");
- }
- thisText = sstRecord.getString(lsrec.getSSTIndex()).toString();
- break;
- case NoteRecord.sid:
- NoteRecord nrec = (NoteRecord) record;
- thisRow = nrec.getRow();
- // TODO: Find object to match nrec.getShapeId()
- break;
- case NumberRecord.sid:
- NumberRecord numrec = (NumberRecord) record;
- thisRow = numrec.getRow();
- thisText = formatNumberDateCell(numrec, numrec.getValue());
- break;
- default:
- break;
+
+ case FormulaRecord.sid:
+ FormulaRecord frec = (FormulaRecord) record;
+ thisRow = frec.getRow();
+
+ if(formulasNotResults) {
+ thisText = FormulaParser.toFormulaString(null, frec.getParsedExpression());
+ } else {
+ if(frec.hasCachedResultString()) {
+ // Formula result is a string
+ // This is stored in the next record
+ outputNextStringValue = true;
+ nextRow = frec.getRow();
+ } else {
+ thisText = formatNumberDateCell(frec, frec.getValue());
+ }
+ }
+ break;
+ case StringRecord.sid:
+ if(outputNextStringValue) {
+ // String for formula
+ StringRecord srec = (StringRecord)record;
+ thisText = srec.getString();
+ thisRow = nextRow;
+ outputNextStringValue = false;
+ }
+ break;
+ case LabelRecord.sid:
+ LabelRecord lrec = (LabelRecord) record;
+ thisRow = lrec.getRow();
+ thisText = lrec.getValue();
+ break;
+ case LabelSSTRecord.sid:
+ LabelSSTRecord lsrec = (LabelSSTRecord) record;
+ thisRow = lsrec.getRow();
+ if(sstRecord == null) {
+ throw new IllegalStateException("No SST record found");
+ }
+ thisText = sstRecord.getString(lsrec.getSSTIndex()).toString();
+ break;
+ case NoteRecord.sid:
+ NoteRecord nrec = (NoteRecord) record;
+ thisRow = nrec.getRow();
+ // TODO: Find object to match nrec.getShapeId()
+ break;
+ case NumberRecord.sid:
+ NumberRecord numrec = (NumberRecord) record;
+ thisRow = numrec.getRow();
+ thisText = formatNumberDateCell(numrec, numrec.getValue());
+ break;
+ default:
+ break;
}
-
+
if(thisText != null) {
if(thisRow != rowNum) {
rowNum = thisRow;
text.append(thisText);
}
}
-
+
/**
- * Formats a number or date cell, be that a real number, or the
+ * Formats a number or date cell, be that a real number, or the
* answer to a formula
*/
private String formatNumberDateCell(CellValueRecordInterface cell, double value) {
- // Get the built in format, if there is one
+ // Get the built in format, if there is one
int formatIndex = ft.getFormatIndex(cell);
String formatString = ft.getFormatString(cell);
-
+
if(formatString == null) {
- return Double.toString(value);
- } else {
- // Is it a date?
- if(HSSFDateUtil.isADateFormat(formatIndex,formatString) &&
- HSSFDateUtil.isValidExcelDate(value)) {
- // Java wants M not m for month
- formatString = formatString.replace('m','M');
- // Change \- into -, if it's there
- formatString = formatString.replaceAll("\\\\-","-");
-
- // Format as a date
- Date d = HSSFDateUtil.getJavaDate(value, false);
- DateFormat df = new SimpleDateFormat(formatString);
- return df.format(d);
- } else {
- if(formatString == "General") {
- // Some sort of wierd default
- return Double.toString(value);
- }
-
- // Format as a number
- DecimalFormat df = new DecimalFormat(formatString);
- return df.format(value);
- }
- }
+ return Double.toString(value);
+ } else {
+ // Is it a date?
+ if(HSSFDateUtil.isADateFormat(formatIndex,formatString) &&
+ HSSFDateUtil.isValidExcelDate(value)) {
+ // Java wants M not m for month
+ formatString = formatString.replace('m','M');
+ // Change \- into -, if it's there
+ formatString = formatString.replaceAll("\\\\-","-");
+
+ // Format as a date
+ Date d = HSSFDateUtil.getJavaDate(value, false);
+ DateFormat df = new SimpleDateFormat(formatString);
+ return df.format(d);
+ } else {
+ if(formatString == "General") {
+ // Some sort of wierd default
+ return Double.toString(value);
+ }
+
+ // Format as a number
+ DecimalFormat df = new DecimalFormat(formatString);
+ return df.format(value);
+ }
+ }
}
}
}
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
+
package org.apache.poi.hssf.extractor;
import java.io.IOException;
import org.apache.poi.POIOLE2TextExtractor;
import org.apache.poi.ss.usermodel.HeaderFooter;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFComment;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
int lastCell = row.getLastCellNum();
for(int k=firstCell;k<lastCell;k++) {
HSSFCell cell = row.getCell(k);
- boolean outputContents = false;
if(cell == null) { continue; }
+ boolean outputContents = true;
switch(cell.getCellType()) {
+ case HSSFCell.CELL_TYPE_BLANK:
+ outputContents = false;
+ break;
case HSSFCell.CELL_TYPE_STRING:
text.append(cell.getRichStringCellValue().getString());
- outputContents = true;
break;
case HSSFCell.CELL_TYPE_NUMERIC:
// Note - we don't apply any formatting!
text.append(cell.getNumericCellValue());
- outputContents = true;
break;
case HSSFCell.CELL_TYPE_BOOLEAN:
text.append(cell.getBooleanCellValue());
- outputContents = true;
+ break;
+ case HSSFCell.CELL_TYPE_ERROR:
+ text.append(ErrorEval.getText(cell.getErrorCellValue()));
break;
case HSSFCell.CELL_TYPE_FORMULA:
if(formulasNotResults) {
text.append(cell.getCellFormula());
} else {
- // Try it as a string, if not as a number
- HSSFRichTextString str =
- cell.getRichStringCellValue();
- if(str != null && str.length() > 0) {
- text.append(str.toString());
- } else {
- // Try and treat it as a number
- double val = cell.getNumericCellValue();
- text.append(val);
+ switch(cell.getCachedFormulaResultType()) {
+ case HSSFCell.CELL_TYPE_STRING:
+ HSSFRichTextString str = cell.getRichStringCellValue();
+ if(str != null && str.length() > 0) {
+ text.append(str.toString());
+ }
+ break;
+ case HSSFCell.CELL_TYPE_NUMERIC:
+ text.append(cell.getNumericCellValue());
+ break;
+ case HSSFCell.CELL_TYPE_BOOLEAN:
+ text.append(cell.getBooleanCellValue());
+ break;
+ case HSSFCell.CELL_TYPE_ERROR:
+ text.append(ErrorEval.getText(cell.getErrorCellValue()));
+ break;
+
}
}
- outputContents = true;
break;
+ default:
+ throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
}
// Output the comment, if requested and exists
import java.util.Stack;
//import PTGs .. since we need everything, import *
+import org.apache.poi.hssf.record.UnicodeString;
+import org.apache.poi.hssf.record.constant.ErrorConstant;
import org.apache.poi.hssf.record.formula.*;
import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.AreaReference;
public static final int FORMULA_TYPE_ARRAY =2;
public static final int FORMULA_TYPE_CONDFORMAT = 3;
public static final int FORMULA_TYPE_NAMEDRANGE = 4;
- // this constant is currently very specific. The exact differences from general data
+ // this constant is currently very specific. The exact differences from general data
// validation formulas or conditional format formulas is not known yet
- public static final int FORMULA_TYPE_DATAVALIDATION_LIST = 5;
+ public static final int FORMULA_TYPE_DATAVALIDATION_LIST = 5;
private final String formulaString;
private final int formulaLength;
/** Report What Was Expected */
private RuntimeException expected(String s) {
String msg;
-
+
if (look == '=' && formulaString.substring(0, pointer-1).trim().length() < 1) {
- msg = "The specified formula '" + formulaString
+ msg = "The specified formula '" + formulaString
+ "' starts with an equals sign which is not allowed.";
} else {
msg = "Parse error near char " + (pointer-1) + " '" + look + "'"
/**
* Parses a sheet name, named range name, or simple cell reference.<br/>
* Note - identifiers in Excel can contain dots, so this method may return a String
- * which may need to be converted to an area reference. For example, this method
- * may return a value like "A1..B2", in which case the caller must convert it to
+ * which may need to be converted to an area reference. For example, this method
+ * may return a value like "A1..B2", in which case the caller must convert it to
* an area reference like "A1:B2"
*/
private String parseIdentifier() {
}
private Ptg parseNameOrReference(String name) {
-
+
AreaReference areaRef = parseArea(name);
if (areaRef != null) {
// will happen if dots are used instead of colon
private ParseNode function(String name) {
Ptg nameToken = null;
if(!AbstractFunctionPtg.isBuiltInFunctionName(name)) {
- // user defined function
+ // user defined function
// in the token tree, the name is more or less the first argument
-
-
- int nameIndex = book.getNameIndex(name);
- if (nameIndex >= 0) {
- Name hName = book.getNameAt(nameIndex);
- if (!hName.isFunctionName()) {
- throw new FormulaParseException("Attempt to use name '" + name
- + "' as a function, but defined name in workbook does not refer to a function");
- }
-
- // calls to user-defined functions within the workbook
- // get a Name token which points to a defined name record
- nameToken = new NamePtg(name, this.book);
- } else {
+ int nameIndex = book.getNameIndex(name);
+ if (nameIndex >= 0) {
+ Name hName = book.getNameAt(nameIndex);
+ if (!hName.isFunctionName()) {
+ throw new FormulaParseException("Attempt to use name '" + name
+ + "' as a function, but defined name in workbook does not refer to a function");
+ }
+
+ // calls to user-defined functions within the workbook
+ // get a Name token which points to a defined name record
+ nameToken = new NamePtg(name, this.book);
+ } else {
if(book instanceof HSSFWorkbook) {
nameToken = ((HSSFWorkbook)book).getNameXPtg(name);
}
- if (nameToken == null) {
- throw new FormulaParseException("Name '" + name
- + "' is completely unknown in the current workbook");
- }
- }
+ if (nameToken == null) {
+ throw new FormulaParseException("Name '" + name
+ + "' is completely unknown in the current workbook");
+ }
+ }
}
Match('(');
SkipWhite();
switch(look) {
case '#':
- return new ParseNode(parseErrorLiteral());
+ return new ParseNode(ErrPtg.valueOf(parseErrorLiteral()));
case '-':
Match('-');
return new ParseNode(UnaryMinusPtg.instance, powerFactor());
Match(')');
return new ParseNode(ParenthesisPtg.instance, inside);
case '"':
- return new ParseNode(parseStringLiteral());
+ return new ParseNode(new StringPtg(parseStringLiteral()));
+ case '{':
+ Match('{');
+ ParseNode arrayNode = parseArray();
+ Match('}');
+ return arrayNode;
}
if (IsAlpha(look) || look == '\''){
return parseFunctionReferenceOrName();
}
+ private ParseNode parseArray() {
+ List rowsData = new ArrayList();
+ while(true) {
+ Object[] singleRowData = parseArrayRow();
+ rowsData.add(singleRowData);
+ if (look == '}') {
+ break;
+ }
+ if (look != ';') {
+ throw expected("'}' or ';'");
+ }
+ Match(';');
+ }
+ int nRows = rowsData.size();
+ Object[][] values2d = new Object[nRows][];
+ rowsData.toArray(values2d);
+ int nColumns = values2d[0].length;
+ checkRowLengths(values2d, nColumns);
+
+ return new ParseNode(new ArrayPtg(values2d));
+ }
+ private void checkRowLengths(Object[][] values2d, int nColumns) {
+ for (int i = 0; i < values2d.length; i++) {
+ int rowLen = values2d[i].length;
+ if (rowLen != nColumns) {
+ throw new FormulaParseException("Array row " + i + " has length " + rowLen
+ + " but row 0 has length " + nColumns);
+ }
+ }
+ }
+
+ private Object[] parseArrayRow() {
+ List temp = new ArrayList();
+ while (true) {
+ temp.add(parseArrayItem());
+ SkipWhite();
+ switch(look) {
+ case '}':
+ case ';':
+ break;
+ case ',':
+ Match(',');
+ continue;
+ default:
+ throw expected("'}' or ','");
+
+ }
+ break;
+ }
+
+ Object[] result = new Object[temp.size()];
+ temp.toArray(result);
+ return result;
+ }
+
+ private Object parseArrayItem() {
+ SkipWhite();
+ switch(look) {
+ case '"': return new UnicodeString(parseStringLiteral());
+ case '#': return ErrorConstant.valueOf(parseErrorLiteral());
+ case 'F': case 'f':
+ case 'T': case 't':
+ return parseBooleanLiteral();
+ }
+ // else assume number
+ return convertArrayNumber(parseNumber());
+ }
+
+ private Boolean parseBooleanLiteral() {
+ String iden = parseIdentifier();
+ if ("TRUE".equalsIgnoreCase(iden)) {
+ return Boolean.TRUE;
+ }
+ if ("FALSE".equalsIgnoreCase(iden)) {
+ return Boolean.FALSE;
+ }
+ throw expected("'TRUE' or 'FALSE'");
+ }
+
+ private static Double convertArrayNumber(Ptg ptg) {
+ if (ptg instanceof IntPtg) {
+ return new Double(((IntPtg)ptg).getValue());
+ }
+ if (ptg instanceof NumberPtg) {
+ return new Double(((NumberPtg)ptg).getValue());
+ }
+ throw new RuntimeException("Unexpected ptg (" + ptg.getClass().getName() + ")");
+ }
+
private Ptg parseNumber() {
String number2 = null;
String exponent = null;
}
- private ErrPtg parseErrorLiteral() {
+ private int parseErrorLiteral() {
Match('#');
String part1 = parseIdentifier().toUpperCase();
case 'V':
if(part1.equals("VALUE")) {
Match('!');
- return ErrPtg.VALUE_INVALID;
+ return HSSFErrorConstants.ERROR_VALUE;
}
throw expected("#VALUE!");
case 'R':
if(part1.equals("REF")) {
Match('!');
- return ErrPtg.REF_INVALID;
+ return HSSFErrorConstants.ERROR_REF;
}
throw expected("#REF!");
case 'D':
Match('/');
Match('0');
Match('!');
- return ErrPtg.DIV_ZERO;
+ return HSSFErrorConstants.ERROR_DIV_0;
}
throw expected("#DIV/0!");
case 'N':
if(part1.equals("NAME")) {
Match('?'); // only one that ends in '?'
- return ErrPtg.NAME_INVALID;
+ return HSSFErrorConstants.ERROR_NAME;
}
if(part1.equals("NUM")) {
Match('!');
- return ErrPtg.NUM_ERROR;
+ return HSSFErrorConstants.ERROR_NUM;
}
if(part1.equals("NULL")) {
Match('!');
- return ErrPtg.NULL_INTERSECTION;
+ return HSSFErrorConstants.ERROR_NULL;
}
if(part1.equals("N")) {
Match('/');
}
Match(look);
// Note - no '!' or '?' suffix
- return ErrPtg.N_A;
+ return HSSFErrorConstants.ERROR_NA;
}
throw expected("#NAME?, #NUM!, #NULL! or #N/A");
}
- private StringPtg parseStringLiteral() {
+ private String parseStringLiteral() {
Match('"');
StringBuffer token = new StringBuffer();
token.append(look);
GetChar();
}
- return new StringPtg(token.toString());
+ return token.toString();
}
/** Parse and Translate a Math Term */
}
return result;
}
-
+
private static String[] getOperands(Stack stack, int nOperands) {
String[] operands = new String[nOperands];
+ _formulaType + ") not supported yet");
}
- transformNode(rootNode, rootNodeOperandClass, false, false);
+ transformNode(rootNode, rootNodeOperandClass, false);
}
/**
* the function return value).
*/
private void transformNode(ParseNode node, byte desiredOperandClass,
- boolean callerForceArrayFlag, boolean isDirectChildOfValueOperator) {
+ boolean callerForceArrayFlag) {
Ptg token = node.getToken();
ParseNode[] children = node.getChildren();
+ boolean isSimpleValueFunc = isSimpleValueFunction(token);
+
+ if (isSimpleValueFunc) {
+ boolean localForceArray = desiredOperandClass == Ptg.CLASS_ARRAY;
+ for (int i = 0; i < children.length; i++) {
+ transformNode(children[i], desiredOperandClass, localForceArray);
+ }
+ setSimpleValueFuncClass((AbstractFunctionPtg) token, desiredOperandClass, callerForceArrayFlag);
+ return;
+ }
+
if (token instanceof ValueOperatorPtg || token instanceof ControlPtg) {
// Value Operator Ptgs and Control are base tokens, so token will be unchanged
-
// but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag
+
+ // As per OOO documentation Sec 3.2.4 "Token Class Transformation", "Step 1"
+ // All direct operands of value operators that are initially 'R' type will
+ // be converted to 'V' type.
+ byte localDesiredOperandClass = desiredOperandClass == Ptg.CLASS_REF ? Ptg.CLASS_VALUE : desiredOperandClass;
for (int i = 0; i < children.length; i++) {
- ParseNode child = children[i];
- transformNode(child, desiredOperandClass, callerForceArrayFlag, true);
+ transformNode(children[i], localDesiredOperandClass, callerForceArrayFlag);
}
return;
}
if (token instanceof AbstractFunctionPtg) {
- transformFunctionNode((AbstractFunctionPtg) token, children, desiredOperandClass,
- callerForceArrayFlag);
+ transformFunctionNode((AbstractFunctionPtg) token, children, desiredOperandClass, callerForceArrayFlag);
return;
}
if (children.length > 0) {
// nothing to do
return;
}
- if (isDirectChildOfValueOperator) {
- // As per OOO documentation Sec 3.2.4 "Token Class Transformation", "Step 1"
- // All direct operands of value operators that are initially 'R' type will
- // be converted to 'V' type.
- if (token.getPtgClass() == Ptg.CLASS_REF) {
- token.setClass(Ptg.CLASS_VALUE);
+ token.setClass(transformClass(token.getPtgClass(), desiredOperandClass, callerForceArrayFlag));
+ }
+
+ private static boolean isSimpleValueFunction(Ptg token) {
+ if (token instanceof AbstractFunctionPtg) {
+ AbstractFunctionPtg aptg = (AbstractFunctionPtg) token;
+ if (aptg.getDefaultOperandClass() != Ptg.CLASS_VALUE) {
+ return false;
+ }
+ int numberOfOperands = aptg.getNumberOfOperands();
+ for (int i=numberOfOperands-1; i>=0; i--) {
+ if (aptg.getParameterClass(i) != Ptg.CLASS_VALUE) {
+ return false;
+ }
}
+ return true;
}
- token.setClass(transformClass(token.getPtgClass(), desiredOperandClass, callerForceArrayFlag));
+ return false;
}
private byte transformClass(byte currentOperandClass, byte desiredOperandClass,
switch (defaultReturnOperandClass) {
case Ptg.CLASS_REF:
afp.setClass(Ptg.CLASS_REF);
+// afp.setClass(Ptg.CLASS_ARRAY);
break;
case Ptg.CLASS_VALUE:
afp.setClass(Ptg.CLASS_ARRAY);
for (int i = 0; i < children.length; i++) {
ParseNode child = children[i];
byte paramOperandClass = afp.getParameterClass(i);
- transformNode(child, paramOperandClass, localForceArrayFlag, false);
+ transformNode(child, paramOperandClass, localForceArrayFlag);
+ }
+ }
+
+ private void setSimpleValueFuncClass(AbstractFunctionPtg afp,
+ byte desiredOperandClass, boolean callerForceArrayFlag) {
+
+ if (callerForceArrayFlag || desiredOperandClass == Ptg.CLASS_ARRAY) {
+ afp.setClass(Ptg.CLASS_ARRAY);
+ } else {
+ afp.setClass(Ptg.CLASS_VALUE);
}
}
}
ColumnInfoRecord ci = _columnInfos.findColumnInfo(columnIndex);
if (ci != null) {
- return ci.getColumnWidth();
+ return (short)ci.getColumnWidth();
}
//default column width is measured in characters
//multiply
public short getXFIndexForColAt(short columnIndex) {
ColumnInfoRecord ci = _columnInfos.findColumnInfo(columnIndex);
if (ci != null) {
- return ci.getXFIndex();
- }
+ return (short)ci.getXFIndex();
+ }
return 0xF;
}
* @param indent if true the group will be indented by one level,
* if false indenting will be removed by one level.
*/
- public void groupColumnRange(short fromColumn, short toColumn, boolean indent)
- {
+ public void groupColumnRange(int fromColumn, int toColumn, boolean indent) {
// Set the level for each column
_columnInfos.groupColumnRange( fromColumn, toColumn, indent);
}
- public void setColumnGroupCollapsed( short columnNumber, boolean collapsed )
- {
- if (collapsed)
- {
- _columnInfos.collapseColumn( columnNumber );
- }
- else
- {
- _columnInfos.expandColumn( columnNumber );
- }
- }
+ public void setColumnGroupCollapsed(int columnNumber, boolean collapsed) {
+ if (collapsed) {
+ _columnInfos.collapseColumn(columnNumber);
+ } else {
+ _columnInfos.expandColumn(columnNumber);
+ }
+ }
/**
* protect a spreadsheet with a password (not encypted, just sets protect
package org.apache.poi.hssf.record;
+import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
*/
public final class ColumnInfoRecord extends Record {
public static final short sid = 0x7d;
- private short field_1_first_col;
- private short field_2_last_col;
- private short field_3_col_width;
- private short field_4_xf_index;
- private short field_5_options;
+ private int field_1_first_col;
+ private int field_2_last_col;
+ private int field_3_col_width;
+ private int field_4_xf_index;
+ private int field_5_options;
private static final BitField hidden = BitFieldFactory.getInstance(0x01);
private static final BitField outlevel = BitFieldFactory.getInstance(0x0700);
private static final BitField collapsed = BitFieldFactory.getInstance(0x1000);
// Excel seems write values 2, 10, and 260, even though spec says "must be zero"
private short field_6_reserved;
- public ColumnInfoRecord()
- {
+ /**
+ * Creates a column info record with default width and format
+ */
+ public ColumnInfoRecord() {
+ setColumnWidth(2275);
+ field_5_options = 2;
+ field_4_xf_index = 0x0f;
field_6_reserved = 2; // seems to be the most common value
}
* @param fc - the first column index (0-based)
*/
- public void setFirstColumn(short fc)
+ public void setFirstColumn(int fc)
{
field_1_first_col = fc;
}
* @param lc - the last column index (0-based)
*/
- public void setLastColumn(short lc)
+ public void setLastColumn(int lc)
{
field_2_last_col = lc;
}
* @param cw - column width
*/
- public void setColumnWidth(short cw)
+ public void setColumnWidth(int cw)
{
field_3_col_width = cw;
}
* @see org.apache.poi.hssf.record.ExtendedFormatRecord
*/
- public void setXFIndex(short xfi)
+ public void setXFIndex(int xfi)
{
field_4_xf_index = xfi;
}
- /**
- * set the options bitfield - use the bitsetters instead
- * @param options - the bitfield raw value
- */
-
- public void setOptions(short options)
- {
- field_5_options = options;
- }
// start options bitfield
public void setHidden(boolean ishidden)
{
- field_5_options = hidden.setShortBoolean(field_5_options, ishidden);
+ field_5_options = hidden.setBoolean(field_5_options, ishidden);
}
/**
* @param olevel -outline level for the cells
*/
- public void setOutlineLevel(short olevel)
+ public void setOutlineLevel(int olevel)
{
- field_5_options = outlevel.setShortValue(field_5_options, olevel);
+ field_5_options = outlevel.setValue(field_5_options, olevel);
}
/**
public void setCollapsed(boolean iscollapsed)
{
- field_5_options = collapsed.setShortBoolean(field_5_options,
+ field_5_options = collapsed.setBoolean(field_5_options,
iscollapsed);
}
* @return the first column index (0-based)
*/
- public short getFirstColumn()
+ public int getFirstColumn()
{
return field_1_first_col;
}
* @return the last column index (0-based)
*/
- public short getLastColumn()
+ public int getLastColumn()
{
return field_2_last_col;
}
* @return column width
*/
- public short getColumnWidth()
+ public int getColumnWidth()
{
return field_3_col_width;
}
* @see org.apache.poi.hssf.record.ExtendedFormatRecord
*/
- public short getXFIndex()
+ public int getXFIndex()
{
return field_4_xf_index;
}
- /**
- * get the options bitfield - use the bitsetters instead
- * @return the bitfield raw value
- */
-
- public short getOptions()
- {
+ public int getOptions() {
return field_5_options;
}
-
+ public void setOptions(int field_5_options) {
+ this.field_5_options = field_5_options;
+ }
+
// start options bitfield
/**
* @return outline level for the cells
*/
- public short getOutlineLevel()
+ public int getOutlineLevel()
{
- return outlevel.getShortValue(field_5_options);
+ return outlevel.getValue(field_5_options);
}
/**
}
// end options bitfield
+
+ public boolean containsColumn(int columnIndex) {
+ return field_1_first_col <= columnIndex && columnIndex <= field_2_last_col;
+ }
+ public boolean isAdjacentBefore(ColumnInfoRecord other) {
+ return field_2_last_col == other.field_1_first_col - 1;
+ }
+
+ /**
+ * @return <code>true</code> if the format, options and column width match
+ */
+ public boolean formatMatches(ColumnInfoRecord other) {
+ if (field_4_xf_index != other.field_4_xf_index) {
+ return false;
+ }
+ if (field_5_options != other.field_5_options) {
+ return false;
+ }
+ if (field_3_col_width != other.field_3_col_width) {
+ return false;
+ }
+ return true;
+ }
+
+
public short getSid()
{
return sid;
public int serialize(int offset, byte [] data)
{
LittleEndian.putShort(data, 0 + offset, sid);
- LittleEndian.putShort(data, 2 + offset, ( short ) 12);
- LittleEndian.putShort(data, 4 + offset, getFirstColumn());
- LittleEndian.putShort(data, 6 + offset, getLastColumn());
- LittleEndian.putShort(data, 8 + offset, getColumnWidth());
- LittleEndian.putShort(data, 10 + offset, getXFIndex());
- LittleEndian.putShort(data, 12 + offset, getOptions());
- LittleEndian.putShort(data, 14 + offset, field_6_reserved);
+ LittleEndian.putUShort(data, 2 + offset, 12);
+ LittleEndian.putUShort(data, 4 + offset, getFirstColumn());
+ LittleEndian.putUShort(data, 6 + offset, getLastColumn());
+ LittleEndian.putUShort(data, 8 + offset, getColumnWidth());
+ LittleEndian.putUShort(data, 10 + offset, getXFIndex());
+ LittleEndian.putUShort(data, 12 + offset, field_5_options);
+ LittleEndian.putUShort(data, 14 + offset, field_6_reserved);
return getRecordSize();
}
public String toString()
{
- StringBuffer buffer = new StringBuffer();
-
- buffer.append("[COLINFO]\n");
- buffer.append("colfirst = ").append(getFirstColumn())
- .append("\n");
- buffer.append("collast = ").append(getLastColumn())
- .append("\n");
- buffer.append("colwidth = ").append(getColumnWidth())
- .append("\n");
- buffer.append("xfindex = ").append(getXFIndex()).append("\n");
- buffer.append("options = ").append(getOptions()).append("\n");
- buffer.append(" hidden = ").append(getHidden()).append("\n");
- buffer.append(" olevel = ").append(getOutlineLevel())
- .append("\n");
- buffer.append(" collapsed = ").append(getCollapsed())
- .append("\n");
- buffer.append("[/COLINFO]\n");
- return buffer.toString();
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("[COLINFO]\n");
+ sb.append(" colfirst = ").append(getFirstColumn()).append("\n");
+ sb.append(" collast = ").append(getLastColumn()).append("\n");
+ sb.append(" colwidth = ").append(getColumnWidth()).append("\n");
+ sb.append(" xfindex = ").append(getXFIndex()).append("\n");
+ sb.append(" options = ").append(HexDump.shortToHex(field_5_options)).append("\n");
+ sb.append(" hidden = ").append(getHidden()).append("\n");
+ sb.append(" olevel = ").append(getOutlineLevel()).append("\n");
+ sb.append(" collapsed= ").append(getCollapsed()).append("\n");
+ sb.append("[/COLINFO]\n");
+ return sb.toString();
}
public Object clone() {
package org.apache.poi.hssf.record;
import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.HexDump;
*/
public final class FormulaRecord extends Record implements CellValueRecordInterface {
- public static final short sid = 0x0006; // docs say 406...because of a bug Microsoft support site article #Q184647)
- private static int FIXED_SIZE = 22;
-
- private static final BitField alwaysCalc = BitFieldFactory.getInstance(0x0001);
- private static final BitField calcOnLoad = BitFieldFactory.getInstance(0x0002);
- private static final BitField sharedFormula = BitFieldFactory.getInstance(0x0008);
-
- private int field_1_row;
- private short field_2_column;
- private short field_3_xf;
- private double field_4_value;
- private short field_5_options;
- private int field_6_zero;
- private Ptg[] field_8_parsed_expr;
-
- /**
- * Since the NaN support seems sketchy (different constants) we'll store and spit it out directly
- */
- private byte[] value_data;
-
- /** Creates new FormulaRecord */
-
- public FormulaRecord() {
- field_8_parsed_expr = Ptg.EMPTY_PTG_ARRAY;
- }
-
- /**
- * Constructs a Formula record and sets its fields appropriately.
- * Note - id must be 0x06 (NOT 0x406 see MSKB #Q184647 for an
- * "explanation of this bug in the documentation) or an exception
- * will be throw upon validation
- *
- * @param in the RecordInputstream to read the record from
- */
-
- public FormulaRecord(RecordInputStream in) {
- super(in);
- }
-
- protected void fillFields(RecordInputStream in) {
- field_1_row = in.readUShort();
- field_2_column = in.readShort();
- field_3_xf = in.readShort();
- field_4_value = in.readDouble();
- field_5_options = in.readShort();
-
- if (Double.isNaN(field_4_value)) {
- value_data = in.getNANData();
- }
-
- field_6_zero = in.readInt();
- int field_7_expression_len = in.readShort(); // this length does not include any extra array data
- field_8_parsed_expr = Ptg.readTokens(field_7_expression_len, in);
- if (in.remaining() == 10) {
- // TODO - this seems to occur when IntersectionPtg is present
- // 10 extra bytes are just 0x01 and 0x00
- // This causes POI stderr: "WARN. Unread 10 bytes of record 0x6"
- }
- }
-
- public void setRow(int row) {
- field_1_row = row;
- }
-
- public void setColumn(short column) {
- field_2_column = column;
- }
-
- public void setXFIndex(short xf) {
- field_3_xf = xf;
- }
-
- /**
- * set the calculated value of the formula
- *
- * @param value calculated value
- */
- public void setValue(double value) {
- field_4_value = value;
- }
-
- /**
- * set the option flags
- *
- * @param options bitmask
- */
- public void setOptions(short options) {
- field_5_options = options;
- }
-
- public int getRow() {
- return field_1_row;
- }
-
- public short getColumn() {
- return field_2_column;
- }
-
- public short getXFIndex() {
- return field_3_xf;
- }
-
- /**
- * get the calculated value of the formula
- *
- * @return calculated value
- */
- public double getValue() {
- return field_4_value;
- }
-
- /**
- * get the option flags
- *
- * @return bitmask
- */
- public short getOptions() {
- return field_5_options;
- }
-
- public boolean isSharedFormula() {
- return sharedFormula.isSet(field_5_options);
- }
- public void setSharedFormula(boolean flag) {
- field_5_options =
- sharedFormula.setShortBoolean(field_5_options, flag);
- }
-
- public boolean isAlwaysCalc() {
- return alwaysCalc.isSet(field_5_options);
- }
- public void setAlwaysCalc(boolean flag) {
- field_5_options =
- alwaysCalc.setShortBoolean(field_5_options, flag);
- }
-
- public boolean isCalcOnLoad() {
- return calcOnLoad.isSet(field_5_options);
- }
- public void setCalcOnLoad(boolean flag) {
- field_5_options =
- calcOnLoad.setShortBoolean(field_5_options, flag);
- }
-
- /**
- * @return the formula tokens. never <code>null</code>
- */
- public Ptg[] getParsedExpression() {
- return (Ptg[]) field_8_parsed_expr.clone();
- }
-
- public void setParsedExpression(Ptg[] ptgs) {
- field_8_parsed_expr = ptgs;
- }
-
- /**
- * called by constructor, should throw runtime exception in the event of a
- * record passed with a differing ID.
- *
- * @param id alleged id for this record
- */
- protected void validateSid(short id) {
- if (id != sid) {
- throw new RecordFormatException("NOT A FORMULA RECORD");
- }
- }
-
- public short getSid() {
- return sid;
- }
-
- private int getDataSize() {
- return FIXED_SIZE + Ptg.getEncodedSize(field_8_parsed_expr);
- }
- public int serialize(int offset, byte [] data) {
-
- int dataSize = getDataSize();
-
- LittleEndian.putShort(data, 0 + offset, sid);
- LittleEndian.putUShort(data, 2 + offset, dataSize);
- LittleEndian.putUShort(data, 4 + offset, getRow());
- LittleEndian.putShort(data, 6 + offset, getColumn());
- LittleEndian.putShort(data, 8 + offset, getXFIndex());
-
- //only reserialize if the value is still NaN and we have old nan data
- if (Double.isNaN(getValue()) && value_data != null) {
- System.arraycopy(value_data,0,data,10 + offset,value_data.length);
- } else {
- LittleEndian.putDouble(data, 10 + offset, field_4_value);
- }
-
- LittleEndian.putShort(data, 18 + offset, getOptions());
-
- //when writing the chn field (offset 20), it's supposed to be 0 but ignored on read
- //Microsoft Excel Developer's Kit Page 318
- LittleEndian.putInt(data, 20 + offset, 0);
- int formulaTokensSize = Ptg.getEncodedSizeWithoutArrayData(field_8_parsed_expr);
- LittleEndian.putUShort(data, 24 + offset, formulaTokensSize);
- Ptg.serializePtgs(field_8_parsed_expr, data, 26+offset);
- return 4 + dataSize;
- }
-
- public int getRecordSize() {
- return 4 + getDataSize();
- }
-
- public boolean isInValueSection() {
- return true;
- }
-
- public boolean isValue() {
- return true;
- }
-
- public String toString() {
-
- StringBuffer sb = new StringBuffer();
- sb.append("[FORMULA]\n");
- sb.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n");
- sb.append(" .column = ").append(HexDump.shortToHex(getColumn())).append("\n");
- sb.append(" .xf = ").append(HexDump.shortToHex(getXFIndex())).append("\n");
- sb.append(" .value = ");
- if (Double.isNaN(this.getValue()) && value_data != null) {
- sb.append("(NaN)").append(HexDump.dump(value_data,0,0)).append("\n");
- } else {
- sb.append(getValue()).append("\n");
- }
- sb.append(" .options = ").append(HexDump.shortToHex(getOptions())).append("\n");
- sb.append(" .alwaysCalc= ").append(alwaysCalc.isSet(getOptions())).append("\n");
- sb.append(" .calcOnLoad= ").append(calcOnLoad.isSet(getOptions())).append("\n");
- sb.append(" .shared = ").append(sharedFormula.isSet(getOptions())).append("\n");
- sb.append(" .zero = ").append(HexDump.intToHex(field_6_zero)).append("\n");
-
- for (int k = 0; k < field_8_parsed_expr.length; k++ ) {
- sb.append(" Ptg[").append(k).append("]=");
- Ptg ptg = field_8_parsed_expr[k];
- sb.append(ptg.toString()).append(ptg.getRVAType()).append("\n");
- }
- sb.append("[/FORMULA]\n");
- return sb.toString();
- }
-
- public Object clone() {
- FormulaRecord rec = new FormulaRecord();
- rec.field_1_row = field_1_row;
- rec.field_2_column = field_2_column;
- rec.field_3_xf = field_3_xf;
- rec.field_4_value = field_4_value;
- rec.field_5_options = field_5_options;
- rec.field_6_zero = field_6_zero;
- int nTokens = field_8_parsed_expr.length;
- Ptg[] ptgs = new Ptg[nTokens];
- for (int i=0; i< nTokens; i++) {
- ptgs[i] = field_8_parsed_expr[i].copy();
- }
- rec.field_8_parsed_expr = ptgs;
- rec.value_data = value_data;
- return rec;
- }
+ public static final short sid = 0x0006; // docs say 406...because of a bug Microsoft support site article #Q184647)
+ private static int FIXED_SIZE = 22;
+
+ private static final BitField alwaysCalc = BitFieldFactory.getInstance(0x0001);
+ private static final BitField calcOnLoad = BitFieldFactory.getInstance(0x0002);
+ private static final BitField sharedFormula = BitFieldFactory.getInstance(0x0008);
+
+ /**
+ * Manages the cached formula result values of other types besides numeric.
+ * Excel encodes the same 8 bytes that would be field_4_value with various NaN
+ * values that are decoded/encoded by this class.
+ */
+ private static final class SpecialCachedValue {
+ /** deliberately chosen by Excel in order to encode other values within Double NaNs */
+ private static final long BIT_MARKER = 0xFFFF000000000000L;
+ private static final int VARIABLE_DATA_LENGTH = 6;
+ private static final int DATA_INDEX = 2;
+
+ public static final int STRING = 0;
+ public static final int BOOLEAN = 1;
+ public static final int ERROR_CODE = 2;
+ public static final int EMPTY = 3;
+
+ private final byte[] _variableData;
+
+ private SpecialCachedValue(byte[] data) {
+ _variableData = data;
+ }
+ public int getTypeCode() {
+ return _variableData[0];
+ }
+
+ /**
+ * @return <code>null</code> if the double value encoded by <tt>valueLongBits</tt>
+ * is a normal (non NaN) double value.
+ */
+ public static SpecialCachedValue create(long valueLongBits) {
+ if ((BIT_MARKER & valueLongBits) != BIT_MARKER) {
+ return null;
+ }
+
+ byte[] result = new byte[VARIABLE_DATA_LENGTH];
+ long x = valueLongBits;
+ for (int i=0; i<VARIABLE_DATA_LENGTH; i++) {
+ result[i] = (byte) x;
+ x >>= 8;
+ }
+ switch (result[0]) {
+ case STRING:
+ case BOOLEAN:
+ case ERROR_CODE:
+ case EMPTY:
+ break;
+ default:
+ throw new RecordFormatException("Bad special value code (" + result[0] + ")");
+ }
+ return new SpecialCachedValue(result);
+ }
+ public void serialize(byte[] data, int offset) {
+ System.arraycopy(_variableData, 0, data, offset, VARIABLE_DATA_LENGTH);
+ LittleEndian.putUShort(data, offset+VARIABLE_DATA_LENGTH, 0xFFFF);
+ }
+ public String formatDebugString() {
+ return formatValue() + ' ' + HexDump.toHex(_variableData);
+ }
+ private String formatValue() {
+ int typeCode = getTypeCode();
+ switch (typeCode) {
+ case STRING: return "<string>";
+ case BOOLEAN: return getDataValue() == 0 ? "FALSE" : "TRUE";
+ case ERROR_CODE: return ErrorEval.getText(getDataValue());
+ case EMPTY: return "<empty>";
+ }
+ return "#error(type=" + typeCode + ")#";
+ }
+ private int getDataValue() {
+ return _variableData[DATA_INDEX];
+ }
+ public static SpecialCachedValue createCachedEmptyValue() {
+ return create(EMPTY, 0);
+ }
+ public static SpecialCachedValue createForString() {
+ return create(STRING, 0);
+ }
+ public static SpecialCachedValue createCachedBoolean(boolean b) {
+ return create(BOOLEAN, b ? 0 : 1);
+ }
+ public static SpecialCachedValue createCachedErrorCode(int errorCode) {
+ return create(ERROR_CODE, errorCode);
+ }
+ private static SpecialCachedValue create(int code, int data) {
+ byte[] vd = {
+ (byte) code,
+ 0,
+ (byte) data,
+ 0,
+ 0,
+ 0,
+ };
+ return new SpecialCachedValue(vd);
+ }
+ public String toString() {
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(getClass().getName());
+ sb.append('[').append(formatValue()).append(']');
+ return sb.toString();
+ }
+ public int getValueType() {
+ int typeCode = getTypeCode();
+ switch (typeCode) {
+ case STRING: return HSSFCell.CELL_TYPE_STRING;
+ case BOOLEAN: return HSSFCell.CELL_TYPE_BOOLEAN;
+ case ERROR_CODE: return HSSFCell.CELL_TYPE_ERROR;
+ case EMPTY: return HSSFCell.CELL_TYPE_STRING; // is this correct?
+ }
+ throw new IllegalStateException("Unexpected type id (" + typeCode + ")");
+ }
+ public boolean getBooleanValue() {
+ if (getTypeCode() != BOOLEAN) {
+ throw new IllegalStateException("Not a boolean cached value - " + formatValue());
+ }
+ return getDataValue() != 0;
+ }
+ public int getErrorValue() {
+ if (getTypeCode() != ERROR_CODE) {
+ throw new IllegalStateException("Not an error cached value - " + formatValue());
+ }
+ return getDataValue();
+ }
+ }
+
+
+
+ private int field_1_row;
+ private short field_2_column;
+ private short field_3_xf;
+ private double field_4_value;
+ private short field_5_options;
+ private int field_6_zero;
+ private Ptg[] field_8_parsed_expr;
+
+ /**
+ * Since the NaN support seems sketchy (different constants) we'll store and spit it out directly
+ */
+ private SpecialCachedValue specialCachedValue;
+
+ /** Creates new FormulaRecord */
+
+ public FormulaRecord() {
+ field_8_parsed_expr = Ptg.EMPTY_PTG_ARRAY;
+ }
+
+ /**
+ * Constructs a Formula record and sets its fields appropriately.
+ * Note - id must be 0x06 (NOT 0x406 see MSKB #Q184647 for an
+ * "explanation of this bug in the documentation) or an exception
+ * will be throw upon validation
+ *
+ * @param in the RecordInputstream to read the record from
+ */
+
+ public FormulaRecord(RecordInputStream in) {
+ super(in);
+ }
+
+ protected void fillFields(RecordInputStream in) {
+ field_1_row = in.readUShort();
+ field_2_column = in.readShort();
+ field_3_xf = in.readShort();
+ long valueLongBits = in.readLong();
+ field_5_options = in.readShort();
+ specialCachedValue = SpecialCachedValue.create(valueLongBits);
+ if (specialCachedValue == null) {
+ field_4_value = Double.longBitsToDouble(valueLongBits);
+ }
+
+ field_6_zero = in.readInt();
+ int field_7_expression_len = in.readShort(); // this length does not include any extra array data
+ field_8_parsed_expr = Ptg.readTokens(field_7_expression_len, in);
+ if (in.remaining() == 10) {
+ // TODO - this seems to occur when IntersectionPtg is present
+ // 10 extra bytes are just 0x01 and 0x00
+ // This causes POI stderr: "WARN. Unread 10 bytes of record 0x6"
+ }
+ }
+
+
+ public void setRow(int row) {
+ field_1_row = row;
+ }
+
+ public void setColumn(short column) {
+ field_2_column = column;
+ }
+
+ public void setXFIndex(short xf) {
+ field_3_xf = xf;
+ }
+
+ /**
+ * set the calculated value of the formula
+ *
+ * @param value calculated value
+ */
+ public void setValue(double value) {
+ field_4_value = value;
+ specialCachedValue = null;
+ }
+
+ public void setCachedResultTypeEmptyString() {
+ specialCachedValue = SpecialCachedValue.createCachedEmptyValue();
+ }
+ public void setCachedResultTypeString() {
+ specialCachedValue = SpecialCachedValue.createForString();
+ }
+ public void setCachedResultErrorCode(int errorCode) {
+ specialCachedValue = SpecialCachedValue.createCachedErrorCode(errorCode);
+ }
+ public void setCachedResultBoolean(boolean value) {
+ specialCachedValue = SpecialCachedValue.createCachedBoolean(value);
+ }
+ /**
+ * @return <code>true</code> if this {@link FormulaRecord} is followed by a
+ * {@link StringRecord} representing the cached text result of the formula
+ * evaluation.
+ */
+ public boolean hasCachedResultString() {
+ if (specialCachedValue == null) {
+ return false;
+ }
+ return specialCachedValue.getTypeCode() == SpecialCachedValue.STRING;
+ }
+
+ public int getCachedResultType() {
+ if (specialCachedValue == null) {
+ return HSSFCell.CELL_TYPE_NUMERIC;
+ }
+ return specialCachedValue.getValueType();
+ }
+
+ public boolean getCachedBooleanValue() {
+ return specialCachedValue.getBooleanValue();
+ }
+ public int getCachedErrorValue() {
+ return specialCachedValue.getErrorValue();
+ }
+
+
+ /**
+ * set the option flags
+ *
+ * @param options bitmask
+ */
+ public void setOptions(short options) {
+ field_5_options = options;
+ }
+
+ public int getRow() {
+ return field_1_row;
+ }
+
+ public short getColumn() {
+ return field_2_column;
+ }
+
+ public short getXFIndex() {
+ return field_3_xf;
+ }
+
+ /**
+ * get the calculated value of the formula
+ *
+ * @return calculated value
+ */
+ public double getValue() {
+ return field_4_value;
+ }
+
+ /**
+ * get the option flags
+ *
+ * @return bitmask
+ */
+ public short getOptions() {
+ return field_5_options;
+ }
+
+ public boolean isSharedFormula() {
+ return sharedFormula.isSet(field_5_options);
+ }
+ public void setSharedFormula(boolean flag) {
+ field_5_options =
+ sharedFormula.setShortBoolean(field_5_options, flag);
+ }
+
+ public boolean isAlwaysCalc() {
+ return alwaysCalc.isSet(field_5_options);
+ }
+ public void setAlwaysCalc(boolean flag) {
+ field_5_options =
+ alwaysCalc.setShortBoolean(field_5_options, flag);
+ }
+
+ public boolean isCalcOnLoad() {
+ return calcOnLoad.isSet(field_5_options);
+ }
+ public void setCalcOnLoad(boolean flag) {
+ field_5_options =
+ calcOnLoad.setShortBoolean(field_5_options, flag);
+ }
+
+ /**
+ * @return the formula tokens. never <code>null</code>
+ */
+ public Ptg[] getParsedExpression() {
+ return (Ptg[]) field_8_parsed_expr.clone();
+ }
+
+ public void setParsedExpression(Ptg[] ptgs) {
+ field_8_parsed_expr = ptgs;
+ }
+
+ /**
+ * called by constructor, should throw runtime exception in the event of a
+ * record passed with a differing ID.
+ *
+ * @param id alleged id for this record
+ */
+ protected void validateSid(short id) {
+ if (id != sid) {
+ throw new RecordFormatException("NOT A FORMULA RECORD");
+ }
+ }
+
+ public short getSid() {
+ return sid;
+ }
+
+ private int getDataSize() {
+ return FIXED_SIZE + Ptg.getEncodedSize(field_8_parsed_expr);
+ }
+ public int serialize(int offset, byte [] data) {
+
+ int dataSize = getDataSize();
+
+ LittleEndian.putShort(data, 0 + offset, sid);
+ LittleEndian.putUShort(data, 2 + offset, dataSize);
+ LittleEndian.putUShort(data, 4 + offset, getRow());
+ LittleEndian.putShort(data, 6 + offset, getColumn());
+ LittleEndian.putShort(data, 8 + offset, getXFIndex());
+
+ if (specialCachedValue == null) {
+ LittleEndian.putDouble(data, 10 + offset, field_4_value);
+ } else {
+ specialCachedValue.serialize(data, 10+offset);
+ }
+
+ LittleEndian.putShort(data, 18 + offset, getOptions());
+
+ //when writing the chn field (offset 20), it's supposed to be 0 but ignored on read
+ //Microsoft Excel Developer's Kit Page 318
+ LittleEndian.putInt(data, 20 + offset, 0);
+ int formulaTokensSize = Ptg.getEncodedSizeWithoutArrayData(field_8_parsed_expr);
+ LittleEndian.putUShort(data, 24 + offset, formulaTokensSize);
+ Ptg.serializePtgs(field_8_parsed_expr, data, 26+offset);
+ return 4 + dataSize;
+ }
+
+ public int getRecordSize() {
+ return 4 + getDataSize();
+ }
+
+ public boolean isInValueSection() {
+ return true;
+ }
+
+ public boolean isValue() {
+ return true;
+ }
+
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer();
+ sb.append("[FORMULA]\n");
+ sb.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n");
+ sb.append(" .column = ").append(HexDump.shortToHex(getColumn())).append("\n");
+ sb.append(" .xf = ").append(HexDump.shortToHex(getXFIndex())).append("\n");
+ sb.append(" .value = ");
+ if (specialCachedValue == null) {
+ sb.append(field_4_value).append("\n");
+ } else {
+ sb.append(specialCachedValue.formatDebugString()).append("\n");
+ }
+ sb.append(" .options = ").append(HexDump.shortToHex(getOptions())).append("\n");
+ sb.append(" .alwaysCalc= ").append(alwaysCalc.isSet(getOptions())).append("\n");
+ sb.append(" .calcOnLoad= ").append(calcOnLoad.isSet(getOptions())).append("\n");
+ sb.append(" .shared = ").append(sharedFormula.isSet(getOptions())).append("\n");
+ sb.append(" .zero = ").append(HexDump.intToHex(field_6_zero)).append("\n");
+
+ for (int k = 0; k < field_8_parsed_expr.length; k++ ) {
+ sb.append(" Ptg[").append(k).append("]=");
+ Ptg ptg = field_8_parsed_expr[k];
+ sb.append(ptg.toString()).append(ptg.getRVAType()).append("\n");
+ }
+ sb.append("[/FORMULA]\n");
+ return sb.toString();
+ }
+
+ public Object clone() {
+ FormulaRecord rec = new FormulaRecord();
+ rec.field_1_row = field_1_row;
+ rec.field_2_column = field_2_column;
+ rec.field_3_xf = field_3_xf;
+ rec.field_4_value = field_4_value;
+ rec.field_5_options = field_5_options;
+ rec.field_6_zero = field_6_zero;
+ int nTokens = field_8_parsed_expr.length;
+ Ptg[] ptgs = new Ptg[nTokens];
+ for (int i = 0; i < nTokens; i++) {
+ ptgs[i] = field_8_parsed_expr[i].copy();
+ }
+ rec.field_8_parsed_expr = ptgs;
+ rec.specialCachedValue = specialCachedValue;
+ return rec;
+ }
}
return result;
}
- byte[] NAN_data = null;
public double readDouble() {
- checkRecordPosition();
- //Reset NAN data
- NAN_data = null;
- double result = LittleEndian.getDouble(data, recordOffset);
- //Excel represents NAN in several ways, at this point in time we do not often
- //know the sequence of bytes, so as a hack we store the NAN byte sequence
- //so that it is not corrupted.
+ checkRecordPosition();
+ long valueLongBits = LittleEndian.getLong(data, recordOffset);
+ double result = Double.longBitsToDouble(valueLongBits);
if (Double.isNaN(result)) {
- NAN_data = new byte[8];
- System.arraycopy(data, recordOffset, NAN_data, 0, 8);
+ throw new RuntimeException("Did not expect to read NaN");
}
-
recordOffset += LittleEndian.DOUBLE_SIZE;
pos += LittleEndian.DOUBLE_SIZE;
return result;
}
-
- public byte[] getNANData() {
- if (NAN_data == null)
- throw new RecordFormatException("Do NOT call getNANData without calling readDouble that returns NaN");
- return NAN_data;
- }
+
public short[] readShortArray() {
checkRecordPosition();
}
public String readCompressedUnicode(int length) {
- if(length == 0) {
- return "";
- }
if ((length < 0) || ((remaining() < length) && !isContinueNext())) {
throw new IllegalArgumentException("Illegal length " + length);
}
if(compressByte != 0) throw new IllegalArgumentException("compressByte in continue records must be 0 while reading compressed unicode");
}
byte b = readByte();
- //Typecast direct to char from byte with high bit set causes all ones
- //in the high byte of the char (which is of course incorrect)
- char ch = (char)( (short)0xff & (short)b );
+ char ch = (char)(0x00FF & b); // avoid sex
buf.append(ch);
}
return buf.toString();
package org.apache.poi.hssf.record.aggregates;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.ColumnInfoRecord;
-import org.apache.poi.hssf.record.Record;
/**
* @author Glen Stampoultzis
- * @version $Id$
*/
public final class ColumnInfoRecordsAggregate extends RecordAggregate {
+ /**
+ * List of {@link ColumnInfoRecord}s assumed to be in order
+ */
private final List records;
+
+
+ private static final class CIRComparator implements Comparator {
+ public static final Comparator instance = new CIRComparator();
+ private CIRComparator() {
+ // enforce singleton
+ }
+ public int compare(Object a, Object b) {
+ return compareColInfos((ColumnInfoRecord)a, (ColumnInfoRecord)b);
+ }
+ public static int compareColInfos(ColumnInfoRecord a, ColumnInfoRecord b) {
+ return a.getFirstColumn()-b.getFirstColumn();
+ }
+ }
/**
* Creates an empty aggregate
public ColumnInfoRecordsAggregate() {
records = new ArrayList();
}
- public ColumnInfoRecordsAggregate(RecordStream rs) {
- this();
-
- while(rs.peekNextClass() == ColumnInfoRecord.class) {
- records.add(rs.getNext());
- }
- if (records.size() < 1) {
- throw new RuntimeException("No column info records found");
- }
- }
-
- /**
- * Performs a deep clone of the record
- */
- public Object clone()
- {
- ColumnInfoRecordsAggregate rec = new ColumnInfoRecordsAggregate();
- for (int k = 0; k < records.size(); k++)
- {
- ColumnInfoRecord ci = ( ColumnInfoRecord ) records.get(k);
- ci=(ColumnInfoRecord) ci.clone();
- rec.insertColumn( ci );
- }
- return rec;
- }
-
- /**
- * Inserts a column into the aggregate (at the end of the list).
- */
- public void insertColumn( ColumnInfoRecord col )
- {
- records.add( col );
- }
-
- /**
- * Inserts a column into the aggregate (at the position specified
- * by <code>idx</code>.
- */
- public void insertColumn( int idx, ColumnInfoRecord col )
- {
- records.add( idx, col );
- }
-
- public int getNumColumns( )
- {
- return records.size();
- }
-
- public void visitContainedRecords(RecordVisitor rv) {
- int nItems = records.size();
- if (nItems < 1) {
- return;
- }
- for(int i=0; i<nItems; i++) {
- rv.visitRecord((Record)records.get(i));
- }
- }
-
- public int findStartOfColumnOutlineGroup(int idx)
- {
- // Find the start of the group.
- ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get( idx );
- int level = columnInfo.getOutlineLevel();
- while (idx != 0)
- {
- ColumnInfoRecord prevColumnInfo = (ColumnInfoRecord) records.get( idx - 1 );
- if (columnInfo.getFirstColumn() - 1 == prevColumnInfo.getLastColumn())
- {
- if (prevColumnInfo.getOutlineLevel() < level)
- {
- break;
- }
- idx--;
- columnInfo = prevColumnInfo;
- }
- else
- {
- break;
- }
- }
-
- return idx;
- }
-
- public int findEndOfColumnOutlineGroup(int idx)
- {
- // Find the end of the group.
- ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get( idx );
- int level = columnInfo.getOutlineLevel();
- while (idx < records.size() - 1)
- {
- ColumnInfoRecord nextColumnInfo = (ColumnInfoRecord) records.get( idx + 1 );
- if (columnInfo.getLastColumn() + 1 == nextColumnInfo.getFirstColumn())
- {
- if (nextColumnInfo.getOutlineLevel() < level)
- {
- break;
- }
- idx++;
- columnInfo = nextColumnInfo;
- }
- else
- {
- break;
- }
- }
-
- return idx;
- }
-
- private ColumnInfoRecord getColInfo(int idx) {
- return (ColumnInfoRecord) records.get( idx );
- }
-
- public ColumnInfoRecord writeHidden( ColumnInfoRecord columnInfo, int idx, boolean hidden )
- {
- int level = columnInfo.getOutlineLevel();
- while (idx < records.size())
- {
- columnInfo.setHidden( hidden );
- if (idx + 1 < records.size())
- {
- ColumnInfoRecord nextColumnInfo = getColInfo(idx + 1);
- if (columnInfo.getLastColumn() + 1 == nextColumnInfo.getFirstColumn())
- {
- if (nextColumnInfo.getOutlineLevel() < level)
- break;
- columnInfo = nextColumnInfo;
- }
- else
- {
- break;
- }
- }
- idx++;
- }
- return columnInfo;
- }
-
- public boolean isColumnGroupCollapsed( int idx )
- {
- int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx );
- if (endOfOutlineGroupIdx >= records.size())
- return false;
- if (getColInfo(endOfOutlineGroupIdx).getLastColumn() + 1 != getColInfo(endOfOutlineGroupIdx + 1).getFirstColumn())
- return false;
- else
- return getColInfo(endOfOutlineGroupIdx+1).getCollapsed();
- }
-
-
- public boolean isColumnGroupHiddenByParent( int idx )
- {
- // Look out outline details of end
- int endLevel;
- boolean endHidden;
- int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx );
- if (endOfOutlineGroupIdx >= records.size())
- {
- endLevel = 0;
- endHidden = false;
- }
- else if (getColInfo(endOfOutlineGroupIdx).getLastColumn() + 1 != getColInfo(endOfOutlineGroupIdx + 1).getFirstColumn())
- {
- endLevel = 0;
- endHidden = false;
- }
- else
- {
- endLevel = getColInfo( endOfOutlineGroupIdx + 1).getOutlineLevel();
- endHidden = getColInfo( endOfOutlineGroupIdx + 1).getHidden();
- }
-
- // Look out outline details of start
- int startLevel;
- boolean startHidden;
- int startOfOutlineGroupIdx = findStartOfColumnOutlineGroup( idx );
- if (startOfOutlineGroupIdx <= 0)
- {
- startLevel = 0;
- startHidden = false;
- }
- else if (getColInfo(startOfOutlineGroupIdx).getFirstColumn() - 1 != getColInfo(startOfOutlineGroupIdx - 1).getLastColumn())
- {
- startLevel = 0;
- startHidden = false;
- }
- else
- {
- startLevel = getColInfo( startOfOutlineGroupIdx - 1).getOutlineLevel();
- startHidden = getColInfo( startOfOutlineGroupIdx - 1 ).getHidden();
- }
-
- if (endLevel > startLevel)
- {
- return endHidden;
- }
- else
- {
- return startHidden;
- }
- }
-
- public void collapseColumn( short columnNumber )
- {
- int idx = findColumnIdx( columnNumber, 0 );
- if (idx == -1)
- return;
-
- // Find the start of the group.
- ColumnInfoRecord columnInfo = getColInfo( findStartOfColumnOutlineGroup( idx ) );
-
- // Hide all the columns until the end of the group
- columnInfo = writeHidden( columnInfo, idx, true );
-
- // Write collapse field
- setColumn( (short) ( columnInfo.getLastColumn() + 1 ), null, null, null, null, Boolean.TRUE);
- }
-
- public void expandColumn( short columnNumber )
- {
- int idx = findColumnIdx( columnNumber, 0 );
- if (idx == -1)
- return;
-
- // If it is already exapanded do nothing.
- if (!isColumnGroupCollapsed(idx))
- return;
-
- // Find the start of the group.
- int startIdx = findStartOfColumnOutlineGroup( idx );
- ColumnInfoRecord columnInfo = getColInfo( startIdx );
-
- // Find the end of the group.
- int endIdx = findEndOfColumnOutlineGroup( idx );
- ColumnInfoRecord endColumnInfo = getColInfo( endIdx );
-
- // expand:
- // colapsed bit must be unset
- // hidden bit gets unset _if_ surrounding groups are expanded you can determine
- // this by looking at the hidden bit of the enclosing group. You will have
- // to look at the start and the end of the current group to determine which
- // is the enclosing group
- // hidden bit only is altered for this outline level. ie. don't uncollapse contained groups
- if (!isColumnGroupHiddenByParent( idx ))
- {
- for (int i = startIdx; i <= endIdx; i++)
- {
- if (columnInfo.getOutlineLevel() == getColInfo(i).getOutlineLevel())
- getColInfo(i).setHidden( false );
- }
- }
-
- // Write collapse field
- setColumn( (short) ( columnInfo.getLastColumn() + 1 ), null, null, null, null, Boolean.FALSE);
- }
-
- /**
- * creates the ColumnInfo Record and sets it to a default column/width
- * @see org.apache.poi.hssf.record.ColumnInfoRecord
- * @return record containing a ColumnInfoRecord
- */
- public static ColumnInfoRecord createColInfo()
- {
- ColumnInfoRecord retval = new ColumnInfoRecord();
-
- retval.setColumnWidth(( short ) 2275);
- // was: retval.setOptions(( short ) 6);
- retval.setOptions(( short ) 2);
- retval.setXFIndex(( short ) 0x0f);
- return retval;
- }
-
-
- public void setColumn(short column, Short xfIndex, Short width, Integer level, Boolean hidden, Boolean collapsed)
- {
- ColumnInfoRecord ci = null;
- int k = 0;
-
- for (k = 0; k < records.size(); k++)
- {
- ci = ( ColumnInfoRecord ) records.get(k);
- if ((ci.getFirstColumn() <= column)
- && (column <= ci.getLastColumn()))
- {
- break;
- }
- ci = null;
- }
-
- if (ci != null)
- {
- boolean styleChanged = xfIndex != null && ci.getXFIndex() != xfIndex.shortValue();
- boolean widthChanged = width != null && ci.getColumnWidth() != width.shortValue();
- boolean levelChanged = level != null && ci.getOutlineLevel() != level.intValue();
- boolean hiddenChanged = hidden != null && ci.getHidden() != hidden.booleanValue();
- boolean collapsedChanged = collapsed != null && ci.getCollapsed() != collapsed.booleanValue();
- boolean columnChanged = styleChanged || widthChanged || levelChanged || hiddenChanged || collapsedChanged;
- if (!columnChanged)
- {
- // do nothing...nothing changed.
- }
- else if ((ci.getFirstColumn() == column)
- && (ci.getLastColumn() == column))
- { // if its only for this cell then
- setColumnInfoFields( ci, xfIndex, width, level, hidden, collapsed );
- }
- else if ((ci.getFirstColumn() == column)
- || (ci.getLastColumn() == column))
- {
- // okay so the width is different but the first or last column == the column we'return setting
- // we'll just divide the info and create a new one
- if (ci.getFirstColumn() == column)
- {
- ci.setFirstColumn(( short ) (column + 1));
- }
- else
- {
- ci.setLastColumn(( short ) (column - 1));
- }
- ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo();
-
- nci.setFirstColumn(column);
- nci.setLastColumn(column);
- nci.setOptions(ci.getOptions());
- nci.setXFIndex(ci.getXFIndex());
- setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
-
- insertColumn(k, nci);
- }
- else
- {
- //split to 3 records
- short lastcolumn = ci.getLastColumn();
- ci.setLastColumn(( short ) (column - 1));
-
- ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo();
- nci.setFirstColumn(column);
- nci.setLastColumn(column);
- nci.setOptions(ci.getOptions());
- nci.setXFIndex(ci.getXFIndex());
- setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
- insertColumn(++k, nci);
-
- nci = ( ColumnInfoRecord ) createColInfo();
- nci.setFirstColumn((short)(column+1));
- nci.setLastColumn(lastcolumn);
- nci.setOptions(ci.getOptions());
- nci.setXFIndex(ci.getXFIndex());
- nci.setColumnWidth(ci.getColumnWidth());
- insertColumn(++k, nci);
- }
- }
- else
- {
-
- // okay so there ISN'T a column info record that cover's this column so lets create one!
- ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo();
-
- nci.setFirstColumn(column);
- nci.setLastColumn(column);
- setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
- insertColumn(k, nci);
- }
- }
-
- /**
- * Sets all non null fields into the <code>ci</code> parameter.
- */
- private void setColumnInfoFields( ColumnInfoRecord ci, Short xfStyle, Short width, Integer level, Boolean hidden, Boolean collapsed )
- {
- if (xfStyle != null)
- ci.setXFIndex(xfStyle.shortValue());
- if (width != null)
- ci.setColumnWidth(width.shortValue());
- if (level != null)
- ci.setOutlineLevel( level.shortValue() );
- if (hidden != null)
- ci.setHidden( hidden.booleanValue() );
- if (collapsed != null)
- ci.setCollapsed( collapsed.booleanValue() );
- }
-
- private int findColumnIdx(int column, int fromIdx)
- {
- if (column < 0)
- throw new IllegalArgumentException( "column parameter out of range: " + column );
- if (fromIdx < 0)
- throw new IllegalArgumentException( "fromIdx parameter out of range: " + fromIdx );
-
- ColumnInfoRecord ci;
- for (int k = fromIdx; k < records.size(); k++)
- {
- ci = getColInfo(k);
- if ((ci.getFirstColumn() <= column)
- && (column <= ci.getLastColumn()))
- {
- return k;
- }
- ci = null;
- }
- return -1;
- }
-
- public void collapseColInfoRecords( int columnIdx )
- {
- if (columnIdx == 0)
- return;
- ColumnInfoRecord previousCol = getColInfo( columnIdx - 1);
- ColumnInfoRecord currentCol = getColInfo( columnIdx );
- boolean adjacentColumns = previousCol.getLastColumn() == currentCol.getFirstColumn() - 1;
- if (!adjacentColumns)
- return;
-
- boolean columnsMatch =
- previousCol.getXFIndex() == currentCol.getXFIndex() &&
- previousCol.getOptions() == currentCol.getOptions() &&
- previousCol.getColumnWidth() == currentCol.getColumnWidth();
-
- if (columnsMatch)
- {
- previousCol.setLastColumn( currentCol.getLastColumn() );
- records.remove( columnIdx );
- }
- }
-
- /**
- * Creates an outline group for the specified columns.
- * @param fromColumn group from this column (inclusive)
- * @param toColumn group to this column (inclusive)
- * @param indent if true the group will be indented by one level,
- * if false indenting will be removed by one level.
- */
- public void groupColumnRange(short fromColumn, short toColumn, boolean indent)
- {
-
- // Set the level for each column
- int fromIdx = 0;
- for (int i = fromColumn; i <= toColumn; i++)
- {
- int level = 1;
- int columnIdx = findColumnIdx( i, Math.max(0,fromIdx) );
- if (columnIdx != -1)
- {
- level = getColInfo(columnIdx).getOutlineLevel();
- if (indent) level++; else level--;
- level = Math.max(0, level);
- level = Math.min(7, level);
- fromIdx = columnIdx - 1; // subtract 1 just in case this column is collapsed later.
- }
- setColumn((short)i, null, null, new Integer(level), null, null);
- columnIdx = findColumnIdx( i, Math.max(0, fromIdx ) );
- collapseColInfoRecords( columnIdx );
- }
-
- }
- /**
- * Finds the <tt>ColumnInfoRecord</tt> which contains the specified columnIndex
- * @param columnIndex index of the column (not the index of the ColumnInfoRecord)
- * @return <code>null</code> if no column info found for the specified column
- */
+ public ColumnInfoRecordsAggregate(RecordStream rs) {
+ this();
+
+ boolean isInOrder = true;
+ ColumnInfoRecord cirPrev = null;
+ while(rs.peekNextClass() == ColumnInfoRecord.class) {
+ ColumnInfoRecord cir = (ColumnInfoRecord) rs.getNext();
+ records.add(cir);
+ if (cirPrev != null && CIRComparator.compareColInfos(cirPrev, cir) > 0) {
+ isInOrder = false;
+ }
+ cirPrev = cir;
+ }
+ if (records.size() < 1) {
+ throw new RuntimeException("No column info records found");
+ }
+ if (!isInOrder) {
+ Collections.sort(records, CIRComparator.instance);
+ }
+ }
+
+ /**
+ * Performs a deep clone of the record
+ */
+ public Object clone() {
+ ColumnInfoRecordsAggregate rec = new ColumnInfoRecordsAggregate();
+ for (int k = 0; k < records.size(); k++) {
+ ColumnInfoRecord ci = ( ColumnInfoRecord ) records.get(k);
+ rec.records.add(ci.clone());
+ }
+ return rec;
+ }
+
+ /**
+ * Inserts a column into the aggregate (at the end of the list).
+ */
+ public void insertColumn(ColumnInfoRecord col) {
+ records.add(col);
+ Collections.sort(records, CIRComparator.instance);
+ }
+
+ /**
+ * Inserts a column into the aggregate (at the position specified by
+ * <code>idx</code>.
+ */
+ private void insertColumn(int idx, ColumnInfoRecord col) {
+ records.add(idx, col);
+ }
+
+ /* package */ int getNumColumns() {
+ return records.size();
+ }
+
+ public void visitContainedRecords(RecordVisitor rv) {
+ int nItems = records.size();
+ if (nItems < 1) {
+ return;
+ }
+ ColumnInfoRecord cirPrev = null;
+ for(int i=0; i<nItems; i++) {
+ ColumnInfoRecord cir = (ColumnInfoRecord)records.get(i);
+ rv.visitRecord(cir);
+ if (cirPrev != null && CIRComparator.compareColInfos(cirPrev, cir) > 0) {
+ // Excel probably wouldn't mind, but there is much logic in this class
+ // that assumes the column info records are kept in order
+ throw new RuntimeException("Column info records are out of order");
+ }
+ cirPrev = cir;
+ }
+ }
+
+ private int findStartOfColumnOutlineGroup(int pIdx) {
+ // Find the start of the group.
+ ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get(pIdx);
+ int level = columnInfo.getOutlineLevel();
+ int idx = pIdx;
+ while (idx != 0) {
+ ColumnInfoRecord prevColumnInfo = (ColumnInfoRecord) records.get(idx - 1);
+ if (!prevColumnInfo.isAdjacentBefore(columnInfo)) {
+ break;
+ }
+ if (prevColumnInfo.getOutlineLevel() < level) {
+ break;
+ }
+ idx--;
+ columnInfo = prevColumnInfo;
+ }
+
+ return idx;
+ }
+
+ private int findEndOfColumnOutlineGroup(int colInfoIndex) {
+ // Find the end of the group.
+ ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get(colInfoIndex);
+ int level = columnInfo.getOutlineLevel();
+ int idx = colInfoIndex;
+ while (idx < records.size() - 1) {
+ ColumnInfoRecord nextColumnInfo = (ColumnInfoRecord) records.get(idx + 1);
+ if (!columnInfo.isAdjacentBefore(nextColumnInfo)) {
+ break;
+ }
+ if (nextColumnInfo.getOutlineLevel() < level) {
+ break;
+ }
+ idx++;
+ columnInfo = nextColumnInfo;
+ }
+ return idx;
+ }
+
+ private ColumnInfoRecord getColInfo(int idx) {
+ return (ColumnInfoRecord) records.get( idx );
+ }
+
+ /**
+ * 'Collapsed' state is stored in a single column col info record immediately after the outline group
+ * @param idx
+ * @return
+ */
+ private boolean isColumnGroupCollapsed(int idx) {
+ int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup(idx);
+ int nextColInfoIx = endOfOutlineGroupIdx+1;
+ if (nextColInfoIx >= records.size()) {
+ return false;
+ }
+ ColumnInfoRecord nextColInfo = getColInfo(nextColInfoIx);
+ if (!getColInfo(endOfOutlineGroupIdx).isAdjacentBefore(nextColInfo)) {
+ return false;
+ }
+ return nextColInfo.getCollapsed();
+ }
+
+
+ private boolean isColumnGroupHiddenByParent(int idx) {
+ // Look out outline details of end
+ int endLevel = 0;
+ boolean endHidden = false;
+ int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx );
+ if (endOfOutlineGroupIdx < records.size()) {
+ ColumnInfoRecord nextInfo = getColInfo(endOfOutlineGroupIdx + 1);
+ if (getColInfo(endOfOutlineGroupIdx).isAdjacentBefore(nextInfo)) {
+ endLevel = nextInfo.getOutlineLevel();
+ endHidden = nextInfo.getHidden();
+ }
+ }
+ // Look out outline details of start
+ int startLevel = 0;
+ boolean startHidden = false;
+ int startOfOutlineGroupIdx = findStartOfColumnOutlineGroup( idx );
+ if (startOfOutlineGroupIdx > 0) {
+ ColumnInfoRecord prevInfo = getColInfo(startOfOutlineGroupIdx - 1);
+ if (prevInfo.isAdjacentBefore(getColInfo(startOfOutlineGroupIdx))) {
+ startLevel = prevInfo.getOutlineLevel();
+ startHidden = prevInfo.getHidden();
+ }
+ }
+ if (endLevel > startLevel) {
+ return endHidden;
+ }
+ return startHidden;
+ }
+
+ public void collapseColumn(int columnIndex) {
+ int colInfoIx = findColInfoIdx(columnIndex, 0);
+ if (colInfoIx == -1) {
+ return;
+ }
+
+ // Find the start of the group.
+ int groupStartColInfoIx = findStartOfColumnOutlineGroup(colInfoIx);
+ ColumnInfoRecord columnInfo = getColInfo(groupStartColInfoIx);
+
+ // Hide all the columns until the end of the group
+ int lastColIx = setGroupHidden(groupStartColInfoIx, columnInfo.getOutlineLevel(), true);
+
+ // Write collapse field
+ setColumn(lastColIx + 1, null, null, null, null, Boolean.TRUE);
+ }
+ /**
+ * Sets all adjacent columns of the same outline level to the specified hidden status.
+ * @param pIdx the col info index of the start of the outline group
+ * @return the column index of the last column in the outline group
+ */
+ private int setGroupHidden(int pIdx, int level, boolean hidden) {
+ int idx = pIdx;
+ ColumnInfoRecord columnInfo = getColInfo(idx);
+ while (idx < records.size()) {
+ columnInfo.setHidden(hidden);
+ if (idx + 1 < records.size()) {
+ ColumnInfoRecord nextColumnInfo = getColInfo(idx + 1);
+ if (!columnInfo.isAdjacentBefore(nextColumnInfo)) {
+ break;
+ }
+ if (nextColumnInfo.getOutlineLevel() < level) {
+ break;
+ }
+ columnInfo = nextColumnInfo;
+ }
+ idx++;
+ }
+ return columnInfo.getLastColumn();
+ }
+
+
+ public void expandColumn(int columnIndex) {
+ int idx = findColInfoIdx(columnIndex, 0);
+ if (idx == -1) {
+ return;
+ }
+
+ // If it is already expanded do nothing.
+ if (!isColumnGroupCollapsed(idx)) {
+ return;
+ }
+
+ // Find the start/end of the group.
+ int startIdx = findStartOfColumnOutlineGroup(idx);
+ int endIdx = findEndOfColumnOutlineGroup(idx);
+
+ // expand:
+ // colapsed bit must be unset
+ // hidden bit gets unset _if_ surrounding groups are expanded you can determine
+ // this by looking at the hidden bit of the enclosing group. You will have
+ // to look at the start and the end of the current group to determine which
+ // is the enclosing group
+ // hidden bit only is altered for this outline level. ie. don't uncollapse contained groups
+ ColumnInfoRecord columnInfo = getColInfo(endIdx);
+ if (!isColumnGroupHiddenByParent(idx)) {
+ int outlineLevel = columnInfo.getOutlineLevel();
+ for (int i = startIdx; i <= endIdx; i++) {
+ ColumnInfoRecord ci = getColInfo(i);
+ if (outlineLevel == ci.getOutlineLevel())
+ ci.setHidden(false);
+ }
+ }
+
+ // Write collapse flag (stored in a single col info record after this outline group)
+ setColumn(columnInfo.getLastColumn() + 1, null, null, null, null, Boolean.FALSE);
+ }
+
+ private static ColumnInfoRecord copyColInfo(ColumnInfoRecord ci) {
+ return (ColumnInfoRecord) ci.clone();
+ }
+
+
+ public void setColumn(int targetColumnIx, Short xfIndex, Short width,
+ Integer level, Boolean hidden, Boolean collapsed) {
+ ColumnInfoRecord ci = null;
+ int k = 0;
+
+ for (k = 0; k < records.size(); k++) {
+ ColumnInfoRecord tci = (ColumnInfoRecord) records.get(k);
+ if (tci.containsColumn(targetColumnIx)) {
+ ci = tci;
+ break;
+ }
+ if (tci.getFirstColumn() > targetColumnIx) {
+ // call column infos after k are for later columns
+ break; // exit now so k will be the correct insert pos
+ }
+ }
+
+ if (ci == null) {
+ // okay so there ISN'T a column info record that covers this column so lets create one!
+ ColumnInfoRecord nci = new ColumnInfoRecord();
+
+ nci.setFirstColumn(targetColumnIx);
+ nci.setLastColumn(targetColumnIx);
+ setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
+ insertColumn(k, nci);
+ attemptMergeColInfoRecords(k);
+ return;
+ }
+
+ boolean styleChanged = xfIndex != null && ci.getXFIndex() != xfIndex.shortValue();
+ boolean widthChanged = width != null && ci.getColumnWidth() != width.shortValue();
+ boolean levelChanged = level != null && ci.getOutlineLevel() != level.intValue();
+ boolean hiddenChanged = hidden != null && ci.getHidden() != hidden.booleanValue();
+ boolean collapsedChanged = collapsed != null && ci.getCollapsed() != collapsed.booleanValue();
+
+ boolean columnChanged = styleChanged || widthChanged || levelChanged || hiddenChanged || collapsedChanged;
+ if (!columnChanged) {
+ // do nothing...nothing changed.
+ return;
+ }
+
+ if (ci.getFirstColumn() == targetColumnIx && ci.getLastColumn() == targetColumnIx) {
+ // ColumnInfo ci for a single column, the target column
+ setColumnInfoFields(ci, xfIndex, width, level, hidden, collapsed);
+ attemptMergeColInfoRecords(k);
+ return;
+ }
+
+ if (ci.getFirstColumn() == targetColumnIx || ci.getLastColumn() == targetColumnIx) {
+ // The target column is at either end of the multi-column ColumnInfo ci
+ // we'll just divide the info and create a new one
+ if (ci.getFirstColumn() == targetColumnIx) {
+ ci.setFirstColumn(targetColumnIx + 1);
+ } else {
+ ci.setLastColumn(targetColumnIx - 1);
+ k++; // adjust insert pos to insert after
+ }
+ ColumnInfoRecord nci = copyColInfo(ci);
+
+ nci.setFirstColumn(targetColumnIx);
+ nci.setLastColumn(targetColumnIx);
+ setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
+
+ insertColumn(k, nci);
+ attemptMergeColInfoRecords(k);
+ } else {
+ //split to 3 records
+ ColumnInfoRecord ciStart = ci;
+ ColumnInfoRecord ciMid = copyColInfo(ci);
+ ColumnInfoRecord ciEnd = copyColInfo(ci);
+ int lastcolumn = ci.getLastColumn();
+
+ ciStart.setLastColumn(targetColumnIx - 1);
+
+ ciMid.setFirstColumn(targetColumnIx);
+ ciMid.setLastColumn(targetColumnIx);
+ setColumnInfoFields(ciMid, xfIndex, width, level, hidden, collapsed);
+ insertColumn(++k, ciMid);
+
+ ciEnd.setFirstColumn(targetColumnIx+1);
+ ciEnd.setLastColumn(lastcolumn);
+ insertColumn(++k, ciEnd);
+ // no need to attemptMergeColInfoRecords because we
+ // know both on each side are different
+ }
+ }
+
+ /**
+ * Sets all non null fields into the <code>ci</code> parameter.
+ */
+ private static void setColumnInfoFields( ColumnInfoRecord ci, Short xfStyle, Short width,
+ Integer level, Boolean hidden, Boolean collapsed ) {
+ if (xfStyle != null) {
+ ci.setXFIndex(xfStyle.shortValue());
+ }
+ if (width != null) {
+ ci.setColumnWidth(width.shortValue());
+ }
+ if (level != null) {
+ ci.setOutlineLevel( level.shortValue() );
+ }
+ if (hidden != null) {
+ ci.setHidden( hidden.booleanValue() );
+ }
+ if (collapsed != null) {
+ ci.setCollapsed( collapsed.booleanValue() );
+ }
+ }
+
+ private int findColInfoIdx(int columnIx, int fromColInfoIdx) {
+ if (columnIx < 0) {
+ throw new IllegalArgumentException( "column parameter out of range: " + columnIx );
+ }
+ if (fromColInfoIdx < 0) {
+ throw new IllegalArgumentException( "fromIdx parameter out of range: " + fromColInfoIdx );
+ }
+
+ for (int k = fromColInfoIdx; k < records.size(); k++) {
+ ColumnInfoRecord ci = getColInfo(k);
+ if (ci.containsColumn(columnIx)) {
+ return k;
+ }
+ if (ci.getFirstColumn() > columnIx) {
+ break;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Attempts to merge the col info record at the specified index
+ * with either or both of its neighbours
+ */
+ private void attemptMergeColInfoRecords(int colInfoIx) {
+ int nRecords = records.size();
+ if (colInfoIx < 0 || colInfoIx >= nRecords) {
+ throw new IllegalArgumentException("colInfoIx " + colInfoIx
+ + " is out of range (0.." + (nRecords-1) + ")");
+ }
+ ColumnInfoRecord currentCol = getColInfo(colInfoIx);
+ int nextIx = colInfoIx+1;
+ if (nextIx < nRecords) {
+ if (mergeColInfoRecords(currentCol, getColInfo(nextIx))) {
+ records.remove(nextIx);
+ }
+ }
+ if (colInfoIx > 0) {
+ if (mergeColInfoRecords(getColInfo(colInfoIx - 1), currentCol)) {
+ records.remove(colInfoIx);
+ }
+ }
+ }
+ /**
+ * merges two column info records (if they are adjacent and have the same formatting, etc)
+ * @return <code>false</code> if the two column records could not be merged
+ */
+ private static boolean mergeColInfoRecords(ColumnInfoRecord ciA, ColumnInfoRecord ciB) {
+ if (ciA.isAdjacentBefore(ciB) && ciA.formatMatches(ciB)) {
+ ciA.setLastColumn(ciB.getLastColumn());
+ return true;
+ }
+ return false;
+ }
+ /**
+ * Creates an outline group for the specified columns, by setting the level
+ * field for each col info record in the range. {@link ColumnInfoRecord}s
+ * may be created, split or merged as a result of this operation.
+ *
+ * @param fromColumnIx
+ * group from this column (inclusive)
+ * @param toColumnIx
+ * group to this column (inclusive)
+ * @param indent
+ * if <code>true</code> the group will be indented by one
+ * level, if <code>false</code> indenting will be decreased by
+ * one level.
+ */
+ public void groupColumnRange(int fromColumnIx, int toColumnIx, boolean indent) {
+
+ int colInfoSearchStartIdx = 0; // optimization to speed up the search for col infos
+ for (int i = fromColumnIx; i <= toColumnIx; i++) {
+ int level = 1;
+ int colInfoIdx = findColInfoIdx(i, colInfoSearchStartIdx);
+ if (colInfoIdx != -1) {
+ level = getColInfo(colInfoIdx).getOutlineLevel();
+ if (indent) {
+ level++;
+ } else {
+ level--;
+ }
+ level = Math.max(0, level);
+ level = Math.min(7, level);
+ colInfoSearchStartIdx = Math.max(0, colInfoIdx - 1); // -1 just in case this column is collapsed later.
+ }
+ setColumn(i, null, null, new Integer(level), null, null);
+ }
+ }
+ /**
+ * Finds the <tt>ColumnInfoRecord</tt> which contains the specified columnIndex
+ * @param columnIndex index of the column (not the index of the ColumnInfoRecord)
+ * @return <code>null</code> if no column info found for the specified column
+ */
public ColumnInfoRecord findColumnInfo(int columnIndex) {
int nInfos = records.size();
for(int i=0; i< nInfos; i++) {
ColumnInfoRecord ci = getColInfo(i);
- if (ci.getFirstColumn() <= columnIndex && columnIndex <= ci.getLastColumn()) {
+ if (ci.containsColumn(columnIndex)) {
return ci;
}
}
return null;
}
public int getMaxOutlineLevel() {
- int result = 0;
- int count=records.size();
- for (int i=0; i<count; i++) {
- ColumnInfoRecord columnInfoRecord = getColInfo(i);
- result = Math.max(columnInfoRecord.getOutlineLevel(), result);
- }
- return result;
+ int result = 0;
+ int count=records.size();
+ for (int i=0; i<count; i++) {
+ ColumnInfoRecord columnInfoRecord = getColInfo(i);
+ result = Math.max(columnInfoRecord.getOutlineLevel(), result);
+ }
+ return result;
}
-
-
}
import org.apache.poi.hssf.record.CellValueRecordInterface;
import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.record.StringRecord;
/**
private SharedValueManager _sharedValueManager;
/** caches the calculated result of the formula */
private StringRecord _stringRecord;
-
+
/**
- * @param stringRec may be <code>null</code> if this formula does not have a cached text
+ * @param stringRec may be <code>null</code> if this formula does not have a cached text
* value.
* @param svm the {@link SharedValueManager} for the current sheet
*/
if (svm == null) {
throw new IllegalArgumentException("sfm must not be null");
}
+ boolean hasStringRec = stringRec != null;
+ boolean hasCachedStringFlag = formulaRec.hasCachedResultString();
+ if (hasStringRec != hasCachedStringFlag) {
+ throw new RecordFormatException("String record was "
+ + (hasStringRec ? "": "not ") + " supplied but formula record flag is "
+ + (hasCachedStringFlag ? "" : "not ") + " set");
+ }
+
if (formulaRec.isSharedFormula()) {
svm.convertSharedFormulaRecord(formulaRec);
}
_stringRecord = stringRec;
}
- public void setStringRecord(StringRecord stringRecord) {
- _stringRecord = stringRecord;
- }
-
public FormulaRecord getFormulaRecord() {
return _formulaRecord;
}
+ /**
+ * debug only
+ * TODO - encapsulate
+ */
public StringRecord getStringRecord() {
return _stringRecord;
}
-
+
public short getXFIndex() {
return _formulaRecord.getXFIndex();
}
public String toString() {
return _formulaRecord.toString();
}
-
+
public void visitContainedRecords(RecordVisitor rv) {
rv.visitRecord(_formulaRecord);
Record sharedFormulaRecord = _sharedValueManager.getRecordForFirstCell(_formulaRecord);
rv.visitRecord(_stringRecord);
}
}
-
+
public String getStringValue() {
if(_stringRecord==null) {
return null;
}
return _stringRecord.getString();
}
+
+ public void setCachedStringResult(String value) {
+
+ // Save the string into a String Record, creating one if required
+ if(_stringRecord == null) {
+ _stringRecord = new StringRecord();
+ }
+ _stringRecord.setString(value);
+ if (value.length() < 1) {
+ _formulaRecord.setCachedResultTypeEmptyString();
+ } else {
+ _formulaRecord.setCachedResultTypeString();
+ }
+ }
+ public void setCachedBooleanResult(boolean value) {
+ _stringRecord = null;
+ _formulaRecord.setCachedResultBoolean(value);
+ }
+ public void setCachedErrorResult(int errorCode) {
+ _stringRecord = null;
+ _formulaRecord.setCachedResultErrorCode(errorCode);
+ }
}
package org.apache.poi.hssf.record.formula;\r
\r
import org.apache.poi.hssf.record.RecordInputStream;\r
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
+import org.apache.poi.ss.usermodel.Workbook;\r
import org.apache.poi.util.LittleEndian;\r
\r
/**\r
public final int getSize() {\r
return SIZE;\r
}\r
- public final String toFormulaString(HSSFWorkbook book) {\r
+ public final String toFormulaString(Workbook book) {\r
return formatReferenceAsString();\r
}\r
public final String toString() {\r
* (not including the data which comes after all formula tokens)
*/
public static final int PLAIN_TOKEN_SIZE = 1+RESERVED_FIELD_LEN;
+
+ private static final byte[] DEFAULT_RESERVED_DATA = new byte[RESERVED_FIELD_LEN];
+
// TODO - fix up field visibility and subclasses
- private byte[] field_1_reserved;
+ private final byte[] field_1_reserved;
// data from these fields comes after the Ptg data of all tokens in current formula
private short token_1_columns;
field_1_reserved[i] = in.readByte();
}
}
- public Object[] getTokenArrayValues() {
- return (Object[]) token_3_arrayValues.clone();
+ /**
+ * @param values2d array values arranged in rows
+ */
+ public ArrayPtg(Object[][] values2d) {
+ int nColumns = values2d[0].length;
+ int nRows = values2d.length;
+ // convert 2-d to 1-d array (row by row according to getValueIndex())
+ token_1_columns = (short) nColumns;
+ token_2_rows = (short) nRows;
+
+ Object[] vv = new Object[token_1_columns * token_2_rows];
+ for (int r=0; r<nRows; r++) {
+ Object[] rowData = values2d[r];
+ for (int c=0; c<nColumns; c++) {
+ vv[getValueIndex(c, r)] = rowData[c];
+ }
+ }
+
+ token_3_arrayValues = vv;
+ field_1_reserved = DEFAULT_RESERVED_DATA;
+ }
+ /**
+ * @return 2-d array (inner index is rowIx, outer index is colIx)
+ */
+ public Object[][] getTokenArrayValues() {
+ if (token_3_arrayValues == null) {
+ throw new IllegalStateException("array values not read yet");
+ }
+ Object[][] result = new Object[token_2_rows][token_1_columns];
+ for (int r = 0; r < token_2_rows; r++) {
+ Object[] rowData = result[r];
+ for (int c = 0; c < token_1_columns; c++) {
+ rowData[c] = token_3_arrayValues[getValueIndex(c, r)];
+ }
+ }
+ return result;
}
public boolean isBaseToken() {
token_3_arrayValues = ConstantValueParser.parse(in, totalCount);
}
- public String toString()
- {
- StringBuffer buffer = new StringBuffer("[ArrayPtg]\n");
+ public String toString() {
+ StringBuffer sb = new StringBuffer("[ArrayPtg]\n");
- buffer.append("columns = ").append(getColumnCount()).append("\n");
- buffer.append("rows = ").append(getRowCount()).append("\n");
+ sb.append("nRows = ").append(getRowCount()).append("\n");
+ sb.append("nCols = ").append(getColumnCount()).append("\n");
if (token_3_arrayValues == null) {
- buffer.append(" #values#uninitialised#\n");
+ sb.append(" #values#uninitialised#\n");
} else {
- for (int x=0;x<getColumnCount();x++) {
- for (int y=0;y<getRowCount();y++) {
- Object o = token_3_arrayValues[getValueIndex(x, y)];
- buffer.append("[").append(x).append("][").append(y).append("] = ").append(o).append("\n");
- }
- }
+ sb.append(" ").append(formatAsString());
}
- return buffer.toString();
+ return sb.toString();
}
/**
- * Note - (2D) array elements are stored column by column
+ * Note - (2D) array elements are stored row by row
* @return the index into the internal 1D array for the specified column and row
*/
/* package */ int getValueIndex(int colIx, int rowIx) {
throw new IllegalArgumentException("Specified rowIx (" + rowIx
+ ") is outside the allowed range (0.." + (token_2_rows-1) + ")");
}
- return rowIx + token_2_rows * colIx;
+ return rowIx * token_1_columns + colIx;
}
public void writeBytes(byte[] data, int offset) {
+ ConstantValueParser.getEncodedSize(token_3_arrayValues);
}
- public String toFormulaString(Workbook book)
- {
+ public String formatAsString() {
StringBuffer b = new StringBuffer();
b.append("{");
- for (int x=0;x<getColumnCount();x++) {
- if (x > 0) {
+ for (int y=0;y<getRowCount();y++) {
+ if (y > 0) {
b.append(";");
}
- for (int y=0;y<getRowCount();y++) {
- if (y > 0) {
+ for (int x=0;x<getColumnCount();x++) {
+ if (x > 0) {
b.append(",");
}
Object o = token_3_arrayValues[getValueIndex(x, y)];
b.append("}");
return b.toString();
}
+ public String toFormulaString(Workbook book) {
+ return formatAsString();
+ }
private static String getConstantText(Object o) {
if (o == null) {
- return ""; // TODO - how is 'empty value' represented in formulas?
+ throw new RuntimeException("Array item cannot be null");
}
if (o instanceof UnicodeString) {
return "\"" + ((UnicodeString)o).getString() + "\"";
public byte getDefaultOperandClass() {
return Ptg.CLASS_ARRAY;
}
-
- public Object clone() {
- ArrayPtg ptg = (ArrayPtg) super.clone();
- ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
- ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
- return ptg;
- }
}
* @author Daniel Noll (daniel at nuix dot com dot au)
*/
public final class ErrPtg extends ScalarConstantPtg {
-
+
// convenient access to namespace
private static final HSSFErrorConstants EC = null;
-
+
/** <b>#NULL!</b> - Intersection of two cell ranges is empty */
- public static final ErrPtg NULL_INTERSECTION = new ErrPtg(EC.ERROR_NULL);
+ public static final ErrPtg NULL_INTERSECTION = new ErrPtg(EC.ERROR_NULL);
/** <b>#DIV/0!</b> - Division by zero */
public static final ErrPtg DIV_ZERO = new ErrPtg(EC.ERROR_DIV_0);
/** <b>#VALUE!</b> - Wrong type of operand */
/** <b>#REF!</b> - Illegal or deleted cell reference */
public static final ErrPtg REF_INVALID = new ErrPtg(EC.ERROR_REF);
/** <b>#NAME?</b> - Wrong function or range name */
- public static final ErrPtg NAME_INVALID = new ErrPtg(EC.ERROR_NAME);
+ public static final ErrPtg NAME_INVALID = new ErrPtg(EC.ERROR_NAME);
/** <b>#NUM!</b> - Value range overflow */
public static final ErrPtg NUM_ERROR = new ErrPtg(EC.ERROR_NUM);
/** <b>#N/A</b> - Argument or function not available */
public static final ErrPtg N_A = new ErrPtg(EC.ERROR_NA);
-
-
+
+
public static final short sid = 0x1c;
private static final int SIZE = 2;
private final int field_1_error_code;
/** Creates new ErrPtg */
- public ErrPtg(int errorCode) {
+ private ErrPtg(int errorCode) {
if(!HSSFErrorConstants.isValidCode(errorCode)) {
throw new IllegalArgumentException("Invalid error code (" + errorCode + ")");
}
field_1_error_code = errorCode;
}
-
- public ErrPtg(RecordInputStream in) {
- this(in.readByte());
+
+ public static ErrPtg read(RecordInputStream in) {
+ return valueOf(in.readByte());
}
public void writeBytes(byte [] array, int offset)
public int getErrorCode() {
return field_1_error_code;
}
+
+ public static ErrPtg valueOf(int code) {
+ switch(code) {
+ case HSSFErrorConstants.ERROR_DIV_0: return DIV_ZERO;
+ case HSSFErrorConstants.ERROR_NA: return N_A;
+ case HSSFErrorConstants.ERROR_NAME: return NAME_INVALID;
+ case HSSFErrorConstants.ERROR_NULL: return NULL_INTERSECTION;
+ case HSSFErrorConstants.ERROR_NUM: return NUM_ERROR;
+ case HSSFErrorConstants.ERROR_REF: return REF_INVALID;
+ case HSSFErrorConstants.ERROR_VALUE: return VALUE_INVALID;
+ }
+ throw new RuntimeException("Unexpected error code (" + code + ")");
+ }
}
/**
* @deprecated - use readTokens()
*/
- public static Stack createParsedExpressionTokens(short size, RecordInputStream in)
- {
+ public static Stack createParsedExpressionTokens(short size, RecordInputStream in) {
Stack stack = new Stack();
int pos = 0;
List arrayPtgs = null;
- while ( pos < size )
- {
+ while (pos < size) {
Ptg ptg = Ptg.createPtg( in );
if (ptg instanceof ArrayPtg) {
- if (arrayPtgs == null)
+ if (arrayPtgs == null) {
arrayPtgs = new ArrayList(5);
+ }
arrayPtgs.add(ptg);
- pos += 8;
- } else pos += ptg.getSize();
+ pos += ArrayPtg.PLAIN_TOKEN_SIZE;
+ } else {
+ pos += ptg.getSize();
+ }
stack.push( ptg );
}
if(pos != size) {
int baseId = id & 0x1F | 0x20;
switch (baseId) {
- case ArrayPtg.sid: return new ArrayPtg(in); // 0x20, 0x40, 0x60
- case FuncPtg.sid: return new FuncPtg(in); // 0x21, 0x41, 0x61
- case FuncVarPtg.sid: return new FuncVarPtg(in); // 0x22, 0x42, 0x62
- case NamePtg.sid: return new NamePtg(in); // 0x23, 0x43, 0x63
- case RefPtg.sid: return new RefPtg(in); // 0x24, 0x44, 0x64
- case AreaPtg.sid: return new AreaPtg(in); // 0x25, 0x45, 0x65
- case MemAreaPtg.sid: return new MemAreaPtg(in); // 0x26, 0x46, 0x66
- case MemErrPtg.sid: return new MemErrPtg(in); // 0x27, 0x47, 0x67
- case MemFuncPtg.sid: return new MemFuncPtg(in); // 0x29, 0x49, 0x69
- case RefErrorPtg.sid: return new RefErrorPtg(in);// 0x2a, 0x4a, 0x6a
- case AreaErrPtg.sid: return new AreaErrPtg(in); // 0x2b, 0x4b, 0x6b
- case RefNPtg.sid: return new RefNPtg(in); // 0x2c, 0x4c, 0x6c
- case AreaNPtg.sid: return new AreaNPtg(in); // 0x2d, 0x4d, 0x6d
+ case ArrayPtg.sid: return new ArrayPtg(in); // 0x20, 0x40, 0x60
+ case FuncPtg.sid: return new FuncPtg(in); // 0x21, 0x41, 0x61
+ case FuncVarPtg.sid: return new FuncVarPtg(in); // 0x22, 0x42, 0x62
+ case NamePtg.sid: return new NamePtg(in); // 0x23, 0x43, 0x63
+ case RefPtg.sid: return new RefPtg(in); // 0x24, 0x44, 0x64
+ case AreaPtg.sid: return new AreaPtg(in); // 0x25, 0x45, 0x65
+ case MemAreaPtg.sid: return new MemAreaPtg(in); // 0x26, 0x46, 0x66
+ case MemErrPtg.sid: return new MemErrPtg(in); // 0x27, 0x47, 0x67
+ case MemFuncPtg.sid: return new MemFuncPtg(in); // 0x29, 0x49, 0x69
+ case RefErrorPtg.sid: return new RefErrorPtg(in); // 0x2a, 0x4a, 0x6a
+ case AreaErrPtg.sid: return new AreaErrPtg(in); // 0x2b, 0x4b, 0x6b
+ case RefNPtg.sid: return new RefNPtg(in); // 0x2c, 0x4c, 0x6c
+ case AreaNPtg.sid: return new AreaNPtg(in); // 0x2d, 0x4d, 0x6d
- case NameXPtg.sid: return new NameXPtg(in); // 0x39, 0x49, 0x79
- case Ref3DPtg.sid: return new Ref3DPtg(in); // 0x3a, 0x5a, 0x7a
- case Area3DPtg.sid: return new Area3DPtg(in); // 0x3b, 0x5b, 0x7b
- case DeletedRef3DPtg.sid: return new DeletedRef3DPtg(in); // 0x3c, 0x5c, 0x7c
- case DeletedArea3DPtg.sid: return new DeletedArea3DPtg(in); // 0x3d, 0x5d, 0x7d
+ case NameXPtg.sid: return new NameXPtg(in); // 0x39, 0x49, 0x79
+ case Ref3DPtg.sid: return new Ref3DPtg(in); // 0x3a, 0x5a, 0x7a
+ case Area3DPtg.sid: return new Area3DPtg(in); // 0x3b, 0x5b, 0x7b
+ case DeletedRef3DPtg.sid: return new DeletedRef3DPtg(in); // 0x3c, 0x5c, 0x7c
+ case DeletedArea3DPtg.sid: return new DeletedArea3DPtg(in); // 0x3d, 0x5d, 0x7d
}
throw new UnsupportedOperationException(" Unknown Ptg in Formula: 0x"+
Integer.toHexString(id) + " (" + ( int ) id + ")");
case StringPtg.sid: return new StringPtg(in); // 0x17
case AttrPtg.sid:
case 0x1a: return new AttrPtg(in); // 0x19
- case ErrPtg.sid: return new ErrPtg(in); // 0x1c
+ case ErrPtg.sid: return ErrPtg.read(in); // 0x1c
case BoolPtg.sid: return new BoolPtg(in); // 0x1d
case IntPtg.sid: return new IntPtg(in); // 0x1e
case NumberPtg.sid: return new NumberPtg(in); // 0x1f
ptg.writeBytes(array, pos + offset);
if (ptg instanceof ArrayPtg) {
- if (arrayPtgs == null)
- arrayPtgs = new ArrayList(5);
- arrayPtgs.add(ptg);
- pos += 8;
- } else pos += ptg.getSize();
+ if (arrayPtgs == null) {
+ arrayPtgs = new ArrayList(5);
+ }
+ arrayPtgs.add(ptg);
+ pos += ArrayPtg.PLAIN_TOKEN_SIZE;
+ } else {
+ pos += ptg.getSize();
+ }
}
if (arrayPtgs != null) {
for (int i=0;i<arrayPtgs.size();i++) {
import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
-import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
public final class AnalysisToolPak {
private static final FreeRefFunction NotImplemented = new FreeRefFunction() {
- public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol,
- Workbook workbook, Sheet sheet) {
+ public ValueEval evaluate(Eval[] args, Workbook workbook, int srcCellSheet,
+ int srcCellRow, int srcCellCol) {
return ErrorEval.FUNCTION_NOT_IMPLEMENTED;
}
};
_desiredParity = desiredParity;
}
- public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook,
- Sheet sheet) {
+ public ValueEval evaluate(Eval[] args, Workbook workbook, int srcCellSheet, int srcCellRow,
+ int srcCellCol) {
if (args.length != 1) {
return ErrorEval.VALUE_INVALID;
}
return BoolEval.valueOf(val == _desiredParity);
}
- private static int evaluateArgParity(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
- ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+ private static int evaluateArgParity(Eval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
+ ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, (short)srcCellCol);
double d = OperandResolver.coerceValueToDouble(ve);
if (d < 0) {
// enforce singleton
}
- public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook,
- Sheet sheet) {
+ public ValueEval evaluate(Eval[] args, Workbook workbook, int srcCellSheet, int srcCellRow,
+ int srcCellCol) {
double result;
try {
return new NumberEval(result);
}
- private static double evaluateDateArg(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
- ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+ private static double evaluateDateArg(Eval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
+ ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, (short) srcCellCol);
if (ve instanceof StringEval) {
String strVal = ((StringEval) ve).getStringValue();
return cal;
}
- private static int evaluateIntArg(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
- ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+ private static int evaluateIntArg(Eval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
+ ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, (short) srcCellCol);
return OperandResolver.coerceValueToInt(ve);
}
}
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*
*/
-public final class ConcatEval extends StringOperationEval {
+public final class ConcatEval implements OperationEval {
private ConcatPtg delegate;
return ErrorEval.VALUE_INVALID;
}
StringBuffer sb = new StringBuffer();
- for (int i = 0; i < 2; i++) {
-
- ValueEval ve = singleOperandEvaluate(args[i], srcRow, srcCol);
- if (ve instanceof StringValueEval) {
- StringValueEval sve = (StringValueEval) ve;
- sb.append(sve.getStringValue());
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else { // must be an error eval
- return ve;
- }
- }
+ try {
+ for (int i = 0; i < 2; i++) {
+
+ ValueEval ve = OperandResolver.getSingleValue(args[i], srcRow, srcCol);
+ if (ve instanceof StringValueEval) {
+ StringValueEval sve = (StringValueEval) ve;
+ sb.append(sve.getStringValue());
+ } else if (ve == BlankEval.INSTANCE) {
+ // do nothing
+ } else { // must be an error eval
+ throw new RuntimeException("Unexpected value type ("
+ + ve.getClass().getName() + ")");
+ }
+ }
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
return new StringEval(sb.toString());
}
import org.apache.poi.hssf.record.formula.atp.AnalysisToolPak;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
-import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
/**
*
*/
final class ExternalFunction implements FreeRefFunction {
- public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet) {
+ public ValueEval evaluate(Eval[] args, Workbook workbook,
+ int srcCellSheet, int srcCellRow,int srcCellCol) {
int nIncomingArgs = args.length;
if(nIncomingArgs < 1) {
int nOutGoingArgs = nIncomingArgs -1;
Eval[] outGoingArgs = new Eval[nOutGoingArgs];
System.arraycopy(args, 1, outGoingArgs, 0, nOutGoingArgs);
- return targetFunc.evaluate(outGoingArgs, srcCellRow, srcCellCol, workbook, sheet);
+ return targetFunc.evaluate(outGoingArgs, workbook, srcCellSheet, srcCellRow, srcCellCol);
}
private FreeRefFunction findExternalUserDefinedFunction(Workbook workbook,
-/*
-* 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.
-*/
-/*
- * Created on May 8, 2005
- *
- */
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
package org.apache.poi.hssf.record.formula.eval;
import java.util.HashMap;
retval[1] = new If(); // IF
retval[2] = new IsNa(); // ISNA
retval[3] = new IsError(); // ISERROR
- retval[4] = new Sum(); // SUM
- retval[5] = new Average(); // AVERAGE
- retval[6] = new Min(); // MIN
- retval[7] = new Max(); // MAX
+ retval[4] = AggregateFunction.SUM;
+ retval[5] = AggregateFunction.AVERAGE;
+ retval[6] = AggregateFunction.MIN;
+ retval[7] = AggregateFunction.MAX;
retval[8] = new Row(); // ROW
retval[9] = new Column(); // COLUMN
retval[10] = new Na(); // NA
retval[11] = new Npv(); // NPV
- retval[12] = new Stdev(); // STDEV
- retval[13] = NumericFunctionOneArg.DOLLAR;
+ retval[12] = AggregateFunction.STDEV;
+ retval[13] = NumericFunction.DOLLAR;
retval[14] = new Fixed(); // FIXED
- retval[15] = NumericFunctionOneArg.SIN;
- retval[16] = NumericFunctionOneArg.COS;
- retval[17] = NumericFunctionOneArg.TAN;
- retval[18] = NumericFunctionOneArg.ATAN;
+ retval[15] = NumericFunction.SIN;
+ retval[16] = NumericFunction.COS;
+ retval[17] = NumericFunction.TAN;
+ retval[18] = NumericFunction.ATAN;
retval[19] = new Pi(); // PI
- retval[20] = NumericFunctionOneArg.SQRT;
- retval[21] = NumericFunctionOneArg.EXP;
- retval[22] = NumericFunctionOneArg.LN;
- retval[23] = NumericFunctionOneArg.LOG10;
- retval[24] = NumericFunctionOneArg.ABS;
- retval[25] = NumericFunctionOneArg.INT;
- retval[26] = NumericFunctionOneArg.SIGN;
- retval[27] = new Round(); // ROUND
+ retval[20] = NumericFunction.SQRT;
+ retval[21] = NumericFunction.EXP;
+ retval[22] = NumericFunction.LN;
+ retval[23] = NumericFunction.LOG10;
+ retval[24] = NumericFunction.ABS;
+ retval[25] = NumericFunction.INT;
+ retval[26] = NumericFunction.SIGN;
+ retval[27] = NumericFunction.ROUND;
retval[28] = new Lookup(); // LOOKUP
retval[29] = new Index(); // INDEX
retval[30] = new Rept(); // REPT
- retval[31] = new Mid(); // MID
- retval[32] = new Len(); // LEN
+ retval[31] = TextFunction.MID;
+ retval[32] = TextFunction.LEN;
retval[33] = new Value(); // VALUE
retval[34] = new True(); // TRUE
retval[35] = new False(); // FALSE
retval[36] = new And(); // AND
retval[37] = new Or(); // OR
retval[38] = new Not(); // NOT
- retval[39] = new Mod(); // MOD
+ retval[39] = NumericFunction.MOD;
retval[40] = new Dcount(); // DCOUNT
retval[41] = new Dsum(); // DSUM
retval[42] = new Daverage(); // DAVERAGE
retval[52] = new Growth(); // GROWTH
retval[53] = new Goto(); // GOTO
retval[54] = new Halt(); // HALT
- retval[56] = new Pv(); // PV
- retval[57] = new Fv(); // FV
- retval[58] = new Nper(); // NPER
- retval[59] = new Pmt(); // PMT
+ retval[56] = FinanceFunction.PV;
+ retval[57] = FinanceFunction.FV;
+ retval[58] = FinanceFunction.NPER;
+ retval[59] = FinanceFunction.PMT;
retval[60] = new Rate(); // RATE
retval[61] = new Mirr(); // MIRR
retval[62] = new Irr(); // IRR
retval[63] = new Rand(); // RAND
retval[64] = new Match(); // MATCH
- retval[65] = new Date(); // DATE
+ retval[65] = DateFunc.instance; // DATE
retval[66] = new Time(); // TIME
retval[67] = CalendarFieldFunction.DAY; // DAY
retval[68] = CalendarFieldFunction.MONTH; // MONTH
retval[94] = new Activecell(); // ACTIVECELL
retval[95] = new NotImplementedFunction(); // SELECTION
retval[96] = new Result(); // RESULT
- retval[97] = new Atan2(); // ATAN2
- retval[98] = NumericFunctionOneArg.ASIN;
- retval[99] = NumericFunctionOneArg.ACOS;
+ retval[97] = NumericFunction.ATAN2;
+ retval[98] = NumericFunction.ASIN;
+ retval[99] = NumericFunction.ACOS;
retval[100] = new Choose(); // CHOOSE
retval[101] = new Hlookup(); // HLOOKUP
retval[102] = new Vlookup(); // VLOOKUP
retval[106] = new NotImplementedFunction(); // GETFORMULA
retval[107] = new NotImplementedFunction(); // GETNAME
retval[108] = new Setvalue(); // SETVALUE
- retval[109] = new Log(); // LOG
+ retval[109] = NumericFunction.LOG;
retval[110] = new Exec(); // EXEC
retval[111] = new Char(); // CHAR
- retval[112] = new Lower(); // LOWER
- retval[113] = new Upper(); // UPPER
+ retval[112] = TextFunction.LOWER;
+ retval[113] = TextFunction.UPPER;
retval[114] = new Proper(); // PROPER
- retval[115] = new Left(); // LEFT
- retval[116] = new Right(); // RIGHT
- retval[117] = new Exact(); // EXACT
- retval[118] = new Trim(); // TRIM
+ retval[115] = TextFunction.LEFT;
+ retval[116] = TextFunction.RIGHT;
+ retval[117] = TextFunction.EXACT;
+ retval[118] = TextFunction.TRIM;
retval[119] = new Replace(); // REPLACE
retval[120] = new Substitute(); // SUBSTITUTE
retval[121] = new Code(); // CODE
retval[180] = new NotImplementedFunction(); // RESTART
retval[181] = new Help(); // HELP
retval[182] = new NotImplementedFunction(); // GETBAR
- retval[183] = new Product(); // PRODUCT
- retval[184] = NumericFunctionOneArg.FACT;
+ retval[183] = AggregateFunction.PRODUCT;
+ retval[184] = NumericFunction.FACT;
retval[185] = new NotImplementedFunction(); // GETCELL
retval[186] = new NotImplementedFunction(); // GETWORKSPACE
retval[187] = new NotImplementedFunction(); // GETWINDOW
retval[209] = new Rightb(); // RIGHTB
retval[210] = new Midb(); // MIDB
retval[211] = new Lenb(); // LENB
- retval[212] = new Roundup(); // ROUNDUP
- retval[213] = new Rounddown(); // ROUNDDOWN
+ retval[212] = NumericFunction.ROUNDUP;
+ retval[213] = NumericFunction.ROUNDDOWN;
retval[214] = new Asc(); // ASC
retval[215] = new Dbcs(); // DBCS
retval[216] = new Rank(); // RANK
retval[220] = new Days360(); // DAYS360
retval[221] = new Today(); // TODAY
retval[222] = new Vdb(); // VDB
- retval[227] = new Median(); // MEDIAN
+ retval[227] = AggregateFunction.MEDIAN;
retval[228] = new Sumproduct(); // SUMPRODUCT
- retval[229] = NumericFunctionOneArg.SINH;
- retval[230] = NumericFunctionOneArg.COSH;
- retval[231] = NumericFunctionOneArg.TANH;
- retval[232] = NumericFunctionOneArg.ASINH;
- retval[233] = NumericFunctionOneArg.ACOSH;
- retval[234] = NumericFunctionOneArg.ATANH;
+ retval[229] = NumericFunction.SINH;
+ retval[230] = NumericFunction.COSH;
+ retval[231] = NumericFunction.TANH;
+ retval[232] = NumericFunction.ASINH;
+ retval[233] = NumericFunction.ACOSH;
+ retval[234] = NumericFunction.ATANH;
retval[235] = new Dget(); // DGET
retval[236] = new NotImplementedFunction(); // CREATEOBJECT
retval[237] = new Volatile(); // VOLATILE
retval[266] = new NotImplementedFunction(); // PRESSTOOL
retval[267] = new NotImplementedFunction(); // REGISTERID
retval[268] = new NotImplementedFunction(); // GETWORKBOOK
- retval[269] = new Avedev(); // AVEDEV
+ retval[269] = AggregateFunction.AVEDEV;
retval[270] = new Betadist(); // BETADIST
retval[271] = new Gammaln(); // GAMMALN
retval[272] = new Betainv(); // BETAINV
retval[273] = new Binomdist(); // BINOMDIST
retval[274] = new Chidist(); // CHIDIST
retval[275] = new Chiinv(); // CHIINV
- retval[276] = new Combin(); // COMBIN
+ retval[276] = NumericFunction.COMBIN;
retval[277] = new Confidence(); // CONFIDENCE
retval[278] = new Critbinom(); // CRITBINOM
retval[279] = new Even(); // EVEN
retval[282] = new Finv(); // FINV
retval[283] = new Fisher(); // FISHER
retval[284] = new Fisherinv(); // FISHERINV
- retval[285] = new Floor(); // FLOOR
+ retval[285] = NumericFunction.FLOOR;
retval[286] = new Gammadist(); // GAMMADIST
retval[287] = new Gammainv(); // GAMMAINV
- retval[288] = new Ceiling(); // CEILING
+ retval[288] = NumericFunction.CEILING;
retval[289] = new Hypgeomdist(); // HYPGEOMDIST
retval[290] = new Lognormdist(); // LOGNORMDIST
retval[291] = new Loginv(); // LOGINV
retval[315] = new Slope(); // SLOPE
retval[316] = new Ttest(); // TTEST
retval[317] = new Prob(); // PROB
- retval[318] = new Devsq(); // DEVSQ
+ retval[318] = AggregateFunction.DEVSQ;
retval[319] = new Geomean(); // GEOMEAN
retval[320] = new Harmean(); // HARMEAN
- retval[321] = new Sumsq(); // SUMSQ
+ retval[321] = AggregateFunction.SUMSQ;
retval[322] = new Kurt(); // KURT
retval[323] = new Skew(); // SKEW
retval[324] = new Ztest(); // ZTEST
- retval[325] = new Large(); // LARGE
- retval[326] = new Small(); // SMALL
+ retval[325] = AggregateFunction.LARGE;
+ retval[326] = AggregateFunction.SMALL;
retval[327] = new Quartile(); // QUARTILE
retval[328] = new Percentile(); // PERCENTILE
retval[329] = new Percentrank(); // PERCENTRANK
retval[332] = new Tinv(); // TINV
retval[334] = new NotImplementedFunction(); // MOVIECOMMAND
retval[335] = new NotImplementedFunction(); // GETMOVIE
- retval[336] = new Concatenate(); // CONCATENATE
- retval[337] = new Power(); // POWER
+ retval[336] = TextFunction.CONCATENATE;
+ retval[337] = NumericFunction.POWER;
retval[338] = new NotImplementedFunction(); // PIVOTADDDATA
retval[339] = new NotImplementedFunction(); // GETPIVOTTABLE
retval[340] = new NotImplementedFunction(); // GETPIVOTFIELD
retval[341] = new NotImplementedFunction(); // GETPIVOTITEM
- retval[342] = NumericFunctionOneArg.RADIANS;
- retval[343] = NumericFunctionOneArg.DEGREES;
+ retval[342] = NumericFunction.RADIANS;
+ retval[343] = NumericFunction.DEGREES;
retval[344] = new Subtotal(); // SUBTOTAL
retval[345] = new Sumif(); // SUMIF
retval[346] = new Countif(); // COUNTIF
retval[359] = new Hyperlink(); // HYPERLINK
retval[360] = new NotImplementedFunction(); // PHONETIC
retval[361] = new Averagea(); // AVERAGEA
- retval[362] = new Maxa(); // MAXA
- retval[363] = new Mina(); // MINA
+ retval[362] = MinaMaxa.MAXA;
+ retval[363] = MinaMaxa.MINA;
retval[364] = new Stdevpa(); // STDEVPA
retval[365] = new Varpa(); // VARPA
retval[366] = new Stdeva(); // STDEVA
+++ /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.hssf.record.formula.eval;
-
-import org.apache.poi.hssf.record.formula.AreaI;
-import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.util.CellReference;
-
-/**
- *
- * @author Josh Micich
- */
-public final class LazyAreaEval extends AreaEvalBase {
-
- private final Sheet _sheet;
- private FormulaEvaluator _evaluator;
-
- public LazyAreaEval(AreaI ptg, Sheet sheet, FormulaEvaluator evaluator) {
- super(ptg);
- _sheet = sheet;
- _evaluator = evaluator;
- }
-
- public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
-
- int rowIx = (relativeRowIndex + getFirstRow() ) & 0xFFFF;
- int colIx = (relativeColumnIndex + getFirstColumn() ) & 0x00FF;
-
- Row row = _sheet.getRow(rowIx);
- if (row == null) {
- return BlankEval.INSTANCE;
- }
- Cell cell = row.getCell(colIx);
- if (cell == null) {
- return BlankEval.INSTANCE;
- }
- return _evaluator.getEvalForCell(cell, _sheet);
- }
-
- public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
- AreaI area = new OffsetArea(getFirstRow(), getFirstColumn(),
- relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
-
- return new LazyAreaEval(area, _sheet, _evaluator);
- }
- public String toString() {
- CellReference crA = new CellReference(getFirstRow(), getFirstColumn());
- CellReference crB = new CellReference(getLastRow(), getLastColumn());
- StringBuffer sb = new StringBuffer();
- sb.append(getClass().getName()).append("[");
- String sheetName = _evaluator.getSheetName(_sheet);
- sb.append(sheetName);
- sb.append('!');
- sb.append(crA.formatAsString());
- sb.append(':');
- sb.append(crB.formatAsString());
- sb.append("]");
- return sb.toString();
- }
-}
+++ /dev/null
-/* ====================================================================\r
- Licensed to the Apache Software Foundation (ASF) under one or more\r
- contributor license agreements. See the NOTICE file distributed with\r
- this work for additional information regarding copyright ownership.\r
- The ASF licenses this file to You under the Apache License, Version 2.0\r
- (the "License"); you may not use this file except in compliance with\r
- the License. You may obtain a copy of the License at\r
-\r
- http://www.apache.org/licenses/LICENSE-2.0\r
-\r
- Unless required by applicable law or agreed to in writing, software\r
- distributed under the License is distributed on an "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- See the License for the specific language governing permissions and\r
- limitations under the License.\r
-==================================================================== */\r
-\r
-package org.apache.poi.hssf.record.formula.eval;\r
-\r
-import org.apache.poi.hssf.record.formula.AreaI;\r
-import org.apache.poi.hssf.record.formula.Ref3DPtg;\r
-import org.apache.poi.hssf.record.formula.RefPtg;\r
-import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;\r
-import org.apache.poi.ss.usermodel.Cell;\r
-import org.apache.poi.ss.usermodel.FormulaEvaluator;\r
-import org.apache.poi.ss.usermodel.Row;\r
-import org.apache.poi.ss.usermodel.Sheet;\r
-import org.apache.poi.ss.usermodel.Workbook;\r
-import org.apache.poi.ss.util.CellReference;\r
-\r
-/**\r
-*\r
-* @author Josh Micich \r
-*/\r
-public final class LazyRefEval extends RefEvalBase {\r
- private final Sheet _sheet;\r
- private final FormulaEvaluator _evaluator;\r
-\r
-\r
- public LazyRefEval(RefPtg ptg, Sheet sheet, FormulaEvaluator evaluator) {\r
- super(ptg.getRow(), ptg.getColumn());\r
- _sheet = sheet;\r
- _evaluator = evaluator;\r
- }\r
- public LazyRefEval(Ref3DPtg ptg, Sheet sheet, FormulaEvaluator evaluator) {\r
- super(ptg.getRow(), ptg.getColumn());\r
- _sheet = sheet;\r
- _evaluator = evaluator;\r
- }\r
-\r
- public ValueEval getInnerValueEval() {\r
- int rowIx = getRow();\r
- int colIx = getColumn();\r
- \r
- Row row = _sheet.getRow(rowIx);\r
- if (row == null) {\r
- return BlankEval.INSTANCE;\r
- }\r
- Cell cell = row.getCell(colIx);\r
- if (cell == null) {\r
- return BlankEval.INSTANCE;\r
- }\r
- return _evaluator.getEvalForCell(cell, _sheet);\r
- }\r
- \r
- public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {\r
- \r
- AreaI area = new OffsetArea(getRow(), getColumn(),\r
- relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);\r
-\r
- return new LazyAreaEval(area, _sheet, _evaluator);\r
- }\r
- \r
- public String toString() {\r
- CellReference cr = new CellReference(getRow(), getColumn());\r
- StringBuffer sb = new StringBuffer();\r
- sb.append(getClass().getName()).append("[");\r
- String sheetName = _evaluator.getSheetName(_sheet);\r
- sb.append(sheetName);\r
- sb.append('!');\r
- sb.append(cr.formatAsString());\r
- sb.append("]");\r
- return sb.toString();\r
- }\r
-}\r
StringValueEval sve = (StringValueEval) ve;
return sve.getStringValue();
}
- if (ve instanceof NumberEval) {
- NumberEval neval = (NumberEval) ve;
- return neval.getStringValue();
- }
-
- if (ve instanceof BlankEval) {
+ if (ve == BlankEval.INSTANCE) {
return "";
}
throw new IllegalArgumentException("Unexpected eval class (" + ve.getClass().getName() + ")");
*/
public static Boolean coerceValueToBoolean(ValueEval ve, boolean stringsAreBlanks) throws EvaluationException {
- if (ve == null || ve instanceof BlankEval) {
+ if (ve == null || ve == BlankEval.INSTANCE) {
// TODO - remove 've == null' condition once AreaEval is fixed
return null;
}
return Boolean.valueOf(((BoolEval) ve).getBooleanValue());
}
- if (ve instanceof BlankEval) {
+ if (ve == BlankEval.INSTANCE) {
return null;
}
+++ /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.hssf.record.formula.eval;
-
-import org.apache.poi.hssf.record.formula.RefPtg;
-
-/**
- * @author adeshmukh
- *
- */
-public final class Ref2DEval implements RefEval {
-
- private final ValueEval value;
- private final RefPtg delegate;
-
- public Ref2DEval(RefPtg ptg, ValueEval ve) {
- if(ve == null) {
- throw new IllegalArgumentException("ve must not be null");
- }
- if(false && ptg == null) { // TODO - fix dodgy code in MultiOperandNumericFunction
- throw new IllegalArgumentException("ptg must not be null");
- }
- value = ve;
- delegate = ptg;
- }
- public ValueEval getInnerValueEval() {
- return value;
- }
- public int getRow() {
- return delegate.getRow();
- }
- public int getColumn() {
- return delegate.getColumn();
- }
- public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
- throw new RuntimeException("should not be called"); // TODO - delete this whole class
- }
-}
+++ /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.
-*/
-/*
- * Created on May 14, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.eval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public final class ValueEvalToNumericXlator {
-
- public static final int STRING_IS_PARSED = 0x0001;
- public static final int BOOL_IS_PARSED = 0x0002;
- public static final int BLANK_IS_PARSED = 0x0004; // => blanks are not ignored, converted to 0
-
- public static final int REF_STRING_IS_PARSED = 0x0008;
- public static final int REF_BOOL_IS_PARSED = 0x0010;
- public static final int REF_BLANK_IS_PARSED = 0x0020;
-
- public static final int STRING_IS_INVALID_VALUE = 0x0800;
-
- private final int flags;
-
-
- public ValueEvalToNumericXlator(int flags) {
-
- if (false) { // uncomment to see who is using this class
- System.err.println(new Throwable().getStackTrace()[1].getClassName() + "\t0x"
- + Integer.toHexString(flags).toUpperCase());
- }
- this.flags = flags;
- }
-
- /**
- * returned value can be either A NumericValueEval, BlankEval or ErrorEval.
- * The params can be either NumberEval, BoolEval, StringEval, or
- * RefEval
- * @param eval
- */
- public ValueEval attemptXlateToNumeric(ValueEval eval) {
-
- if (eval == null) {
- throw new IllegalArgumentException("eval must not be null");
- }
-
- // most common case - least worries :)
- if (eval instanceof NumberEval) {
- return eval;
- }
-
- if (eval instanceof BoolEval) {
- return ((flags & BOOL_IS_PARSED) > 0)
- ? (NumericValueEval) eval
- : xlateBlankEval(BLANK_IS_PARSED);
- }
-
- if (eval instanceof StringEval) {
- return xlateStringEval((StringEval) eval); // TODO: recursive call needed
- }
-
- if (eval instanceof RefEval) {
- return xlateRefEval((RefEval) eval);
- }
-
- if (eval instanceof ErrorEval) {
- return eval;
- }
-
- if (eval instanceof BlankEval) {
- return xlateBlankEval(BLANK_IS_PARSED);
- }
-
- // probably AreaEval? then not acceptable.
- throw new RuntimeException("Invalid ValueEval type passed for conversion: " + eval.getClass());
- }
-
- /**
- * no args are required since BlankEval has only one
- * instance. If flag is set, a zero
- * valued numbereval is returned, else BlankEval.INSTANCE
- * is returned.
- */
- private ValueEval xlateBlankEval(int flag) {
- return ((flags & flag) > 0)
- ? (ValueEval) NumberEval.ZERO
- : BlankEval.INSTANCE;
- }
-
- /**
- * uses the relevant flags to decode the supplied RefVal
- * @param eval
- */
- private ValueEval xlateRefEval(RefEval reval) {
- ValueEval eval = reval.getInnerValueEval();
-
- // most common case - least worries :)
- if (eval instanceof NumberEval) {
- return eval;
- }
-
- if (eval instanceof BoolEval) {
- return ((flags & REF_BOOL_IS_PARSED) > 0)
- ? (ValueEval) eval
- : BlankEval.INSTANCE;
- }
-
- if (eval instanceof StringEval) {
- return xlateRefStringEval((StringEval) eval);
- }
-
- if (eval instanceof ErrorEval) {
- return eval;
- }
-
- if (eval instanceof BlankEval) {
- return xlateBlankEval(REF_BLANK_IS_PARSED);
- }
-
- throw new RuntimeException("Invalid ValueEval type passed for conversion: ("
- + eval.getClass().getName() + ")");
- }
-
- /**
- * uses the relevant flags to decode the StringEval
- * @param eval
- */
- private ValueEval xlateStringEval(StringEval eval) {
-
- if ((flags & STRING_IS_PARSED) > 0) {
- String s = eval.getStringValue();
- Double d = OperandResolver.parseDouble(s);
- if(d == null) {
- return ErrorEval.VALUE_INVALID;
- }
- return new NumberEval(d.doubleValue());
- }
- // strings are errors?
- if ((flags & STRING_IS_INVALID_VALUE) > 0) {
- return ErrorEval.VALUE_INVALID;
- }
-
- // ignore strings
- return xlateBlankEval(BLANK_IS_PARSED);
- }
-
- /**
- * uses the relevant flags to decode the StringEval
- * @param eval
- */
- private ValueEval xlateRefStringEval(StringEval sve) {
- if ((flags & REF_STRING_IS_PARSED) > 0) {
- String s = sve.getStringValue();
- Double d = OperandResolver.parseDouble(s);
- if(d == null) {
- return ErrorEval.VALUE_INVALID;
- }
- return new NumberEval(d.doubleValue());
- }
- // strings are blanks
- return BlankEval.INSTANCE;
- }
-}
--- /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.hssf.record.formula.functions;
+
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ *
+ */
+public abstract class AggregateFunction extends MultiOperandNumericFunction {
+
+ protected AggregateFunction() {
+ super(false, false);
+ }
+
+ /* ---------------------------------------------------------------------- */
+
+ public static final Function AVEDEV = new AggregateFunction() {
+ protected double evaluate(double[] values) {
+ return StatsLib.avedev(values);
+ }
+ };
+ public static final Function AVERAGE = new AggregateFunction() {
+ protected double evaluate(double[] values) throws EvaluationException {
+ if (values.length < 1) {
+ throw new EvaluationException(ErrorEval.DIV_ZERO);
+ }
+ return MathX.average(values);
+ }
+ };
+ public static final Function DEVSQ = new AggregateFunction() {
+ protected double evaluate(double[] values) {
+ return StatsLib.devsq(values);
+ }
+ };
+ public static final Function LARGE = new AggregateFunction() {
+ protected double evaluate(double[] ops) throws EvaluationException {
+ if (ops.length < 2) {
+ throw new EvaluationException(ErrorEval.NUM_ERROR);
+ }
+ double[] values = new double[ops.length-1];
+ int k = (int) ops[ops.length-1];
+ System.arraycopy(ops, 0, values, 0, values.length);
+ return StatsLib.kthLargest(values, k);
+ }
+ };
+ public static final Function MAX = new AggregateFunction() {
+ protected double evaluate(double[] values) {
+ return values.length > 0 ? MathX.max(values) : 0;
+ }
+ };
+ public static final Function MEDIAN = new AggregateFunction() {
+ protected double evaluate(double[] values) {
+ return StatsLib.median(values);
+ }
+ };
+ public static final Function MIN = new AggregateFunction() {
+ protected double evaluate(double[] values) {
+ return values.length > 0 ? MathX.min(values) : 0;
+ }
+ };
+ public static final Function PRODUCT = new AggregateFunction() {
+ protected double evaluate(double[] values) {
+ return MathX.product(values);
+ }
+ };
+ public static final Function SMALL = new AggregateFunction() {
+ protected double evaluate(double[] ops) throws EvaluationException {
+ if (ops.length < 2) {
+ throw new EvaluationException(ErrorEval.NUM_ERROR);
+ }
+ double[] values = new double[ops.length-1];
+ int k = (int) ops[ops.length-1];
+ System.arraycopy(ops, 0, values, 0, values.length);
+ return StatsLib.kthSmallest(values, k);
+ }
+ };
+ public static final Function STDEV = new AggregateFunction() {
+ protected double evaluate(double[] values) throws EvaluationException {
+ if (values.length < 1) {
+ throw new EvaluationException(ErrorEval.DIV_ZERO);
+ }
+ return StatsLib.stdev(values);
+ }
+ };
+ public static final Function SUM = new AggregateFunction() {
+ protected double evaluate(double[] values) {
+ return MathX.sum(values);
+ }
+ };
+ public static final Function SUMSQ = new AggregateFunction() {
+ protected double evaluate(double[] values) {
+ return MathX.sumsq(values);
+ }
+ };
+}
+++ /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.
-*/
-/*
- * Created on May 6, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Atan2 extends NumericFunction {
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double d0 = 0;
- double d1 = 0;
- ValueEval retval = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 2:
- ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d0 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
-
- if (retval == null) {
- ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d1 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
- }
- }
-
- if (retval == null) {
- double d = (d0 == d1 && d1 == 0)
- ? Double.NaN
- : Math.atan2(d1, d0);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
- return retval;
- }
-
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Avedev extends MultiOperandNumericFunction {
-
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (
- ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- ));
-
- /**
- * this is the default impl for the factory method getXlator
- * of the super class NumericFunction. Subclasses can override this method
- * if they desire to return a different ValueEvalToNumericXlator instance
- * than the default.
- */
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = StatsLib.avedev(values);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Average extends MultiOperandNumericFunction {
-
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (
- ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- ));
-
- /**
- * this is the default impl for the factory method getXlator
- * of the super class NumericFunction. Subclasses can override this method
- * if they desire to return a different ValueEvalToNumericXlator instance
- * than the default.
- */
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = MathX.average(values);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Ceiling extends NumericFunction {
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double d0 = 0;
- double d1 = 0;
- ValueEval retval = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 2:
- ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d0 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
-
- if (retval == null) {
- ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d1 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
- }
- }
-
- if (retval == null) {
- double d = MathX.ceiling(d0, d1);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
- return retval;
- }
-
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Combin extends NumericFunction {
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double d0 = 0;
- double d1 = 0;
- ValueEval retval = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 2:
- ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d0 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
-
- if (retval == null) {
- ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d1 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
- }
- }
-
- if (retval == null) {
- if (d0 > Integer.MAX_VALUE || d1 > Integer.MAX_VALUE) {
- retval = ErrorEval.NUM_ERROR;
- }
- else {
- double d = MathX.nChooseK((int) d0, (int) d1);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
- }
- return retval;
- }
-
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.StringEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Concatenate extends TextFunction {
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- StringBuffer sb = new StringBuffer();
-
- for (int i=0, iSize=operands.length; i<iSize; i++) {
- ValueEval ve = singleOperandEvaluate(operands[i], srcCellRow, srcCellCol);
- if (ve instanceof StringValueEval) {
- StringValueEval sve = (StringValueEval) ve;
- sb.append(sve.getStringValue());
- }
- else if (ve instanceof BlankEval) {}
- else {
- retval = ErrorEval.VALUE_INVALID;
- break;
- }
- }
-
- if (retval == null) {
- retval = new StringEval(sb.toString());
- }
-
- return retval;
- }
-}
+++ /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.hssf.record.formula.functions;
-
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-
-import org.apache.poi.hssf.usermodel.HSSFDateUtil;
-
-import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.RefEval;
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
-
-/**
- * @author Pavel Krupets (pkrupets at palmtreebusiness dot com)
- */
-public class Date extends NumericFunction {
- /**
- * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.eval.Eval[], int, short)
- */
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- if (operands.length == 3) {
- ValueEval ve[] = new ValueEval[3];
-
- ve[0] = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
- ve[1] = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
- ve[2] = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol);
-
- if (validValues(ve)) {
- int year = getYear(ve[0]);
- int month = (int) ((NumericValueEval) ve[1]).getNumberValue() - 1;
- int day = (int) ((NumericValueEval) ve[2]).getNumberValue();
-
- if (year < 0 || month < 0 || day < 0) {
- return ErrorEval.VALUE_INVALID;
- }
-
- if (year == 1900 && month == Calendar.FEBRUARY && day == 29) {
- return new NumberEval(60.0);
- }
-
- if (year == 1900) {
- if ((month == Calendar.JANUARY && day >= 60) ||
- (month == Calendar.FEBRUARY && day >= 30))
- {
- day--;
- }
- }
-
- Calendar c = new GregorianCalendar();
-
- c.set(year, month, day, 0, 0, 0);
- c.set(Calendar.MILLISECOND, 0);
-
- return new NumberEval(HSSFDateUtil.getExcelDate(c.getTime(), false)); // XXX fix 1900/1904 problem
- }
- }
-
- return ErrorEval.VALUE_INVALID;
- }
-
- private int getYear(ValueEval ve) {
- int year = (int) ((NumericValueEval) ve).getNumberValue();
-
- if (year < 0) {
- return -1;
- }
-
- return year < 1900 ? 1900 + year : year;
- }
-
- private boolean validValues(ValueEval[] values) {
- for (int i = 0; i < values.length; i++) {
- ValueEval value = values[i];
-
- if (value instanceof RefEval) {
- RefEval re = (RefEval) value;
- ValueEval ive = re.getInnerValueEval();
-
- if (ive instanceof BlankEval) {
- value = new NumberEval(0);
- } else if (ive instanceof NumericValueEval) {
- value = ive;
- } else {
- return false;
- }
- }
-
- if (!(value instanceof NumericValueEval)) {
- return false;
- }
- }
-
- return true;
- }
-}
--- /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.hssf.record.formula.functions;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.usermodel.HSSFDateUtil;
+
+/**
+ * @author Pavel Krupets (pkrupets at palmtreebusiness dot com)
+ */
+public final class DateFunc extends NumericFunction.MultiArg {
+
+ public static final Function instance = new DateFunc();
+
+ private DateFunc() {
+ super(3,3);
+ }
+
+ protected double evaluate(double[] ds) throws EvaluationException {
+ int year = getYear(ds[0]);
+ int month = (int) ds[1] - 1;
+ int day = (int) ds[2];
+
+ if (year < 0 || month < 0 || day < 0) {
+ throw new EvaluationException(ErrorEval.VALUE_INVALID);
+ }
+
+ if (year == 1900 && month == Calendar.FEBRUARY && day == 29) {
+ return 60.0;
+ }
+
+ if (year == 1900) {
+ if ((month == Calendar.JANUARY && day >= 60) ||
+ (month == Calendar.FEBRUARY && day >= 30))
+ {
+ day--;
+ }
+ }
+
+ Calendar c = new GregorianCalendar();
+
+ c.set(year, month, day, 0, 0, 0);
+ c.set(Calendar.MILLISECOND, 0);
+
+ return HSSFDateUtil.getExcelDate(c.getTime(), false); // XXX fix 1900/1904 problem
+ }
+
+ private static int getYear(double d) {
+ int year = (int)d;
+
+ if (year < 0) {
+ return -1;
+ }
+
+ return year < 1900 ? 1900 + year : year;
+ }
+}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Devsq extends MultiOperandNumericFunction {
-
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (0
- | ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.EVALUATED_REF_BLANK_IS_PARSED
- ));
-
- /**
- * this is the default impl for the factory method getXlator
- * of the super class NumericFunction. Subclasses can override this method
- * if they desire to return a different ValueEvalToNumericXlator instance
- * than the default.
- */
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = StatsLib.devsq(values);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*
*/
-public final class Even extends NumericFunctionOneArg {
+public final class Even extends NumericFunction.OneArg {
private static final long PARITY_MASK = 0xFFFFFFFFFFFFFFFEL;
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Exact extends TextFunction {
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- String s0 = null;
- String s1 = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 2:
- ValueEval ve = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
- if (ve instanceof StringValueEval) {
- StringValueEval sve = (StringValueEval) ve;
- s0 = sve.getStringValue();
- }
- else if (ve instanceof BlankEval) {
- s0 = StringEval.EMPTY_INSTANCE.getStringValue();
- }
- else {
- retval = ErrorEval.VALUE_INVALID;
- break;
- }
-
- if (retval == null) {
- ve = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
- if (ve instanceof StringValueEval) {
- StringValueEval sve = (StringValueEval) ve;
- s1 = sve.getStringValue();
- }
- else if (ve instanceof BlankEval) {
- s1 = StringEval.EMPTY_INSTANCE.getStringValue();
- }
- else {
- retval = ErrorEval.VALUE_INVALID;
- break;
- }
- }
- }
-
- if (retval == null) {
- boolean b = s0.equals(s1);
- retval = b ? BoolEval.TRUE : BoolEval.FALSE;
- }
-
- return retval;
- }
-}
-/*
-* 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.
-*/
+/* ====================================================================
+ 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
-package org.apache.poi.hssf.record.formula.functions;
+ 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 org.apache.poi.hssf.record.formula.eval.BoolEval;
-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;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
+package org.apache.poi.hssf.record.formula.functions;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
* Super class for all Evals for financial function evaluation.
- *
+ *
*/
-public abstract class FinanceFunction extends NumericFunction {
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (0
- | ValueEvalToNumericXlator.BOOL_IS_PARSED
- | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- | ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- | ValueEvalToNumericXlator.BLANK_IS_PARSED
- | ValueEvalToNumericXlator.REF_BLANK_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- ));
-
- /**
- * this is the default impl of the factory(ish) method getXlator.
- * Subclasses can override this method
- * if they desire to return a different ValueEvalToNumericXlator instance
- * than the default.
- */
- protected final ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
- protected final ValueEval singleOperandNumericAsBoolean(Eval eval, int srcRow, short srcCol) {
- ValueEval retval = null;
- retval = singleOperandEvaluate(eval, srcRow, srcCol);
- if (retval instanceof NumericValueEval) {
- NumericValueEval nve = (NumericValueEval) retval;
- retval = (nve.getNumberValue() == 0)
- ? BoolEval.FALSE
- : BoolEval.TRUE;
- }
- else {
- retval = ErrorEval.VALUE_INVALID;
- }
- return retval;
- }
+public abstract class FinanceFunction extends NumericFunction.MultiArg {
+
+ protected FinanceFunction() {
+ super (3, 5);
+ }
+
+ protected double evaluate(double[] ds) throws EvaluationException {
+ // All finance functions have 3 to 5 args, first 4 are numbers, last is boolean
+ // default for last 2 args are 0.0 and false
+ // Text boolean literals are not valid for the last arg
+
+ double arg3 = 0.0;
+ double arg4 = 0.0;
+
+ switch(ds.length) {
+ case 5:
+ arg4 = ds[4];
+ case 4:
+ arg3 = ds[3];
+ case 3:
+ break;
+ default:
+ throw new IllegalStateException("Wrong number of arguments");
+ }
+ return evaluate(ds[0], ds[1], ds[2], arg3, arg4!=0.0);
+ }
+
+ protected abstract double evaluate(double rate, double arg1, double arg2, double arg3, boolean type) throws EvaluationException ;
+
+
+ public static final Function FV = new FinanceFunction() {
+ protected double evaluate(double rate, double arg1, double arg2, double arg3, boolean type) {
+ return FinanceLib.fv(rate, arg1, arg2, arg3, type);
+ }
+ };
+ public static final Function NPER = new FinanceFunction() {
+ protected double evaluate(double rate, double arg1, double arg2, double arg3, boolean type) {
+ return FinanceLib.nper(rate, arg1, arg2, arg3, type);
+ }
+ };
+ public static final Function PMT = new FinanceFunction() {
+ protected double evaluate(double rate, double arg1, double arg2, double arg3, boolean type) {
+ return FinanceLib.pmt(rate, arg1, arg2, arg3, type);
+ }
+ };
+ public static final Function PV = new FinanceFunction() {
+ protected double evaluate(double rate, double arg1, double arg2, double arg3, boolean type) {
+ return FinanceLib.pv(rate, arg1, arg2, arg3, type);
+ }
+ };
}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Floor extends NumericFunction {
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double d0 = 0;
- double d1 = 0;
- ValueEval retval = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 2:
- ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d0 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
-
- if (retval == null) {
- ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d1 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
- }
- }
-
- if (retval == null) {
- double d = MathX.floor(d0, d1);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
- return retval;
- }
-
-}
*
* @param args the pre-evaluated arguments for this function. args is never <code>null</code>,
* nor are any of its elements.
+ * @param srcCellSheet zero based sheet index of the cell containing the currently evaluating formula
* @param srcCellRow zero based row index of the cell containing the currently evaluating formula
* @param srcCellCol zero based column index of the cell containing the currently evaluating formula
* @param workbook is the workbook containing the formula/cell being evaluated
- * @param sheet is the sheet containing the formula/cell being evaluated
* @return never <code>null</code>. Possibly an instance of <tt>ErrorEval</tt> in the case of
* a specified Excel error (Exceptions are never thrown to represent Excel errors).
*
*/
- ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet);
+ ValueEval evaluate(Eval[] args, Workbook workbook, int srcCellSheet, int srcCellRow, int srcCellCol);
}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-public class Fv extends FinanceFunction {
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double rate = 0, nper = 0, pmt = 0, pv = 0, d = 0;
- boolean type = false;
- ValueEval retval = null;
- ValueEval ve = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 5:
- ve = singleOperandNumericAsBoolean(operands[4], srcRow, srcCol);
- if (ve instanceof ErrorEval) { retval = ErrorEval.VALUE_INVALID; break; }
- type = ((BoolEval) ve).getBooleanValue();
- case 4:
- ve = singleOperandEvaluate(operands[3], srcRow, srcCol);
- if (ve instanceof NumericValueEval) pv = ((NumericValueEval) ve).getNumberValue();
- else { retval = ErrorEval.VALUE_INVALID; break; }
- case 3:
- ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (ve instanceof NumericValueEval) nper = ((NumericValueEval) ve).getNumberValue();
- else { retval = ErrorEval.VALUE_INVALID; break; }
-
- ve = singleOperandEvaluate(operands[2], srcRow, srcCol);
- if (ve instanceof NumericValueEval) pmt = ((NumericValueEval) ve).getNumberValue();
- else { retval = ErrorEval.VALUE_INVALID; break; }
-
- ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if (ve instanceof NumericValueEval) rate = ((NumericValueEval) ve).getNumberValue();
- else { retval = ErrorEval.VALUE_INVALID; break; }
- }
-
- if (retval == null) {
- d = FinanceLib.fv(rate, nper, pmt, pv, type);
- retval = (Double.isNaN(d))
- ? (ValueEval) ErrorEval.VALUE_INVALID
- : (Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
- return retval;
- }
-
-}
import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.EvaluationException;
import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
return ErrorEval.VALUE_INVALID;
}
Eval firstArg = args[0];
+ if (firstArg instanceof RefEval) {
+ // convert to area ref for simpler code in getValueFromArea()
+ firstArg = ((RefEval)firstArg).offset(0, 0, 0, 0);
+ }
if(!(firstArg instanceof AreaEval)) {
// else the other variation of this function takes an array as the first argument
// too many arguments
return ErrorEval.VALUE_INVALID;
}
- return getValueFromArea(reference, rowIx, columnIx);
+ return getValueFromArea(reference, rowIx, columnIx, nArgs);
} catch (EvaluationException e) {
return e.getErrorEval();
}
}
- private static ValueEval getValueFromArea(AreaEval ae, int rowIx, int columnIx) throws EvaluationException {
+ /**
+ * @param nArgs - needed because error codes are slightly different when only 2 args are passed
+ */
+ private static ValueEval getValueFromArea(AreaEval ae, int pRowIx, int pColumnIx, int nArgs) throws EvaluationException {
+ int rowIx;
+ int columnIx;
+
+ // when the area ref is a single row or a single column,
+ // there are special rules for conversion of rowIx and columnIx
+ if (ae.isRow()) {
+ if (ae.isColumn()) {
+ rowIx = pRowIx == -1 ? 0 : pRowIx;
+ columnIx = pColumnIx == -1 ? 0 : pColumnIx;
+ } else {
+ if (nArgs == 2) {
+ rowIx = 0;
+ columnIx = pRowIx;
+ } else {
+ rowIx = pRowIx == -1 ? 0 : pRowIx;
+ columnIx = pColumnIx;
+ }
+ }
+ if (rowIx < -1 || columnIx < -1) {
+ throw new EvaluationException(ErrorEval.VALUE_INVALID);
+ }
+ } else if (ae.isColumn()) {
+ if (nArgs == 2) {
+ rowIx = pRowIx;
+ columnIx = 0;
+ } else {
+ rowIx = pRowIx;
+ columnIx = pColumnIx == -1 ? 0 : pColumnIx;
+ }
+ if (rowIx < -1 || columnIx < -1) {
+ throw new EvaluationException(ErrorEval.VALUE_INVALID);
+ }
+ } else {
+ if (nArgs == 2) {
+ // always an error with 2-D area refs
+ if (pRowIx < -1) {
+ throw new EvaluationException(ErrorEval.VALUE_INVALID);
+ }
+ throw new EvaluationException(ErrorEval.REF_INVALID);
+ }
+ // Normal case - area ref is 2-D, and both index args were provided
+ rowIx = pRowIx;
+ columnIx = pColumnIx;
+ }
+
int width = ae.getWidth();
int height = ae.getHeight();
-
// Slightly irregular logic for bounds checking errors
if (rowIx >= height || columnIx >= width) {
throw new EvaluationException(ErrorEval.REF_INVALID);
*/
public final class Indirect implements FreeRefFunction {
- public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet) {
+ public ValueEval evaluate(Eval[] args, Workbook workbook, int srcCellSheet, int srcCellRow, int srcCellCol) {
// TODO - implement INDIRECT()
return ErrorEval.FUNCTION_NOT_IMPLEMENTED;
}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Large extends MultiOperandNumericFunction {
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (0
- | ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.EVALUATED_REF_BLANK_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BLANK_IS_PARSED
- //| ValueEvalToNumericXlator.BLANK_IS_PARSED
- ));
-
- /**
- * this is the default impl for the factory method getXlator
- * of the super class NumericFunction. Subclasses can override this method
- * if they desire to return a different ValueEvalToNumericXlator instance
- * than the default.
- */
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] ops = getNumberArray(operands, srcCellRow, srcCellCol);
- if (ops == null || ops.length < 2) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double[] values = new double[ops.length-1];
- int k = (int) ops[ops.length-1];
- System.arraycopy(ops, 0, values, 0, values.length);
- double d = StatsLib.kthLargest(values, k);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-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;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Left extends TextFunction {
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- Eval retval = ErrorEval.VALUE_INVALID;
- int index = 1;
- switch (operands.length) {
- default:
- break;
- case 2:
- Eval indexEval = operands[1];
- index = evaluateAsInteger(indexEval);
- if (index < 0) {
- break;
- }
- case 1:
- ValueEval veval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
- String str = null;
- if (veval instanceof StringEval) {
- StringEval stringEval = (StringEval) veval;
- str = stringEval.getStringValue();
- }
- else if (veval instanceof BoolEval) {
- BoolEval beval = (BoolEval) veval;
- str = beval.getBooleanValue() ? "TRUE" : "FALSE";
- }
- else if (veval instanceof NumberEval) {
- NumberEval neval = (NumberEval) veval;
- str = neval.getStringValue();
- }
- if (null != str) {
- str = str.substring(0, Math.min(str.length(), index));
- retval = new StringEval(str);
- }
- }
- return retval;
- }
-
- protected int evaluateAsInteger(Eval eval) {
- int numval = -1;
- if (eval instanceof NumberEval) {
- NumberEval neval = (NumberEval) eval;
- double d = neval.getNumberValue();
- numval = (int) d;
- }
- else if (eval instanceof StringEval) {
- StringEval seval = (StringEval) eval;
- String s = seval.getStringValue();
- try {
- double d = Double.parseDouble(s);
- numval = (int) d;
- }
- catch (Exception e) {
- }
- }
- else if (eval instanceof BoolEval) {
- BoolEval beval = (BoolEval) eval;
- numval = beval.getBooleanValue() ? 1 : 0;
- }
- else if (eval instanceof RefEval) {
- numval = evaluateAsInteger(xlateRefEval((RefEval) eval));
- }
- return numval;
- }
-
- protected Eval xlateRefEval(RefEval reval) {
- Eval retval = reval.getInnerValueEval();
-
- if (retval instanceof RefEval) {
- retval = xlateRefEval((RefEval) retval);
- }
- return retval;
- }
-}
+++ /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.hssf.record.formula.functions;
-
-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.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public final class Len extends TextFunction {
-
- public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
-
- if(args.length != 1) {
- return ErrorEval.VALUE_INVALID;
- }
-
- try {
- ValueEval veval = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
-
- String str = OperandResolver.coerceValueToString(veval);
-
- return new NumberEval(str.length());
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
- }
-}
+++ /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.
-*/
-/*
- * Created on May 6, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- * Log: LOG(number,[base])
- */
-public class Log extends NumericFunction {
-
- private static final double DEFAULT_BASE = 10;
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double d = 0;
- double base = DEFAULT_BASE;
- double num = 0;
- ValueEval retval = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 2: // second arg is base
- ValueEval ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- base = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
-
- case 1: // first arg is number
- if (retval == null) {
- ValueEval vev = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if (vev instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) vev;
- num = ne.getNumberValue();
- }
- else if (vev instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
- }
- }
-
- if (retval == null) {
- d = (base == E)
- ? Math.log(num)
- : Math.log(num) / Math.log(base);
- retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d);
- }
- return retval;
- }
-
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.StringEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Lower extends TextFunction {
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- String s = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 1:
- ValueEval ve = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
- if (ve instanceof StringValueEval) {
- StringValueEval sve = (StringValueEval) ve;
- s = sve.getStringValue();
- }
- else if (ve instanceof BlankEval) {}
- else {
- retval = ErrorEval.VALUE_INVALID;
- break;
- }
- }
-
- if (retval == null) {
- s = (s == null) ? EMPTY_STRING : s;
- retval = new StringEval(s.toLowerCase());
- }
-
- return retval;
- }
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Max extends MultiOperandNumericFunction {
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (
- ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- ));
-
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = values.length > 0 ? MathX.max(values) : 0;
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
+++ /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.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public final class Maxa extends MultiOperandNumericFunction {
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (
- ValueEvalToNumericXlator.BOOL_IS_PARSED
- | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- | ValueEvalToNumericXlator.BLANK_IS_PARSED
- | ValueEvalToNumericXlator.REF_BLANK_IS_PARSED
- ));
-
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = values.length > 0 ? MathX.max(values) : 0;
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Median extends MultiOperandNumericFunction {
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (0
- | ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.EVALUATED_REF_BLANK_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BLANK_IS_PARSED
- //| ValueEvalToNumericXlator.BLANK_IS_PARSED
- ));
-
- /**
- * this is the default impl for the factory method getXlator
- * of the super class NumericFunction. Subclasses can override this method
- * if they desire to return a different ValueEvalToNumericXlator instance
- * than the default.
- */
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = StatsLib.median(values);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
+++ /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.hssf.record.formula.functions;
-
-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.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * An implementation of the MID function<br/> MID returns a specific number of
- * characters from a text string, starting at the specified position.<p/>
- *
- * <b>Syntax<b>:<br/> <b>MID</b>(<b>text</b>, <b>start_num</b>,
- * <b>num_chars</b>)<br/>
- *
- * @author Manda Wilson < wilson at c bio dot msk cc dot org >
- */
-public class Mid implements Function {
- /**
- * Returns a specific number of characters from a text string, starting at
- * the position you specify, based on the number of characters you specify.
- *
- * @see org.apache.poi.hssf.record.formula.eval.Eval
- */
- public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
- if (args.length != 3) {
- return ErrorEval.VALUE_INVALID;
- }
-
- String text;
- int startIx; // zero based
- int numChars;
-
- try {
- ValueEval evText = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
- text = OperandResolver.coerceValueToString(evText);
- int startCharNum = evaluateNumberArg(args[1], srcCellRow, srcCellCol);
- numChars = evaluateNumberArg(args[2], srcCellRow, srcCellCol);
- startIx = startCharNum - 1; // convert to zero-based
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
-
- int len = text.length();
- if (startIx < 0) {
- return ErrorEval.VALUE_INVALID;
- }
- if (numChars < 0) {
- return ErrorEval.VALUE_INVALID;
- }
- if (numChars < 0 || startIx > len) {
- return new StringEval("");
- }
- int endIx = startIx + numChars;
- if (endIx > len) {
- endIx = len;
- }
- String result = text.substring(startIx, endIx);
- return new StringEval(result);
-
- }
-
- private static int evaluateNumberArg(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
- ValueEval ev = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
- // Note - for start_num arg, blank/zero causes error(#VALUE!),
- // but for num_chars causes empty string to be returned.
- return OperandResolver.coerceValueToInt(ev);
- }
-}
\ No newline at end of file
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Min extends MultiOperandNumericFunction {
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (
- ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- ));
-
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = values.length > 0 ? MathX.min(values) : 0;
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
+++ /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.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Mina extends MultiOperandNumericFunction {
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (
- ValueEvalToNumericXlator.BOOL_IS_PARSED
- | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- | ValueEvalToNumericXlator.REF_BLANK_IS_PARSED
- | ValueEvalToNumericXlator.BLANK_IS_PARSED
- ));
-
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = values.length > 0 ? MathX.min(values) : 0;
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
--- /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.hssf.record.formula.functions;
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ *
+ */
+public abstract class MinaMaxa extends MultiOperandNumericFunction {
+
+ protected MinaMaxa() {
+ super(true, true);
+ }
+
+ public static final Function MAXA = new MinaMaxa() {
+ protected double evaluate(double[] values) {
+ return values.length > 0 ? MathX.max(values) : 0;
+ }
+ };
+ public static final Function MINA = new MinaMaxa() {
+ protected double evaluate(double[] values) {
+ return values.length > 0 ? MathX.min(values) : 0;
+ }
+ };
+}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Mod extends NumericFunction {
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double d0 = 0;
- double d1 = 0;
- ValueEval retval = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 2:
- ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d0 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
-
- if (retval == null) {
- ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d1 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
- }
- }
-
- if (retval == null) {
- if (d1 == 0) {
- retval = ErrorEval.DIV_ZERO;
- }
- else {
- double d = MathX.mod(d0, d1);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
- }
- return retval;
- }
-
-}
-/*
-* 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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
+/* ====================================================================
+ 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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+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.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
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;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
+ *
*/
-public class Mode extends MultiOperandNumericFunction {
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (0
- //| ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.EVALUATED_REF_BLANK_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BLANK_IS_PARSED
- //| ValueEvalToNumericXlator.BLANK_IS_PARSED
- ));
-
- /**
- * this is the default impl for the factory method getXlator
- * of the super class NumericFunction. Subclasses can override this method
- * if they desire to return a different ValueEvalToNumericXlator instance
- * than the default.
- */
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
+public class Mode implements Function {
+
+ /**
+ * if v is zero length or contains no duplicates, return value is
+ * Double.NaN. Else returns the value that occurs most times and if there is
+ * a tie, returns the first such value.
+ *
+ * @param v
+ */
+ public static double evaluate(double[] v) throws EvaluationException {
+ if (v.length < 2) {
+ throw new EvaluationException(ErrorEval.NA);
+ }
+
+ // very naive impl, may need to be optimized
+ int[] counts = new int[v.length];
+ Arrays.fill(counts, 1);
+ for (int i = 0, iSize = v.length; i < iSize; i++) {
+ for (int j = i + 1, jSize = v.length; j < jSize; j++) {
+ if (v[i] == v[j])
+ counts[i]++;
+ }
+ }
+ double maxv = 0;
+ int maxc = 0;
+ for (int i = 0, iSize = counts.length; i < iSize; i++) {
+ if (counts[i] > maxc) {
+ maxv = v[i];
+ maxc = counts[i];
+ }
+ }
+ if (maxc > 1) {
+ return maxv;
+ }
+ throw new EvaluationException(ErrorEval.NA);
+
+ }
+
+ public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ double result;
+ try {
+ List temp = new ArrayList();
+ for (int i = 0; i < args.length; i++) {
+ collectValues(args[i], temp);
+ }
+ double[] values = new double[temp.size()];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = ((Double) temp.get(i)).doubleValue();
+ }
+ result = evaluate(values);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ return new NumberEval(result);
+ }
+
+ private static void collectValues(Eval arg, List temp) throws EvaluationException {
+ if (arg instanceof AreaEval) {
+ AreaEval ae = (AreaEval) arg;
+ int width = ae.getWidth();
+ int height = ae.getHeight();
+ for (int rrIx = 0; rrIx < height; rrIx++) {
+ for (int rcIx = 0; rcIx < width; rcIx++) {
+ ValueEval ve1 = ae.getRelativeValue(rrIx, rcIx);
+ collectValue(ve1, temp, false);
+ }
+ }
+ return;
+ }
+ if (arg instanceof RefEval) {
+ RefEval re = (RefEval) arg;
+ collectValue(re.getInnerValueEval(), temp, true);
+ return;
+ }
+ collectValue(arg, temp, true);
+ }
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = StatsLib.mode(values);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
+ private static void collectValue(Eval arg, List temp, boolean mustBeNumber)
+ throws EvaluationException {
+ if (arg instanceof ErrorEval) {
+ throw new EvaluationException((ErrorEval) arg);
+ }
+ if (arg == BlankEval.INSTANCE || arg instanceof BoolEval || arg instanceof StringEval) {
+ if (mustBeNumber) {
+ throw EvaluationException.invalidValue();
+ }
+ return;
+ }
+ if (arg instanceof NumberEval) {
+ temp.add(new Double(((NumberEval) arg).getNumberValue()));
+ return;
+ }
+ throw new RuntimeException("Unexpected value type (" + arg.getClass().getName() + ")");
+ }
}
-/*
-* 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.
-*/
+/* ====================================================================
+ 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.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.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
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;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
* classes that take variable number of operands, and
* where the order of operands does not matter
*/
-public abstract class MultiOperandNumericFunction extends NumericFunction {
- static final double[] EMPTY_DOUBLE_ARRAY = { };
-
- private static class DoubleList {
- private double[] _array;
- private int _count;
-
- public DoubleList() {
- _array = new double[8];
- _count = 0;
- }
-
- public double[] toArray() {
- if(_count < 1) {
- return EMPTY_DOUBLE_ARRAY;
- }
- double[] result = new double[_count];
- System.arraycopy(_array, 0, result, 0, _count);
- return result;
- }
-
- public void add(double[] values) {
- int addLen = values.length;
- ensureCapacity(_count + addLen);
- System.arraycopy(values, 0, _array, _count, addLen);
- _count += addLen;
- }
-
- private void ensureCapacity(int reqSize) {
- if(reqSize > _array.length) {
- int newSize = reqSize * 3 / 2; // grow with 50% extra
- double[] newArr = new double[newSize];
- System.arraycopy(_array, 0, newArr, 0, _count);
- _array = newArr;
- }
- }
-
- public void add(double value) {
- ensureCapacity(_count + 1);
- _array[_count] = value;
- _count++;
- }
- }
-
- private static final int DEFAULT_MAX_NUM_OPERANDS = 30;
-
- protected abstract ValueEvalToNumericXlator getXlator();
-
- /**
- * Maximum number of operands accepted by this function.
- * Subclasses may override to change default value.
- */
- protected int getMaxNumOperands() {
- return DEFAULT_MAX_NUM_OPERANDS;
- }
-
- /**
- * Returns a double array that contains values for the numeric cells
- * from among the list of operands. Blanks and Blank equivalent cells
- * are ignored. Error operands or cells containing operands of type
- * that are considered invalid and would result in #VALUE! error in
- * excel cause this function to return <code>null</code>.
- *
- * @param operands
- * @param srcRow
- * @param srcCol
- */
- protected double[] getNumberArray(Eval[] operands, int srcRow, short srcCol) {
- if (operands.length > getMaxNumOperands()) {
- return null;
- }
- DoubleList retval = new DoubleList();
-
- for (int i=0, iSize=operands.length; i<iSize; i++) {
- double[] temp = getNumberArray(operands[i], srcRow, srcCol);
- if (temp == null) {
- return null; // error occurred.
- }
- retval.add(temp);
- }
- return retval.toArray();
- }
-
- /**
- * Same as getNumberArray(Eval[], int, short) except that this
- * takes Eval instead of Eval[].
- * @param operand
- * @param srcRow
- * @param srcCol
- */
- protected double[] getNumberArray(Eval operand, int srcRow, short srcCol) {
-
- if (operand instanceof AreaEval) {
- AreaEval ae = (AreaEval) operand;
- DoubleList retval = new DoubleList();
- int width = ae.getWidth();
- int height = ae.getHeight();
- for (int rrIx=0; rrIx<height; rrIx++) {
- for (int rcIx=0; rcIx<width; rcIx++) {
- ValueEval ve1 = ae.getRelativeValue(rrIx, rcIx);
- /*
- * TODO: For an AreaEval, we are constructing a RefEval
- * per element.
- * For now this is a tempfix solution since this may
- * require a more generic fix at the level of
- * HSSFFormulaEvaluator where we store an array
- * of RefEvals as the "values" array.
- */
- RefEval re = new Ref2DEval(null, ve1);
- ValueEval ve = singleOperandEvaluate(re, srcRow, srcCol);
-
- if (ve instanceof NumericValueEval) {
- NumericValueEval nve = (NumericValueEval) ve;
- retval.add(nve.getNumberValue());
- }
- else if (ve instanceof BlankEval) {
- // note - blanks are ignored, so returned array will be smaller.
- }
- else {
- return null; // indicate to calling subclass that error occurred
- }
- }
- }
- return retval.toArray();
- }
-
- // for ValueEvals other than AreaEval
- ValueEval ve = singleOperandEvaluate(operand, srcRow, srcCol);
-
- if (ve instanceof NumericValueEval) {
- NumericValueEval nve = (NumericValueEval) ve;
- return new double[] { nve.getNumberValue(), };
- }
-
- if (ve instanceof BlankEval) {
- // ignore blanks
- return EMPTY_DOUBLE_ARRAY;
- }
- return null;
- }
-
- /**
- * Ensures that a two dimensional array has all sub-arrays present and the same length
- * @return <code>false</code> if any sub-array is missing, or is of different length
- */
- protected static final boolean areSubArraysConsistent(double[][] values) {
-
- if (values == null || values.length < 1) {
- // TODO this doesn't seem right. Fix or add comment.
- return true;
- }
-
- if (values[0] == null) {
- return false;
- }
- int outerMax = values.length;
- int innerMax = values[0].length;
- for (int i=1; i<outerMax; i++) { // note - 'i=1' start at second sub-array
- double[] subArr = values[i];
- if (subArr == null) {
- return false;
- }
- if (innerMax != subArr.length) {
- return false;
- }
- }
- return true;
- }
-
-
-
+public abstract class MultiOperandNumericFunction implements Function {
+
+ private final boolean _isReferenceBoolCounted;
+ private final boolean _isBlankCounted;
+
+ protected MultiOperandNumericFunction(boolean isReferenceBoolCounted, boolean isBlankCounted) {
+ _isReferenceBoolCounted = isReferenceBoolCounted;
+ _isBlankCounted = isBlankCounted;
+ }
+
+
+ static final double[] EMPTY_DOUBLE_ARRAY = { };
+
+ private static class DoubleList {
+ private double[] _array;
+ private int _count;
+
+ public DoubleList() {
+ _array = new double[8];
+ _count = 0;
+ }
+
+ public double[] toArray() {
+ if(_count < 1) {
+ return EMPTY_DOUBLE_ARRAY;
+ }
+ double[] result = new double[_count];
+ System.arraycopy(_array, 0, result, 0, _count);
+ return result;
+ }
+
+ private void ensureCapacity(int reqSize) {
+ if(reqSize > _array.length) {
+ int newSize = reqSize * 3 / 2; // grow with 50% extra
+ double[] newArr = new double[newSize];
+ System.arraycopy(_array, 0, newArr, 0, _count);
+ _array = newArr;
+ }
+ }
+
+ public void add(double value) {
+ ensureCapacity(_count + 1);
+ _array[_count] = value;
+ _count++;
+ }
+ }
+
+ private static final int DEFAULT_MAX_NUM_OPERANDS = 30;
+
+ public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+
+ double d;
+ try {
+ double[] values = getNumberArray(args);
+ d = evaluate(values);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+
+ if (Double.isNaN(d) || Double.isInfinite(d))
+ return ErrorEval.NUM_ERROR;
+
+ return new NumberEval(d);
+ }
+
+ protected abstract double evaluate(double[] values) throws EvaluationException;
+
+
+ /**
+ * Maximum number of operands accepted by this function.
+ * Subclasses may override to change default value.
+ */
+ protected int getMaxNumOperands() {
+ return DEFAULT_MAX_NUM_OPERANDS;
+ }
+
+ /**
+ * Returns a double array that contains values for the numeric cells
+ * from among the list of operands. Blanks and Blank equivalent cells
+ * are ignored. Error operands or cells containing operands of type
+ * that are considered invalid and would result in #VALUE! error in
+ * excel cause this function to return <code>null</code>.
+ *
+ * @return never <code>null</code>
+ */
+ protected final double[] getNumberArray(Eval[] operands) throws EvaluationException {
+ if (operands.length > getMaxNumOperands()) {
+ throw EvaluationException.invalidValue();
+ }
+ DoubleList retval = new DoubleList();
+
+ for (int i=0, iSize=operands.length; i<iSize; i++) {
+ collectValues(operands[i], retval);
+ }
+ return retval.toArray();
+ }
+
+ /**
+ * Collects values from a single argument
+ */
+ private void collectValues(Eval operand, DoubleList temp) throws EvaluationException {
+
+ if (operand instanceof AreaEval) {
+ AreaEval ae = (AreaEval) operand;
+ int width = ae.getWidth();
+ int height = ae.getHeight();
+ for (int rrIx=0; rrIx<height; rrIx++) {
+ for (int rcIx=0; rcIx<width; rcIx++) {
+ ValueEval ve = ae.getRelativeValue(rrIx, rcIx);
+ collectValue(ve, true, temp);
+ }
+ }
+ return;
+ }
+ if (operand instanceof RefEval) {
+ RefEval re = (RefEval) operand;
+ collectValue(re.getInnerValueEval(), true, temp);
+ return;
+ }
+ collectValue((ValueEval)operand, false, temp);
+ }
+ private void collectValue(ValueEval ve, boolean isViaReference, DoubleList temp) throws EvaluationException {
+ if (ve == null) {
+ throw new IllegalArgumentException("ve must not be null");
+ }
+ if (ve instanceof NumberEval) {
+ NumberEval ne = (NumberEval) ve;
+ temp.add(ne.getNumberValue());
+ return;
+ }
+ if (ve instanceof ErrorEval) {
+ throw new EvaluationException((ErrorEval) ve);
+ }
+ if (ve instanceof StringEval) {
+ if (isViaReference) {
+ // ignore all ref strings
+ return;
+ }
+ String s = ((StringEval) ve).getStringValue();
+ Double d = OperandResolver.parseDouble(s);
+ if(d == null) {
+ throw new EvaluationException(ErrorEval.VALUE_INVALID);
+ }
+ temp.add(d.doubleValue());
+ return;
+ }
+ if (ve instanceof BoolEval) {
+ if (!isViaReference || _isReferenceBoolCounted) {
+ BoolEval boolEval = (BoolEval) ve;
+ temp.add(boolEval.getNumberValue());
+ }
+ return;
+ }
+ if (ve == BlankEval.INSTANCE) {
+ if (_isBlankCounted) {
+ temp.add(0.0);
+ }
+ return;
+ }
+ throw new RuntimeException("Invalid ValueEval type passed for conversion: ("
+ + ve.getClass() + ")");
+ }
}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-public class Nper extends FinanceFunction {
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double rate = 0, fv = 0, pmt = 0, pv = 0, d = 0;
- boolean type = false;
- ValueEval retval = null;
- ValueEval ve = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 5:
- ve = singleOperandNumericAsBoolean(operands[4], srcRow, srcCol);
- if (ve instanceof ErrorEval) { retval = ErrorEval.VALUE_INVALID; break; }
- type = ((BoolEval) ve).getBooleanValue();
- case 4:
- ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if (ve instanceof NumericValueEval) rate = ((NumericValueEval) ve).getNumberValue();
- else { retval = ErrorEval.VALUE_INVALID; break; }
-
- ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (ve instanceof NumericValueEval) pmt = ((NumericValueEval) ve).getNumberValue();
- else { retval = ErrorEval.VALUE_INVALID; break; }
-
- ve = singleOperandEvaluate(operands[2], srcRow, srcCol);
- if (ve instanceof NumericValueEval) pv = ((NumericValueEval) ve).getNumberValue();
- else { retval = ErrorEval.VALUE_INVALID; break; }
-
- ve = singleOperandEvaluate(operands[3], srcRow, srcCol);
- if (ve instanceof NumericValueEval) fv = ((NumericValueEval) ve).getNumberValue();
- else { retval = ErrorEval.VALUE_INVALID; break; }
- }
-
- if (retval == null) {
- d = FinanceLib.nper(rate, pmt, pv, fv, type);
- retval = (Double.isNaN(d))
- ? (ValueEval) ErrorEval.VALUE_INVALID
- : (Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
- return retval;
- }
-
-}
-/*
-* 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.
-*/
-/*
- * Created on May 14, 2005
- *
- */
+/* ====================================================================
+ 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.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.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
*/
public abstract class NumericFunction implements Function {
-
- protected static final double E = Math.E;
- protected static final double PI = Math.PI;
-
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (
- ValueEvalToNumericXlator.BOOL_IS_PARSED
- | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- | ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- ));
-
- private static final int DEFAULT_MAX_NUM_OPERANDS = 30;
-
- /**
- * this is the default impl of the factory(ish) method getXlator.
- * Subclasses can override this method
- * if they desire to return a different ValueEvalToNumericXlator instance
- * than the default.
- */
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
- protected ValueEval singleOperandEvaluate(Eval eval, int srcRow, short srcCol) {
- ValueEval retval;
- if (eval instanceof AreaEval) {
- AreaEval ae = (AreaEval) eval;
- if (ae.contains(srcRow, srcCol)) { // circular ref!
- retval = ErrorEval.CIRCULAR_REF_ERROR;
- }
- else if (ae.isRow()) {
- if (ae.containsColumn(srcCol)) {
- ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCol);
- ve = getXlator().attemptXlateToNumeric(ve);
- retval = getXlator().attemptXlateToNumeric(ve);
- }
- else {
- retval = ErrorEval.VALUE_INVALID;
- }
- }
- else if (ae.isColumn()) {
- if (ae.containsRow(srcRow)) {
- ValueEval ve = ae.getValueAt(srcRow, ae.getFirstColumn());
- retval = getXlator().attemptXlateToNumeric(ve);
- }
- else {
- retval = ErrorEval.VALUE_INVALID;
- }
- }
- else {
- retval = ErrorEval.VALUE_INVALID;
- }
- }
- else {
- retval = getXlator().attemptXlateToNumeric((ValueEval) eval);
- }
- return retval;
- }
+ static final double ZERO = 0.0;
+ static final double TEN = 10.0;
+ static final double LOG_10_TO_BASE_e = Math.log(TEN);
+
+ protected static final double singleOperandEvaluate(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
+ ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+ double result = OperandResolver.coerceValueToDouble(ve);
+ checkValue(result);
+ return result;
+ }
+
+ private static final void checkValue(double result) throws EvaluationException {
+ if (Double.isNaN(result) || Double.isInfinite(result)) {
+ throw new EvaluationException(ErrorEval.NUM_ERROR);
+ }
+ }
+
+ public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ double result;
+ try {
+ result = eval(args, srcCellRow, srcCellCol);
+ checkValue(result);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ return new NumberEval(result);
+ }
+
+ protected abstract double eval(Eval[] args, int srcCellRow, short srcCellCol) throws EvaluationException;
+
+ /* -------------------------------------------------------------------------- */
+ // intermediate sub-classes (one-arg, two-arg and multi-arg
+
+
+ public static abstract class OneArg extends NumericFunction {
+ protected OneArg() {
+ // no fields to initialise
+ }
+ protected final double eval(Eval[] args, int srcCellRow, short srcCellCol) throws EvaluationException {
+ if (args.length != 1) {
+ throw new EvaluationException(ErrorEval.VALUE_INVALID);
+ }
+ double d = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
+ return evaluate(d);
+ }
+ protected abstract double evaluate(double d) throws EvaluationException;
+ }
+
+ public static abstract class TwoArg extends NumericFunction {
+ protected TwoArg() {
+ // no fields to initialise
+ }
+ protected final double eval(Eval[] args, int srcCellRow, short srcCellCol) throws EvaluationException {
+ if (args.length != 2) {
+ throw new EvaluationException(ErrorEval.VALUE_INVALID);
+ }
+ double d0 = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
+ double d1 = singleOperandEvaluate(args[1], srcCellRow, srcCellCol);
+ return evaluate(d0, d1);
+ }
+ protected abstract double evaluate(double d0, double d1) throws EvaluationException;
+ }
+
+ public static abstract class MultiArg extends NumericFunction {
+ private final int _minArgs;
+ private final int _maxArgs;
+ protected MultiArg(int minArgs, int maxArgs) {
+ _minArgs = minArgs;
+ _maxArgs = maxArgs;
+ }
+ protected final double eval(Eval[] args, int srcCellRow, short srcCellCol) throws EvaluationException {
+ int nArgs = args.length;
+ if (nArgs < _minArgs || nArgs > _maxArgs) {
+ throw new EvaluationException(ErrorEval.VALUE_INVALID);
+ }
+ double[] ds = new double[nArgs];
+ for(int i=0; i<nArgs; i++) {
+ ds[i] = singleOperandEvaluate(args[i], srcCellRow, srcCellCol);
+ }
+ return evaluate(ds);
+ }
+ protected abstract double evaluate(double[] ds) throws EvaluationException;
+ }
+
+ /* -------------------------------------------------------------------------- */
+
+
+ public static final Function ABS = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.abs(d);
+ }
+ };
+ public static final Function ACOS = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.acos(d);
+ }
+ };
+ public static final Function ACOSH = new OneArg() {
+ protected double evaluate(double d) {
+ return MathX.acosh(d);
+ }
+ };
+ public static final Function ASIN = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.asin(d);
+ }
+ };
+ public static final Function ASINH = new OneArg() {
+ protected double evaluate(double d) {
+ return MathX.asinh(d);
+ }
+ };
+ public static final Function ATAN = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.atan(d);
+ }
+ };
+ public static final Function ATANH = new OneArg() {
+ protected double evaluate(double d) {
+ return MathX.atanh(d);
+ }
+ };
+ public static final Function COS = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.cos(d);
+ }
+ };
+ public static final Function COSH = new OneArg() {
+ protected double evaluate(double d) {
+ return MathX.cosh(d);
+ }
+ };
+ public static final Function DEGREES = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.toDegrees(d);
+ }
+ };
+ public static final Function DOLLAR = new OneArg() {
+ protected double evaluate(double d) {
+ return d;
+ }
+ };
+ public static final Function EXP = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.pow(Math.E, d);
+ }
+ };
+ public static final Function FACT = new OneArg() {
+ protected double evaluate(double d) {
+ return MathX.factorial((int)d);
+ }
+ };
+ public static final Function INT = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.round(d-0.5);
+ }
+ };
+ public static final Function LN = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.log(d);
+ }
+ };
+ public static final Function LOG10 = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.log(d) / LOG_10_TO_BASE_e;
+ }
+ };
+ public static final Function RADIANS = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.toRadians(d);
+ }
+ };
+ public static final Function SIGN = new OneArg() {
+ protected double evaluate(double d) {
+ return MathX.sign(d);
+ }
+ };
+ public static final Function SIN = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.sin(d);
+ }
+ };
+ public static final Function SINH = new OneArg() {
+ protected double evaluate(double d) {
+ return MathX.sinh(d);
+ }
+ };
+ public static final Function SQRT = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.sqrt(d);
+ }
+ };
+
+ public static final Function TAN = new OneArg() {
+ protected double evaluate(double d) {
+ return Math.tan(d);
+ }
+ };
+ public static final Function TANH = new OneArg() {
+ protected double evaluate(double d) {
+ return MathX.tanh(d);
+ }
+ };
+
+
+ /* -------------------------------------------------------------------------- */
+
+ public static final Function ATAN2 = new TwoArg() {
+ protected double evaluate(double d0, double d1) throws EvaluationException {
+ if (d0 == ZERO && d1 == ZERO) {
+ throw new EvaluationException(ErrorEval.DIV_ZERO);
+ }
+ return Math.atan2(d1, d0);
+ }
+ };
+ public static final Function CEILING = new TwoArg() {
+ protected double evaluate(double d0, double d1) {
+ return MathX.ceiling(d0, d1);
+ }
+ };
+ public static final Function COMBIN = new TwoArg() {
+ protected double evaluate(double d0, double d1) throws EvaluationException {
+ if (d0 > Integer.MAX_VALUE || d1 > Integer.MAX_VALUE) {
+ throw new EvaluationException(ErrorEval.NUM_ERROR);
+ }
+ return MathX.nChooseK((int) d0, (int) d1);
+ }
+ };
+ public static final Function FLOOR = new TwoArg() {
+ protected double evaluate(double d0, double d1) throws EvaluationException {
+ if (d1 == ZERO) {
+ if (d0 == ZERO) {
+ return ZERO;
+ }
+ throw new EvaluationException(ErrorEval.DIV_ZERO);
+ }
+ return MathX.floor(d0, d1);
+ }
+ };
+ public static final Function MOD = new TwoArg() {
+ protected double evaluate(double d0, double d1) throws EvaluationException {
+ if (d1 == ZERO) {
+ throw new EvaluationException(ErrorEval.DIV_ZERO);
+ }
+ return MathX.mod(d0, d1);
+ }
+ };
+ public static final Function POWER = new TwoArg() {
+ protected double evaluate(double d0, double d1) {
+ return Math.pow(d0, d1);
+ }
+ };
+ public static final Function ROUND = new TwoArg() {
+ protected double evaluate(double d0, double d1) {
+ return MathX.round(d0, (int)d1);
+ }
+ };
+ public static final Function ROUNDDOWN = new TwoArg() {
+ protected double evaluate(double d0, double d1) {
+ return MathX.roundDown(d0, (int)d1);
+ }
+ };
+ public static final Function ROUNDUP = new TwoArg() {
+ protected double evaluate(double d0, double d1) {
+ return MathX.roundUp(d0, (int)d1);
+ }
+ };
+
+ /* -------------------------------------------------------------------------- */
+
+ public static final Function LOG = new MultiArg(1,2) {
+ protected double evaluate(double[] ds) {
+
+ double logE = Math.log(ds[0]);
+ if (ds.length == 1) {
+ return logE / LOG_10_TO_BASE_e;
+ }
+ double base = ds[1];
+ if (base == Math.E) {
+ return logE;
+ }
+ return logE / Math.log(base);
+ }
+ };
}
+++ /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.hssf.record.formula.functions;
-
-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.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public abstract class NumericFunctionOneArg implements Function {
-
- public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
- if (args.length != 1) {
- return ErrorEval.VALUE_INVALID;
- }
- try {
- ValueEval ve = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
- double d = OperandResolver.coerceValueToDouble(ve);
- if (Double.isNaN(d) || Double.isInfinite(d)) {
- return ErrorEval.NUM_ERROR;
- }
- double result = evaluate(d);
- if (Double.isNaN(result) || Double.isInfinite(result)) {
- return ErrorEval.NUM_ERROR;
- }
- return new NumberEval(result);
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
- }
-
- protected abstract double evaluate(double d);
-
- public static final Function ABS = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.abs(d);
- }
- };
- public static final Function ACOS = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.acos(d);
- }
- };
- public static final Function ACOSH = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return MathX.acosh(d);
- }
- };
- public static final Function ASIN = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.asin(d);
- }
- };
- public static final Function ASINH = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return MathX.asinh(d);
- }
- };
- public static final Function ATAN = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.atan(d);
- }
- };
- public static final Function ATANH = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return MathX.atanh(d);
- }
- };
- public static final Function COS = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.cos(d);
- }
- };
- public static final Function COSH = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return MathX.cosh(d);
- }
- };
- public static final Function DEGREES = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.toDegrees(d);
- }
- };
- public static final Function DOLLAR = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return d;
- }
- };
- public static final Function EXP = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.pow(Math.E, d);
- }
- };
- public static final Function FACT = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return MathX.factorial((int)d);
- }
- };
- public static final Function INT = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.round(d-0.5);
- }
- };
- public static final Function LN = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.log(d);
- }
- };
- static final double LOG_10_TO_BASE_e = Math.log(10);
- public static final Function LOG10 = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.log(d) / LOG_10_TO_BASE_e;
- }
- };
- public static final Function RADIANS = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.toRadians(d);
- }
- };
- public static final Function SIGN = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return MathX.sign(d);
- }
- };
- public static final Function SIN = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.sin(d);
- }
- };
- public static final Function SINH = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return MathX.sinh(d);
- }
- };
- public static final Function SQRT = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.sqrt(d);
- }
- };
-
- public static final Function TAN = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return Math.tan(d);
- }
- };
- public static final Function TANH = new NumericFunctionOneArg() {
- protected double evaluate(double d) {
- return MathX.tanh(d);
- }
- };
-}
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*
*/
-public final class Odd extends NumericFunctionOneArg {
+public final class Odd extends NumericFunction.OneArg {
private static final long PARITY_MASK = 0xFFFFFFFFFFFFFFFEL;
protected double evaluate(double d) {
+++ /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.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-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.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * Implementation for the PMT() Excel function.<p/>
- *
- * <b>Syntax:</b><br/>
- * <b>PMT</b>(<b>rate</b>, <b>nper</b>, <b>pv</b>, fv, type)<p/>
- *
- * Returns the constant repayment amount required for a loan assuming a constant interest rate.<p/>
- *
- * <b>rate</b> the loan interest rate.<br/>
- * <b>nper</b> the number of loan repayments.<br/>
- * <b>pv</b> the present value of the future payments (or principle).<br/>
- * <b>fv</b> the future value (default zero) surplus cash at the end of the loan lifetime.<br/>
- * <b>type</b> whether payments are due at the beginning(1) or end(0 - default) of each payment period.<br/>
- *
- */
-public final class Pmt extends FinanceFunction {
-
- public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
-
- if(args.length < 3 || args.length > 5) {
- return ErrorEval.VALUE_INVALID;
- }
-
- try {
- // evaluate first three (always present) args
- double rate = evalArg(args[0], srcRow, srcCol);
- double nper = evalArg(args[1], srcRow, srcCol);
- double pv = evalArg(args[2], srcRow, srcCol);
- double fv = 0;
- boolean arePaymentsAtPeriodBeginning = false;
-
- switch (args.length) {
- case 5:
- ValueEval ve = singleOperandNumericAsBoolean(args[4], srcRow, srcCol);
- if (ve instanceof ErrorEval) {
- return ve;
- }
- arePaymentsAtPeriodBeginning = ((BoolEval) ve).getBooleanValue();
- case 4:
- fv = evalArg(args[3], srcRow, srcCol);
- }
- double d = FinanceLib.pmt(rate, nper, pv, fv, arePaymentsAtPeriodBeginning);
- if (Double.isNaN(d)) {
- return ErrorEval.VALUE_INVALID;
- }
- if (Double.isInfinite(d)) {
- return ErrorEval.NUM_ERROR;
- }
- return new NumberEval(d);
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
- }
-
- private double evalArg(Eval arg, int srcRow, short srcCol) throws EvaluationException {
- ValueEval ve = singleOperandEvaluate(arg, srcRow, srcCol);
- if(ve instanceof ErrorEval) {
- throw new EvaluationException((ErrorEval) ve);
- }
- if (ve instanceof NumericValueEval) {
- return ((NumericValueEval) ve).getNumberValue();
- }
- throw new EvaluationException(ErrorEval.VALUE_INVALID);
- }
-}
+++ /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.
-*/
-/*
- * Created on May 6, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Power extends NumericFunction {
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double d0 = 0;
- double d1 = 0;
- ValueEval retval = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 2:
- ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d0 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
-
- if (retval == null) {
- ValueEval vev = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (vev instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) vev;
- d1 = ne.getNumberValue();
- }
- else if (vev instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
- }
- }
-
- if (retval == null) {
- double d = Math.pow(d0, d1);
- retval = (Double.isNaN(d) || Double.isNaN(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d);
- }
- return retval;
- }
-
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Product extends MultiOperandNumericFunction {
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (
- ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- ));
-
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = MathX.product(values);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-public class Pv extends FinanceFunction {
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double rate = 0, fv = 0, nper = 0, pmt = 0, d = 0;
- boolean type = false;
- ValueEval retval = null;
- ValueEval ve = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 5:
- ve = singleOperandNumericAsBoolean(operands[4], srcRow, srcCol);
- if (ve instanceof ErrorEval) { retval = ErrorEval.VALUE_INVALID; break; }
- type = ((BoolEval) ve).getBooleanValue();
- case 4:
- ve = singleOperandEvaluate(operands[3], srcRow, srcCol);
- if (ve instanceof NumericValueEval) fv = ((NumericValueEval) ve).getNumberValue();
- else { retval = ErrorEval.VALUE_INVALID; break; }
- case 3:
- ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (ve instanceof NumericValueEval) nper = ((NumericValueEval) ve).getNumberValue();
- else { retval = ErrorEval.VALUE_INVALID; break; }
-
- ve = singleOperandEvaluate(operands[2], srcRow, srcCol);
- if (ve instanceof NumericValueEval) pmt = ((NumericValueEval) ve).getNumberValue();
- else { retval = ErrorEval.VALUE_INVALID; break; }
-
- ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if (ve instanceof NumericValueEval) rate = ((NumericValueEval) ve).getNumberValue();
- else { retval = ErrorEval.VALUE_INVALID; break; }
- }
-
- if (retval == null) {
- d = FinanceLib.pv(rate, nper, pmt, fv, type);
- retval = (Double.isNaN(d))
- ? (ValueEval) ErrorEval.VALUE_INVALID
- : (Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
- return retval;
- }
-}
-/*
-* 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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
+/* ====================================================================
+ 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.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
- * An implementation of the REPLACE function:
- * Replaces part of a text string based on the number of characters
- * you specify, with another text string.
+ * An implementation of the Excel REPLACE() function<p/>:
+ * Replaces part of a text string based on the number of characters
+ * you specify, with another text string.<br/>
+ *
+ * <b>Syntax</b>:<br/>
+ * <b>REPLACE</b>(<b>oldText</b>, <b>startNum</b>, <b>numChars</b>, <b>newText</b>)<p/>
+ *
+ * <b>oldText</b> The text string containing characters to replace<br/>
+ * <b>startNum</b> The position of the first character to replace (1-based)<br/>
+ * <b>numChars</b> The number of characters to replace<br/>
+ * <b>newText</b> The new text value to replace the removed section<br/>
+ *
* @author Manda Wilson < wilson at c bio dot msk cc dot org >
*/
-public class Replace extends TextFunction {
+public final class Replace extends TextFunction {
+
+ protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+ throws EvaluationException {
+ if (args.length != 4) {
+ return ErrorEval.VALUE_INVALID;
+ }
- /**
- * Replaces part of a text string based on the number of characters
- * you specify, with another text string.
- *
- * @see org.apache.poi.hssf.record.formula.eval.Eval
- */
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- Eval retval = null;
- String oldStr = null;
- String newStr = null;
- int startNum = 0;
- int numChars = 0;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- case 4:
- // first operand is text string containing characters to replace
- // second operand is position of first character to replace
- // third operand is the number of characters in the old string
- // you want to replace with new string
- // fourth operand is the new string
- ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
- ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
- ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol);
- ValueEval fourthveval = singleOperandEvaluate(operands[3], srcCellRow, srcCellCol);
- if (firstveval instanceof StringValueEval
- && secondveval instanceof NumericValueEval
- && thirdveval instanceof NumericValueEval
- && fourthveval instanceof StringValueEval) {
-
- StringValueEval oldStrEval = (StringValueEval) firstveval;
- oldStr = oldStrEval.getStringValue();
-
- NumericValueEval startNumEval = (NumericValueEval) secondveval;
- // NOTE: it is safe to cast to int here
- // because in Excel =REPLACE("task", 2.7, 3, "est")
- // returns test
- // so 2.7 must be truncated to 2
- // and =REPLACE("task", 1, 1.9, "") returns ask
- // so 1.9 must be truncated to 1
- startNum = (int) startNumEval.getNumberValue();
-
- NumericValueEval numCharsEval = (NumericValueEval) thirdveval;
- numChars = (int) numCharsEval.getNumberValue();
-
- StringValueEval newStrEval = (StringValueEval) fourthveval;
- newStr = newStrEval.getStringValue();
- } else {
- retval = ErrorEval.VALUE_INVALID;
- }
- }
-
- if (retval == null) {
- if (startNum < 1 || numChars < 0) {
- retval = ErrorEval.VALUE_INVALID;
- } else {
- StringBuffer strBuff = new StringBuffer(oldStr);
- // remove any characters that should be replaced
- if (startNum <= oldStr.length() && numChars != 0) {
- strBuff.delete(startNum - 1, startNum - 1 + numChars);
- }
- // now insert (or append) newStr
- if (startNum > strBuff.length()) {
- strBuff.append(newStr);
- } else {
- strBuff.insert(startNum - 1, newStr);
- }
- retval = new StringEval(strBuff.toString());
- }
- }
- return retval;
- }
+ String oldStr = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+ int startNum = evaluateIntArg(args[1], srcCellRow, srcCellCol);
+ int numChars = evaluateIntArg(args[2], srcCellRow, srcCellCol);
+ String newStr = evaluateStringArg(args[3], srcCellRow, srcCellCol);
+ if (startNum < 1 || numChars < 0) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ StringBuffer strBuff = new StringBuffer(oldStr);
+ // remove any characters that should be replaced
+ if (startNum <= oldStr.length() && numChars != 0) {
+ strBuff.delete(startNum - 1, startNum - 1 + numChars);
+ }
+ // now insert (or append) newStr
+ if (startNum > strBuff.length()) {
+ strBuff.append(newStr);
+ } else {
+ strBuff.insert(startNum - 1, newStr);
+ }
+ return new StringEval(strBuff.toString());
+ }
}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-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;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Right extends TextFunction {
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- Eval retval = ErrorEval.VALUE_INVALID;
- int index = 1;
- switch (operands.length) {
- default:
- break;
- case 2:
- Eval indexEval = operands[1];
- index = evaluateAsInteger(indexEval);
- if (index < 0) {
- break;
- }
- case 1:
- ValueEval veval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
- String str = null;
- if (veval instanceof StringEval) {
- StringEval stringEval = (StringEval) veval;
- str = stringEval.getStringValue();
- }
- else if (veval instanceof BoolEval) {
- BoolEval beval = (BoolEval) veval;
- str = beval.getBooleanValue() ? "TRUE" : "FALSE";
- }
- else if (veval instanceof NumberEval) {
- NumberEval neval = (NumberEval) veval;
- str = neval.getStringValue();
- }
- if (null != str) {
- int strlen = str.length();
- str = str.substring(Math.max(0, strlen-index));
- retval = new StringEval(str);
- }
- }
- return retval;
- }
-
- protected int evaluateAsInteger(Eval eval) {
- int numval = -1;
- if (eval instanceof NumberEval) {
- NumberEval neval = (NumberEval) eval;
- double d = neval.getNumberValue();
- numval = (int) d;
- }
- else if (eval instanceof StringEval) {
- StringEval seval = (StringEval) eval;
- String s = seval.getStringValue();
- try {
- double d = Double.parseDouble(s);
- numval = (int) d;
- }
- catch (Exception e) {
- }
- }
- else if (eval instanceof BoolEval) {
- BoolEval beval = (BoolEval) eval;
- numval = beval.getBooleanValue() ? 1 : 0;
- }
- else if (eval instanceof RefEval) {
- numval = evaluateAsInteger(xlateRefEval((RefEval) eval));
- }
- return numval;
- }
-
- protected Eval xlateRefEval(RefEval reval) {
- Eval retval = reval.getInnerValueEval();
-
- if (retval instanceof RefEval) {
- retval = xlateRefEval((RefEval) retval);
- }
- return retval;
- }
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-public class Round extends NumericFunction {
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double d0 = 0;
- double d1 = 0;
- ValueEval retval = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 2:
- ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d0 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
-
- if (retval == null) {
- ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d1 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
- }
- }
-
- if (retval == null) {
- double d;
- if (d0 > Integer.MAX_VALUE) {
- d = (Double.isNaN(d0) || Double.isInfinite(d0))
- ? Double.NaN
- : 0;
- }
- else {
- d = MathX.round(d0, (int) d1);
- }
- retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d);
- }
- return retval;
- }
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-public class Rounddown extends NumericFunction {
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double d0 = 0;
- double d1 = 0;
- ValueEval retval = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 2:
- ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if(ve instanceof ErrorEval) {
- return ve;
- }
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d0 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
-
- if (retval == null) {
- ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d1 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
- }
- }
-
- if (retval == null) {
- double d;
- if (d0 > Integer.MAX_VALUE) {
- d = (Double.isInfinite(d0))
- ? Double.NaN
- : 0;
- }
- else {
- d = MathX.roundDown(d0, (int) d1);
- }
- retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d);
- }
- return retval;
- }
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-public class Roundup extends NumericFunction {
-
- public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
- double d0 = 0;
- double d1 = 0;
- ValueEval retval = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 2:
- ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
- if(ve instanceof ErrorEval) {
- return ve;
- }
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d0 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
-
- if (retval == null) {
- ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
- if (ve instanceof NumericValueEval) {
- NumericValueEval ne = (NumericValueEval) ve;
- d1 = ne.getNumberValue();
- }
- else if (ve instanceof BlankEval) {
- // do nothing
- }
- else {
- retval = ErrorEval.NUM_ERROR;
- }
- }
- }
-
- if (retval == null) {
- double d;
- if (d0 > Integer.MAX_VALUE) {
- d = (Double.isNaN(d0))
- ? Double.NaN
- : 0;
- }
- else {
- d = MathX.roundUp(d0, (int) d1);
- }
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
- return retval;
- }
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Small extends MultiOperandNumericFunction {
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (0
- | ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.EVALUATED_REF_BLANK_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BLANK_IS_PARSED
- //| ValueEvalToNumericXlator.BLANK_IS_PARSED
- ));
-
- /**
- * this is the default impl for the factory method getXlator
- * of the super class NumericFunction. Subclasses can override this method
- * if they desire to return a different ValueEvalToNumericXlator instance
- * than the default.
- */
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] ops = getNumberArray(operands, srcCellRow, srcCellCol);
- if (ops == null || ops.length < 2) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double[] values = new double[ops.length-1];
- int k = (int) ops[ops.length-1];
- System.arraycopy(ops, 0, values, 0, values.length);
- double d = StatsLib.kthSmallest(values, k);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
return r;
}
- /**
- * if v is zero length or contains no duplicates, return value
- * is Double.NaN. Else returns the value that occurs most times
- * and if there is a tie, returns the first such value.
- * @param v
- */
- public static double mode(double[] v) {
- double r = Double.NaN;
-
- // very naive impl, may need to be optimized
- if (v!=null && v.length > 1) {
- int[] counts = new int[v.length];
- Arrays.fill(counts, 1);
- for (int i=0, iSize=v.length; i<iSize; i++) {
- for (int j=i+1, jSize=v.length; j<jSize; j++) {
- if (v[i] == v[j]) counts[i]++;
- }
- }
- double maxv = 0;
- int maxc = 0;
- for (int i=0, iSize=counts.length; i<iSize; i++) {
- if (counts[i] > maxc) {
- maxv = v[i];
- maxc = counts[i];
- }
- }
- r = (maxc > 1) ? maxv : Double.NaN; // "no-dups" check
- }
- return r;
- }
public static double median(double[] v) {
double r = Double.NaN;
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Stdev extends MultiOperandNumericFunction {
-
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (
- ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- ));
-
- /**
- * this is the default impl for the factory method getXlator
- * of the super class NumericFunction. Subclasses can override this method
- * if they desire to return a different ValueEvalToNumericXlator instance
- * than the default.
- */
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = StatsLib.stdev(values);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
-/*
-* 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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
+/* ====================================================================
+ 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.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
* Substitutes text in a text string with new text, some number of times.
* @author Manda Wilson < wilson at c bio dot msk cc dot org >
*/
-public class Substitute extends TextFunction {
- private static final int REPLACE_ALL = -1;
-
- /**
- *Substitutes text in a text string with new text, some number of times.
- *
- * @see org.apache.poi.hssf.record.formula.eval.Eval
- */
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- Eval retval = null;
- String oldStr = null;
- String searchStr = null;
- String newStr = null;
- int numToReplace = REPLACE_ALL;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- case 4:
- ValueEval fourthveval = singleOperandEvaluate(operands[3], srcCellRow, srcCellCol);
- if (fourthveval instanceof NumericValueEval) {
- NumericValueEval numToReplaceEval = (NumericValueEval) fourthveval;
- // NOTE: it is safe to cast to int here
- // because in Excel =SUBSTITUTE("teststr","t","T",1.9)
- // returns Teststr
- // so 1.9 must be truncated to 1
- numToReplace = (int) numToReplaceEval.getNumberValue();
- } else {
- retval = ErrorEval.VALUE_INVALID;
- }
- case 3:
- // first operand is text string containing characters to replace
- // second operand is text to find
- // third operand is replacement text
- ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
- ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
- ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol);
- if (firstveval instanceof StringValueEval
- && secondveval instanceof StringValueEval
- && thirdveval instanceof StringValueEval) {
-
- StringValueEval oldStrEval = (StringValueEval) firstveval;
- oldStr = oldStrEval.getStringValue();
-
- StringValueEval searchStrEval = (StringValueEval) secondveval;
- searchStr = searchStrEval.getStringValue();
-
- StringValueEval newStrEval = (StringValueEval) thirdveval;
- newStr = newStrEval.getStringValue();
- } else {
- retval = ErrorEval.VALUE_INVALID;
- }
- }
-
- if (retval == null) {
- if (numToReplace != REPLACE_ALL && numToReplace < 1) {
- retval = ErrorEval.VALUE_INVALID;
- } else if (searchStr.length() == 0) {
- retval = new StringEval(oldStr);
- } else {
- StringBuffer strBuff = new StringBuffer();
- int startIndex = 0;
- int nextMatch = -1;
- for (int leftToReplace = numToReplace;
- (leftToReplace > 0 || numToReplace == REPLACE_ALL)
- && (nextMatch = oldStr.indexOf(searchStr, startIndex)) != -1;
- leftToReplace--) {
- // store everything from end of last match to start of this match
- strBuff.append(oldStr.substring(startIndex, nextMatch));
- strBuff.append(newStr);
- startIndex = nextMatch + searchStr.length();
+public final class Substitute extends TextFunction {
+
+ protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+ throws EvaluationException {
+ if (args.length < 3 || args.length > 4) {
+ return ErrorEval.VALUE_INVALID;
+ }
+
+ String oldStr = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+ String searchStr = evaluateStringArg(args[1], srcCellRow, srcCellCol);
+ String newStr = evaluateStringArg(args[2], srcCellRow, srcCellCol);
+
+ String result;
+ switch (args.length) {
+ default:
+ throw new IllegalStateException("Cannot happen");
+ case 4:
+ int instanceNumber = evaluateIntArg(args[3], srcCellRow, srcCellCol);
+ if (instanceNumber < 1) {
+ return ErrorEval.VALUE_INVALID;
}
+ result = replaceOneOccurrence(oldStr, searchStr, newStr, instanceNumber);
+ break;
+ case 3:
+ result = replaceAllOccurrences(oldStr, searchStr, newStr);
+ }
+ return new StringEval(result);
+ }
+
+ private static String replaceAllOccurrences(String oldStr, String searchStr, String newStr) {
+ StringBuffer sb = new StringBuffer();
+ int startIndex = 0;
+ int nextMatch = -1;
+ while (true) {
+ nextMatch = oldStr.indexOf(searchStr, startIndex);
+ if (nextMatch < 0) {
// store everything from end of last match to end of string
- if (startIndex < oldStr.length()) {
- strBuff.append(oldStr.substring(startIndex));
- }
- retval = new StringEval(strBuff.toString());
+ sb.append(oldStr.substring(startIndex));
+ return sb.toString();
+ }
+ // store everything from end of last match to start of this match
+ sb.append(oldStr.substring(startIndex, nextMatch));
+ sb.append(newStr);
+ startIndex = nextMatch + searchStr.length();
+ }
+ }
+
+ private static String replaceOneOccurrence(String oldStr, String searchStr, String newStr, int instanceNumber) {
+ if (searchStr.length() < 1) {
+ return oldStr;
+ }
+ int startIndex = 0;
+ int nextMatch = -1;
+ int count=0;
+ while (true) {
+ nextMatch = oldStr.indexOf(searchStr, startIndex);
+ if (nextMatch < 0) {
+ // not enough occurrences found - leave unchanged
+ return oldStr;
+ }
+ count++;
+ if (count == instanceNumber) {
+ StringBuffer sb = new StringBuffer(oldStr.length() + newStr.length());
+ sb.append(oldStr.substring(0, nextMatch));
+ sb.append(newStr);
+ sb.append(oldStr.substring(nextMatch + searchStr.length()));
+ return sb.toString();
}
- }
- return retval;
- }
-
+ startIndex = nextMatch + searchStr.length();
+ }
+ }
}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Sum extends MultiOperandNumericFunction {
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (
- ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- ));
-
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = values.length > 0 ? MathX.sum(values) : 0;
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Sumsq extends MultiOperandNumericFunction {
- private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
- new ValueEvalToNumericXlator((short) (
- ValueEvalToNumericXlator.BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
- | ValueEvalToNumericXlator.STRING_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
- //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
- //| ValueEvalToNumericXlator.REF_BLANK_IS_PARSED
- //| ValueEvalToNumericXlator.BLANK_IS_PARSED
- ));
-
- protected ValueEvalToNumericXlator getXlator() {
- return DEFAULT_NUM_XLATOR;
- }
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- double[] values = getNumberArray(operands, srcCellRow, srcCellCol);
- if (values == null) {
- retval = ErrorEval.VALUE_INVALID;
- }
- else {
- double d = MathX.sumsq(values);
- retval = (Double.isNaN(d) || Double.isInfinite(d))
- ? (ValueEval) ErrorEval.NUM_ERROR
- : new NumberEval(d);
- }
-
- return retval;
- }
-}
-/*
-* 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.
-*/
-/*
- * Created on May 22, 2005
- *
- */
+/* ====================================================================
+ 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.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.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.RefEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
*
*/
public abstract class TextFunction implements Function {
-
- protected static final String EMPTY_STRING = "";
-
- protected ValueEval singleOperandEvaluate(Eval eval, int srcRow, short srcCol) {
- ValueEval retval;
- if (eval instanceof AreaEval) {
- AreaEval ae = (AreaEval) eval;
- if (ae.contains(srcRow, srcCol)) { // circular ref!
- retval = ErrorEval.CIRCULAR_REF_ERROR;
- }
- else if (ae.isRow()) {
- if (ae.containsColumn(srcCol)) {
- ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCol);
- retval = attemptXlateToText(ve);
- }
- else {
- retval = ErrorEval.VALUE_INVALID;
- }
- }
- else if (ae.isColumn()) {
- if (ae.containsRow(srcRow)) {
- ValueEval ve = ae.getValueAt(srcRow, ae.getFirstColumn());
- retval = attemptXlateToText(ve);
- }
- else {
- retval = ErrorEval.VALUE_INVALID;
- }
- }
- else {
- retval = ErrorEval.VALUE_INVALID;
- }
- }
- else {
- retval = attemptXlateToText((ValueEval) eval);
- }
- return retval;
- }
-
-
- /**
- * converts from Different ValueEval types to StringEval.
- * Note: AreaEvals are not handled, if arg is an AreaEval,
- * the returned value is ErrorEval.VALUE_INVALID
- * @param ve
- */
- protected ValueEval attemptXlateToText(ValueEval ve) {
- ValueEval retval;
- if (ve instanceof StringValueEval) {
- retval = ve;
- }
- else if (ve instanceof RefEval) {
- RefEval re = (RefEval) ve;
- ValueEval ive = re.getInnerValueEval();
- if (ive instanceof StringValueEval) {
- retval = ive;
- }
- else if (ive instanceof BlankEval) {
- retval = ive;
- }
- else {
- retval = ErrorEval.VALUE_INVALID;
- }
- }
- else if (ve instanceof BlankEval) {
- retval = ve;
- }
- else {
- retval = ErrorEval.VALUE_INVALID;
- }
- return retval;
- }
+
+ protected static final String EMPTY_STRING = "";
+
+ protected static final String evaluateStringArg(Eval eval, int srcRow, short srcCol) throws EvaluationException {
+ ValueEval ve = OperandResolver.getSingleValue(eval, srcRow, srcCol);
+ return OperandResolver.coerceValueToString(ve);
+ }
+ protected static final int evaluateIntArg(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
+ ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+ return OperandResolver.coerceValueToInt(ve);
+ }
+
+ public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ try {
+ return evaluateFunc(args, srcCellRow, srcCellCol);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ }
+
+ protected abstract ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol) throws EvaluationException;
+
+ /* ---------------------------------------------------------------------- */
+
+ private static abstract class SingleArgTextFunc extends TextFunction {
+
+ protected SingleArgTextFunc() {
+ // no fields to initialise
+ }
+ protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+ throws EvaluationException {
+ if (args.length != 1) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ String arg = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+ return evaluate(arg);
+ }
+ protected abstract ValueEval evaluate(String arg);
+ }
+
+ public static final Function LEN = new SingleArgTextFunc() {
+ protected ValueEval evaluate(String arg) {
+ return new NumberEval(arg.length());
+ }
+ };
+ public static final Function LOWER = new SingleArgTextFunc() {
+ protected ValueEval evaluate(String arg) {
+ return new StringEval(arg.toLowerCase());
+ }
+ };
+ public static final Function UPPER = new SingleArgTextFunc() {
+ protected ValueEval evaluate(String arg) {
+ return new StringEval(arg.toUpperCase());
+ }
+ };
+ /**
+ * An implementation of the TRIM function:
+ * Removes leading and trailing spaces from value if evaluated operand
+ * value is string.
+ * @author Manda Wilson < wilson at c bio dot msk cc dot org >
+ */
+ public static final Function TRIM = new SingleArgTextFunc() {
+ protected ValueEval evaluate(String arg) {
+ return new StringEval(arg.trim());
+ }
+ };
+
+ /**
+ * An implementation of the MID function<br/>
+ * MID returns a specific number of
+ * characters from a text string, starting at the specified position.<p/>
+ *
+ * <b>Syntax<b>:<br/> <b>MID</b>(<b>text</b>, <b>start_num</b>,
+ * <b>num_chars</b>)<br/>
+ *
+ * @author Manda Wilson < wilson at c bio dot msk cc dot org >
+ */
+ public static final Function MID = new TextFunction() {
+
+ protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+ throws EvaluationException {
+ if (args.length != 3) {
+ return ErrorEval.VALUE_INVALID;
+ }
+
+ String text = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+ int startCharNum = evaluateIntArg(args[1], srcCellRow, srcCellCol);
+ int numChars = evaluateIntArg(args[2], srcCellRow, srcCellCol);
+ int startIx = startCharNum - 1; // convert to zero-based
+
+ // Note - for start_num arg, blank/zero causes error(#VALUE!),
+ // but for num_chars causes empty string to be returned.
+ if (startIx < 0) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ if (numChars < 0) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ int len = text.length();
+ if (numChars < 0 || startIx > len) {
+ return new StringEval("");
+ }
+ int endIx = Math.min(startIx + numChars, len);
+ String result = text.substring(startIx, endIx);
+ return new StringEval(result);
+ }
+ };
+
+ private static final class LeftRight extends TextFunction {
+
+ private final boolean _isLeft;
+ protected LeftRight(boolean isLeft) {
+ _isLeft = isLeft;
+ }
+ protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+ throws EvaluationException {
+ if (args.length != 2) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ String arg = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+ int index = evaluateIntArg(args[1], srcCellRow, srcCellCol);
+
+ String result;
+ if (_isLeft) {
+ result = arg.substring(0, Math.min(arg.length(), index));
+ } else {
+ result = arg.substring(Math.max(0, arg.length()-index));
+ }
+ return new StringEval(result);
+ }
+ }
+
+ public static final Function LEFT = new LeftRight(true);
+ public static final Function RIGHT = new LeftRight(false);
+
+ public static final Function CONCATENATE = new TextFunction() {
+
+ protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+ throws EvaluationException {
+ StringBuffer sb = new StringBuffer();
+ for (int i=0, iSize=args.length; i<iSize; i++) {
+ sb.append(evaluateStringArg(args[i], srcCellRow, srcCellCol));
+ }
+ return new StringEval(sb.toString());
+ }
+ };
+
+ public static final Function EXACT = new TextFunction() {
+
+ protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+ throws EvaluationException {
+ if (args.length != 2) {
+ return ErrorEval.VALUE_INVALID;
+ }
+
+ String s0 = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+ String s1 = evaluateStringArg(args[1], srcCellRow, srcCellCol);
+ return BoolEval.valueOf(s0.equals(s1));
+ }
+ };
}
+++ /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.hssf.record.formula.functions;
-
-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.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * An implementation of the TRIM function:
- * Removes leading and trailing spaces from value if evaluated operand
- * value is string.
- * @author Manda Wilson < wilson at c bio dot msk cc dot org >
- */
-public final class Trim extends TextFunction {
-
- public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
-
- if(args.length != 1) {
- return ErrorEval.VALUE_INVALID;
- }
-
- try {
- ValueEval veval = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
-
- String str = OperandResolver.coerceValueToString(veval);
- str = str.trim();
- if(str.length() < 1) {
- return StringEval.EMPTY_INSTANCE;
- }
- return new StringEval(str);
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
- }
-}
+++ /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.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-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.StringEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public class Upper extends TextFunction {
-
-
- public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
- ValueEval retval = null;
- String s = null;
-
- switch (operands.length) {
- default:
- retval = ErrorEval.VALUE_INVALID;
- break;
- case 1:
- ValueEval ve = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
- if (ve instanceof StringValueEval) {
- StringValueEval sve = (StringValueEval) ve;
- s = sve.getStringValue();
- }
- else if (ve instanceof BlankEval) {}
- else {
- retval = ErrorEval.VALUE_INVALID;
- break;
- }
- }
-
- if (retval == null) {
- s = (s == null) ? EMPTY_STRING : s;
- retval = new StringEval(s.toUpperCase());
- }
-
- return retval;
- }
-}
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import org.apache.poi.hssf.model.FormulaParser;
import org.apache.poi.hssf.model.Sheet;
* Cells can be numeric, formula-based or string-based (text). The cell type
* specifies this. String cells cannot conatin numbers and numeric cells cannot
* contain strings (at least according to our model). Client apps should do the
- * conversions themselves. Formula cells have the formula string, as well as
- * the formula result, which can be numeric or string.
+ * conversions themselves. Formula cells have the formula string, as well as
+ * the formula result, which can be numeric or string.
* <p>
* Cells should have their number (0 based) before being added to a row. Only
* cells that have values should be added.
public final static int CELL_TYPE_BOOLEAN = 4;
/** Error Cell type (5) @see #setCellType(int) @see #getCellType() */
public final static int CELL_TYPE_ERROR = 5;
-
+
public final static short ENCODING_UNCHANGED = -1;
public final static short ENCODING_COMPRESSED_UNICODE = 0;
public final static short ENCODING_UTF_16 = 1;
+
+ private final HSSFWorkbook book;
+ private final HSSFSheet sheet;
private int cellType;
private HSSFRichTextString stringValue;
- private HSSFWorkbook book;
- private Sheet sheet;
private CellValueRecordInterface record;
private HSSFComment comment;
*
* @see org.apache.poi.hssf.usermodel.HSSFRow#createCell(short)
*/
- protected HSSFCell(HSSFWorkbook book, Sheet sheet, int row, short col)
+ protected HSSFCell(HSSFWorkbook book, HSSFSheet sheet, int row, short col)
{
checkBounds(col);
stringValue = null;
// Relying on the fact that by default the cellType is set to 0 which
// is different to CELL_TYPE_BLANK hence the following method call correctly
// creates a new blank cell.
- short xfindex = sheet.getXFIndexForColAt(col);
+ short xfindex = sheet.getSheet().getXFIndexForColAt(col);
setCellType(CELL_TYPE_BLANK, false, row, col,xfindex);
}
+ public HSSFSheet getSheet() {
+ return sheet;
+ }
/**
* Creates new Cell - Should only be called by HSSFRow. This creates a cell
* Type of cell
* @see org.apache.poi.hssf.usermodel.HSSFRow#createCell(short,int)
*/
- protected HSSFCell(HSSFWorkbook book, Sheet sheet, int row, short col,
+ protected HSSFCell(HSSFWorkbook book, HSSFSheet sheet, int row, short col,
int type)
{
checkBounds(col);
stringValue = null;
this.book = book;
this.sheet = sheet;
-
- short xfindex = sheet.getXFIndexForColAt(col);
+
+ short xfindex = sheet.getSheet().getXFIndexForColAt(col);
setCellType(type,false,row,col,xfindex);
}
* @param sheet - Sheet record of the sheet containing this cell
* @param cval - the Cell Value Record we wish to represent
*/
- protected HSSFCell(HSSFWorkbook book, Sheet sheet, CellValueRecordInterface cval) {
+ protected HSSFCell(HSSFWorkbook book, HSSFSheet sheet, CellValueRecordInterface cval) {
record = cval;
cellType = determineType(cval);
stringValue = null;
* used internally -- given a cell value record, figure out its type
*/
private static int determineType(CellValueRecordInterface cval) {
- if (cval instanceof FormulaRecordAggregate) {
- return HSSFCell.CELL_TYPE_FORMULA;
- }
- // all others are plain BIFF records
+ if (cval instanceof FormulaRecordAggregate) {
+ return HSSFCell.CELL_TYPE_FORMULA;
+ }
+ // all others are plain BIFF records
Record record = ( Record ) cval;
switch (record.getSid()) {
}
throw new RuntimeException("Bad cell value rec (" + cval.getClass().getName() + ")");
}
-
+
/**
* Returns the Workbook that this Cell is bound to
* @return
*/
protected Workbook getBoundWorkbook() {
- return book.getWorkbook();
+ return book.getWorkbook();
}
/**
{
record.setColumn(num);
}
-
+
/**
* Updates the cell record's idea of what
* column it belongs in (0 based)
*/
protected void updateCellNum(short num)
{
- record.setColumn(num);
+ record.setColumn(num);
}
/**
FormulaRecordAggregate frec;
if (cellType != this.cellType) {
- frec = sheet.createFormula(row, col);
+ frec = sheet.getSheet().createFormula(row, col);
} else {
frec = (FormulaRecordAggregate) record;
frec.setRow(row);
errRec.setColumn(col);
if (setValue)
{
- errRec.setValue(getErrorCellValue());
+ errRec.setValue((byte)HSSFErrorConstants.ERROR_VALUE);
}
errRec.setXFIndex(styleIndex);
errRec.setRow(row);
record = errRec;
break;
}
- if (cellType != this.cellType &&
+ if (cellType != this.cellType &&
this.cellType!=-1 ) // Special Value to indicate an uninitialized Cell
{
- sheet.replaceValueRecord(record);
+ sheet.getSheet().replaceValueRecord(record);
}
this.cellType = cellType;
}
* precalculated value, for numerics we'll set its value. For other types we
* will change the cell to a numeric cell and set its value.
*/
- public void setCellValue(double value)
- {
+ public void setCellValue(double value) {
int row=record.getRow();
short col=record.getColumn();
short styleIndex=record.getXFIndex();
- if ((cellType != CELL_TYPE_NUMERIC) && (cellType != CELL_TYPE_FORMULA))
- {
- setCellType(CELL_TYPE_NUMERIC, false, row, col, styleIndex);
- }
-
- // Save into the appropriate record
- if(record instanceof FormulaRecordAggregate) {
- (( FormulaRecordAggregate ) record).getFormulaRecord().setValue(value);
- } else {
- (( NumberRecord ) record).setValue(value);
+
+ switch (cellType) {
+ default:
+ setCellType(CELL_TYPE_NUMERIC, false, row, col, styleIndex);
+ case CELL_TYPE_ERROR:
+ (( NumberRecord ) record).setValue(value);
+ break;
+ case CELL_TYPE_FORMULA:
+ ((FormulaRecordAggregate)record).getFormulaRecord().setValue(value);
+ break;
}
}
/**
* set a date value for the cell. Excel treats dates as numeric so you will need to format the cell as
* a date.
- *
+ *
* This will set the cell value based on the Calendar's timezone. As Excel
* does not support timezones this means that both 20:00+03:00 and
* 20:00-03:00 will be reported as the same value (20:00) even that there
return;
}
if (cellType == CELL_TYPE_FORMULA) {
- // Set the 'pre-evaluated result' for the formula
+ // Set the 'pre-evaluated result' for the formula
// note - formulas do not preserve text formatting.
FormulaRecordAggregate fr = (FormulaRecordAggregate) record;
-
- // Save the string into a String Record, creating
- // one if required
- StringRecord sr = fr.getStringRecord();
- if(sr == null) {
- // Wasn't a string before, need a new one
- sr = new StringRecord();
- fr.setStringRecord(sr);
- }
-
- // Save, loosing the formatting
- sr.setString(hvalue.getString());
+ fr.setCachedStringResult(hvalue.getString());
// Update our local cache to the un-formatted version
- stringValue = new HSSFRichTextString(sr.getString());
-
+ stringValue = new HSSFRichTextString(value.getString());
+
// All done
return;
}
// If we get here, we're not dealing with a formula,
// so handle things as a normal rich text cell
-
+
if (cellType != CELL_TYPE_STRING) {
setCellType(CELL_TYPE_STRING, false, row, col, styleIndex);
}
FormulaRecord frec = rec.getFormulaRecord();
frec.setOptions((short) 2);
frec.setValue(0);
-
+
//only set to default if there is no extended format index already set
if (rec.getXFIndex() == (short)0) {
- rec.setXFIndex((short) 0x0f);
- }
+ rec.setXFIndex((short) 0x0f);
+ }
Ptg[] ptgs = FormulaParser.parse(formula, book);
frec.setParsedExpression(ptgs);
}
+ /* package */ void setFormulaOnly(Ptg[] ptgs) {
+ if (ptgs == null) {
+ throw new IllegalArgumentException("ptgs must not be null");
+ }
+ ((FormulaRecordAggregate)record).getFormulaRecord().setParsedExpression(ptgs);
+ }
public String getCellFormula() {
return FormulaParser.toFormulaString(book, ((FormulaRecordAggregate)record).getFormulaRecord().getParsedExpression());
}
+ /**
+ * Used to help format error messages
+ */
+ private static String getCellTypeName(int cellTypeCode) {
+ switch (cellTypeCode) {
+ case CELL_TYPE_BLANK: return "blank";
+ case CELL_TYPE_STRING: return "text";
+ case CELL_TYPE_BOOLEAN: return "boolean";
+ case CELL_TYPE_ERROR: return "error";
+ case CELL_TYPE_NUMERIC: return "numeric";
+ case CELL_TYPE_FORMULA: return "formula";
+ }
+ return "#unknown cell type (" + cellTypeCode + ")#";
+ }
+
+ private static RuntimeException typeMismatch(int expectedTypeCode, int actualTypeCode, boolean isFormulaCell) {
+ String msg = "Cannot get a "
+ + getCellTypeName(expectedTypeCode) + " value from a "
+ + getCellTypeName(actualTypeCode) + " " + (isFormulaCell ? "formula " : "") + "cell";
+ return new IllegalStateException(msg);
+ }
+ private static void checkFormulaCachedValueType(int expectedTypeCode, FormulaRecord fr) {
+ int cachedValueType = fr.getCachedResultType();
+ if (cachedValueType != expectedTypeCode) {
+ throw typeMismatch(expectedTypeCode, cachedValueType, true);
+ }
+ }
/**
- * Get the value of the cell as a number.
+ * Get the value of the cell as a number.
* For strings we throw an exception.
* For blank cells we return a 0.
* See {@link HSSFDataFormatter} for turning this
* number into a string similar to that which
- * Excel would render this number as.
+ * Excel would render this number as.
*/
- public double getNumericCellValue()
- {
- if (cellType == CELL_TYPE_BLANK)
- {
- return 0;
- }
- if (cellType == CELL_TYPE_STRING)
- {
- throw new NumberFormatException(
- "You cannot get a numeric value from a String based cell");
- }
- if (cellType == CELL_TYPE_BOOLEAN)
- {
- throw new NumberFormatException(
- "You cannot get a numeric value from a boolean cell");
- }
- if (cellType == CELL_TYPE_ERROR)
- {
- throw new NumberFormatException(
- "You cannot get a numeric value from an error cell");
- }
- if(cellType == CELL_TYPE_NUMERIC)
- {
- return ((NumberRecord)record).getValue();
- }
- if(cellType == CELL_TYPE_FORMULA)
- {
- return ((FormulaRecordAggregate)record).getFormulaRecord().getValue();
+ public double getNumericCellValue() {
+
+ switch(cellType) {
+ case CELL_TYPE_BLANK:
+ return 0.0;
+ case CELL_TYPE_NUMERIC:
+ return ((NumberRecord)record).getValue();
+ default:
+ throw typeMismatch(CELL_TYPE_NUMERIC, cellType, false);
+ case CELL_TYPE_FORMULA:
+ break;
}
- throw new NumberFormatException("Unknown Record Type in Cell:"+cellType);
+ FormulaRecord fr = ((FormulaRecordAggregate)record).getFormulaRecord();
+ checkFormulaCachedValueType(CELL_TYPE_NUMERIC, fr);
+ return fr.getValue();
}
/**
- * Get the value of the cell as a date.
+ * Get the value of the cell as a date.
* For strings we throw an exception.
* For blank cells we return a null.
* See {@link HSSFDataFormatter} for formatting
* this date into a string similar to how excel does.
*/
- public Date getDateCellValue()
- {
- if (cellType == CELL_TYPE_BLANK)
- {
+ public Date getDateCellValue() {
+
+ if (cellType == CELL_TYPE_BLANK) {
return null;
}
- if (cellType == CELL_TYPE_STRING)
- {
- throw new NumberFormatException(
- "You cannot get a date value from a String based cell");
- }
- if (cellType == CELL_TYPE_BOOLEAN)
- {
- throw new NumberFormatException(
- "You cannot get a date value from a boolean cell");
- }
- if (cellType == CELL_TYPE_ERROR)
- {
- throw new NumberFormatException(
- "You cannot get a date value from an error cell");
- }
- double value=this.getNumericCellValue();
+ double value = getNumericCellValue();
if (book.getWorkbook().isUsing1904DateWindowing()) {
- return HSSFDateUtil.getJavaDate(value,true);
- }
- else {
- return HSSFDateUtil.getJavaDate(value,false);
+ return HSSFDateUtil.getJavaDate(value, true);
}
+ return HSSFDateUtil.getJavaDate(value, false);
}
/**
* For blank cells we return an empty string.
* For formulaCells that are not string Formulas, we return empty String
*/
+ public HSSFRichTextString getRichStringCellValue() {
- public HSSFRichTextString getRichStringCellValue()
- {
- if (cellType == CELL_TYPE_BLANK)
- {
- return new HSSFRichTextString("");
- }
- if (cellType == CELL_TYPE_NUMERIC)
- {
- throw new NumberFormatException(
- "You cannot get a string value from a numeric cell");
- }
- if (cellType == CELL_TYPE_BOOLEAN)
- {
- throw new NumberFormatException(
- "You cannot get a string value from a boolean cell");
- }
- if (cellType == CELL_TYPE_ERROR)
- {
- throw new NumberFormatException(
- "You cannot get a string value from an error cell");
- }
- if (cellType == CELL_TYPE_FORMULA)
- {
- if (stringValue==null) return new HSSFRichTextString("");
+ switch(cellType) {
+ case CELL_TYPE_BLANK:
+ return new HSSFRichTextString("");
+ case CELL_TYPE_STRING:
+ return stringValue;
+ default:
+ throw typeMismatch(CELL_TYPE_STRING, cellType, false);
+ case CELL_TYPE_FORMULA:
+ break;
}
- return stringValue;
+ FormulaRecordAggregate fra = ((FormulaRecordAggregate)record);
+ checkFormulaCachedValueType(CELL_TYPE_STRING, fra.getFormulaRecord());
+ String strVal = fra.getStringValue();
+ return new HSSFRichTextString(strVal == null ? "" : strVal);
}
/**
* will change the cell to a boolean cell and set its value.
*/
- public void setCellValue(boolean value)
- {
+ public void setCellValue(boolean value) {
int row=record.getRow();
short col=record.getColumn();
short styleIndex=record.getXFIndex();
- if ((cellType != CELL_TYPE_BOOLEAN ) && ( cellType != CELL_TYPE_FORMULA))
- {
- setCellType(CELL_TYPE_BOOLEAN, false, row, col, styleIndex);
+
+ switch (cellType) {
+ default:
+ setCellType(CELL_TYPE_BOOLEAN, false, row, col, styleIndex);
+ case CELL_TYPE_ERROR:
+ (( BoolErrRecord ) record).setValue(value);
+ break;
+ case CELL_TYPE_FORMULA:
+ ((FormulaRecordAggregate)record).getFormulaRecord().setCachedResultBoolean(value);
+ break;
}
- (( BoolErrRecord ) record).setValue(value);
}
/**
* set a error value for the cell
*
- * @param value the error value to set this cell to. For formulas we'll set the
- * precalculated value ??? IS THIS RIGHT??? , for errors we'll set
+ * @param errorCode the error value to set this cell to. For formulas we'll set the
+ * precalculated value , for errors we'll set
* its value. For other types we will change the cell to an error
* cell and set its value.
*/
-
- public void setCellErrorValue(byte value)
- {
+ public void setCellErrorValue(byte errorCode) {
int row=record.getRow();
short col=record.getColumn();
short styleIndex=record.getXFIndex();
- if (cellType != CELL_TYPE_ERROR) {
- setCellType(CELL_TYPE_ERROR, false, row, col, styleIndex);
+ switch (cellType) {
+ default:
+ setCellType(CELL_TYPE_ERROR, false, row, col, styleIndex);
+ case CELL_TYPE_ERROR:
+ (( BoolErrRecord ) record).setValue(errorCode);
+ break;
+ case CELL_TYPE_FORMULA:
+ ((FormulaRecordAggregate)record).getFormulaRecord().setCachedResultErrorCode(errorCode);
+ break;
}
- (( BoolErrRecord ) record).setValue(value);
}
/**
* Chooses a new boolean value for the cell when its type is changing.<p/>
- *
- * Usually the caller is calling setCellType() with the intention of calling
+ *
+ * Usually the caller is calling setCellType() with the intention of calling
* setCellValue(boolean) straight afterwards. This method only exists to give
* the cell a somewhat reasonable value until the setCellValue() call (if at all).
* TODO - perhaps a method like setCellTypeAndValue(int, Object) should be introduced to avoid this
*/
private boolean convertCellValueToBoolean() {
-
+
switch (cellType) {
case CELL_TYPE_BOOLEAN:
return (( BoolErrRecord ) record).getBooleanValue();
// All other cases convert to false
// These choices are not well justified.
- case CELL_TYPE_FORMULA:
+ case CELL_TYPE_FORMULA:
// should really evaluate, but HSSFCell can't call HSSFFormulaEvaluator
case CELL_TYPE_ERROR:
case CELL_TYPE_BLANK:
- return false;
+ return false;
}
throw new RuntimeException("Unexpected cell type (" + cellType + ")");
}
* get the value of the cell as a boolean. For strings, numbers, and errors, we throw an exception.
* For blank cells we return a false.
*/
+ public boolean getBooleanCellValue() {
- public boolean getBooleanCellValue()
- {
- if (cellType == CELL_TYPE_BOOLEAN)
- {
- return (( BoolErrRecord ) record).getBooleanValue();
- }
- if (cellType == CELL_TYPE_BLANK)
- {
- return false;
+ switch(cellType) {
+ case CELL_TYPE_BLANK:
+ return false;
+ case CELL_TYPE_BOOLEAN:
+ return (( BoolErrRecord ) record).getBooleanValue();
+ default:
+ throw typeMismatch(CELL_TYPE_BOOLEAN, cellType, false);
+ case CELL_TYPE_FORMULA:
+ break;
}
- throw new NumberFormatException(
- "You cannot get a boolean value from a non-boolean cell");
+ FormulaRecord fr = ((FormulaRecordAggregate)record).getFormulaRecord();
+ checkFormulaCachedValueType(CELL_TYPE_BOOLEAN, fr);
+ return fr.getCachedBooleanValue();
}
/**
* get the value of the cell as an error code. For strings, numbers, and booleans, we throw an exception.
* For blank cells we return a 0.
*/
-
- public byte getErrorCellValue()
- {
- if (cellType == CELL_TYPE_ERROR)
- {
- return (( BoolErrRecord ) record).getErrorValue();
- }
- if (cellType == CELL_TYPE_BLANK)
- {
- return ( byte ) 0;
+ public byte getErrorCellValue() {
+ switch(cellType) {
+ case CELL_TYPE_ERROR:
+ return (( BoolErrRecord ) record).getErrorValue();
+ default:
+ throw typeMismatch(CELL_TYPE_ERROR, cellType, false);
+ case CELL_TYPE_FORMULA:
+ break;
}
- throw new NumberFormatException(
- "You cannot get an error value from a non-error cell");
+ FormulaRecord fr = ((FormulaRecordAggregate)record).getFormulaRecord();
+ checkFormulaCachedValueType(CELL_TYPE_ERROR, fr);
+ return (byte) fr.getCachedErrorValue();
}
/**
throw new RuntimeException("You cannot reference columns with an index of less then 0.");
}
}
-
+
/**
* Sets this cell as the active cell for the worksheet
*/
{
int row=record.getRow();
short col=record.getColumn();
- this.sheet.setActiveCellRow(row);
- this.sheet.setActiveCellCol(col);
+ this.sheet.getSheet().setActiveCellRow(row);
+ this.sheet.getSheet().setActiveCellCol(col);
}
-
+
/**
* Returns a string representation of the cell
- *
- * This method returns a simple representation,
+ *
+ * This method returns a simple representation,
* anthing more complex should be in user code, with
- * knowledge of the semantics of the sheet being processed.
- *
- * Formula cells return the formula string,
- * rather than the formula result.
+ * knowledge of the semantics of the sheet being processed.
+ *
+ * Formula cells return the formula string,
+ * rather than the formula result.
* Dates are displayed in dd-MMM-yyyy format
* Errors are displayed as #ERR<errIdx>
*/
public String toString() {
- switch (getCellType()) {
- case CELL_TYPE_BLANK:
- return "";
- case CELL_TYPE_BOOLEAN:
- return getBooleanCellValue()?"TRUE":"FALSE";
- case CELL_TYPE_ERROR:
- return ErrorEval.getText((( BoolErrRecord ) record).getErrorValue());
- case CELL_TYPE_FORMULA:
- return getCellFormula();
- case CELL_TYPE_NUMERIC:
- //TODO apply the dataformat for this cell
- if (HSSFDateUtil.isCellDateFormatted(this)) {
- DateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy");
- return sdf.format(getDateCellValue());
- } else {
- return getNumericCellValue() + "";
- }
- case CELL_TYPE_STRING:
- return getStringCellValue();
- default:
- return "Unknown Cell Type: " + getCellType();
- }
+ switch (getCellType()) {
+ case CELL_TYPE_BLANK:
+ return "";
+ case CELL_TYPE_BOOLEAN:
+ return getBooleanCellValue()?"TRUE":"FALSE";
+ case CELL_TYPE_ERROR:
+ return ErrorEval.getText((( BoolErrRecord ) record).getErrorValue());
+ case CELL_TYPE_FORMULA:
+ return getCellFormula();
+ case CELL_TYPE_NUMERIC:
+ //TODO apply the dataformat for this cell
+ if (HSSFDateUtil.isCellDateFormatted(this)) {
+ DateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy");
+ return sdf.format(getDateCellValue());
+ } else {
+ return getNumericCellValue() + "";
+ }
+ case CELL_TYPE_STRING:
+ return getStringCellValue();
+ default:
+ return "Unknown Cell Type: " + getCellType();
+ }
}
/**
* @param comment comment associated with this cell
*/
public void setCellComment(Comment comment){
- if(comment == null) {
- removeCellComment();
- return;
- }
-
- this.comment = (HSSFComment) comment;
- this.comment.setRow((short)record.getRow());
- this.comment.setColumn(record.getColumn());
+ if(comment == null) {
+ removeCellComment();
+ return;
+ }
+
+ comment.setRow((short)record.getRow());
+ comment.setColumn(record.getColumn());
+ this.comment = (HSSFComment)comment;
}
/**
*/
public HSSFComment getCellComment(){
if (comment == null) {
- comment = findCellComment(sheet, record.getRow(), record.getColumn());
+ comment = findCellComment(sheet.getSheet(), record.getRow(), record.getColumn());
}
return comment;
}
-
+
/**
* Removes the comment for this cell, if
* there is one.
* all comments after performing this action!
*/
public void removeCellComment() {
- HSSFComment comment = findCellComment(sheet, record.getRow(), record.getColumn());
- this.comment = null;
-
- if(comment == null) {
- // Nothing to do
- return;
- }
-
- // Zap the underlying NoteRecord
- sheet.getRecords().remove(comment.getNoteRecord());
-
- // If we have a TextObjectRecord, is should
- // be proceeed by:
- // MSODRAWING with container
- // OBJ
- // MSODRAWING with EscherTextboxRecord
- if(comment.getTextObjectRecord() != null) {
- TextObjectRecord txo = comment.getTextObjectRecord();
- int txoAt = sheet.getRecords().indexOf(txo);
-
- if(sheet.getRecords().get(txoAt-3) instanceof DrawingRecord &&
- sheet.getRecords().get(txoAt-2) instanceof ObjRecord &&
- sheet.getRecords().get(txoAt-1) instanceof DrawingRecord) {
- // Zap these, in reverse order
- sheet.getRecords().remove(txoAt-1);
- sheet.getRecords().remove(txoAt-2);
- sheet.getRecords().remove(txoAt-3);
- } else {
- throw new IllegalStateException("Found the wrong records before the TextObjectRecord, can't remove comment");
- }
-
- // Now remove the text record
- sheet.getRecords().remove(txo);
- }
+ HSSFComment comment = findCellComment(sheet.getSheet(), record.getRow(), record.getColumn());
+ this.comment = null;
+
+ if(comment == null) {
+ // Nothing to do
+ return;
+ }
+
+ // Zap the underlying NoteRecord
+ List sheetRecords = sheet.getSheet().getRecords();
+ sheetRecords.remove(comment.getNoteRecord());
+
+ // If we have a TextObjectRecord, is should
+ // be proceeed by:
+ // MSODRAWING with container
+ // OBJ
+ // MSODRAWING with EscherTextboxRecord
+ if(comment.getTextObjectRecord() != null) {
+ TextObjectRecord txo = comment.getTextObjectRecord();
+ int txoAt = sheetRecords.indexOf(txo);
+
+ if(sheetRecords.get(txoAt-3) instanceof DrawingRecord &&
+ sheetRecords.get(txoAt-2) instanceof ObjRecord &&
+ sheetRecords.get(txoAt-1) instanceof DrawingRecord) {
+ // Zap these, in reverse order
+ sheetRecords.remove(txoAt-1);
+ sheetRecords.remove(txoAt-2);
+ sheetRecords.remove(txoAt-3);
+ } else {
+ throw new IllegalStateException("Found the wrong records before the TextObjectRecord, can't remove comment");
+ }
+
+ // Now remove the text record
+ sheetRecords.remove(txo);
+ }
}
/**
* @return hyperlink associated with this cell or null if not found
*/
public HSSFHyperlink getHyperlink(){
- for (Iterator it = sheet.getRecords().iterator(); it.hasNext(); ) {
+ for (Iterator it = sheet.getSheet().getRecords().iterator(); it.hasNext(); ) {
RecordBase rec = (RecordBase) it.next();
if (rec instanceof HyperlinkRecord){
HyperlinkRecord link = (HyperlinkRecord)rec;
break;
}
- int eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid );
- sheet.getRecords().add( eofLoc, link.record );
+ int eofLoc = sheet.getSheet().findFirstRecordLocBySid( EOFRecord.sid );
+ sheet.getSheet().getRecords().add( eofLoc, link.record );
+ }
+ /**
+ * Only valid for formula cells
+ * @return one of ({@link #CELL_TYPE_NUMERIC}, {@link #CELL_TYPE_STRING},
+ * {@link #CELL_TYPE_BOOLEAN}, {@link #CELL_TYPE_ERROR}) depending
+ * on the cached value of the formula
+ */
+ public int getCachedFormulaResultType() {
+ if (this.cellType != CELL_TYPE_FORMULA) {
+ throw new IllegalStateException("Only formula cells have cached results");
+ }
+ return ((FormulaRecordAggregate)record).getFormulaRecord().getCachedResultType();
}
}
public HSSFFormulaEvaluator(HSSFSheet sheet, HSSFWorkbook workbook) {
super(sheet, workbook);
}
+ public HSSFFormulaEvaluator(HSSFWorkbook workbook) {
+ super(workbook);
+ }
/**
* Returns an underlying FormulaParser, for the specified
import java.util.Iterator;
import java.util.NoSuchElementException;
-import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.record.CellValueRecordInterface;
import org.apache.poi.hssf.record.RowRecord;
import org.apache.poi.ss.usermodel.Cell;
/**
* reference to containing Sheet
*/
- private Sheet sheet;
+ private HSSFSheet sheet;
/**
* Creates new HSSFRow from scratch. Only HSSFSheet should do this.
* @param rowNum the row number of this row (0 based)
* @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(int)
*/
- HSSFRow(HSSFWorkbook book, Sheet sheet, int rowNum)
+ HSSFRow(HSSFWorkbook book, HSSFSheet sheet, int rowNum)
{
this.rowNum = rowNum;
this.book = book;
* @param record the low level api object this row should represent
* @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(int)
*/
- HSSFRow(HSSFWorkbook book, Sheet sheet, RowRecord record)
+ HSSFRow(HSSFWorkbook book, HSSFSheet sheet, RowRecord record)
{
this.book = book;
this.sheet = sheet;
HSSFCell cell = new HSSFCell(book, sheet, getRowNum(), shortCellNum, type);
addCell(cell);
- sheet.addValueRecord(getRowNum(), cell.getCellValueRecord());
+ sheet.getSheet().addValueRecord(getRowNum(), cell.getCellValueRecord());
return cell;
}
if(alsoRemoveRecords) {
CellValueRecordInterface cval = cell.getCellValueRecord();
- sheet.removeValueRecord(getRowNum(), cval);
+ sheet.getSheet().removeValueRecord(getRowNum(), cval);
}
if (cell.getCellNum()+1 == row.getLastCol()) {
//The low-order 15 bits contain the row height.
//The 0x8000 bit indicates that the row is standard height (optional)
- if ((height & 0x8000) != 0) height = sheet.getDefaultRowHeight();
+ if ((height & 0x8000) != 0) height = sheet.getSheet().getDefaultRowHeight();
else height &= 0x7FFF;
return height;
*/
public HSSFRow createRow(int rownum)
{
- HSSFRow row = new HSSFRow(workbook, sheet, rownum);
+ HSSFRow row = new HSSFRow(workbook, this, rownum);
addRow(row, true);
return row;
private HSSFRow createRowFromRecord(RowRecord row)
{
- HSSFRow hrow = new HSSFRow(workbook, sheet, row);
+ HSSFRow hrow = new HSSFRow(workbook, this, row);
addRow(hrow, false);
return hrow;
for(int index=0; index<records.size(); index++) {
if(records.get(index) instanceof DVRecord) {
- dvRecords.add(records.get(index));
+ dvRecords.add(records.get(index));
}
}
return dvRecords;
// If any references were changed, then
// re-create the formula string
if(changed) {
- c.setCellFormula(
- FormulaParser.toFormulaString(workbook, ptgs)
- );
+ c.setFormulaOnly(ptgs);
}
}
}
return patriarch;
}
+ /**
+ * @deprecated (Sep 2008) use {@link #setColumnGroupCollapsed(int, boolean)}
+ */
+ public void setColumnGroupCollapsed(short columnNumber, boolean collapsed) {
+ setColumnGroupCollapsed(columnNumber & 0xFFFF, collapsed);
+ }
+ /**
+ * @deprecated (Sep 2008) use {@link #groupColumn(int, int)}
+ */
+ public void groupColumn(short fromColumn, short toColumn) {
+ groupColumn(fromColumn & 0xFFFF, toColumn & 0xFFFF);
+ }
+ /**
+ * @deprecated (Sep 2008) use {@link #ungroupColumn(int, int)}
+ */
+ public void ungroupColumn(short fromColumn, short toColumn) {
+ ungroupColumn(fromColumn & 0xFFFF, toColumn & 0xFFFF);
+ }
+
/**
* Expands or collapses a column group.
*
* @param columnNumber One of the columns in the group.
* @param collapsed true = collapse group, false = expand group.
*/
- public void setColumnGroupCollapsed( short columnNumber, boolean collapsed )
- {
- sheet.setColumnGroupCollapsed( columnNumber, collapsed );
+ public void setColumnGroupCollapsed(int columnNumber, boolean collapsed) {
+ sheet.setColumnGroupCollapsed(columnNumber, collapsed);
}
/**
* @param fromColumn beginning of the column range.
* @param toColumn end of the column range.
*/
- public void groupColumn(short fromColumn, short toColumn)
- {
- sheet.groupColumnRange( fromColumn, toColumn, true );
+ public void groupColumn(int fromColumn, int toColumn) {
+ sheet.groupColumnRange(fromColumn, toColumn, true);
}
- public void ungroupColumn( short fromColumn, short toColumn )
- {
- sheet.groupColumnRange( fromColumn, toColumn, false );
+ public void ungroupColumn(int fromColumn, int toColumn) {
+ sheet.groupColumnRange(fromColumn, toColumn, false);
}
public void groupRow(int fromRow, int toRow)
return -1;
}
+ /* package */ int findSheetIndex(Sheet sheet) {
+ for(int i=0; i<_sheets.size(); i++) {
+ HSSFSheet hSheet = (HSSFSheet) _sheets.get(i);
+ if(hSheet.getSheet() == sheet) {
+ return i;
+ }
+ }
+ throw new IllegalArgumentException("Specified sheet not found in this workbook");
+ }
+
/**
* Returns the external sheet index of the sheet
* with the given internal index, creating one
--- /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.hssf.usermodel;
+import org.apache.poi.hssf.record.formula.AreaI;
+
+/**
+ *
+ * @author Josh Micich
+ */
+final class LazyAreaEval extends org.apache.poi.ss.usermodel.LazyAreaEval {
+ public LazyAreaEval(AreaI ptg, HSSFSheet sheet, HSSFFormulaEvaluator evaluator) {
+ super(ptg, sheet, evaluator);
+ }
+}
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hssf.usermodel;\r
+import org.apache.poi.hssf.record.formula.Ref3DPtg;\r
+import org.apache.poi.hssf.record.formula.RefPtg;\r
+\r
+/**\r
+*\r
+* @author Josh Micich \r
+*/\r
+final class LazyRefEval extends org.apache.poi.ss.usermodel.LazyRefEval {\r
+ public LazyRefEval(RefPtg ptg, HSSFSheet sheet, HSSFFormulaEvaluator evaluator) {\r
+ super(ptg, sheet, evaluator);\r
+ }\r
+ public LazyRefEval(Ref3DPtg ptg, HSSFSheet sheet, HSSFFormulaEvaluator evaluator) {\r
+ super(ptg, sheet, evaluator);\r
+ }\r
+}\r
import java.util.ArrayList;
import java.util.List;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-
/**
* Instances of this class keep track of multiple dependent cell evaluations due
- * to recursive calls to <tt>HSSFFormulaEvaluator.internalEvaluate()</tt>.
+ * to recursive calls to <tt>FormulaEvaluator.internalEvaluate()</tt>.
* The main purpose of this class is to detect an attempt to evaluate a cell
* that is already being evaluated. In other words, it detects circular
* references in spreadsheet formulas.
private static final class CellEvaluationFrame {
private final Workbook _workbook;
- private final Sheet _sheet;
+ private final int _sheetIndex;
private final int _srcRowNum;
private final int _srcColNum;
- public CellEvaluationFrame(Workbook workbook, Sheet sheet, int srcRowNum, int srcColNum) {
+ public CellEvaluationFrame(Workbook workbook, int sheetIndex, int srcRowNum, int srcColNum) {
if (workbook == null) {
throw new IllegalArgumentException("workbook must not be null");
}
- if (sheet == null) {
- throw new IllegalArgumentException("sheet must not be null");
+ if (sheetIndex < 0) {
+ throw new IllegalArgumentException("sheetIndex must not be negative");
}
_workbook = workbook;
- _sheet = sheet;
+ _sheetIndex = sheetIndex;
_srcRowNum = srcRowNum;
_srcColNum = srcColNum;
}
if (_workbook != other._workbook) {
return false;
}
- if (_sheet != other._sheet) {
+ if (_sheetIndex != other._sheetIndex) {
return false;
}
if (_srcRowNum != other._srcRowNum) {
* @return human readable string for debug purposes
*/
public String formatAsString() {
- return "R=" + _srcRowNum + " C=" + _srcColNum + " ShIx=" + _workbook.getSheetIndex(_sheet);
+ return "R=" + _srcRowNum + " C=" + _srcColNum + " ShIx=" + _sheetIndex;
}
public String toString() {
* @return <code>true</code> if the specified cell has not been visited yet in the current
* evaluation. <code>false</code> if the specified cell is already being evaluated.
*/
- public boolean startEvaluate(Workbook workbook, Sheet sheet, int srcRowNum, int srcColNum) {
- CellEvaluationFrame cef = new CellEvaluationFrame(workbook, sheet, srcRowNum, srcColNum);
+ public boolean startEvaluate(Workbook workbook, int sheetIndex, int srcRowNum, int srcColNum) {
+ CellEvaluationFrame cef = new CellEvaluationFrame(workbook, sheetIndex, srcRowNum, srcColNum);
if (_evaluationFrames.contains(cef)) {
return false;
}
* required. However, they have been included to assert correct behaviour,
* and form more meaningful error messages.
*/
- public void endEvaluate(Workbook workbook, Sheet sheet, int srcRowNum, int srcColNum) {
+ public void endEvaluate(Workbook workbook, int sheetIndex, int srcRowNum, int srcColNum) {
int nFrames = _evaluationFrames.size();
if (nFrames < 1) {
throw new IllegalStateException("Call to endEvaluate without matching call to startEvaluate");
nFrames--;
CellEvaluationFrame cefExpected = (CellEvaluationFrame) _evaluationFrames.get(nFrames);
- CellEvaluationFrame cefActual = new CellEvaluationFrame(workbook, sheet, srcRowNum, srcColNum);
+ CellEvaluationFrame cefActual = new CellEvaluationFrame(workbook, sheetIndex, srcRowNum, srcColNum);
if (!cefActual.equals(cefExpected)) {
throw new RuntimeException("Wrong cell specified. "
+ "Corresponding startEvaluate() call was for cell {"
import java.util.Iterator;
import java.util.Stack;
-import org.apache.poi.ss.util.AreaReference;
-import org.apache.poi.ss.util.CellReference;
-
import org.apache.poi.hssf.model.FormulaParser;
import org.apache.poi.hssf.record.NameRecord;
import org.apache.poi.hssf.record.formula.Area3DPtg;
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.FunctionEval;
-import org.apache.poi.hssf.record.formula.eval.LazyAreaEval;
-import org.apache.poi.hssf.record.formula.eval.LazyRefEval;
import org.apache.poi.hssf.record.formula.eval.NameEval;
import org.apache.poi.hssf.record.formula.eval.NameXEval;
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;
+import org.apache.poi.hssf.util.CellReference;
/**
* Evaluates formula cells.<p/>
* @author Josh Micich
*/
public class FormulaEvaluator {
- /**
- * used to track the number of evaluations
- */
+
+ /**
+ * used to track the number of evaluations
+ */
private static final class Counter {
public int value;
+ public int depth;
public Counter() {
value = 0;
}
}
- protected Sheet _sheet;
- protected Workbook _workbook;
+ protected final Workbook _workbook;
private final EvaluationCache _cache;
private Counter _evaluationCounter;
-
+ /**
+ * @deprecated (Sep 2008) Sheet parameter is ignored
+ */
public FormulaEvaluator(Sheet sheet, Workbook workbook) {
- this(sheet, workbook, new EvaluationCache(), new Counter());
+ this(workbook);
+ if (false) {
+ sheet.toString(); // suppress unused parameter compiler warning
+ }
+ }
+ public FormulaEvaluator(Workbook workbook) {
+ this(workbook, new EvaluationCache(), new Counter());
}
-
- private FormulaEvaluator(Sheet sheet, Workbook workbook, EvaluationCache cache, Counter evaluationCounter) {
- _sheet = sheet;
+
+ private FormulaEvaluator(Workbook workbook, EvaluationCache cache, Counter evaluationCounter) {
_workbook = workbook;
_cache = cache;
_evaluationCounter = evaluationCounter;
_cache.clear();
}
-
/**
* If cell contains a formula, the formula is evaluated and returned,
* else the CellValue simply copies the appropriate cell value from
* @param cell
*/
public CellValue evaluate(Cell cell) {
- CellValue retval = null;
- if (cell != null) {
- switch (cell.getCellType()) {
- case Cell.CELL_TYPE_BLANK:
- retval = new CellValue(Cell.CELL_TYPE_BLANK, _workbook.getCreationHelper());
- break;
+ if (cell == null) {
+ return null;
+ }
+
+ switch (cell.getCellType()) {
case Cell.CELL_TYPE_BOOLEAN:
- retval = new CellValue(Cell.CELL_TYPE_BOOLEAN, _workbook.getCreationHelper());
- retval.setBooleanValue(cell.getBooleanCellValue());
- break;
+ return CellValue.valueOf(cell.getBooleanCellValue());
case Cell.CELL_TYPE_ERROR:
- retval = new CellValue(Cell.CELL_TYPE_ERROR, _workbook.getCreationHelper());
- retval.setErrorValue(cell.getErrorCellValue());
- break;
+ return CellValue.getError(cell.getErrorCellValue());
case Cell.CELL_TYPE_FORMULA:
- retval = getCellValueForEval(internalEvaluate(cell, _sheet), _workbook.getCreationHelper());
- break;
+ return evaluateFormulaCellValue(cell);
case Cell.CELL_TYPE_NUMERIC:
- retval = new CellValue(Cell.CELL_TYPE_NUMERIC, _workbook.getCreationHelper());
- retval.setNumberValue(cell.getNumericCellValue());
- break;
+ return new CellValue(cell.getNumericCellValue(), _workbook.getCreationHelper());
case Cell.CELL_TYPE_STRING:
- retval = new CellValue(Cell.CELL_TYPE_STRING, _workbook.getCreationHelper());
- retval.setRichTextStringValue(cell.getRichStringCellValue());
- break;
- }
+ return new CellValue(cell.getRichStringCellValue().getString(), _workbook.getCreationHelper());
}
- return retval;
+ throw new IllegalStateException("Bad cell type (" + cell.getCellType() + ")");
}
* @return The type of the formula result (the cell's type remains as Cell.CELL_TYPE_FORMULA however)
*/
public int evaluateFormulaCell(Cell cell) {
- if (cell != null) {
- switch (cell.getCellType()) {
- case Cell.CELL_TYPE_FORMULA:
- CellValue cv = getCellValueForEval(internalEvaluate(cell, _sheet), _workbook.getCreationHelper());
- switch (cv.getCellType()) {
- case Cell.CELL_TYPE_BOOLEAN:
- cell.setCellValue(cv.getBooleanValue());
- break;
- case Cell.CELL_TYPE_ERROR:
- cell.setCellValue(cv.getErrorValue());
- break;
- case Cell.CELL_TYPE_NUMERIC:
- cell.setCellValue(cv.getNumberValue());
- break;
- case Cell.CELL_TYPE_STRING:
- cell.setCellValue(cv.getRichTextStringValue());
- break;
- case Cell.CELL_TYPE_BLANK:
- break;
- case Cell.CELL_TYPE_FORMULA: // this will never happen, we have already evaluated the formula
- break;
- }
- return cv.getCellType();
- }
+ if (cell == null || cell.getCellType() != Cell.CELL_TYPE_FORMULA) {
+ return -1;
}
- return -1;
+ CellValue cv = evaluateFormulaCellValue(cell);
+ // cell remains a formula cell, but the cached value is changed
+ setCellValue(cell, cv);
+ return cv.getCellType();
}
/**
* @param cell
*/
public Cell evaluateInCell(Cell cell) {
- if (cell != null) {
- switch (cell.getCellType()) {
- case Cell.CELL_TYPE_FORMULA:
- CellValue cv = getCellValueForEval(internalEvaluate(cell, _sheet), _workbook.getCreationHelper());
- switch (cv.getCellType()) {
- case Cell.CELL_TYPE_BOOLEAN:
- cell.setCellType(Cell.CELL_TYPE_BOOLEAN);
- cell.setCellValue(cv.getBooleanValue());
- break;
- case Cell.CELL_TYPE_ERROR:
- cell.setCellErrorValue(cv.getErrorValue());
- break;
- case Cell.CELL_TYPE_NUMERIC:
- cell.setCellType(Cell.CELL_TYPE_NUMERIC);
- cell.setCellValue(cv.getNumberValue());
- break;
- case Cell.CELL_TYPE_STRING:
- cell.setCellType(Cell.CELL_TYPE_STRING);
- cell.setCellValue(cv.getRichTextStringValue());
- break;
- case Cell.CELL_TYPE_BLANK:
- break;
- case Cell.CELL_TYPE_FORMULA: // this will never happen, we have already evaluated the formula
- break;
- }
- }
+ if (cell == null) {
+ return null;
+ }
+ if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
+ CellValue cv = evaluateFormulaCellValue(cell);
+ setCellType(cell, cv); // cell will no longer be a formula cell
+ setCellValue(cell, cv);
}
return cell;
}
+ private static void setCellType(Cell cell, CellValue cv) {
+ int cellType = cv.getCellType();
+ switch (cellType) {
+ case Cell.CELL_TYPE_BOOLEAN:
+ case Cell.CELL_TYPE_ERROR:
+ case Cell.CELL_TYPE_NUMERIC:
+ case Cell.CELL_TYPE_STRING:
+ cell.setCellType(cellType);
+ return;
+ case Cell.CELL_TYPE_BLANK:
+ // never happens - blanks eventually get translated to zero
+ case Cell.CELL_TYPE_FORMULA:
+ // this will never happen, we have already evaluated the formula
+ }
+ throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
+ }
+
+ private static void setCellValue(Cell cell, CellValue cv) {
+ int cellType = cv.getCellType();
+ switch (cellType) {
+ case Cell.CELL_TYPE_BOOLEAN:
+ cell.setCellValue(cv.getBooleanValue());
+ break;
+ case Cell.CELL_TYPE_ERROR:
+ cell.setCellErrorValue(cv.getErrorValue());
+ break;
+ case Cell.CELL_TYPE_NUMERIC:
+ cell.setCellValue(cv.getNumberValue());
+ break;
+ case Cell.CELL_TYPE_STRING:
+ cell.setCellValue(cv.getRichTextStringValue());
+ break;
+ case Cell.CELL_TYPE_BLANK:
+ // never happens - blanks eventually get translated to zero
+ case Cell.CELL_TYPE_FORMULA:
+ // this will never happen, we have already evaluated the formula
+ default:
+ throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
+ }
+ }
/**
* Loops over all cells in all sheets of the supplied
* cells, and calling evaluateFormulaCell on each one.
*/
public static void evaluateAllFormulaCells(Workbook wb) {
+ FormulaEvaluator evaluator = new FormulaEvaluator(wb);
for(int i=0; i<wb.getNumberOfSheets(); i++) {
Sheet sheet = wb.getSheetAt(i);
- FormulaEvaluator evaluator = new FormulaEvaluator(sheet, wb);
for (Iterator rit = sheet.rowIterator(); rit.hasNext();) {
Row r = (Row)rit.next();
}
}
-
/**
* Returns a CellValue wrapper around the supplied ValueEval instance.
* @param eval
*/
- private static CellValue getCellValueForEval(ValueEval eval, CreationHelper cHelper) {
- CellValue retval = null;
- if (eval != null) {
- if (eval instanceof NumberEval) {
- NumberEval ne = (NumberEval) eval;
- retval = new CellValue(Cell.CELL_TYPE_NUMERIC, cHelper);
- retval.setNumberValue(ne.getNumberValue());
- }
- else if (eval instanceof BoolEval) {
- BoolEval be = (BoolEval) eval;
- retval = new CellValue(Cell.CELL_TYPE_BOOLEAN, cHelper);
- retval.setBooleanValue(be.getBooleanValue());
- }
- else if (eval instanceof StringEval) {
- StringEval ne = (StringEval) eval;
- retval = new CellValue(Cell.CELL_TYPE_STRING, cHelper);
- retval.setStringValue(ne.getStringValue());
- }
- else if (eval instanceof BlankEval) {
- retval = new CellValue(Cell.CELL_TYPE_BLANK, cHelper);
- }
- else if (eval instanceof ErrorEval) {
- retval = new CellValue(Cell.CELL_TYPE_ERROR, cHelper);
- retval.setErrorValue((byte)((ErrorEval)eval).getErrorCode());
-// retval.setRichTextStringValue(new RichTextString("#An error occurred. check cell.getErrorCode()"));
- }
- else {
- retval = new CellValue(Cell.CELL_TYPE_ERROR, cHelper);
- }
+ private CellValue evaluateFormulaCellValue(Cell cell) {
+ ValueEval eval = internalEvaluate(cell);
+ if (eval instanceof NumberEval) {
+ NumberEval ne = (NumberEval) eval;
+ return new CellValue(ne.getNumberValue(), _workbook.getCreationHelper());
+ }
+ if (eval instanceof BoolEval) {
+ BoolEval be = (BoolEval) eval;
+ return CellValue.valueOf(be.getBooleanValue());
}
- return retval;
+ if (eval instanceof StringEval) {
+ StringEval ne = (StringEval) eval;
+ return new CellValue(ne.getStringValue(), _workbook.getCreationHelper());
+ }
+ if (eval instanceof ErrorEval) {
+ return CellValue.getError(((ErrorEval)eval).getErrorCode());
+ }
+ throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
}
/**
* Dev. Note: Internal evaluate must be passed only a formula cell
* else a runtime exception will be thrown somewhere inside the method.
* (Hence this is a private method.)
+ * @return never <code>null</code>, never {@link BlankEval}
*/
- private ValueEval internalEvaluate(Cell srcCell, Sheet sheet) {
+ private ValueEval internalEvaluate(Cell srcCell) {
int srcRowNum = srcCell.getRowIndex();
int srcColNum = srcCell.getCellNum();
ValueEval result;
- int sheetIndex = _workbook.getSheetIndex(sheet);
+ int sheetIndex = _workbook.getSheetIndex(srcCell.getSheet());
result = _cache.getValue(sheetIndex, srcRowNum, srcColNum);
if (result != null) {
- return result;
+ return result;
}
_evaluationCounter.value++;
+ _evaluationCounter.depth++;
EvaluationCycleDetector tracker = EvaluationCycleDetectorManager.getTracker();
- if(!tracker.startEvaluate(_workbook, sheet, srcRowNum, srcColNum)) {
+ if(!tracker.startEvaluate(_workbook, sheetIndex, srcRowNum, srcColNum)) {
return ErrorEval.CIRCULAR_REF_ERROR;
}
try {
- result = evaluateCell(srcRowNum, (short)srcColNum, srcCell.getCellFormula());
+ result = evaluateCell(sheetIndex, srcRowNum, (short)srcColNum, srcCell.getCellFormula());
} finally {
- tracker.endEvaluate(_workbook, sheet, srcRowNum, srcColNum);
+ tracker.endEvaluate(_workbook, sheetIndex, srcRowNum, srcColNum);
_cache.setValue(sheetIndex, srcRowNum, srcColNum, result);
+ _evaluationCounter.depth--;
}
if (isDebugLogEnabled()) {
String sheetName = _workbook.getSheetName(sheetIndex);
}
return result;
}
- private ValueEval evaluateCell(int srcRowNum, short srcColNum, String cellFormulaText) {
+ private ValueEval evaluateCell(int sheetIndex, int srcRowNum, short srcColNum, String cellFormulaText) {
Ptg[] ptgs = FormulaParser.parse(cellFormulaText, _workbook);
}
if (ptg instanceof MemErrPtg) { continue; }
if (ptg instanceof MissingArgPtg) {
- // TODO - might need to push BlankEval or MissingArgEval
- continue;
+ // TODO - might need to push BlankEval or MissingArgEval
+ continue;
}
Eval opResult;
if (ptg instanceof OperationPtg) {
Eval p = (Eval) stack.pop();
ops[j] = p;
}
- logDebug("invoke " + operation + " (nAgs=" + numops + ")");
- opResult = invokeOperation(operation, ops, srcRowNum, srcColNum, _workbook, _sheet);
+// logDebug("invoke " + operation + " (nAgs=" + numops + ")");
+ opResult = invokeOperation(operation, ops, _workbook, sheetIndex, srcRowNum, srcColNum);
} else {
- opResult = getEvalForPtg(ptg, _sheet);
+ opResult = getEvalForPtg(ptg, sheetIndex);
}
if (opResult == null) {
throw new RuntimeException("Evaluation result must not be null");
}
- logDebug("push " + opResult);
+// logDebug("push " + opResult);
stack.push(opResult);
}
throw new IllegalStateException("evaluation stack not empty");
}
value = dereferenceValue(value, srcRowNum, srcColNum);
- if (value instanceof BlankEval) {
+ if (value == BlankEval.INSTANCE) {
// Note Excel behaviour here. A blank final final value is converted to zero.
return NumberEval.ZERO;
// Formulas _never_ evaluate to blank. If a formula appears to have evaluated to
return evaluationResult;
}
- private static Eval invokeOperation(OperationEval operation, Eval[] ops, int srcRowNum, short srcColNum,
- Workbook workbook, Sheet sheet) {
+ private static Eval invokeOperation(OperationEval operation, Eval[] ops,
+ Workbook workbook, int sheetIndex, int srcRowNum, int srcColNum) {
if(operation instanceof FunctionEval) {
FunctionEval fe = (FunctionEval) operation;
if(fe.isFreeRefFunction()) {
- return fe.getFreeRefFunction().evaluate(ops, srcRowNum, srcColNum, workbook, sheet);
+ return fe.getFreeRefFunction().evaluate(ops, workbook, sheetIndex, srcRowNum, srcColNum);
}
}
- return operation.evaluate(ops, srcRowNum, srcColNum);
+ return operation.evaluate(ops, srcRowNum, (short)srcColNum);
}
private Sheet getOtherSheet(int externSheetIndex) {
return _workbook.getSheetAt(_workbook.getSheetIndexFromExternSheetIndex(externSheetIndex));
}
- private FormulaEvaluator createEvaluatorForAnotherSheet(Sheet sheet) {
- return new FormulaEvaluator(sheet, _workbook, _cache, _evaluationCounter);
- }
/**
* returns an appropriate Eval impl instance for the Ptg. The Ptg must be
* StringPtg, BoolPtg <br/>special Note: OperationPtg subtypes cannot be
* passed here!
*/
- private Eval getEvalForPtg(Ptg ptg, Sheet sheet) {
+ private Eval getEvalForPtg(Ptg ptg, int sheetIndex) {
if (ptg instanceof NamePtg) {
// named ranges, macro functions
NamePtg namePtg = (NamePtg) ptg;
throw new RuntimeException("Bad name index (" + nameIndex
+ "). Allowed range is (0.." + (numberOfNames-1) + ")");
}
- if(_workbook instanceof org.apache.poi.hssf.usermodel.HSSFWorkbook) {
- org.apache.poi.hssf.usermodel.HSSFWorkbook hssfWb =
- (org.apache.poi.hssf.usermodel.HSSFWorkbook)_workbook;
- NameRecord nameRecord = hssfWb.getNameRecord(nameIndex);
+ if(_workbook instanceof org.apache.poi.hssf.usermodel.HSSFWorkbook) {
+ NameRecord nameRecord = ((org.apache.poi.hssf.usermodel.HSSFWorkbook)_workbook).getNameRecord(nameIndex);
if (nameRecord.isFunctionName()) {
return new NameEval(nameRecord.getNameText());
}
if (nameRecord.hasFormula()) {
- return evaluateNameFormula(nameRecord.getNameDefinition(), sheet);
+ return evaluateNameFormula(nameRecord.getNameDefinition(), sheetIndex);
}
- throw new RuntimeException("Don't know how to evalate name '" + nameRecord.getNameText() + "'");
- } else {
- throw new RuntimeException("Don't know how to evaluate name records for XSSF");
+
+ throw new RuntimeException("Don't now how to evalate name '" + nameRecord.getNameText() + "'");
}
+ throw new RuntimeException("Don't now how to evalate name for XSSFWorkbook");
}
if (ptg instanceof NameXPtg) {
NameXPtg nameXPtg = (NameXPtg) ptg;
return new NameXEval(nameXPtg.getSheetRefIndex(), nameXPtg.getNameIndex());
}
- if (ptg instanceof RefPtg) {
- return new LazyRefEval(((RefPtg) ptg), sheet, this);
- }
- if (ptg instanceof Ref3DPtg) {
- Ref3DPtg refPtg = (Ref3DPtg) ptg;
- Sheet xsheet = getOtherSheet(refPtg.getExternSheetIndex());
- return new LazyRefEval(refPtg, xsheet, createEvaluatorForAnotherSheet(xsheet));
- }
- if (ptg instanceof AreaPtg) {
- return new LazyAreaEval(((AreaPtg) ptg), sheet, this);
- }
- if (ptg instanceof Area3DPtg) {
- Area3DPtg a3dp = (Area3DPtg) ptg;
- Sheet xsheet = getOtherSheet(a3dp.getExternSheetIndex());
- return new LazyAreaEval(a3dp, xsheet, createEvaluatorForAnotherSheet(xsheet));
- }
if (ptg instanceof IntPtg) {
return new NumberEval(((IntPtg)ptg).getValue());
if (ptg instanceof ErrPtg) {
return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
}
+ Sheet sheet = _workbook.getSheetAt(sheetIndex);
+ if (ptg instanceof RefPtg) {
+ return new LazyRefEval(((RefPtg) ptg), sheet, this);
+ }
+ if (ptg instanceof AreaPtg) {
+ return new LazyAreaEval(((AreaPtg) ptg), sheet, this);
+ }
+ if (ptg instanceof Ref3DPtg) {
+ Ref3DPtg refPtg = (Ref3DPtg) ptg;
+ Sheet xsheet = getOtherSheet(refPtg.getExternSheetIndex());
+ return new LazyRefEval(refPtg, xsheet, this);
+ }
+ if (ptg instanceof Area3DPtg) {
+ Area3DPtg a3dp = (Area3DPtg) ptg;
+ Sheet xsheet = getOtherSheet(a3dp.getExternSheetIndex());
+ return new LazyAreaEval(a3dp, xsheet, this);
+ }
+
if (ptg instanceof UnknownPtg) {
- // TODO - remove UnknownPtg
+ // POI uses UnknownPtg when the encoded Ptg array seems to be corrupted.
+ // This seems to occur in very rare cases (e.g. unused name formulas in bug 44774, attachment 21790)
+ // In any case, formulas are re-parsed before execution, so UnknownPtg should not get here
throw new RuntimeException("UnknownPtg not allowed");
}
+
throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")");
}
- private Eval evaluateNameFormula(Ptg[] ptgs, Sheet sheet) {
+ private Eval evaluateNameFormula(Ptg[] ptgs, int sheetIndex) {
if (ptgs.length > 1) {
throw new RuntimeException("Complex name formulas not supported yet");
}
- return getEvalForPtg(ptgs[0], sheet);
+ return getEvalForPtg(ptgs[0], sheetIndex);
}
/**
* impl instance and return that. Since the cell could be an external
* reference, we need the sheet that this belongs to.
* Non existent cells are treated as empty.
- * @param cell
- * @param sheet
- * @param workbook
*/
- public ValueEval getEvalForCell(Cell cell, Sheet sheet) {
+ public ValueEval getEvalForCell(Cell cell) {
if (cell == null) {
return BlankEval.INSTANCE;
case Cell.CELL_TYPE_STRING:
return new StringEval(cell.getRichStringCellValue().getString());
case Cell.CELL_TYPE_FORMULA:
- return internalEvaluate(cell, sheet);
+ return internalEvaluate(cell);
case Cell.CELL_TYPE_BOOLEAN:
return BoolEval.valueOf(cell.getBooleanCellValue());
case Cell.CELL_TYPE_BLANK:
* or Number or boolean type.
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*/
- public static class CellValue {
- private CreationHelper creationHelper;
- private int cellType;
- private RichTextString richTextStringValue;
- private double numberValue;
- private boolean booleanValue;
- private byte errorValue;
-
- /**
- * CellType should be one of the types defined in Cell
- * @param cellType
- */
- public CellValue(int cellType, CreationHelper creationHelper) {
- super();
- this.creationHelper = creationHelper;
- this.cellType = cellType;
- }
+ public static final class CellValue {
+ public static final CellValue TRUE = new CellValue(Cell.CELL_TYPE_BOOLEAN, 0.0, true, null, 0, null);
+ public static final CellValue FALSE= new CellValue(Cell.CELL_TYPE_BOOLEAN, 0.0, false, null, 0, null);
+
+ private final int _cellType;
+ private final double _numberValue;
+ private final boolean _booleanValue;
+ private final String _textValue;
+ private final int _errorCode;
+ private CreationHelper _creationHelper;
+
+ private CellValue(int cellType, double numberValue, boolean booleanValue,
+ String textValue, int errorCode, CreationHelper creationHelper) {
+ _cellType = cellType;
+ _numberValue = numberValue;
+ _booleanValue = booleanValue;
+ _textValue = textValue;
+ _errorCode = errorCode;
+ _creationHelper = creationHelper;
+ }
+
+
+ /* package*/ CellValue(double numberValue, CreationHelper creationHelper) {
+ this(Cell.CELL_TYPE_NUMERIC, numberValue, false, null, 0, creationHelper);
+ }
+ /* package*/ static CellValue valueOf(boolean booleanValue) {
+ return booleanValue ? TRUE : FALSE;
+ }
+ /* package*/ CellValue(String stringValue, CreationHelper creationHelper) {
+ this(Cell.CELL_TYPE_STRING, 0.0, false, stringValue, 0, creationHelper);
+ }
+ /* package*/ static CellValue getError(int errorCode) {
+ return new CellValue(Cell.CELL_TYPE_ERROR, 0.0, false, null, errorCode, null);
+ }
+
+
/**
* @return Returns the booleanValue.
*/
public boolean getBooleanValue() {
- return booleanValue;
- }
- /**
- * @param booleanValue The booleanValue to set.
- */
- public void setBooleanValue(boolean booleanValue) {
- this.booleanValue = booleanValue;
+ return _booleanValue;
}
/**
* @return Returns the numberValue.
*/
public double getNumberValue() {
- return numberValue;
- }
- /**
- * @param numberValue The numberValue to set.
- */
- public void setNumberValue(double numberValue) {
- this.numberValue = numberValue;
+ return _numberValue;
}
/**
- * @return Returns the stringValue. This method is deprecated, use
- * getRichTextStringValue instead
- * @deprecated
+ * @return Returns the stringValue.
*/
public String getStringValue() {
- return richTextStringValue.getString();
- }
- /**
- * @param stringValue The stringValue to set. This method is deprecated, use
- * getRichTextStringValue instead.
- * @deprecated
- */
- public void setStringValue(String stringValue) {
- this.richTextStringValue =
- creationHelper.createRichTextString(stringValue);
+ return _textValue;
}
/**
* @return Returns the cellType.
*/
public int getCellType() {
- return cellType;
+ return _cellType;
}
/**
* @return Returns the errorValue.
*/
public byte getErrorValue() {
- return errorValue;
- }
- /**
- * @param errorValue The errorValue to set.
- */
- public void setErrorValue(byte errorValue) {
- this.errorValue = errorValue;
+ return (byte) _errorCode;
}
/**
* @return Returns the richTextStringValue.
+ * @deprecated (Sep 2008) Text formatting is lost during formula evaluation. Use {@link #getStringValue()}
*/
public RichTextString getRichTextStringValue() {
- return richTextStringValue;
+ return _creationHelper.createRichTextString(_textValue);
}
- /**
- * @param richTextStringValue The richTextStringValue to set.
- */
- public void setRichTextStringValue(RichTextString richTextStringValue) {
- this.richTextStringValue = richTextStringValue;
+ public String toString() {
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(getClass().getName()).append(" [");
+ sb.append(formatAsString());
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public String formatAsString() {
+ switch (_cellType) {
+ case Cell.CELL_TYPE_NUMERIC:
+ return String.valueOf(_numberValue);
+ case Cell.CELL_TYPE_STRING:
+ return '"' + _textValue + '"';
+ case Cell.CELL_TYPE_BOOLEAN:
+ return _booleanValue ? "TRUE" : "FALSE";
+ case Cell.CELL_TYPE_ERROR:
+ return ErrorEval.getText(_errorCode);
+ }
+ return "<error unexpected cell type " + _cellType + ">";
}
}
}
--- /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.ss.usermodel;
+
+import org.apache.poi.hssf.record.formula.AreaI;
+import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.AreaEvalBase;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.util.CellReference;
+
+/**
+ *
+ * @author Josh Micich
+ */
+public class LazyAreaEval extends AreaEvalBase {
+
+ private final Sheet _sheet;
+ private FormulaEvaluator _evaluator;
+
+ public LazyAreaEval(AreaI ptg, Sheet sheet, FormulaEvaluator evaluator) {
+ super(ptg);
+ _sheet = sheet;
+ _evaluator = evaluator;
+ }
+
+ public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
+
+ int rowIx = (relativeRowIndex + getFirstRow() ) & 0xFFFF;
+ int colIx = (relativeColumnIndex + getFirstColumn() ) & 0x00FF;
+
+ Row row = _sheet.getRow(rowIx);
+ if (row == null) {
+ return BlankEval.INSTANCE;
+ }
+ Cell cell = row.getCell(colIx);
+ if (cell == null) {
+ return BlankEval.INSTANCE;
+ }
+ return _evaluator.getEvalForCell(cell);
+ }
+
+ public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+ AreaI area = new OffsetArea(getFirstRow(), getFirstColumn(),
+ relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
+
+ return new LazyAreaEval(area, _sheet, _evaluator);
+ }
+ public String toString() {
+ CellReference crA = new CellReference(getFirstRow(), getFirstColumn());
+ CellReference crB = new CellReference(getLastRow(), getLastColumn());
+ StringBuffer sb = new StringBuffer();
+ sb.append(getClass().getName()).append("[");
+ String sheetName = _evaluator.getSheetName(_sheet);
+ sb.append(sheetName);
+ sb.append('!');
+ sb.append(crA.formatAsString());
+ sb.append(':');
+ sb.append(crB.formatAsString());
+ sb.append("]");
+ return sb.toString();
+ }
+}
--- /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.ss.usermodel;
+
+import org.apache.poi.hssf.record.formula.AreaI;
+import org.apache.poi.hssf.record.formula.Ref3DPtg;
+import org.apache.poi.hssf.record.formula.RefPtg;
+import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;
+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.RefEvalBase;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.util.CellReference;
+
+/**
+*
+* @author Josh Micich
+*/
+public class LazyRefEval extends RefEvalBase {
+
+ private final Sheet _sheet;
+ private final FormulaEvaluator _evaluator;
+
+
+ public LazyRefEval(RefPtg ptg, Sheet sheet, FormulaEvaluator evaluator) {
+ super(ptg.getRow(), ptg.getColumn());
+ _sheet = sheet;
+ _evaluator = evaluator;
+ }
+ public LazyRefEval(Ref3DPtg ptg, Sheet sheet, FormulaEvaluator evaluator) {
+ super(ptg.getRow(), ptg.getColumn());
+ _sheet = sheet;
+ _evaluator = evaluator;
+ }
+
+ public ValueEval getInnerValueEval() {
+ int rowIx = getRow();
+ int colIx = getColumn();
+
+ Row row = _sheet.getRow(rowIx);
+ if (row == null) {
+ return BlankEval.INSTANCE;
+ }
+ Cell cell = row.getCell(colIx);
+ if (cell == null) {
+ return BlankEval.INSTANCE;
+ }
+ return _evaluator.getEvalForCell(cell);
+ }
+
+ public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+
+ AreaI area = new OffsetArea(getRow(), getColumn(),
+ relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
+
+ return new LazyAreaEval(area, _sheet, _evaluator);
+ }
+
+ public String toString() {
+ CellReference cr = new CellReference(getRow(), getColumn());
+ StringBuffer sb = new StringBuffer();
+ sb.append(getClass().getName()).append("[");
+ String sheetName = _evaluator.getSheetName(_sheet);
+ sb.append(sheetName);
+ sb.append('!');
+ sb.append(cr.formatAsString());
+ sb.append("]");
+ return sb.toString();
+ }
+}
retVal.append('[');
for(int x = 0; x < value.length; x++)
{
+ if (x>0) {
+ retVal.append(", ");
+ }
retVal.append(toHex(value[x]));
- retVal.append(", ");
}
retVal.append(']');
return retVal.toString();
return rval;
}
- static public byte[] readFromString(String data) throws IOException
- {
- return readData(new ByteArrayInputStream( data.getBytes() ), -1);
+ static public byte[] readFromString(String data) {
+ try {
+ return readData(new ByteArrayInputStream( data.getBytes() ), -1);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
static private void readToEOL( InputStream stream ) throws IOException
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
/**
* This is a JDK 1.4 compatible interface for HSSFCell.
void setCellErrorValue(byte value);
HSSFCellStyle getCellStyle();
+ HSSFSheet getSheet();
boolean getBooleanCellValue();
double getNumericCellValue();
package org.apache.poi.ss.usermodel;
-public interface Comment {}
+public interface Comment {
+ public void setRow(short row);
+ public void setColumn(short row);
+}
int getRowIndex();
+ Sheet getSheet();
+
/**
* set the cells type (numeric, formula or string)
* @see #CELL_TYPE_NUMERIC
assertEquals( (short) 0x0001, r.getOptions() );
assertEquals( EscherBSERecord.BT_JPEG, r.getBlipTypeWin32() );
assertEquals( EscherBSERecord.BT_JPEG, r.getBlipTypeMacOS() );
- assertEquals( "[01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 00, ]", HexDump.toHex( r.getUid() ) );
+ assertEquals( "[01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 00]", HexDump.toHex( r.getUid() ) );
assertEquals( (short) 1, r.getTag() );
assertEquals( 2, r.getRef() );
assertEquals( 3, r.getOffset() );
assertEquals( 44, bytesWritten );
assertEquals( "[01, 00, 00, 00, 24, 00, 00, 00, 05, 05, 01, 02, 03, 04, " +
"05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 00, 01, 00, 00, 00, " +
- "00, 00, 02, 00, 00, 00, 03, 00, 00, 00, 04, 05, 06, 07, ]",
+ "00, 00, 02, 00, 00, 00, 03, 00, 00, 00, 04, 05, 06, 07]",
HexDump.toHex( data ) );
}
" Options: 0x0001" + nl +
" BlipTypeWin32: 5" + nl +
" BlipTypeMacOS: 5" + nl +
- " SUID: [01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 00, ]" + nl +
+ " SUID: [01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 00]" + nl +
" Tag: 1" + nl +
" Size: 0" + nl +
" Ref: 2" + nl +
-
/* ====================================================================
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.ddf;
import junit.framework.TestCase;
data = HexRead.readFromString(dataStr);
}
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherBlipWMFRecord r = new EscherBlipWMFRecord();
r.setBoundaryLeft(1);
r.setBoundaryHeight(2);
"05, 00, 00, 00, " + // field_9_cacheOfSavedSize
"08, " + // field_10_compressionFlag
"07, " + // field_11_filter
- "01, 02, ]", // field_12_data
+ "01, 02]", // field_12_data
HexDump.toHex(buf));
assertEquals(60, r.getRecordSize() );
}
- public void testFillFields() throws Exception
- {
+ public void testFillFields() {
EscherBlipWMFRecord r = new EscherBlipWMFRecord();
r.fillFields( data, 0, new DefaultEscherRecordFactory());
assertEquals( 6, r.getCacheOfSize() );
assertEquals( 7, r.getFilter() );
assertEquals( 8, r.getCompressionFlag() );
- assertEquals( "[01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, ]", HexDump.toHex(r.getSecondaryUID() ) );
+ assertEquals( "[01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01]", HexDump.toHex(r.getSecondaryUID() ) );
assertEquals( 10, r.getWidth() );
assertEquals( 11, r.getHeight() );
assertEquals( (short)5420, r.getOptions() );
- assertEquals( "[01, 02, ]", HexDump.toHex( r.getData() ) );
+ assertEquals( "[01, 02]", HexDump.toHex( r.getData() ) );
}
- public void testToString() throws Exception
- {
+ public void testToString() {
EscherBlipWMFRecord r = new EscherBlipWMFRecord();
r.fillFields( data, 0, new DefaultEscherRecordFactory() );
assertEquals( "org.apache.poi.ddf.EscherBlipWMFRecord:" + nl +
" RecordId: 0xF018" + nl +
" Options: 0x152C" + nl +
- " Secondary UID: [01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, ]" + nl +
+ " Secondary UID: [01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01]" + nl +
" CacheOfSize: 6" + nl +
" BoundaryTop: 3" + nl +
" BoundaryLeft: 1" + nl +
"00000000 01 02 .." + nl
, r.toString() );
}
-
}
+
-
/* ====================================================================
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.ddf;
import junit.framework.TestCase;
public class TestEscherChildAnchorRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherChildAnchorRecord r = createRecord();
byte[] data = new byte[8 + 16];
"01, 00, 00, 00, " +
"02, 00, 00, 00, " +
"03, 00, 00, 00, " +
- "04, 00, 00, 00, ]", HexDump.toHex( data ) );
+ "04, 00, 00, 00]", HexDump.toHex( data ) );
}
public void testFillFields() throws Exception
assertEquals( (short) 0x0001, r.getOptions() );
}
- public void testToString() throws Exception
- {
+ public void testToString(){
String nl = System.getProperty( "line.separator" );
String expected = "org.apache.poi.ddf.EscherChildAnchorRecord:" + nl +
assertEquals( expected, createRecord().toString() );
}
- private EscherChildAnchorRecord createRecord()
+ private static EscherChildAnchorRecord createRecord()
{
EscherChildAnchorRecord r = new EscherChildAnchorRecord();
r.setRecordId( EscherChildAnchorRecord.RECORD_ID );
r.setDy2( 4 );
return r;
}
-
}
+
-
/* ====================================================================
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.ddf;
import junit.framework.TestCase;
public class TestEscherClientAnchorRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherClientAnchorRecord r = createRecord();
byte[] data = new byte[8 + 18 + 2];
"4D, 00, 37, 00, 21, 00, 58, 00, " +
"0B, 00, 2C, 00, 16, 00, 63, 00, " +
"42, 00, " +
- "FF, DD, ]", HexDump.toHex( data ) );
+ "FF, DD]", HexDump.toHex( data ) );
}
- public void testFillFields() throws Exception
- {
+ public void testFillFields() {
String hexData = "01 00 " +
"10 F0 " +
"14 00 00 00 " +
assertEquals( (byte) 0xDD, r.getRemainingData()[1] );
}
- public void testToString() throws Exception
- {
+ public void testToString() {
String nl = System.getProperty("line.separator");
String expected = "org.apache.poi.ddf.EscherClientAnchorRecord:" + nl +
-
/* ====================================================================
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.ddf;
import junit.framework.TestCase;
public class TestEscherClientDataRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherClientDataRecord r = createRecord();
byte[] data = new byte[8];
assertEquals( 8, bytesWritten );
assertEquals( "[02, 00, " +
"11, F0, " +
- "00, 00, 00, 00, ]",
+ "00, 00, 00, 00]",
HexDump.toHex( data ) );
}
- public void testFillFields() throws Exception
- {
+ public void testFillFields() {
String hexData = "02 00 " +
"11 F0 " +
"00 00 00 00 ";
assertEquals( "[]", HexDump.toHex(r.getRemainingData()) );
}
- public void testToString() throws Exception
- {
+ public void testToString() {
String nl = System.getProperty("line.separator");
String expected = "org.apache.poi.ddf.EscherClientDataRecord:" + nl +
assertEquals( expected, createRecord().toString() );
}
- private EscherClientDataRecord createRecord()
+ private static EscherClientDataRecord createRecord()
{
EscherClientDataRecord r = new EscherClientDataRecord();
r.setOptions( (short) 0x0002 );
r.setRemainingData( new byte[] {} );
return r;
}
-
}
{
private String ESCHER_DATA_PATH;
- protected void setUp() throws Exception {
- super.setUp();
+ protected void setUp() {
ESCHER_DATA_PATH = System.getProperty("DDF.testdata.path");
}
- public void testFillFields() throws Exception
- {
+ public void testFillFields() {
EscherRecordFactory f = new DefaultEscherRecordFactory();
byte[] data = HexRead.readFromString( "0F 02 11 F1 00 00 00 00" );
EscherRecord r = f.createRecord( data, 0 );
assertEquals( (short) 0xF222, c.getRecordId() );
}
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
UnknownEscherRecord r = new UnknownEscherRecord();
r.setOptions( (short) 0x123F );
r.setRecordId( (short) 0xF112 );
byte[] data = new byte[8];
r.serialize( 0, data, new NullEscherSerializationListener() );
- assertEquals( "[3F, 12, 12, F1, 00, 00, 00, 00, ]", HexDump.toHex( data ) );
+ assertEquals( "[3F, 12, 12, F1, 00, 00, 00, 00]", HexDump.toHex( data ) );
EscherRecord childRecord = new UnknownEscherRecord();
childRecord.setOptions( (short) 0x9999 );
data = new byte[16];
r.serialize( 0, data, new NullEscherSerializationListener() );
- assertEquals( "[3F, 12, 12, F1, 08, 00, 00, 00, 99, 99, 01, FF, 00, 00, 00, 00, ]", HexDump.toHex( data ) );
+ assertEquals( "[3F, 12, 12, F1, 08, 00, 00, 00, 99, 99, 01, FF, 00, 00, 00, 00]", HexDump.toHex( data ) );
}
- public void testToString() throws Exception
- {
+ public void testToString() {
EscherContainerRecord r = new EscherContainerRecord();
r.setRecordId( EscherContainerRecord.SP_CONTAINER );
r.setOptions( (short) 0x000F );
assertEquals( expected, r.toString() );
}
- public void testGetRecordSize() throws Exception
- {
+ public void testGetRecordSize() {
EscherContainerRecord r = new EscherContainerRecord();
r.addChildRecord(new EscherRecord()
{
-
/* ====================================================================
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.ddf;
import junit.framework.TestCase;
public class TestEscherDgRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherDgRecord r = createRecord();
byte[] data = new byte[16];
"08, F0, " +
"08, 00, 00, 00, " +
"02, 00, 00, 00, " + // num shapes in drawing
- "01, 04, 00, 00, ]", // The last MSOSPID given to an SP in this DG
+ "01, 04, 00, 00]", // The last MSOSPID given to an SP in this DG
HexDump.toHex( data ) );
}
- public void testFillFields() throws Exception
- {
+ public void testFillFields() {
String hexData = "10 00 " +
"08 F0 " +
"08 00 00 00 " +
assertEquals( 1025, r.getLastMSOSPID() );
}
- public void testToString() throws Exception
- {
+ public void testToString() {
String nl = System.getProperty("line.separator");
String expected = "org.apache.poi.ddf.EscherDgRecord:" + nl +
assertEquals( expected, createRecord().toString() );
}
- private EscherDgRecord createRecord()
+ private static EscherDgRecord createRecord()
{
EscherDgRecord r = new EscherDgRecord();
r.setOptions( (short) 0x0010 );
r.setLastMSOSPID(1025);
return r;
}
-
}
-
/* ====================================================================
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.ddf;
import junit.framework.TestCase;
public class TestEscherDggRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherDggRecord r = createRecord();
byte[] data = new byte[32];
"02, 00, 00, 00, " +
"02, 00, 00, 00, " +
"01, 00, 00, 00, " +
- "01, 00, 00, 00, 02, 00, 00, 00, ]",
+ "01, 00, 00, 00, 02, 00, 00, 00]",
HexDump.toHex( data ) );
}
- public void testFillFields() throws Exception
- {
+ public void testFillFields() {
String hexData = "00 00 " +
"06 F0 " +
"18 00 00 00 " +
assertEquals( 0x02, r.getFileIdClusters()[0].getNumShapeIdsUsed());
}
- public void testToString() throws Exception
- {
+ public void testToString() {
String nl = System.getProperty("line.separator");
String expected = "org.apache.poi.ddf.EscherDggRecord:" + nl +
assertEquals( expected, createRecord().toString() );
}
- private EscherDggRecord createRecord()
+ private static EscherDggRecord createRecord()
{
EscherDggRecord r = new EscherDggRecord();
r.setOptions( (short) 0x0000 );
return r;
}
- public void testGetRecordSize() throws Exception
- {
+ public void testGetRecordSize() {
EscherDggRecord r = new EscherDggRecord();
r.setFileIdClusters(new EscherDggRecord.FileIdCluster[] { new EscherDggRecord.FileIdCluster(0,0) } );
assertEquals(32,r.getRecordSize());
-
}
-
}
import java.io.IOException;
import java.util.Arrays;
-import java.util.List;
-import java.util.Iterator;
public class TestEscherOptRecord extends TestCase
{
- public void testFillFields() throws Exception
- {
+ public void testFillFields() {
checkFillFieldsSimple();
checkFillFieldsComplex();
}
- private void checkFillFieldsComplex() throws IOException
- {
+ private void checkFillFieldsComplex() {
String dataStr = "33 00 " +
"0B F0 " +
"14 00 00 00 " +
}
- private void checkFillFieldsSimple()
- throws IOException
- {
+ private void checkFillFieldsSimple() {
String dataStr = "33 00 " + // options
"0B F0 " + // recordid
"12 00 00 00 " + // remaining bytes
assertEquals( prop3, r.getEscherProperty( 2 ) );
}
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
checkSerializeSimple();
checkSerializeComplex();
}
"BF, 00, 01, 00, 00, 00, " +
"01, 80, 02, 00, 00, 00, " +
"BF, 00, 01, 00, 00, 00, " +
- "01, 02, ]";
+ "01, 02]";
assertEquals( dataStr, HexDump.toHex(data) );
}
"12, 00, 00, 00, " +
"BF, 00, 01, 00, 00, 00, " +
"81, 01, 09, 00, 00, 08, " +
- "C0, 01, 40, 00, 00, 08, ]";
+ "C0, 01, 40, 00, 00, 08]";
assertEquals( dataStr, HexDump.toHex(data) );
assertEquals( 26, bytesWritten );
}
- public void testToString() throws Exception
- {
+ public void testToString() {
String nl = System.getProperty("line.separator");
EscherOptRecord r = new EscherOptRecord();
r.setOptions((short)0x000F);
* Test serialisation of a particually complex example
* This test is currently broken!
*/
- public void testComplexSerialise() throws Exception {
- byte[] data = new byte[] {
+ public void testComplexSerialise() {
+ byte[] data = {
0x53, 0x01, 0x0B, 0xF0-256, 0x9C-256, 0x01, 0x00, 0x00,
// Simple data follows
0x42, 0x01, 0x49, 0x00, 0x00, 0x00, // SP @ 8
*
* See Bug 41946 for details.
*/
- public void test41946() throws IOException {
+ public void test41946() {
String dataStr1 =
"03 08 0B F0 00 03 00 00 81 00 30 65 01 00 82 00 98 B2 00 00 83 00 30 65 01 " +
"00 84 00 98 B2 00 00 85 00 00 00 00 00 87 00 01 00 00 00 88 00 00 00 00 00 " +
* Test that EscherOptRecord can properly read/write array properties
* with empty complex part.
*/
- public void testEmptyArrayProperty() throws IOException {
+ public void testEmptyArrayProperty() {
EscherOptRecord r = new EscherOptRecord();
EscherArrayProperty p = new EscherArrayProperty((short)(EscherProperties.FILL__SHADECOLORS + 0x8000), new byte[0] );
assertEquals(0, p.getNumberOfElementsInArray());
-
/* ====================================================================
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.ddf;
import junit.framework.TestCase;
*/
public class TestEscherPropertyFactory extends TestCase
{
- public void testCreateProperties() throws Exception
- {
+ public void testCreateProperties() {
String dataStr = "41 C1 " + // propid, complex ind
"03 00 00 00 " + // size of complex property
"01 00 " + // propid, complex ind
List props = f.createProperties( data, 0, (short)3 );
EscherComplexProperty p1 = (EscherComplexProperty) props.get( 0 );
assertEquals( (short)0xC141, p1.getId() );
- assertEquals( "[01, 02, 03, ]", HexDump.toHex( p1.getComplexData() ) );
+ assertEquals( "[01, 02, 03]", HexDump.toHex( p1.getComplexData() ) );
EscherComplexProperty p3 = (EscherComplexProperty) props.get( 2 );
assertEquals( (short)0xC141, p3.getId() );
- assertEquals( "[01, 02, 03, ]", HexDump.toHex( p3.getComplexData() ) );
-
-
+ assertEquals( "[01, 02, 03]", HexDump.toHex( p3.getComplexData() ) );
}
-
-
-
}
+
-
/* ====================================================================
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.ddf;
import junit.framework.TestCase;
public class TestEscherSpRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherSpRecord r = createRecord();
byte[] data = new byte[16];
"0A, F0, " +
"08, 00, 00, 00, " +
"00, 04, 00, 00, " +
- "05, 00, 00, 00, ]",
+ "05, 00, 00, 00]",
HexDump.toHex( data ) );
}
- public void testFillFields() throws Exception
- {
+ public void testFillFields() {
String hexData = "02 00 " +
"0A F0 " +
"08 00 00 00 " +
assertEquals( 0x05, r.getFlags() );
}
- public void testToString() throws Exception
- {
+ public void testToString() {
String nl = System.getProperty("line.separator");
String expected = "org.apache.poi.ddf.EscherSpRecord:" + nl +
assertEquals( expected, createRecord().toString() );
}
- private EscherSpRecord createRecord()
+ private static EscherSpRecord createRecord()
{
EscherSpRecord r = new EscherSpRecord();
r.setOptions( (short) 0x0002 );
-
/* ====================================================================
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.ddf;
import junit.framework.TestCase;
public class TestEscherSpgrRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherSpgrRecord r = createRecord();
byte[] data = new byte[24];
"01, 00, 00, 00, " + // x
"02, 00, 00, 00, " + // y
"03, 00, 00, 00, " + // width
- "04, 00, 00, 00, ]", // height
+ "04, 00, 00, 00]", // height
HexDump.toHex( data ) );
}
- public void testFillFields() throws Exception
- {
+ public void testFillFields() {
String hexData = "10 00 " +
"09 F0 " +
"10 00 00 00 " +
assertEquals( 4, r.getRectY2() );
}
- public void testToString() throws Exception
- {
+ public void testToString() {
String nl = System.getProperty("line.separator");
String expected = "org.apache.poi.ddf.EscherSpgrRecord:" + nl +
" RectY: 2" + nl +
" RectWidth: 3" + nl +
" RectHeight: 4" + nl;
- ;
assertEquals( expected, createRecord().toString() );
}
- private EscherSpgrRecord createRecord()
+ private static EscherSpgrRecord createRecord()
{
EscherSpgrRecord r = new EscherSpgrRecord();
r.setOptions( (short) 0x0010 );
r.setRectY2(4);
return r;
}
-
}
public class TestEscherSplitMenuColorsRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherSplitMenuColorsRecord r = createRecord();
byte[] data = new byte[24];
"02, 04, 00, 00, " +
"02, 00, 00, 00, " +
"02, 00, 00, 00, " +
- "01, 00, 00, 00, ]",
+ "01, 00, 00, 00]",
HexDump.toHex( data ) );
}
- public void testFillFields() throws Exception
- {
+ public void testFillFields() {
String hexData = "40 00 " +
"1E F1 " +
"10 00 00 00 " +
assertEquals( 0x01, r.getColor4() );
}
- public void testToString() throws Exception
- {
+ public void testToString() {
String nl = System.getProperty("line.separator");
String expected = "org.apache.poi.ddf.EscherSplitMenuColorsRecord:" + nl +
assertEquals( expected, createRecord().toString() );
}
- private EscherSplitMenuColorsRecord createRecord()
+ private static EscherSplitMenuColorsRecord createRecord()
{
EscherSplitMenuColorsRecord r = new EscherSplitMenuColorsRecord();
r.setOptions( (short) 0x0040 );
r.setColor4( 0x1 );
return r;
}
-
}
public class TestUnknownEscherRecord extends TestCase
{
- public void testFillFields() throws Exception
- {
+ public void testFillFields() {
String testData =
"0F 02 " + // options
"11 F1 " + // record id
}
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
UnknownEscherRecord r = new UnknownEscherRecord();
r.setOptions( (short) 0x1234 );
r.setRecordId( (short) 0xF112 );
byte[] data = new byte[8];
r.serialize( 0, data, new NullEscherSerializationListener() );
- assertEquals( "[34, 12, 12, F1, 00, 00, 00, 00, ]", HexDump.toHex( data ) );
+ assertEquals( "[34, 12, 12, F1, 00, 00, 00, 00]", HexDump.toHex( data ) );
EscherRecord childRecord = new UnknownEscherRecord();
childRecord.setOptions( (short) 0x9999 );
data = new byte[16];
r.serialize( 0, data, new NullEscherSerializationListener() );
- assertEquals( "[3F, 12, 12, F1, 08, 00, 00, 00, 99, 99, 01, FF, 00, 00, 00, 00, ]", HexDump.toHex( data ) );
+ assertEquals( "[3F, 12, 12, F1, 08, 00, 00, 00, 99, 99, 01, FF, 00, 00, 00, 00]", HexDump.toHex( data ) );
}
- public void testToString() throws Exception
- {
+ public void testToString() {
UnknownEscherRecord r = new UnknownEscherRecord();
r.setOptions( (short) 0x1234 );
r.setRecordId( (short) 0xF112 );
" numchildren: 0" + nl
, r.toString() );
}
-
-
}
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.model.FormulaParser.FormulaParseException;
+import org.apache.poi.hssf.record.constant.ErrorConstant;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.AddPtg;
import org.apache.poi.hssf.record.formula.AreaI;
import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.ArrayPtg;
import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.BoolPtg;
import org.apache.poi.hssf.record.formula.ConcatPtg;
import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
import org.apache.poi.hssf.usermodel.HSSFName;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
assertEquals(65535, aptg.getLastRow());
}
+ public void testParseArray() {
+ Ptg[] ptgs;
+ ptgs = parseFormula("mode({1,2,2,#REF!;FALSE,3,3,2})");
+ assertEquals(2, ptgs.length);
+ Ptg ptg0 = ptgs[0];
+ assertEquals(ArrayPtg.class, ptg0.getClass());
+ assertEquals("{1.0,2.0,2.0,#REF!;FALSE,3.0,3.0,2.0}", ptg0.toFormulaString(null));
+
+ ArrayPtg aptg = (ArrayPtg) ptg0;
+ Object[][] values = aptg.getTokenArrayValues();
+ assertEquals(ErrorConstant.valueOf(HSSFErrorConstants.ERROR_REF), values[0][3]);
+ assertEquals(Boolean.FALSE, values[1][0]);
+
+ }
}
\ No newline at end of file
sheet.createRow(32768).createCell(0).setCellValue(31);
sheet.createRow(32769).createCell(0).setCellValue(11);
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
CellValue result;
try {
result = fe.evaluate(cell);
try {
confirmCell(cell, formula, wb);
} catch (AssertionFailedError e) {
+ System.out.flush();
System.err.println("Problem with row[" + rowIx + "] formula '" + formula + "'");
System.err.println(e.getMessage());
+ System.err.flush();
countFailures++;
} catch (RuntimeException e) {
System.err.println("Problem with row[" + rowIx + "] formula '" + formula + "'");
if (excelPtg.getClass() != poiPtg.getClass()) {
hasMismatch = true;
sb.append(" mismatch token type[" + i + "] " + getShortClassName(excelPtg) + " "
- + getOperandClassName(excelPtg) + " - " + getShortClassName(poiPtg) + " "
- + getOperandClassName(poiPtg));
+ + excelPtg.getRVAType() + " - " + getShortClassName(poiPtg) + " "
+ + poiPtg.getRVAType());
sb.append(NEW_LINE);
continue;
}
continue;
}
sb.append(" token[" + i + "] " + excelPtg.toString() + " "
- + getOperandClassName(excelPtg));
+ + excelPtg.getRVAType());
if (excelPtg.getPtgClass() != poiPtg.getPtgClass()) {
hasMismatch = true;
- sb.append(" - was " + getOperandClassName(poiPtg));
+ sb.append(" - was " + poiPtg.getRVAType());
}
sb.append(NEW_LINE);
}
if (false) { // set 'true' to see trace of RVA values
- System.out.println(formula);
+ System.out.println(formulaCell.getRowIndex() + " " + formula);
System.out.println(sb.toString());
}
if (hasMismatch) {
int pos = cn.lastIndexOf('.');
return cn.substring(pos + 1);
}
-
- private static String getOperandClassName(Ptg ptg) {
- byte ptgClass = ptg.getPtgClass();
- switch (ptgClass) {
- case Ptg.CLASS_REF: return "R";
- case Ptg.CLASS_VALUE: return "V";
- case Ptg.CLASS_ARRAY: return "A";
- }
- throw new RuntimeException("Unknown operand class (" + ptgClass + ")");
- }
}
records.add(new DimensionsRecord());
records.add(new RowRecord(0));
records.add(new RowRecord(1));
- records.add(new FormulaRecord());
+ FormulaRecord formulaRecord = new FormulaRecord();
+ formulaRecord.setCachedResultTypeString();
+ records.add(formulaRecord);
records.add(new StringRecord());
records.add(new RowRecord(2));
records.add(createWindow2Record());
xfindex = sheet.getXFIndexForColAt((short) 1);
assertEquals(DEFAULT_IDX, xfindex);
- ColumnInfoRecord nci = ColumnInfoRecordsAggregate.createColInfo();
+ ColumnInfoRecord nci = new ColumnInfoRecord();
sheet._columnInfos.insertColumn(nci);
// single column ColumnInfoRecord
sheet.setMargin(HSSFSheet.LeftMargin, 0.3);
try {
- row.createCell((short) 0);
+ row.createCell(0);
} catch (IllegalStateException e) {
if (e.getMessage().equals("Cannot create value records before row records exist")) {
throw new AssertionFailedError("Identified bug 45717");
}
}
}
-
import junit.framework.TestCase;
import org.apache.poi.hssf.record.ColumnInfoRecord;
-import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
/**
* @author Tony Poppleton
public void testGetCellWidth() {
Sheet sheet = Sheet.createSheet();
- ColumnInfoRecord nci = ColumnInfoRecordsAggregate.createColInfo();
+ ColumnInfoRecord nci = new ColumnInfoRecord();
// Prepare test model
nci.setFirstColumn((short)5);
assertEquals((short)100,sheet.getColumnWidth((short)9));
assertEquals((short)100,sheet.getColumnWidth((short)10));
}
-
}
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.util.HexDump;
-public class TestDrawingGroupRecord extends TestCase
-{
- static final int MAX_RECORD_SIZE = 8228;
+public final class TestDrawingGroupRecord extends TestCase {
+ private static final int MAX_RECORD_SIZE = 8228;
private static final int MAX_DATA_SIZE = MAX_RECORD_SIZE - 4;
- public void testGetRecordSize()
- throws Exception
- {
+ public void testGetRecordSize() {
DrawingGroupRecord r = new DrawingGroupRecord();
assertEquals(4, r.getRecordSize());
byte[] data = new byte[28];
int size = r.serialize(0, data);
- assertEquals("[EB, 00, 18, 00, 0F, 00, 00, F0, 10, 00, 00, 00, 11, 11, 0A, F0, 08, 00, 00, 00, FF, FF, FF, FF, FF, FF, FF, FF, ]", HexDump.toHex(data));
+ assertEquals("[EB, 00, 18, 00, 0F, 00, 00, F0, 10, 00, 00, 00, 11, 11, 0A, F0, 08, 00, 00, 00, FF, FF, FF, FF, FF, FF, FF, FF]", HexDump.toHex(data));
assertEquals(28, size);
assertEquals(24, dggContainer.getRecordSize());
assertEquals( MAX_RECORD_SIZE * 2 + 5, r.getRecordSize() );
}
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
// Check under max record size
DrawingGroupRecord r = new DrawingGroupRecord();
byte[] rawData = new byte[100];
byte[] buffer = new byte[r.getRecordSize()];
int size = r.serialize( 0, buffer );
assertEquals( 104, size );
- assertEquals("[EB, 00, 64, 00, 64, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, C8, ]", HexDump.toHex(buffer));
+ assertEquals("[EB, 00, 64, 00, 64, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, C8]", HexDump.toHex(buffer));
// check at max record size
rawData = new byte[MAX_DATA_SIZE];
buffer = new byte[r.getRecordSize()];
size = r.serialize( 0, buffer );
assertEquals( MAX_RECORD_SIZE + 5, size );
- assertEquals( "[EB, 00, 20, 20, ]", HexDump.toHex(cut(buffer, 0, 4) ));
- assertEquals( "[00, EB, 00, 01, 00, FF, ]", HexDump.toHex(cut(buffer, MAX_RECORD_SIZE - 1, MAX_RECORD_SIZE + 5) ));
+ assertEquals( "[EB, 00, 20, 20]", HexDump.toHex(cut(buffer, 0, 4) ));
+ assertEquals( "[00, EB, 00, 01, 00, FF]", HexDump.toHex(cut(buffer, MAX_RECORD_SIZE - 1, MAX_RECORD_SIZE + 5) ));
// check continue record
rawData = new byte[MAX_DATA_SIZE * 2 + 1];
size = r.serialize( 0, buffer );
assertEquals( MAX_RECORD_SIZE * 2 + 5, size );
assertEquals( MAX_RECORD_SIZE * 2 + 5, r.getRecordSize() );
- assertEquals( "[EB, 00, 20, 20, ]", HexDump.toHex(cut(buffer, 0, 4) ));
- assertEquals( "[EB, 00, 20, 20, ]", HexDump.toHex(cut(buffer, MAX_RECORD_SIZE, MAX_RECORD_SIZE + 4) ));
- assertEquals( "[3C, 00, 01, 00, FF, ]", HexDump.toHex(cut(buffer, MAX_RECORD_SIZE * 2, MAX_RECORD_SIZE * 2 + 5) ));
+ assertEquals( "[EB, 00, 20, 20]", HexDump.toHex(cut(buffer, 0, 4) ));
+ assertEquals( "[EB, 00, 20, 20]", HexDump.toHex(cut(buffer, MAX_RECORD_SIZE, MAX_RECORD_SIZE + 4) ));
+ assertEquals( "[3C, 00, 01, 00, FF]", HexDump.toHex(cut(buffer, MAX_RECORD_SIZE * 2, MAX_RECORD_SIZE * 2 + 5) ));
// check continue record
rawData = new byte[664532];
assertEquals( 664856, r.getRecordSize() );
}
- private byte[] cut( byte[] data, int fromInclusive, int toExclusive )
+ private static byte[] cut( byte[] data, int fromInclusive, int toExclusive )
{
int length = toExclusive - fromInclusive;
byte[] result = new byte[length];
return result;
}
- public void testGrossSizeFromDataSize() throws Exception
- {
+ public void testGrossSizeFromDataSize() {
for (int i = 0; i < MAX_RECORD_SIZE * 4; i += 11)
{
//System.out.print( "data size = " + i + ", gross size = " + DrawingGroupRecord.grossSizeFromDataSize( i ) );
assertEquals( MAX_RECORD_SIZE * 2, DrawingGroupRecord.grossSizeFromDataSize( MAX_DATA_SIZE * 2 ) );
assertEquals( MAX_RECORD_SIZE * 2 + 5, DrawingGroupRecord.grossSizeFromDataSize( MAX_DATA_SIZE * 2 + 1 ) );
}
-
-
}
byte[] data = new byte[112];
int bytesWritten = aggregate.serialize( 0, data );
assertEquals( 112, bytesWritten );
- assertEquals( "[EC, 00, 40, 00, 0F, 00, 00, 00, 58, 00, 00, 00, 0F, 00, 04, F0, 10, 00, 00, 00, 00, 00, 0A, F0, 08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0F, 00, 04, F0, 18, 00, 00, 00, 00, 00, 0A, F0, 08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 11, F0, 00, 00, 00, 00, 5D, 00, 00, 00, EC, 00, 20, 00, 0F, 00, 04, F0, 18, 00, 00, 00, 00, 00, 0A, F0, 08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 11, F0, 00, 00, 00, 00, 5D, 00, 00, 00, ]",
+ assertEquals( "[EC, 00, 40, 00, 0F, 00, 00, 00, 58, 00, 00, 00, 0F, 00, 04, F0, 10, 00, 00, 00, 00, 00, 0A, F0, 08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0F, 00, 04, F0, 18, 00, 00, 00, 00, 00, 0A, F0, 08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 11, F0, 00, 00, 00, 00, 5D, 00, 00, 00, EC, 00, 20, 00, 0F, 00, 04, F0, 18, 00, 00, 00, 00, 00, 0A, F0, 08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 11, F0, 00, 00, 00, 00, 5D, 00, 00, 00]",
HexDump.toHex( data ) );
}
import org.apache.poi.hssf.record.formula.IntPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.RefPtg;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
/**
* Tests the serialization and deserialization of the FormulaRecord
- * class works correctly.
+ * class works correctly.
*
- * @author Andrew C. Oliver
+ * @author Andrew C. Oliver
*/
public final class TestFormulaRecord extends TestCase {
record.setColumn((short)0);
record.setRow(1);
record.setXFIndex((short)4);
-
+
assertEquals(record.getColumn(),0);
assertEquals(record.getRow(), 1);
assertEquals(record.getXFIndex(),4);
}
-
+
/**
* Make sure a NAN value is preserved
- * This formula record is a representation of =1/0 at row 0, column 0
+ * This formula record is a representation of =1/0 at row 0, column 0
*/
public void testCheckNanPreserve() {
- byte[] formulaByte = new byte[29];
-
- formulaByte[4] = (byte)0x0F;
- formulaByte[6] = (byte)0x02;
- formulaByte[8] = (byte)0x07;
- formulaByte[12] = (byte)0xFF;
- formulaByte[13] = (byte)0xFF;
- formulaByte[18] = (byte)0xE0;
- formulaByte[19] = (byte)0xFC;
- formulaByte[20] = (byte)0x07;
- formulaByte[22] = (byte)0x1E;
- formulaByte[23] = (byte)0x01;
- formulaByte[25] = (byte)0x1E;
- formulaByte[28] = (byte)0x06;
-
+ byte[] formulaByte = {
+ 0, 0, 0, 0,
+ 0x0F, 0x00,
+
+ // 8 bytes cached number is a 'special value' in this case
+ 0x02, // special cached value type 'error'
+ 0x00,
+ HSSFErrorConstants.ERROR_DIV_0,
+ 0x00,
+ 0x00,
+ 0x00,
+ (byte)0xFF,
+ (byte)0xFF,
+
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+
+ (byte)0xE0, //18
+ (byte)0xFC,
+ // Ptgs
+ 0x07, 0x00, // encoded length
+ 0x1E, 0x01, 0x00, // IntPtg(1)
+ 0x1E, 0x00, 0x00, // IntPtg(0)
+ 0x06, // DividePtg
+
+ };
+
FormulaRecord record = new FormulaRecord(new TestcaseRecordInputStream(FormulaRecord.sid, (short)29, formulaByte));
assertEquals("Row", 0, record.getRow());
- assertEquals("Column", 0, record.getColumn());
- assertTrue("Value is not NaN", Double.isNaN(record.getValue()));
-
+ assertEquals("Column", 0, record.getColumn());
+ assertEquals(HSSFCell.CELL_TYPE_ERROR, record.getCachedResultType());
+
byte[] output = record.serialize();
assertEquals("Output size", 33, output.length); //includes sid+recordlength
-
+
for (int i = 5; i < 13;i++) {
assertEquals("FormulaByte NaN doesn't match", formulaByte[i], output[i+4]);
}
}
-
+
/**
* Tests to see if the shared formula cells properly reserialize the expPtg
*
*/
public void testExpFormula() {
byte[] formulaByte = new byte[27];
-
+
formulaByte[4] =(byte)0x0F;
formulaByte[14]=(byte)0x08;
formulaByte[18]=(byte)0xE0;
assertEquals("Output size", 31, output.length); //includes sid+recordlength
assertEquals("Offset 22", 1, output[26]);
}
-
+
public void testWithConcat() {
// =CHOOSE(2,A2,A3,A4)
byte[] data = {
6, 0, 68, 0,
1, 0, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 57,
- 64, 0, 0, 12, 0, 12, -4, 46, 0,
+ 64, 0, 0, 12, 0, 12, -4, 46, 0,
30, 2, 0, // Int - 2
25, 4, 3, 0, // Attr
8, 0, 17, 0, 26, 0, // jumpTable
36, 2, 0, 0, -64, // Ref - A3
25, 8, 12, 0, // Attr
36, 3, 0, 0, -64, // Ref - A4
- 25, 8, 3, 0, // Attr
+ 25, 8, 3, 0, // Attr
66, 4, 100, 0 // CHOOSE
};
RecordInputStream inp = new RecordInputStream( new ByteArrayInputStream(data));
inp.nextRecord();
-
+
FormulaRecord fr = new FormulaRecord(inp);
-
+
Ptg[] ptgs = fr.getParsedExpression();
assertEquals(9, ptgs.length);
assertEquals(IntPtg.class, ptgs[0].getClass());
assertEquals(RefPtg.class, ptgs[6].getClass());
assertEquals(AttrPtg.class, ptgs[7].getClass());
assertEquals(FuncVarPtg.class, ptgs[8].getClass());
-
+
FuncVarPtg choose = (FuncVarPtg)ptgs[8];
assertEquals("CHOOSE", choose.getName());
}
package org.apache.poi.hssf.record.aggregates;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
+
import org.apache.poi.hssf.record.ColumnInfoRecord;
+import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordBase;
+import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
/**
* @author Glen Stampoultzis
public void testGetRecordSize() {
ColumnInfoRecordsAggregate agg = new ColumnInfoRecordsAggregate();
- agg.insertColumn(createColumn(1, 3));
- agg.insertColumn(createColumn(4, 7));
- agg.insertColumn(createColumn(8, 8));
+ agg.insertColumn(createColInfo(1, 3));
+ agg.insertColumn(createColInfo(4, 7));
+ agg.insertColumn(createColInfo(8, 8));
agg.groupColumnRange((short) 2, (short) 5, true);
- assertEquals(6, agg.getNumColumns());
+ assertEquals(4, agg.getNumColumns());
confirmSerializedSize(agg);
assertEquals(estimatedSize, serializedSize);
}
- private static ColumnInfoRecord createColumn(int firstCol, int lastCol) {
+ private static ColumnInfoRecord createColInfo(int firstCol, int lastCol) {
ColumnInfoRecord columnInfoRecord = new ColumnInfoRecord();
columnInfoRecord.setFirstColumn((short) firstCol);
columnInfoRecord.setLastColumn((short) lastCol);
return columnInfoRecord;
}
-}
\ No newline at end of file
+
+ private static final class CIRCollector implements RecordVisitor {
+
+ private List _list;
+ public CIRCollector() {
+ _list = new ArrayList();
+ }
+ public void visitRecord(Record r) {
+ _list.add(r);
+ }
+ public static ColumnInfoRecord[] getRecords(ColumnInfoRecordsAggregate agg) {
+ CIRCollector circ = new CIRCollector();
+ agg.visitContainedRecords(circ);
+ List list = circ._list;
+ ColumnInfoRecord[] result = new ColumnInfoRecord[list.size()];
+ list.toArray(result);
+ return result;
+ }
+ }
+
+ public void testGroupColumns_bug45639() {
+ ColumnInfoRecordsAggregate agg = new ColumnInfoRecordsAggregate();
+ agg.groupColumnRange( 7, 9, true);
+ agg.groupColumnRange( 4, 12, true);
+ try {
+ agg.groupColumnRange( 1, 15, true);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new AssertionFailedError("Identified bug 45639");
+ }
+ ColumnInfoRecord[] cirs = CIRCollector.getRecords(agg);
+ assertEquals(5, cirs.length);
+ confirmCIR(cirs, 0, 1, 3, 1, false, false);
+ confirmCIR(cirs, 1, 4, 6, 2, false, false);
+ confirmCIR(cirs, 2, 7, 9, 3, false, false);
+ confirmCIR(cirs, 3, 10, 12, 2, false, false);
+ confirmCIR(cirs, 4, 13, 15, 1, false, false);
+ }
+
+ /**
+ * Check that an inner group remains hidden
+ */
+ public void testHiddenAfterExpanding() {
+ ColumnInfoRecordsAggregate agg = new ColumnInfoRecordsAggregate();
+ agg.groupColumnRange(1, 15, true);
+ agg.groupColumnRange(4, 12, true);
+
+ ColumnInfoRecord[] cirs;
+
+ // collapse both inner and outer groups
+ agg.collapseColumn(6);
+ agg.collapseColumn(3);
+
+ cirs = CIRCollector.getRecords(agg);
+ assertEquals(5, cirs.length);
+ confirmCIR(cirs, 0, 1, 3, 1, true, false);
+ confirmCIR(cirs, 1, 4, 12, 2, true, false);
+ confirmCIR(cirs, 2, 13, 13, 1, true, true);
+ confirmCIR(cirs, 3, 14, 15, 1, true, false);
+ confirmCIR(cirs, 4, 16, 16, 0, false, true);
+
+ // just expand the inner group
+ agg.expandColumn(6);
+
+ cirs = CIRCollector.getRecords(agg);
+ assertEquals(4, cirs.length);
+ if (!cirs[1].getHidden()) {
+ throw new AssertionFailedError("Inner group should still be hidden");
+ }
+ confirmCIR(cirs, 0, 1, 3, 1, true, false);
+ confirmCIR(cirs, 1, 4, 12, 2, true, false);
+ confirmCIR(cirs, 2, 13, 15, 1, true, false);
+ confirmCIR(cirs, 3, 16, 16, 0, false, true);
+ }
+ private static void confirmCIR(ColumnInfoRecord[] cirs, int ix, int startColIx, int endColIx, int level, boolean isHidden, boolean isCollapsed) {
+ ColumnInfoRecord cir = cirs[ix];
+ assertEquals("startColIx", startColIx, cir.getFirstColumn());
+ assertEquals("endColIx", endColIx, cir.getLastColumn());
+ assertEquals("level", level, cir.getOutlineLevel());
+ assertEquals("hidden", isHidden, cir.getHidden());
+ assertEquals("collapsed", isCollapsed, cir.getCollapsed());
+ }
+}
public void testBasic() throws Exception {
FormulaRecord f = new FormulaRecord();
+ f.setCachedResultTypeString();
StringRecord s = new StringRecord();
s.setString("abc");
FormulaRecordAggregate fagg = new FormulaRecordAggregate(f, s, SharedValueManager.EMPTY);
public final class TestArrayPtg extends TestCase {
private static final byte[] ENCODED_PTG_DATA = {
- 0x40, 0x00,
- 0x08, 0x00,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x40,
+ 0, 0, 0, 0, 0, 0, 0,
};
private static final byte[] ENCODED_CONSTANT_DATA = {
2, // 3 columns
ptg.readTokenValues(new TestcaseRecordInputStream(0, ENCODED_CONSTANT_DATA));
assertEquals(3, ptg.getColumnCount());
assertEquals(2, ptg.getRowCount());
- Object[] values = ptg.getTokenArrayValues();
- assertEquals(6, values.length);
+ Object[][] values = ptg.getTokenArrayValues();
+ assertEquals(2, values.length);
- assertEquals(Boolean.TRUE, values[0]);
- assertEquals(new UnicodeString("ABCD"), values[1]);
- assertEquals(new Double(0), values[3]);
- assertEquals(Boolean.FALSE, values[4]);
- assertEquals(new UnicodeString("FG"), values[5]);
+ assertEquals(Boolean.TRUE, values[0][0]);
+ assertEquals(new UnicodeString("ABCD"), values[0][1]);
+ assertEquals(new Double(0), values[1][0]);
+ assertEquals(Boolean.FALSE, values[1][1]);
+ assertEquals(new UnicodeString("FG"), values[1][2]);
byte[] outBuf = new byte[ENCODED_CONSTANT_DATA.length];
ptg.writeTokenValueBytes(outBuf, 0);
assertEquals(2, ptg.getRowCount());
assertEquals(0, ptg.getValueIndex(0, 0));
- assertEquals(2, ptg.getValueIndex(1, 0));
- assertEquals(4, ptg.getValueIndex(2, 0));
- assertEquals(1, ptg.getValueIndex(0, 1));
- assertEquals(3, ptg.getValueIndex(1, 1));
+ assertEquals(1, ptg.getValueIndex(1, 0));
+ assertEquals(2, ptg.getValueIndex(2, 0));
+ assertEquals(3, ptg.getValueIndex(0, 1));
+ assertEquals(4, ptg.getValueIndex(1, 1));
assertEquals(5, ptg.getValueIndex(2, 1));
}
if (formula.equals("SUM({1.0,6.0,11.0;2.0,7.0,12.0;3.0,8.0,13.0;4.0,9.0,14.0;5.0,10.0,15.0})")) {
throw new AssertionFailedError("Identified bug 42564 b");
}
- assertEquals("SUM({1.0,2.0,3.0;4.0,5.0,6.0;7.0,8.0,9.0;10.0,11.0,12.0;13.0,14.0,15.0})", formula);
+ assertEquals("SUM({1.0,2.0,3.0,4.0,5.0;6.0,7.0,8.0,9.0,10.0;11.0,12.0,13.0,14.0,15.0})", formula);
}
public void testToFormulaString() {
}
throw e;
}
- assertEquals("{TRUE,\"ABCD\";\"E\",0.0;FALSE,\"FG\"}", actualFormula);
+ assertEquals("{TRUE,\"ABCD\",\"E\";0.0,FALSE,\"FG\"}", actualFormula);
}
/**
RecordInputStream in = new TestcaseRecordInputStream(ArrayPtg.sid, fullData);
Ptg[] ptgs = Ptg.readTokens(ENCODED_PTG_DATA.length, in);
+ assertEquals(1, ptgs.length);
ArrayPtg aPtg = (ArrayPtg) ptgs[0];
assertEquals(operandClass, aPtg.getPtgClass());
}
public void testEvaluate() {
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls");
HSSFSheet sheet = wb.getSheetAt(0);
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
confirmCellEval(sheet, 0, 0, fe, "YEARFRAC(B1,C1)", 29.0/90.0);
confirmCellEval(sheet, 1, 0, fe, "YEARFRAC(B2,C2)", 0.0);
confirmCellEval(sheet, 2, 0, fe, "YEARFRAC(B3,C3,D3)", 0.0);
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("yearfracExamples.xls");
HSSFSheet sheet = wb.getSheetAt(0);
- HSSFFormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator(wb);
int nSuccess = 0;
int nFailures = 0;
int nUnexpectedErrors = 0;
/**
* Translates StackOverflowError into AssertionFailedError
*/
- private static CellValue evaluateWithCycles(HSSFWorkbook wb, HSSFSheet sheet, HSSFCell testCell)
+ private static CellValue evaluateWithCycles(HSSFWorkbook wb, HSSFCell testCell)
throws AssertionFailedError {
- HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb);
try {
return evaluator.evaluate(testCell);
} catch (StackOverflowError e) {
// arguments before invoking operators, POI must handle such potential cycles gracefully.
- CellValue cellValue = evaluateWithCycles(wb, sheet, testCell);
+ CellValue cellValue = evaluateWithCycles(wb, testCell);
assertTrue(cellValue.getCellType() == HSSFCell.CELL_TYPE_NUMERIC);
assertEquals(2, cellValue.getNumberValue(), 0);
HSSFCell testCell = row.createCell(0);
testCell.setCellFormula("A1");
- CellValue cellValue = evaluateWithCycles(wb, sheet, testCell);
+ CellValue cellValue = evaluateWithCycles(wb, testCell);
confirmCycleErrorCode(cellValue);
}
HSSFCell testCell = row.createCell(3);
testCell.setCellFormula("A1");
- CellValue cellValue = evaluateWithCycles(wb, sheet, testCell);
+ CellValue cellValue = evaluateWithCycles(wb, testCell);
confirmCycleErrorCode(cellValue);
}
String actualFormula=cell.getCellFormula();
assertEquals("myFunc()", actualFormula);
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
CellValue evalResult = fe.evaluate(cell);
// Check the return value from ExternalFunction.evaluate()
.getCellFormula());
// We might as well evaluate the formula
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
CellValue cv = fe.evaluate(cell);
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
}
// use POI's evaluator as an extra sanity check
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
CellValue cv;
cv = fe.evaluate(cell);
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
double expectedResult = (4.0 * 8.0 + 5.0 * 9.0) / 10.0;
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet1, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
CellValue cv = fe.evaluate(cell);
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
throw new AssertionFailedError(msg + " - actual value was null");
}
- if (expected.getCellType() == Cell.CELL_TYPE_STRING) {
- String value = expected.getRichStringCellValue().getString();
- if (value.startsWith("#")) {
- // TODO - this code never called
- expected.setCellType(Cell.CELL_TYPE_ERROR);
- // expected.setCellErrorValue(...?);
- }
- }
-
switch (expected.getCellType()) {
case Cell.CELL_TYPE_BLANK:
assertEquals(msg, Cell.CELL_TYPE_BLANK, actual.getCellType());
break;
case Cell.CELL_TYPE_ERROR:
assertEquals(msg, Cell.CELL_TYPE_ERROR, actual.getCellType());
- if(false) { // TODO: fix ~45 functions which are currently returning incorrect error values
- assertEquals(msg, expected.getErrorCellValue(), actual.getErrorValue());
- }
+ assertEquals(msg, ErrorEval.getText(expected.getErrorCellValue()), ErrorEval.getText(actual.getErrorValue()));
break;
case Cell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation
throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg);
case Cell.CELL_TYPE_NUMERIC:
assertEquals(msg, Cell.CELL_TYPE_NUMERIC, actual.getCellType());
TestMathX.assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR);
-// double delta = Math.abs(expected.getNumericCellValue()-actual.getNumberValue());
-// double pctExpected = Math.abs(0.00001*expected.getNumericCellValue());
-// assertTrue(msg, delta <= pctExpected);
break;
case Cell.CELL_TYPE_STRING:
assertEquals(msg, Cell.CELL_TYPE_STRING, actual.getCellType());
- assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getRichTextStringValue().getString());
+ assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getStringValue());
break;
}
}
- protected void setUp() throws Exception {
+ protected void setUp() {
if (workbook == null) {
workbook = HSSFTestDataSamples.openSampleWorkbook(SS.FILENAME);
sheet = workbook.getSheetAt( 0 );
- }
+ }
_functionFailureCount = 0;
_functionSuccessCount = 0;
_evaluationFailureCount = 0;
* Typically pass <code>null</code> to test all functions
*/
private void processFunctionGroup(int startRowIndex, String testFocusFunctionName) {
-
- FormulaEvaluator evaluator = new FormulaEvaluator(sheet, workbook);
+ FormulaEvaluator evaluator = new FormulaEvaluator(workbook);
int rowIndex = startRowIndex;
while (true) {
result = Result.SOME_EVALUATIONS_FAILED;
}
}
- return result;
+ return result;
}
/**
cell.setCellFormula("B1%");
row.createCell(1).setCellValue(50.0);
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
CellValue cv;
try {
cv = fe.evaluate(cell);
result.addTestSuite(TestDate.class);
result.addTestSuite(TestFinanceLib.class);
result.addTestSuite(TestIndex.class);
+ result.addTestSuite(TestIndexFunctionFromSpreadsheet.class);
result.addTestSuite(TestIsBlank.class);
result.addTestSuite(TestLen.class);
result.addTestSuite(TestLookupFunctionsFromSpreadsheet.class);
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
* Tests for Excel function AVERAGE()
- *
+ *
* @author Josh Micich
*/
public final class TestAverage extends TestCase {
-
private static Eval invokeAverage(Eval[] args) {
- return new Average().evaluate(args, -1, (short)-1);
+ return AggregateFunction.AVERAGE.evaluate(args, -1, (short)-1);
}
private void confirmAverage(Eval[] args, double expected) {
assertEquals(ErrorEval.class, result.getClass());
assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode());
}
-
+
public void testBasic() {
-
+
ValueEval[] values = {
- new NumberEval(1),
- new NumberEval(2),
- new NumberEval(3),
- new NumberEval(4),
+ new NumberEval(1),
+ new NumberEval(2),
+ new NumberEval(3),
+ new NumberEval(4),
};
-
+
confirmAverage(values, 2.5);
-
+
values = new ValueEval[] {
- new NumberEval(1),
+ new NumberEval(1),
new NumberEval(2),
BlankEval.INSTANCE,
- new NumberEval(3),
+ new NumberEval(3),
BlankEval.INSTANCE,
- new NumberEval(4),
+ new NumberEval(4),
BlankEval.INSTANCE,
};
-
+
confirmAverage(values, 2.5);
}
-
+
/**
* Valid cases where values are not pure numbers
*/
public void testUnusualArgs() {
ValueEval[] values = {
- new NumberEval(1),
- new NumberEval(2),
- BoolEval.TRUE,
- BoolEval.FALSE,
+ new NumberEval(1),
+ new NumberEval(2),
+ BoolEval.TRUE,
+ BoolEval.FALSE,
};
-
+
confirmAverage(values, 1.0);
-
+
}
// currently disabled because MultiOperandNumericFunction.getNumberArray(Eval[], int, short)
// does not handle error values properly yet
public void XtestErrors() {
ValueEval[] values = {
- new NumberEval(1),
- ErrorEval.NAME_INVALID,
- new NumberEval(3),
- ErrorEval.DIV_ZERO,
+ new NumberEval(1),
+ ErrorEval.NAME_INVALID,
+ new NumberEval(3),
+ ErrorEval.DIV_ZERO,
};
confirmAverage(values, ErrorEval.NAME_INVALID);
-
+
}
}
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.record.formula.RefPtg;
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;
import org.apache.poi.hssf.record.formula.functions.CountUtils.I_MatchPredicate;
int failureCount = 0;
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(FILE_NAME);
HSSFSheet sheet = wb.getSheetAt(0);
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
int maxRow = sheet.getLastRowNum();
for (int rowIx=START_ROW_IX; rowIx<maxRow; rowIx++) {
HSSFRow row = sheet.getRow(rowIx);
HSSFSheet sheet = wb.createSheet("new sheet");
cell11 = sheet.createRow(0).createCell(0);
cell11.setCellType(HSSFCell.CELL_TYPE_FORMULA);
- evaluator = new HSSFFormulaEvaluator(sheet, wb);
+ evaluator = new HSSFFormulaEvaluator(wb);
}
/**
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);
+ 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);
+ confirmAreaEval("C10:E13", values, 4, 1, 10);
}
/**
--- /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.hssf.record.formula.functions;
+
+import java.io.PrintStream;
+
+import junit.framework.Assert;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.CellReference;
+import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue;
+
+/**
+ * Tests INDEX() as loaded from a test data spreadsheet.<p/>
+ *
+ * @author Josh Micich
+ */
+public final class TestIndexFunctionFromSpreadsheet extends TestCase {
+
+ private static final class Result {
+ public static final int SOME_EVALUATIONS_FAILED = -1;
+ public static final int ALL_EVALUATIONS_SUCCEEDED = +1;
+ public static final int NO_EVALUATIONS_FOUND = 0;
+ }
+
+ /**
+ * This class defines constants for navigating around the test data spreadsheet used for these tests.
+ */
+ private static final class SS {
+
+ /** Name of the test spreadsheet (found in the standard test data folder) */
+ public final static String FILENAME = "IndexFunctionTestCaseData.xls";
+
+ public static final int COLUMN_INDEX_EVALUATION = 2; // Column 'C'
+ public static final int COLUMN_INDEX_EXPECTED_RESULT = 3; // Column 'D'
+
+ }
+
+ // Note - multiple failures are aggregated before ending.
+ // If one or more functions fail, a single AssertionFailedError is thrown at the end
+ private int _evaluationFailureCount;
+ private int _evaluationSuccessCount;
+
+
+
+ private static void confirmExpectedResult(String msg, HSSFCell expected, HSSFFormulaEvaluator.CellValue actual) {
+ if (expected == null) {
+ throw new AssertionFailedError(msg + " - Bad setup data expected value is null");
+ }
+ if(actual == null) {
+ throw new AssertionFailedError(msg + " - actual value was null");
+ }
+ if(expected.getCellType() == HSSFCell.CELL_TYPE_ERROR) {
+ confirmErrorResult(msg, expected.getErrorCellValue(), actual);
+ return;
+ }
+ if(actual.getCellType() == HSSFCell.CELL_TYPE_ERROR) {
+ throw unexpectedError(msg, expected, actual.getErrorValue());
+ }
+ if(actual.getCellType() != expected.getCellType()) {
+ throw wrongTypeError(msg, expected, actual);
+ }
+
+
+ switch (expected.getCellType()) {
+ case HSSFCell.CELL_TYPE_BOOLEAN:
+ assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue());
+ break;
+ case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation
+ throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg);
+ case HSSFCell.CELL_TYPE_NUMERIC:
+ assertEquals(expected.getNumericCellValue(), actual.getNumberValue(), 0.0);
+ break;
+ case HSSFCell.CELL_TYPE_STRING:
+ assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getStringValue());
+ break;
+ }
+ }
+
+
+ private static AssertionFailedError wrongTypeError(String msgPrefix, HSSFCell expectedCell, CellValue actualValue) {
+ return new AssertionFailedError(msgPrefix + " Result type mismatch. Evaluated result was "
+ + actualValue.formatAsString()
+ + " but the expected result was "
+ + formatValue(expectedCell)
+ );
+ }
+ private static AssertionFailedError unexpectedError(String msgPrefix, HSSFCell expected, int actualErrorCode) {
+ return new AssertionFailedError(msgPrefix + " Error code ("
+ + ErrorEval.getText(actualErrorCode)
+ + ") was evaluated, but the expected result was "
+ + formatValue(expected)
+ );
+ }
+
+
+ private static void confirmErrorResult(String msgPrefix, int expectedErrorCode, CellValue actual) {
+ if(actual.getCellType() != HSSFCell.CELL_TYPE_ERROR) {
+ throw new AssertionFailedError(msgPrefix + " Expected cell error ("
+ + ErrorEval.getText(expectedErrorCode) + ") but actual value was "
+ + actual.formatAsString());
+ }
+ if(expectedErrorCode != actual.getErrorValue()) {
+ throw new AssertionFailedError(msgPrefix + " Expected cell error code ("
+ + ErrorEval.getText(expectedErrorCode)
+ + ") but actual error code was ("
+ + ErrorEval.getText(actual.getErrorValue())
+ + ")");
+ }
+ }
+
+
+ private static String formatValue(HSSFCell expecedCell) {
+ switch (expecedCell.getCellType()) {
+ case HSSFCell.CELL_TYPE_BLANK: return "<blank>";
+ case HSSFCell.CELL_TYPE_BOOLEAN: return String.valueOf(expecedCell.getBooleanCellValue());
+ case HSSFCell.CELL_TYPE_NUMERIC: return String.valueOf(expecedCell.getNumericCellValue());
+ case HSSFCell.CELL_TYPE_STRING: return expecedCell.getRichStringCellValue().getString();
+ }
+ throw new RuntimeException("Unexpected cell type of expected value (" + expecedCell.getCellType() + ")");
+ }
+
+
+ protected void setUp() {
+ _evaluationFailureCount = 0;
+ _evaluationSuccessCount = 0;
+ }
+
+ public void testFunctionsFromTestSpreadsheet() {
+ HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook(SS.FILENAME);
+
+ processTestSheet(workbook, workbook.getSheetName(0));
+
+ // confirm results
+ String successMsg = "There were "
+ + _evaluationSuccessCount + " function(s) without error";
+ if(_evaluationFailureCount > 0) {
+ String msg = _evaluationFailureCount + " evaluation(s) failed. " + successMsg;
+ throw new AssertionFailedError(msg);
+ }
+ if(false) { // normally no output for successful tests
+ System.out.println(getClass().getName() + ": " + successMsg);
+ }
+ }
+
+ private void processTestSheet(HSSFWorkbook workbook, String sheetName) {
+ HSSFSheet sheet = workbook.getSheetAt(0);
+ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook);
+ int maxRows = sheet.getLastRowNum()+1;
+ int result = Result.NO_EVALUATIONS_FOUND; // so far
+
+ for(int rowIndex=0; rowIndex<maxRows; rowIndex++) {
+ HSSFRow r = sheet.getRow(rowIndex);
+ if(r == null) {
+ continue;
+ }
+ HSSFCell c = r.getCell(SS.COLUMN_INDEX_EVALUATION);
+ if (c == null || c.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
+ continue;
+ }
+ CellValue actualValue = evaluator.evaluate(c);
+ HSSFCell expectedValueCell = r.getCell(SS.COLUMN_INDEX_EXPECTED_RESULT);
+
+ String msgPrefix = formatTestCaseDetails(sheetName, r.getRowNum(), c);
+ try {
+ confirmExpectedResult(msgPrefix, expectedValueCell, actualValue);
+ _evaluationSuccessCount ++;
+ if(result != Result.SOME_EVALUATIONS_FAILED) {
+ result = Result.ALL_EVALUATIONS_SUCCEEDED;
+ }
+ } catch (RuntimeException e) {
+ _evaluationFailureCount ++;
+ printShortStackTrace(System.err, e);
+ result = Result.SOME_EVALUATIONS_FAILED;
+ } catch (AssertionFailedError e) {
+ _evaluationFailureCount ++;
+ printShortStackTrace(System.err, e);
+ result = Result.SOME_EVALUATIONS_FAILED;
+ }
+
+ }
+ }
+
+
+ private static String formatTestCaseDetails(String sheetName, int rowNum, HSSFCell c) {
+
+ StringBuffer sb = new StringBuffer();
+ CellReference cr = new CellReference(sheetName, rowNum, c.getCellNum(), false, false);
+ sb.append(cr.formatAsString());
+ sb.append(" {=").append(c.getCellFormula()).append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Useful to keep output concise when expecting many failures to be reported by this test case
+ */
+ private static void printShortStackTrace(PrintStream ps, Throwable e) {
+ StackTraceElement[] stes = e.getStackTrace();
+
+ int startIx = 0;
+ // skip any top frames inside junit.framework.Assert
+ while(startIx<stes.length) {
+ if(!stes[startIx].getClassName().equals(Assert.class.getName())) {
+ break;
+ }
+ startIx++;
+ }
+ // skip bottom frames (part of junit framework)
+ int endIx = startIx+1;
+ while(endIx < stes.length) {
+ if(stes[endIx].getClassName().equals(TestCase.class.getName())) {
+ break;
+ }
+ endIx++;
+ }
+ if(startIx >= endIx) {
+ // something went wrong. just print the whole stack trace
+ e.printStackTrace(ps);
+ }
+ endIx -= 4; // skip 4 frames of reflection invocation
+ ps.println(e.toString());
+ for(int i=startIx; i<endIx; i++) {
+ ps.println("\tat " + stes[i].toString());
+ }
+ }
+}
+
cell.setCellFormula("isblank(Sheet2!A1:A1)");
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet1, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
CellValue result = fe.evaluate(cell);
assertEquals(HSSFCell.CELL_TYPE_BOOLEAN, result.getCellType());
assertEquals(true, result.getBooleanValue());
private static Eval invokeLen(Eval text) {
Eval[] args = new Eval[] { text, };
- return new Len().evaluate(args, -1, (short)-1);
+ return TextFunction.LEN.evaluate(args, -1, (short)-1);
}
private void confirmLen(Eval text, int expected) {
* Tests lookup functions (VLOOKUP, HLOOKUP, LOOKUP, MATCH) as loaded from a test data spreadsheet.<p/>
* These tests have been separated from the common function and operator tests because the lookup
* functions have more complex test cases and test data setup.
- *
+ *
* Tests for bug fixes and specific/tricky behaviour can be found in the corresponding test class
* (<tt>TestXxxx</tt>) of the target (<tt>Xxxx</tt>) implementor, where execution can be observed
* more easily.
- *
+ *
* @author Josh Micich
*/
public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
-
+
private static final class Result {
public static final int SOME_EVALUATIONS_FAILED = -1;
public static final int ALL_EVALUATIONS_SUCCEEDED = +1;
public static final int NO_EVALUATIONS_FOUND = 0;
}
- /**
+ /**
* This class defines constants for navigating around the test data spreadsheet used for these tests.
*/
private static final class SS {
-
+
/** Name of the test spreadsheet (found in the standard test data folder) */
public final static String FILENAME = "LookupFunctionsTestCaseData.xls";
-
+
/** Name of the first sheet in the spreadsheet (contains comments) */
public final static String README_SHEET_NAME = "Read Me";
-
-
+
+
/** Row (zero-based) in each sheet where the evaluation cases start. */
public static final int START_TEST_CASES_ROW_INDEX = 4; // Row '5'
/** Index of the column that contains the function names */
public static final int COLUMN_INDEX_EVALUATION = 1; // Column 'B'
public static final int COLUMN_INDEX_EXPECTED_RESULT = 2; // Column 'C'
public static final int COLUMN_ROW_COMMENT = 3; // Column 'D'
-
+
/** Used to indicate when there are no more test cases on the current sheet */
public static final String TEST_CASES_END_MARKER = "<end>";
/** Used to indicate that the test on the current row should be ignored */
public static final String SKIP_CURRENT_TEST_CASE_MARKER = "<skip>";
-
+
}
- // Note - multiple failures are aggregated before ending.
+ // Note - multiple failures are aggregated before ending.
// If one or more functions fail, a single AssertionFailedError is thrown at the end
private int _sheetFailureCount;
private int _sheetSuccessCount;
if(actual.getCellType() != expected.getCellType()) {
throw wrongTypeError(msg, expected, actual);
}
-
-
+
+
switch (expected.getCellType()) {
case HSSFCell.CELL_TYPE_BOOLEAN:
assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue());
break;
case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation
- throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg);
+ throw new IllegalStateException("Cannot expect formula as result of formula evaluation: " + msg);
case HSSFCell.CELL_TYPE_NUMERIC:
assertEquals(expected.getNumericCellValue(), actual.getNumberValue(), 0.0);
break;
case HSSFCell.CELL_TYPE_STRING:
- assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getRichTextStringValue().getString());
+ assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getStringValue());
break;
}
}
private static AssertionFailedError wrongTypeError(String msgPrefix, HSSFCell expectedCell, CellValue actualValue) {
return new AssertionFailedError(msgPrefix + " Result type mismatch. Evaluated result was "
- + formatValue(actualValue)
+ + actualValue.formatAsString()
+ " but the expected result was "
+ formatValue(expectedCell)
);
}
private static AssertionFailedError unexpectedError(String msgPrefix, HSSFCell expected, int actualErrorCode) {
return new AssertionFailedError(msgPrefix + " Error code ("
- + ErrorEval.getText(actualErrorCode)
+ + ErrorEval.getText(actualErrorCode)
+ ") was evaluated, but the expected result was "
+ formatValue(expected)
);
private static void confirmErrorResult(String msgPrefix, int expectedErrorCode, CellValue actual) {
if(actual.getCellType() != HSSFCell.CELL_TYPE_ERROR) {
- throw new AssertionFailedError(msgPrefix + " Expected cell error ("
+ throw new AssertionFailedError(msgPrefix + " Expected cell error ("
+ ErrorEval.getText(expectedErrorCode) + ") but actual value was "
- + formatValue(actual));
+ + actual.formatAsString());
}
if(expectedErrorCode != actual.getErrorValue()) {
- throw new AssertionFailedError(msgPrefix + " Expected cell error code ("
- + ErrorEval.getText(expectedErrorCode)
+ throw new AssertionFailedError(msgPrefix + " Expected cell error code ("
+ + ErrorEval.getText(expectedErrorCode)
+ ") but actual error code was ("
- + ErrorEval.getText(actual.getErrorValue())
+ + ErrorEval.getText(actual.getErrorValue())
+ ")");
}
}
}
throw new RuntimeException("Unexpected cell type of expected value (" + expecedCell.getCellType() + ")");
}
- private static String formatValue(CellValue actual) {
- switch (actual.getCellType()) {
- case HSSFCell.CELL_TYPE_BLANK: return "<blank>";
- case HSSFCell.CELL_TYPE_BOOLEAN: return String.valueOf(actual.getBooleanValue());
- case HSSFCell.CELL_TYPE_NUMERIC: return String.valueOf(actual.getNumberValue());
- case HSSFCell.CELL_TYPE_STRING: return actual.getRichTextStringValue().getString();
- }
- throw new RuntimeException("Unexpected cell type of evaluated value (" + actual.getCellType() + ")");
- }
- protected void setUp() throws Exception {
+ protected void setUp() {
_sheetFailureCount = 0;
_sheetSuccessCount = 0;
_evaluationFailureCount = 0;
_evaluationSuccessCount = 0;
}
-
+
public void testFunctionsFromTestSpreadsheet() {
HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook(SS.FILENAME);
-
+
confirmReadMeSheet(workbook);
int nSheets = workbook.getNumberOfSheets();
for(int i=1; i< nSheets; i++) {
int sheetResult = processTestSheet(workbook, i, workbook.getSheetName(i));
switch(sheetResult) {
- case Result.ALL_EVALUATIONS_SUCCEEDED: _sheetSuccessCount ++; break;
- case Result.SOME_EVALUATIONS_FAILED: _sheetFailureCount ++; break;
+ case Result.ALL_EVALUATIONS_SUCCEEDED: _sheetSuccessCount ++; break;
+ case Result.SOME_EVALUATIONS_FAILED: _sheetFailureCount ++; break;
}
}
-
+
// confirm results
- String successMsg = "There were "
+ String successMsg = "There were "
+ _sheetSuccessCount + " successful sheets(s) and "
+ _evaluationSuccessCount + " function(s) without error";
- if(_sheetFailureCount > 0) {
+ if(_sheetFailureCount > 0) {
String msg = _sheetFailureCount + " sheets(s) failed with "
+ _evaluationFailureCount + " evaluation(s). " + successMsg;
throw new AssertionFailedError(msg);
}
- if(false) { // normally no output for successful tests
- System.out.println(getClass().getName() + ": " + successMsg);
- }
+ if(false) { // normally no output for successful tests
+ System.out.println(getClass().getName() + ": " + successMsg);
+ }
}
private int processTestSheet(HSSFWorkbook workbook, int sheetIndex, String sheetName) {
HSSFSheet sheet = workbook.getSheetAt(sheetIndex);
- HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, workbook);
+ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook);
int maxRows = sheet.getLastRowNum()+1;
int result = Result.NO_EVALUATIONS_FOUND; // so far
-
+
String currentGroupComment = null;
for(int rowIndex=SS.START_TEST_CASES_ROW_INDEX; rowIndex<maxRows; rowIndex++) {
HSSFRow r = sheet.getRow(rowIndex);
CellValue actualValue = evaluator.evaluate(c);
HSSFCell expectedValueCell = r.getCell(SS.COLUMN_INDEX_EXPECTED_RESULT);
String rowComment = getRowCommentColumnValue(r);
-
+
String msgPrefix = formatTestCaseDetails(sheetName, r.getRowNum(), c, currentGroupComment, rowComment);
try {
confirmExpectedResult(msgPrefix, expectedValueCell, actualValue);
printShortStackTrace(System.err, e);
result = Result.SOME_EVALUATIONS_FAILED;
}
-
+
}
- throw new RuntimeException("Missing end marker '" + SS.TEST_CASES_END_MARKER
+ throw new RuntimeException("Missing end marker '" + SS.TEST_CASES_END_MARKER
+ "' on sheet '" + sheetName + "'");
-
+
}
private static String formatTestCaseDetails(String sheetName, int rowNum, HSSFCell c, String currentGroupComment,
String rowComment) {
-
+
StringBuffer sb = new StringBuffer();
CellReference cr = new CellReference(sheetName, rowNum, c.getCellNum(), false, false);
sb.append(cr.formatAsString());
sb.append(" {=").append(c.getCellFormula()).append("}");
-
+
if(currentGroupComment != null) {
sb.append(" '");
sb.append(currentGroupComment);
sb.append("' ");
}
}
-
+
return sb.toString();
}
/**
- * Asserts that the 'read me' comment page exists, and has this class' name in one of the
- * cells. This back-link is to make it easy to find this class if a reader encounters the
+ * Asserts that the 'read me' comment page exists, and has this class' name in one of the
+ * cells. This back-link is to make it easy to find this class if a reader encounters the
* spreadsheet first.
*/
private void confirmReadMeSheet(HSSFWorkbook workbook) {
*/
private static void printShortStackTrace(PrintStream ps, Throwable e) {
StackTraceElement[] stes = e.getStackTrace();
-
+
int startIx = 0;
// skip any top frames inside junit.framework.Assert
while(startIx<stes.length) {
for(int i=startIx; i<endIx; i++) {
ps.println("\tat " + stes[i].toString());
}
-
+
}
private static String getRowCommentColumnValue(HSSFRow r) {
return getCellTextValue(r, SS.COLUMN_ROW_COMMENT, "row comment");
}
-
+
private static String getMarkerColumnValue(HSSFRow r) {
return getCellTextValue(r, SS.COLUMN_INDEX_MARKER, "marker");
}
-
+
/**
* @return <code>null</code> if cell is missing, empty or blank
*/
if(cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
return cell.getRichStringCellValue().getString();
}
-
+
throw new RuntimeException("Bad cell type for '" + columnName + "' column: ("
+ cell.getCellType() + ") row (" + (r.getRowNum() +1) + ")");
}
private static Eval invokeMid(Eval text, Eval startPos, Eval numChars) {
Eval[] args = new Eval[] { text, startPos, numChars, };
- return new Mid().evaluate(args, -1, (short)-1);
+ return TextFunction.MID.evaluate(args, -1, (short)-1);
}
private void confirmMid(Eval text, Eval startPos, Eval numChars, String expected) {
assertEquals(expected, ne.getNumberValue(), 0.00005);
}
private static Eval invoke(Eval[] args) {
- return new Pmt().evaluate(args, -1, (short)-1);
+ return FinanceFunction.PMT.evaluate(args, -1, (short)-1);
}
/**
* Invocation when not expecting an error result
package org.apache.poi.hssf.record.formula.functions;
+import junit.framework.TestCase;
+
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.StringEval;
-import junit.framework.TestCase;
-
/**
* Test cases for ROUND(), ROUNDUP(), ROUNDDOWN()
*
* @author Josh Micich
*/
public final class TestRoundFuncs extends TestCase {
+ private static final NumericFunction F = null;
public void testRounddownWithStringArg() {
Eval strArg = new StringEval("abc");
Eval[] args = { strArg, new NumberEval(2), };
- Eval result = new Rounddown().evaluate(args, -1, (short)-1);
+ Eval result = F.ROUNDDOWN.evaluate(args, -1, (short)-1);
assertEquals(ErrorEval.VALUE_INVALID, result);
}
Eval strArg = new StringEval("abc");
Eval[] args = { strArg, new NumberEval(2), };
- Eval result = new Roundup().evaluate(args, -1, (short)-1);
+ Eval result = F.ROUNDUP.evaluate(args, -1, (short)-1);
assertEquals(ErrorEval.VALUE_INVALID, result);
}
*/
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.EvaluationException;
+
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
}
public void testMode() {
- double[] v = null;
+ double[] v;
double d, x = 0;
v = new double[] {1,2,3,4,5,6,7,8,9,10};
- d = StatsLib.mode(v);
- x = Double.NaN;
- assertEquals("mode ", x, d);
+ confirmMode(v, null);
v = new double[] {1,1,1,1,1,1,1,1,1,1};
- d = StatsLib.mode(v);
- x = 1;
- assertEquals("mode ", x, d);
+ confirmMode(v, 1.0);
v = new double[] {0,0,0,0,0,0,0,0,0,0};
- d = StatsLib.mode(v);
- x = 0;
- assertEquals("mode ", x, d);
+ confirmMode(v, 0.0);
v = new double[] {1,2,1,2,1,2,1,2,1,2};
- d = StatsLib.mode(v);
- x = 1;
- assertEquals("mode ", x, d);
+ confirmMode(v, 1.0);
v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999};
- d = StatsLib.mode(v);
- x = Double.NaN;
- assertEquals("mode ", x, d);
+ confirmMode(v, null);
v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10};
- d = StatsLib.mode(v);
- x = Double.NaN;
- assertEquals("mode ", x, d);
+ confirmMode(v, null);
v = new double[] {1,2,3,4,1,1,1,1,0,0,0,0,0};
- d = StatsLib.mode(v);
- x = 1;
- assertEquals("mode ", x, d);
+ confirmMode(v, 1.0);
v = new double[] {0,1,2,3,4,1,1,1,0,0,0,0,1};
- d = StatsLib.mode(v);
- x = 0;
- assertEquals("mode ", x, d);
+ confirmMode(v, 0.0);
+ }
+ private static void confirmMode(double[] v, double expectedResult) {
+ confirmMode(v, new Double(expectedResult));
+ }
+ private static void confirmMode(double[] v, Double expectedResult) {
+ double actual;
+ try {
+ actual = Mode.evaluate(v);
+ if (expectedResult == null) {
+ throw new AssertionFailedError("Expected N/A exception was not thrown");
+ }
+ } catch (EvaluationException e) {
+ if (expectedResult == null) {
+ assertEquals(ErrorEval.NA, e.getErrorEval());
+ return;
+ }
+ throw new RuntimeException(e);
+ }
+ assertEquals("mode", expectedResult.doubleValue(), actual);
}
+
public void testStddev() {
double[] v = null;
private static Eval invokeTrim(Eval text) {
Eval[] args = new Eval[] { text, };
- return new Trim().evaluate(args, -1, (short)-1);
+ return TextFunction.TRIM.evaluate(args, -1, (short)-1);
}
private void confirmTrim(Eval text, String expected) {
}
private static void process(HSSFWorkbook wb) {
+ HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(wb);
for(int i=0; i<wb.getNumberOfSheets(); i++) {
HSSFSheet s = wb.getSheetAt(i);
- HSSFFormulaEvaluator eval =
- new HSSFFormulaEvaluator(s, wb);
Iterator it = s.rowIterator();
while(it.hasNext()) {
}
public void testBug43093() {
- HSSFWorkbook xlw = new HSSFWorkbook();
+ HSSFWorkbook xlw = new HSSFWorkbook();
addNewSheetWithCellsA1toD4(xlw, 1);
addNewSheetWithCellsA1toD4(xlw, 2);
HSSFCell s2E4 = s2r3.createCell(4);
s2E4.setCellFormula("SUM(s3!B2:C3)");
- HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(s2, xlw);
+ HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(xlw);
double d = eva.evaluate(s2E4).getNumberValue();
// internalEvaluate(...) Area3DEval.: 311+312+321+322 expected
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);
}
-
+
/**
* Problems with extracting check boxes from
* HSSFObjectData
// Take a look at the embeded objects
List objects = wb.getAllEmbeddedObjects();
assertEquals(1, objects.size());
-
+
HSSFObjectData obj = (HSSFObjectData)objects.get(0);
assertNotNull(obj);
-
+
// Peek inside the underlying record
EmbeddedObjectRefSubRecord rec = obj.findObjectRecord();
assertNotNull(rec);
-
+
assertEquals(32, rec.field_1_stream_id_offset);
assertEquals(0, rec.field_6_stream_id); // WRONG!
assertEquals("Forms.CheckBox.1", rec.field_5_ole_classname);
assertEquals(12, rec.remainingBytes.length);
-
+
// Doesn't have a directory
assertFalse(obj.hasDirectoryEntry());
assertNotNull(obj.getObjectData());
assertEquals(12, obj.getObjectData().length);
assertEquals("Forms.CheckBox.1", obj.getOLE2ClassName());
-
+
try {
obj.getDirectory();
fail();
} catch(FileNotFoundException e) {
- // expectd during successful test
+ // expectd during successful test
} catch (IOException e) {
- throw new RuntimeException(e);
- }
+ throw new RuntimeException(e);
+ }
}
-
+
/**
* Test that we can delete sheets without
* breaking the build in named ranges
HSSFWorkbook wb = openSample("30978-alt.xls");
assertEquals(1, wb.getNumberOfNames());
assertEquals(3, wb.getNumberOfSheets());
-
+
// Check all names fit within range, and use
// DeletedArea3DPtg
Workbook w = wb.getWorkbook();
for(int i=0; i<w.getNumNames(); i++) {
NameRecord r = w.getNameRecord(i);
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
-
+
Ptg[] nd = r.getNameDefinition();
assertEquals(1, nd.length);
assertTrue(nd[0] instanceof DeletedArea3DPtg);
}
-
-
+
+
// Delete the 2nd sheet
wb.removeSheetAt(1);
-
-
+
+
// Re-check
assertEquals(1, wb.getNumberOfNames());
assertEquals(2, wb.getNumberOfSheets());
-
+
for(int i=0; i<w.getNumNames(); i++) {
NameRecord r = w.getNameRecord(i);
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
-
+
Ptg[] nd = r.getNameDefinition();
assertEquals(1, nd.length);
assertTrue(nd[0] instanceof DeletedArea3DPtg);
}
-
-
+
+
// Save and re-load
wb = writeOutAndReadBack(wb);
w = wb.getWorkbook();
-
+
assertEquals(1, wb.getNumberOfNames());
assertEquals(2, wb.getNumberOfSheets());
-
+
for(int i=0; i<w.getNumNames(); i++) {
NameRecord r = w.getNameRecord(i);
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
-
+
Ptg[] nd = r.getNameDefinition();
assertEquals(1, nd.length);
assertTrue(nd[0] instanceof DeletedArea3DPtg);
}
}
-
+
/**
* Test that fonts get added properly
*/
public void test45338() {
HSSFWorkbook wb = new HSSFWorkbook();
assertEquals(4, wb.getNumberOfFonts());
-
+
HSSFSheet s = wb.createSheet();
s.createRow(0);
s.createRow(1);
HSSFCell c1 = s.getRow(0).createCell(0);
HSSFCell c2 = s.getRow(1).createCell(0);
-
+
assertEquals(4, wb.getNumberOfFonts());
-
+
HSSFFont f1 = wb.getFontAt((short)0);
assertEquals(400, f1.getBoldweight());
-
+
// Check that asking for the same font
// multiple times gives you the same thing.
// Otherwise, our tests wouldn't work!
!=
wb.getFontAt((short)2)
);
-
+
// Look for a new font we have
// yet to add
assertNull(
wb.findFont(
- (short)11, (short)123, (short)22,
+ (short)11, (short)123, (short)22,
"Thingy", false, true, (short)2, (byte)2
)
);
-
+
HSSFFont nf = wb.createFont();
assertEquals(5, wb.getNumberOfFonts());
-
+
assertEquals(5, nf.getIndex());
assertEquals(nf, wb.getFontAt((short)5));
-
+
nf.setBoldweight((short)11);
nf.setColor((short)123);
nf.setFontHeight((short)22);
nf.setStrikeout(true);
nf.setTypeOffset((short)2);
nf.setUnderline((byte)2);
-
+
assertEquals(5, wb.getNumberOfFonts());
assertEquals(nf, wb.getFontAt((short)5));
-
+
// Find it now
assertNotNull(
wb.findFont(
- (short)11, (short)123, (short)22,
+ (short)11, (short)123, (short)22,
"Thingy", false, true, (short)2, (byte)2
)
);
assertEquals(
5,
wb.findFont(
- (short)11, (short)123, (short)22,
+ (short)11, (short)123, (short)22,
"Thingy", false, true, (short)2, (byte)2
).getIndex()
);
assertEquals(nf,
wb.findFont(
- (short)11, (short)123, (short)22,
+ (short)11, (short)123, (short)22,
"Thingy", false, true, (short)2, (byte)2
)
);
}
-
+
/**
* From the mailing list - ensure we can handle a formula
* containing a zip code, eg ="70164"
c1.setCellFormula("70164");
c2.setCellFormula("\"70164\"");
c3.setCellFormula("\"90210\"");
-
+
// Check the formulas
assertEquals("70164.0", c1.getCellFormula());
assertEquals("\"70164\"", c2.getCellFormula());
-
+
// And check the values - blank
- assertEquals(0.0, c1.getNumericCellValue(), 0.00001);
- assertEquals("", c1.getRichStringCellValue().getString());
- assertEquals(0.0, c2.getNumericCellValue(), 0.00001);
- assertEquals("", c2.getRichStringCellValue().getString());
- assertEquals(0.0, c3.getNumericCellValue(), 0.00001);
- assertEquals("", c3.getRichStringCellValue().getString());
-
+ confirmCachedValue(0.0, c1);
+ confirmCachedValue(0.0, c2);
+ confirmCachedValue(0.0, c3);
+
// Try changing the cached value on one of the string
// formula cells, so we can see it updates properly
c3.setCellValue(new HSSFRichTextString("test"));
- assertEquals(0.0, c3.getNumericCellValue(), 0.00001);
- assertEquals("test", c3.getRichStringCellValue().getString());
-
-
+ confirmCachedValue("test", c3);
+ try {
+ c3.getNumericCellValue();
+ throw new AssertionFailedError("exception should have been thrown");
+ } catch (IllegalStateException e) {
+ assertEquals("Cannot get a numeric value from a text formula cell", e.getMessage());
+ }
+
+
// Now evaluate, they should all be changed
- HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(s, wb);
+ HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(wb);
eval.evaluateFormulaCell(c1);
eval.evaluateFormulaCell(c2);
eval.evaluateFormulaCell(c3);
-
+
// Check that the cells now contain
// the correct values
- assertEquals(70164.0, c1.getNumericCellValue(), 0.00001);
- assertEquals("", c1.getRichStringCellValue().getString());
- assertEquals(0.0, c2.getNumericCellValue(), 0.00001);
- assertEquals("70164", c2.getRichStringCellValue().getString());
- assertEquals(0.0, c3.getNumericCellValue(), 0.00001);
- assertEquals("90210", c3.getRichStringCellValue().getString());
-
-
+ confirmCachedValue(70164.0, c1);
+ confirmCachedValue("70164", c2);
+ confirmCachedValue("90210", c3);
+
+
// Write and read
HSSFWorkbook nwb = writeOutAndReadBack(wb);
HSSFSheet ns = nwb.getSheetAt(0);
HSSFCell nc1 = ns.getRow(0).getCell(0);
HSSFCell nc2 = ns.getRow(0).getCell(1);
HSSFCell nc3 = ns.getRow(0).getCell(2);
-
+
// Re-check
- assertEquals(70164.0, nc1.getNumericCellValue(), 0.00001);
- assertEquals("", nc1.getRichStringCellValue().getString());
- assertEquals(0.0, nc2.getNumericCellValue(), 0.00001);
- assertEquals("70164", nc2.getRichStringCellValue().getString());
- assertEquals(0.0, nc3.getNumericCellValue(), 0.00001);
- assertEquals("90210", nc3.getRichStringCellValue().getString());
-
+ confirmCachedValue(70164.0, nc1);
+ confirmCachedValue("70164", nc2);
+ confirmCachedValue("90210", nc3);
+
CellValueRecordInterface[] cvrs = ns.getSheet().getValueRecords();
for (int i = 0; i < cvrs.length; i++) {
CellValueRecordInterface cvr = cvrs[i];
if(cvr instanceof FormulaRecordAggregate) {
FormulaRecordAggregate fr = (FormulaRecordAggregate)cvr;
-
+
if(i == 0) {
assertEquals(70164.0, fr.getFormulaRecord().getValue(), 0.0001);
assertNull(fr.getStringRecord());
}
assertEquals(3, cvrs.length);
}
-
+
+ private static void confirmCachedValue(double expectedValue, HSSFCell cell) {
+ assertEquals(HSSFCell.CELL_TYPE_FORMULA, cell.getCellType());
+ assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
+ assertEquals(expectedValue, cell.getNumericCellValue(), 0.0);
+ }
+ private static void confirmCachedValue(String expectedValue, HSSFCell cell) {
+ assertEquals(HSSFCell.CELL_TYPE_FORMULA, cell.getCellType());
+ assertEquals(HSSFCell.CELL_TYPE_STRING, cell.getCachedFormulaResultType());
+ assertEquals(expectedValue, cell.getRichStringCellValue().getString());
+ }
+
/**
* Problem with "Vector Rows", eg a whole
* column which is set to the result of
* {=sin(B1:B9){9,1)[rownum][0]
* In this sample file, the vector column
* is C, and the data column is B.
- *
+ *
* For now, blows up with an exception from ExtPtg
* Expected ExpPtg to be converted from Shared to Non-Shared...
*/
public void DISABLEDtest43623() {
HSSFWorkbook wb = openSample("43623.xls");
assertEquals(1, wb.getNumberOfSheets());
-
+
HSSFSheet s1 = wb.getSheetAt(0);
-
+
HSSFCell c1 = s1.getRow(0).getCell(2);
HSSFCell c2 = s1.getRow(1).getCell(2);
HSSFCell c3 = s1.getRow(2).getCell(2);
-
+
// These formula contents are a guess...
assertEquals("{=sin(B1:B9){9,1)[0][0]", c1.getCellFormula());
assertEquals("{=sin(B1:B9){9,1)[1][0]", c2.getCellFormula());
assertEquals("{=sin(B1:B9){9,1)[2][0]", c3.getCellFormula());
-
+
// Save and re-open, ensure it still works
HSSFWorkbook nwb = writeOutAndReadBack(wb);
HSSFSheet ns1 = nwb.getSheetAt(0);
HSSFCell nc1 = ns1.getRow(0).getCell(2);
HSSFCell nc2 = ns1.getRow(1).getCell(2);
HSSFCell nc3 = ns1.getRow(2).getCell(2);
-
+
assertEquals("{=sin(B1:B9){9,1)[0][0]", nc1.getCellFormula());
assertEquals("{=sin(B1:B9){9,1)[1][0]", nc2.getCellFormula());
assertEquals("{=sin(B1:B9){9,1)[2][0]", nc3.getCellFormula());
}
-
+
/**
* People are all getting confused about the last
* row and cell number
public void test30635() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
-
+
// No rows, everything is 0
assertEquals(0, s.getFirstRowNum());
assertEquals(0, s.getLastRowNum());
assertEquals(0, s.getPhysicalNumberOfRows());
-
+
// One row, most things are 0, physical is 1
s.createRow(0);
assertEquals(0, s.getFirstRowNum());
assertEquals(0, s.getLastRowNum());
assertEquals(1, s.getPhysicalNumberOfRows());
-
+
// And another, things change
s.createRow(4);
assertEquals(0, s.getFirstRowNum());
assertEquals(4, s.getLastRowNum());
assertEquals(2, s.getPhysicalNumberOfRows());
-
-
+
+
// Now start on cells
HSSFRow r = s.getRow(0);
assertEquals(-1, r.getFirstCellNum());
assertEquals(-1, r.getLastCellNum());
assertEquals(0, r.getPhysicalNumberOfCells());
-
+
// Add a cell, things move off -1
r.createCell(0);
assertEquals(0, r.getFirstCellNum());
assertEquals(1, r.getLastCellNum()); // last cell # + 1
assertEquals(1, r.getPhysicalNumberOfCells());
-
+
r.createCell(1);
assertEquals(0, r.getFirstCellNum());
assertEquals(2, r.getLastCellNum()); // last cell # + 1
assertEquals(2, r.getPhysicalNumberOfCells());
-
+
r.createCell(4);
assertEquals(0, r.getFirstCellNum());
assertEquals(5, r.getLastCellNum()); // last cell # + 1
assertEquals(3, r.getPhysicalNumberOfCells());
}
-
+
/**
* Data Tables - ptg 0x2
*/
HSSFSheet s;
HSSFRow r;
HSSFCell c;
-
+
// Check the contents of the formulas
-
+
// E4 to G9 of sheet 4 make up the table
s = wb.getSheet("OneVariable Table Completed");
r = s.getRow(3);
c = r.getCell(4);
assertEquals(HSSFCell.CELL_TYPE_FORMULA, c.getCellType());
-
+
// TODO - check the formula once tables and
// arrays are properly supported
-
+
// E4 to H9 of sheet 5 make up the table
s = wb.getSheet("TwoVariable Table Example");
r = s.getRow(3);
c = r.getCell(4);
assertEquals(HSSFCell.CELL_TYPE_FORMULA, c.getCellType());
-
+
// TODO - check the formula once tables and
// arrays are properly supported
}
HSSFSheet sh = wb.getSheetAt(0);
for(short i=0; i < 30; i++) sh.autoSizeColumn(i);
}
-
+
/**
* We used to add too many UncalcRecords to sheets
* with diagrams on. Don't any more
wb.getSheetAt(0).setForceFormulaRecalculation(true);
wb.getSheetAt(1).setForceFormulaRecalculation(false);
wb.getSheetAt(2).setForceFormulaRecalculation(true);
-
+
// Write out and back in again
// This used to break
HSSFWorkbook nwb = writeOutAndReadBack(wb);
-
+
// Check now set as it should be
assertTrue(nwb.getSheetAt(0).getForceFormulaRecalculation());
assertFalse(nwb.getSheetAt(1).getForceFormulaRecalculation());
assertTrue(nwb.getSheetAt(2).getForceFormulaRecalculation());
}
-
+
/**
* Very hidden sheets not displaying as such
*/
public void test45761() {
- HSSFWorkbook wb = openSample("45761.xls");
- assertEquals(3, wb.getNumberOfSheets());
-
- assertFalse(wb.isSheetHidden(0));
- assertFalse(wb.isSheetVeryHidden(0));
- assertTrue(wb.isSheetHidden(1));
- assertFalse(wb.isSheetVeryHidden(1));
- assertFalse(wb.isSheetHidden(2));
- assertTrue(wb.isSheetVeryHidden(2));
-
- // Change 0 to be very hidden, and re-load
- wb.setSheetHidden(0, 2);
-
+ HSSFWorkbook wb = openSample("45761.xls");
+ assertEquals(3, wb.getNumberOfSheets());
+
+ assertFalse(wb.isSheetHidden(0));
+ assertFalse(wb.isSheetVeryHidden(0));
+ assertTrue(wb.isSheetHidden(1));
+ assertFalse(wb.isSheetVeryHidden(1));
+ assertFalse(wb.isSheetHidden(2));
+ assertTrue(wb.isSheetVeryHidden(2));
+
+ // Change 0 to be very hidden, and re-load
+ wb.setSheetHidden(0, 2);
+
HSSFWorkbook nwb = writeOutAndReadBack(wb);
- assertFalse(nwb.isSheetHidden(0));
- assertTrue(nwb.isSheetVeryHidden(0));
- assertTrue(nwb.isSheetHidden(1));
- assertFalse(nwb.isSheetVeryHidden(1));
- assertFalse(nwb.isSheetHidden(2));
- assertTrue(nwb.isSheetVeryHidden(2));
+ assertFalse(nwb.isSheetHidden(0));
+ assertTrue(nwb.isSheetVeryHidden(0));
+ assertTrue(nwb.isSheetHidden(1));
+ assertFalse(nwb.isSheetVeryHidden(1));
+ assertFalse(nwb.isSheetHidden(2));
+ assertTrue(nwb.isSheetVeryHidden(2));
}
}
HSSFSheet sheet = wb.getSheetAt(0);
- HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(wb);
row = sheet.getRow(0);
cell = row.getCell(0);
HSSFSheet sheet = wb.getSheetAt(0);
- HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(wb);
// =index(C:C,2,1) -> 2
HSSFRow rowIDX = sheet.getRow(3);
cell.setCellFormula("1=1");
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
try {
fe.evaluateInCell(cell);
} catch (NumberFormatException e) {
int numSheets = wb.getNumberOfSheets();
for (int i = 0; i < numSheets; i++) {
HSSFSheet s = wb.getSheetAt(i);
- HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(s, wb);
+ HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(wb);
for (Iterator rows = s.rowIterator(); rows.hasNext();) {
HSSFRow r = (HSSFRow) rows.next();
HSSFRow row = sheet.createRow(1);
HSSFCell cell = row.createCell(0);
cell.setCellFormula("na()"); // this formula evaluates to an Excel error code '#N/A'
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
try {
fe.evaluateInCell(cell);
} catch (NumberFormatException e) {
// Choose cell A9, so that the failing test case doesn't take too long to execute.
HSSFCell cell = row.getCell(8);
- HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb);
evaluator.evaluate(cell);
int evalCount = evaluator.getEvaluationCount();
// With caching, the evaluationCount is 8 which is a big improvement
// uses evaluateFormulaCell()
for(int sheetNum = 0; sheetNum < wb.getNumberOfSheets(); sheetNum++) {
HSSFSheet sheet = wb.getSheetAt(sheetNum);
- HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb);
for(Iterator rit = sheet.rowIterator(); rit.hasNext();) {
HSSFRow r = (HSSFRow)rit.next();
// uses evaluateInCell()
for(int sheetNum = 0; sheetNum < wb.getNumberOfSheets(); sheetNum++) {
HSSFSheet sheet = wb.getSheetAt(sheetNum);
- HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb);
for(Iterator rit = sheet.rowIterator(); rit.hasNext();) {
HSSFRow r = (HSSFRow)rit.next();
assertEquals("SUM(12.25,12.25)/100", formatter.formatCellValue(cell));
// now with a formula evaluator
- HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb.getSheetAt(0), wb);
+ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb);
log(formatter.formatCellValue(cell, evaluator) + "\t\t\t (with evaluator)");
assertEquals("24.50%", formatter.formatCellValue(cell,evaluator));
}
Iterator it = row.cellIterator();
Format defaultFormat = new DecimalFormat("Balance $#,#00.00 USD;Balance -$#,#00.00 USD");
formatter.setDefaultNumberFormat(defaultFormat);
- double value = 10d;
+
log("\n==== DEFAULT NUMBER FORMAT ====");
while (it.hasNext()) {
HSSFCell cell = (HSSFCell) it.next();
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls");
HSSFSheet sheet = wb.getSheetAt(0);
HSSFCell cell = sheet.getRow(8).getCell(0);
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
CellValue cv = fe.evaluate(cell);
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
assertEquals(3.72, cv.getNumberValue(), 0.0);
setValue(sheet, 3, 6, 100.0);
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
assertEquals(26.0, fe.evaluate(cell0).getNumberValue(), 0.0);
assertEquals(56.0, fe.evaluate(cell1).getNumberValue(), 0.0);
}