fpspreadsheet: Reading of biff5 and biff8 shared formulas (biff2 does not have them).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3524 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-09-04 13:18:28 +00:00
parent e2bb18e694
commit 2d26e91522
3 changed files with 127 additions and 10 deletions

View File

@ -2677,14 +2677,17 @@ begin
if ACell = nil then if ACell = nil then
exit; exit;
if HasFormula(ACell) then begin if HasFormula(ACell) then begin
// case (1): Formula is localized and has to be converted to default syntax
if ALocalized then if ALocalized then
begin begin
parser := TsSpreadsheetParser.Create(self); parser := TsSpreadsheetParser.Create(self);
try try
if ACell^.SharedFormulaBase <> nil then begin if ACell^.SharedFormulaBase <> nil then begin
// case (1a): shared formula
parser.ActiveCell := ACell; parser.ActiveCell := ACell;
parser.Expression := ACell^.SharedFormulaBase^.FormulaValue; parser.Expression := ACell^.SharedFormulaBase^.FormulaValue;
end else begin end else begin
// case (1b): normal formula
parser.ActiveCell := nil; parser.ActiveCell := nil;
parser.Expression := ACell^.FormulaValue; parser.Expression := ACell^.FormulaValue;
end; end;
@ -2694,6 +2697,20 @@ begin
end; end;
end end
else else
// case (2): Formula is in default syntax
if ACell^.SharedFormulaBase <> nil then
begin
// case (2a): shared formula
parser := TsSpreadsheetParser.Create(self);
try
parser.ActiveCell := ACell;
parser.Expression := ACell^.SharedFormulaBase^.FormulaValue;
Result := parser.Expression;
finally
parser.Free;
end;
end else
// case (2b): normal formula
Result := ACell^.FormulaValue; Result := ACell^.FormulaValue;
end; end;
end; end;

View File

@ -91,6 +91,9 @@ type
out ARowOffset, AColOffset: Integer; out AFlags: TsRelFlags); override; out ARowOffset, AColOffset: Integer; out AFlags: TsRelFlags); override;
procedure ReadRPNCellRangeAddress(AStream: TStream; procedure ReadRPNCellRangeAddress(AStream: TStream;
out ARow1, ACol1, ARow2, ACol2: Cardinal; out AFlags: TsRelFlags); override; out ARow1, ACol1, ARow2, ACol2: Cardinal; out AFlags: TsRelFlags); override;
procedure ReadRPNCellRangeOffset(AStream: TStream;
out ARow1Offset, ACol1Offset, ARow2Offset, ACol2Offset: Integer;
out AFlags: TsRelFlags); override;
procedure ReadSST(const AStream: TStream); procedure ReadSST(const AStream: TStream);
function ReadString_8bitLen(AStream: TStream): String; override; function ReadString_8bitLen(AStream: TStream): String; override;
procedure ReadStringRecord(AStream: TStream); override; procedure ReadStringRecord(AStream: TStream); override;
@ -1710,6 +1713,38 @@ begin
if (c2 and MASK_EXCEL_RELATIVE_ROW <> 0) then Include(AFlags, rfRelRow2); if (c2 and MASK_EXCEL_RELATIVE_ROW <> 0) then Include(AFlags, rfRelRow2);
end; end;
{ Reads the difference between row and column corner indexes of a cell range
and a reference cell.
Overriding the implementation in xlscommon. }
procedure TsSpreadBIFF8Reader.ReadRPNCellRangeOffset(AStream: TStream;
out ARow1Offset, ACol1Offset, ARow2Offset, ACol2Offset: Integer;
out AFlags: TsRelFlags);
var
c1, c2: Word;
begin
// 2 bytes for offset of first row
ARow1Offset := ShortInt(WordLEToN(AStream.ReadWord));
// 2 bytes for offset to last row
ARow2Offset := ShortInt(WordLEToN(AStream.ReadWord));
// 2 bytes for offset of first column
c1 := WordLEToN(AStream.ReadWord);
ACol1Offset := Shortint(Lo(c1));
// 2 bytes for offset of last column
c2 := WordLEToN(AStream.ReadWord);
ACol2Offset := ShortInt(Lo(c2));
// Extract info on absolute/relative addresses.
AFlags := [];
if (c1 and MASK_EXCEL_RELATIVE_COL <> 0) then Include(AFlags, rfRelCol);
if (c1 and MASK_EXCEL_RELATIVE_ROW <> 0) then Include(AFlags, rfRelRow);
if (c2 and MASK_EXCEL_RELATIVE_COL <> 0) then Include(AFlags, rfRelCol2);
if (c2 and MASK_EXCEL_RELATIVE_ROW <> 0) then Include(AFlags, rfRelRow2);
end;
procedure TsSpreadBIFF8Reader.ReadSST(const AStream: TStream); procedure TsSpreadBIFF8Reader.ReadSST(const AStream: TStream);
var var
Items: DWORD; Items: DWORD;

View File

