Start to update how the formula parser looks up sheets from formula ptgs, to account for the differences in how HSSF and XSSF store references to external sheets. For #56737

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1611948 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2014-07-19 19:19:06 +00:00
parent 76c8077a40
commit 83d9405d43
7 changed files with 91 additions and 29 deletions

View File

@ -120,10 +120,29 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
} }
public ExternalSheet getExternalSheet(int externSheetIndex) { public ExternalSheet getExternalSheet(int externSheetIndex) {
return _iBook.getExternalSheet(externSheetIndex); ExternalSheet sheet = _iBook.getExternalSheet(externSheetIndex);
if (sheet == null) {
// Try to treat it as a local sheet
int localSheetIndex = convertFromExternSheetIndex(externSheetIndex);
if (localSheetIndex == -1) {
// The sheet referenced can't be found, sorry
return null;
}
if (localSheetIndex == -2) {
// Not actually sheet based at all - is workbook scoped
return null;
}
// Look up the local sheet
String sheetName = getSheetName(localSheetIndex);
sheet = new ExternalSheet(null, sheetName);
}
return sheet;
} }
public ExternalSheet getExternalSheet(String sheetName, int externalWorkbookNumber) {
public ExternalName getExternalName(int externSheetIndex, int externNameIndex) { throw new IllegalStateException("XSSF-style external references are not supported for HSSF");
}
public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
return _iBook.getExternalName(externSheetIndex, externNameIndex); return _iBook.getExternalName(externSheetIndex, externNameIndex);
} }
@ -141,7 +160,9 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
int ix = namePtg.getIndex(); int ix = namePtg.getIndex();
return new Name(_iBook.getNameRecord(ix), ix); return new Name(_iBook.getNameRecord(ix), ix);
} }
public Ptg[] getFormulaTokens(EvaluationCell evalCell) {
@SuppressWarnings("unused")
public Ptg[] getFormulaTokens(EvaluationCell evalCell) {
HSSFCell cell = ((HSSFEvaluationCell)evalCell).getHSSFCell(); HSSFCell cell = ((HSSFEvaluationCell)evalCell).getHSSFCell();
if (false) { if (false) {
// re-parsing the formula text also works, but is a waste of time // re-parsing the formula text also works, but is a waste of time
@ -159,6 +180,7 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord(); FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord();
return fra.getFormulaTokens(); return fra.getFormulaTokens();
} }
public UDFFinder getUDFFinder(){ public UDFFinder getUDFFinder(){
return _uBook.getUDFFinder(); return _uBook.getUDFFinder();
} }

View File

@ -44,10 +44,21 @@ public interface EvaluationWorkbook {
EvaluationSheet getSheet(int sheetIndex); EvaluationSheet getSheet(int sheetIndex);
/** /**
* @return <code>null</code> if externSheetIndex refers to a sheet inside the current workbook * HSSF Only - fetch the external-style sheet details
* <p>Return will have no workbook set if it's actually in our own workbook</p>
*/ */
ExternalSheet getExternalSheet(int externSheetIndex); ExternalSheet getExternalSheet(int externSheetIndex);
/**
* XSSF Only - fetch the external-style sheet details
* <p>Return will have no workbook set if it's actually in our own workbook</p>
*/
ExternalSheet getExternalSheet(String sheetName, int externalWorkbookNumber);
/**
* HSSF Only - convert an external sheet index to an internal sheet index,
* for an external-style reference to one of this workbook's own sheets
*/
int convertFromExternSheetIndex(int externSheetIndex); int convertFromExternSheetIndex(int externSheetIndex);
ExternalName getExternalName(int externSheetIndex, int externNameIndex); ExternalName getExternalName(int externSheetIndex, int externNameIndex);
EvaluationName getName(NamePtg namePtg); EvaluationName getName(NamePtg namePtg);
EvaluationName getName(String name, int sheetIndex); EvaluationName getName(String name, int sheetIndex);

View File

@ -17,16 +17,21 @@
package org.apache.poi.ss.formula; package org.apache.poi.ss.formula;
import org.apache.poi.ss.formula.ptg.Area3DPtg;
import org.apache.poi.ss.formula.ptg.NameXPtg;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
import org.apache.poi.ss.formula.eval.*;
import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException; import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName; import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet; import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
import org.apache.poi.ss.formula.eval.AreaEval;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.NameXEval;
import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.ptg.Area3DPtg;
import org.apache.poi.ss.formula.ptg.NameXPtg;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
import org.apache.poi.ss.formula.ptg.Ref3DPxg;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.CellReference.NameType; import org.apache.poi.ss.util.CellReference.NameType;
@ -70,13 +75,20 @@ public final class OperationEvaluationContext {
SheetRefEvaluator createExternSheetRefEvaluator(ExternSheetReferenceToken ptg) { SheetRefEvaluator createExternSheetRefEvaluator(ExternSheetReferenceToken ptg) {
return createExternSheetRefEvaluator(ptg.getExternSheetIndex()); return createExternSheetRefEvaluator(ptg.getExternSheetIndex());
} }
SheetRefEvaluator createExternSheetRefEvaluator(String sheetName, int externalWorkbookNumber) {
ExternalSheet externalSheet = _workbook.getExternalSheet(sheetName, externalWorkbookNumber);
return createExternSheetRefEvaluator(externalSheet);
}
SheetRefEvaluator createExternSheetRefEvaluator(int externSheetIndex) { SheetRefEvaluator createExternSheetRefEvaluator(int externSheetIndex) {
ExternalSheet externalSheet = _workbook.getExternalSheet(externSheetIndex); ExternalSheet externalSheet = _workbook.getExternalSheet(externSheetIndex);
return createExternSheetRefEvaluator(externalSheet);
}
SheetRefEvaluator createExternSheetRefEvaluator(ExternalSheet externalSheet) {
WorkbookEvaluator targetEvaluator; WorkbookEvaluator targetEvaluator;
int otherSheetIndex; int otherSheetIndex;
if (externalSheet == null) { if (externalSheet == null || externalSheet.getWorkbookName() == null) {
// sheet is in same workbook // sheet is in same workbook
otherSheetIndex = _workbook.convertFromExternSheetIndex(externSheetIndex); otherSheetIndex = _workbook.getSheetIndex(externalSheet.getSheetName());
targetEvaluator = _bookEvaluator; targetEvaluator = _bookEvaluator;
} else { } else {
// look up sheet by name from external workbook // look up sheet by name from external workbook
@ -259,10 +271,14 @@ public final class OperationEvaluationContext {
SheetRefEvaluator sre = getRefEvaluatorForCurrentSheet(); SheetRefEvaluator sre = getRefEvaluatorForCurrentSheet();
return new LazyRefEval(rowIndex, columnIndex, sre); return new LazyRefEval(rowIndex, columnIndex, sre);
} }
public ValueEval getRef3DEval(int rowIndex, int columnIndex, int extSheetIndex) { public ValueEval getRef3DEval(Ref3DPtg rptg) {
SheetRefEvaluator sre = createExternSheetRefEvaluator(extSheetIndex); SheetRefEvaluator sre = createExternSheetRefEvaluator(rptg.getExternSheetIndex());
return new LazyRefEval(rowIndex, columnIndex, sre); return new LazyRefEval(rptg.getRow(), rptg.getColumn(), sre);
} }
public ValueEval getRef3DEval(Ref3DPxg rptg) {
SheetRefEvaluator sre = createExternSheetRefEvaluator(rptg.getSheetName(), rptg.getExternalWorkbookNumber());
return new LazyRefEval(rptg.getRow(), rptg.getColumn(), sre);
}
public ValueEval getAreaEval(int firstRowIndex, int firstColumnIndex, public ValueEval getAreaEval(int firstRowIndex, int firstColumnIndex,
int lastRowIndex, int lastColumnIndex) { int lastRowIndex, int lastColumnIndex) {
SheetRefEvaluator sre = getRefEvaluatorForCurrentSheet(); SheetRefEvaluator sre = getRefEvaluatorForCurrentSheet();

View File

@ -28,7 +28,6 @@ import org.apache.poi.ss.usermodel.Cell;
* @author Josh Micich * @author Josh Micich
*/ */
final class SheetRefEvaluator { final class SheetRefEvaluator {
private final WorkbookEvaluator _bookEvaluator; private final WorkbookEvaluator _bookEvaluator;
private final EvaluationTracker _tracker; private final EvaluationTracker _tracker;
private final int _sheetIndex; private final int _sheetIndex;

View File

@ -673,12 +673,10 @@ public final class WorkbookEvaluator {
return ErrorEval.REF_INVALID; return ErrorEval.REF_INVALID;
} }
if (ptg instanceof Ref3DPtg) { if (ptg instanceof Ref3DPtg) {
Ref3DPtg rptg = (Ref3DPtg) ptg; return ec.getRef3DEval((Ref3DPtg)ptg);
return ec.getRef3DEval(rptg.getRow(), rptg.getColumn(), rptg.getExternSheetIndex());
} }
if (ptg instanceof Ref3DPxg) { if (ptg instanceof Ref3DPxg) {
Ref3DPtg rptg = (Ref3DPtg) ptg; return ec.getRef3DEval((Ref3DPxg)ptg);
// TODO Return the right eval, should be easy as we already know the sheet details
} }
if (ptg instanceof Area3DPtg) { if (ptg instanceof Area3DPtg) {
Area3DPtg aptg = (Area3DPtg) ptg; Area3DPtg aptg = (Area3DPtg) ptg;

View File

@ -20,13 +20,13 @@ package org.apache.poi.ss.formula.eval.forked;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.poi.ss.formula.ptg.NamePtg;
import org.apache.poi.ss.formula.ptg.NameXPtg;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.EvaluationCell; import org.apache.poi.ss.formula.EvaluationCell;
import org.apache.poi.ss.formula.EvaluationName; import org.apache.poi.ss.formula.EvaluationName;
import org.apache.poi.ss.formula.EvaluationSheet; import org.apache.poi.ss.formula.EvaluationSheet;
import org.apache.poi.ss.formula.EvaluationWorkbook; import org.apache.poi.ss.formula.EvaluationWorkbook;
import org.apache.poi.ss.formula.ptg.NamePtg;
import org.apache.poi.ss.formula.ptg.NameXPtg;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.udf.UDFFinder; import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Workbook;
@ -90,8 +90,11 @@ final class ForkedEvaluationWorkbook implements EvaluationWorkbook {
public ExternalSheet getExternalSheet(int externSheetIndex) { public ExternalSheet getExternalSheet(int externSheetIndex) {
return _masterBook.getExternalSheet(externSheetIndex); return _masterBook.getExternalSheet(externSheetIndex);
} }
public ExternalSheet getExternalSheet(String sheetName, int externalWorkbookNumber) {
return _masterBook.getExternalSheet(sheetName, externalWorkbookNumber);
}
public Ptg[] getFormulaTokens(EvaluationCell cell) { public Ptg[] getFormulaTokens(EvaluationCell cell) {
if (cell instanceof ForkedEvaluationCell) { if (cell instanceof ForkedEvaluationCell) {
// doesn't happen yet because formulas cannot be modified from the master workbook // doesn't happen yet because formulas cannot be modified from the master workbook
throw new RuntimeException("Updated formulas not supported yet"); throw new RuntimeException("Updated formulas not supported yet");

View File

@ -37,6 +37,7 @@ import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder; import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.util.AreaReference; import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.model.ExternalLinksTable;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
/** /**
@ -63,7 +64,8 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
return externSheetIndex; return externSheetIndex;
} }
/** /**
* @return the sheet index of the sheet with the given external index. * XSSF doesn't use external sheet indexes, so when asked treat
* it just as a local index
*/ */
public int convertFromExternSheetIndex(int externSheetIndex) { public int convertFromExternSheetIndex(int externSheetIndex) {
return externSheetIndex; return externSheetIndex;
@ -175,10 +177,21 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
} }
public ExternalSheet getExternalSheet(int externSheetIndex) { public ExternalSheet getExternalSheet(int externSheetIndex) {
// TODO Auto-generated method stub throw new IllegalStateException("HSSF-style external references are not supported for XSSF");
return null;
} }
public int getExternalSheetIndex(String workbookName, String sheetName) { public ExternalSheet getExternalSheet(String sheetName, int externalWorkbookNumber) {
if (externalWorkbookNumber > 0) {
// External reference - reference is 1 based, link table is 0 based
int linkNumber = externalWorkbookNumber - 1;
ExternalLinksTable linkTable = _uBook.getExternalLinksTable().get(linkNumber);
return new ExternalSheet(linkTable.getLinkedFileName(), sheetName);
} else {
// Internal reference
return new ExternalSheet(null, sheetName);
}
}
public int getExternalSheetIndex(String workbookName, String sheetName) {
throw new RuntimeException("not implemented yet"); throw new RuntimeException("not implemented yet");
} }
public int getSheetIndex(String sheetName) { public int getSheetIndex(String sheetName) {