diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index bc95d9b7a..a2bd40d73 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -36,6 +36,7 @@ + 41726 - Fix how we handle signed cell offsets in relative areas and references 44233 - Support for getting and setting a flag on the sheet, which tells excel to re-calculate all formulas on it at next reload 44201 - Enable cloning of sheets with data validation rules 44200 - Enable cloning of sheets with notes diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 122cab85c..56b868b87 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -33,6 +33,7 @@ + 41726 - Fix how we handle signed cell offsets in relative areas and references 44233 - Support for getting and setting a flag on the sheet, which tells excel to re-calculate all formulas on it at next reload 44201 - Enable cloning of sheets with data validation rules 44200 - Enable cloning of sheets with notes diff --git a/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java b/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java index e2871ac5c..ae250246d 100755 --- a/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java +++ b/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java @@ -156,8 +156,8 @@ public class SharedFormulaRecord protected void fillFields(RecordInputStream in) { - field_1_first_row = in.readShort(); - field_2_last_row = in.readShort(); + field_1_first_row = in.readUShort(); + field_2_last_row = in.readUShort(); field_3_first_column = in.readUByte(); field_4_last_column = in.readUByte(); field_5_reserved = in.readShort(); @@ -200,48 +200,48 @@ public class SharedFormulaRecord Ptg ptg = (Ptg) field_7_parsed_expr.get(k); if (ptg instanceof RefNPtg) { RefNPtg refNPtg = (RefNPtg)ptg; - ptg = new ReferencePtg( (short)(formulaRow + refNPtg.getRow()), - (byte)(formulaColumn + refNPtg.getColumn()), + ptg = new ReferencePtg(fixupRelativeRow(formulaRow,refNPtg.getRow(),refNPtg.isRowRelative()), + fixupRelativeColumn(formulaColumn,refNPtg.getColumn(),refNPtg.isColRelative()), refNPtg.isRowRelative(), refNPtg.isColRelative()); } else if (ptg instanceof RefNVPtg) { RefNVPtg refNVPtg = (RefNVPtg)ptg; - ptg = new RefVPtg( (short)(formulaRow + refNVPtg.getRow()), - (byte)(formulaColumn + refNVPtg.getColumn()), - refNVPtg.isRowRelative(), - refNVPtg.isColRelative()); + ptg = new RefVPtg(fixupRelativeRow(formulaRow,refNVPtg.getRow(),refNVPtg.isRowRelative()), + fixupRelativeColumn(formulaColumn,refNVPtg.getColumn(),refNVPtg.isColRelative()), + refNVPtg.isRowRelative(), + refNVPtg.isColRelative()); } else if (ptg instanceof RefNAPtg) { RefNAPtg refNAPtg = (RefNAPtg)ptg; - ptg = new RefAPtg( (short)(formulaRow + refNAPtg.getRow()), - (byte)(formulaColumn + refNAPtg.getColumn()), + ptg = new RefAPtg( fixupRelativeRow(formulaRow,refNAPtg.getRow(),refNAPtg.isRowRelative()), + fixupRelativeColumn(formulaColumn,refNAPtg.getColumn(),refNAPtg.isColRelative()), refNAPtg.isRowRelative(), refNAPtg.isColRelative()); } else if (ptg instanceof AreaNPtg) { AreaNPtg areaNPtg = (AreaNPtg)ptg; - ptg = new AreaPtg((short)(formulaRow + areaNPtg.getFirstRow()), - (short)(formulaRow + areaNPtg.getLastRow()), - (short)(formulaColumn + areaNPtg.getFirstColumn()), - (short)(formulaColumn + areaNPtg.getLastColumn()), + ptg = new AreaPtg(fixupRelativeRow(formulaRow,areaNPtg.getFirstRow(),areaNPtg.isFirstRowRelative()), + fixupRelativeRow(formulaRow,areaNPtg.getLastRow(),areaNPtg.isLastRowRelative()), + fixupRelativeColumn(formulaColumn,areaNPtg.getFirstColumn(),areaNPtg.isFirstColRelative()), + fixupRelativeColumn(formulaColumn,areaNPtg.getLastColumn(),areaNPtg.isLastColRelative()), areaNPtg.isFirstRowRelative(), areaNPtg.isLastRowRelative(), areaNPtg.isFirstColRelative(), areaNPtg.isLastColRelative()); } else if (ptg instanceof AreaNVPtg) { AreaNVPtg areaNVPtg = (AreaNVPtg)ptg; - ptg = new AreaVPtg((short)(formulaRow + areaNVPtg.getFirstRow()), - (short)(formulaRow + areaNVPtg.getLastRow()), - (short)(formulaColumn + areaNVPtg.getFirstColumn()), - (short)(formulaColumn + areaNVPtg.getLastColumn()), + ptg = new AreaVPtg(fixupRelativeRow(formulaRow,areaNVPtg.getFirstRow(),areaNVPtg.isFirstRowRelative()), + fixupRelativeRow(formulaRow,areaNVPtg.getLastRow(),areaNVPtg.isLastRowRelative()), + fixupRelativeColumn(formulaColumn,areaNVPtg.getFirstColumn(),areaNVPtg.isFirstColRelative()), + fixupRelativeColumn(formulaColumn,areaNVPtg.getLastColumn(),areaNVPtg.isLastColRelative()), areaNVPtg.isFirstRowRelative(), areaNVPtg.isLastRowRelative(), areaNVPtg.isFirstColRelative(), areaNVPtg.isLastColRelative()); } else if (ptg instanceof AreaNAPtg) { AreaNAPtg areaNAPtg = (AreaNAPtg)ptg; - ptg = new AreaAPtg((short)(formulaRow + areaNAPtg.getFirstRow()), - (short)(formulaRow + areaNAPtg.getLastRow()), - (short)(formulaColumn + areaNAPtg.getFirstColumn()), - (short)(formulaColumn + areaNAPtg.getLastColumn()), + ptg = new AreaAPtg(fixupRelativeRow(formulaRow,areaNAPtg.getFirstRow(),areaNAPtg.isFirstRowRelative()), + fixupRelativeRow(formulaRow,areaNAPtg.getLastRow(),areaNAPtg.isLastRowRelative()), + fixupRelativeColumn(formulaColumn,areaNAPtg.getFirstColumn(),areaNAPtg.isFirstColRelative()), + fixupRelativeColumn(formulaColumn,areaNAPtg.getLastColumn(),areaNAPtg.isLastColRelative()), areaNAPtg.isFirstRowRelative(), areaNAPtg.isLastRowRelative(), areaNAPtg.isFirstColRelative(), @@ -256,6 +256,21 @@ public class SharedFormulaRecord throw new RuntimeException("Shared Formula Conversion: Coding Error"); } } + + private short fixupRelativeColumn(int currentcolumn, short column, boolean relative) { + if(relative) { + if((column&128)!=0) column=(short)(column-256); + column+=currentcolumn; + } + return column; + } + + private short fixupRelativeRow(int currentrow, short row, boolean relative) { + if(relative) { + row+=currentrow; + } + return row; + } /** * Mirroring formula records so it is registered in the ValueRecordsAggregate diff --git a/src/testcases/org/apache/poi/hssf/data/SharedFormulaTest.xls b/src/testcases/org/apache/poi/hssf/data/SharedFormulaTest.xls new file mode 100644 index 000000000..8db77d982 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/SharedFormulaTest.xls differ diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulas.java b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulas.java index e6ee73f22..f1e8f4977 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulas.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulas.java @@ -1127,6 +1127,17 @@ extends TestCase { cell.setCellFormula("IF(A1=\"A\",1,)"); } + public void testSharedFormula() throws Exception { + String readFilename = System.getProperty("HSSF.testdata.path"); + File inFile = new File(readFilename+"/SharedFormulaTest.xls"); + FileInputStream fis = new FileInputStream(inFile); + HSSFWorkbook wb = new HSSFWorkbook(fis); + + assertEquals("A$1*2", wb.getSheetAt(0).getRow(1).getCell((short)1).toString()); + assertEquals("$A11*2", wb.getSheetAt(0).getRow(11).getCell((short)1).toString()); + assertEquals("DZ2*2", wb.getSheetAt(0).getRow(1).getCell((short)128).toString()); + assertEquals("B32770*2", wb.getSheetAt(0).getRow(32768).getCell((short)1).toString()); + } public static void main(String [] args) { System.out