diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 59bd2eab7a..c691408478 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -36,6 +36,7 @@ + 42464 - Avoid "Expected ExpPtg to be converted from Shared to Non-Shared Formula" on large, formula heavy worksheets 42033 - Add support for named ranges with unicode names 34023 - When shifting rows, update formulas on that sheet to point to the new location of those rows Support getting all the cells referenced by an AreaReference, not just the corner ones diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 5844821008..6cac38bf52 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -33,6 +33,7 @@ + 42464 - Avoid "Expected ExpPtg to be converted from Shared to Non-Shared Formula" on large, formula heavy worksheets 42033 - Add support for named ranges with unicode names 34023 - When shifting rows, update formulas on that sheet to point to the new location of those rows Support getting all the cells referenced by an AreaReference, not just the corner ones diff --git a/src/java/org/apache/poi/hssf/record/FormulaRecord.java b/src/java/org/apache/poi/hssf/record/FormulaRecord.java index f864cc63ea..eba34a3073 100644 --- a/src/java/org/apache/poi/hssf/record/FormulaRecord.java +++ b/src/java/org/apache/poi/hssf/record/FormulaRecord.java @@ -199,11 +199,24 @@ public class FormulaRecord public boolean isSharedFormula() { return sharedFormula.isSet(field_5_options); } - public void setSharedFormula(boolean flag) { sharedFormula.setBoolean(field_5_options, flag); } + public boolean isAlwaysCalc() { + return alwaysCalc.isSet(field_5_options); + } + public void setAlwaysCalc(boolean flag) { + alwaysCalc.setBoolean(field_5_options, flag); + } + + public boolean isCalcOnLoad() { + return calcOnLoad.isSet(field_5_options); + } + public void setCalcOnLoad(boolean flag) { + calcOnLoad.setBoolean(field_5_options, flag); + } + /** * get the length (in number of tokens) of the expression * @return expression length diff --git a/src/java/org/apache/poi/hssf/record/RecordInputStream.java b/src/java/org/apache/poi/hssf/record/RecordInputStream.java index 399e0f566d..dd853f2463 100755 --- a/src/java/org/apache/poi/hssf/record/RecordInputStream.java +++ b/src/java/org/apache/poi/hssf/record/RecordInputStream.java @@ -133,6 +133,9 @@ public class RecordInputStream extends InputStream } } + /** + * Reads an 8 bit, signed value + */ public byte readByte() { checkRecordPosition(); @@ -141,7 +144,10 @@ public class RecordInputStream extends InputStream pos += 1; return result; } - + + /** + * Reads a 16 bit, signed value + */ public short readShort() { checkRecordPosition(); @@ -169,6 +175,21 @@ public class RecordInputStream extends InputStream return result; } + /** + * Reads an 8 bit, unsigned value + */ + public short readUByte() { + short s = readByte(); + if(s < 0) { + s += 256; + } + return s; + } + + /** + * Reads a 16 bit,un- signed value. + * @return + */ public int readUShort() { checkRecordPosition(); diff --git a/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java b/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java index c0f77cb558..e2871ac5cf 100755 --- a/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java +++ b/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java @@ -20,10 +20,8 @@ package org.apache.poi.hssf.record; import java.util.Stack; -import java.util.List; import org.apache.poi.hssf.record.formula.*; -import org.apache.poi.util.LittleEndian; /** * Title: SharedFormulaRecord @@ -156,15 +154,12 @@ public class SharedFormulaRecord return sid; } - /** - * Shared formulas are to treated like unknown records, and as a result d - */ protected void fillFields(RecordInputStream in) { field_1_first_row = in.readShort(); field_2_last_row = in.readShort(); - field_3_first_column = in.readByte(); - field_4_last_column = in.readByte(); + field_3_first_column = in.readUByte(); + field_4_last_column = in.readUByte(); field_5_reserved = in.readShort(); field_6_expression_len = in.readShort(); field_7_parsed_expr = getParsedExpressionTokens(in); @@ -181,6 +176,9 @@ public class SharedFormulaRecord return stack; } + /** + * Are we shared by the supplied formula record? + */ public boolean isFormulaInShared(FormulaRecord formula) { final int formulaRow = formula.getRow(); final int formulaColumn = formula.getColumn(); 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 be0f703e80..7840d32562 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java @@ -99,7 +99,7 @@ public class FormulaRecordAggregate { this.formulaRecord = formulaRecord; } - + public FormulaRecord getFormulaRecord() { return formulaRecord; @@ -109,7 +109,7 @@ public class FormulaRecordAggregate { return stringRecord; } - + public boolean isEqual(CellValueRecordInterface i) { return formulaRecord.isEqual( i ); diff --git a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java index fe3af5aede..e48a0a902b 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java @@ -127,8 +127,17 @@ public class ValueRecordsAggregate FormulaRecordAggregate lastFormulaAggregate = null; + // First up, locate all the shared formulas List sharedFormulas = new java.util.ArrayList(); + for (k = offset; k < records.size(); k++) + { + Record rec = ( Record ) records.get(k); + if (rec instanceof SharedFormulaRecord) { + sharedFormulas.add(rec); + } + } + // Now do the main processing sweep for (k = offset; k < records.size(); k++) { Record rec = ( Record ) records.get(k); @@ -137,18 +146,14 @@ public class ValueRecordsAggregate { break; } else if (rec instanceof SharedFormulaRecord) { - sharedFormulas.add(rec); + // Already handled, not to worry } else if (rec instanceof FormulaRecord) { FormulaRecord formula = (FormulaRecord)rec; if (formula.isSharedFormula()) { - Record nextRecord = (Record) records.get(k + 1); - if (nextRecord instanceof SharedFormulaRecord) { - sharedFormulas.add(nextRecord); - k++; - } - //traverse the list of shared formulas in reverse order, and try to find the correct one - //for us + // Traverse the list of shared formulas in + // reverse order, and try to find the correct one + // for us boolean found = false; for (int i=sharedFormulas.size()-1;i>=0;i--) { SharedFormulaRecord shrd = (SharedFormulaRecord)sharedFormulas.get(i); diff --git a/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java b/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java index 511ac44d7b..a7fc0274ad 100644 --- a/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java @@ -75,7 +75,7 @@ public class ExpPtg public String toFormulaString(Workbook book) { - throw new RecordFormatException("Coding Error: Expected ExpPtg to be converted from Shared to Non-Shared Formula"); + throw new RecordFormatException("Coding Error: Expected ExpPtg to be converted from Shared to Non-Shared Formula by ValueRecordsAggregate, but it wasn't"); } public String toString() diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/data/42464-ExpPtg-bad.xls b/src/scratchpad/testcases/org/apache/poi/hssf/data/42464-ExpPtg-bad.xls new file mode 100644 index 0000000000..54a7edb404 Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hssf/data/42464-ExpPtg-bad.xls differ diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/data/42464-ExpPtg-ok.xls b/src/scratchpad/testcases/org/apache/poi/hssf/data/42464-ExpPtg-ok.xls new file mode 100644 index 0000000000..5ae84bc90e Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hssf/data/42464-ExpPtg-ok.xls differ diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java new file mode 100644 index 0000000000..3b31cc03a3 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java @@ -0,0 +1,93 @@ +/* ==================================================================== + 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 java.io.File; +import java.io.FileInputStream; +import java.util.Iterator; +import java.util.List; + +import org.apache.poi.hssf.record.FormulaRecord; +import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; +import org.apache.poi.hssf.record.formula.ExpPtg; +import org.apache.poi.hssf.util.CellReference; + +import junit.framework.TestCase; + +public class TestBug42464 extends TestCase { + String dirname; + + protected void setUp() throws Exception { + super.setUp(); + dirname = System.getProperty("HSSF.testdata.path"); + } + + public void testOKFile() throws Exception { + HSSFWorkbook wb = new HSSFWorkbook( + new FileInputStream(new File(dirname,"42464-ExpPtg-ok.xls")) + ); + process(wb); + } + public void testExpSharedBadFile() throws Exception { + HSSFWorkbook wb = new HSSFWorkbook( + new FileInputStream(new File(dirname,"42464-ExpPtg-bad.xls")) + ); + process(wb); + } + + protected void process(HSSFWorkbook wb) { + for(int i=0; i " + cell.getCellFormula()); + } + + eval.evaluate(cell); + + } + } + } +} diff --git a/src/testcases/org/apache/poi/hssf/data/42464-ExpPtg-bad.xls b/src/testcases/org/apache/poi/hssf/data/42464-ExpPtg-bad.xls new file mode 100644 index 0000000000..54a7edb404 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/42464-ExpPtg-bad.xls differ diff --git a/src/testcases/org/apache/poi/hssf/data/42464-ExpPtg-ok.xls b/src/testcases/org/apache/poi/hssf/data/42464-ExpPtg-ok.xls new file mode 100644 index 0000000000..5ae84bc90e Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/42464-ExpPtg-ok.xls differ