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:
|
||||
| A
|
||||
| B
|
||||
\|/ C
|
||||
v C
|
||||
|
||||
And 90 degree counter clockwise will be:
|
||||
|
||||
/|\ C
|
||||
^ C
|
||||
| B
|
||||
| A
|
||||
}
|
||||
|
||||
TsTextRotation = (trHorizontal, rt90DegreeClockwiseRotation,
|
||||
rt90DegreeCounterClockwiseRotation);
|
||||
rt90DegreeCounterClockwiseRotation, rtStacked);
|
||||
|
||||
{@@ Indicates the border for a cell }
|
||||
|
||||
|
@ -31,6 +31,18 @@ type
|
||||
{ BIFF2 file format tests }
|
||||
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 }
|
||||
// Background colors...
|
||||
procedure TestWriteReadBIFF8_Background_InternalPal; // internal palette
|
||||
@ -250,6 +262,47 @@ begin
|
||||
TestWriteReadFontColors(sfExcel2, 0);
|
||||
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 }
|
||||
procedure TSpreadWriteReadColorTests.TestWriteReadBIFF8_Background_InternalPal;
|
||||
begin
|
||||
|
@ -43,6 +43,12 @@ type
|
||||
procedure TestWriteReadFontBIFF2_TimesNewRoman;
|
||||
procedure TestWriteReadFontBIFF2_CourierNew;
|
||||
|
||||
// BIFF5 test cases
|
||||
procedure TestWriteReadBoldBIFF5;
|
||||
procedure TestWriteReadFontBIFF5_Arial;
|
||||
procedure TestWriteReadFontBIFF5_TimesNewRoman;
|
||||
procedure TestWriteReadFontBIFF5_CourierNew;
|
||||
|
||||
// BIFF8 test cases
|
||||
procedure TestWriteReadBoldBIFF8;
|
||||
procedure TestWriteReadFontBIFF8_Arial;
|
||||
@ -189,6 +195,11 @@ begin
|
||||
TestWriteReadBold(sfExcel2);
|
||||
end;
|
||||
|
||||
procedure TSpreadWriteReadFontTests.TestWriteReadBoldBIFF5;
|
||||
begin
|
||||
TestWriteReadBold(sfExcel5);
|
||||
end;
|
||||
|
||||
procedure TSpreadWriteReadFontTests.TestWriteReadBoldBIFF8;
|
||||
begin
|
||||
TestWriteReadBold(sfExcel8);
|
||||
@ -270,6 +281,7 @@ begin
|
||||
DeleteFile(TempFile);
|
||||
end;
|
||||
|
||||
{ BIFF2 }
|
||||
procedure TSpreadWriteReadFontTests.TestWriteReadFontBIFF2_Arial;
|
||||
begin
|
||||
TestWriteReadFont(sfExcel2, 'Arial');
|
||||
@ -285,6 +297,23 @@ begin
|
||||
TestWriteReadFont(sfExcel2, 'CourierNew');
|
||||
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;
|
||||
begin
|
||||
TestWriteReadFont(sfExcel8, 'Arial');
|
||||
|
@ -49,6 +49,8 @@ type
|
||||
procedure TestWriteReadBorder(AFormat: TsSpreadsheetFormat);
|
||||
// Test column widths
|
||||
procedure TestWriteReadColWidths(AFormat: TsSpreadsheetFormat);
|
||||
// Test word wrapping
|
||||
procedure TestWriteReadWordWrap(AFormat: TsSpreadsheetFormat);
|
||||
|
||||
published
|
||||
// Writes out numbers & reads back.
|
||||
@ -56,18 +58,23 @@ type
|
||||
|
||||
{ BIFF2 Tests }
|
||||
procedure TestWriteReadBIFF2_Alignment;
|
||||
procedure TestWriteReadBIFF2_ColWidths;
|
||||
procedure TestWriteReadBIFF2_Border;
|
||||
procedure TestWriteReadBIFF2_ColWidths;
|
||||
|
||||
{ BIFF5 Tests }
|
||||
procedure TestWriteReadBIFF5_Alignment;
|
||||
procedure TestWriteReadBIFF5_Border;
|
||||
procedure TestWriteReadBIFF5_ColWidths;
|
||||
procedure TestWriteReadBIFF5_WordWrap;
|
||||
|
||||
{ BIFF8 Tests }
|
||||
procedure TestWriteReadBIFF8_Alignment;
|
||||
procedure TestWriteReadBIFF8_ColWidths;
|
||||
procedure TestWriteReadBIFF8_Border;
|
||||
procedure TestWriteReadBIFF8_ColWidths;
|
||||
procedure TestWriteReadBIFF8_WordWrap;
|
||||
procedure TestWriteReadNumberFormats;
|
||||
// Repeat with date/times
|
||||
procedure TestWriteReadDateTimeFormats;
|
||||
// Test word wrapping
|
||||
procedure TestWriteReadWordWrap;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -81,6 +88,7 @@ const
|
||||
ColWidthSheet = 'ColWidths';
|
||||
BordersSheet = 'CellBorders';
|
||||
AlignmentSheet = 'TextAlignments';
|
||||
WordwrapSheet = 'Wordwrap';
|
||||
|
||||
// Initialize array with variables that represent the values
|
||||
// we expect to be in the test spreadsheet files.
|
||||
@ -364,6 +372,11 @@ begin
|
||||
TestWriteReadAlignment(sfExcel2);
|
||||
end;
|
||||
|
||||
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF5_Alignment;
|
||||
begin
|
||||
TestWriteReadAlignment(sfExcel5);
|
||||
end;
|
||||
|
||||
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF8_Alignment;
|
||||
begin
|
||||
TestWriteReadAlignment(sfExcel8);
|
||||
@ -428,6 +441,11 @@ begin
|
||||
TestWriteReadBorder(sfExcel2);
|
||||
end;
|
||||
|
||||
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF5_Border;
|
||||
begin
|
||||
TestWriteReadBorder(sfExcel5);
|
||||
end;
|
||||
|
||||
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF8_Border;
|
||||
begin
|
||||
TestWriteReadBorder(sfExcel8);
|
||||
@ -485,12 +503,17 @@ begin
|
||||
TestWriteReadColWidths(sfExcel2);
|
||||
end;
|
||||
|
||||
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF5_ColWidths;
|
||||
begin
|
||||
TestWriteReadColWidths(sfExcel5);
|
||||
end;
|
||||
|
||||
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF8_ColWidths;
|
||||
begin
|
||||
TestWriteReadColWidths(sfExcel8);
|
||||
end;
|
||||
|
||||
procedure TSpreadWriteReadFormatTests.TestWriteReadWordWrap;
|
||||
procedure TSpreadWriteReadFormatTests.TestWriteReadWordWrap(AFormat: TsSpreadsheetFormat);
|
||||
const
|
||||
LONGTEXT = 'This is a very, very, very, very long text.';
|
||||
var
|
||||
@ -507,7 +530,7 @@ begin
|
||||
// Write out all test values:
|
||||
// Cell A1 is word-wrapped, Cell B1 is NOT word-wrapped
|
||||
MyWorkbook := TsWorkbook.Create;
|
||||
MyWorkSheet:= MyWorkBook.AddWorksheet(FmtNumbersSheet);
|
||||
MyWorkSheet:= MyWorkBook.AddWorksheet(WordwrapSheet);
|
||||
MyWorksheet.WriteUTF8Text(0, 0, LONGTEXT);
|
||||
MyWorksheet.WriteUsedFormatting(0, 0, [uffWordwrap]);
|
||||
MyCell := MyWorksheet.FindCell(0, 0);
|
||||
@ -520,13 +543,16 @@ begin
|
||||
if MyCell = nil then
|
||||
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));
|
||||
MyWorkBook.WriteToFile(TempFile,sfExcel8,true);
|
||||
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
||||
MyWorkbook.Free;
|
||||
|
||||
// Open the spreadsheet, as biff8
|
||||
MyWorkbook := TsWorkbook.Create;
|
||||
MyWorkbook.ReadFromFile(TempFile, sfExcel8);
|
||||
MyWorksheet:=GetWorksheetByName(MyWorkBook, FmtNumbersSheet);
|
||||
MyWorkbook.ReadFromFile(TempFile, AFormat);
|
||||
if AFormat = sfExcel2 then
|
||||
MyWorksheet := MyWorkbook.GetFirstWorksheet
|
||||
else
|
||||
MyWorksheet := GetWorksheetByName(MyWorkBook, WordwrapSheet);
|
||||
if MyWorksheet=nil then
|
||||
fail('Error in test code. Failed to get named worksheet');
|
||||
MyCell := MyWorksheet.FindCell(0, 0);
|
||||
@ -542,6 +568,16 @@ begin
|
||||
DeleteFile(TempFile);
|
||||
end;
|
||||
|
||||
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF5_Wordwrap;
|
||||
begin
|
||||
TestWriteReadWordwrap(sfExcel5);
|
||||
end;
|
||||
|
||||
procedure TSpreadWriteReadFormatTests.TestWriteReadBIFF8_Wordwrap;
|
||||
begin
|
||||
TestWriteReadWordwrap(sfExcel8);
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterTest(TSpreadWriteReadFormatTests);
|
||||
InitSollFmtData;
|
||||
|
@ -78,15 +78,14 @@ type
|
||||
TsSpreadBIFF5Reader = class(TsSpreadBIFFReader)
|
||||
private
|
||||
RecordSize: Word;
|
||||
FWorksheet: TsWorksheet;
|
||||
FWorksheetNames: TStringList;
|
||||
FCurrentWorksheet: Integer;
|
||||
protected
|
||||
{ Helpers }
|
||||
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Integer);
|
||||
function DecodeRKValue(const ARK: DWORD): Double;
|
||||
{ Record writing methods }
|
||||
procedure ReadBlank(AStream: TStream); override;
|
||||
procedure ReadFont(const AStream: TStream);
|
||||
procedure ReadFormula(AStream: TStream); override;
|
||||
procedure ReadFormulaExcel(AStream: TStream);
|
||||
procedure ReadLabel(AStream: TStream); override;
|
||||
@ -97,7 +96,7 @@ type
|
||||
procedure ReadBoundsheet(AStream: TStream);
|
||||
procedure ReadRichString(AStream: TStream);
|
||||
procedure ReadRKValue(AStream: TStream);
|
||||
procedure ReadRowColXF(const AStream: TStream; out ARow,ACol,AXF: WORD); virtual;
|
||||
procedure ReadXF(AStream: TStream);
|
||||
public
|
||||
{ General reading methods }
|
||||
procedure ReadFromFile(AFileName: string; AData: TsWorkbook); override;
|
||||
@ -110,28 +109,36 @@ type
|
||||
private
|
||||
WorkBookEncoding: TsEncoding;
|
||||
protected
|
||||
procedure AddDefaultFormats; override;
|
||||
{ Record writing methods }
|
||||
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal;
|
||||
ACell: PCell); override;
|
||||
procedure WriteBOF(AStream: TStream; ADataType: Word);
|
||||
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;
|
||||
const AValue: TDateTime; ACell: PCell); override;
|
||||
procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
|
||||
procedure WriteEOF(AStream: TStream);
|
||||
procedure WriteFont(AStream: TStream; AFont: TFPCustomFont);
|
||||
procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal;
|
||||
const AFormula: TsRPNFormula; ACell: PCell); override;
|
||||
procedure WriteFont(AStream: TStream; AFont: TsFont);
|
||||
procedure WriteFonts(AStream: TStream);
|
||||
procedure WriteIndex(AStream: TStream);
|
||||
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal;
|
||||
const AValue: string; ACell: PCell); override;
|
||||
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
|
||||
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 WriteWindow1(AStream: TStream);
|
||||
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
|
||||
{ General writing methods }
|
||||
procedure WriteToFile(const AFileName: string;
|
||||
@ -307,43 +314,40 @@ const
|
||||
|
||||
{ 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 substructures --- see xlscommon! }
|
||||
XF_ROTATION_HORIZONTAL = 0;
|
||||
XF_ROTATION_STACKED = 1;
|
||||
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,
|
||||
while a set bit indicates that the data in this XF is used
|
||||
{ XF CELL BACKGROUND }
|
||||
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 }
|
||||
|
||||
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 ()
|
||||
*
|
||||
@ -392,11 +396,10 @@ end;
|
||||
*******************************************************************}
|
||||
procedure TsSpreadBIFF5Writer.WriteToStream(AStream: TStream);
|
||||
var
|
||||
FontData: TFPCustomFont;
|
||||
MyData: TMemoryStream;
|
||||
CurrentPos: Int64;
|
||||
Boundsheets: array of Int64;
|
||||
i, len: Integer;
|
||||
sheet : TsWorksheet;
|
||||
begin
|
||||
{ Store some data about the workbook that other routines need }
|
||||
WorkBookEncoding := Workbook.Encoding;
|
||||
@ -404,60 +407,12 @@ begin
|
||||
{ Write workbook globals }
|
||||
|
||||
WriteBOF(AStream, INT_BOF_WORKBOOK_GLOBALS);
|
||||
|
||||
WriteCodepage(AStream, WorkBookEncoding);
|
||||
WriteWindow1(AStream);
|
||||
|
||||
FontData := TFPCustomFont.Create;
|
||||
try
|
||||
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);
|
||||
|
||||
WriteFonts(AStream);
|
||||
WritePalette(AStream);
|
||||
WriteXFRecords(AStream);
|
||||
WriteStyle(AStream);
|
||||
|
||||
// A BOUNDSHEET for each worksheet
|
||||
@ -474,6 +429,8 @@ begin
|
||||
|
||||
for i := 0 to Workbook.GetWorksheetCount - 1 do
|
||||
begin
|
||||
sheet := Workbook.GetWorksheetByIndex(i);
|
||||
|
||||
{ First goes back and writes the position of the BOF of the
|
||||
sheet on the respective BOUNDSHEET record }
|
||||
CurrentPos := AStream.Position;
|
||||
@ -482,13 +439,11 @@ begin
|
||||
AStream.Position := CurrentPos;
|
||||
|
||||
WriteBOF(AStream, INT_BOF_SHEET);
|
||||
|
||||
WriteIndex(AStream);
|
||||
WriteDimensions(AStream, Workbook.GetWorksheetByIndex(i));
|
||||
WriteColInfos(AStream, sheet);
|
||||
WriteDimensions(AStream, sheet);
|
||||
WriteWindow2(AStream, True);
|
||||
|
||||
WriteCellsToStream(AStream, Workbook.GetWorksheetByIndex(i).Cells);
|
||||
|
||||
WriteCellsToStream(AStream, sheet.Cells);
|
||||
WriteEOF(AStream);
|
||||
end;
|
||||
|
||||
@ -515,7 +470,7 @@ begin
|
||||
AStream.WriteWord(WordToLE(ACol));
|
||||
|
||||
{ Index to XF record }
|
||||
AStream.WriteWord(WordToLE(15));
|
||||
WriteXFIndex(AStream, ACell);
|
||||
end;
|
||||
|
||||
{*******************************************************************
|
||||
@ -647,32 +602,52 @@ end;
|
||||
* 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
|
||||
Len: Byte;
|
||||
optn: Word;
|
||||
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 }
|
||||
AStream.WriteWord(WordToLE(INT_EXCEL_ID_FONT));
|
||||
AStream.WriteWord(WordToLE(14 + 1 + Len));
|
||||
|
||||
{ Height of the font in twips = 1/20 of a point }
|
||||
AStream.WriteWord(WordToLE(200));
|
||||
AStream.WriteWord(WordToLE(round(AFont.Size*20)));
|
||||
|
||||
{ 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 }
|
||||
AStream.WriteWord($7FFF);
|
||||
AStream.WriteWord(WordToLE(ord(AFont.Color)));
|
||||
|
||||
{ Font weight }
|
||||
if fssBold in AFont.Style then
|
||||
AStream.WriteWord(WordToLE(INT_FONT_WEIGHT_BOLD))
|
||||
else
|
||||
AStream.WriteWord(WordToLE(INT_FONT_WEIGHT_NORMAL));
|
||||
|
||||
{ Escapement type }
|
||||
AStream.WriteWord(0);
|
||||
|
||||
{ Underline type }
|
||||
if fssUnderline in AFont.Style then
|
||||
AStream.WriteByte(1)
|
||||
else
|
||||
AStream.WriteByte(0);
|
||||
|
||||
{ Font family }
|
||||
@ -686,11 +661,26 @@ begin
|
||||
|
||||
{ Font name: Byte string, 8-bit length }
|
||||
AStream.WriteByte(Len);
|
||||
AStream.WriteBuffer(AFont.Name[1], Len);
|
||||
AStream.WriteBuffer(AFont.FontName[1], Len);
|
||||
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
|
||||
*
|
||||
@ -725,7 +715,7 @@ begin
|
||||
AStream.WriteWord(WordToLE(ACol));
|
||||
|
||||
{ Index to XF Record }
|
||||
AStream.WriteWord($0000);
|
||||
WriteXFIndex(AStream, ACell);
|
||||
|
||||
{ Result of the formula in IEEE 754 floating-point value }
|
||||
AStream.WriteBuffer(FormulaResult, 8);
|
||||
@ -939,7 +929,7 @@ begin
|
||||
AStream.WriteWord(WordToLE(ACol));
|
||||
|
||||
{ Index to XF record }
|
||||
AStream.WriteWord(WordToLE(15));
|
||||
WriteXFIndex(AStream, ACell);
|
||||
|
||||
{ Byte String with 16-bit size }
|
||||
AStream.WriteWord(WordToLE(L));
|
||||
@ -974,7 +964,7 @@ begin
|
||||
AStream.WriteWord(WordToLE(ACol));
|
||||
|
||||
{ Index to XF record }
|
||||
AStream.WriteWord($0);
|
||||
WriteXFIndex(AStream, ACell);
|
||||
|
||||
{ IEE 754 floating-point value }
|
||||
AStream.WriteBuffer(AValue, 8);
|
||||
@ -1120,14 +1110,23 @@ end;
|
||||
*
|
||||
* DESCRIPTION: Writes an Excel 5 XF record
|
||||
*
|
||||
* Writes a number (64-bit floating point) to the sheet
|
||||
*
|
||||
*******************************************************************}
|
||||
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
|
||||
optns: Word;
|
||||
b: Byte;
|
||||
dw1, dw2: DWord;
|
||||
XFOptions: Word;
|
||||
XFAlignment, XFOrientationAttrib: Byte;
|
||||
XFAlignment: byte;
|
||||
XFBorderDWord1, XFBorderDWord2: DWord;
|
||||
begin
|
||||
{ BIFF Record header }
|
||||
AStream.WriteWord(WordToLE(INT_EXCEL_ID_XF));
|
||||
@ -1137,43 +1136,263 @@ begin
|
||||
AStream.WriteWord(WordToLE(AFontIndex));
|
||||
|
||||
{ Index to FORMAT record }
|
||||
AStream.WriteWord($00);
|
||||
AStream.WriteWord(WordToLE(AFormatIndex));
|
||||
|
||||
{ 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
|
||||
XFOptions := XFOptions or MASK_XF_TYPE_PROT_PARENT;
|
||||
|
||||
AStream.WriteWord(WordToLE(XFOptions));
|
||||
optns := optns or MASK_XF_TYPE_PROT_PARENT;
|
||||
AStream.WriteWord(WordToLE(optns));
|
||||
|
||||
{ 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 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));
|
||||
{ Text rotation }
|
||||
AStream.WriteByte(ATextRotation); // 0 is horizontal / normal
|
||||
|
||||
{ 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;
|
||||
|
||||
{*******************************************************************
|
||||
* Initialization section
|
||||
*
|
||||
* Registers this reader / writer on fpSpreadsheet
|
||||
*
|
||||
*******************************************************************}
|
||||
|
||||
{ TsSpreadBIFF5Reader }
|
||||
|
||||
@ -1184,6 +1403,9 @@ var
|
||||
RecordType: Word;
|
||||
CurStreamPos: Int64;
|
||||
begin
|
||||
// Clear existing fonts. They will be replaced by those from the file.
|
||||
FWorkbook.RemoveAllFonts;
|
||||
|
||||
while (not SectionEOF) do
|
||||
begin
|
||||
{ Read the record header }
|
||||
@ -1195,6 +1417,9 @@ begin
|
||||
case RecordType of
|
||||
INT_EXCEL_ID_BOF : ;
|
||||
INT_EXCEL_ID_BOUNDSHEET : ReadBoundSheet(AStream);
|
||||
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
|
||||
// nothing
|
||||
@ -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_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_COLINFO: ReadColInfo(AStream);
|
||||
INT_EXCEL_ID_ROWINFO: ReadRowInfo(AStream);
|
||||
INT_EXCEL_ID_FORMULA: ReadFormulaExcel(AStream);
|
||||
INT_EXCEL_ID_BOF: ;
|
||||
@ -1437,17 +1663,6 @@ begin
|
||||
Result:=Number;
|
||||
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);
|
||||
var
|
||||
MemStream: TMemoryStream;
|
||||
@ -1476,6 +1691,71 @@ begin
|
||||
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);
|
||||
var
|
||||
BIFF5EOF: Boolean;
|
||||
@ -1525,6 +1805,68 @@ begin
|
||||
ApplyCellFormatting(ARow, ACol, XF);
|
||||
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);
|
||||
begin
|
||||
|
||||
@ -1569,12 +1911,6 @@ begin
|
||||
ApplyCellFormatting(ARow, ACol, XF);
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFF5Reader.ApplyCellFormatting(ARow, ACol: Cardinal;
|
||||
XFIndex: Integer);
|
||||
begin
|
||||
// to do...
|
||||
end;
|
||||
|
||||
|
||||
initialization
|
||||
|
||||
|
@ -63,29 +63,6 @@ uses
|
||||
fpsutils, lazutf8;
|
||||
|
||||
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
|
||||
public
|
||||
Index: Integer;
|
||||
@ -101,10 +78,9 @@ type
|
||||
FWorksheetNames: TStringList;
|
||||
FCurrentWorksheet: Integer;
|
||||
FSharedStringTable: TStringList;
|
||||
FXFList: TFPList; // of TXFRecordData
|
||||
FFormatList: TFPList; // of TFormatRecordData
|
||||
function DecodeRKValue(const ARK: DWORD): Double;
|
||||
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Integer);
|
||||
// procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Integer);
|
||||
procedure ExtractNumberFormat(AXFIndex: WORD;
|
||||
out ANumberFormat: TsNumberFormat; out ADecimals: Word;
|
||||
out ANumberFormatStr: String);
|
||||
@ -119,9 +95,8 @@ type
|
||||
|
||||
procedure ReadRKValue(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;
|
||||
procedure ReadRichString(const AStream: TStream);
|
||||
procedure ReadSST(const AStream: TStream);
|
||||
procedure ReadLabelSST(const AStream: TStream);
|
||||
// Read XF record
|
||||
@ -135,13 +110,12 @@ type
|
||||
// procedure ReadCodepage in xlscommon
|
||||
// procedure ReadDateMode in xlscommon
|
||||
procedure ReadFont(const AStream: TStream);
|
||||
// Read col info
|
||||
procedure ReadColInfo(const AStream: TStream);
|
||||
{ Record reading methods }
|
||||
procedure ReadBlank(AStream: TStream); override;
|
||||
procedure ReadFormula(AStream: TStream); override;
|
||||
procedure ReadLabel(AStream: TStream); override;
|
||||
procedure ReadNumber(AStream: TStream); override;
|
||||
procedure ReadRichString(const AStream: TStream);
|
||||
public
|
||||
constructor Create(AWorkbook: TsWorkbook); override;
|
||||
destructor Destroy; override;
|
||||
@ -164,12 +138,8 @@ type
|
||||
ACell: PCell); override;
|
||||
procedure WriteBOF(AStream: TStream; ADataType: Word);
|
||||
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;
|
||||
const AValue: TDateTime; ACell: PCell); override;
|
||||
// procedure WriteDateMode in xlscommon; Workbook Globals record
|
||||
procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
|
||||
procedure WriteEOF(AStream: TStream);
|
||||
procedure WriteFont(AStream: TStream; AFont: TsFont);
|
||||
@ -279,7 +249,6 @@ const
|
||||
INT_EXCEL_ID_BLANK = $0201;
|
||||
INT_EXCEL_ID_BOF = $0809;
|
||||
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_EOF = $000A;
|
||||
INT_EXCEL_ID_DIMENSIONS = $0200;
|
||||
@ -291,7 +260,6 @@ const
|
||||
INT_EXCEL_ID_STYLE = $0293;
|
||||
INT_EXCEL_ID_WINDOW1 = $003D;
|
||||
INT_EXCEL_ID_WINDOW2 = $023E;
|
||||
INT_EXCEL_ID_XF = $00E0;
|
||||
INT_EXCEL_ID_RSTRING = $00D6;
|
||||
INT_EXCEL_ID_RK = $027E;
|
||||
INT_EXCEL_ID_MULRK = $00BD;
|
||||
@ -318,10 +286,6 @@ const
|
||||
INT_BOF_BUILD_ID = $1FD2;
|
||||
INT_BOF_BUILD_YEAR = $07CD;
|
||||
|
||||
{ FONT record constants }
|
||||
INT_FONT_WEIGHT_NORMAL = $0190;
|
||||
INT_FONT_WEIGHT_BOLD = $02BC;
|
||||
|
||||
{ FORMULA record constants }
|
||||
MASK_FORMULA_RECALCULATE_ALWAYS = $0001;
|
||||
MASK_FORMULA_RECALCULATE_ON_OPEN = $0002;
|
||||
@ -352,44 +316,11 @@ const
|
||||
|
||||
{ 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_HORIZONTAL = 0;
|
||||
XF_ROTATION_90_DEGREE_COUNTERCLOCKWISE = 90;
|
||||
XF_ROTATION_90_DEGREE_CLOCKWISE = 180;
|
||||
XF_ROTATION_90DEG_CCW = 90;
|
||||
XF_ROTATION_90DEG_CW = 180;
|
||||
XF_ROTATION_STACKED = 255; // Letters stacked top to bottom, but not rotated
|
||||
|
||||
{ XF CELL BORDER }
|
||||
MASK_XF_BORDER_LEFT = $0000000F;
|
||||
@ -397,18 +328,6 @@ const
|
||||
MASK_XF_BORDER_TOP = $00000F00;
|
||||
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 }
|
||||
|
||||
@ -425,6 +344,7 @@ begin
|
||||
Exit;
|
||||
end;
|
||||
|
||||
{
|
||||
if ACell^.UsedFormattingFields = [uffTextRotation] then
|
||||
begin
|
||||
case ACell^.TextRotation of
|
||||
@ -435,6 +355,7 @@ begin
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
}
|
||||
|
||||
{
|
||||
uffNumberFormat does not seem to have default XF indexes, but perhaps look at XF_21
|
||||
@ -553,8 +474,9 @@ begin
|
||||
begin
|
||||
case FFormattingStyles[i].TextRotation of
|
||||
trHorizontal: lTextRotation := XF_ROTATION_HORIZONTAL;
|
||||
rt90DegreeClockwiseRotation: lTextRotation := XF_ROTATION_90_DEGREE_CLOCKWISE;
|
||||
rt90DegreeCounterClockwiseRotation: lTextRotation := XF_ROTATION_90_DEGREE_COUNTERCLOCKWISE;
|
||||
rt90DegreeClockwiseRotation: lTextRotation := XF_ROTATION_90DEG_CW;
|
||||
rt90DegreeCounterClockwiseRotation: lTextRotation := XF_ROTATION_90DEG_CCW;
|
||||
rtStacked: lTextRotation := XF_ROTATION_STACKED;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -680,17 +602,11 @@ begin
|
||||
AStream.Position := CurrentPos;
|
||||
|
||||
WriteBOF(AStream, INT_BOF_SHEET);
|
||||
|
||||
WriteIndex(AStream);
|
||||
|
||||
WriteColInfos(AStream, sheet);
|
||||
|
||||
WriteDimensions(AStream, sheet);
|
||||
|
||||
WriteWindow2(AStream, True);
|
||||
|
||||
WriteCellsToStream(AStream, sheet.Cells);
|
||||
|
||||
WriteEOF(AStream);
|
||||
end;
|
||||
|
||||
@ -800,42 +716,6 @@ begin
|
||||
AStream.WriteBuffer(WideStringToLE(WideSheetName)[1], Len * Sizeof(WideChar));
|
||||
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 ()
|
||||
*
|
||||
@ -949,7 +829,6 @@ begin
|
||||
AStream.WriteWord(WordToLE(optn));
|
||||
|
||||
{ Colour index }
|
||||
//AStream.WriteWord(WordToLE(8 + ord(AFont.Color))); //WordToLE($7FFF));
|
||||
AStream.WriteWord(WordToLE(ord(AFont.Color)));
|
||||
|
||||
{ Font weight }
|
||||
@ -1643,6 +1522,22 @@ end;
|
||||
|
||||
{ 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;
|
||||
var
|
||||
Number: Double;
|
||||
@ -1701,7 +1596,7 @@ const
|
||||
0, 0, 0, 0, 0, 0, 0, 0); // 51..58
|
||||
var
|
||||
lFormatData: TFormatRecordData;
|
||||
lXFData: TXFRecordData;
|
||||
lXFData: TXFListData;
|
||||
isAMPM: Boolean;
|
||||
isLongTime: Boolean;
|
||||
isMilliSec: Boolean;
|
||||
@ -1719,7 +1614,7 @@ begin
|
||||
|
||||
if lFormatData = nil then begin
|
||||
// no custom format, so first test for default formats
|
||||
lXFData := TXFRecordData (FXFList.Items[AXFIndex]);
|
||||
lXFData := TXFListData (FXFList.Items[AXFIndex]);
|
||||
case lXFData.FormatIndex of
|
||||
FORMAT_DATE_DM:
|
||||
begin ANumberFormat := nfFmtDateTime; ANumberFormatStr := 'DM'; end;
|
||||
@ -1861,7 +1756,7 @@ begin
|
||||
Result := DecomprStrValue;
|
||||
end;
|
||||
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
|
||||
if (PendingRecordSize<=0) then begin
|
||||
//A CONTINUE may happend here
|
||||
@ -1909,10 +1804,9 @@ var
|
||||
begin
|
||||
// Clear existing fonts. They will be replaced by those from the file.
|
||||
FWorkbook.RemoveAllFonts;
|
||||
|
||||
if Assigned(FSharedStringTable) then FreeAndNil(FSharedStringTable);
|
||||
while (not SectionEOF) do
|
||||
begin
|
||||
|
||||
while (not SectionEOF) do begin
|
||||
{ Read the record header }
|
||||
RecordType := WordLEToN(AStream.ReadWord);
|
||||
RecordSize := WordLEToN(AStream.ReadWord);
|
||||
@ -2086,86 +1980,12 @@ begin
|
||||
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;
|
||||
const ALength: WORD): UTF8String;
|
||||
begin
|
||||
Result:=UTF16ToUTF8(ReadWideString(AStream, ALength));
|
||||
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);
|
||||
var
|
||||
MemStream: TMemoryStream;
|
||||
@ -2466,13 +2286,13 @@ type
|
||||
Border_Background_3: DWord; // Offset 18, Size 2
|
||||
end;
|
||||
var
|
||||
lData: TXFRecordData;
|
||||
lData: TXFListData;
|
||||
xf: TXFRecord;
|
||||
b: Byte;
|
||||
begin
|
||||
AStream.ReadBuffer(xf, SizeOf(xf));
|
||||
|
||||
lData := TXFRecordData.Create;
|
||||
lData := TXFListData.Create;
|
||||
|
||||
// Font index
|
||||
lData.FontIndex := WordLEToN(xf.FontIndex);
|
||||
@ -2541,12 +2361,12 @@ end;
|
||||
function TsSpreadBIFF8Reader.FindFormatRecordForCell(const AXFIndex: Integer
|
||||
): TFormatRecordData;
|
||||
var
|
||||
lXFData: TXFRecordData;
|
||||
lXFData: TXFListData;
|
||||
lFormatData: TFormatRecordData;
|
||||
i: Integer;
|
||||
begin
|
||||
Result := nil;
|
||||
lXFData := TXFRecordData(FXFList.Items[AXFIndex]);
|
||||
lXFData := TXFListData(FXFList.Items[AXFIndex]);
|
||||
for i := 0 to FFormatList.Count-1 do
|
||||
begin
|
||||
lFormatData := TFormatRecordData(FFormatList.Items[i]);
|
||||
@ -2614,24 +2434,6 @@ begin
|
||||
FWorkbook.AddFont(font);
|
||||
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
|
||||
|
@ -18,8 +18,14 @@ const
|
||||
{ RECORD IDs which didn't change across versions 2-8 }
|
||||
INT_EXCEL_ID_FONT = $0031;
|
||||
INT_EXCEL_ID_CODEPAGE = $0042;
|
||||
INT_EXCEL_ID_COLINFO = $007D;
|
||||
INT_EXCEL_ID_DATEMODE = $0022;
|
||||
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 }
|
||||
|
||||
@ -183,46 +189,6 @@ const
|
||||
// 1AH tSheet Start 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 }
|
||||
WORD_ASCII = 367;
|
||||
WORD_UTF_16 = 1200; // BIFF 8
|
||||
@ -267,6 +233,57 @@ const
|
||||
FORMAT_TIME_MSZ = 47; //time MM:SS.0
|
||||
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
|
||||
TDateMode=(dm1900,dm1904); //DATEMODE values, 5.28
|
||||
@ -280,25 +297,41 @@ type
|
||||
(const ADateTime: TDateTime; ADateMode: TDateMode): Double;
|
||||
|
||||
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 = class(TsCustomSpreadReader)
|
||||
protected
|
||||
FCodepage: string; // in a format prepared for lconvencoding.ConvertEncoding
|
||||
FDateMode: TDateMode;
|
||||
FPaletteFound: Boolean;
|
||||
// converts an Excel color index to a color value.
|
||||
// function ExcelPaletteToFPSColor(AIndex: Word): TsColor;
|
||||
// Here we can add reading of records which didn't change across BIFF2-8 versions
|
||||
// Workbook Globals records
|
||||
FXFList: TFPList;
|
||||
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Integer); virtual;
|
||||
// Here we can add reading of records which didn't change across BIFF5-8 versions
|
||||
procedure ReadCodePage(AStream: TStream);
|
||||
// Read column info
|
||||
procedure ReadColInfo(const AStream: TStream);
|
||||
// Figures out what the base year for dates is for this file
|
||||
procedure ReadDateMode(AStream: TStream);
|
||||
// Read palette
|
||||
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
|
||||
procedure ReadRowInfo(AStream: TStream); virtual;
|
||||
public
|
||||
constructor Create(AWorkbook: TsWorkbook); override;
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
{ TsSpreadBIFFWriter }
|
||||
@ -308,16 +341,17 @@ type
|
||||
FDateMode: TDateMode;
|
||||
FLastRow: Integer;
|
||||
FLastCol: Word;
|
||||
// function FPSColorToExcelPalette(AColor: TsColor): Word;
|
||||
procedure GetLastRowCallback(ACell: PCell; AStream: TStream);
|
||||
function GetLastRowIndex(AWorksheet: TsWorksheet): Integer;
|
||||
procedure GetLastColCallback(ACell: PCell; AStream: TStream);
|
||||
function GetLastColIndex(AWorksheet: TsWorksheet): 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
|
||||
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
|
||||
procedure WriteDateMode(AStream: TStream);
|
||||
// Writes out a PALETTE record containing all colors defined in the workbook
|
||||
@ -387,40 +421,70 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{ TsSpreadBIFFReader }
|
||||
|
||||
constructor TsSpreadBIFFReader.Create(AWorkbook: TsWorkbook);
|
||||
begin
|
||||
inherited Create(AWorkbook);
|
||||
FXFList := TFPList.Create;
|
||||
// Initial base date in case it won't be read from file
|
||||
FDateMode := dm1900;
|
||||
end;
|
||||
(*
|
||||
function TsSpreadBIFFReader.ExcelPaletteToFPSColor(AIndex: Word): TsColor;
|
||||
|
||||
destructor TsSpreadBIFFReader.Destroy;
|
||||
var
|
||||
j: integer;
|
||||
begin
|
||||
case AIndex of
|
||||
BUILT_IN_COLOR_PALLETE_BLACK : Result := scBlack;
|
||||
BUILT_IN_COLOR_PALLETE_WHITE: Result := scWhite;
|
||||
BUILT_IN_COLOR_PALLETE_RED: Result := scRed;
|
||||
BUILT_IN_COLOR_PALLETE_GREEN: Result := scGreen;
|
||||
BUILT_IN_COLOR_PALLETE_BLUE: Result := scBlue;
|
||||
BUILT_IN_COLOR_PALLETE_YELLOW: Result := scYellow;
|
||||
BUILT_IN_COLOR_PALLETE_MAGENTA: Result := scMagenta;
|
||||
BUILT_IN_COLOR_PALLETE_CYAN: Result := scCyan;
|
||||
BUILT_IN_COLOR_PALLETE_DARK_RED: Result := scDarkRed;
|
||||
BUILT_IN_COLOR_PALLETE_DARK_GREEN: Result := scDarkGreen;
|
||||
BUILT_IN_COLOR_PALLETE_DARK_BLUE: Result := scDarkBlue;
|
||||
BUILT_IN_COLOR_PALLETE_OLIVE: Result := scOlive;
|
||||
BUILT_IN_COLOR_PALLETE_PURPLE: Result := scPurple;
|
||||
BUILT_IN_COLOR_PALLETE_TEAL: Result := scTeal;
|
||||
BUILT_IN_COLOR_PALLETE_SILVER: Result := scSilver;
|
||||
BUILT_IN_COLOR_PALLETE_GREY: Result := scGrey;
|
||||
//
|
||||
EXTRA_COLOR_PALETTE_GREY10PCT: Result := scGrey10pct;
|
||||
EXTRA_COLOR_PALETTE_GREY20PCT: Result := scGrey20pct;
|
||||
for j := FXFList.Count-1 downto 0 do TObject(FXFList[j]).Free;
|
||||
FXFList.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{ Applies the XF formatting given by the given index to the specified cell }
|
||||
procedure TsSpreadBIFFReader.ApplyCellFormatting(ARow, ACol: Cardinal;
|
||||
XFIndex: Integer);
|
||||
var
|
||||
lCell: PCell;
|
||||
XFData: TXFListData;
|
||||
begin
|
||||
lCell := FWorksheet.GetCell(ARow, ACol);
|
||||
if Assigned(lCell) then begin
|
||||
XFData := TXFListData(FXFList.Items[XFIndex]);
|
||||
|
||||
// Font
|
||||
if XFData.FontIndex = 1 then
|
||||
Include(lCell^.UsedFormattingFields, uffBold)
|
||||
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;
|
||||
|
||||
// In BIFF 8 it seams to always use the UTF-16 codepage
|
||||
procedure TsSpreadBIFFReader.ReadCodePage(AStream: TStream);
|
||||
var
|
||||
@ -476,6 +540,24 @@ begin
|
||||
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);
|
||||
var
|
||||
lBaseMode: Word;
|
||||
@ -514,6 +596,18 @@ begin
|
||||
FPaletteFound := true;
|
||||
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
|
||||
procedure TsSpreadBIFFReader.ReadRowInfo(AStream: TStream);
|
||||
type
|
||||
@ -768,6 +862,37 @@ begin
|
||||
AStream.WriteWord(WordToLE(lCodepage));
|
||||
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);
|
||||
begin
|
||||
{ BIFF Record header }
|
||||
|
Reference in New Issue
Block a user