aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Burch <nick@apache.org>2008-09-13 13:48:27 +0000
committerNick Burch <nick@apache.org>2008-09-13 13:48:27 +0000
commit1255f2e0bcf5b8fb102fd5fcb3aeefcb2f03d572 (patch)
treee5ffaf04ec3f7a7b7e884a4486bc11b927e975a1
parent6d1b247b69deebf1c5eee0d98ab6ffa99a460830 (diff)
downloadpoi-1255f2e0bcf5b8fb102fd5fcb3aeefcb2f03d572.tar.gz
poi-1255f2e0bcf5b8fb102fd5fcb3aeefcb2f03d572.zip
Merged revisions 693591,693639,693658,693939,693941,693947,693990,694050,694065,694153,694534,694615,694619-694620,694631,694643,694877,694881 via svnmerge from
https://svn.apache.org/repos/asf/poi/trunk ........ r693591 | josh | 2008-09-09 21:25:16 +0100 (Tue, 09 Sep 2008) | 1 line Added support for parsing array constants in formulas. (Helping investigation for bug 45752) ........ r693639 | josh | 2008-09-09 23:26:28 +0100 (Tue, 09 Sep 2008) | 1 line removed debug code accidentally submitted with r693591 ........ r693658 | josh | 2008-09-10 00:46:46 +0100 (Wed, 10 Sep 2008) | 2 lines Fixed special cases of INDEX function (single columns / single rows, and errors) ........ r693939 | josh | 2008-09-10 20:23:43 +0100 (Wed, 10 Sep 2008) | 1 line Fixing error value handling for numeric functions. Refactored hierarchy. ........ r693941 | josh | 2008-09-10 20:27:24 +0100 (Wed, 10 Sep 2008) | 1 line (Should have been submitted with 693939) Fixing error value handling for numeric functions. Refactored hierarchy. ........ r693947 | josh | 2008-09-10 20:33:58 +0100 (Wed, 10 Sep 2008) | 1 line (Should have been submitted with 693939) Fixing error value handling for numeric functions. Refactored hierarchy. ........ r693990 | josh | 2008-09-10 22:21:28 +0100 (Wed, 10 Sep 2008) | 1 line Refactored hierarchy of MultiOperandNumericFunction. Fixed error value handling. Enabled error value check in TestFormulasFromSpreadsheet ........ r694050 | josh | 2008-09-10 23:43:30 +0100 (Wed, 10 Sep 2008) | 1 line Refactored finance functions. ........ r694065 | josh | 2008-09-11 00:37:22 +0100 (Thu, 11 Sep 2008) | 1 line fixed special cases of MODE function ........ r694153 | josh | 2008-09-11 08:16:20 +0100 (Thu, 11 Sep 2008) | 1 line Refactoring MultiOperandNumericFunction - removed Ref2DEval. ........ r694534 | josh | 2008-09-12 00:18:50 +0100 (Fri, 12 Sep 2008) | 1 line Fix for bug 45639 - cleaned up index logic inside ColumnInfoRecordsAggregate ........ r694615 | josh | 2008-09-12 07:14:07 +0100 (Fri, 12 Sep 2008) | 1 line small tweak to unit test which was silently creating UnknownPtgs ........ r694619 | josh | 2008-09-12 07:58:52 +0100 (Fri, 12 Sep 2008) | 1 line Removed trailing comma from output of HexDump.toHex() ........ r694620 | josh | 2008-09-12 08:03:00 +0100 (Fri, 12 Sep 2008) | 1 line clarification of ArrayPtg size increment ........ r694631 | josh | 2008-09-12 08:43:20 +0100 (Fri, 12 Sep 2008) | 1 line Extended support for cached results of formula cells ........ r694643 | josh | 2008-09-12 09:18:54 +0100 (Fri, 12 Sep 2008) | 2 lines Made HSSFFormulaEvaluator no longer require initialisation with sheet or row. ........ r694877 | josh | 2008-09-13 06:14:26 +0100 (Sat, 13 Sep 2008) | 1 line Refactored TextFunctions. Some minor fixes - test cases added. ........ r694881 | josh | 2008-09-13 06:43:41 +0100 (Sat, 13 Sep 2008) | 1 line Added toString methods formatAsString to CellValue. Changed deprecation on CellValue.getRichTextStringValue ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@694947 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/documentation/content/xdocs/changes.xml4
-rw-r--r--src/documentation/content/xdocs/status.xml4
-rw-r--r--src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java199
-rw-r--r--src/java/org/apache/poi/hssf/extractor/ExcelExtractor.java42
-rw-r--r--src/java/org/apache/poi/hssf/model/FormulaParser.java175
-rw-r--r--src/java/org/apache/poi/hssf/model/OperandClassTransformer.java63
-rw-r--r--src/java/org/apache/poi/hssf/model/Sheet.java27
-rw-r--r--src/java/org/apache/poi/hssf/record/ColumnInfoRecord.java140
-rw-r--r--src/java/org/apache/poi/hssf/record/FormulaRecord.java686
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/RecordInputStream.java29
-rw-r--r--src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java947
-rw-r--r--src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java49
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java4
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java90
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/ErrPtg.java33
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/Ptg.java66
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java5
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java8
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java12
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/ConcatEval.java65
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java6
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java159
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java11
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java53
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/eval/ValueEvalToNumericXlator.java179
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java113
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Atan2.java84
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Avedev.java76
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Average.java76
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Ceiling.java82
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Combin.java87
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Concatenate.java60
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Date.java114
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/DateFunc.java76
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Devsq.java77
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Even.java2
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Exact.java84
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java130
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Floor.java82
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java4
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Fv.java75
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Index.java58
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java2
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Large.java81
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Left.java107
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Len.java49
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Log.java87
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Lower.java65
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Max.java68
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Maxa.java66
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Median.java77
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Mid.java87
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Min.java68
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Mina.java66
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/MinaMaxa.java40
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Mod.java87
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Mode.java186
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/MultiOperandNumericFunction.java374
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Nper.java75
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java390
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/NumericFunctionOneArg.java172
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Odd.java2
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Pmt.java91
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Power.java80
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Product.java68
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Pv.java74
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Replace.java156
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Right.java108
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Round.java83
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Rounddown.java86
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Roundup.java88
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Small.java81
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/StatsLib.java30
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Stdev.java76
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Substitute.java187
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Sum.java68
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Sumsq.java70
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java277
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Trim.java53
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/functions/Upper.java65
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFCell.java519
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java3
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFRow.java13
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java44
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java10
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/LazyAreaEval.java29
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/LazyRefEval.java33
-rwxr-xr-xsrc/java/org/apache/poi/ss/usermodel/EvaluationCycleDetector.java27
-rw-r--r--src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java452
-rw-r--r--src/java/org/apache/poi/ss/usermodel/LazyAreaEval.java (renamed from src/java/org/apache/poi/hssf/record/formula/eval/LazyAreaEval.java)17
-rw-r--r--src/java/org/apache/poi/ss/usermodel/LazyRefEval.java (renamed from src/java/org/apache/poi/hssf/record/formula/eval/LazyRefEval.java)170
-rw-r--r--src/java/org/apache/poi/util/HexDump.java4
-rw-r--r--src/java/org/apache/poi/util/HexRead.java9
-rw-r--r--src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Cell.java2
-rw-r--r--src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Comment.java5
-rw-r--r--src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Cell.java2
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherBSERecord.java6
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherBlipWMFRecord.java22
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherChildAnchorRecord.java15
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherClientAnchorRecord.java14
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherClientDataRecord.java17
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherContainerRecord.java19
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherDgRecord.java17
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherDggRecord.java21
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherOptRecord.java30
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherPropertyFactory.java16
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherSpRecord.java16
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherSpgrRecord.java18
-rw-r--r--src/testcases/org/apache/poi/ddf/TestEscherSplitMenuColorsRecord.java14
-rw-r--r--src/testcases/org/apache/poi/ddf/TestUnknownEscherRecord.java15
-rw-r--r--src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xlsbin154624 -> 157184 bytes
-rw-r--r--src/testcases/org/apache/poi/hssf/data/IndexFunctionTestCaseData.xlsbin0 -> 24576 bytes
-rw-r--r--src/testcases/org/apache/poi/hssf/data/testRVA.xlsbin32256 -> 37888 bytes
-rw-r--r--src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java17
-rw-r--r--src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java2
-rw-r--r--src/testcases/org/apache/poi/hssf/model/TestRVA.java22
-rw-r--r--src/testcases/org/apache/poi/hssf/model/TestSheet.java9
-rw-r--r--src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java4
-rw-r--r--src/testcases/org/apache/poi/hssf/record/TestDrawingGroupRecord.java33
-rw-r--r--src/testcases/org/apache/poi/hssf/record/TestEscherAggregate.java2
-rw-r--r--src/testcases/org/apache/poi/hssf/record/TestFormulaRecord.java80
-rw-r--r--src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java100
-rw-r--r--src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java1
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java32
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java2
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculatorFromSpreadsheet.java2
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java10
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java2
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java6
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java27
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java2
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java1
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/functions/TestAverage.java53
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java4
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/functions/TestDate.java2
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java4
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndexFunctionFromSpreadsheet.java250
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/functions/TestIsBlank.java2
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/functions/TestLen.java2
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/functions/TestLookupFunctionsFromSpreadsheet.java107
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/functions/TestMid.java2
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/functions/TestPmt.java2
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/functions/TestRoundFuncs.java9
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/functions/TestStatsLib.java59
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/record/formula/functions/TestTrim.java2
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java3
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestBug43093.java4
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java239
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java12
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java4
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java4
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java4
152 files changed, 4427 insertions, 6500 deletions
diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml
index c1152ef344..6025906757 100644
--- a/src/documentation/content/xdocs/changes.xml
+++ b/src/documentation/content/xdocs/changes.xml
@@ -65,6 +65,10 @@
<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>
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml
index 155d522d7b..9eaab3dad1 100644
--- a/src/documentation/content/xdocs/status.xml
+++ b/src/documentation/content/xdocs/status.xml
@@ -62,6 +62,10 @@
<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>
diff --git a/src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java b/src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java
index 8f3eebb2d3..2ea35c773e 100644
--- a/src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java
+++ b/src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java
@@ -14,6 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
+
package org.apache.poi.hssf.extractor;
import java.io.IOException;
@@ -49,10 +50,10 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/**
* 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
@@ -63,8 +64,8 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
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;
}
@@ -98,8 +99,8 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
public void setFormulasNotResults(boolean formulasNotResults) {
this.formulasNotResults = formulasNotResults;
}
-
-
+
+
/**
* Retreives the text contents of the file
*/
@@ -107,7 +108,7 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
String text = null;
try {
TextListener tl = triggerExtraction();
-
+
text = tl.text.toString();
if(! text.endsWith("\n")) {
text = text + "\n";
@@ -115,37 +116,37 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
} 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;
@@ -160,7 +161,7 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
if(bof.getType() == BOFRecord.TYPE_WORKSHEET) {
sheetNum++;
rowNum = -1;
-
+
if(includeSheetNames) {
if(text.length() > 0) text.append("\n");
text.append(sheetNames.get(sheetNum));
@@ -170,60 +171,60 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
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;
@@ -235,42 +236,42 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
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);
+ }
+ }
}
}
}
diff --git a/src/java/org/apache/poi/hssf/extractor/ExcelExtractor.java b/src/java/org/apache/poi/hssf/extractor/ExcelExtractor.java
index b9750fc58a..17bde6da5f 100644
--- a/src/java/org/apache/poi/hssf/extractor/ExcelExtractor.java
+++ b/src/java/org/apache/poi/hssf/extractor/ExcelExtractor.java
@@ -14,12 +14,14 @@
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;
@@ -112,40 +114,52 @@ public class ExcelExtractor extends POIOLE2TextExtractor implements org.apache.p
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
diff --git a/src/java/org/apache/poi/hssf/model/FormulaParser.java b/src/java/org/apache/poi/hssf/model/FormulaParser.java
index 5fd30d06e0..32f38d40d1 100644
--- a/src/java/org/apache/poi/hssf/model/FormulaParser.java
+++ b/src/java/org/apache/poi/hssf/model/FormulaParser.java
@@ -22,11 +22,14 @@ import java.util.List;
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;
@@ -70,9 +73,9 @@ public final class FormulaParser {
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;
@@ -140,9 +143,9 @@ public final class FormulaParser {
/** 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 + "'"
@@ -194,8 +197,8 @@ public final class FormulaParser {
/**
* 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() {
@@ -251,7 +254,7 @@ public final class FormulaParser {
}
private Ptg parseNameOrReference(String name) {
-
+
AreaReference areaRef = parseArea(name);
if (areaRef != null) {
// will happen if dots are used instead of colon
@@ -373,30 +376,28 @@ public final class FormulaParser {
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('(');
@@ -544,7 +545,7 @@ public final class FormulaParser {
SkipWhite();
switch(look) {
case '#':
- return new ParseNode(parseErrorLiteral());
+ return new ParseNode(ErrPtg.valueOf(parseErrorLiteral()));
case '-':
Match('-');
return new ParseNode(UnaryMinusPtg.instance, powerFactor());
@@ -557,7 +558,12 @@ public final class FormulaParser {
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();
@@ -567,6 +573,95 @@ public final class FormulaParser {
}
+ 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;
@@ -603,7 +698,7 @@ public final class FormulaParser {
}
- private ErrPtg parseErrorLiteral() {
+ private int parseErrorLiteral() {
Match('#');
String part1 = parseIdentifier().toUpperCase();
@@ -611,13 +706,13 @@ public final class FormulaParser {
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':
@@ -625,21 +720,21 @@ public final class FormulaParser {
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('/');
@@ -648,7 +743,7 @@ public final class FormulaParser {
}
Match(look);
// Note - no '!' or '?' suffix
- return ErrPtg.N_A;
+ return HSSFErrorConstants.ERROR_NA;
}
throw expected("#NAME?, #NUM!, #NULL! or #N/A");
@@ -701,7 +796,7 @@ public final class FormulaParser {
}
- private StringPtg parseStringLiteral() {
+ private String parseStringLiteral() {
Match('"');
StringBuffer token = new StringBuffer();
@@ -715,7 +810,7 @@ public final class FormulaParser {
token.append(look);
GetChar();
}
- return new StringPtg(token.toString());
+ return token.toString();
}
/** Parse and Translate a Math Term */
@@ -972,7 +1067,7 @@ end;
}
return result;
}
-
+
private static String[] getOperands(Stack stack, int nOperands) {
String[] operands = new String[nOperands];
diff --git a/src/java/org/apache/poi/hssf/model/OperandClassTransformer.java b/src/java/org/apache/poi/hssf/model/OperandClassTransformer.java
index 9b5804f0c4..8b7b56638b 100644
--- a/src/java/org/apache/poi/hssf/model/OperandClassTransformer.java
+++ b/src/java/org/apache/poi/hssf/model/OperandClassTransformer.java
@@ -74,7 +74,7 @@ final class OperandClassTransformer {
+ _formulaType + ") not supported yet");
}
- transformNode(rootNode, rootNodeOperandClass, false, false);
+ transformNode(rootNode, rootNodeOperandClass, false);
}
/**
@@ -83,22 +83,35 @@ final class OperandClassTransformer {
* 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) {
@@ -109,15 +122,24 @@ final class OperandClassTransformer {
// 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,
@@ -185,6 +207,7 @@ final class OperandClassTransformer {
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);
@@ -220,7 +243,17 @@ final class OperandClassTransformer {
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);
}
}
}
diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java
index 388f1a6ee4..8bbc30435a 100644
--- a/src/java/org/apache/poi/hssf/model/Sheet.java
+++ b/src/java/org/apache/poi/hssf/model/Sheet.java
@@ -1055,7 +1055,7 @@ public final class Sheet implements Model {
ColumnInfoRecord ci = _columnInfos.findColumnInfo(columnIndex);
if (ci != null) {
- return ci.getColumnWidth();
+ return (short)ci.getColumnWidth();
}
//default column width is measured in characters
//multiply
@@ -1079,8 +1079,8 @@ public final class Sheet implements Model {
public short getXFIndexForColAt(short columnIndex) {
ColumnInfoRecord ci = _columnInfos.findColumnInfo(columnIndex);
if (ci != null) {
- return ci.getXFIndex();
- }
+ return (short)ci.getXFIndex();
+ }
return 0xF;
}
@@ -1138,8 +1138,7 @@ public final class Sheet implements Model {
* @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);
@@ -1709,17 +1708,13 @@ public final class Sheet implements Model {
}
- 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
diff --git a/src/java/org/apache/poi/hssf/record/ColumnInfoRecord.java b/src/java/org/apache/poi/hssf/record/ColumnInfoRecord.java
index b77dca3e17..32aef3a6c3 100644
--- a/src/java/org/apache/poi/hssf/record/ColumnInfoRecord.java
+++ b/src/java/org/apache/poi/hssf/record/ColumnInfoRecord.java
@@ -17,6 +17,7 @@
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;
@@ -30,19 +31,24 @@ 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
}
@@ -90,7 +96,7 @@ public final class ColumnInfoRecord extends Record {
* @param fc - the first column index (0-based)
*/
- public void setFirstColumn(short fc)
+ public void setFirstColumn(int fc)
{
field_1_first_col = fc;
}
@@ -100,7 +106,7 @@ public final class ColumnInfoRecord extends Record {
* @param lc - the last column index (0-based)
*/
- public void setLastColumn(short lc)
+ public void setLastColumn(int lc)
{
field_2_last_col = lc;
}
@@ -110,7 +116,7 @@ public final class ColumnInfoRecord extends Record {
* @param cw - column width
*/
- public void setColumnWidth(short cw)
+ public void setColumnWidth(int cw)
{
field_3_col_width = cw;
}
@@ -121,20 +127,11 @@ public final class ColumnInfoRecord extends Record {
* @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
@@ -146,7 +143,7 @@ public final class ColumnInfoRecord extends Record {
public void setHidden(boolean ishidden)
{
- field_5_options = hidden.setShortBoolean(field_5_options, ishidden);
+ field_5_options = hidden.setBoolean(field_5_options, ishidden);
}
/**
@@ -155,9 +152,9 @@ public final class ColumnInfoRecord extends Record {
* @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);
}
/**
@@ -168,7 +165,7 @@ public final class ColumnInfoRecord extends Record {
public void setCollapsed(boolean iscollapsed)
{
- field_5_options = collapsed.setShortBoolean(field_5_options,
+ field_5_options = collapsed.setBoolean(field_5_options,
iscollapsed);
}
@@ -179,7 +176,7 @@ public final class ColumnInfoRecord extends Record {
* @return the first column index (0-based)
*/
- public short getFirstColumn()
+ public int getFirstColumn()
{
return field_1_first_col;
}
@@ -189,7 +186,7 @@ public final class ColumnInfoRecord extends Record {
* @return the last column index (0-based)
*/
- public short getLastColumn()
+ public int getLastColumn()
{
return field_2_last_col;
}
@@ -199,7 +196,7 @@ public final class ColumnInfoRecord extends Record {
* @return column width
*/
- public short getColumnWidth()
+ public int getColumnWidth()
{
return field_3_col_width;
}
@@ -210,21 +207,18 @@ public final class ColumnInfoRecord extends Record {
* @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
/**
@@ -244,9 +238,9 @@ public final class ColumnInfoRecord extends Record {
* @return outline level for the cells
*/
- public short getOutlineLevel()
+ public int getOutlineLevel()
{
- return outlevel.getShortValue(field_5_options);
+ return outlevel.getValue(field_5_options);
}
/**
@@ -261,6 +255,31 @@ public final class ColumnInfoRecord extends Record {
}
// 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;
@@ -269,13 +288,13 @@ public final class ColumnInfoRecord extends Record {
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();
}
@@ -286,24 +305,19 @@ public final class ColumnInfoRecord extends Record {
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() {
diff --git a/src/java/org/apache/poi/hssf/record/FormulaRecord.java b/src/java/org/apache/poi/hssf/record/FormulaRecord.java
index 46e8283dc2..b9616e0db7 100644
--- a/src/java/org/apache/poi/hssf/record/FormulaRecord.java
+++ b/src/java/org/apache/poi/hssf/record/FormulaRecord.java
@@ -18,6 +18,8 @@
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;
@@ -32,264 +34,430 @@ import org.apache.poi.util.LittleEndian;
*/
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;
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/RecordInputStream.java b/src/java/org/apache/poi/hssf/record/RecordInputStream.java
index 12c818b183..fe6a4b2ea3 100755
--- a/src/java/org/apache/poi/hssf/record/RecordInputStream.java
+++ b/src/java/org/apache/poi/hssf/record/RecordInputStream.java
@@ -209,30 +209,18 @@ public class RecordInputStream extends InputStream {
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();
@@ -276,9 +264,6 @@ public class RecordInputStream extends InputStream {
}
public String readCompressedUnicode(int length) {
- if(length == 0) {
- return "";
- }
if ((length < 0) || ((remaining() < length) && !isContinueNext())) {
throw new IllegalArgumentException("Illegal length " + length);
}
@@ -291,9 +276,7 @@ public class RecordInputStream extends InputStream {
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();
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java
index b24d8c5b45..0f405bd111 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java
@@ -18,18 +18,35 @@
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
@@ -37,486 +54,470 @@ public final class ColumnInfoRecordsAggregate extends RecordAggregate {
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;
}
-
-
}
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
index 68d5f453dc..06bb53a38d 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
@@ -20,6 +20,7 @@ package org.apache.poi.hssf.record.aggregates;
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;
/**
@@ -34,9 +35,9 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
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
*/
@@ -44,6 +45,14 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
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);
}
@@ -52,18 +61,18 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
_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();
}
@@ -91,7 +100,7 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
public String toString() {
return _formulaRecord.toString();
}
-
+
public void visitContainedRecords(RecordVisitor rv) {
rv.visitRecord(_formulaRecord);
Record sharedFormulaRecord = _sharedValueManager.getRecordForFirstCell(_formulaRecord);
@@ -102,11 +111,33 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
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);
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java b/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java
index 2193854f47..68ae5b48c1 100644
--- a/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java
+++ b/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java
@@ -18,7 +18,7 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.LittleEndian;
/**
@@ -45,7 +45,7 @@ public abstract class Area2DPtgBase extends AreaPtgBase {
public final int getSize() {
return SIZE;
}
- public final String toFormulaString(HSSFWorkbook book) {
+ public final String toFormulaString(Workbook book) {
return formatReferenceAsString();
}
public final String toString() {
diff --git a/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java b/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java
index 49994c0597..48acaac205 100644
--- a/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java
@@ -44,8 +44,11 @@ public final class ArrayPtg extends Ptg {
* (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;
@@ -59,8 +62,42 @@ public final class ArrayPtg extends Ptg {
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() {
@@ -88,27 +125,21 @@ public final class ArrayPtg extends Ptg {
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) {
@@ -120,7 +151,7 @@ public final class ArrayPtg extends Ptg {
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) {
@@ -153,16 +184,15 @@ public final class ArrayPtg extends Ptg {
+ 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)];
@@ -172,11 +202,14 @@ public final class ArrayPtg extends Ptg {
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() + "\"";
@@ -196,11 +229,4 @@ public final class ArrayPtg extends Ptg {
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;
- }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/ErrPtg.java b/src/java/org/apache/poi/hssf/record/formula/ErrPtg.java
index aef580d5e4..d94f2a3807 100644
--- a/src/java/org/apache/poi/hssf/record/formula/ErrPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/ErrPtg.java
@@ -24,12 +24,12 @@ import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
* @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 */
@@ -37,28 +37,28 @@ public final class ErrPtg extends ScalarConstantPtg {
/** <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)
@@ -78,4 +78,17 @@ public final class ErrPtg extends ScalarConstantPtg {
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 + ")");
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/Ptg.java b/src/java/org/apache/poi/hssf/record/formula/Ptg.java
index 296b691cda..630803c3cb 100644
--- a/src/java/org/apache/poi/hssf/record/formula/Ptg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/Ptg.java
@@ -56,20 +56,21 @@ public abstract class Ptg implements Cloneable {
/**
* @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) {
@@ -109,25 +110,25 @@ public abstract class Ptg implements Cloneable {
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 + ")");
@@ -162,7 +163,7 @@ public abstract class Ptg implements Cloneable {
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
@@ -262,11 +263,14 @@ public abstract class Ptg implements Cloneable {
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++) {
diff --git a/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java b/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java
index 87a6462b7d..efeb5c484b 100644
--- a/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java
+++ b/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java
@@ -24,15 +24,14 @@ 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.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;
}
};
diff --git a/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java b/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java
index 71cfa03591..b76ca96019 100644
--- a/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java
@@ -42,8 +42,8 @@ final class ParityFunction implements FreeRefFunction {
_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;
}
@@ -58,8 +58,8 @@ final class ParityFunction implements FreeRefFunction {
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) {
diff --git a/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java b/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java
index f5bc3fe8f4..59c6aea89d 100644
--- a/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java
+++ b/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java
@@ -61,8 +61,8 @@ final class YearFrac implements FreeRefFunction {
// 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 {
@@ -85,8 +85,8 @@ final class YearFrac implements FreeRefFunction {
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();
@@ -155,8 +155,8 @@ final class YearFrac implements FreeRefFunction {
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);
}
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/ConcatEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/ConcatEval.java
index e54cd483f1..6755cfafef 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/ConcatEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/ConcatEval.java
@@ -1,19 +1,19 @@
-/*
-* 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;
@@ -24,7 +24,7 @@ import org.apache.poi.hssf.record.formula.Ptg;
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
-public final class ConcatEval extends StringOperationEval {
+public final class ConcatEval implements OperationEval {
private ConcatPtg delegate;
@@ -37,20 +37,23 @@ public final class ConcatEval extends StringOperationEval {
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());
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java b/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java
index 95dd0b545b..3782c6c4de 100755
--- a/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java
@@ -19,7 +19,6 @@ package org.apache.poi.hssf.record.formula.eval;
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;
/**
*
@@ -31,7 +30,8 @@ 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) {
@@ -55,7 +55,7 @@ final class ExternalFunction implements FreeRefFunction {
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,
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
index a1c7356fa9..e68b8ee67d 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
@@ -1,23 +1,20 @@
-/*
-* 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;
@@ -81,42 +78,42 @@ public abstract class FunctionEval implements OperationEval {
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
@@ -132,16 +129,16 @@ public abstract class FunctionEval implements OperationEval {
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
@@ -173,9 +170,9 @@ public abstract class FunctionEval implements OperationEval {
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
@@ -185,16 +182,16 @@ public abstract class FunctionEval implements OperationEval {
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
@@ -255,8 +252,8 @@ public abstract class FunctionEval implements OperationEval {
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
@@ -282,8 +279,8 @@ public abstract class FunctionEval implements OperationEval {
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
@@ -291,14 +288,14 @@ public abstract class FunctionEval implements OperationEval {
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
@@ -331,14 +328,14 @@ public abstract class FunctionEval implements OperationEval {
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
@@ -347,10 +344,10 @@ public abstract class FunctionEval implements OperationEval {
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
@@ -380,15 +377,15 @@ public abstract class FunctionEval implements OperationEval {
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
@@ -397,14 +394,14 @@ public abstract class FunctionEval implements OperationEval {
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
@@ -423,8 +420,8 @@ public abstract class FunctionEval implements OperationEval {
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
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java b/src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java
index 87f45236bf..09be70477f 100755
--- a/src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java
@@ -272,12 +272,7 @@ public final class OperandResolver {
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() + ")");
@@ -289,7 +284,7 @@ public final class OperandResolver {
*/
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;
}
@@ -297,7 +292,7 @@ public final class OperandResolver {
return Boolean.valueOf(((BoolEval) ve).getBooleanValue());
}
- if (ve instanceof BlankEval) {
+ if (ve == BlankEval.INSTANCE) {
return null;
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java
deleted file mode 100644
index e4bb47a43d..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-* 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
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/ValueEvalToNumericXlator.java b/src/java/org/apache/poi/hssf/record/formula/eval/ValueEvalToNumericXlator.java
deleted file mode 100644
index 46aa0ddf69..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/eval/ValueEvalToNumericXlator.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java
new file mode 100644
index 0000000000..0495ee3fc4
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java
@@ -0,0 +1,113 @@
+/* ====================================================================
+ 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 &lt; amolweb at ya hoo dot com &gt;
+ *
+ */
+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);
+ }
+ };
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Atan2.java b/src/java/org/apache/poi/hssf/record/formula/functions/Atan2.java
deleted file mode 100644
index a0ff7b00c0..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Atan2.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Avedev.java b/src/java/org/apache/poi/hssf/record/formula/functions/Avedev.java
deleted file mode 100644
index bf888b97df..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Avedev.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Average.java b/src/java/org/apache/poi/hssf/record/formula/functions/Average.java
deleted file mode 100644
index 4043040713..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Average.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Ceiling.java b/src/java/org/apache/poi/hssf/record/formula/functions/Ceiling.java
deleted file mode 100644
index a158b856bc..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Ceiling.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Combin.java b/src/java/org/apache/poi/hssf/record/formula/functions/Combin.java
deleted file mode 100644
index 72d6d4691e..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Combin.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Concatenate.java b/src/java/org/apache/poi/hssf/record/formula/functions/Concatenate.java
deleted file mode 100644
index be961c151e..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Concatenate.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Date.java b/src/java/org/apache/poi/hssf/record/formula/functions/Date.java
deleted file mode 100644
index 6861a02524..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Date.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
-* 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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/DateFunc.java b/src/java/org/apache/poi/hssf/record/formula/functions/DateFunc.java
new file mode 100644
index 0000000000..6cbe8414fe
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/DateFunc.java
@@ -0,0 +1,76 @@
+/* ====================================================================
+ 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;
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Devsq.java b/src/java/org/apache/poi/hssf/record/formula/functions/Devsq.java
deleted file mode 100644
index a198ff8398..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Devsq.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Even.java b/src/java/org/apache/poi/hssf/record/formula/functions/Even.java
index 272863908c..eaeed89247 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Even.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Even.java
@@ -22,7 +22,7 @@ package org.apache.poi.hssf.record.formula.functions;
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
-public final class Even extends NumericFunctionOneArg {
+public final class Even extends NumericFunction.OneArg {
private static final long PARITY_MASK = 0xFFFFFFFFFFFFFFFEL;
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Exact.java b/src/java/org/apache/poi/hssf/record/formula/functions/Exact.java
deleted file mode 100644
index 63dc18d771..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Exact.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java
index c054c6dac4..01fcf9ef0b 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java
@@ -1,71 +1,77 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
* 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);
+ }
+ };
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Floor.java b/src/java/org/apache/poi/hssf/record/formula/functions/Floor.java
deleted file mode 100644
index 8698ce9f23..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Floor.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java
index 2163d8f5ed..3a3478ca52 100755
--- a/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java
@@ -45,13 +45,13 @@ public interface FreeRefFunction {
*
* @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);
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Fv.java b/src/java/org/apache/poi/hssf/record/formula/functions/Fv.java
deleted file mode 100644
index fd0335c388..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Fv.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-* 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;
- }
-
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Index.java b/src/java/org/apache/poi/hssf/record/formula/functions/Index.java
index 3c93c0846b..1c149dbdfc 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Index.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Index.java
@@ -22,6 +22,7 @@ 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.RefEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
@@ -51,6 +52,10 @@ public final class Index implements Function {
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
@@ -84,16 +89,63 @@ public final class Index implements Function {
// 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);
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java b/src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java
index 8d7d4463e5..be63d70275 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java
@@ -41,7 +41,7 @@ import org.apache.poi.ss.usermodel.Workbook;
*/
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;
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Large.java b/src/java/org/apache/poi/hssf/record/formula/functions/Large.java
deleted file mode 100644
index 3b9aed9768..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Large.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Left.java b/src/java/org/apache/poi/hssf/record/formula/functions/Left.java
deleted file mode 100644
index ecb14a7008..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Left.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Len.java b/src/java/org/apache/poi/hssf/record/formula/functions/Len.java
deleted file mode 100644
index 0bc49b4070..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Len.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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();
- }
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Log.java b/src/java/org/apache/poi/hssf/record/formula/functions/Log.java
deleted file mode 100644
index 7727c35275..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Log.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- * 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;
- }
-
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Lower.java b/src/java/org/apache/poi/hssf/record/formula/functions/Lower.java
deleted file mode 100644
index edf7e279ea..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Lower.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Max.java b/src/java/org/apache/poi/hssf/record/formula/functions/Max.java
deleted file mode 100644
index d5b3971494..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Max.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Maxa.java b/src/java/org/apache/poi/hssf/record/formula/functions/Maxa.java
deleted file mode 100644
index e25db7b746..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Maxa.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Median.java b/src/java/org/apache/poi/hssf/record/formula/functions/Median.java
deleted file mode 100644
index 57a18b3314..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Median.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Mid.java b/src/java/org/apache/poi/hssf/record/formula/functions/Mid.java
deleted file mode 100644
index b9d679d3d3..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Mid.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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 &lt; wilson at c bio dot msk cc dot org &gt;
- */
-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
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Min.java b/src/java/org/apache/poi/hssf/record/formula/functions/Min.java
deleted file mode 100644
index 8cd896783c..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Min.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Mina.java b/src/java/org/apache/poi/hssf/record/formula/functions/Mina.java
deleted file mode 100644
index 21ba47b569..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Mina.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/MinaMaxa.java b/src/java/org/apache/poi/hssf/record/formula/functions/MinaMaxa.java
new file mode 100644
index 0000000000..70e5e7ff1b
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/MinaMaxa.java
@@ -0,0 +1,40 @@
+/* ====================================================================
+ 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 &lt; amolweb at ya hoo dot com &gt;
+ *
+ */
+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;
+ }
+ };
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Mod.java b/src/java/org/apache/poi/hssf/record/formula/functions/Mod.java
deleted file mode 100644
index ebef231544..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Mod.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Mode.java b/src/java/org/apache/poi/hssf/record/formula/functions/Mode.java
index 724b6e6543..c236ccee62 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Mode.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Mode.java
@@ -1,78 +1,134 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
+ *
*/
-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() + ")");
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/MultiOperandNumericFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/MultiOperandNumericFunction.java
index a9e98ae313..b3feac6a07 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/MultiOperandNumericFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/MultiOperandNumericFunction.java
@@ -1,30 +1,33 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
@@ -32,175 +35,166 @@ import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
* 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() + ")");
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Nper.java b/src/java/org/apache/poi/hssf/record/formula/functions/Nper.java
deleted file mode 100644
index 95411edb77..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Nper.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-* 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;
- }
-
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java
index fd96f1495a..9a702ee6a3 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java
@@ -1,98 +1,316 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
*/
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);
+ }
+ };
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunctionOneArg.java b/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunctionOneArg.java
deleted file mode 100644
index 0012013949..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunctionOneArg.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/* ====================================================================
- 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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);
- }
- };
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Odd.java b/src/java/org/apache/poi/hssf/record/formula/functions/Odd.java
index 4cb8c700d1..74eddac2de 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Odd.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Odd.java
@@ -22,7 +22,7 @@ package org.apache.poi.hssf.record.formula.functions;
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
-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) {
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Pmt.java b/src/java/org/apache/poi/hssf/record/formula/functions/Pmt.java
deleted file mode 100644
index 68a8d43dce..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Pmt.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
-* 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);
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Power.java b/src/java/org/apache/poi/hssf/record/formula/functions/Power.java
deleted file mode 100644
index 1327e80061..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Power.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Product.java b/src/java/org/apache/poi/hssf/record/formula/functions/Product.java
deleted file mode 100644
index a88a3245d6..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Product.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Pv.java b/src/java/org/apache/poi/hssf/record/formula/functions/Pv.java
deleted file mode 100644
index 1d54bee93d..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Pv.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-* 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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Replace.java b/src/java/org/apache/poi/hssf/record/formula/functions/Replace.java
index 95413f0823..1dfc4f8f05 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Replace.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Replace.java
@@ -1,112 +1,70 @@
-/*
-* 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 &lt; wilson at c bio dot msk cc dot org &gt;
*/
-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());
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Right.java b/src/java/org/apache/poi/hssf/record/formula/functions/Right.java
deleted file mode 100644
index 771d045734..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Right.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Round.java b/src/java/org/apache/poi/hssf/record/formula/functions/Round.java
deleted file mode 100644
index db4f1db0ee..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Round.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
-* 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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Rounddown.java b/src/java/org/apache/poi/hssf/record/formula/functions/Rounddown.java
deleted file mode 100644
index 13522294fd..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Rounddown.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-* 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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Roundup.java b/src/java/org/apache/poi/hssf/record/formula/functions/Roundup.java
deleted file mode 100644
index 4dae76d981..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Roundup.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
-* 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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Small.java b/src/java/org/apache/poi/hssf/record/formula/functions/Small.java
deleted file mode 100644
index 9fcdc1045e..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Small.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/StatsLib.java b/src/java/org/apache/poi/hssf/record/formula/functions/StatsLib.java
index 8ebccfd950..e78f38caaa 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/StatsLib.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/StatsLib.java
@@ -60,36 +60,6 @@ public final class StatsLib {
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;
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Stdev.java b/src/java/org/apache/poi/hssf/record/formula/functions/Stdev.java
deleted file mode 100644
index 7995e66c34..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Stdev.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Substitute.java b/src/java/org/apache/poi/hssf/record/formula/functions/Substitute.java
index 9d2e9ce361..b00d7510e3 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Substitute.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Substitute.java
@@ -1,30 +1,26 @@
-/*
-* 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;
/**
@@ -32,86 +28,75 @@ 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 &lt; wilson at c bio dot msk cc dot org &gt;
*/
-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();
+ }
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Sum.java b/src/java/org/apache/poi/hssf/record/formula/functions/Sum.java
deleted file mode 100644
index d3dcd9b202..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Sum.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Sumsq.java b/src/java/org/apache/poi/hssf/record/formula/functions/Sumsq.java
deleted file mode 100644
index b74b4161ac..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Sumsq.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java
index 9da1776127..df7db7ad32 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java
@@ -1,31 +1,29 @@
-/*
-* 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;
/**
@@ -33,75 +31,164 @@ 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 &lt; wilson at c bio dot msk cc dot org &gt;
+ */
+ 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 &lt; wilson at c bio dot msk cc dot org &gt;
+ */
+ 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));
+ }
+ };
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Trim.java b/src/java/org/apache/poi/hssf/record/formula/functions/Trim.java
deleted file mode 100644
index 87e29ee34d..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Trim.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-* 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 &lt; wilson at c bio dot msk cc dot org &gt;
- */
-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();
- }
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Upper.java b/src/java/org/apache/poi/hssf/record/formula/functions/Upper.java
deleted file mode 100644
index 5146a6641c..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Upper.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-* 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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
index 21fb5707e6..1f88cce2bd 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
@@ -23,6 +23,7 @@ import java.util.Calendar;
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;
@@ -60,8 +61,8 @@ import org.apache.poi.ss.usermodel.RichTextString;
* 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.
@@ -86,14 +87,15 @@ public class HSSFCell implements Cell {
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;
@@ -113,7 +115,7 @@ public class HSSFCell implements Cell {
*
* @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;
@@ -123,9 +125,12 @@ public class HSSFCell implements Cell {
// 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
@@ -140,7 +145,7 @@ public class HSSFCell implements 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);
@@ -148,8 +153,8 @@ public class HSSFCell implements Cell {
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);
}
@@ -161,7 +166,7 @@ public class HSSFCell implements Cell {
* @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;
@@ -190,10 +195,10 @@ public class HSSFCell implements Cell {
* 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()) {
@@ -209,13 +214,13 @@ public class HSSFCell implements Cell {
}
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();
}
/**
@@ -233,7 +238,7 @@ public class HSSFCell implements Cell {
{
record.setColumn(num);
}
-
+
/**
* Updates the cell record's idea of what
* column it belongs in (0 based)
@@ -241,7 +246,7 @@ public class HSSFCell implements Cell {
*/
protected void updateCellNum(short num)
{
- record.setColumn(num);
+ record.setColumn(num);
}
/**
@@ -295,7 +300,7 @@ public class HSSFCell implements Cell {
FormulaRecordAggregate frec;
if (cellType != this.cellType) {
- frec = sheet.createFormula(row, col);
+ frec = sheet.getSheet().createFormula(row, col);
} else {
frec = (FormulaRecordAggregate) record;
frec.setRow(row);
@@ -421,17 +426,17 @@ public class HSSFCell implements Cell {
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;
}
@@ -457,21 +462,20 @@ public class HSSFCell implements Cell {
* 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;
}
}
@@ -491,7 +495,7 @@ public class HSSFCell implements Cell {
/**
* 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
@@ -547,31 +551,20 @@ public class HSSFCell implements Cell {
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);
}
@@ -599,95 +592,95 @@ public class HSSFCell implements Cell {
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);
}
/**
@@ -708,33 +701,22 @@ public class HSSFCell implements Cell {
* 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);
}
/**
@@ -745,47 +727,56 @@ public class HSSFCell implements Cell {
* 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();
@@ -796,11 +787,11 @@ public class HSSFCell implements Cell {
// 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 + ")");
}
@@ -809,38 +800,39 @@ public class HSSFCell implements Cell {
* 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();
}
/**
@@ -897,7 +889,7 @@ public class HSSFCell implements Cell {
throw new RuntimeException("You cannot reference columns with an index of less then 0.");
}
}
-
+
/**
* Sets this cell as the active cell for the worksheet
*/
@@ -905,45 +897,45 @@ public class HSSFCell implements Cell {
{
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&lt;errIdx&gt;
*/
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();
+ }
}
/**
@@ -954,14 +946,14 @@ public class HSSFCell implements Cell {
* @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;
}
/**
@@ -971,11 +963,11 @@ public class HSSFCell implements Cell {
*/
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.
@@ -983,40 +975,41 @@ public class HSSFCell implements Cell {
* 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);
+ }
}
/**
@@ -1070,7 +1063,7 @@ public class HSSFCell implements Cell {
* @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;
@@ -1108,7 +1101,19 @@ public class HSSFCell implements Cell {
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();
}
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
index 4fb31606ea..64ec2fd211 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
@@ -31,6 +31,9 @@ public class HSSFFormulaEvaluator extends FormulaEvaluator {
public HSSFFormulaEvaluator(HSSFSheet sheet, HSSFWorkbook workbook) {
super(sheet, workbook);
}
+ public HSSFFormulaEvaluator(HSSFWorkbook workbook) {
+ super(workbook);
+ }
/**
* Returns an underlying FormulaParser, for the specified
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java
index 4e351e6ade..641c07467c 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java
@@ -20,7 +20,6 @@ package org.apache.poi.hssf.usermodel;
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;
@@ -55,7 +54,7 @@ public final class HSSFRow implements Comparable, Row {
/**
* reference to containing Sheet
*/
- private Sheet sheet;
+ private HSSFSheet sheet;
/**
* Creates new HSSFRow from scratch. Only HSSFSheet should do this.
@@ -65,7 +64,7 @@ public final class HSSFRow implements Comparable, Row {
* @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;
@@ -84,7 +83,7 @@ public final class HSSFRow implements Comparable, Row {
* @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;
@@ -139,7 +138,7 @@ public final class HSSFRow implements Comparable, Row {
HSSFCell cell = new HSSFCell(book, sheet, getRowNum(), shortCellNum, type);
addCell(cell);
- sheet.addValueRecord(getRowNum(), cell.getCellValueRecord());
+ sheet.getSheet().addValueRecord(getRowNum(), cell.getCellValueRecord());
return cell;
}
@@ -166,7 +165,7 @@ public final class HSSFRow implements Comparable, Row {
if(alsoRemoveRecords) {
CellValueRecordInterface cval = cell.getCellValueRecord();
- sheet.removeValueRecord(getRowNum(), cval);
+ sheet.getSheet().removeValueRecord(getRowNum(), cval);
}
if (cell.getCellNum()+1 == row.getLastCol()) {
@@ -465,7 +464,7 @@ public final class HSSFRow implements Comparable, Row {
//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;
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
index 6670b20414..4d6a1f7253 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
@@ -207,7 +207,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
*/
public HSSFRow createRow(int rownum)
{
- HSSFRow row = new HSSFRow(workbook, sheet, rownum);
+ HSSFRow row = new HSSFRow(workbook, this, rownum);
addRow(row, true);
return row;
@@ -222,7 +222,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
private HSSFRow createRowFromRecord(RowRecord row)
{
- HSSFRow hrow = new HSSFRow(workbook, sheet, row);
+ HSSFRow hrow = new HSSFRow(workbook, this, row);
addRow(hrow, false);
return hrow;
@@ -390,7 +390,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
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;
@@ -1301,9 +1301,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
// If any references were changed, then
// re-create the formula string
if(changed) {
- c.setCellFormula(
- FormulaParser.toFormulaString(workbook, ptgs)
- );
+ c.setFormulaOnly(ptgs);
}
}
}
@@ -1602,14 +1600,32 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
}
/**
+ * @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);
}
/**
@@ -1618,14 +1634,12 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
* @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)
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index 54962e7f20..1d24ad3921 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -661,6 +661,16 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
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
diff --git a/src/java/org/apache/poi/hssf/usermodel/LazyAreaEval.java b/src/java/org/apache/poi/hssf/usermodel/LazyAreaEval.java
new file mode 100644
index 0000000000..0a195c8754
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/usermodel/LazyAreaEval.java
@@ -0,0 +1,29 @@
+/* ====================================================================
+ 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);
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/LazyRefEval.java b/src/java/org/apache/poi/hssf/usermodel/LazyRefEval.java
new file mode 100644
index 0000000000..3b591bbcc0
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/usermodel/LazyRefEval.java
@@ -0,0 +1,33 @@
+/* ====================================================================
+ 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.Ref3DPtg;
+import org.apache.poi.hssf.record.formula.RefPtg;
+
+/**
+*
+* @author Josh Micich
+*/
+final class LazyRefEval extends org.apache.poi.ss.usermodel.LazyRefEval {
+ public LazyRefEval(RefPtg ptg, HSSFSheet sheet, HSSFFormulaEvaluator evaluator) {
+ super(ptg, sheet, evaluator);
+ }
+ public LazyRefEval(Ref3DPtg ptg, HSSFSheet sheet, HSSFFormulaEvaluator evaluator) {
+ super(ptg, sheet, evaluator);
+ }
+}
diff --git a/src/java/org/apache/poi/ss/usermodel/EvaluationCycleDetector.java b/src/java/org/apache/poi/ss/usermodel/EvaluationCycleDetector.java
index 9cf3aa982f..30c6d31b1e 100755
--- a/src/java/org/apache/poi/ss/usermodel/EvaluationCycleDetector.java
+++ b/src/java/org/apache/poi/ss/usermodel/EvaluationCycleDetector.java
@@ -20,12 +20,9 @@ package org.apache.poi.ss.usermodel;
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.
@@ -40,19 +37,19 @@ final class EvaluationCycleDetector {
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;
}
@@ -62,7 +59,7 @@ final class EvaluationCycleDetector {
if (_workbook != other._workbook) {
return false;
}
- if (_sheet != other._sheet) {
+ if (_sheetIndex != other._sheetIndex) {
return false;
}
if (_srcRowNum != other._srcRowNum) {
@@ -78,7 +75,7 @@ final class EvaluationCycleDetector {
* @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() {
@@ -111,8 +108,8 @@ final class EvaluationCycleDetector {
* @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;
}
@@ -132,7 +129,7 @@ final class EvaluationCycleDetector {
* 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");
@@ -140,7 +137,7 @@ final class EvaluationCycleDetector {
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 {"
diff --git a/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java b/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java
index 30e78c33e7..0f1b7bc47c 100644
--- a/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java
+++ b/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java
@@ -20,9 +20,6 @@ package org.apache.poi.ss.usermodel;
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;
@@ -49,8 +46,6 @@ 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.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;
@@ -58,6 +53,7 @@ import org.apache.poi.hssf.record.formula.eval.OperationEval;
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/>
@@ -70,29 +66,37 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
* @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;
@@ -140,7 +144,6 @@ public class FormulaEvaluator {
_cache.clear();
}
-
/**
* If cell contains a formula, the formula is evaluated and returned,
* else the CellValue simply copies the appropriate cell value from
@@ -150,34 +153,23 @@ public class FormulaEvaluator {
* @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() + ")");
}
@@ -200,32 +192,13 @@ public class FormulaEvaluator {
* @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();
}
/**
@@ -245,35 +218,56 @@ public class FormulaEvaluator {
* @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
@@ -287,9 +281,9 @@ public class FormulaEvaluator {
* 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();
@@ -303,72 +297,61 @@ public class FormulaEvaluator {
}
}
-
/**
* 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);
@@ -377,7 +360,7 @@ public class FormulaEvaluator {
}
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);
@@ -392,8 +375,8 @@ public class FormulaEvaluator {
}
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) {
@@ -411,15 +394,15 @@ public class FormulaEvaluator {
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);
}
@@ -428,7 +411,7 @@ public class FormulaEvaluator {
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
@@ -464,24 +447,21 @@ public class FormulaEvaluator {
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
@@ -489,7 +469,7 @@ public class FormulaEvaluator {
* 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;
@@ -499,41 +479,23 @@ public class FormulaEvaluator {
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());
@@ -550,17 +512,38 @@ public class FormulaEvaluator {
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);
}
/**
@@ -568,11 +551,8 @@ public class FormulaEvaluator {
* 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;
@@ -583,7 +563,7 @@ public class FormulaEvaluator {
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:
@@ -600,93 +580,99 @@ public class FormulaEvaluator {
* or Number or boolean type.
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*/
- 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 + ">";
}
}
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/LazyAreaEval.java b/src/java/org/apache/poi/ss/usermodel/LazyAreaEval.java
index 9f38305545..8d9b192291 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/LazyAreaEval.java
+++ b/src/java/org/apache/poi/ss/usermodel/LazyAreaEval.java
@@ -15,22 +15,21 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hssf.record.formula.eval;
+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.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;
+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 final class LazyAreaEval extends AreaEvalBase {
+public class LazyAreaEval extends AreaEvalBase {
private final Sheet _sheet;
private FormulaEvaluator _evaluator;
@@ -54,7 +53,7 @@ public final class LazyAreaEval extends AreaEvalBase {
if (cell == null) {
return BlankEval.INSTANCE;
}
- return _evaluator.getEvalForCell(cell, _sheet);
+ return _evaluator.getEvalForCell(cell);
}
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/LazyRefEval.java b/src/java/org/apache/poi/ss/usermodel/LazyRefEval.java
index b458011972..7fb7681aeb 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/LazyRefEval.java
+++ b/src/java/org/apache/poi/ss/usermodel/LazyRefEval.java
@@ -1,85 +1,85 @@
-/* ====================================================================
- 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.Ref3DPtg;
-import org.apache.poi.hssf.record.formula.RefPtg;
-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 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, _sheet);
- }
-
- 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();
- }
-}
+/* ====================================================================
+ 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();
+ }
+}
diff --git a/src/java/org/apache/poi/util/HexDump.java b/src/java/org/apache/poi/util/HexDump.java
index ed6f128822..c5ebab30a7 100644
--- a/src/java/org/apache/poi/util/HexDump.java
+++ b/src/java/org/apache/poi/util/HexDump.java
@@ -255,8 +255,10 @@ public class HexDump {
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();
diff --git a/src/java/org/apache/poi/util/HexRead.java b/src/java/org/apache/poi/util/HexRead.java
index cd11ccc640..91632e8fc5 100644
--- a/src/java/org/apache/poi/util/HexRead.java
+++ b/src/java/org/apache/poi/util/HexRead.java
@@ -172,9 +172,12 @@ public class HexRead
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
diff --git a/src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Cell.java b/src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Cell.java
index 51d9874edc..823b6191c8 100644
--- a/src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Cell.java
+++ b/src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Cell.java
@@ -19,6 +19,7 @@ package org.apache.poi.ss.usermodel;
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.
@@ -85,6 +86,7 @@ public interface Cell {
void setCellErrorValue(byte value);
HSSFCellStyle getCellStyle();
+ HSSFSheet getSheet();
boolean getBooleanCellValue();
double getNumericCellValue();
diff --git a/src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Comment.java b/src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Comment.java
index 0b1d55c568..1959f9ad56 100644
--- a/src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Comment.java
+++ b/src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Comment.java
@@ -17,4 +17,7 @@
package org.apache.poi.ss.usermodel;
-public interface Comment {}
+public interface Comment {
+ public void setRow(short row);
+ public void setColumn(short row);
+}
diff --git a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Cell.java b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Cell.java
index 0211a9aaa5..29e6bdd8f8 100644
--- a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Cell.java
+++ b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Cell.java
@@ -106,6 +106,8 @@ public interface Cell {
int getRowIndex();
+ Sheet getSheet();
+
/**
* set the cells type (numeric, formula or string)
* @see #CELL_TYPE_NUMERIC
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherBSERecord.java b/src/testcases/org/apache/poi/ddf/TestEscherBSERecord.java
index 7d4dc7bee6..7db08a34a6 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherBSERecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherBSERecord.java
@@ -37,7 +37,7 @@ public class TestEscherBSERecord extends TestCase
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() );
@@ -57,7 +57,7 @@ public class TestEscherBSERecord extends TestCase
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 ) );
}
@@ -90,7 +90,7 @@ public class TestEscherBSERecord extends TestCase
" 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 +
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherBlipWMFRecord.java b/src/testcases/org/apache/poi/ddf/TestEscherBlipWMFRecord.java
index 3f73ccb1c2..8db7c4be38 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherBlipWMFRecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherBlipWMFRecord.java
@@ -1,4 +1,3 @@
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
+
package org.apache.poi.ddf;
import junit.framework.TestCase;
@@ -36,8 +35,7 @@ public class TestEscherBlipWMFRecord extends TestCase
data = HexRead.readFromString(dataStr);
}
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherBlipWMFRecord r = new EscherBlipWMFRecord();
r.setBoundaryLeft(1);
r.setBoundaryHeight(2);
@@ -72,14 +70,13 @@ public class TestEscherBlipWMFRecord extends TestCase
"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());
@@ -92,15 +89,14 @@ public class TestEscherBlipWMFRecord extends TestCase
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() );
@@ -109,7 +105,7 @@ public class TestEscherBlipWMFRecord extends TestCase
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 +
@@ -124,5 +120,5 @@ public class TestEscherBlipWMFRecord extends TestCase
"00000000 01 02 .." + nl
, r.toString() );
}
-
}
+
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherChildAnchorRecord.java b/src/testcases/org/apache/poi/ddf/TestEscherChildAnchorRecord.java
index 545351a3fa..9cf14e47b4 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherChildAnchorRecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherChildAnchorRecord.java
@@ -1,4 +1,3 @@
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
+
package org.apache.poi.ddf;
import junit.framework.TestCase;
@@ -24,8 +23,7 @@ import org.apache.poi.util.HexRead;
public class TestEscherChildAnchorRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherChildAnchorRecord r = createRecord();
byte[] data = new byte[8 + 16];
@@ -37,7 +35,7 @@ public class TestEscherChildAnchorRecord extends TestCase
"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
@@ -62,8 +60,7 @@ public class TestEscherChildAnchorRecord extends TestCase
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 +
@@ -76,7 +73,7 @@ public class TestEscherChildAnchorRecord extends TestCase
assertEquals( expected, createRecord().toString() );
}
- private EscherChildAnchorRecord createRecord()
+ private static EscherChildAnchorRecord createRecord()
{
EscherChildAnchorRecord r = new EscherChildAnchorRecord();
r.setRecordId( EscherChildAnchorRecord.RECORD_ID );
@@ -87,5 +84,5 @@ public class TestEscherChildAnchorRecord extends TestCase
r.setDy2( 4 );
return r;
}
-
}
+
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherClientAnchorRecord.java b/src/testcases/org/apache/poi/ddf/TestEscherClientAnchorRecord.java
index c058622dbc..3a1e5c2b60 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherClientAnchorRecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherClientAnchorRecord.java
@@ -1,4 +1,3 @@
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
+
package org.apache.poi.ddf;
import junit.framework.TestCase;
@@ -24,8 +23,7 @@ import org.apache.poi.util.HexRead;
public class TestEscherClientAnchorRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherClientAnchorRecord r = createRecord();
byte[] data = new byte[8 + 18 + 2];
@@ -37,11 +35,10 @@ public class TestEscherClientAnchorRecord extends TestCase
"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 " +
@@ -68,8 +65,7 @@ public class TestEscherClientAnchorRecord extends TestCase
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 +
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherClientDataRecord.java b/src/testcases/org/apache/poi/ddf/TestEscherClientDataRecord.java
index 22a11181c6..2f26a37c5a 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherClientDataRecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherClientDataRecord.java
@@ -1,4 +1,3 @@
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
+
package org.apache.poi.ddf;
import junit.framework.TestCase;
@@ -24,8 +23,7 @@ import org.apache.poi.util.HexRead;
public class TestEscherClientDataRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherClientDataRecord r = createRecord();
byte[] data = new byte[8];
@@ -33,12 +31,11 @@ public class TestEscherClientDataRecord extends TestCase
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 ";
@@ -51,8 +48,7 @@ public class TestEscherClientDataRecord extends TestCase
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 +
@@ -63,7 +59,7 @@ public class TestEscherClientDataRecord extends TestCase
assertEquals( expected, createRecord().toString() );
}
- private EscherClientDataRecord createRecord()
+ private static EscherClientDataRecord createRecord()
{
EscherClientDataRecord r = new EscherClientDataRecord();
r.setOptions( (short) 0x0002 );
@@ -71,5 +67,4 @@ public class TestEscherClientDataRecord extends TestCase
r.setRemainingData( new byte[] {} );
return r;
}
-
}
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherContainerRecord.java b/src/testcases/org/apache/poi/ddf/TestEscherContainerRecord.java
index 0f1fc9c733..490a3d50ca 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherContainerRecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherContainerRecord.java
@@ -30,13 +30,11 @@ public class TestEscherContainerRecord extends TestCase
{
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 );
@@ -55,15 +53,14 @@ public class TestEscherContainerRecord extends TestCase
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 );
@@ -72,12 +69,11 @@ public class TestEscherContainerRecord extends TestCase
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 );
@@ -134,8 +130,7 @@ public class TestEscherContainerRecord extends TestCase
assertEquals( expected, r.toString() );
}
- public void testGetRecordSize() throws Exception
- {
+ public void testGetRecordSize() {
EscherContainerRecord r = new EscherContainerRecord();
r.addChildRecord(new EscherRecord()
{
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherDgRecord.java b/src/testcases/org/apache/poi/ddf/TestEscherDgRecord.java
index c1be281720..70ddd47330 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherDgRecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherDgRecord.java
@@ -1,4 +1,3 @@
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
+
package org.apache.poi.ddf;
import junit.framework.TestCase;
@@ -24,8 +23,7 @@ import org.apache.poi.util.HexRead;
public class TestEscherDgRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherDgRecord r = createRecord();
byte[] data = new byte[16];
@@ -35,12 +33,11 @@ public class TestEscherDgRecord extends TestCase
"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 " +
@@ -55,8 +52,7 @@ public class TestEscherDgRecord extends TestCase
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 +
@@ -67,7 +63,7 @@ public class TestEscherDgRecord extends TestCase
assertEquals( expected, createRecord().toString() );
}
- private EscherDgRecord createRecord()
+ private static EscherDgRecord createRecord()
{
EscherDgRecord r = new EscherDgRecord();
r.setOptions( (short) 0x0010 );
@@ -76,5 +72,4 @@ public class TestEscherDgRecord extends TestCase
r.setLastMSOSPID(1025);
return r;
}
-
}
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherDggRecord.java b/src/testcases/org/apache/poi/ddf/TestEscherDggRecord.java
index afecbf3c99..8968066959 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherDggRecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherDggRecord.java
@@ -1,4 +1,3 @@
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
+
package org.apache.poi.ddf;
import junit.framework.TestCase;
@@ -24,8 +23,7 @@ import org.apache.poi.util.HexRead;
public class TestEscherDggRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherDggRecord r = createRecord();
byte[] data = new byte[32];
@@ -38,12 +36,11 @@ public class TestEscherDggRecord extends TestCase
"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 " +
@@ -66,8 +63,7 @@ public class TestEscherDggRecord extends TestCase
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 +
@@ -82,7 +78,7 @@ public class TestEscherDggRecord extends TestCase
assertEquals( expected, createRecord().toString() );
}
- private EscherDggRecord createRecord()
+ private static EscherDggRecord createRecord()
{
EscherDggRecord r = new EscherDggRecord();
r.setOptions( (short) 0x0000 );
@@ -96,12 +92,9 @@ public class TestEscherDggRecord extends TestCase
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());
-
}
-
}
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherOptRecord.java b/src/testcases/org/apache/poi/ddf/TestEscherOptRecord.java
index fe996f636b..a96ba84968 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherOptRecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherOptRecord.java
@@ -24,20 +24,16 @@ import org.apache.poi.util.HexDump;
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 " +
@@ -60,9 +56,7 @@ public class TestEscherOptRecord extends TestCase
}
- private void checkFillFieldsSimple()
- throws IOException
- {
+ private void checkFillFieldsSimple() {
String dataStr = "33 00 " + // options
"0B F0 " + // recordid
"12 00 00 00 " + // remaining bytes
@@ -83,8 +77,7 @@ public class TestEscherOptRecord extends TestCase
assertEquals( prop3, r.getEscherProperty( 2 ) );
}
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
checkSerializeSimple();
checkSerializeComplex();
}
@@ -111,7 +104,7 @@ public class TestEscherOptRecord extends TestCase
"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) );
}
@@ -135,13 +128,12 @@ public class TestEscherOptRecord extends TestCase
"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);
@@ -162,8 +154,8 @@ public class TestEscherOptRecord extends TestCase
* 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
@@ -263,7 +255,7 @@ public class TestEscherOptRecord extends TestCase
*
* 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 " +
@@ -315,7 +307,7 @@ public class TestEscherOptRecord extends TestCase
* 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());
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherPropertyFactory.java b/src/testcases/org/apache/poi/ddf/TestEscherPropertyFactory.java
index f79b27c637..aef2c72add 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherPropertyFactory.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherPropertyFactory.java
@@ -1,4 +1,3 @@
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
+
package org.apache.poi.ddf;
import junit.framework.TestCase;
@@ -30,8 +29,7 @@ import org.apache.poi.util.HexDump;
*/
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
@@ -46,15 +44,11 @@ public class TestEscherPropertyFactory extends TestCase
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() ) );
}
-
-
-
}
+
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherSpRecord.java b/src/testcases/org/apache/poi/ddf/TestEscherSpRecord.java
index 4521727e0a..b4ab900ea9 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherSpRecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherSpRecord.java
@@ -1,4 +1,3 @@
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
+
package org.apache.poi.ddf;
import junit.framework.TestCase;
@@ -24,8 +23,7 @@ import org.apache.poi.util.HexRead;
public class TestEscherSpRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherSpRecord r = createRecord();
byte[] data = new byte[16];
@@ -35,12 +33,11 @@ public class TestEscherSpRecord extends TestCase
"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 " +
@@ -55,8 +52,7 @@ public class TestEscherSpRecord extends TestCase
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 +
@@ -67,7 +63,7 @@ public class TestEscherSpRecord extends TestCase
assertEquals( expected, createRecord().toString() );
}
- private EscherSpRecord createRecord()
+ private static EscherSpRecord createRecord()
{
EscherSpRecord r = new EscherSpRecord();
r.setOptions( (short) 0x0002 );
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherSpgrRecord.java b/src/testcases/org/apache/poi/ddf/TestEscherSpgrRecord.java
index f640183097..9feca0abbc 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherSpgrRecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherSpgrRecord.java
@@ -1,4 +1,3 @@
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
+
package org.apache.poi.ddf;
import junit.framework.TestCase;
@@ -24,8 +23,7 @@ import org.apache.poi.util.HexRead;
public class TestEscherSpgrRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherSpgrRecord r = createRecord();
byte[] data = new byte[24];
@@ -37,12 +35,11 @@ public class TestEscherSpgrRecord extends TestCase
"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 " +
@@ -61,8 +58,7 @@ public class TestEscherSpgrRecord extends TestCase
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 +
@@ -72,11 +68,10 @@ public class TestEscherSpgrRecord extends TestCase
" 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 );
@@ -87,5 +82,4 @@ public class TestEscherSpgrRecord extends TestCase
r.setRectY2(4);
return r;
}
-
}
diff --git a/src/testcases/org/apache/poi/ddf/TestEscherSplitMenuColorsRecord.java b/src/testcases/org/apache/poi/ddf/TestEscherSplitMenuColorsRecord.java
index 1163575eb8..d9a9080713 100644
--- a/src/testcases/org/apache/poi/ddf/TestEscherSplitMenuColorsRecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestEscherSplitMenuColorsRecord.java
@@ -24,8 +24,7 @@ import org.apache.poi.util.HexRead;
public class TestEscherSplitMenuColorsRecord extends TestCase
{
- public void testSerialize() throws Exception
- {
+ public void testSerialize() {
EscherSplitMenuColorsRecord r = createRecord();
byte[] data = new byte[24];
@@ -37,12 +36,11 @@ public class TestEscherSplitMenuColorsRecord extends TestCase
"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 " +
@@ -61,8 +59,7 @@ public class TestEscherSplitMenuColorsRecord extends TestCase
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 +
@@ -76,7 +73,7 @@ public class TestEscherSplitMenuColorsRecord extends TestCase
assertEquals( expected, createRecord().toString() );
}
- private EscherSplitMenuColorsRecord createRecord()
+ private static EscherSplitMenuColorsRecord createRecord()
{
EscherSplitMenuColorsRecord r = new EscherSplitMenuColorsRecord();
r.setOptions( (short) 0x0040 );
@@ -87,5 +84,4 @@ public class TestEscherSplitMenuColorsRecord extends TestCase
r.setColor4( 0x1 );
return r;
}
-
}
diff --git a/src/testcases/org/apache/poi/ddf/TestUnknownEscherRecord.java b/src/testcases/org/apache/poi/ddf/TestUnknownEscherRecord.java
index 9845a58891..d8c36e1a5c 100644
--- a/src/testcases/org/apache/poi/ddf/TestUnknownEscherRecord.java
+++ b/src/testcases/org/apache/poi/ddf/TestUnknownEscherRecord.java
@@ -24,8 +24,7 @@ import org.apache.poi.util.HexDump;
public class TestUnknownEscherRecord extends TestCase
{
- public void testFillFields() throws Exception
- {
+ public void testFillFields() {
String testData =
"0F 02 " + // options
"11 F1 " + // record id
@@ -82,15 +81,14 @@ public class TestUnknownEscherRecord extends TestCase
}
- 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 );
@@ -100,11 +98,10 @@ public class TestUnknownEscherRecord extends TestCase
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 );
@@ -119,6 +116,4 @@ public class TestUnknownEscherRecord extends TestCase
" numchildren: 0" + nl
, r.toString() );
}
-
-
}
diff --git a/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls b/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
index e4c8e42dcb..f806c792f6 100644
--- a/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
+++ b/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
Binary files differ
diff --git a/src/testcases/org/apache/poi/hssf/data/IndexFunctionTestCaseData.xls b/src/testcases/org/apache/poi/hssf/data/IndexFunctionTestCaseData.xls
new file mode 100644
index 0000000000..9dcde61772
--- /dev/null
+++ b/src/testcases/org/apache/poi/hssf/data/IndexFunctionTestCaseData.xls
Binary files differ
diff --git a/src/testcases/org/apache/poi/hssf/data/testRVA.xls b/src/testcases/org/apache/poi/hssf/data/testRVA.xls
index 17aa9fd710..f24b6926e8 100644
--- a/src/testcases/org/apache/poi/hssf/data/testRVA.xls
+++ b/src/testcases/org/apache/poi/hssf/data/testRVA.xls
Binary files differ
diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
index c9fea7f1e4..e1ffc2538d 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
@@ -22,10 +22,12 @@ import junit.framework.TestCase;
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;
@@ -48,6 +50,7 @@ import org.apache.poi.hssf.record.formula.SubtractPtg;
import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
import org.apache.poi.hssf.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;
@@ -862,4 +865,18 @@ public final class TestFormulaParser extends TestCase {
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
diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java
index d89ffee3eb..bd40e3d05a 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java
@@ -85,7 +85,7 @@ public final class TestFormulaParserEval extends TestCase {
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);
diff --git a/src/testcases/org/apache/poi/hssf/model/TestRVA.java b/src/testcases/org/apache/poi/hssf/model/TestRVA.java
index ca74c6e2db..1ec7c92ae9 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestRVA.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestRVA.java
@@ -61,8 +61,10 @@ public final class TestRVA extends TestCase {
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 + "'");
@@ -104,8 +106,8 @@ public final class TestRVA extends TestCase {
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;
}
@@ -113,16 +115,16 @@ public final class TestRVA extends TestCase {
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) {
@@ -135,14 +137,4 @@ public final class TestRVA extends TestCase {
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 + ")");
- }
}
diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheet.java b/src/testcases/org/apache/poi/hssf/model/TestSheet.java
index ca6a10f45e..3bc79299b5 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestSheet.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestSheet.java
@@ -214,7 +214,9 @@ public final class TestSheet extends TestCase {
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());
@@ -357,7 +359,7 @@ public final class TestSheet extends TestCase {
xfindex = sheet.getXFIndexForColAt((short) 1);
assertEquals(DEFAULT_IDX, xfindex);
- ColumnInfoRecord nci = ColumnInfoRecordsAggregate.createColInfo();
+ ColumnInfoRecord nci = new ColumnInfoRecord();
sheet._columnInfos.insertColumn(nci);
// single column ColumnInfoRecord
@@ -567,7 +569,7 @@ public final class TestSheet extends TestCase {
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");
@@ -576,4 +578,3 @@ public final class TestSheet extends TestCase {
}
}
}
-
diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java b/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java
index 0962b9148a..477908dc72 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java
@@ -20,7 +20,6 @@ package org.apache.poi.hssf.model;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.ColumnInfoRecord;
-import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
/**
* @author Tony Poppleton
@@ -29,7 +28,7 @@ public final class TestSheetAdditional extends TestCase {
public void testGetCellWidth() {
Sheet sheet = Sheet.createSheet();
- ColumnInfoRecord nci = ColumnInfoRecordsAggregate.createColInfo();
+ ColumnInfoRecord nci = new ColumnInfoRecord();
// Prepare test model
nci.setFirstColumn((short)5);
@@ -55,5 +54,4 @@ public final class TestSheetAdditional extends TestCase {
assertEquals((short)100,sheet.getColumnWidth((short)9));
assertEquals((short)100,sheet.getColumnWidth((short)10));
}
-
}
diff --git a/src/testcases/org/apache/poi/hssf/record/TestDrawingGroupRecord.java b/src/testcases/org/apache/poi/hssf/record/TestDrawingGroupRecord.java
index d248baf304..17d6475e8b 100644
--- a/src/testcases/org/apache/poi/hssf/record/TestDrawingGroupRecord.java
+++ b/src/testcases/org/apache/poi/hssf/record/TestDrawingGroupRecord.java
@@ -22,14 +22,11 @@ import org.apache.poi.ddf.EscherContainerRecord;
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());
@@ -48,7 +45,7 @@ public class TestDrawingGroupRecord extends TestCase
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());
@@ -65,8 +62,7 @@ public class TestDrawingGroupRecord extends TestCase
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];
@@ -76,7 +72,7 @@ public class TestDrawingGroupRecord extends TestCase
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];
@@ -92,8 +88,8 @@ public class TestDrawingGroupRecord extends TestCase
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];
@@ -103,9 +99,9 @@ public class TestDrawingGroupRecord extends TestCase
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];
@@ -116,7 +112,7 @@ public class TestDrawingGroupRecord extends TestCase
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];
@@ -124,8 +120,7 @@ public class TestDrawingGroupRecord extends TestCase
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 ) );
@@ -139,6 +134,4 @@ public class TestDrawingGroupRecord extends TestCase
assertEquals( MAX_RECORD_SIZE * 2, DrawingGroupRecord.grossSizeFromDataSize( MAX_DATA_SIZE * 2 ) );
assertEquals( MAX_RECORD_SIZE * 2 + 5, DrawingGroupRecord.grossSizeFromDataSize( MAX_DATA_SIZE * 2 + 1 ) );
}
-
-
}
diff --git a/src/testcases/org/apache/poi/hssf/record/TestEscherAggregate.java b/src/testcases/org/apache/poi/hssf/record/TestEscherAggregate.java
index 21be7ad1d0..593290b337 100644
--- a/src/testcases/org/apache/poi/hssf/record/TestEscherAggregate.java
+++ b/src/testcases/org/apache/poi/hssf/record/TestEscherAggregate.java
@@ -133,7 +133,7 @@ public class TestEscherAggregate extends TestCase
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 ) );
}
diff --git a/src/testcases/org/apache/poi/hssf/record/TestFormulaRecord.java b/src/testcases/org/apache/poi/hssf/record/TestFormulaRecord.java
index 0d96d737cf..4696539f23 100644
--- a/src/testcases/org/apache/poi/hssf/record/TestFormulaRecord.java
+++ b/src/testcases/org/apache/poi/hssf/record/TestFormulaRecord.java
@@ -26,12 +26,14 @@ import org.apache.poi.hssf.record.formula.FuncVarPtg;
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 {
@@ -40,52 +42,66 @@ 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;
@@ -99,13 +115,13 @@ public final class TestFormulaRecord extends TestCase {
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
@@ -115,14 +131,14 @@ public final class TestFormulaRecord extends TestCase {
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());
@@ -134,7 +150,7 @@ public final class TestFormulaRecord extends TestCase {
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());
}
diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java
index 2988290616..6c981cab5e 100644
--- a/src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java
+++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java
@@ -17,9 +17,16 @@
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
@@ -28,11 +35,11 @@ public final class TestColumnInfoRecordsAggregate extends TestCase {
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);
@@ -48,10 +55,91 @@ public final class TestColumnInfoRecordsAggregate extends TestCase {
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());
+ }
+}
diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java
index 9b95356027..978f400fcd 100644
--- a/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java
+++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java
@@ -30,6 +30,7 @@ public final class TestFormulaRecordAggregate extends TestCase {
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);
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java b/src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java
index 9e5a340045..2455c87ab9 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java
@@ -35,9 +35,8 @@ import junit.framework.TestCase;
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
@@ -60,15 +59,15 @@ public final class TestArrayPtg extends TestCase {
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);
@@ -89,10 +88,10 @@ public final class TestArrayPtg extends TestCase {
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));
}
@@ -110,7 +109,7 @@ public final class TestArrayPtg extends TestCase {
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() {
@@ -127,7 +126,7 @@ public final class TestArrayPtg extends TestCase {
}
throw e;
}
- assertEquals("{TRUE,\"ABCD\";\"E\",0.0;FALSE,\"FG\"}", actualFormula);
+ assertEquals("{TRUE,\"ABCD\",\"E\";0.0,FALSE,\"FG\"}", actualFormula);
}
/**
@@ -150,6 +149,7 @@ public final class TestArrayPtg extends TestCase {
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());
}
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java b/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java
index c1087c1fc4..7e71889d8b 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java
@@ -74,7 +74,7 @@ public final class TestExternalFunctionFormulas extends TestCase {
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);
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculatorFromSpreadsheet.java b/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculatorFromSpreadsheet.java
index 2cad8e3620..37d1bb314b 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculatorFromSpreadsheet.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculatorFromSpreadsheet.java
@@ -56,7 +56,7 @@ public final class TestYearFracCalculatorFromSpreadsheet extends TestCase {
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;
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java
index 07f13a0445..74691b27dd 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java
@@ -35,9 +35,9 @@ public final class TestCircularReferences extends TestCase {
/**
* 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) {
@@ -75,7 +75,7 @@ public final class TestCircularReferences extends TestCase {
// 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);
@@ -93,7 +93,7 @@ public final class TestCircularReferences extends TestCase {
HSSFCell testCell = row.createCell(0);
testCell.setCellFormula("A1");
- CellValue cellValue = evaluateWithCycles(wb, sheet, testCell);
+ CellValue cellValue = evaluateWithCycles(wb, testCell);
confirmCycleErrorCode(cellValue);
}
@@ -113,7 +113,7 @@ public final class TestCircularReferences extends TestCase {
HSSFCell testCell = row.createCell(3);
testCell.setCellFormula("A1");
- CellValue cellValue = evaluateWithCycles(wb, sheet, testCell);
+ CellValue cellValue = evaluateWithCycles(wb, testCell);
confirmCycleErrorCode(cellValue);
}
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java
index e1bed55c51..95408a4aaf 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java
@@ -65,7 +65,7 @@ public final class TestExternalFunction extends TestCase {
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()
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java
index da110a020c..257bb8f711 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java
@@ -66,7 +66,7 @@ public final class TestFormulaBugs extends TestCase {
.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());
@@ -111,7 +111,7 @@ public final class TestFormulaBugs extends TestCase {
}
// 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());
@@ -162,7 +162,7 @@ public final class TestFormulaBugs extends TestCase {
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());
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java
index ffe4bffc0a..74b436cdb7 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java
@@ -113,15 +113,6 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
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());
@@ -132,32 +123,27 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
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;
@@ -192,8 +178,7 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
* 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) {
@@ -263,7 +248,7 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
result = Result.SOME_EVALUATIONS_FAILED;
}
}
- return result;
+ return result;
}
/**
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java
index ef2340d4a4..bac2e68862 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java
@@ -67,7 +67,7 @@ public final class TestPercentEval extends TestCase {
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);
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java
index 2ec7ad005a..4ae90d067b 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java
@@ -34,6 +34,7 @@ public final class AllIndividualFunctionEvaluationTests {
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);
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestAverage.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestAverage.java
index 4f0e5fff2c..727f6b7645 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestAverage.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestAverage.java
@@ -27,14 +27,13 @@ import org.apache.poi.hssf.record.formula.eval.NumberEval;
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) {
@@ -48,56 +47,56 @@ public final class TestAverage extends TestCase {
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);
-
+
}
}
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
index 41d703e2cf..8e5a8f32a4 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
@@ -21,13 +21,11 @@ import junit.framework.AssertionFailedError;
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;
@@ -270,7 +268,7 @@ public final class TestCountFuncs extends TestCase {
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);
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDate.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDate.java
index 68bc43154a..0c08ef5a54 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDate.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDate.java
@@ -37,7 +37,7 @@ public final class TestDate extends TestCase {
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);
}
/**
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java
index 80c154596e..95355733d2 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java
@@ -48,11 +48,11 @@ public final class TestIndex extends TestCase {
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);
}
/**
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndexFunctionFromSpreadsheet.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndexFunctionFromSpreadsheet.java
new file mode 100644
index 0000000000..f28a6462f8
--- /dev/null
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndexFunctionFromSpreadsheet.java
@@ -0,0 +1,250 @@
+/* ====================================================================
+ 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());
+ }
+ }
+}
+
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIsBlank.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIsBlank.java
index 62cc32e957..50f92dfecf 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIsBlank.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIsBlank.java
@@ -44,7 +44,7 @@ public final class TestIsBlank extends TestCase {
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());
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLen.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLen.java
index a96fb4e2b0..459d2fb555 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLen.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLen.java
@@ -35,7 +35,7 @@ public final class TestLen extends TestCase {
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) {
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLookupFunctionsFromSpreadsheet.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLookupFunctionsFromSpreadsheet.java
index fe0bab0a0d..49d67a8d4e 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLookupFunctionsFromSpreadsheet.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLookupFunctionsFromSpreadsheet.java
@@ -37,33 +37,33 @@ import org.apache.poi.hssf.util.CellReference;
* 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 */
@@ -71,15 +71,15 @@ public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
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;
@@ -105,19 +105,19 @@ public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
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;
}
}
@@ -125,14 +125,14 @@ public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
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)
);
@@ -141,15 +141,15 @@ public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
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())
+ ")");
}
}
@@ -164,57 +164,48 @@ public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
}
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);
@@ -240,7 +231,7 @@ public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
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);
@@ -257,22 +248,22 @@ public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
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);
@@ -288,13 +279,13 @@ public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
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) {
@@ -313,7 +304,7 @@ public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
*/
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) {
@@ -339,17 +330,17 @@ public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
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
*/
@@ -367,7 +358,7 @@ public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
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) + ")");
}
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMid.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMid.java
index 76cd1056ed..81e78e737c 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMid.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMid.java
@@ -38,7 +38,7 @@ public final class TestMid extends TestCase {
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) {
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestPmt.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestPmt.java
index 2fecef7046..9a4cded9af 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestPmt.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestPmt.java
@@ -36,7 +36,7 @@ public final class TestPmt extends TestCase {
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
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestRoundFuncs.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestRoundFuncs.java
index a6ce345aeb..9dbbb438e0 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestRoundFuncs.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestRoundFuncs.java
@@ -17,24 +17,25 @@
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);
}
@@ -42,7 +43,7 @@ public final class TestRoundFuncs extends TestCase {
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);
}
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestStatsLib.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestStatsLib.java
index 237366baf0..3562a67789 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestStatsLib.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestStatsLib.java
@@ -20,6 +20,11 @@
*/
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 &lt; amolweb at ya hoo dot com &gt;
@@ -181,49 +186,53 @@ public class TestStatsLib extends AbstractNumericTestCase {
}
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;
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrim.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrim.java
index 076ac1fc7e..1c65c9ca6d 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrim.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrim.java
@@ -35,7 +35,7 @@ public final class TestTrim extends TestCase {
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) {
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java
index c128c773c5..a43764e852 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java
@@ -43,10 +43,9 @@ public final class TestBug42464 extends TestCase {
}
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()) {
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBug43093.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBug43093.java
index 1989d7d4e7..3dbf5907ff 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestBug43093.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBug43093.java
@@ -39,7 +39,7 @@ public final class TestBug43093 extends TestCase {
}
public void testBug43093() {
- HSSFWorkbook xlw = new HSSFWorkbook();
+ HSSFWorkbook xlw = new HSSFWorkbook();
addNewSheetWithCellsA1toD4(xlw, 1);
addNewSheetWithCellsA1toD4(xlw, 2);
@@ -51,7 +51,7 @@ public final class TestBug43093 extends TestCase {
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
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
index 200e62884a..8954656c6e 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
@@ -963,7 +963,7 @@ public final class TestBugs extends TestCase {
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);
}
-
+
/**
* Problems with extracting check boxes from
* HSSFObjectData
@@ -975,35 +975,35 @@ public final class TestBugs extends TestCase {
// 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
@@ -1013,73 +1013,73 @@ public final class TestBugs extends TestCase {
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!
@@ -1096,22 +1096,22 @@ public final class TestBugs extends TestCase {
!=
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);
@@ -1120,32 +1120,32 @@ public final class TestBugs extends TestCase {
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"
@@ -1162,63 +1162,59 @@ public final class TestBugs extends TestCase {
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());
@@ -1235,7 +1231,18 @@ public final class TestBugs extends TestCase {
}
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
@@ -1244,37 +1251,37 @@ public final class TestBugs extends TestCase {
* {=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
@@ -1282,48 +1289,48 @@ public final class TestBugs extends TestCase {
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
*/
@@ -1332,25 +1339,25 @@ public final class TestBugs extends TestCase {
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
}
@@ -1363,7 +1370,7 @@ public final class TestBugs extends TestCase {
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
@@ -1373,41 +1380,41 @@ public final class TestBugs extends TestCase {
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));
}
}
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java
index f1d838efa3..dc4454d515 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java
@@ -117,7 +117,7 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
HSSFSheet sheet = wb.getSheetAt(0);
- HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(wb);
row = sheet.getRow(0);
cell = row.getCell(0);
@@ -177,7 +177,7 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
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);
@@ -238,7 +238,7 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
cell.setCellFormula("1=1");
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
try {
fe.evaluateInCell(cell);
} catch (NumberFormatException e) {
@@ -257,7 +257,7 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
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();
@@ -276,7 +276,7 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
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) {
@@ -312,7 +312,7 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
// 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
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java
index bed8869d54..d2c9d0753c 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java
@@ -68,7 +68,7 @@ public final class TestFormulaEvaluatorDocs extends TestCase {
// 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();
@@ -103,7 +103,7 @@ public final class TestFormulaEvaluatorDocs extends TestCase {
// 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();
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java
index f1be47fd1b..e1a6e1b3ca 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java
@@ -243,7 +243,7 @@ public final class TestHSSFDataFormatter extends TestCase {
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));
}
@@ -257,7 +257,7 @@ public final class TestHSSFDataFormatter extends TestCase {
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();
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java
index 970b166dd7..d1c511feb2 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java
@@ -35,7 +35,7 @@ public final class TestHSSFFormulaEvaluator extends TestCase {
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);
@@ -67,7 +67,7 @@ public final class TestHSSFFormulaEvaluator extends TestCase {
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);
}