fpspreadsheet: Write printranges and repeated cells to biff5 files. Related improvements in BIFFExplorer.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4501 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2016-02-14 17:03:20 +00:00
parent 42e34dc695
commit 8eff203daa
4 changed files with 300 additions and 79 deletions

View File

@ -13,7 +13,7 @@ type
TBIFFDetailsEvent = procedure(Sender: TObject; ADetails: TStrings) of object; TBIFFDetailsEvent = procedure(Sender: TObject; ADetails: TStrings) of object;
TRichTextFormattingRun = packed record TRichTextFormattingRun = packed record
FirstIndex, fontIndex: Word; FirstIndex, FontIndex: Word;
end; end;
TRichTextFormattingRuns = array of TRichTextFormattingRun; TRichTextFormattingRuns = array of TRichTextFormattingRun;
@ -153,7 +153,6 @@ type
constructor Create(AOwner: TComponent); override; constructor Create(AOwner: TComponent); override;
destructor Destroy; override; destructor Destroy; override;
procedure SetBIFFNodeData(AData: TBIFFNodeData; ABuffer: TBIFFBuffer; AFormat: TsSpreadsheetFormat); procedure SetBIFFNodeData(AData: TBIFFNodeData; ABuffer: TBIFFBuffer; AFormat: TsSpreadsheetFormat);
// procedure SetRecordType(ARecType: Word; ABuffer: TBIFFBuffer; AFormat: TsSpreadsheetFormat);
published published
property OnDetails: TBIFFDetailsEvent read FOnDetails write FOnDetails; property OnDetails: TBIFFDetailsEvent read FOnDetails write FOnDetails;
@ -1676,8 +1675,7 @@ begin
numBytes := lenName * sizeOf(ansiChar); numBytes := lenName * sizeOf(ansiChar);
SetLength(ansiStr, lenName); SetLength(ansiStr, lenName);
Move(FBuffer[FBufferIndex], ansiStr[1], numbytes); Move(FBuffer[FBufferIndex], ansiStr[1], numbytes);
ShowInRow(FCurrRow, FBufferIndex, numBytes, ansiStr, s := AnsiToUTF8(ansistr);
'Character array of the name');
end else end else
begin begin
if (FBuffer[FBufferIndex] and $01 = 0) //and (not IgnoreCompressedFlag) if (FBuffer[FBufferIndex] and $01 = 0) //and (not IgnoreCompressedFlag)
@ -1692,29 +1690,29 @@ begin
Move(FBuffer[FBufferIndex + 1], wideStr[1], lenName*SizeOf(WideChar)); Move(FBuffer[FBufferIndex + 1], wideStr[1], lenName*SizeOf(WideChar));
s := UTF8Encode(WideStringLEToN(wideStr)); s := UTF8Encode(WideStringLEToN(wideStr));
end; end;
if builtinName and (Length(s) = 1) then begin
s := Format('%s ($%x --> ', [s, ord(s[1])]);
case ord(s[1]) of
0: s := s + 'Consolidate_Area)';
1: s := s + 'Auto_Open)';
2: s := s + 'Auto_Close)';
3: s := s + 'Extract)';
4: s := s + 'Database)';
5: s := s + 'Citeria)';
6: s := s + 'Print_Area)';
7: s := s + 'Print_Titles)';
8: s := s + 'Recorder)';
9: s := s + 'Data_Form)';
10: s := s + 'Auto_Activate)';
11: s := s + 'Auto_Deactivate)';
12: s := s + 'Sheet_Title)';
13: s := s + '_FilterDatabase)';
else s := s + 'unknown meaning)';
end;
end;
ShowInRow(FCurrRow, FBufferIndex, numbytes, s,
'Name (Unicode string without length field)');
end; end;
if builtinName and (Length(s) = 1) then begin
s := Format('%s ($%x --> ', [s, ord(s[1])]);
case ord(s[1]) of
0: s := s + 'Consolidate_Area)';
1: s := s + 'Auto_Open)';
2: s := s + 'Auto_Close)';
3: s := s + 'Extract)';
4: s := s + 'Database)';
5: s := s + 'Citeria)';
6: s := s + 'Print_Area)';
7: s := s + 'Print_Titles)';
8: s := s + 'Recorder)';
9: s := s + 'Data_Form)';
10: s := s + 'Auto_Activate)';
11: s := s + 'Auto_Deactivate)';
12: s := s + 'Sheet_Title)';
13: s := s + '_FilterDatabase)';
else s := s + 'unknown meaning)';
end;
end;
ShowInRow(FCurrRow, FBufferIndex, numbytes, s,
'Name (Unicode string without length field)');
end; end;
firstTokenBufIdx := FBufferIndex; firstTokenBufIdx := FBufferIndex;
@ -1770,16 +1768,16 @@ begin
if FFormat = sfExcel5 then begin if FFormat = sfExcel5 then begin
if w and $8000 <> 0 then begin // negative value --> 3D reference if w and $8000 <> 0 then begin // negative value --> 3D reference
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(SmallInt(w)), ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(SmallInt(w)),
'3D reference, 1-based index to EXTERNSHEET record'); 'negative --> 3D reference, 1-based index to EXTERNSHEET record = ' + IntToStr(-SmallInt(w)));
numBytes := 8; numBytes := 8;
ShowInRow(FCurrRow, FBufferIndex, numBytes, '', 'Not used'); ShowInRow(FCurrRow, FBufferIndex, numBytes, '', 'Not used');
numBytes := 2; numBytes := 2;
Move(FBuffer[FBufferIndex], w, numBytes); Move(FBuffer[FBufferIndex], w, numBytes);
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)), ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
'Index to first referenced sheet ($FFFF = deleted sheet)'); 'Zero-based index to first referenced sheet ($FFFF = deleted sheet)');
Move(FBuffer[FBufferIndex], w, numBytes); Move(FBuffer[FBufferIndex], w, numBytes);
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)), ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
'Index to last referenced sheet ($FFFF = deleted sheet)'); 'Zero-based index to last referenced sheet ($FFFF = deleted sheet)');
end else end else
begin begin
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
@ -2050,13 +2048,15 @@ begin
FDetails.Add('First character = $03: EXTERNSHEET stores a reference to one of the own sheets'); FDetails.Add('First character = $03: EXTERNSHEET stores a reference to one of the own sheets');
FDetails.Add('Document name: ' + Copy(s, 2, Length(s))); FDetails.Add('Document name: ' + Copy(s, 2, Length(s)));
end else end else
if (s[1] = ':') and (Length(s) = 1) then begin if (Length(s) = 1) and (s[1] = ':') then begin
FDetails.Add('Special EXTERNSHEET record for an add-in function. EXTERNName record with the name of the function follows.'); FDetails.Add('Special EXTERNSHEET record for an add-in function. EXTERNName record with the name of the function follows.');
end else end else
FDetails.Add('Document name: ' + s); FDetails.Add('Document name: ' + s);
end; end;
if s[1] = #03 then if s[1] = #03 then begin
Delete(s, 1, 1); Delete(s, 1, 1);
s := '<#03>' + s;
end;
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, ShowInRow(FCurrRow, FBufferIndex, numBytes, s,
'Encoded document and sheet name (Byte string, 8-bit string length)'); 'Encoded document and sheet name (Byte string, 8-bit string length)');
end else begin end else begin