@ -272,6 +272,9 @@ type
out ARowOffset, AColOffset: Integer; out AFlags: TsRelFlags); virtual; out ARowOffset, AColOffset: Integer; out AFlags: TsRelFlags); virtual;
procedure ReadRPNCellRangeAddress(AStream: TStream; procedure ReadRPNCellRangeAddress(AStream: TStream;
out ARow1, ACol1, ARow2, ACol2: Cardinal; out AFlags: TsRelFlags); virtual; out ARow1, ACol1, ARow2, ACol2: Cardinal; out AFlags: TsRelFlags); virtual;
procedure ReadRPNCellRangeOffset(AStream: TStream;
out ARow1Offset, ACol1Offset, ARow2Offset, ACol2Offset: Integer;
out AFlags: TsRelFlags); virtual;
function ReadRPNFunc(AStream: TStream): Word; virtual; function ReadRPNFunc(AStream: TStream): Word; virtual;
procedure ReadRPNSharedFormulaBase(AStream: TStream; out ARow, ACol: Cardinal); virtual; procedure ReadRPNSharedFormulaBase(AStream: TStream; out ARow, ACol: Cardinal); virtual;
function ReadRPNTokenArray(AStream: TStream; ACell: PCell): Boolean; function ReadRPNTokenArray(AStream: TStream; ACell: PCell): Boolean;
@ -1388,8 +1391,8 @@ begin
if (r and MASK_EXCEL_RELATIVE_ROW <> 0) then Include(AFlags, rfRelRow); if (r and MASK_EXCEL_RELATIVE_ROW <> 0) then Include(AFlags, rfRelRow);
end; end;
{ Read the difference between cell row and column indexed of a cell and a reference { Read the difference between cell row and column indexes of a cell and a
cell. reference cell.
Implemented here for BIFF5. BIFF8 must be overridden. Not used by BIFF2. } Implemented here for BIFF5. BIFF8 must be overridden. Not used by BIFF2. }
procedure TsSpreadBIFFReader.ReadRPNCellAddressOffset(AStream: TStream; procedure TsSpreadBIFFReader.ReadRPNCellAddressOffset(AStream: TStream;
out ARowOffset, AColOffset: Integer; out AFlags: TsRelFlags); out ARowOffset, AColOffset: Integer; out AFlags: TsRelFlags);
@ -1404,7 +1407,7 @@ begin
ARowOffset := dr; ARowOffset := dr;
// 1 byte for column // 1 byte for column
dc := AStream.ReadByte; dc := ShortInt(AStream.ReadByte);
AColOffset := dc; AColOffset := dc;
// Extract absolute/relative flags // Extract absolute/relative flags
@ -1413,8 +1416,9 @@ begin
if (r and MASK_EXCEL_RELATIVE_ROW <> 0) then Include(AFlags, rfRelRow); if (r and MASK_EXCEL_RELATIVE_ROW <> 0) then Include(AFlags, rfRelRow);
end; end;
{ Reads the cell address used in an RPN formula element. Evaluates the corresponding { Reads the cell range address used in an RPN formula element.
bits to distinguish between absolute and relative addresses. Evaluates the corresponding bits to distinguish between absolute and
relative addresses.
Implemented here for BIFF2-BIFF5. BIFF8 must be overridden. } Implemented here for BIFF2-BIFF5. BIFF8 must be overridden. }
procedure TsSpreadBIFFReader.ReadRPNCellRangeAddress(AStream: TStream; procedure TsSpreadBIFFReader.ReadRPNCellRangeAddress(AStream: TStream;
out ARow1, ACol1, ARow2, ACol2: Cardinal; out AFlags: TsRelFlags); out ARow1, ACol1, ARow2, ACol2: Cardinal; out AFlags: TsRelFlags);
@ -1438,6 +1442,43 @@ begin
if (r2 and MASK_EXCEL_RELATIVE_ROW <> 0) then Include(AFlags, rfRelRow2); if (r2 and MASK_EXCEL_RELATIVE_ROW <> 0) then Include(AFlags, rfRelRow2);
end; end;
{ Read the difference between row and column corner indexes of a cell range
and a reference cell.
Implemented here for BIFF5. BIFF8 must be overridden. Not used by BIFF2. }
procedure TsSpreadBIFFReader.ReadRPNCellRangeOffset(AStream: TStream;
out ARow1Offset, ACol1Offset, ARow2Offset, ACol2Offset: Integer;
out AFlags: TsRelFlags);
var
r1, r2: Word;
dr1, dr2: SmallInt;
dc1, dc2: ShortInt;
begin
// 2 bytes for offset to first row
r1 := WordLEToN(AStream.ReadWord);
dr1 := SmallInt(r1 and $3FFF);
ARow1Offset := dr1;
// 2 bytes for offset to last row
r2 := WordLEToN(AStream.ReadWord);
dr2 := SmallInt(r2 and $3FFF);
ARow1Offset := dr2;
// 1 byte for offset to first column
dc1 := ShortInt(AStream.ReadByte);
ACol1Offset := dc1;
// 1 byte for offset to last column
dc2 := ShortInt(AStream.ReadByte);
ACol2Offset := dc2;
// Extract absolute/relative flags
AFlags := [];
if (r1 and MASK_EXCEL_RELATIVE_COL <> 0) then Include(AFlags, rfRelCol);
if (r1 and MASK_EXCEL_RELATIVE_ROW <> 0) then Include(AFlags, rfRelRow);
if (r2 and MASK_EXCEL_RELATIVE_COL <> 0) then Include(AFlags, rfRelCol2);
if (r2 and MASK_EXCEL_RELATIVE_ROW <> 0) then Include(AFlags, rfRelRow2);
end;
{ Reads the identifier for an RPN function with fixed argument count. { Reads the identifier for an RPN function with fixed argument count.
Valid for BIFF4-BIFF8. Override in BIFF2-BIFF3 which read 1 byte only. } Valid for BIFF4-BIFF8. Override in BIFF2-BIFF3 which read 1 byte only. }
function TsSpreadBIFFReader.ReadRPNFunc(AStream: TStream): Word; function TsSpreadBIFFReader.ReadRPNFunc(AStream: TStream): Word;
@ -1470,7 +1511,7 @@ var
dblVal: Double = 0.0; // IEEE 8 byte floating point number dblVal: Double = 0.0; // IEEE 8 byte floating point number
flags: TsRelFlags; flags: TsRelFlags;
r, c, r2, c2: Cardinal; r, c, r2, c2: Cardinal;
dr, dc: Integer; dr, dc, dr2, dc2: Integer;
fek: TFEKind; fek: TFEKind;
exprDef: TsBuiltInExprIdentifierDef; exprDef: TsBuiltInExprIdentifierDef;
funcCode: Word; funcCode: Word;
@ -1503,11 +1544,35 @@ begin
INT_EXCEL_TOKEN_TREFN_R, INT_EXCEL_TOKEN_TREFN_V: INT_EXCEL_TOKEN_TREFN_R, INT_EXCEL_TOKEN_TREFN_V:
begin begin
ReadRPNCellAddressOffset(AStream, dr, dc, flags); ReadRPNCellAddressOffset(AStream, dr, dc, flags);
rpnItem := RPNCellOffset(dr, dc, flags, rpnItem); // For compatibility with other formats, convert offsets back to regular indexes.
if (rfRelRow in flags)
then r := ACell^.Row + dr
else r := ACell^.SharedFormulaBase^.Row + dr;
if (rfRelCol in flags)
then c := ACell^.Col + dc
else c := ACell^.SharedFormulaBase^.Col + dc;
case token of
INT_EXCEL_TOKEN_TREFN_V: rpnItem := RPNCellValue(r, c, flags, rpnItem);
INT_EXCEL_TOKEN_TREFN_R: rpnItem := RPNCellRef(r, c, flags, rpnItem);
end;
end; end;
INT_EXCEL_TOKEN_TREFN_A: INT_EXCEL_TOKEN_TREFN_A:
begin begin
raise Exception.Create('Cell range offset not yet implemented. Please report an issue'); ReadRPNCellRangeOffset(AStream, dr, dc, dr2, dc2, flags);
// For compatibility with other formats, convert offsets back to regular indexes.
if (rfRelRow in flags)
then r := ACell^.Row + dr
else r := ACell^.SharedFormulaBase^.Row + dr;
if (rfRelRow2 in flags)
then r2 := ACell^.Row + dr2
else r2 := ACell^.SharedFormulaBase^.Row + dr2;
if (rfRelCol in flags)
then c := ACell^.Col + dc
else c := ACell^.SharedFormulaBase^.Col + dc;
if (rfRelCol2 in flags)
then c2 := ACell^.Col + dc2
else c2 := ACell^.SharedFormulaBase^.Col + dc2;
rpnItem := RPNCellRange(r, c, r2, c2, flags, rpnItem);
end; end;
INT_EXCEL_TOKEN_TMISSARG: INT_EXCEL_TOKEN_TMISSARG:
rpnItem := RPNMissingArg(rpnItem); rpnItem := RPNMissingArg(rpnItem);
@ -1594,8 +1659,8 @@ begin
end; end;
{ Reads a SHAREDFMLA record, i.e. reads cell range coordinates and a rpn { Reads a SHAREDFMLA record, i.e. reads cell range coordinates and a rpn
formula. The formula is applied to all cells in the range. The formula stored formula. The formula is applied to all cells in the range. The formula is
only in the top/left cell of the range. } stored only in the top/left cell of the range. }
procedure TsSpreadBIFFReader.ReadSharedFormula(AStream: TStream); procedure TsSpreadBIFFReader.ReadSharedFormula(AStream: TStream);
var var
r1, r2, c1, c2: Cardinal; r1, r2, c1, c2: Cardinal;