You've already forked lazarus-ccr
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:
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Reference in New Issue
Block a user