You've already forked lazarus-ccr
fpspreadsheet: Add most of the BIFF8 features to BIFF5. Add test cases for BIFF5 --> pass. Move more shared code from xlsbiff5 and xlsbiff8 to xlscommon. Update wiki.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2971 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -155,17 +155,17 @@ type
|
|||||||
So 90 degrees clockwise means that the text will be:
|
So 90 degrees clockwise means that the text will be:
|
||||||
| A
|
| A
|
||||||
| B
|
| B
|
||||||
\|/ C
|
v C
|
||||||
|
|
||||||
And 90 degree counter clockwise will be:
|
And 90 degree counter clockwise will be:
|
||||||
|
|
||||||
/|\ C
|
^ C
|
||||||
| B
|
| B
|
||||||
| A
|
| A
|
||||||
}
|
}
|
||||||
|
|
||||||
TsTextRotation = (trHorizontal, rt90DegreeClockwiseRotation,
|
TsTextRotation = (trHorizontal, rt90DegreeClockwiseRotation,
|
||||||
rt90DegreeCounterClockwiseRotation);
|
rt90DegreeCounterClockwiseRotation, rtStacked);
|
||||||
|
|
||||||
{@@ Indicates the border for a cell }
|
{@@ Indicates the border for a cell }
|
||||||
|
|
||||||
|
@ -31,6 +31,18 @@ type
|
|||||||
{ BIFF2 file format tests }
|
{ BIFF2 file format tests }
|
||||||
procedure TestWriteReadBIFF2_Font_InternalPal; // internal palette for BIFF2 file format
|
procedure TestWriteReadBIFF2_Font_InternalPal; // internal palette for BIFF2 file format
|
||||||
|
|
||||||
|
{ BIFF5 file format tests }
|
||||||
|
// Background colors...
|
||||||
|
procedure TestWriteReadBIFF5_Background_InternalPal; // internal palette
|
||||||
|
procedure TestWriteReadBIFF5_Background_Biff5Pal; // official biff5 palette
|
||||||
|
procedure TestWriteReadBIFF5_Background_Biff8Pal; // official biff8 palette
|
||||||
|
procedure TestWriteReadBIFF5_Background_RandomPal; // palette 64, top 56 entries random
|
||||||
|
// Font colors...
|
||||||
|
procedure TestWriteReadBIFF5_Font_InternalPal; // internal palette for BIFF8 file format
|
||||||
|
procedure TestWriteReadBIFF5_Font_Biff5Pal; // official biff5 palette in BIFF8 file format
|
||||||
|
procedure TestWriteReadBIFF5_Font_Biff8Pal; // official biff8 palette in BIFF8 file format
|
||||||
|
procedure TestWriteReadBIFF5_Font_RandomPal; // palette 64, top 56 entries random
|
||||||
|
|
||||||
{ BIFF8 file format tests }
|
{ BIFF8 file format tests }
|
||||||
// Background colors...
|
// Background colors...
|
||||||
procedure TestWriteReadBIFF8_Background_InternalPal; // internal palette
|
procedure TestWriteReadBIFF8_Background_InternalPal; // internal palette
|
||||||
@ -250,6 +262,47 @@ begin
|
|||||||
TestWriteReadFontColors(sfExcel2, 0);
|
TestWriteReadFontColors(sfExcel2, 0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Tests for BIFF5 file format }
|
||||||
|
procedure TSpreadWriteReadColorTests.TestWriteReadBIFF5_Background_InternalPal;
|
||||||
|
begin
|
||||||
|
TestWriteReadBackgroundColors(sfExcel5, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadColorTests.TestWriteReadBIFF5_Background_Biff5Pal;
|
||||||
|
begin
|
||||||
|
TestWriteReadBackgroundColors(sfExcel5, 5);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadColorTests.TestWriteReadBIFF5_Background_Biff8Pal;
|
||||||
|
begin
|
||||||
|
TestWriteReadBackgroundColors(sfExcel5, 8);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadColorTests.TestWriteReadBIFF5_Background_RandomPal;
|
||||||
|
begin
|
||||||
|
TestWriteReadBackgroundColors(sfExcel5, 999);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadColorTests.TestWriteReadBIFF5_Font_InternalPal;
|
||||||
|
begin
|
||||||
|
TestWriteReadFontColors(sfExcel5, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadColorTests.TestWriteReadBIFF5_Font_Biff5Pal;
|
||||||
|
begin
|
||||||
|
TestWriteReadFontColors(sfExcel5, 5);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadColorTests.TestWriteReadBIFF5_Font_Biff8Pal;
|
||||||
|
begin
|
||||||
|
TestWriteReadFontColors(sfExcel5, 8);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadColorTests.TestWriteReadBIFF5_Font_RandomPal;
|
||||||
|
begin
|
||||||
|
TestWriteReadFontColors(sfExcel5, 999);
|
||||||
|
end;
|
||||||
|
|
||||||
{ Tests for BIFF8 file format }
|
{ Tests for BIFF8 file format }
|
||||||
procedure TSpreadWriteReadColorTests.TestWriteReadBIFF8_Background_InternalPal;
|
procedure TSpreadWriteReadColorTests.TestWriteReadBIFF8_Background_InternalPal;
|
||||||
begin
|
begin
|
||||||
|
@ -43,6 +43,12 @@ type
|
|||||||
procedure TestWriteReadFontBIFF2_TimesNewRoman;
|
procedure TestWriteReadFontBIFF2_TimesNewRoman;
|
||||||
procedure TestWriteReadFontBIFF2_CourierNew;
|
procedure TestWriteReadFontBIFF2_CourierNew;
|
||||||
|
|
||||||
|
// BIFF5 test cases
|
||||||
|
procedure TestWriteReadBoldBIFF5;
|
||||||
|
procedure TestWriteReadFontBIFF5_Arial;
|
||||||
|
procedure TestWriteReadFontBIFF5_TimesNewRoman;
|
||||||
|
procedure TestWriteReadFontBIFF5_CourierNew;
|
||||||
|
|
||||||
// BIFF8 test cases
|
// BIFF8 test cases
|
||||||
procedure TestWriteReadBoldBIFF8;
|
procedure TestWriteReadBoldBIFF8;
|
||||||
procedure TestWriteReadFontBIFF8_Arial;
|
procedure TestWriteReadFontBIFF8_Arial;
|
||||||
@ -189,6 +195,11 @@ begin
|
|||||||
TestWriteReadBold(sfExcel2);
|
TestWriteReadBold(sfExcel2);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFontTests.TestWriteReadBoldBIFF5;
|
||||||
|
begin
|
||||||
|
TestWriteReadBold(sfExcel5);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadFontTests.TestWriteReadBoldBIFF8;
|
procedure TSpreadWriteReadFontTests.TestWriteReadBoldBIFF8;
|
||||||
begin
|
begin
|
||||||
TestWriteReadBold(sfExcel8);
|
TestWriteReadBold(sfExcel8);
|
||||||
@ -270,6 +281,7 @@ begin
|
|||||||
DeleteFile(TempFile);
|
DeleteFile(TempFile);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ BIFF2 }
|
||||||
procedure TSpreadWriteReadFontTests.TestWriteReadFontBIFF2_Arial;
|
procedure TSpreadWriteReadFontTests.TestWriteReadFontBIFF2_Arial;
|
||||||
begin
|
begin
|
||||||
TestWriteReadFont(sfExcel2, 'Arial');
|
TestWriteReadFont(sfExcel2, 'Arial');
|
||||||
@ -285,6 +297,23 @@ begin
|
|||||||
TestWriteReadFont(sfExcel2, 'CourierNew');
|
TestWriteReadFont(sfExcel2, 'CourierNew');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ BIFF5 }
|
||||||
|
procedure TSpreadWriteReadFontTests.TestWriteReadFontBIFF5_Arial;
|
||||||
|
begin
|
||||||
|
TestWriteReadFont(sfExcel5, 'Arial');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFontTests.TestWriteReadFontBIFF5_TimesNewRoman;
|
||||||
|
begin
|
||||||
|
TestWriteReadFont(sfExcel5, 'TimesNewRoman');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFontTests.TestWriteReadFontBIFF5_CourierNew;
|
||||||
|
begin
|
||||||
|
TestWriteReadFont(sfExcel5, 'CourierNew');
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ BIFF8 }
|
||||||
procedure TSpreadWriteReadFontTests.TestWriteReadFontBIFF8_Arial;
|
procedure TSpreadWriteReadFontTests.TestWriteReadFontBIFF8_Arial;
|
||||||
begin
|
begin
|
||||||
TestWriteReadFont(sfExcel8, 'Arial');
|
TestWriteReadFont(sfExcel8, 'Arial');
|
||||||
|
@ -49,6 +49,8 @@ type
|
|||||||
procedure TestWriteReadBorder(AFormat: TsSpreadsheetFormat);
|
procedure TestWriteReadBorder(AFormat: TsSpreadsheetFormat);
|
||||||
// Test column widths
|
// Test column widths
|
||||||
procedure TestWriteReadColWidths(AFormat: TsSpreadsheetFormat);
|
procedure TestWriteReadColWidths(AFormat: TsSpreadsheetFormat);
|
||||||
|
// Test word wrapping
|
||||||
|
procedure TestWriteReadWordWrap(AFormat: TsSpreadsheetFormat);
|
||||||
|
|
||||||
published
|
published
|
||||||
// Writes out numbers & reads back.
|
// Writes out numbers & reads back.
|
||||||
@ -56,18 +58,23 @@ type
|
|||||||
|
|
||||||
{ BIFF2 Tests }
|
{ BIFF2 Tests }
|
||||||
procedure TestWriteReadBIFF2_Alignment;
|
procedure TestWriteReadBIFF2_Alignment;
|
||||||
procedure TestWriteReadBIFF2_ColWidths;
|
|
||||||
procedure TestWriteReadBIFF2_Border;
|
procedure TestWriteReadBIFF2_Border;
|
||||||
|
procedure TestWriteReadBIFF2_ColWidths;
|
||||||
|
|
||||||
|
{ BIFF5 Tests }
|
||||||
|
procedure TestWriteReadBIFF5_Alignment;
|
||||||
|
procedure TestWriteReadBIFF5_Border;
|
||||||
|
procedure TestWriteReadBIFF5_ColWidths;
|
||||||
|
procedure TestWriteReadBIFF5_WordWrap;
|
||||||
|
|
||||||
{ BIFF8 Tests }
|
{ BIFF8 Tests }
|
||||||
procedure TestWriteReadBIFF8_Alignment;
|
procedure TestWriteReadBIFF8_Alignment;
|
||||||
procedure TestWriteReadBIFF8_ColWidths;
|
|
||||||
procedure TestWriteReadBIFF8_Border;
|
procedure TestWriteReadBIFF8_Border;
|
||||||
|
procedure TestWriteReadBIFF8_ColWidths;
|
||||||
|
procedure TestWriteReadBIFF8_WordWrap;
|
||||||
procedure TestWriteReadNumberFormats;
|
procedure TestWriteReadNumberFormats;
|
||||||
// Repeat with date/times
|
// Repeat with date/times
|
||||||
procedure TestWriteReadDateTimeFormats;
|
procedure TestWriteReadDateTimeFormats;
|
||||||
// Test word wrapping
|
|
||||||
procedure TestWriteReadWordWrap;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@ -81,6 +88,7 @@ const
|
|||||||
ColWidthSheet = 'ColWidths';
|
ColWidthSheet = 'ColWidths';
|
||||||
BordersSheet = 'CellBorders';
|
BordersSheet = 'CellBorders';
|
||||||
AlignmentSheet = 'TextAlignments';
|
AlignmentSheet = 'TextAlignments';
|
||||||
|
WordwrapSheet = 'Wordwrap';
|
||||||
|
|
||||||
// Initialize array with variables that represent the values
|
// Initialize array with variables that represent the values
|
||||||
// we expect to be in the test spreadsheet files.
|
// we expect to be in the test spreadsheet files.
|
||||||
@ -364,6 +372,11 @@ begin
|
|||||||
TestWriteReadAlignment(sfExcel2);
|
TestWriteReadAlignment(sfExcel2);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF5_Alignment;
|
||||||
|
begin
|
||||||
|
TestWriteReadAlignment(sfExcel5);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF8_Alignment;
|
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF8_Alignment;
|
||||||
begin
|
begin
|
||||||
TestWriteReadAlignment(sfExcel8);
|
TestWriteReadAlignment(sfExcel8);
|
||||||
@ -428,6 +441,11 @@ begin
|
|||||||
TestWriteReadBorder(sfExcel2);
|
TestWriteReadBorder(sfExcel2);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF5_Border;
|
||||||
|
begin
|
||||||
|
TestWriteReadBorder(sfExcel5);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF8_Border;
|
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF8_Border;
|
||||||
begin
|
begin
|
||||||
TestWriteReadBorder(sfExcel8);
|
TestWriteReadBorder(sfExcel8);
|
||||||
@ -485,12 +503,17 @@ begin
|
|||||||
TestWriteReadColWidths(sfExcel2);
|
TestWriteReadColWidths(sfExcel2);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF5_ColWidths;
|
||||||
|
begin
|
||||||
|
TestWriteReadColWidths(sfExcel5);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF8_ColWidths;
|
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF8_ColWidths;
|
||||||
begin
|
begin
|
||||||
TestWriteReadColWidths(sfExcel8);
|
TestWriteReadColWidths(sfExcel8);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadFormatTests.TestWriteReadWordWrap;
|
procedure TSpreadWriteReadFormatTests.TestWriteReadWordWrap(AFormat: TsSpreadsheetFormat);
|
||||||
const
|
const
|
||||||
LONGTEXT = 'This is a very, very, very, very long text.';
|
LONGTEXT = 'This is a very, very, very, very long text.';
|
||||||
var
|
var
|
||||||
@ -507,7 +530,7 @@ begin
|
|||||||
// Write out all test values:
|
// Write out all test values:
|
||||||
// Cell A1 is word-wrapped, Cell B1 is NOT word-wrapped
|
// Cell A1 is word-wrapped, Cell B1 is NOT word-wrapped
|
||||||
MyWorkbook := TsWorkbook.Create;
|
MyWorkbook := TsWorkbook.Create;
|
||||||
MyWorkSheet:= MyWorkBook.AddWorksheet(FmtNumbersSheet);
|
MyWorkSheet:= MyWorkBook.AddWorksheet(WordwrapSheet);
|
||||||
MyWorksheet.WriteUTF8Text(0, 0, LONGTEXT);
|
MyWorksheet.WriteUTF8Text(0, 0, LONGTEXT);
|
||||||
MyWorksheet.WriteUsedFormatting(0, 0, [uffWordwrap]);
|
MyWorksheet.WriteUsedFormatting(0, 0, [uffWordwrap]);
|
||||||
MyCell := MyWorksheet.FindCell(0, 0);
|
MyCell := MyWorksheet.FindCell(0, 0);
|
||||||
@ -520,13 +543,16 @@ begin
|
|||||||
if MyCell = nil then
|
if MyCell = nil then
|
||||||
fail('Error in test code. Failed to get word-wrapped cell.');
|
fail('Error in test code. Failed to get word-wrapped cell.');
|
||||||
CheckEquals((uffWordWrap in MyCell^.UsedFormattingFields), false, 'Test unsaved non-wrapped cell mismatch, cell ' + CellNotation(MyWorksheet,0,0));
|
CheckEquals((uffWordWrap in MyCell^.UsedFormattingFields), false, 'Test unsaved non-wrapped cell mismatch, cell ' + CellNotation(MyWorksheet,0,0));
|
||||||
MyWorkBook.WriteToFile(TempFile,sfExcel8,true);
|
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
||||||
MyWorkbook.Free;
|
MyWorkbook.Free;
|
||||||
|
|
||||||
// Open the spreadsheet, as biff8
|
// Open the spreadsheet, as biff8
|
||||||
MyWorkbook := TsWorkbook.Create;
|
MyWorkbook := TsWorkbook.Create;
|
||||||
MyWorkbook.ReadFromFile(TempFile, sfExcel8);
|
MyWorkbook.ReadFromFile(TempFile, AFormat);
|
||||||
MyWorksheet:=GetWorksheetByName(MyWorkBook, FmtNumbersSheet);
|
if AFormat = sfExcel2 then
|
||||||
|
MyWorksheet := MyWorkbook.GetFirstWorksheet
|
||||||
|
else
|
||||||
|
MyWorksheet := GetWorksheetByName(MyWorkBook, WordwrapSheet);
|
||||||
if MyWorksheet=nil then
|
if MyWorksheet=nil then
|
||||||
fail('Error in test code. Failed to get named worksheet');
|
fail('Error in test code. Failed to get named worksheet');
|
||||||
MyCell := MyWorksheet.FindCell(0, 0);
|
MyCell := MyWorksheet.FindCell(0, 0);
|
||||||
@ -542,6 +568,16 @@ begin
|
|||||||
DeleteFile(TempFile);
|
DeleteFile(TempFile);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF5_Wordwrap;
|
||||||
|
begin
|
||||||
|
TestWriteReadWordwrap(sfExcel5);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF8_Wordwrap;
|
||||||
|
begin
|
||||||
|
TestWriteReadWordwrap(sfExcel8);
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
RegisterTest(TSpreadWriteReadFormatTests);
|
RegisterTest(TSpreadWriteReadFormatTests);
|
||||||
InitSollFmtData;
|
InitSollFmtData;
|
||||||
|
@ -78,15 +78,14 @@ type
|
|||||||
TsSpreadBIFF5Reader = class(TsSpreadBIFFReader)
|
TsSpreadBIFF5Reader = class(TsSpreadBIFFReader)
|
||||||
private
|
private
|
||||||
RecordSize: Word;
|
RecordSize: Word;
|
||||||
FWorksheet: TsWorksheet;
|
|
||||||
FWorksheetNames: TStringList;
|
FWorksheetNames: TStringList;
|
||||||
FCurrentWorksheet: Integer;
|
FCurrentWorksheet: Integer;
|
||||||
protected
|
protected
|
||||||
{ Helpers }
|
{ Helpers }
|
||||||
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Integer);
|
|
||||||
function DecodeRKValue(const ARK: DWORD): Double;
|
function DecodeRKValue(const ARK: DWORD): Double;
|
||||||
{ Record writing methods }
|
{ Record writing methods }
|
||||||
procedure ReadBlank(AStream: TStream); override;
|
procedure ReadBlank(AStream: TStream); override;
|
||||||
|
procedure ReadFont(const AStream: TStream);
|
||||||
procedure ReadFormula(AStream: TStream); override;
|
procedure ReadFormula(AStream: TStream); override;
|
||||||
procedure ReadFormulaExcel(AStream: TStream);
|
procedure ReadFormulaExcel(AStream: TStream);
|
||||||
procedure ReadLabel(AStream: TStream); override;
|
procedure ReadLabel(AStream: TStream); override;
|
||||||
@ -97,7 +96,7 @@ type
|
|||||||
procedure ReadBoundsheet(AStream: TStream);
|
procedure ReadBoundsheet(AStream: TStream);
|
||||||
procedure ReadRichString(AStream: TStream);
|
procedure ReadRichString(AStream: TStream);
|
||||||
procedure ReadRKValue(AStream: TStream);
|
procedure ReadRKValue(AStream: TStream);
|
||||||
procedure ReadRowColXF(const AStream: TStream; out ARow,ACol,AXF: WORD); virtual;
|
procedure ReadXF(AStream: TStream);
|
||||||
public
|
public
|
||||||
{ General reading methods }
|
{ General reading methods }
|
||||||
procedure ReadFromFile(AFileName: string; AData: TsWorkbook); override;
|
procedure ReadFromFile(AFileName: string; AData: TsWorkbook); override;
|
||||||
@ -110,28 +109,36 @@ type
|
|||||||
private
|
private
|
||||||
WorkBookEncoding: TsEncoding;
|
WorkBookEncoding: TsEncoding;
|
||||||
protected
|
protected
|
||||||
|
procedure AddDefaultFormats; override;
|
||||||
{ Record writing methods }
|
{ Record writing methods }
|
||||||
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal;
|
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
ACell: PCell); override;
|
ACell: PCell); override;
|
||||||
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 WriteCodepage(AStream: TStream; AEncoding: TsEncoding); this is in xlscommon
|
|
||||||
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;
|
||||||
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: TFPCustomFont);
|
procedure WriteFont(AStream: TStream; AFont: TsFont);
|
||||||
procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal;
|
procedure WriteFonts(AStream: TStream);
|
||||||
const AFormula: TsRPNFormula; ACell: PCell); override;
|
|
||||||
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 WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
|
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
const AValue: double; ACell: PCell); override;
|
const AValue: double; ACell: PCell); override;
|
||||||
|
procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
|
const AFormula: TsRPNFormula; ACell: PCell); override;
|
||||||
procedure WriteStyle(AStream: TStream);
|
procedure WriteStyle(AStream: TStream);
|
||||||
procedure WriteWindow1(AStream: TStream);
|
procedure WriteWindow1(AStream: TStream);
|
||||||
procedure WriteWindow2(AStream: TStream; ASheetSelected: Boolean);
|
procedure WriteWindow2(AStream: TStream; ASheetSelected: Boolean);
|
||||||
procedure WriteXF(AStream: TStream; AFontIndex: Word; AXF_TYPE_PROT: Byte);
|
procedure WriteXF(AStream: TStream; AFontIndex: Word;
|
||||||
|
AFormatIndex: Word; AXF_TYPE_PROT, ATextRotation: Byte; ABorders: TsCellBorders;
|
||||||
|
AHorAlignment: TsHorAlignment = haDefault; AVertAlignment: TsVertAlignment = vaDefault;
|
||||||
|
AWordWrap: Boolean = false; AddBackground: Boolean = false;
|
||||||
|
ABackgroundColor: TsColor = scSilver);
|
||||||
|
procedure WriteXFFieldsForFormattingStyles(AStream: TStream);
|
||||||
|
procedure WriteXFIndex(AStream: TStream; ACell: PCell);
|
||||||
|
procedure WriteXFRecords(AStream: TStream);
|
||||||
public
|
public
|
||||||
{ General writing methods }
|
{ General writing methods }
|
||||||
procedure WriteToFile(const AFileName: string;
|
procedure WriteToFile(const AFileName: string;
|
||||||
@ -307,43 +314,40 @@ const
|
|||||||
|
|
||||||
{ XF substructures }
|
{ XF substructures }
|
||||||
|
|
||||||
{ XF_TYPE_PROT - XF Type and Cell protection (3 Bits) - BIFF3-BIFF8 }
|
{ XF substructures --- see xlscommon! }
|
||||||
MASK_XF_TYPE_PROT_LOCKED = $1;
|
XF_ROTATION_HORIZONTAL = 0;
|
||||||
MASK_XF_TYPE_PROT_FORMULA_HIDDEN = $2;
|
XF_ROTATION_STACKED = 1;
|
||||||
MASK_XF_TYPE_PROT_STYLE_XF = $4; // 0 = CELL XF
|
XF_ROTATION_90DEG_CCW = 2;
|
||||||
|
XF_ROTATION_90DEG_CW = 3;
|
||||||
|
|
||||||
{ XF_USED_ATTRIB - Attributes from parent Style XF (6 Bits) - BIFF3-BIFF8
|
{ XF CELL BORDER }
|
||||||
|
MASK_XF_BORDER_LEFT = $00000038;
|
||||||
|
MASK_XF_BORDER_RIGHT = $000001C0;
|
||||||
|
MASK_XF_BORDER_TOP = $00000007;
|
||||||
|
MASK_XF_BORDER_BOTTOM = $01C00000;
|
||||||
|
|
||||||
In a CELL XF a cleared bit means that the parent attribute is used,
|
{ XF CELL BACKGROUND }
|
||||||
while a set bit indicates that the data in this XF is used
|
MASK_XF_BKGR_PATTERN_COLOR = $0000007F;
|
||||||
|
MASK_XF_BKGR_BACKGROUND_COLOR = $00003F80;
|
||||||
|
MASK_XF_BKGR_FILLPATTERN = $003F0000;
|
||||||
|
|
||||||
In a STYLE XF a cleared bit means that the data in this XF is used,
|
|
||||||
while a set bit indicates that the attribute should be ignored }
|
|
||||||
MASK_XF_USED_ATTRIB_NUMBER_FORMAT = $04;
|
|
||||||
MASK_XF_USED_ATTRIB_FONT = $08;
|
|
||||||
MASK_XF_USED_ATTRIB_TEXT = $10;
|
|
||||||
MASK_XF_USED_ATTRIB_BORDER_LINES = $20;
|
|
||||||
MASK_XF_USED_ATTRIB_BACKGROUND = $40;
|
|
||||||
MASK_XF_USED_ATTRIB_CELL_PROTECTION = $80;
|
|
||||||
|
|
||||||
{ XF_VERT_ALIGN }
|
|
||||||
MASK_XF_VERT_ALIGN_TOP = $00;
|
|
||||||
MASK_XF_VERT_ALIGN_CENTRED = $10;
|
|
||||||
MASK_XF_VERT_ALIGN_BOTTOM = $20;
|
|
||||||
MASK_XF_VERT_ALIGN_JUSTIFIED = $30;
|
|
||||||
|
|
||||||
{ XF record constants }
|
|
||||||
MASK_XF_TYPE_PROT = $0007;
|
|
||||||
MASK_XF_TYPE_PROT_PARENT = $FFF0;
|
|
||||||
|
|
||||||
MASK_XF_VERT_ALIGN = $70;
|
|
||||||
|
|
||||||
{
|
|
||||||
Exported functions
|
|
||||||
}
|
|
||||||
|
|
||||||
{ TsSpreadBIFF5Writer }
|
{ TsSpreadBIFF5Writer }
|
||||||
|
|
||||||
|
procedure TsSpreadBIFF5Writer.AddDefaultFormats();
|
||||||
|
begin
|
||||||
|
NextXFIndex := 16;
|
||||||
|
|
||||||
|
SetLength(FFormattingStyles, 1);
|
||||||
|
|
||||||
|
// XF0..XF14: Normal style, Row Outline level 1..7,
|
||||||
|
// Column Outline level 1..7.
|
||||||
|
|
||||||
|
// XF15 - Default cell format, no formatting (4.6.2)
|
||||||
|
FFormattingStyles[0].UsedFormattingFields := [];
|
||||||
|
FFormattingStyles[0].Row := 15;
|
||||||
|
end;
|
||||||
|
|
||||||
{*******************************************************************
|
{*******************************************************************
|
||||||
* TsSpreadBIFF5Writer.WriteToFile ()
|
* TsSpreadBIFF5Writer.WriteToFile ()
|
||||||
*
|
*
|
||||||
@ -392,11 +396,10 @@ end;
|
|||||||
*******************************************************************}
|
*******************************************************************}
|
||||||
procedure TsSpreadBIFF5Writer.WriteToStream(AStream: TStream);
|
procedure TsSpreadBIFF5Writer.WriteToStream(AStream: TStream);
|
||||||
var
|
var
|
||||||
FontData: TFPCustomFont;
|
|
||||||
MyData: TMemoryStream;
|
|
||||||
CurrentPos: Int64;
|
CurrentPos: Int64;
|
||||||
Boundsheets: array of Int64;
|
Boundsheets: array of Int64;
|
||||||
i, len: Integer;
|
i, len: Integer;
|
||||||
|
sheet : TsWorksheet;
|
||||||
begin
|
begin
|
||||||
{ Store some data about the workbook that other routines need }
|
{ Store some data about the workbook that other routines need }
|
||||||
WorkBookEncoding := Workbook.Encoding;
|
WorkBookEncoding := Workbook.Encoding;
|
||||||
@ -404,60 +407,12 @@ begin
|
|||||||
{ Write workbook globals }
|
{ Write workbook globals }
|
||||||
|
|
||||||
WriteBOF(AStream, INT_BOF_WORKBOOK_GLOBALS);
|
WriteBOF(AStream, INT_BOF_WORKBOOK_GLOBALS);
|
||||||
|
|
||||||
WriteCodepage(AStream, WorkBookEncoding);
|
WriteCodepage(AStream, WorkBookEncoding);
|
||||||
WriteWindow1(AStream);
|
WriteWindow1(AStream);
|
||||||
|
WriteFonts(AStream);
|
||||||
FontData := TFPCustomFont.Create;
|
WritePalette(AStream);
|
||||||
try
|
WriteXFRecords(AStream);
|
||||||
FontData.Name := 'Arial';
|
|
||||||
|
|
||||||
// FONT0
|
|
||||||
WriteFont(AStream, FontData);
|
|
||||||
// FONT1
|
|
||||||
WriteFont(AStream, FontData);
|
|
||||||
// FONT2
|
|
||||||
WriteFont(AStream, FontData);
|
|
||||||
// FONT3
|
|
||||||
WriteFont(AStream, FontData);
|
|
||||||
// FONT5
|
|
||||||
WriteFont(AStream, FontData);
|
|
||||||
finally
|
|
||||||
FontData.Free;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// XF0
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF1
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF2
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF3
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF4
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF5
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF6
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF7
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF8
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF9
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF10
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF11
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF12
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF13
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF14
|
|
||||||
WriteXF(AStream, 0, MASK_XF_TYPE_PROT_STYLE_XF);
|
|
||||||
// XF15
|
|
||||||
WriteXF(AStream, 0, 0);
|
|
||||||
|
|
||||||
WriteStyle(AStream);
|
WriteStyle(AStream);
|
||||||
|
|
||||||
// A BOUNDSHEET for each worksheet
|
// A BOUNDSHEET for each worksheet
|
||||||
@ -474,6 +429,8 @@ begin
|
|||||||
|
|
||||||
for i := 0 to Workbook.GetWorksheetCount - 1 do
|
for i := 0 to Workbook.GetWorksheetCount - 1 do
|
||||||
begin
|
begin
|
||||||
|
sheet := 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 }
|
||||||
CurrentPos := AStream.Position;
|
CurrentPos := AStream.Position;
|
||||||
@ -482,13 +439,11 @@ begin
|
|||||||
AStream.Position := CurrentPos;
|
AStream.Position := CurrentPos;
|
||||||
|
|
||||||
WriteBOF(AStream, INT_BOF_SHEET);
|
WriteBOF(AStream, INT_BOF_SHEET);
|
||||||
|
WriteIndex(AStream);
|
||||||
WriteIndex(AStream);
|
WriteColInfos(AStream, sheet);
|
||||||
WriteDimensions(AStream, Workbook.GetWorksheetByIndex(i));
|
WriteDimensions(AStream, sheet);
|
||||||
WriteWindow2(AStream, True);
|
WriteWindow2(AStream, True);
|
||||||
|
WriteCellsToStream(AStream, sheet.Cells);
|
||||||
WriteCellsToStream(AStream, Workbook.GetWorksheetByIndex(i).Cells);
|
|
||||||
|
|
||||||
WriteEOF(AStream);
|
WriteEOF(AStream);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -515,7 +470,7 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(ACol));
|
AStream.WriteWord(WordToLE(ACol));
|
||||||
|
|
||||||
{ Index to XF record }
|
{ Index to XF record }
|
||||||
AStream.WriteWord(WordToLE(15));
|
WriteXFIndex(AStream, ACell);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{*******************************************************************
|
{*******************************************************************
|
||||||
@ -647,33 +602,53 @@ end;
|
|||||||
* The font data is passed in an instance of TFPCustomFont
|
* The font data is passed in an instance of TFPCustomFont
|
||||||
*
|
*
|
||||||
*******************************************************************}
|
*******************************************************************}
|
||||||
procedure TsSpreadBIFF5Writer.WriteFont(AStream: TStream; AFont: TFPCustomFont);
|
procedure TsSpreadBIFF5Writer.WriteFont(AStream: TStream; AFont: TsFont);
|
||||||
var
|
var
|
||||||
Len: Byte;
|
Len: Byte;
|
||||||
|
optn: Word;
|
||||||
begin
|
begin
|
||||||
Len := Length(AFont.Name);
|
if AFont = nil then // this happens for FONT4 in case of BIFF
|
||||||
|
exit;
|
||||||
|
|
||||||
|
if AFont.FontName = '' then
|
||||||
|
raise Exception.Create('Font name not specified.');
|
||||||
|
if AFont.Size <= 0.0 then
|
||||||
|
raise Exception.Create('Font size not specified.');
|
||||||
|
|
||||||
|
Len := Length(AFont.FontName);
|
||||||
|
|
||||||
{ BIFF Record header }
|
{ BIFF Record header }
|
||||||
AStream.WriteWord(WordToLE(INT_EXCEL_ID_FONT));
|
AStream.WriteWord(WordToLE(INT_EXCEL_ID_FONT));
|
||||||
AStream.WriteWord(WordToLE(14 + 1 + Len));
|
AStream.WriteWord(WordToLE(14 + 1 + Len));
|
||||||
|
|
||||||
{ Height of the font in twips = 1/20 of a point }
|
{ Height of the font in twips = 1/20 of a point }
|
||||||
AStream.WriteWord(WordToLE(200));
|
AStream.WriteWord(WordToLE(round(AFont.Size*20)));
|
||||||
|
|
||||||
{ Option flags }
|
{ Option flags }
|
||||||
AStream.WriteWord(0);
|
optn := 0;
|
||||||
|
if fssBold in AFont.Style then optn := optn or $0001;
|
||||||
|
if fssItalic in AFont.Style then optn := optn or $0002;
|
||||||
|
if fssUnderline in AFont.Style then optn := optn or $0004;
|
||||||
|
if fssStrikeout in AFont.Style then optn := optn or $0008;
|
||||||
|
AStream.WriteWord(WordToLE(optn));
|
||||||
|
|
||||||
{ Colour index }
|
{ Colour index }
|
||||||
AStream.WriteWord($7FFF);
|
AStream.WriteWord(WordToLE(ord(AFont.Color)));
|
||||||
|
|
||||||
{ Font weight }
|
{ Font weight }
|
||||||
AStream.WriteWord(WordToLE(INT_FONT_WEIGHT_NORMAL));
|
if fssBold in AFont.Style then
|
||||||
|
AStream.WriteWord(WordToLE(INT_FONT_WEIGHT_BOLD))
|
||||||
|
else
|
||||||
|
AStream.WriteWord(WordToLE(INT_FONT_WEIGHT_NORMAL));
|
||||||
|
|
||||||
{ Escapement type }
|
{ Escapement type }
|
||||||
AStream.WriteWord(0);
|
AStream.WriteWord(0);
|
||||||
|
|
||||||
{ Underline type }
|
{ Underline type }
|
||||||
AStream.WriteByte(0);
|
if fssUnderline in AFont.Style then
|
||||||
|
AStream.WriteByte(1)
|
||||||
|
else
|
||||||
|
AStream.WriteByte(0);
|
||||||
|
|
||||||
{ Font family }
|
{ Font family }
|
||||||
AStream.WriteByte(0);
|
AStream.WriteByte(0);
|
||||||
@ -686,11 +661,26 @@ begin
|
|||||||
|
|
||||||
{ Font name: Byte string, 8-bit length }
|
{ Font name: Byte string, 8-bit length }
|
||||||
AStream.WriteByte(Len);
|
AStream.WriteByte(Len);
|
||||||
AStream.WriteBuffer(AFont.Name[1], Len);
|
AStream.WriteBuffer(AFont.FontName[1], Len);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{*******************************************************************
|
{*******************************************************************
|
||||||
* TsSpreadBIFF5Writer.WriteFormula ()
|
* TsSpreadBIFF5Writer.WriteFonts ()
|
||||||
|
*
|
||||||
|
* DESCRIPTION: Writes the Excel 5 FONT records neede for the
|
||||||
|
* used fonts in the workbook.
|
||||||
|
*
|
||||||
|
*******************************************************************}
|
||||||
|
procedure TsSpreadBiff5Writer.WriteFonts(AStream: TStream);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
for i:=0 to Workbook.GetFontCount-1 do
|
||||||
|
WriteFont(AStream, Workbook.GetFont(i));
|
||||||
|
end;
|
||||||
|
|
||||||
|
{*******************************************************************
|
||||||
|
* TsSpreadBIFF5Writer.WriteRPNFormula ()
|
||||||
*
|
*
|
||||||
* DESCRIPTION: Writes an Excel 5 FORMULA record
|
* DESCRIPTION: Writes an Excel 5 FORMULA record
|
||||||
*
|
*
|
||||||
@ -725,7 +715,7 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(ACol));
|
AStream.WriteWord(WordToLE(ACol));
|
||||||
|
|
||||||
{ Index to XF Record }
|
{ Index to XF Record }
|
||||||
AStream.WriteWord($0000);
|
WriteXFIndex(AStream, ACell);
|
||||||
|
|
||||||
{ Result of the formula in IEEE 754 floating-point value }
|
{ Result of the formula in IEEE 754 floating-point value }
|
||||||
AStream.WriteBuffer(FormulaResult, 8);
|
AStream.WriteBuffer(FormulaResult, 8);
|
||||||
@ -939,7 +929,7 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(ACol));
|
AStream.WriteWord(WordToLE(ACol));
|
||||||
|
|
||||||
{ Index to XF record }
|
{ Index to XF record }
|
||||||
AStream.WriteWord(WordToLE(15));
|
WriteXFIndex(AStream, ACell);
|
||||||
|
|
||||||
{ Byte String with 16-bit size }
|
{ Byte String with 16-bit size }
|
||||||
AStream.WriteWord(WordToLE(L));
|
AStream.WriteWord(WordToLE(L));
|
||||||
@ -974,7 +964,7 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(ACol));
|
AStream.WriteWord(WordToLE(ACol));
|
||||||
|
|
||||||
{ Index to XF record }
|
{ Index to XF record }
|
||||||
AStream.WriteWord($0);
|
WriteXFIndex(AStream, ACell);
|
||||||
|
|
||||||
{ IEE 754 floating-point value }
|
{ IEE 754 floating-point value }
|
||||||
AStream.WriteBuffer(AValue, 8);
|
AStream.WriteBuffer(AValue, 8);
|
||||||
@ -1120,14 +1110,23 @@ end;
|
|||||||
*
|
*
|
||||||
* DESCRIPTION: Writes an Excel 5 XF record
|
* DESCRIPTION: Writes an Excel 5 XF record
|
||||||
*
|
*
|
||||||
* Writes a number (64-bit floating point) to the sheet
|
|
||||||
*
|
|
||||||
*******************************************************************}
|
*******************************************************************}
|
||||||
procedure TsSpreadBIFF5Writer.WriteXF(AStream: TStream; AFontIndex: Word;
|
procedure TsSpreadBIFF5Writer.WriteXF(AStream: TStream; AFontIndex: Word;
|
||||||
AXF_TYPE_PROT: Byte);
|
AFormatIndex: Word; AXF_TYPE_PROT, ATextRotation: Byte; ABorders: TsCellBorders;
|
||||||
|
AHorAlignment: TsHorAlignment = haDefault; AVertAlignment: TsVertAlignment = vaDefault;
|
||||||
|
AWordWrap: Boolean = false; AddBackground: Boolean = false;
|
||||||
|
ABackgroundColor: TsColor = scSilver);
|
||||||
|
const
|
||||||
|
FILL_PATTERN = 1; // solid fill
|
||||||
|
BORDER_LINE_STYLE = 1; // thin solid line
|
||||||
|
BORDER_COLOR = scBLACK;
|
||||||
var
|
var
|
||||||
|
optns: Word;
|
||||||
|
b: Byte;
|
||||||
|
dw1, dw2: DWord;
|
||||||
XFOptions: Word;
|
XFOptions: Word;
|
||||||
XFAlignment, XFOrientationAttrib: Byte;
|
XFAlignment: byte;
|
||||||
|
XFBorderDWord1, XFBorderDWord2: DWord;
|
||||||
begin
|
begin
|
||||||
{ BIFF Record header }
|
{ BIFF Record header }
|
||||||
AStream.WriteWord(WordToLE(INT_EXCEL_ID_XF));
|
AStream.WriteWord(WordToLE(INT_EXCEL_ID_XF));
|
||||||
@ -1137,43 +1136,263 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(AFontIndex));
|
AStream.WriteWord(WordToLE(AFontIndex));
|
||||||
|
|
||||||
{ Index to FORMAT record }
|
{ Index to FORMAT record }
|
||||||
AStream.WriteWord($00);
|
AStream.WriteWord(WordToLE(AFormatIndex));
|
||||||
|
|
||||||
{ XF type, cell protection and parent style XF }
|
{ XF type, cell protection and parent style XF }
|
||||||
XFOptions := AXF_TYPE_PROT and MASK_XF_TYPE_PROT;
|
optns := AXF_TYPE_PROT and MASK_XF_TYPE_PROT;
|
||||||
|
|
||||||
if AXF_TYPE_PROT and MASK_XF_TYPE_PROT_STYLE_XF <> 0 then
|
if AXF_TYPE_PROT and MASK_XF_TYPE_PROT_STYLE_XF <> 0 then
|
||||||
XFOptions := XFOptions or MASK_XF_TYPE_PROT_PARENT;
|
optns := optns or MASK_XF_TYPE_PROT_PARENT;
|
||||||
|
AStream.WriteWord(WordToLE(optns));
|
||||||
AStream.WriteWord(WordToLE(XFOptions));
|
|
||||||
|
|
||||||
{ Alignment and text break }
|
{ Alignment and text break }
|
||||||
XFAlignment := MASK_XF_VERT_ALIGN_BOTTOM;
|
b := 0;
|
||||||
|
case AHorAlignment of
|
||||||
|
haLeft : b := b or MASK_XF_HOR_ALIGN_LEFT;
|
||||||
|
haCenter : b := b or MASK_XF_HOR_ALIGN_CENTER;
|
||||||
|
haRight : b := b or MASK_XF_HOR_ALIGN_RIGHT;
|
||||||
|
end;
|
||||||
|
case AVertAlignment of
|
||||||
|
vaTop : b := b or MASK_XF_VERT_ALIGN_TOP;
|
||||||
|
vaCenter : b := b or MASK_XF_VERT_ALIGN_CENTER;
|
||||||
|
vaBottom : b := b or MASK_XF_VERT_ALIGN_BOTTOM;
|
||||||
|
else b := b or MASK_XF_VERT_ALIGN_BOTTOM;
|
||||||
|
end;
|
||||||
|
if AWordWrap then
|
||||||
|
b := b or MASK_XF_TEXTWRAP;
|
||||||
|
AStream.WriteByte(b);
|
||||||
|
|
||||||
AStream.WriteByte(WordToLE(XFAlignment));
|
{ Text rotation }
|
||||||
|
AStream.WriteByte(ATextRotation); // 0 is horizontal / normal
|
||||||
{ Text orientation and flags for used attribute groups }
|
|
||||||
XFOrientationAttrib :=
|
|
||||||
MASK_XF_USED_ATTRIB_NUMBER_FORMAT or
|
|
||||||
MASK_XF_USED_ATTRIB_FONT or
|
|
||||||
MASK_XF_USED_ATTRIB_TEXT or
|
|
||||||
MASK_XF_USED_ATTRIB_BORDER_LINES or
|
|
||||||
MASK_XF_USED_ATTRIB_BACKGROUND or
|
|
||||||
MASK_XF_USED_ATTRIB_CELL_PROTECTION;
|
|
||||||
|
|
||||||
AStream.WriteByte(WordToLE(XFOrientationAttrib));
|
|
||||||
|
|
||||||
{ Cell border lines and background area }
|
{ Cell border lines and background area }
|
||||||
AStream.WriteDWord($000020C0);
|
|
||||||
AStream.WriteDWord($00000000);
|
dw1 := 0;
|
||||||
|
dw2 := 0;
|
||||||
|
// Background color
|
||||||
|
if AddBackground then begin
|
||||||
|
dw1 := dw1 or (ABackgroundColor and $0000007F);
|
||||||
|
dw1 := dw1 or (FILL_PATTERN shl 16);
|
||||||
|
end;
|
||||||
|
// Border lines
|
||||||
|
if cbSouth in ABorders then
|
||||||
|
dw1 := dw1 or (BORDER_LINE_STYLE shl 22);
|
||||||
|
dw1 := dw1 or (BORDER_COLOR shl 25); // Bottom line color
|
||||||
|
dw2 := (BORDER_COLOR shl 9) or // Top line color
|
||||||
|
(BORDER_COLOR shl 16) or // Left line color
|
||||||
|
(BORDER_COLOR shl 23); // Right line color
|
||||||
|
if cbNorth in ABorders then dw2 := dw2 or BORDER_LINE_STYLE;
|
||||||
|
if cbWest in ABorders then dw2 := dw2 or (BORDER_LINE_STYLE shl 3);
|
||||||
|
if cbEast in ABorders then dw2 := dw2 or (BORDER_LINE_STYLE shl 6);
|
||||||
|
AStream.WriteDWord(DWordToLE(dw1));
|
||||||
|
AStream.WriteDWord(DWordToLE(dw2));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadBIFF5Writer.WriteXFFieldsForFormattingStyles(AStream: TStream);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
lFontIndex: Word;
|
||||||
|
lFormatIndex: Word; //number format
|
||||||
|
lTextRotation: Byte;
|
||||||
|
lBorders: TsCellBorders;
|
||||||
|
lAddBackground: Boolean;
|
||||||
|
lBackgroundColor: TsColor;
|
||||||
|
lHorAlign: TsHorAlignment;
|
||||||
|
lVertAlign: TsVertAlignment;
|
||||||
|
lWordWrap: Boolean;
|
||||||
|
fmt: String;
|
||||||
|
begin
|
||||||
|
// The first style was already added
|
||||||
|
for i := 1 to Length(FFormattingStyles) - 1 do begin
|
||||||
|
// Default styles
|
||||||
|
lFontIndex := 0;
|
||||||
|
lFormatIndex := 0; //General format (one of the built-in number formats)
|
||||||
|
lTextRotation := XF_ROTATION_HORIZONTAL;
|
||||||
|
lBorders := [];
|
||||||
|
lHorAlign := FFormattingStyles[i].HorAlignment;
|
||||||
|
lVertAlign := FFormattingStyles[i].VertAlignment;
|
||||||
|
lBackgroundColor := FFormattingStyles[i].BackgroundColor;
|
||||||
|
(*
|
||||||
|
// Now apply the modifications.
|
||||||
|
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then
|
||||||
|
case FFormattingStyles[i].NumberFormat of
|
||||||
|
nfFixed:
|
||||||
|
case FFormattingStyles[i].NumberDecimals of
|
||||||
|
0: lFormatIndex := FORMAT_FIXED_0_DECIMALS;
|
||||||
|
2: lFormatIndex := FORMAT_FIXED_2_DECIMALS;
|
||||||
|
end;
|
||||||
|
nfFixedTh:
|
||||||
|
case FFormattingStyles[i].NumberDecimals of
|
||||||
|
0: lFormatIndex := FORMAT_FIXED_THOUSANDS_0_DECIMALS;
|
||||||
|
2: lFormatIndex := FORMAT_FIXED_THOUSANDS_2_DECIMALS;
|
||||||
|
end;
|
||||||
|
nfExp:
|
||||||
|
lFormatIndex := FORMAT_EXP_2_DECIMALS;
|
||||||
|
nfSci:
|
||||||
|
lFormatIndex := FORMAT_SCI_1_DECIMAL;
|
||||||
|
nfPercentage:
|
||||||
|
case FFormattingStyles[i].NumberDecimals of
|
||||||
|
0: lFormatIndex := FORMAT_PERCENT_0_DECIMALS;
|
||||||
|
2: lFormatIndex := FORMAT_PERCENT_2_DECIMALS;
|
||||||
|
end;
|
||||||
|
{
|
||||||
|
nfCurrency:
|
||||||
|
case FFormattingStyles[i].NumberDecimals of
|
||||||
|
0: lFormatIndex := FORMAT_CURRENCY_0_DECIMALS;
|
||||||
|
2: lFormatIndex := FORMAT_CURRENCY_2_DECIMALS;
|
||||||
|
end;
|
||||||
|
}
|
||||||
|
nfShortDate:
|
||||||
|
lFormatIndex := FORMAT_SHORT_DATE;
|
||||||
|
nfShortTime:
|
||||||
|
lFormatIndex := FORMAT_SHORT_TIME;
|
||||||
|
nfLongTime:
|
||||||
|
lFormatIndex := FORMAT_LONG_TIME;
|
||||||
|
nfShortTimeAM:
|
||||||
|
lFormatIndex := FORMAT_SHORT_TIME_AM;
|
||||||
|
nfLongTimeAM:
|
||||||
|
lFormatIndex := FORMAT_LONG_TIME_AM;
|
||||||
|
nfShortDateTime:
|
||||||
|
lFormatIndex := FORMAT_SHORT_DATETIME;
|
||||||
|
nfFmtDateTime:
|
||||||
|
begin
|
||||||
|
fmt := lowercase(FFormattingStyles[i].NumberFormatStr);
|
||||||
|
if (fmt = 'dm') or (fmt = 'd-mmm') or (fmt = 'd mmm') or (fmt = 'd. mmm') or (fmt = 'd/mmm') then
|
||||||
|
lFormatIndex := FORMAT_DATE_DM
|
||||||
|
else
|
||||||
|
if (fmt = 'my') or (fmt = 'mmm-yy') or (fmt = 'mmm yy') or (fmt = 'mmm/yy') then
|
||||||
|
lFormatIndex := FORMAT_DATE_MY
|
||||||
|
else
|
||||||
|
if (fmt = 'ms') or (fmt = 'nn:ss') or (fmt = 'mm:ss') then
|
||||||
|
lFormatIndex := FORMAT_TIME_MS
|
||||||
|
else
|
||||||
|
if (fmt = 'msz') or (fmt = 'nn:ss.zzz') or (fmt = 'mm:ss.zzz') or (fmt = 'mm:ss.0') or (fmt = 'mm:ss.z') or (fmt = 'nn:ss.z') then
|
||||||
|
lFormatIndex := FORMAT_TIME_MSZ
|
||||||
|
end;
|
||||||
|
nfTimeInterval:
|
||||||
|
lFormatIndex := FORMAT_TIME_INTERVAL;
|
||||||
|
end;
|
||||||
|
*)
|
||||||
|
|
||||||
|
if uffBorder in FFormattingStyles[i].UsedFormattingFields then
|
||||||
|
lBorders := FFormattingStyles[i].Border;
|
||||||
|
|
||||||
|
if uffTextRotation in FFormattingStyles[i].UsedFormattingFields then
|
||||||
|
begin
|
||||||
|
case FFormattingStyles[i].TextRotation of
|
||||||
|
trHorizontal : lTextRotation := XF_ROTATION_HORIZONTAL;
|
||||||
|
rt90DegreeClockwiseRotation : lTextRotation := XF_ROTATION_90DEG_CW;
|
||||||
|
rt90DegreeCounterClockwiseRotation: lTextRotation := XF_ROTATION_90DEG_CCW;
|
||||||
|
rtStacked : lTextRotation := XF_ROTATION_STACKED;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if uffBold in FFormattingStyles[i].UsedFormattingFields then
|
||||||
|
lFontIndex := 1; // must be before uffFont which overrides uffBold
|
||||||
|
// the "1" was defined in TsWorkbook.InitFont (FONT1)
|
||||||
|
|
||||||
|
if uffFont in FFormattingStyles[i].UsedFormattingFields then
|
||||||
|
lFontIndex := FFormattingStyles[i].FontIndex;
|
||||||
|
|
||||||
|
lAddBackground := (uffBackgroundColor in FFormattingStyles[i].UsedFormattingFields);
|
||||||
|
lWordwrap := (uffWordwrap in FFormattingStyles[i].UsedFormattingFields);
|
||||||
|
|
||||||
|
// And finally write the style
|
||||||
|
|
||||||
|
WriteXF(AStream, lFontIndex, lFormatIndex, 0, lTextRotation, lBorders,
|
||||||
|
lHorAlign, lVertAlign, lWordwrap, lAddBackground, lBackgroundColor);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Index to XF record, according to formatting }
|
||||||
|
procedure TsSpreadBIFF5Writer.WriteXFIndex(AStream: TStream; ACell: PCell);
|
||||||
|
var
|
||||||
|
lIndex: Integer;
|
||||||
|
lXFIndex: Word;
|
||||||
|
begin
|
||||||
|
// First try the fast methods for default formats
|
||||||
|
if ACell^.UsedFormattingFields = [] then
|
||||||
|
begin
|
||||||
|
AStream.WriteWord(WordToLE(15)); //XF15; see TsSpreadBIFF8Writer.AddDefaultFormats
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
(*
|
||||||
|
if ACell^.UsedFormattingFields = [uffTextRotation] then
|
||||||
|
begin
|
||||||
|
case ACell^.TextRotation of
|
||||||
|
rt90DegreeCounterClockwiseRotation: AStream.WriteWord(WordToLE(16)); //XF_16
|
||||||
|
rt90DegreeClockwiseRotation: AStream.WriteWord(WordToLE(17)); //XF_17
|
||||||
|
else
|
||||||
|
AStream.WriteWord(WordToLE(15)); //XF_15
|
||||||
|
end;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
*)
|
||||||
|
|
||||||
|
{
|
||||||
|
uffNumberFormat does not seem to have default XF indexes, but perhaps look at XF_21
|
||||||
|
if ACell^.UsedFormattingFields = [uffNumberFormat] then
|
||||||
|
begin
|
||||||
|
case ACell^.NumberFormat of
|
||||||
|
nfShortDate: AStream.WriteWord(WordToLE(???)); //what XF index?
|
||||||
|
nfShortDateTime: AStream.WriteWord(WordToLE(???)); //what XF index?
|
||||||
|
else
|
||||||
|
AStream.WriteWord(WordToLE(15)); //e.g. nfGeneral: XF_15
|
||||||
|
end;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not, then we need to search in the list of dynamic formats
|
||||||
|
lIndex := FindFormattingInList(ACell);
|
||||||
|
// Carefully check the index
|
||||||
|
if (lIndex < 0) or (lIndex > Length(FFormattingStyles)) then
|
||||||
|
raise Exception.Create('[TsSpreadBIFF5Writer.WriteXFIndex] Invalid Index, this should not happen!');
|
||||||
|
|
||||||
|
lXFIndex := FFormattingStyles[lIndex].Row;
|
||||||
|
|
||||||
|
AStream.WriteWord(WordToLE(lXFIndex));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadBIFF5Writer.WriteXFRecords(AStream: TStream);
|
||||||
|
begin
|
||||||
|
// XF0
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF1
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF2
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF3
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF4
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF5
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF6
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF7
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF8
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF9
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF10
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF11
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF12
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF13
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF14
|
||||||
|
WriteXF(AStream, 0, 0, MASK_XF_TYPE_PROT_STYLE_XF, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
// XF15 - Default, no formatting
|
||||||
|
WriteXF(AStream, 0, 0, 0, XF_ROTATION_HORIZONTAL, []);
|
||||||
|
|
||||||
|
// Add all further non-standard/built-in formatting styles
|
||||||
|
ListAllFormattingStyles;
|
||||||
|
WriteXFFieldsForFormattingStyles(AStream);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{*******************************************************************
|
|
||||||
* Initialization section
|
|
||||||
*
|
|
||||||
* Registers this reader / writer on fpSpreadsheet
|
|
||||||
*
|
|
||||||
*******************************************************************}
|
|
||||||
|
|
||||||
{ TsSpreadBIFF5Reader }
|
{ TsSpreadBIFF5Reader }
|
||||||
|
|
||||||
@ -1184,6 +1403,9 @@ var
|
|||||||
RecordType: Word;
|
RecordType: Word;
|
||||||
CurStreamPos: Int64;
|
CurStreamPos: Int64;
|
||||||
begin
|
begin
|
||||||
|
// Clear existing fonts. They will be replaced by those from the file.
|
||||||
|
FWorkbook.RemoveAllFonts;
|
||||||
|
|
||||||
while (not SectionEOF) do
|
while (not SectionEOF) do
|
||||||
begin
|
begin
|
||||||
{ Read the record header }
|
{ Read the record header }
|
||||||
@ -1193,9 +1415,12 @@ begin
|
|||||||
CurStreamPos := AStream.Position;
|
CurStreamPos := AStream.Position;
|
||||||
|
|
||||||
case RecordType of
|
case RecordType of
|
||||||
INT_EXCEL_ID_BOF: ;
|
INT_EXCEL_ID_BOF : ;
|
||||||
INT_EXCEL_ID_BOUNDSHEET: ReadBoundSheet(AStream);
|
INT_EXCEL_ID_BOUNDSHEET : ReadBoundSheet(AStream);
|
||||||
INT_EXCEL_ID_EOF: SectionEOF := True;
|
INT_EXCEL_ID_FONT : ReadFont(AStream);
|
||||||
|
INT_EXCEL_ID_XF : ReadXF(AStream);
|
||||||
|
INT_EXCEL_ID_PALETTE : ReadPalette(AStream);
|
||||||
|
INT_EXCEL_ID_EOF : SectionEOF := True;
|
||||||
else
|
else
|
||||||
// nothing
|
// nothing
|
||||||
end;
|
end;
|
||||||
@ -1232,6 +1457,7 @@ begin
|
|||||||
INT_EXCEL_ID_RSTRING: ReadRichString(AStream); //(RSTRING) This record stores a formatted text cell (Rich-Text). In BIFF8 it is usually replaced by the LABELSST record. Excel still uses this record, if it copies formatted text cells to the clipboard.
|
INT_EXCEL_ID_RSTRING: ReadRichString(AStream); //(RSTRING) This record stores a formatted text cell (Rich-Text). In BIFF8 it is usually replaced by the LABELSST record. Excel still uses this record, if it copies formatted text cells to the clipboard.
|
||||||
INT_EXCEL_ID_RK: ReadRKValue(AStream); //(RK) This record represents a cell that contains an RK value (encoded integer or floating-point value). If a floating-point value cannot be encoded to an RK value, a NUMBER record will be written. This record replaces the record INTEGER written in BIFF2.
|
INT_EXCEL_ID_RK: ReadRKValue(AStream); //(RK) This record represents a cell that contains an RK value (encoded integer or floating-point value). If a floating-point value cannot be encoded to an RK value, a NUMBER record will be written. This record replaces the record INTEGER written in BIFF2.
|
||||||
INT_EXCEL_ID_MULRK: ReadMulRKValues(AStream);
|
INT_EXCEL_ID_MULRK: ReadMulRKValues(AStream);
|
||||||
|
INT_EXCEL_ID_COLINFO: ReadColInfo(AStream);
|
||||||
INT_EXCEL_ID_ROWINFO: ReadRowInfo(AStream);
|
INT_EXCEL_ID_ROWINFO: ReadRowInfo(AStream);
|
||||||
INT_EXCEL_ID_FORMULA: ReadFormulaExcel(AStream);
|
INT_EXCEL_ID_FORMULA: ReadFormulaExcel(AStream);
|
||||||
INT_EXCEL_ID_BOF: ;
|
INT_EXCEL_ID_BOF: ;
|
||||||
@ -1437,17 +1663,6 @@ begin
|
|||||||
Result:=Number;
|
Result:=Number;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBIFF5Reader.ReadRowColXF(const AStream: TStream; out ARow,
|
|
||||||
ACol, AXF: WORD);
|
|
||||||
begin
|
|
||||||
{ BIFF Record data }
|
|
||||||
ARow := WordLEToN(AStream.ReadWord);
|
|
||||||
ACol := WordLEToN(AStream.ReadWord);
|
|
||||||
|
|
||||||
{ Index to XF record }
|
|
||||||
AXF:=WordLEtoN(AStream.ReadWord);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TsSpreadBIFF5Reader.ReadFromFile(AFileName: string; AData: TsWorkbook);
|
procedure TsSpreadBIFF5Reader.ReadFromFile(AFileName: string; AData: TsWorkbook);
|
||||||
var
|
var
|
||||||
MemStream: TMemoryStream;
|
MemStream: TMemoryStream;
|
||||||
@ -1476,6 +1691,71 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadBIFF5Reader.ReadXF(AStream: TStream);
|
||||||
|
type
|
||||||
|
TXFRecord = packed record // see p. 224
|
||||||
|
FontIndex: Word; // Offset 0, Size 2
|
||||||
|
FormatIndex: Word; // Offset 2, Size 2
|
||||||
|
XFType_CellProt_ParentStyleXF: Word; // Offset 4, Size 2
|
||||||
|
Align_TextBreak: Byte; // Offset 6, Size 1
|
||||||
|
XFRotation: Byte; // Offset 7, Size 1
|
||||||
|
Border_Background_1: DWord; // Offset 8, Size 4
|
||||||
|
Border_Background_2: DWord; // Offset 12, Size 4
|
||||||
|
end;
|
||||||
|
var
|
||||||
|
lData: TXFListData;
|
||||||
|
xf: TXFRecord;
|
||||||
|
b: Byte;
|
||||||
|
begin
|
||||||
|
AStream.ReadBuffer(xf, SizeOf(xf));
|
||||||
|
|
||||||
|
lData := TXFListData.Create;
|
||||||
|
|
||||||
|
// Font index
|
||||||
|
lData.FontIndex := WordLEToN(xf.FontIndex);
|
||||||
|
|
||||||
|
// Format index
|
||||||
|
lData.FormatIndex := WordLEToN(xf.FormatIndex);
|
||||||
|
|
||||||
|
// Horizontal text alignment
|
||||||
|
b := xf.Align_TextBreak AND MASK_XF_HOR_ALIGN;
|
||||||
|
if (b <= ord(High(TsHorAlignment))) then
|
||||||
|
lData.HorAlignment := TsHorAlignment(b)
|
||||||
|
else
|
||||||
|
lData.HorAlignment := haDefault;
|
||||||
|
|
||||||
|
// Vertical text alignment
|
||||||
|
b := (xf.Align_TextBreak AND MASK_XF_VERT_ALIGN) shr 4;
|
||||||
|
if (b + 1 <= ord(high(TsVertAlignment))) then
|
||||||
|
lData.VertAlignment := tsVertAlignment(b + 1) // + 1 due to vaDefault
|
||||||
|
else
|
||||||
|
lData.VertAlignment := vaDefault;
|
||||||
|
|
||||||
|
// Word wrap
|
||||||
|
lData.WordWrap := (xf.Align_TextBreak and MASK_XF_TEXTWRAP) <> 0;
|
||||||
|
|
||||||
|
// Cell borders and background
|
||||||
|
xf.Border_Background_1 := DWordLEToN(xf.Border_Background_1);
|
||||||
|
xf.Border_Background_2 := DWordLEToN(xf.Border_Background_2);
|
||||||
|
lData.Borders := [];
|
||||||
|
// the 4 masked bits encode the line style of the border line. 0 = no line
|
||||||
|
// We ignore the line style here. --> check against "no line"
|
||||||
|
if xf.Border_Background_1 and MASK_XF_BORDER_BOTTOM <> 0 then
|
||||||
|
Include(lData.Borders, cbSouth);
|
||||||
|
if xf.Border_Background_2 and MASK_XF_BORDER_LEFT <> 0 then
|
||||||
|
Include(lData.Borders, cbWest);
|
||||||
|
if xf.Border_Background_2 and MASK_XF_BORDER_RIGHT <> 0 then
|
||||||
|
Include(lData.Borders, cbEast);
|
||||||
|
if xf.Border_Background_2 and MASK_XF_BORDER_TOP <> 0 then
|
||||||
|
Include(lData.Borders, cbNorth);
|
||||||
|
|
||||||
|
// Background color
|
||||||
|
lData.BackgroundColor := xf.Border_Background_1 AND MASK_XF_BKGR_PATTERN_COLOR;
|
||||||
|
|
||||||
|
// Add the XF to the list
|
||||||
|
FXFList.Add(lData);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBIFF5Reader.ReadFromStream(AStream: TStream; AData: TsWorkbook);
|
procedure TsSpreadBIFF5Reader.ReadFromStream(AStream: TStream; AData: TsWorkbook);
|
||||||
var
|
var
|
||||||
BIFF5EOF: Boolean;
|
BIFF5EOF: Boolean;
|
||||||
@ -1525,6 +1805,68 @@ begin
|
|||||||
ApplyCellFormatting(ARow, ACol, XF);
|
ApplyCellFormatting(ARow, ACol, XF);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadBIFF5Reader.ReadFont(const AStream: TStream);
|
||||||
|
var
|
||||||
|
lCodePage: Word;
|
||||||
|
lHeight: Word;
|
||||||
|
lOptions: Word;
|
||||||
|
lColor: Word;
|
||||||
|
lWeight: Word;
|
||||||
|
Len: Byte;
|
||||||
|
fontname: ansistring;
|
||||||
|
font: TsFont;
|
||||||
|
begin
|
||||||
|
font := TsFont.Create;
|
||||||
|
|
||||||
|
{ Height of the font in twips = 1/20 of a point }
|
||||||
|
lHeight := WordLEToN(AStream.ReadWord); // WordToLE(200)
|
||||||
|
font.Size := lHeight/20;
|
||||||
|
|
||||||
|
{ Option flags }
|
||||||
|
lOptions := WordLEToN(AStream.ReadWord);
|
||||||
|
font.Style := [];
|
||||||
|
if lOptions and $0001 <> 0 then Include(font.Style, fssBold);
|
||||||
|
if lOptions and $0002 <> 0 then Include(font.Style, fssItalic);
|
||||||
|
if lOptions and $0004 <> 0 then Include(font.Style, fssUnderline);
|
||||||
|
if lOptions and $0008 <> 0 then Include(font.Style, fssStrikeout);
|
||||||
|
|
||||||
|
{ Colour index }
|
||||||
|
lColor := WordLEToN(AStream.ReadWord);
|
||||||
|
//font.Color := TsColor(lColor - 8); // Palette colors have an offset 8
|
||||||
|
font.Color := tsColor(lColor);
|
||||||
|
|
||||||
|
{ Font weight }
|
||||||
|
lWeight := WordLEToN(AStream.ReadWord);
|
||||||
|
if lWeight = 700 then Include(font.Style, fssBold);
|
||||||
|
|
||||||
|
{ Escapement type }
|
||||||
|
AStream.ReadWord();
|
||||||
|
|
||||||
|
{ Underline type }
|
||||||
|
if AStream.ReadByte > 0 then Include(font.Style, fssUnderline);
|
||||||
|
|
||||||
|
{ Font family }
|
||||||
|
AStream.ReadByte();
|
||||||
|
|
||||||
|
{ Character set }
|
||||||
|
lCodepage := AStream.ReadByte();
|
||||||
|
{$ifdef FPSPREADDEBUG}
|
||||||
|
WriteLn('Reading Font Codepage='+IntToStr(lCodepage));
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
{ Not used }
|
||||||
|
AStream.ReadByte();
|
||||||
|
|
||||||
|
{ Font name: Ansistring, char count in 1 byte }
|
||||||
|
Len := AStream.ReadByte();
|
||||||
|
SetLength(fontname, Len);
|
||||||
|
AStream.ReadBuffer(fontname[1], Len);
|
||||||
|
font.FontName := fontname;
|
||||||
|
|
||||||
|
{ Add font to workbook's font list }
|
||||||
|
FWorkbook.AddFont(font);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBIFF5Reader.ReadFormula(AStream: TStream);
|
procedure TsSpreadBIFF5Reader.ReadFormula(AStream: TStream);
|
||||||
begin
|
begin
|
||||||
|
|
||||||
@ -1569,12 +1911,6 @@ begin
|
|||||||
ApplyCellFormatting(ARow, ACol, XF);
|
ApplyCellFormatting(ARow, ACol, XF);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBIFF5Reader.ApplyCellFormatting(ARow, ACol: Cardinal;
|
|
||||||
XFIndex: Integer);
|
|
||||||
begin
|
|
||||||
// to do...
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
|
|
||||||
|
@ -63,29 +63,6 @@ uses
|
|||||||
fpsutils, lazutf8;
|
fpsutils, lazutf8;
|
||||||
|
|
||||||
type
|
type
|
||||||
TXFRecordData = class
|
|
||||||
public
|
|
||||||
FontIndex: Integer;
|
|
||||||
FormatIndex: Integer;
|
|
||||||
HorAlignment: TsHorAlignment;
|
|
||||||
VertAlignment: TsVertAlignment;
|
|
||||||
WordWrap: Boolean;
|
|
||||||
Borders: TsCellBorders;
|
|
||||||
BackgroundColor: TsColor;
|
|
||||||
{
|
|
||||||
FontIndex: Integer;
|
|
||||||
Border: TsBorder;
|
|
||||||
XFType_Protection: Word;
|
|
||||||
Align_TextBreak: Byte;
|
|
||||||
XF_Rotation: Byte;
|
|
||||||
Indent_Shrink_TextDir: Byte;
|
|
||||||
UsedAttrib: Byte;
|
|
||||||
Border_Background1: DWord;
|
|
||||||
Border_Background2: DWord;
|
|
||||||
Border_Background3: Word;
|
|
||||||
}
|
|
||||||
end;
|
|
||||||
|
|
||||||
TFormatRecordData = class
|
TFormatRecordData = class
|
||||||
public
|
public
|
||||||
Index: Integer;
|
Index: Integer;
|
||||||
@ -101,10 +78,9 @@ type
|
|||||||
FWorksheetNames: TStringList;
|
FWorksheetNames: TStringList;
|
||||||
FCurrentWorksheet: Integer;
|
FCurrentWorksheet: Integer;
|
||||||
FSharedStringTable: TStringList;
|
FSharedStringTable: TStringList;
|
||||||
FXFList: TFPList; // of TXFRecordData
|
|
||||||
FFormatList: TFPList; // of TFormatRecordData
|
FFormatList: TFPList; // of TFormatRecordData
|
||||||
function DecodeRKValue(const ARK: DWORD): Double;
|
function DecodeRKValue(const ARK: DWORD): Double;
|
||||||
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Integer);
|
// procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Integer);
|
||||||
procedure ExtractNumberFormat(AXFIndex: WORD;
|
procedure ExtractNumberFormat(AXFIndex: WORD;
|
||||||
out ANumberFormat: TsNumberFormat; out ADecimals: Word;
|
out ANumberFormat: TsNumberFormat; out ADecimals: Word;
|
||||||
out ANumberFormatStr: String);
|
out ANumberFormatStr: String);
|
||||||
@ -119,9 +95,8 @@ type
|
|||||||
|
|
||||||
procedure ReadRKValue(const AStream: TStream);
|
procedure ReadRKValue(const AStream: TStream);
|
||||||
procedure ReadMulRKValues(const AStream: TStream);
|
procedure ReadMulRKValues(const AStream: TStream);
|
||||||
procedure ReadRowColXF(const AStream: TStream; out ARow,ACol,AXF: WORD);
|
// procedure ReadRowColXF(const AStream: TStream; out ARow,ACol,AXF: WORD);
|
||||||
function ReadString(const AStream: TStream; const ALength: WORD): UTF8String;
|
function ReadString(const AStream: TStream; const ALength: WORD): UTF8String;
|
||||||
procedure ReadRichString(const AStream: TStream);
|
|
||||||
procedure ReadSST(const AStream: TStream);
|
procedure ReadSST(const AStream: TStream);
|
||||||
procedure ReadLabelSST(const AStream: TStream);
|
procedure ReadLabelSST(const AStream: TStream);
|
||||||
// Read XF record
|
// Read XF record
|
||||||
@ -135,13 +110,12 @@ type
|
|||||||
// procedure ReadCodepage in xlscommon
|
// procedure ReadCodepage in xlscommon
|
||||||
// procedure ReadDateMode in xlscommon
|
// procedure ReadDateMode in xlscommon
|
||||||
procedure ReadFont(const AStream: TStream);
|
procedure ReadFont(const AStream: TStream);
|
||||||
// Read col info
|
|
||||||
procedure ReadColInfo(const AStream: TStream);
|
|
||||||
{ Record reading methods }
|
{ Record reading methods }
|
||||||
procedure ReadBlank(AStream: TStream); override;
|
procedure ReadBlank(AStream: TStream); override;
|
||||||
procedure ReadFormula(AStream: TStream); override;
|
procedure ReadFormula(AStream: TStream); override;
|
||||||
procedure ReadLabel(AStream: TStream); override;
|
procedure ReadLabel(AStream: TStream); override;
|
||||||
procedure ReadNumber(AStream: TStream); override;
|
procedure ReadNumber(AStream: TStream); override;
|
||||||
|
procedure ReadRichString(const AStream: TStream);
|
||||||
public
|
public
|
||||||
constructor Create(AWorkbook: TsWorkbook); override;
|
constructor Create(AWorkbook: TsWorkbook); override;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -164,12 +138,8 @@ type
|
|||||||
ACell: PCell); override;
|
ACell: PCell); override;
|
||||||
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 WriteCodepage in xlscommon; Workbook Globals record
|
|
||||||
procedure WriteColInfo(AStream: TStream; ACol: PCol);
|
|
||||||
procedure WriteColInfos(AStream: TStream; ASheet: TsWorksheet);
|
|
||||||
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;
|
||||||
// procedure WriteDateMode in xlscommon; Workbook Globals record
|
|
||||||
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);
|
||||||
@ -279,7 +249,6 @@ const
|
|||||||
INT_EXCEL_ID_BLANK = $0201;
|
INT_EXCEL_ID_BLANK = $0201;
|
||||||
INT_EXCEL_ID_BOF = $0809;
|
INT_EXCEL_ID_BOF = $0809;
|
||||||
INT_EXCEL_ID_BOUNDSHEET = $0085; // Renamed to SHEET in the latest OpenOffice docs
|
INT_EXCEL_ID_BOUNDSHEET = $0085; // Renamed to SHEET in the latest OpenOffice docs
|
||||||
INT_EXCEL_ID_COLINFO = $007D;
|
|
||||||
INT_EXCEL_ID_COUNTRY = $008C;
|
INT_EXCEL_ID_COUNTRY = $008C;
|
||||||
INT_EXCEL_ID_EOF = $000A;
|
INT_EXCEL_ID_EOF = $000A;
|
||||||
INT_EXCEL_ID_DIMENSIONS = $0200;
|
INT_EXCEL_ID_DIMENSIONS = $0200;
|
||||||
@ -291,7 +260,6 @@ const
|
|||||||
INT_EXCEL_ID_STYLE = $0293;
|
INT_EXCEL_ID_STYLE = $0293;
|
||||||
INT_EXCEL_ID_WINDOW1 = $003D;
|
INT_EXCEL_ID_WINDOW1 = $003D;
|
||||||
INT_EXCEL_ID_WINDOW2 = $023E;
|
INT_EXCEL_ID_WINDOW2 = $023E;
|
||||||
INT_EXCEL_ID_XF = $00E0;
|
|
||||||
INT_EXCEL_ID_RSTRING = $00D6;
|
INT_EXCEL_ID_RSTRING = $00D6;
|
||||||
INT_EXCEL_ID_RK = $027E;
|
INT_EXCEL_ID_RK = $027E;
|
||||||
INT_EXCEL_ID_MULRK = $00BD;
|
INT_EXCEL_ID_MULRK = $00BD;
|
||||||
@ -318,10 +286,6 @@ const
|
|||||||
INT_BOF_BUILD_ID = $1FD2;
|
INT_BOF_BUILD_ID = $1FD2;
|
||||||
INT_BOF_BUILD_YEAR = $07CD;
|
INT_BOF_BUILD_YEAR = $07CD;
|
||||||
|
|
||||||
{ FONT record constants }
|
|
||||||
INT_FONT_WEIGHT_NORMAL = $0190;
|
|
||||||
INT_FONT_WEIGHT_BOLD = $02BC;
|
|
||||||
|
|
||||||
{ FORMULA record constants }
|
{ FORMULA record constants }
|
||||||
MASK_FORMULA_RECALCULATE_ALWAYS = $0001;
|
MASK_FORMULA_RECALCULATE_ALWAYS = $0001;
|
||||||
MASK_FORMULA_RECALCULATE_ON_OPEN = $0002;
|
MASK_FORMULA_RECALCULATE_ON_OPEN = $0002;
|
||||||
@ -352,44 +316,11 @@ const
|
|||||||
|
|
||||||
{ XF substructures }
|
{ XF substructures }
|
||||||
|
|
||||||
{ XF_TYPE_PROT - XF Type and Cell protection (3 Bits) - BIFF3-BIFF8 }
|
|
||||||
MASK_XF_TYPE_PROT_LOCKED = $1;
|
|
||||||
MASK_XF_TYPE_PROT_FORMULA_HIDDEN = $2;
|
|
||||||
MASK_XF_TYPE_PROT_STYLE_XF = $4; // 0 = CELL XF
|
|
||||||
|
|
||||||
{ XF_USED_ATTRIB - Attributes from parent Style XF (6 Bits) - BIFF3-BIFF8
|
|
||||||
|
|
||||||
In a CELL XF a cleared bit means that the parent attribute is used,
|
|
||||||
while a set bit indicates that the data in this XF is used
|
|
||||||
|
|
||||||
In a STYLE XF a cleared bit means that the data in this XF is used,
|
|
||||||
while a set bit indicates that the attribute should be ignored }
|
|
||||||
MASK_XF_USED_ATTRIB_NUMBER_FORMAT = $04;
|
|
||||||
MASK_XF_USED_ATTRIB_FONT = $08;
|
|
||||||
MASK_XF_USED_ATTRIB_TEXT = $10;
|
|
||||||
MASK_XF_USED_ATTRIB_BORDER_LINES = $20;
|
|
||||||
MASK_XF_USED_ATTRIB_BACKGROUND = $40;
|
|
||||||
MASK_XF_USED_ATTRIB_CELL_PROTECTION = $80;
|
|
||||||
|
|
||||||
{ XF HORIZONTAL ALIGN }
|
|
||||||
MASK_XF_HOR_ALIGN_LEFT = $01;
|
|
||||||
MASK_XF_HOR_ALIGN_CENTER = $02;
|
|
||||||
MASK_XF_HOR_ALIGN_RIGHT = $03;
|
|
||||||
MASK_XF_HOR_ALIGN_FILLED = $04;
|
|
||||||
MASK_XF_HOR_ALIGN_JUSTIFIED = $05; // BIFF4-BIFF8
|
|
||||||
MASK_XF_HOR_ALIGN_CENTERED_SELECTION= $06; // BIFF4-BIFF8
|
|
||||||
MASK_XF_HOR_ALIGN_DISTRIBUTED = $07; // BIFF8
|
|
||||||
|
|
||||||
{ XF_VERT_ALIGN }
|
|
||||||
MASK_XF_VERT_ALIGN_TOP = $00;
|
|
||||||
MASK_XF_VERT_ALIGN_CENTER = $10;
|
|
||||||
MASK_XF_VERT_ALIGN_BOTTOM = $20;
|
|
||||||
MASK_XF_VERT_ALIGN_JUSTIFIED = $30;
|
|
||||||
|
|
||||||
{ XF_ROTATION }
|
{ XF_ROTATION }
|
||||||
XF_ROTATION_HORIZONTAL = 0;
|
XF_ROTATION_HORIZONTAL = 0;
|
||||||
XF_ROTATION_90_DEGREE_COUNTERCLOCKWISE = 90;
|
XF_ROTATION_90DEG_CCW = 90;
|
||||||
XF_ROTATION_90_DEGREE_CLOCKWISE = 180;
|
XF_ROTATION_90DEG_CW = 180;
|
||||||
|
XF_ROTATION_STACKED = 255; // Letters stacked top to bottom, but not rotated
|
||||||
|
|
||||||
{ XF CELL BORDER }
|
{ XF CELL BORDER }
|
||||||
MASK_XF_BORDER_LEFT = $0000000F;
|
MASK_XF_BORDER_LEFT = $0000000F;
|
||||||
@ -397,18 +328,6 @@ const
|
|||||||
MASK_XF_BORDER_TOP = $00000F00;
|
MASK_XF_BORDER_TOP = $00000F00;
|
||||||
MASK_XF_BORDER_BOTTOM = $0000F000;
|
MASK_XF_BORDER_BOTTOM = $0000F000;
|
||||||
|
|
||||||
{ XF record constants }
|
|
||||||
MASK_XF_TYPE_PROT = $0007;
|
|
||||||
MASK_XF_TYPE_PROT_PARENT = $FFF0;
|
|
||||||
|
|
||||||
MASK_XF_HOR_ALIGN = $07;
|
|
||||||
MASK_XF_VERT_ALIGN = $70;
|
|
||||||
MASK_XF_TEXTWRAP = $08;
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
Exported functions
|
|
||||||
}
|
|
||||||
|
|
||||||
{ TsSpreadBIFF8Writer }
|
{ TsSpreadBIFF8Writer }
|
||||||
|
|
||||||
@ -425,6 +344,7 @@ begin
|
|||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
if ACell^.UsedFormattingFields = [uffTextRotation] then
|
if ACell^.UsedFormattingFields = [uffTextRotation] then
|
||||||
begin
|
begin
|
||||||
case ACell^.TextRotation of
|
case ACell^.TextRotation of
|
||||||
@ -435,6 +355,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
uffNumberFormat does not seem to have default XF indexes, but perhaps look at XF_21
|
uffNumberFormat does not seem to have default XF indexes, but perhaps look at XF_21
|
||||||
@ -553,8 +474,9 @@ begin
|
|||||||
begin
|
begin
|
||||||
case FFormattingStyles[i].TextRotation of
|
case FFormattingStyles[i].TextRotation of
|
||||||
trHorizontal: lTextRotation := XF_ROTATION_HORIZONTAL;
|
trHorizontal: lTextRotation := XF_ROTATION_HORIZONTAL;
|
||||||
rt90DegreeClockwiseRotation: lTextRotation := XF_ROTATION_90_DEGREE_CLOCKWISE;
|
rt90DegreeClockwiseRotation: lTextRotation := XF_ROTATION_90DEG_CW;
|
||||||
rt90DegreeCounterClockwiseRotation: lTextRotation := XF_ROTATION_90_DEGREE_COUNTERCLOCKWISE;
|
rt90DegreeCounterClockwiseRotation: lTextRotation := XF_ROTATION_90DEG_CCW;
|
||||||
|
rtStacked: lTextRotation := XF_ROTATION_STACKED;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -680,17 +602,11 @@ begin
|
|||||||
AStream.Position := CurrentPos;
|
AStream.Position := CurrentPos;
|
||||||
|
|
||||||
WriteBOF(AStream, INT_BOF_SHEET);
|
WriteBOF(AStream, INT_BOF_SHEET);
|
||||||
|
WriteIndex(AStream);
|
||||||
WriteIndex(AStream);
|
WriteColInfos(AStream, sheet);
|
||||||
|
WriteDimensions(AStream, sheet);
|
||||||
WriteColInfos(AStream, sheet);
|
WriteWindow2(AStream, True);
|
||||||
|
WriteCellsToStream(AStream, sheet.Cells);
|
||||||
WriteDimensions(AStream, sheet);
|
|
||||||
|
|
||||||
WriteWindow2(AStream, True);
|
|
||||||
|
|
||||||
WriteCellsToStream(AStream, sheet.Cells);
|
|
||||||
|
|
||||||
WriteEOF(AStream);
|
WriteEOF(AStream);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -800,42 +716,6 @@ begin
|
|||||||
AStream.WriteBuffer(WideStringToLE(WideSheetName)[1], Len * Sizeof(WideChar));
|
AStream.WriteBuffer(WideStringToLE(WideSheetName)[1], Len * Sizeof(WideChar));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{*******************************************************************
|
|
||||||
* TsSpreadBIFF8Writer.WriteColInfo ()
|
|
||||||
*
|
|
||||||
* DESCRIPTION: Writes a COLINFO record
|
|
||||||
*******************************************************************}
|
|
||||||
procedure TsSpreadBIFF8Writer.WriteColInfo(AStream: TStream; ACol: PCol);
|
|
||||||
var
|
|
||||||
w: Integer;
|
|
||||||
begin
|
|
||||||
if Assigned(ACol) then begin
|
|
||||||
{ BIFF Record header }
|
|
||||||
AStream.WriteWord(WordToLE(INT_EXCEL_ID_COLINFO)); // BIFF record header
|
|
||||||
AStream.WriteWord(WordToLE(12)); // Record size
|
|
||||||
AStream.WriteWord(WordToLE(ACol^.Col)); // start column
|
|
||||||
AStream.WriteWord(WordToLE(ACol^.Col)); // end column
|
|
||||||
{ calculate width to be in units of 1/256 of pixel width of character "0" }
|
|
||||||
w := round(ACol^.Width * 256);
|
|
||||||
AStream.WriteWord(WordToLE(w)); // write width
|
|
||||||
AStream.WriteWord(15); // XF record, ignored
|
|
||||||
AStream.WriteWord(0); // option flags, ignored
|
|
||||||
AStream.WriteWord(0); // "not used"
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TsSpreadBIFF8Writer.WriteColInfos(AStream: TStream;
|
|
||||||
ASheet: TsWorksheet);
|
|
||||||
var
|
|
||||||
j: Integer;
|
|
||||||
col: PCol;
|
|
||||||
begin
|
|
||||||
for j := 0 to ASheet.Cols.Count-1 do begin
|
|
||||||
col := PCol(ASheet.Cols[j]);
|
|
||||||
WriteColInfo(AStream, col);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{*******************************************************************
|
{*******************************************************************
|
||||||
* TsSpreadBIFF8Writer.WriteDateTime ()
|
* TsSpreadBIFF8Writer.WriteDateTime ()
|
||||||
*
|
*
|
||||||
@ -949,7 +829,6 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(optn));
|
AStream.WriteWord(WordToLE(optn));
|
||||||
|
|
||||||
{ Colour index }
|
{ Colour index }
|
||||||
//AStream.WriteWord(WordToLE(8 + ord(AFont.Color))); //WordToLE($7FFF));
|
|
||||||
AStream.WriteWord(WordToLE(ord(AFont.Color)));
|
AStream.WriteWord(WordToLE(ord(AFont.Color)));
|
||||||
|
|
||||||
{ Font weight }
|
{ Font weight }
|
||||||
@ -1643,6 +1522,22 @@ end;
|
|||||||
|
|
||||||
{ TsSpreadBIFF8Reader }
|
{ TsSpreadBIFF8Reader }
|
||||||
|
|
||||||
|
constructor TsSpreadBIFF8Reader.Create(AWorkbook: TsWorkbook);
|
||||||
|
begin
|
||||||
|
inherited Create(AWorkbook);
|
||||||
|
FFormatList := TFPList.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TsSpreadBIFF8Reader.Destroy;
|
||||||
|
var
|
||||||
|
j: integer;
|
||||||
|
begin
|
||||||
|
for j := FFormatList.Count-1 downto 0 do TObject(FFormatList[j]).Free;
|
||||||
|
FFormatList.Free;
|
||||||
|
if Assigned(FSharedStringTable) then FSharedStringTable.Free;
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
function TsSpreadBIFF8Reader.DecodeRKValue(const ARK: DWORD): Double;
|
function TsSpreadBIFF8Reader.DecodeRKValue(const ARK: DWORD): Double;
|
||||||
var
|
var
|
||||||
Number: Double;
|
Number: Double;
|
||||||
@ -1701,7 +1596,7 @@ const
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0); // 51..58
|
0, 0, 0, 0, 0, 0, 0, 0); // 51..58
|
||||||
var
|
var
|
||||||
lFormatData: TFormatRecordData;
|
lFormatData: TFormatRecordData;
|
||||||
lXFData: TXFRecordData;
|
lXFData: TXFListData;
|
||||||
isAMPM: Boolean;
|
isAMPM: Boolean;
|
||||||
isLongTime: Boolean;
|
isLongTime: Boolean;
|
||||||
isMilliSec: Boolean;
|
isMilliSec: Boolean;
|
||||||
@ -1719,7 +1614,7 @@ begin
|
|||||||
|
|
||||||
if lFormatData = nil then begin
|
if lFormatData = nil then begin
|
||||||
// no custom format, so first test for default formats
|
// no custom format, so first test for default formats
|
||||||
lXFData := TXFRecordData (FXFList.Items[AXFIndex]);
|
lXFData := TXFListData (FXFList.Items[AXFIndex]);
|
||||||
case lXFData.FormatIndex of
|
case lXFData.FormatIndex of
|
||||||
FORMAT_DATE_DM:
|
FORMAT_DATE_DM:
|
||||||
begin ANumberFormat := nfFmtDateTime; ANumberFormatStr := 'DM'; end;
|
begin ANumberFormat := nfFmtDateTime; ANumberFormatStr := 'DM'; end;
|
||||||
@ -1861,7 +1756,7 @@ begin
|
|||||||
Result := DecomprStrValue;
|
Result := DecomprStrValue;
|
||||||
end;
|
end;
|
||||||
if StringFlags and 8 = 8 then begin
|
if StringFlags and 8 = 8 then begin
|
||||||
//Rich string (This only happend in BIFF8)
|
//Rich string (This only happened in BIFF8)
|
||||||
for j := 1 to RunsCounter do begin
|
for j := 1 to RunsCounter do begin
|
||||||
if (PendingRecordSize<=0) then begin
|
if (PendingRecordSize<=0) then begin
|
||||||
//A CONTINUE may happend here
|
//A CONTINUE may happend here
|
||||||
@ -1909,14 +1804,13 @@ var
|
|||||||
begin
|
begin
|
||||||
// Clear existing fonts. They will be replaced by those from the file.
|
// Clear existing fonts. They will be replaced by those from the file.
|
||||||
FWorkbook.RemoveAllFonts;
|
FWorkbook.RemoveAllFonts;
|
||||||
|
|
||||||
if Assigned(FSharedStringTable) then FreeAndNil(FSharedStringTable);
|
if Assigned(FSharedStringTable) then FreeAndNil(FSharedStringTable);
|
||||||
while (not SectionEOF) do
|
|
||||||
begin
|
while (not SectionEOF) do begin
|
||||||
{ Read the record header }
|
{ Read the record header }
|
||||||
RecordType := WordLEToN(AStream.ReadWord);
|
RecordType := WordLEToN(AStream.ReadWord);
|
||||||
RecordSize := WordLEToN(AStream.ReadWord);
|
RecordSize := WordLEToN(AStream.ReadWord);
|
||||||
PendingRecordSize:=RecordSize;
|
PendingRecordSize := RecordSize;
|
||||||
|
|
||||||
CurStreamPos := AStream.Position;
|
CurStreamPos := AStream.Position;
|
||||||
|
|
||||||
@ -2086,86 +1980,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBIFF8Reader.ReadRowColXF(const AStream: TStream; out ARow,
|
|
||||||
ACol, AXF: WORD);
|
|
||||||
begin
|
|
||||||
{ BIFF Record data }
|
|
||||||
ARow := WordLEToN(AStream.ReadWord);
|
|
||||||
ACol := WordLEToN(AStream.ReadWord);
|
|
||||||
|
|
||||||
{ Index to XF record }
|
|
||||||
AXF:=WordLEtoN(AStream.ReadWord);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ Applies the XF formatting given by the given index to the specified cell }
|
|
||||||
procedure TsSpreadBIFF8Reader.ApplyCellFormatting(ARow, ACol: Cardinal;
|
|
||||||
XFIndex: Integer);
|
|
||||||
var
|
|
||||||
lCell: PCell;
|
|
||||||
XFData: TXFRecordData;
|
|
||||||
begin
|
|
||||||
lCell := FWorksheet.GetCell(ARow, ACol);
|
|
||||||
if Assigned(lCell) then begin
|
|
||||||
XFData := TXFRecordData(FXFList.Items[XFIndex]);
|
|
||||||
|
|
||||||
// Font
|
|
||||||
if XFData.FontIndex = 1 then
|
|
||||||
Include(lCell^.UsedFormattingFields, uffBold)
|
|
||||||
else
|
|
||||||
if XFData.FontIndex > 0 then
|
|
||||||
Include(lCell^.UsedFormattingFields, uffFont);
|
|
||||||
lCell^.FontIndex := XFData.FontIndex;
|
|
||||||
|
|
||||||
// Alignment
|
|
||||||
lCell^.HorAlignment := XFData.HorAlignment;
|
|
||||||
lCell^.VertAlignment := XFData.VertAlignment;
|
|
||||||
|
|
||||||
// Word wrap
|
|
||||||
if XFData.WordWrap then
|
|
||||||
Include(lCell^.UsedFormattingFields, uffWordWrap)
|
|
||||||
else
|
|
||||||
Exclude(lCell^.UsedFormattingFields, uffWordWrap);
|
|
||||||
|
|
||||||
// Borders
|
|
||||||
if XFData.Borders <> [] then begin
|
|
||||||
Include(lCell^.UsedFormattingFields, uffBorder);
|
|
||||||
lCell^.Border := XFData.Borders;
|
|
||||||
end else
|
|
||||||
Exclude(lCell^.UsedFormattingFields, uffBorder);
|
|
||||||
|
|
||||||
// Background color
|
|
||||||
if XFData.BackgroundColor <> 0 then begin
|
|
||||||
Include(lCell^.UsedFormattingFields, uffBackgroundColor);
|
|
||||||
lCell^.BackgroundColor := XFData.BackgroundColor;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TsSpreadBIFF8Reader.ReadString(const AStream: TStream;
|
function TsSpreadBIFF8Reader.ReadString(const AStream: TStream;
|
||||||
const ALength: WORD): UTF8String;
|
const ALength: WORD): UTF8String;
|
||||||
begin
|
begin
|
||||||
Result:=UTF16ToUTF8(ReadWideString(AStream, ALength));
|
Result:=UTF16ToUTF8(ReadWideString(AStream, ALength));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
constructor TsSpreadBIFF8Reader.Create(AWorkbook: TsWorkbook);
|
|
||||||
begin
|
|
||||||
inherited Create(AWorkbook);
|
|
||||||
FXFList := TFPList.Create;
|
|
||||||
FFormatList := TFPList.Create;
|
|
||||||
end;
|
|
||||||
|
|
||||||
destructor TsSpreadBIFF8Reader.Destroy;
|
|
||||||
var
|
|
||||||
j: integer;
|
|
||||||
begin
|
|
||||||
for j := FXFList.Count-1 downto 0 do TObject(FXFList[j]).Free;
|
|
||||||
for j := FFormatList.Count-1 downto 0 do TObject(FFormatList[j]).Free;
|
|
||||||
FXFList.Free;
|
|
||||||
FFormatList.Free;
|
|
||||||
if Assigned(FSharedStringTable) then FSharedStringTable.Free;
|
|
||||||
inherited;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TsSpreadBIFF8Reader.ReadFromFile(AFileName: string; AData: TsWorkbook);
|
procedure TsSpreadBIFF8Reader.ReadFromFile(AFileName: string; AData: TsWorkbook);
|
||||||
var
|
var
|
||||||
MemStream: TMemoryStream;
|
MemStream: TMemoryStream;
|
||||||
@ -2466,13 +2286,13 @@ type
|
|||||||
Border_Background_3: DWord; // Offset 18, Size 2
|
Border_Background_3: DWord; // Offset 18, Size 2
|
||||||
end;
|
end;
|
||||||
var
|
var
|
||||||
lData: TXFRecordData;
|
lData: TXFListData;
|
||||||
xf: TXFRecord;
|
xf: TXFRecord;
|
||||||
b: Byte;
|
b: Byte;
|
||||||
begin
|
begin
|
||||||
AStream.ReadBuffer(xf, SizeOf(xf));
|
AStream.ReadBuffer(xf, SizeOf(xf));
|
||||||
|
|
||||||
lData := TXFRecordData.Create;
|
lData := TXFListData.Create;
|
||||||
|
|
||||||
// Font index
|
// Font index
|
||||||
lData.FontIndex := WordLEToN(xf.FontIndex);
|
lData.FontIndex := WordLEToN(xf.FontIndex);
|
||||||
@ -2541,12 +2361,12 @@ end;
|
|||||||
function TsSpreadBIFF8Reader.FindFormatRecordForCell(const AXFIndex: Integer
|
function TsSpreadBIFF8Reader.FindFormatRecordForCell(const AXFIndex: Integer
|
||||||
): TFormatRecordData;
|
): TFormatRecordData;
|
||||||
var
|
var
|
||||||
lXFData: TXFRecordData;
|
lXFData: TXFListData;
|
||||||
lFormatData: TFormatRecordData;
|
lFormatData: TFormatRecordData;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
Result := nil;
|
Result := nil;
|
||||||
lXFData := TXFRecordData(FXFList.Items[AXFIndex]);
|
lXFData := TXFListData(FXFList.Items[AXFIndex]);
|
||||||
for i := 0 to FFormatList.Count-1 do
|
for i := 0 to FFormatList.Count-1 do
|
||||||
begin
|
begin
|
||||||
lFormatData := TFormatRecordData(FFormatList.Items[i]);
|
lFormatData := TFormatRecordData(FFormatList.Items[i]);
|
||||||
@ -2614,24 +2434,6 @@ begin
|
|||||||
FWorkbook.AddFont(font);
|
FWorkbook.AddFont(font);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBiff8Reader.ReadColInfo(const AStream: TStream);
|
|
||||||
var
|
|
||||||
c, c1, c2: Cardinal;
|
|
||||||
w: Word;
|
|
||||||
col: TCol;
|
|
||||||
begin
|
|
||||||
// read column start and end index of column range
|
|
||||||
c1 := WordLEToN(AStream.ReadWord);
|
|
||||||
c2 := WordLEToN(AStream.ReadWord);
|
|
||||||
// read col width in 1/256 of the width of "0" character
|
|
||||||
w := WordLEToN(AStream.ReadWord);
|
|
||||||
// calculate width in units of "characters"
|
|
||||||
col.Width := w / 256;
|
|
||||||
// assign width to columns
|
|
||||||
for c := c1 to c2 do
|
|
||||||
FWorksheet.WriteColInfo(c, col);
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
{*******************************************************************
|
{*******************************************************************
|
||||||
* Initialization section
|
* Initialization section
|
||||||
|
@ -18,8 +18,14 @@ const
|
|||||||
{ RECORD IDs which didn't change across versions 2-8 }
|
{ RECORD IDs which didn't change across versions 2-8 }
|
||||||
INT_EXCEL_ID_FONT = $0031;
|
INT_EXCEL_ID_FONT = $0031;
|
||||||
INT_EXCEL_ID_CODEPAGE = $0042;
|
INT_EXCEL_ID_CODEPAGE = $0042;
|
||||||
|
INT_EXCEL_ID_COLINFO = $007D;
|
||||||
INT_EXCEL_ID_DATEMODE = $0022;
|
INT_EXCEL_ID_DATEMODE = $0022;
|
||||||
INT_EXCEL_ID_PALETTE = $0092;
|
INT_EXCEL_ID_PALETTE = $0092;
|
||||||
|
INT_EXCEL_ID_XF = $00E0;
|
||||||
|
|
||||||
|
{ FONT record constants }
|
||||||
|
INT_FONT_WEIGHT_NORMAL = $0190;
|
||||||
|
INT_FONT_WEIGHT_BOLD = $02BC;
|
||||||
|
|
||||||
{ Formula constants TokenID values }
|
{ Formula constants TokenID values }
|
||||||
|
|
||||||
@ -183,46 +189,6 @@ const
|
|||||||
// 1AH tSheet Start of external sheet reference (BIFF2-BIFF4)
|
// 1AH tSheet Start of external sheet reference (BIFF2-BIFF4)
|
||||||
// 1BH tEndSheet End of external sheet reference (BIFF2-BIFF4)
|
// 1BH tEndSheet End of external sheet reference (BIFF2-BIFF4)
|
||||||
|
|
||||||
{ Built In Color Palette Indexes }
|
|
||||||
// Proper spelling
|
|
||||||
BUILT_IN_COLOR_PALETTE_BLACK = $08; // 000000H
|
|
||||||
BUILT_IN_COLOR_PALETTE_WHITE = $09; // FFFFFFH
|
|
||||||
BUILT_IN_COLOR_PALETTE_RED = $0A; // FF0000H
|
|
||||||
BUILT_IN_COLOR_PALETTE_GREEN = $0B; // 00FF00H
|
|
||||||
BUILT_IN_COLOR_PALETTE_BLUE = $0C; // 0000FFH
|
|
||||||
BUILT_IN_COLOR_PALETTE_YELLOW = $0D; // FFFF00H
|
|
||||||
BUILT_IN_COLOR_PALETTE_MAGENTA = $0E; // FF00FFH
|
|
||||||
BUILT_IN_COLOR_PALETTE_CYAN = $0F; // 00FFFFH
|
|
||||||
BUILT_IN_COLOR_PALETTE_DARK_RED = $10; // 800000H
|
|
||||||
BUILT_IN_COLOR_PALETTE_DARK_GREEN= $11; // 008000H
|
|
||||||
BUILT_IN_COLOR_PALETTE_DARK_BLUE = $12; // 000080H
|
|
||||||
BUILT_IN_COLOR_PALETTE_OLIVE = $13; // 808000H
|
|
||||||
BUILT_IN_COLOR_PALETTE_PURPLE = $14; // 800080H
|
|
||||||
BUILT_IN_COLOR_PALETTE_TEAL = $15; // 008080H
|
|
||||||
BUILT_IN_COLOR_PALETTE_SILVER = $16; // C0C0C0H
|
|
||||||
BUILT_IN_COLOR_PALETTE_GREY = $17; // 808080H
|
|
||||||
|
|
||||||
// Spelling mistake; kept for compatibility
|
|
||||||
BUILT_IN_COLOR_PALLETE_BLACK = $08 deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_WHITE = $09 deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_RED = $0A deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_GREEN = $0B deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_BLUE = $0C deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_YELLOW = $0D deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_MAGENTA = $0E deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_CYAN = $0F deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_DARK_RED = $10 deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_DARK_GREEN= $11 deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_DARK_BLUE = $12 deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_OLIVE = $13 deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_PURPLE = $14 deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_TEAL = $15 deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_SILVER = $16 deprecated 'Please use the *_PALETTE version';
|
|
||||||
BUILT_IN_COLOR_PALLETE_GREY = $17 deprecated 'Please use the *_PALETTE version';
|
|
||||||
|
|
||||||
EXTRA_COLOR_PALETTE_GREY10PCT = $18; // E6E6E6H //todo: is $18 correct? see 5.74.3 Built-In Default Colour Tables
|
|
||||||
EXTRA_COLOR_PALETTE_GREY20PCT = $19; // CCCCCCH //todo: is $19 correct? see 5.74.3 Built-In Default Colour Tables
|
|
||||||
|
|
||||||
{ CODEPAGE record constants }
|
{ CODEPAGE record constants }
|
||||||
WORD_ASCII = 367;
|
WORD_ASCII = 367;
|
||||||
WORD_UTF_16 = 1200; // BIFF 8
|
WORD_UTF_16 = 1200; // BIFF 8
|
||||||
@ -267,6 +233,57 @@ const
|
|||||||
FORMAT_TIME_MSZ = 47; //time MM:SS.0
|
FORMAT_TIME_MSZ = 47; //time MM:SS.0
|
||||||
FORMAT_TIME_INTERVAL = 46; //time [hh]:mm:ss, hh can be >24
|
FORMAT_TIME_INTERVAL = 46; //time [hh]:mm:ss, hh can be >24
|
||||||
|
|
||||||
|
{ XF substructures }
|
||||||
|
|
||||||
|
{ XF_TYPE_PROT - XF Type and Cell protection (3 Bits) - BIFF3-BIFF8 }
|
||||||
|
MASK_XF_TYPE_PROT_LOCKED = $1;
|
||||||
|
MASK_XF_TYPE_PROT_FORMULA_HIDDEN = $2;
|
||||||
|
MASK_XF_TYPE_PROT_STYLE_XF = $4; // 0 = CELL XF
|
||||||
|
|
||||||
|
{ XF_USED_ATTRIB - Attributes from parent Style XF (6 Bits) - BIFF3-BIFF8
|
||||||
|
|
||||||
|
- In a CELL XF a cleared bit means that the parent attribute is used,
|
||||||
|
while a set bit indicates that the data in this XF is used
|
||||||
|
- In a STYLE XF a cleared bit means that the data in this XF is used,
|
||||||
|
while a set bit indicates that the attribute should be ignored }
|
||||||
|
|
||||||
|
MASK_XF_USED_ATTRIB_NUMBER_FORMAT = $01;
|
||||||
|
MASK_XF_USED_ATTRIB_FONT = $02;
|
||||||
|
MASK_XF_USED_ATTRIB_TEXT = $04;
|
||||||
|
MASK_XF_USED_ATTRIB_BORDER_LINES = $08;
|
||||||
|
MASK_XF_USED_ATTRIB_BACKGROUND = $10;
|
||||||
|
MASK_XF_USED_ATTRIB_CELL_PROTECTION = $20;
|
||||||
|
{ the following values do not agree with the documentation !!!
|
||||||
|
MASK_XF_USED_ATTRIB_NUMBER_FORMAT = $04;
|
||||||
|
MASK_XF_USED_ATTRIB_FONT = $08;
|
||||||
|
MASK_XF_USED_ATTRIB_TEXT = $10;
|
||||||
|
MASK_XF_USED_ATTRIB_BORDER_LINES = $20;
|
||||||
|
MASK_XF_USED_ATTRIB_BACKGROUND = $40;
|
||||||
|
MASK_XF_USED_ATTRIB_CELL_PROTECTION = $80; }
|
||||||
|
|
||||||
|
{ XF record constants }
|
||||||
|
MASK_XF_TYPE_PROT = $0007;
|
||||||
|
MASK_XF_TYPE_PROT_PARENT = $FFF0;
|
||||||
|
|
||||||
|
MASK_XF_HOR_ALIGN = $07;
|
||||||
|
MASK_XF_VERT_ALIGN = $70;
|
||||||
|
MASK_XF_TEXTWRAP = $08;
|
||||||
|
|
||||||
|
{ XF HORIZONTAL ALIGN }
|
||||||
|
MASK_XF_HOR_ALIGN_LEFT = $01;
|
||||||
|
MASK_XF_HOR_ALIGN_CENTER = $02;
|
||||||
|
MASK_XF_HOR_ALIGN_RIGHT = $03;
|
||||||
|
MASK_XF_HOR_ALIGN_FILLED = $04;
|
||||||
|
MASK_XF_HOR_ALIGN_JUSTIFIED = $05; // BIFF4-BIFF8
|
||||||
|
MASK_XF_HOR_ALIGN_CENTERED_SELECTION = $06; // BIFF4-BIFF8
|
||||||
|
MASK_XF_HOR_ALIGN_DISTRIBUTED = $07; // BIFF8
|
||||||
|
|
||||||
|
{ XF_VERT_ALIGN }
|
||||||
|
MASK_XF_VERT_ALIGN_TOP = $00;
|
||||||
|
MASK_XF_VERT_ALIGN_CENTER = $10;
|
||||||
|
MASK_XF_VERT_ALIGN_BOTTOM = $20;
|
||||||
|
MASK_XF_VERT_ALIGN_JUSTIFIED = $30;
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TDateMode=(dm1900,dm1904); //DATEMODE values, 5.28
|
TDateMode=(dm1900,dm1904); //DATEMODE values, 5.28
|
||||||
@ -280,25 +297,41 @@ type
|
|||||||
(const ADateTime: TDateTime; ADateMode: TDateMode): Double;
|
(const ADateTime: TDateTime; ADateMode: TDateMode): Double;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
{ Contents of the XF record to be stored in the XFList of the reader }
|
||||||
|
TXFListData = class
|
||||||
|
public
|
||||||
|
FontIndex: Integer;
|
||||||
|
FormatIndex: Integer;
|
||||||
|
HorAlignment: TsHorAlignment;
|
||||||
|
VertAlignment: TsVertAlignment;
|
||||||
|
WordWrap: Boolean;
|
||||||
|
Borders: TsCellBorders;
|
||||||
|
BackgroundColor: TsColor;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TsSpreadBIFFReader }
|
{ TsSpreadBIFFReader }
|
||||||
TsSpreadBIFFReader = class(TsCustomSpreadReader)
|
TsSpreadBIFFReader = class(TsCustomSpreadReader)
|
||||||
protected
|
protected
|
||||||
FCodepage: string; // in a format prepared for lconvencoding.ConvertEncoding
|
FCodepage: string; // in a format prepared for lconvencoding.ConvertEncoding
|
||||||
FDateMode: TDateMode;
|
FDateMode: TDateMode;
|
||||||
FPaletteFound: Boolean;
|
FPaletteFound: Boolean;
|
||||||
// converts an Excel color index to a color value.
|
FXFList: TFPList;
|
||||||
// function ExcelPaletteToFPSColor(AIndex: Word): TsColor;
|
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Integer); virtual;
|
||||||
// Here we can add reading of records which didn't change across BIFF2-8 versions
|
// Here we can add reading of records which didn't change across BIFF5-8 versions
|
||||||
// Workbook Globals records
|
|
||||||
procedure ReadCodePage(AStream: TStream);
|
procedure ReadCodePage(AStream: TStream);
|
||||||
|
// Read column info
|
||||||
|
procedure ReadColInfo(const AStream: TStream);
|
||||||
// Figures out what the base year for dates is for this file
|
// Figures out what the base year for dates is for this file
|
||||||
procedure ReadDateMode(AStream: TStream);
|
procedure ReadDateMode(AStream: TStream);
|
||||||
// Read palette
|
// Read palette
|
||||||
procedure ReadPalette(AStream: TStream);
|
procedure ReadPalette(AStream: TStream);
|
||||||
|
// Read the row, column, and XF index at the current stream position
|
||||||
|
procedure ReadRowColXF(AStream: TStream; out ARow, ACol, AXF: Word);
|
||||||
// Read row info
|
// Read row info
|
||||||
procedure ReadRowInfo(AStream: TStream); virtual;
|
procedure ReadRowInfo(AStream: TStream); virtual;
|
||||||
public
|
public
|
||||||
constructor Create(AWorkbook: TsWorkbook); override;
|
constructor Create(AWorkbook: TsWorkbook); override;
|
||||||
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TsSpreadBIFFWriter }
|
{ TsSpreadBIFFWriter }
|
||||||
@ -308,16 +341,17 @@ type
|
|||||||
FDateMode: TDateMode;
|
FDateMode: TDateMode;
|
||||||
FLastRow: Integer;
|
FLastRow: Integer;
|
||||||
FLastCol: Word;
|
FLastCol: Word;
|
||||||
// function FPSColorToExcelPalette(AColor: TsColor): Word;
|
|
||||||
procedure GetLastRowCallback(ACell: PCell; AStream: TStream);
|
procedure GetLastRowCallback(ACell: PCell; AStream: TStream);
|
||||||
function GetLastRowIndex(AWorksheet: TsWorksheet): Integer;
|
function GetLastRowIndex(AWorksheet: TsWorksheet): Integer;
|
||||||
procedure GetLastColCallback(ACell: PCell; AStream: TStream);
|
procedure GetLastColCallback(ACell: PCell; AStream: TStream);
|
||||||
function GetLastColIndex(AWorksheet: TsWorksheet): Word;
|
function GetLastColIndex(AWorksheet: TsWorksheet): Word;
|
||||||
function FormulaElementKindToExcelTokenID(AElementKind: TFEKind; out ASecondaryID: Word): Word;
|
function FormulaElementKindToExcelTokenID(AElementKind: TFEKind; out ASecondaryID: Word): Word;
|
||||||
// Other records which didn't change
|
|
||||||
// Workbook Globals records
|
|
||||||
// Write out used codepage for character encoding
|
// Write out used codepage for character encoding
|
||||||
procedure WriteCodepage(AStream: TStream; AEncoding: TsEncoding);
|
procedure WriteCodepage(AStream: TStream; AEncoding: TsEncoding);
|
||||||
|
// Writes out column info(s)
|
||||||
|
procedure WriteColInfo(AStream: TStream; ACol: PCol);
|
||||||
|
procedure WriteColInfos(AStream: TStream; ASheet: TsWorksheet);
|
||||||
// Writes out DATEMODE record depending on FDateMode
|
// Writes out DATEMODE record depending on FDateMode
|
||||||
procedure WriteDateMode(AStream: TStream);
|
procedure WriteDateMode(AStream: TStream);
|
||||||
// Writes out a PALETTE record containing all colors defined in the workbook
|
// Writes out a PALETTE record containing all colors defined in the workbook
|
||||||
@ -387,40 +421,70 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TsSpreadBIFFReader }
|
{ TsSpreadBIFFReader }
|
||||||
|
|
||||||
constructor TsSpreadBIFFReader.Create(AWorkbook: TsWorkbook);
|
constructor TsSpreadBIFFReader.Create(AWorkbook: TsWorkbook);
|
||||||
begin
|
begin
|
||||||
inherited Create(AWorkbook);
|
inherited Create(AWorkbook);
|
||||||
|
FXFList := TFPList.Create;
|
||||||
// Initial base date in case it won't be read from file
|
// Initial base date in case it won't be read from file
|
||||||
FDateMode := dm1900;
|
FDateMode := dm1900;
|
||||||
end;
|
end;
|
||||||
(*
|
|
||||||
function TsSpreadBIFFReader.ExcelPaletteToFPSColor(AIndex: Word): TsColor;
|
destructor TsSpreadBIFFReader.Destroy;
|
||||||
|
var
|
||||||
|
j: integer;
|
||||||
begin
|
begin
|
||||||
case AIndex of
|
for j := FXFList.Count-1 downto 0 do TObject(FXFList[j]).Free;
|
||||||
BUILT_IN_COLOR_PALLETE_BLACK : Result := scBlack;
|
FXFList.Free;
|
||||||
BUILT_IN_COLOR_PALLETE_WHITE: Result := scWhite;
|
inherited Destroy;
|
||||||
BUILT_IN_COLOR_PALLETE_RED: Result := scRed;
|
end;
|
||||||
BUILT_IN_COLOR_PALLETE_GREEN: Result := scGreen;
|
|
||||||
BUILT_IN_COLOR_PALLETE_BLUE: Result := scBlue;
|
{ Applies the XF formatting given by the given index to the specified cell }
|
||||||
BUILT_IN_COLOR_PALLETE_YELLOW: Result := scYellow;
|
procedure TsSpreadBIFFReader.ApplyCellFormatting(ARow, ACol: Cardinal;
|
||||||
BUILT_IN_COLOR_PALLETE_MAGENTA: Result := scMagenta;
|
XFIndex: Integer);
|
||||||
BUILT_IN_COLOR_PALLETE_CYAN: Result := scCyan;
|
var
|
||||||
BUILT_IN_COLOR_PALLETE_DARK_RED: Result := scDarkRed;
|
lCell: PCell;
|
||||||
BUILT_IN_COLOR_PALLETE_DARK_GREEN: Result := scDarkGreen;
|
XFData: TXFListData;
|
||||||
BUILT_IN_COLOR_PALLETE_DARK_BLUE: Result := scDarkBlue;
|
begin
|
||||||
BUILT_IN_COLOR_PALLETE_OLIVE: Result := scOlive;
|
lCell := FWorksheet.GetCell(ARow, ACol);
|
||||||
BUILT_IN_COLOR_PALLETE_PURPLE: Result := scPurple;
|
if Assigned(lCell) then begin
|
||||||
BUILT_IN_COLOR_PALLETE_TEAL: Result := scTeal;
|
XFData := TXFListData(FXFList.Items[XFIndex]);
|
||||||
BUILT_IN_COLOR_PALLETE_SILVER: Result := scSilver;
|
|
||||||
BUILT_IN_COLOR_PALLETE_GREY: Result := scGrey;
|
// Font
|
||||||
//
|
if XFData.FontIndex = 1 then
|
||||||
EXTRA_COLOR_PALETTE_GREY10PCT: Result := scGrey10pct;
|
Include(lCell^.UsedFormattingFields, uffBold)
|
||||||
EXTRA_COLOR_PALETTE_GREY20PCT: Result := scGrey20pct;
|
else
|
||||||
|
if XFData.FontIndex > 1 then
|
||||||
|
Include(lCell^.UsedFormattingFields, uffFont);
|
||||||
|
lCell^.FontIndex := XFData.FontIndex;
|
||||||
|
|
||||||
|
// Alignment
|
||||||
|
lCell^.HorAlignment := XFData.HorAlignment;
|
||||||
|
lCell^.VertAlignment := XFData.VertAlignment;
|
||||||
|
|
||||||
|
// Word wrap
|
||||||
|
if XFData.WordWrap then
|
||||||
|
Include(lCell^.UsedFormattingFields, uffWordWrap)
|
||||||
|
else
|
||||||
|
Exclude(lCell^.UsedFormattingFields, uffWordWrap);
|
||||||
|
|
||||||
|
// Borders
|
||||||
|
if XFData.Borders <> [] then begin
|
||||||
|
Include(lCell^.UsedFormattingFields, uffBorder);
|
||||||
|
lCell^.Border := XFData.Borders;
|
||||||
|
end else
|
||||||
|
Exclude(lCell^.UsedFormattingFields, uffBorder);
|
||||||
|
|
||||||
|
// Background color
|
||||||
|
if XFData.BackgroundColor <> 0 then begin
|
||||||
|
Include(lCell^.UsedFormattingFields, uffBackgroundColor);
|
||||||
|
lCell^.BackgroundColor := XFData.BackgroundColor;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
*)
|
|
||||||
// In BIFF 8 it seams to always use the UTF-16 codepage
|
// In BIFF 8 it seams to always use the UTF-16 codepage
|
||||||
procedure TsSpreadBIFFReader.ReadCodePage(AStream: TStream);
|
procedure TsSpreadBIFFReader.ReadCodePage(AStream: TStream);
|
||||||
var
|
var
|
||||||
@ -476,6 +540,24 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadBiffReader.ReadColInfo(const AStream: TStream);
|
||||||
|
var
|
||||||
|
c, c1, c2: Cardinal;
|
||||||
|
w: Word;
|
||||||
|
col: TCol;
|
||||||
|
begin
|
||||||
|
// read column start and end index of column range
|
||||||
|
c1 := WordLEToN(AStream.ReadWord);
|
||||||
|
c2 := WordLEToN(AStream.ReadWord);
|
||||||
|
// read col width in 1/256 of the width of "0" character
|
||||||
|
w := WordLEToN(AStream.ReadWord);
|
||||||
|
// calculate width in units of "characters"
|
||||||
|
col.Width := w / 256;
|
||||||
|
// assign width to columns
|
||||||
|
for c := c1 to c2 do
|
||||||
|
FWorksheet.WriteColInfo(c, col);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBIFFReader.ReadDateMode(AStream: TStream);
|
procedure TsSpreadBIFFReader.ReadDateMode(AStream: TStream);
|
||||||
var
|
var
|
||||||
lBaseMode: Word;
|
lBaseMode: Word;
|
||||||
@ -514,6 +596,18 @@ begin
|
|||||||
FPaletteFound := true;
|
FPaletteFound := true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Read the row, column and xf index
|
||||||
|
procedure TsSpreadBIFFReader.ReadRowColXF(AStream: TStream; out ARow,
|
||||||
|
ACol, AXF: WORD);
|
||||||
|
begin
|
||||||
|
{ BIFF Record data for row and column}
|
||||||
|
ARow := WordLEToN(AStream.ReadWord);
|
||||||
|
ACol := WordLEToN(AStream.ReadWord);
|
||||||
|
|
||||||
|
{ Index to XF record }
|
||||||
|
AXF := WordLEtoN(AStream.ReadWord);
|
||||||
|
end;
|
||||||
|
|
||||||
// Read the part of the ROW record that is common to all BIFF versions
|
// Read the part of the ROW record that is common to all BIFF versions
|
||||||
procedure TsSpreadBIFFReader.ReadRowInfo(AStream: TStream);
|
procedure TsSpreadBIFFReader.ReadRowInfo(AStream: TStream);
|
||||||
type
|
type
|
||||||
@ -768,6 +862,37 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(lCodepage));
|
AStream.WriteWord(WordToLE(lCodepage));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadBIFFWriter.WriteColInfo(AStream: TStream; ACol: PCol);
|
||||||
|
var
|
||||||
|
w: Integer;
|
||||||
|
begin
|
||||||
|
if Assigned(ACol) then begin
|
||||||
|
{ BIFF Record header }
|
||||||
|
AStream.WriteWord(WordToLE(INT_EXCEL_ID_COLINFO)); // BIFF record header
|
||||||
|
AStream.WriteWord(WordToLE(12)); // Record size
|
||||||
|
AStream.WriteWord(WordToLE(ACol^.Col)); // start column
|
||||||
|
AStream.WriteWord(WordToLE(ACol^.Col)); // end column
|
||||||
|
{ calculate width to be in units of 1/256 of pixel width of character "0" }
|
||||||
|
w := round(ACol^.Width * 256);
|
||||||
|
AStream.WriteWord(WordToLE(w)); // write width
|
||||||
|
AStream.WriteWord(15); // XF record, ignored
|
||||||
|
AStream.WriteWord(0); // option flags, ignored
|
||||||
|
AStream.WriteWord(0); // "not used"
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadBIFFWriter.WriteColInfos(AStream: TStream;
|
||||||
|
ASheet: TsWorksheet);
|
||||||
|
var
|
||||||
|
j: Integer;
|
||||||
|
col: PCol;
|
||||||
|
begin
|
||||||
|
for j := 0 to ASheet.Cols.Count-1 do begin
|
||||||
|
col := PCol(ASheet.Cols[j]);
|
||||||
|
WriteColInfo(AStream, col);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBIFFWriter.WriteDateMode(AStream: TStream);
|
procedure TsSpreadBIFFWriter.WriteDateMode(AStream: TStream);
|
||||||
begin
|
begin
|
||||||
{ BIFF Record header }
|
{ BIFF Record header }
|
||||||
|
Reference in New Issue
Block a user