fpspreadsheet: Functional writing support for shared formulas in BIFF5 and BIFF8.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3492 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-08-18 09:16:24 +00:00
parent 87283fda5d
commit f2338f41bb
4 changed files with 44 additions and 48 deletions

View File

@ -164,7 +164,6 @@
<Unit7> <Unit7>
<Filename Value="mrumanager.pp"/> <Filename Value="mrumanager.pp"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
<UnitName Value="mrumanager"/>
</Unit7> </Unit7>
<Unit8> <Unit8>
<Filename Value="bemain.lfm"/> <Filename Value="bemain.lfm"/>

View File

@ -119,7 +119,6 @@ type
procedure WriteIndex(AStream: TStream); procedure WriteIndex(AStream: TStream);
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal; procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: string; ACell: PCell); override; const AValue: string; ACell: PCell); override;
procedure WriteSharedFormulaRange(AStream: TStream; const ARange: TRect); override;
procedure WriteStringRecord(AStream: TStream; AString: String); override; procedure WriteStringRecord(AStream: TStream; AString: String); override;
procedure WriteStyle(AStream: TStream); procedure WriteStyle(AStream: TStream);
procedure WriteWindow2(AStream: TStream; ASheet: TsWorksheet); procedure WriteWindow2(AStream: TStream; ASheet: TsWorksheet);
@ -380,7 +379,6 @@ var
CurrentPos: Int64; CurrentPos: Int64;
Boundsheets: array of Int64; Boundsheets: array of Int64;
i, len: Integer; i, len: Integer;
sheet : TsWorksheet;
pane: Byte; pane: Byte;
begin begin
{ Store some data about the workbook that other routines need } { Store some data about the workbook that other routines need }
@ -414,7 +412,7 @@ begin
for i := 0 to Workbook.GetWorksheetCount - 1 do for i := 0 to Workbook.GetWorksheetCount - 1 do
begin begin
sheet := Workbook.GetWorksheetByIndex(i); FWorksheet := Workbook.GetWorksheetByIndex(i);
{ First goes back and writes the position of the BOF of the { First goes back and writes the position of the BOF of the
sheet on the respective BOUNDSHEET record } sheet on the respective BOUNDSHEET record }
@ -427,18 +425,18 @@ begin
WriteIndex(AStream); WriteIndex(AStream);
// WritePageSetup(AStream); // WritePageSetup(AStream);
WriteColInfos(AStream, sheet); WriteColInfos(AStream, FWorksheet);
WriteDimensions(AStream, sheet); WriteDimensions(AStream, FWorksheet);
WriteWindow2(AStream, sheet); WriteWindow2(AStream, FWorksheet);
WritePane(AStream, sheet, true, pane); // true for "is BIFF5 or BIFF8" WritePane(AStream, FWorksheet, true, pane); // true for "is BIFF5 or BIFF8"
WriteSelection(AStream, sheet, pane); WriteSelection(AStream, FWorksheet, pane);
//WriteRows(AStream, sheet); //WriteRows(AStream, sheet);
if (boVirtualMode in Workbook.Options) then if (boVirtualMode in Workbook.Options) then
WriteVirtualCells(AStream) WriteVirtualCells(AStream)
else begin else begin
WriteRows(AStream, sheet); WriteRows(AStream, FWorksheet);
WriteCellsToStream(AStream, sheet.Cells); WriteCellsToStream(AStream, FWorksheet.Cells);
end; end;
WriteEOF(AStream); WriteEOF(AStream);
@ -838,18 +836,6 @@ begin
SetLength(buf, 0); SetLength(buf, 0);
end; end;
{ Writes the borders of the cell range covered by a shared formula.
Needs to be overridden to write the column data (2 bytes in case of BIFF8). }
procedure TsSpreadBIFF5Writer.WriteSharedFormulaRange(AStream: TStream;
const ARange: TRect);
begin
inherited WriteSharedFormulaRange(AStream, ARange);
// Index to first column
AStream.WriteByte(ARange.Left);
// Index to last rcolumn
AStream.WriteByte(ARange.Right);
end;
{ Writes an Excel 5 STRING record which immediately follows a FORMULA record { Writes an Excel 5 STRING record which immediately follows a FORMULA record
when the formula result is a string. when the formula result is a string.
BIFF5 writes a byte-string, but uses a 16-bit length here! } BIFF5 writes a byte-string, but uses a 16-bit length here! }

View File