View File

@ -49,7 +49,7 @@ AUTHORS: Felipe Monteiro de Carvalho
unit xlsbiff5; unit xlsbiff5;
{$ifdef fpc} {$ifdef fpc}
{$mode delphi}{$H+} {$mode objfpc}{$H+}
{$endif} {$endif}
{$define USE_NEW_OLE} {$define USE_NEW_OLE}
@ -101,6 +101,8 @@ type
{ Record writing methods } { Record writing methods }
procedure WriteBOF(AStream: TStream; ADataType: Word); procedure WriteBOF(AStream: TStream; ADataType: Word);
function WriteBoundsheet(AStream: TStream; ASheetName: string): Int64; function WriteBoundsheet(AStream: TStream; ASheetName: string): Int64;
procedure WriteDefinedName(AStream: TStream; AWorksheet: TsWorksheet;
const AName: String; AIndexToREF: Word); override;
procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet); procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteEOF(AStream: TStream); procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFont: TsFont); procedure WriteFont(AStream: TStream; AFont: TsFont);
@ -1007,11 +1009,14 @@ begin
WriteBOF(AStream, INT_BOF_WORKBOOK_GLOBALS); WriteBOF(AStream, INT_BOF_WORKBOOK_GLOBALS);
WriteCodepage(AStream, FCodePage); WriteCODEPAGE(AStream, FCodePage);
WriteWindow1(AStream); WriteEXTERNCOUNT(AStream);
WriteEXTERNSHEET(AStream);
WriteDefinedNames(AStream);
WriteWINDOW1(AStream);
WriteFonts(AStream); WriteFonts(AStream);
WriteNumFormats(AStream); WriteNumFormats(AStream);
WritePalette(AStream); WritePALETTE(AStream);
WriteXFRecords(AStream); WriteXFRecords(AStream);
WriteStyle(AStream); WriteStyle(AStream);
@ -1204,6 +1209,145 @@ begin
AStream.WriteBuffer(xlsSheetName[1], Len); AStream.WriteBuffer(xlsSheetName[1], Len);
end; end;
{@@ ----------------------------------------------------------------------------
Writes out a DEFINEDNAMES record
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF5Writer.WriteDefinedName(AStream: TStream;
AWorksheet: TsWorksheet; const AName: String; AIndexToREF: Word);
procedure WriteRangeFormula(MemStream: TMemoryStream; ARange: TsCellRange;
AIndexToREF, ACounter: Word);
var
sheetIdx: Integer;
begin
sheetIdx := FWorkbook.GetWorksheetIndex(AWorksheet);
{ Token for tArea3dR }
MemStream.WriteByte($3B);
{ 1-based sheet index, negative to indicate 3D reference }
MemStream.WriteWord(WordToLE(-(sheetIdx+1)));
{ 8 bytes not used }
MemStream.WriteDWord(0);
MemStream.WriteDWord(0);
{ Index to first reference worksheet }
MemStream.WriteWord(WordToLE(sheetIdx)); // THIS IS ONLY VALID FOR PRINTRANGE!
{ Index to last reference worksheet }
MemStream.WriteWord(WordToLE(sheetIdx)); // THIS IS ONLY VALID FOR PRINTRANGE!
{ First row index }
MemStream.WriteWord(WordToLE(ARange.Row1));
{ Last row index }
MemStream.WriteWord(WordToLE(ARange.Row2));
{ First column index }
MemStream.WriteByte(ARange.Col1);
{ Last column index }
MemStream.WriteByte(ARange.Col2);
{ Token for list if formula refers to more than 1 range }
if ACounter > 1 then
MemStream.WriteByte($10);
end;
var
memstream: TMemoryStream;
rng: TsCellRange;
j: Integer;
idx: Integer;
begin
// Since this is a variable length record we begin by writing the formula
// to a memory stream
memstream := TMemoryStream.Create;
try
case AName of
#06: begin // Print range
for j := 0 to AWorksheet.NumPrintRanges-1 do
begin
rng := AWorksheet.GetPrintRange(j);
WriteRangeFormula(memstream, rng, AIndexToRef, j+1);
end;
end;
#07: begin
j := 1;
if AWorksheet.HasRepeatedPrintCols then
begin
rng.Col1 := AWorksheet.PageLayout.RepeatedCols.FirstIndex;
rng.Col2 := AWorksheet.PageLayout.RepeatedCols.LastIndex;
if rng.Col2 = UNASSIGNED_ROW_COL_INDEX then rng.Col2 := rng.Col1;
rng.Row1 := 0;
rng.Row2 := 65535;
WriteRangeFormula(memstream, rng, AIndexToRef, j);
inc(j);
end;
if AWorksheet.HasRepeatedPrintRows then
begin
rng.Row1 := AWorksheet.PageLayout.RepeatedRows.FirstIndex;
rng.Row2 := AWorksheet.PageLayout.RepeatedRows.LastIndex;
if rng.Row2 = UNASSIGNED_ROW_COL_INDEX then rng.Row2 := rng.Row1;
rng.Col1 := 0;
rng.Col2 := 255;
WriteRangeFormula(memstream, rng, AIndexToRef, j);
end;
end;
else raise Exception.Create('Name not supported');
end; // case
idx := FWorkbook.GetWorksheetIndex(AWorksheet);
{ BIFF record header }
WriteBIFFHeader(AStream, INT_EXCEL_ID_DEFINEDNAME, 14 + Length(AName) + memstream.Size);
{ Option flags: built-in defined names only }
AStream.WriteWord(WordToLE($0020));
{ Keyboard shortcut (only for command macro names) }
AStream.WriteByte(0);
{ Length of name (character count). Always 1 for built-in names }
AStream.WriteByte(Length(AName));
{ Size of formula data }
AStream.WriteWord(WordToLE(memstream.Size));
{ Global name, otherwise index to EXTERNSHEET record (1-based) }
AStream.WriteWord(WordToLE(AIndexToREF+1));
{ Global name, otherwise index to sheet (1-based) }
AStream.WriteWord(WordToLE(idx+1));
{ Length of menu text }
AStream.WriteByte(0);
{ Length of description text }
AStream.WriteByte(0);
{ Length of help topic text }
AStream.WriteByte(0);
{ Length of status bar text }
AStream.WriteByte(0);
{ Name }
if (Length(AName) = 1) and (AName[1] < #32) then
AStream.WriteByte(ord(AName[1])) else
raise Exception.Create('Name not supported.');
{ Formula }
memstream.Position := 0;
AStream.CopyFrom(memstream, memstream.Size);
finally
memstream.Free;
end;
end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Writes an Excel 5 DIMENSIONS record Writes an Excel 5 DIMENSIONS record

View File

@ -45,7 +45,7 @@ AUTHORS: Felipe Monteiro de Carvalho
unit xlsbiff8; unit xlsbiff8;
{$ifdef fpc} {$ifdef fpc}
{$mode delphi}{$H+} {$mode objfpc}{$H+}
{$endif} {$endif}
// The new OLE code is much better, so always use it // The new OLE code is much better, so always use it
@ -132,12 +132,11 @@ type
procedure WriteComment(AStream: TStream; ACell: PCell); override; procedure WriteComment(AStream: TStream; ACell: PCell); override;
procedure WriteComments(AStream: TStream; AWorksheet: TsWorksheet); procedure WriteComments(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteDefinedName(AStream: TStream; AWorksheet: TsWorksheet; procedure WriteDefinedName(AStream: TStream; AWorksheet: TsWorksheet;
AIndexToREF: Word; AKind: Byte); const AName: String; AIndexToREF: Word); override;
procedure WriteDefinedNames(AStream: TStream);
procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet); procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteEOF(AStream: TStream); procedure WriteEOF(AStream: TStream);
procedure WriteEXTERNBOOK(AStream: TStream); procedure WriteEXTERNBOOK(AStream: TStream);
procedure WriteEXTERNSHEET(AStream: TStream); procedure WriteEXTERNSHEET(AStream: TStream); override;
procedure WriteFONT(AStream: TStream; AFont: TsFont); procedure WriteFONT(AStream: TStream; AFont: TsFont);
procedure WriteFonts(AStream: TStream); procedure WriteFonts(AStream: TStream);
procedure WriteFORMAT(AStream: TStream; ANumFormatStr: String; procedure WriteFORMAT(AStream: TStream; ANumFormatStr: String;
@ -658,8 +657,8 @@ var
i: Integer; i: Integer;
j: Integer; //j: SizeUInt; j: Integer; //j: SizeUInt;
lLen: SizeInt; lLen: SizeInt;
RecordType: WORD; recType: WORD;
RecordSize: WORD; recSize: WORD;
C: WideChar; C: WideChar;
begin begin
StringFlags := AStream.ReadByte; StringFlags := AStream.ReadByte;
@ -699,12 +698,12 @@ begin
Dec(PendingRecordSize); Dec(PendingRecordSize);
if (PendingRecordSize <= 0) and (i < lLen) then begin if (PendingRecordSize <= 0) and (i < lLen) then begin
//A CONTINUE may have happened here //A CONTINUE may have happened here
RecordType := WordLEToN(AStream.ReadWord); recType := WordLEToN(AStream.ReadWord);
RecordSize := WordLEToN(AStream.ReadWord); recSize := WordLEToN(AStream.ReadWord);
if RecordType <> INT_EXCEL_ID_CONTINUE then begin if recType <> INT_EXCEL_ID_CONTINUE then begin
Raise Exception.Create('[TsSpreadBIFF8Reader.ReadWideString] CONTINUE record expected, but not found.'); Raise Exception.Create('[TsSpreadBIFF8Reader.ReadWideString] CONTINUE record expected, but not found.');
end else begin end else begin
PendingRecordSize := RecordSize; PendingRecordSize := recSize;
DecomprStrValue := copy(DecomprStrValue,1,i) + ReadWideString(AStream, ALength-i, ARichTextParams); DecomprStrValue := copy(DecomprStrValue,1,i) + ReadWideString(AStream, ALength-i, ARichTextParams);
break; break;
end; end;
@ -718,12 +717,12 @@ begin
for j := 0 to SmallInt(RunsCounter) - 1 do begin for j := 0 to SmallInt(RunsCounter) - 1 do begin
if (PendingRecordSize <= 0) then begin if (PendingRecordSize <= 0) then begin
// A CONTINUE may happened here // A CONTINUE may happened here
RecordType := WordLEToN(AStream.ReadWord); recType := WordLEToN(AStream.ReadWord);
RecordSize := WordLEToN(AStream.ReadWord); recSize := WordLEToN(AStream.ReadWord);
if RecordType <> INT_EXCEL_ID_CONTINUE then begin if recType <> INT_EXCEL_ID_CONTINUE then begin
Raise Exception.Create('[TsSpreadBIFF8Reader.ReadWideString] CONTINUE record expected, but not found.'); Raise Exception.Create('[TsSpreadBIFF8Reader.ReadWideString] CONTINUE record expected, but not found.');
end else begin end else begin
PendingRecordSize := RecordSize; PendingRecordSize := recSize;
end; end;
end; end;
// character start index: 0-based in file, 1-based in fps // character start index: 0-based in file, 1-based in fps
@ -2239,7 +2238,7 @@ end;
Implements only the builtin defined names for print ranges and titles! Implements only the builtin defined names for print ranges and titles!
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsSpreadBIFF8Writer.WriteDefinedName(AStream: TStream; procedure TsSpreadBIFF8Writer.WriteDefinedName(AStream: TStream;
AWorksheet: TsWorksheet; AIndexToREF: Word; AKind: Byte); AWorksheet: TsWorksheet; const AName: String; AIndexToREF: Word);
procedure WriteRangeFormula(MemStream: TMemoryStream; ARange: TsCellRange; procedure WriteRangeFormula(MemStream: TMemoryStream; ARange: TsCellRange;
AIndexToRef, ACounter: Word); AIndexToRef, ACounter: Word);
@ -2277,15 +2276,15 @@ begin
memstream := TMemoryStream.Create; memstream := TMemoryStream.Create;
try try
case AKind of case AName of
$06: begin // Print range #06: begin // Print range
for j := 0 to AWorksheet.NumPrintRanges-1 do for j := 0 to AWorksheet.NumPrintRanges-1 do
begin begin
rng := AWorksheet.GetPrintRange(j); rng := AWorksheet.GetPrintRange(j);
WriteRangeFormula(memstream, rng, AIndexToRef, j+1); WriteRangeFormula(memstream, rng, AIndexToRef, j+1);
end; end;
end; end;
$07: begin #07: begin // Print titles
j := 1; j := 1;
if AWorksheet.HasRepeatedPrintCols then if AWorksheet.HasRepeatedPrintCols then
begin begin
@ -2307,6 +2306,8 @@ begin
WriteRangeFormula(memstream, rng, AIndexToRef, j); WriteRangeFormula(memstream, rng, AIndexToRef, j);
end; end;
end; end;
else
raise Exception.Create('Name not supported');
end; // case end; // case
{ BIFF record header } { BIFF record header }
@ -2344,7 +2345,9 @@ begin
AStream.WriteByte(0); AStream.WriteByte(0);
{ Name } { Name }
AStream.WriteWord(WordToLE(AKind shl 8)); if (Length(AName) = 1) and (AName[1] < #32) then
AStream.WriteWord(WordToLE(ord(AName[1]) shl 8)) else
raise Exception.Create('Name not supported.');
{ Formula } { Formula }
memstream.Position := 0; memstream.Position := 0;
@ -2355,29 +2358,6 @@ begin
end; end;
end; end;
procedure TsSpreadBIFF8Writer.WriteDefinedNames(AStream: TStream);
var
sheet: TsWorksheet;
i: Integer;
n: Word;
begin
n := 0;
for i:=0 to FWorkbook.GetWorksheetCount-1 do
begin
sheet := FWorkbook.GetWorksheetByIndex(i);
if (sheet.NumPrintRanges > 0) or
sheet.HasRepeatedPrintCols or sheet.HasRepeatedPrintRows then
begin
if sheet.NumPrintRanges > 0 then
WriteDefinedName(AStream, sheet, n, $06);
if sheet.HasRepeatedPrintCols or sheet.HasRepeatedPrintRows then
WriteDefinedName(AStream, sheet, n, $07);
inc(n);
end;
end;
end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Writes an Excel 8 DIMENSIONS record Writes an Excel 8 DIMENSIONS record

View File

@ -35,9 +35,12 @@ const
INT_EXCEL_ID_CODEPAGE = $0042; INT_EXCEL_ID_CODEPAGE = $0042;
INT_EXCEL_ID_DEFCOLWIDTH = $0055; INT_EXCEL_ID_DEFCOLWIDTH = $0055;
{ RECORD IDs which did not changed across versions 2-5 }
INT_EXCEL_ID_EXTERNCOUNT = $0016; // does not exist in BIFF8
{ RECORD IDs which did not change across versions 2, 5, 8} { RECORD IDs which did not change across versions 2, 5, 8}
INT_EXCEL_ID_FORMULA = $0006; // BIFF3: $0206, BIFF4: $0406 INT_EXCEL_ID_FORMULA = $0006; // BIFF3: $0206, BIFF4: $0406
INT_EXCEL_ID_DEFINEDNAME = $0018; // BIFF3: $0218, BIFF4: $0218 INT_EXCEL_ID_DEFINEDNAME = $0018; // BIFF3-4: $0218
INT_EXCEL_ID_FONT = $0031; // BIFF3-4: $0231 INT_EXCEL_ID_FONT = $0031; // BIFF3-4: $0231
{ RECORD IDs which did not change across version 3-8} { RECORD IDs which did not change across version 3-8}
@ -499,10 +502,18 @@ type
procedure WriteDateMode(AStream: TStream); procedure WriteDateMode(AStream: TStream);
// Writes out a TIME/DATE/TIMETIME // Writes out a TIME/DATE/TIMETIME
procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal; procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: TDateTime; ACell: PCell); override; const AValue: TDateTime; ACell: PCell); override;
// Writes out DEFINEDNAMES records
procedure WriteDefinedName(AStream: TStream; AWorksheet: TsWorksheet;
const AName: String; AIndexToREF: Word); virtual;
procedure WriteDefinedNames(AStream: TStream);
// Writes out ERROR cell record // Writes out ERROR cell record
procedure WriteError(AStream: TStream; const ARow, ACol: Cardinal; procedure WriteError(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: TsErrorValue; ACell: PCell); override; const AValue: TsErrorValue; ACell: PCell); override;
// Writes out an EXTERNCOUNT record
procedure WriteEXTERNCOUNT(AStream: TStream);
// Writes out an EXTERNSHEET record
procedure WriteEXTERNSHEET(AStream: TStream); virtual;
// Writes out a FORMAT record // Writes out a FORMAT record
procedure WriteFORMAT(AStream: TStream; ANumFormatStr: String; procedure WriteFORMAT(AStream: TStream; ANumFormatStr: String;
ANumFormatIndex: Integer); virtual; ANumFormatIndex: Integer); virtual;
@ -2884,6 +2895,34 @@ begin
WriteNumber(AStream, ARow, ACol, ExcelDateSerial, ACell); WriteNumber(AStream, ARow, ACol, ExcelDateSerial, ACell);
end; end;
procedure TsSpreadBIFFWriter.WriteDefinedName(AStream: TStream;
AWorksheet: TsWorksheet; const AName: String; AIndexToREF: Word);
begin
// Override
end;
procedure TsSpreadBIFFWriter.WriteDefinedNames(AStream: TStream);
var
sheet: TsWorksheet;
i: Integer;
n: Word;
begin
n := 0;
for i:=0 to FWorkbook.GetWorksheetCount-1 do
begin
sheet := FWorkbook.GetWorksheetByIndex(i);
if (sheet.NumPrintRanges > 0) or
sheet.HasRepeatedPrintCols or sheet.HasRepeatedPrintRows then
begin
if sheet.NumPrintRanges > 0 then
WriteDefinedName(AStream, sheet, #6, n);
if sheet.HasRepeatedPrintCols or sheet.HasRepeatedPrintRows then
WriteDefinedName(AStream, sheet, #7, n);
inc(n);
end;
end;
end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Writes an ERROR cell record. Writes an ERROR cell record.
Valid for BIFF3-BIFF8. Override for BIFF2. Valid for BIFF3-BIFF8. Override for BIFF2.
@ -2915,6 +2954,64 @@ begin
AStream.WriteBuffer(rec, SizeOf(rec)); AStream.WriteBuffer(rec, SizeOf(rec));
end; end;
{@@ ----------------------------------------------------------------------------
Writes a BIFF EXTERNCOUNT record.
Valid for BIFF2-BIFF5.
-------------------------------------------------------------------------------}
procedure TsSpreadBIFFWriter.WriteEXTERNCOUNT(AStream: TStream);
var
i: Integer;
n: Word;
sheet: TsWorksheet;
begin
n := 0;
for i := 0 to FWorkbook.GetWorksheetCount-1 do
begin
sheet := FWorkbook.GetWorksheetByIndex(i);
if (sheet.NumPrintRanges > 0) or
sheet.HasRepeatedPrintCols or sheet.HasRepeatedPrintRows then inc(n);
end;
if n < 1 then
exit;
{ BIFF record header }
WriteBIFFHeader(AStream, INT_EXCEL_ID_EXTERNCOUNT, 2);
{ Count of EXTERNSHEET records following }
AStream.WriteWord(WordToLE(n));
end;
{@@ ----------------------------------------------------------------------------
Writes a BIFF EXTERNSHEET record.
Valid for BIFF2-BIFF5.
-------------------------------------------------------------------------------}
procedure TsSpreadBIFFWriter.WriteEXTERNSHEET(AStream: TStream);
var
sheet: TsWorksheet;
i: Integer;
begin
for i := 0 to FWorkbook.GetWorksheetCount-1 do
begin
sheet := FWorkbook.GetWorksheetByIndex(i);
if (sheet.NumPrintRanges > 0) or
sheet.HasRepeatedPrintCols or sheet.HasRepeatedPrintRows then
begin
{ BIFF record header }
WriteBIFFHeader(AStream, INT_EXCEL_ID_EXTERNSHEET, 2 + Length(sheet.Name));
{ Character count in worksheet name }
AStream.WriteByte(Length(sheet.Name));
{ Flag for identification as own sheet }
AStream.WriteByte($03);
{ Sheet name }
AStream.WriteBuffer(sheet.Name[1], Length(sheet.Name));
end;
end;
end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Writes the a margin record for printing (margin is in inches). Writes the a margin record for printing (margin is in inches).
The margin is identified by the parameter AMargin: The margin is identified by the parameter AMargin: