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 0058985ae..3a6354e01 100644 --- a/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java @@ -19,6 +19,7 @@ package org.apache.poi.hssf.record.formula; import org.apache.poi.hssf.record.constant.ConstantValueParser; import org.apache.poi.hssf.record.constant.ErrorConstant; +import org.apache.poi.ss.util.NumberToTextConverter; import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianOutput; @@ -193,7 +194,7 @@ public final class ArrayPtg extends Ptg { return "\"" + (String)o + "\""; } if (o instanceof Double) { - return ((Double)o).toString(); + return NumberToTextConverter.toText(((Double)o).doubleValue()); } if (o instanceof Boolean) { return ((Boolean)o).booleanValue() ? "TRUE" : "FALSE"; diff --git a/src/java/org/apache/poi/ss/formula/FormulaParser.java b/src/java/org/apache/poi/ss/formula/FormulaParser.java index a750ed13f..d7827b137 100644 --- a/src/java/org/apache/poi/ss/formula/FormulaParser.java +++ b/src/java/org/apache/poi/ss/formula/FormulaParser.java @@ -21,16 +21,15 @@ import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; -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.hssf.usermodel.HSSFErrorConstants; +import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.util.AreaReference; import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference.NameType; -import org.apache.poi.ss.SpreadsheetVersion; /** * This class parses a formula string into a List of tokens in RPN order. @@ -1205,7 +1204,7 @@ public final class FormulaParser { private Object parseArrayItem() { SkipWhite(); switch(look) { - case '"': return new UnicodeString(parseStringLiteral()); + case '"': return parseStringLiteral(); case '#': return ErrorConstant.valueOf(parseErrorLiteral()); case 'F': case 'f': case 'T': case 't': diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java index cdf42e07f..5891831cb 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java +++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java @@ -17,11 +17,14 @@ package org.apache.poi.hssf.model; +import java.util.Arrays; + import junit.framework.AssertionFailedError; import junit.framework.TestCase; import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.record.NameRecord; +import org.apache.poi.hssf.record.UnicodeString; import org.apache.poi.hssf.record.constant.ErrorConstant; import org.apache.poi.hssf.record.formula.AbstractFunctionPtg; import org.apache.poi.hssf.record.formula.AddPtg; @@ -71,6 +74,8 @@ import org.apache.poi.ss.formula.FormulaParser; import org.apache.poi.ss.formula.FormulaType; import org.apache.poi.ss.usermodel.BaseTestBugzillaIssues; import org.apache.poi.ss.usermodel.Name; +import org.apache.poi.util.HexRead; +import org.apache.poi.util.LittleEndianByteArrayInputStream; /** * Test the low level formula parser functionality. High level tests are to @@ -830,7 +835,7 @@ public final class TestFormulaParser extends TestCase { Ptg[] ptgs; ptgs = parseFormula("mode({1,2,2,#REF!;FALSE,3,3,2})"); confirmTokenClasses(ptgs, ArrayPtg.class, FuncVarPtg.class); - assertEquals("{1.0,2.0,2.0,#REF!;FALSE,3.0,3.0,2.0}", ptgs[0].toFormulaString()); + assertEquals("{1,2,2,#REF!;FALSE,3,3,2}", ptgs[0].toFormulaString()); ArrayPtg aptg = (ArrayPtg) ptgs[0]; Object[][] values = aptg.getTokenArrayValues(); @@ -838,6 +843,34 @@ public final class TestFormulaParser extends TestCase { assertEquals(Boolean.FALSE, values[1][0]); } + public void testParseStringElementInArray() { + Ptg[] ptgs; + ptgs = parseFormula("MAX({\"5\"},3)"); + confirmTokenClasses(ptgs, ArrayPtg.class, IntPtg.class, FuncVarPtg.class); + Object element = ((ArrayPtg)ptgs[0]).getTokenArrayValues()[0][0]; + if (element instanceof UnicodeString) { + // this would cause ClassCastException below + throw new AssertionFailedError("Wrong encoding of array element value"); + } + assertEquals(String.class, element.getClass()); + + // make sure the formula encodes OK + int encSize = Ptg.getEncodedSize(ptgs); + byte[] data = new byte[encSize]; + Ptg.serializePtgs(ptgs, data, 0); + byte[] expData = HexRead.readFromString( + "20 00 00 00 00 00 00 00 " // tArray + + "1E 03 00 " // tInt(3) + + "42 02 07 00 " // tFuncVar(MAX) 2-arg + + "00 00 00 " // Array data: 1 col, 1 row + + "02 01 00 00 35" // elem (type=string, len=1, "5") + ); + assertTrue(Arrays.equals(expData, data)); + int initSize = Ptg.getEncodedSizeWithoutArrayData(ptgs); + Ptg[] ptgs2 = Ptg.readTokens(initSize, new LittleEndianByteArrayInputStream(data)); + confirmTokenClasses(ptgs2, ArrayPtg.class, IntPtg.class, FuncVarPtg.class); + } + public void testRangeOperator() { HSSFWorkbook wb = new HSSFWorkbook(); 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 b7eed27df..3379cee28 100644 --- a/src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java @@ -106,12 +106,11 @@ public final class TestArrayPtg extends TestCase { // The formula has an array with 3 rows and 5 columns String formula = wb.getSheetAt(0).getRow(0).getCell(0).getCellFormula(); - // TODO - These number literals should not have '.0'. Excel has different number rendering rules - 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})")) { + if (formula.equals("SUM({1,6,11;2,7,12;3,8,13;4,9,14;5,10,15})")) { 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,2,3,4,5;6,7,8,9,10;11,12,13,14,15})", formula); } public void testToFormulaString() { @@ -125,7 +124,7 @@ public final class TestArrayPtg extends TestCase { } throw e; } - assertEquals("{TRUE,\"ABCD\",\"E\";0.0,FALSE,\"FG\"}", actualFormula); + assertEquals("{TRUE,\"ABCD\",\"E\";0,FALSE,\"FG\"}", actualFormula); } /**