@ -127,7 +127,7 @@ type
AFlags: TsRelFlags): Word; override; AFlags: TsRelFlags): Word; override;
function WriteRPNCellRangeAddress(AStream: TStream; ARow1, ACol1, ARow2, ACol2: Cardinal; function WriteRPNCellRangeAddress(AStream: TStream; ARow1, ACol1, ARow2, ACol2: Cardinal;
AFlags: TsRelFlags): Word; override; AFlags: TsRelFlags): Word; override;
procedure WriteSharedFormulaRange(AStream: TStream; const ARange: TRect); override; // procedure WriteSharedFormulaRange(AStream: TStream; const ARange: TRect); override;
function WriteString_8bitLen(AStream: TStream; AString: String): Integer; override; function WriteString_8bitLen(AStream: TStream; AString: String): Integer; override;
procedure WriteStringRecord(AStream: TStream; AString: string); override; procedure WriteStringRecord(AStream: TStream; AString: string); override;
procedure WriteStyle(AStream: TStream); procedure WriteStyle(AStream: TStream);
@ -435,7 +435,6 @@ const
var var
CurrentPos: Int64; CurrentPos: Int64;
Boundsheets: array of Int64; Boundsheets: array of Int64;
sheet: TsWorksheet;
i, len: Integer; i, len: Integer;
pane: Byte; pane: Byte;
begin begin
@ -465,8 +464,7 @@ begin
for i := 0 to Workbook.GetWorksheetCount - 1 do for i := 0 to Workbook.GetWorksheetCount - 1 do
begin begin
sheet := Workbook.GetWorksheetByIndex(i); FWorksheet := Workbook.GetWorksheetByIndex(i);
FWorksheet := sheet;
{ First goes back and writes the position of the BOF of the { First goes back and writes the position of the BOF of the
sheet on the respective BOUNDSHEET record } sheet on the respective BOUNDSHEET record }
@ -479,20 +477,20 @@ begin
WriteIndex(AStream); WriteIndex(AStream);
//WriteSheetPR(AStream); //WriteSheetPR(AStream);
// WritePageSetup(AStream); // WritePageSetup(AStream);
WriteColInfos(AStream, sheet); WriteColInfos(AStream, FWorksheet);
WriteDimensions(AStream, sheet); WriteDimensions(AStream, FWorksheet);
//WriteRowAndCellBlock(AStream, sheet); //WriteRowAndCellBlock(AStream, sheet);
if (boVirtualMode in Workbook.Options) then if (boVirtualMode in Workbook.Options) then
WriteVirtualCells(AStream) WriteVirtualCells(AStream)
else begin else begin
WriteRows(AStream, sheet); WriteRows(AStream, FWorksheet);
WriteCellsToStream(AStream, sheet.Cells); WriteCellsToStream(AStream, FWorksheet.Cells);
end; end;
WriteWindow2(AStream, sheet); WriteWindow2(AStream, FWorksheet);
WritePane(AStream, sheet, isBIFF8, pane); WritePane(AStream, FWorksheet, isBIFF8, pane);
WriteSelection(AStream, sheet, pane); WriteSelection(AStream, FWorksheet, pane);
WriteEOF(AStream); WriteEOF(AStream);
end; end;
@ -800,13 +798,15 @@ end;
function TsSpreadBIFF8Writer.WriteRPNCellOffset(AStream: TStream; function TsSpreadBIFF8Writer.WriteRPNCellOffset(AStream: TStream;
ARowOffset, AColOffset: Integer; AFlags: TsRelFlags): Word; ARowOffset, AColOffset: Integer; AFlags: TsRelFlags): Word;
var var
c: Word; c: word;
r: SmallInt;
begin begin
// row address // row address
AStream.WriteWord(WordToLE(Word(Lo(ARowOffset)))); r := SmallInt(ARowOffset);
AStream.WriteWord(WordToLE(Word(r)));
// Encoded column address // Encoded column address
c := word(Lo(AColOffset)) and MASK_EXCEL_COL_BITS_BIFF8; c := word(SmallInt(AColOffset)) and MASK_EXCEL_COL_BITS_BIFF8;
if (rfRelRow in AFlags) then c := c or MASK_EXCEL_RELATIVE_ROW_BIFF8; if (rfRelRow in AFlags) then c := c or MASK_EXCEL_RELATIVE_ROW_BIFF8;
if (rfRelCol in AFlags) then c := c or MASK_EXCEL_RELATIVE_COL_BIFF8; if (rfRelCol in AFlags) then c := c or MASK_EXCEL_RELATIVE_COL_BIFF8;
AStream.WriteWord(WordToLE(c)); AStream.WriteWord(WordToLE(c));
@ -836,18 +836,21 @@ begin
Result := 8; Result := 8;
end; end;
(*
{ Writes the borders of the cell range covered by a shared formula. { Writes the borders of the cell range covered by a shared formula.
Needs to be overridden to write the column data (2 bytes in case of BIFF8). } Needs to be overridden to write the column data (2 bytes in case of BIFF8). }
procedure TsSpreadBIFF8Writer.WriteSharedFormulaRange(AStream: TStream; procedure TsSpreadBIFF8Writer.WriteSharedFormulaRange(AStream: TStream;
const ARange: TRect); const ARange: TRect);
begin begin
inherited WriteSharedFormulaRange(AStream, ARange); inherited WriteSharedFormulaRange(AStream, ARange);
{
// Index to first column // Index to first column
AStream.WriteWord(WordToLE(ARange.Left)); AStream.WriteWord(WordToLE(ARange.Left));
// Index to last rcolumn // Index to last rcolumn
AStream.WriteWord(WordToLE(ARange.Right)); AStream.WriteWord(WordToLE(ARange.Right));
}
end; end;
*)
{ Helper function for writing a string with 8-bit length. Overridden version { Helper function for writing a string with 8-bit length. Overridden version
for BIFF8. Called for writing rpn formula string tokens. for BIFF8. Called for writing rpn formula string tokens.

View File

@ -2555,13 +2555,13 @@ end;
{ Is called from WriteRPNFormula in the case that the cell uses a shared { Is called from WriteRPNFormula in the case that the cell uses a shared
formula and writes the token "array" pointing to the shared formula base. formula and writes the token "array" pointing to the shared formula base.
This implementation is valid for BIFF5 and BIFF8. BIFF2 does not support This implementation is valid for BIFF3-BIFF8. BIFF2 is different, but does not
shared formulas; the BIFF2 writer must copy the formula found in the support shared formulas; the BIFF2 writer must copy the formula found in the
SharedFormulaBase field of the cell and adjust the relative references. } SharedFormulaBase field of the cell and adjust the relative references. }
procedure TsSpreadBIFFWriter.WriteRPNSharedFormulaLink(AStream: TStream; procedure TsSpreadBIFFWriter.WriteRPNSharedFormulaLink(AStream: TStream;
ACell: PCell; var RPNLength: Word); ACell: PCell; var RPNLength: Word);
type type
TSharedFormulaLinkRecord = record TSharedFormulaLinkRecord = packed record
FormulaSize: Word; // Size of token array FormulaSize: Word; // Size of token array
Token: Byte; // 1st (and only) token of the rpn formula array Token: Byte; // 1st (and only) token of the rpn formula array
Row: Word; // row of cell containing the shared formula Row: Word; // row of cell containing the shared formula
@ -2570,6 +2570,7 @@ type
var var
rec: TSharedFormulaLinkRecord; rec: TSharedFormulaLinkRecord;
begin begin
FillChar(rec, SizeOf(rec), 0);
rec.FormulaSize := WordToLE(5); rec.FormulaSize := WordToLE(5);
rec.Token := INT_EXCEL_TOKEN_TEXP; // Marks the cell for using a shared formula rec.Token := INT_EXCEL_TOKEN_TEXP; // Marks the cell for using a shared formula
rec.Row := WordToLE(ACell^.SharedFormulaBase.Row); rec.Row := WordToLE(ACell^.SharedFormulaBase.Row);
@ -2636,7 +2637,7 @@ begin
begin begin
n := WriteRPNCellOffset( n := WriteRPNCellOffset(
AStream, AStream,
AFormula[i].Row, AFormula[i].Col, integer(AFormula[i].Row), integer(AFormula[i].Col),
AFormula[i].RelFlags AFormula[i].RelFlags
); );
inc(RPNLength, n); inc(RPNLength, n);
@ -2928,6 +2929,12 @@ begin
// Write borders of cell range covered by the formula // Write borders of cell range covered by the formula
WriteSharedFormulaRange(AStream, range); WriteSharedFormulaRange(AStream, range);
// Not used
AStream.WriteByte(0);
// Number of existing formula records
AStream.WriteByte((range.Right-range.Left+1)*(range.Bottom-range.Top+1));
// Copy the formula (we don't want to overwrite the cell formulas) // Copy the formula (we don't want to overwrite the cell formulas)
// and adjust relative references // and adjust relative references
SetLength(formula, Length(ACell^.SharedFormulaBase^.RPNFormulaValue)); SetLength(formula, Length(ACell^.SharedFormulaBase^.RPNFormulaValue));
@ -2936,7 +2943,7 @@ begin
FixRelativeReferences(ACell, formula[i]); FixRelativeReferences(ACell, formula[i]);
end; end;
// Writes the (copied) rpn token array // Writes the (copied) rpn token array
WriteRPNTokenArray(AStream, formula, false, RPNLength); WriteRPNTokenArray(AStream, formula, true, RPNLength);
{ Write record size at the end after we known it } { Write record size at the end after we known it }
finalPos := AStream.Position; finalPos := AStream.Position;
@ -2946,9 +2953,8 @@ begin
end; end;
{ Writes the borders of the cell range covered by a shared formula. { Writes the borders of the cell range covered by a shared formula.
Needs to be overridden by BIFF5 and BIFF8 to write the column data Valid for BIFF5 and BIFF8 - BIFF8 writes 8-bit column index as well.
(1 byte in BIFF5, 2 bytes in BIFF8). No need for BIFF2 which does not No need for BIFF2 which does not support shared formulas. }
support shared formulas. }
procedure TsSpreadBIFFWriter.WriteSharedFormulaRange(AStream: TStream; procedure TsSpreadBIFFWriter.WriteSharedFormulaRange(AStream: TStream;
const ARange: TRect); const ARange: TRect);
begin begin
@ -2956,8 +2962,10 @@ begin
AStream.WriteWord(WordToLE(ARange.Top)); AStream.WriteWord(WordToLE(ARange.Top));
// Index to last row // Index to last row
AStream.WriteWord(WordToLE(ARange.Bottom)); AStream.WriteWord(WordToLE(ARange.Bottom));
// Index to first column
// column indexes follow in overridden procedure! AStream.WriteByte(Lo(ARange.Left));
// Index to last rcolumn
AStream.WriteByte(Lo(ARange.Right));
end; end;