You've already forked lazarus-ccr
fpspreadsheet: Add reading of cell/sheet/workbook protection for xls biff8.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5789 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -368,6 +368,9 @@ const
|
||||
{ XF CELL BACKGROUND PATTERN }
|
||||
MASK_XF_BACKGROUND_PATTERN = $FC000000;
|
||||
|
||||
{ XP CELL PROTECTION }
|
||||
MASK_XF_PROTECTION = $0007;
|
||||
|
||||
{ HLINK FLAGS }
|
||||
MASK_HLINK_LINK = $00000001;
|
||||
MASK_HLINK_ABSOLUTE = $00000002;
|
||||
@ -797,19 +800,22 @@ begin
|
||||
|
||||
if RecordType <> INT_EXCEL_ID_CONTINUE then begin
|
||||
case RecordType of
|
||||
INT_EXCEL_ID_BOF : ;
|
||||
INT_EXCEL_ID_BOUNDSHEET : ReadBoundSheet(AStream);
|
||||
INT_EXCEL_ID_DEFINEDNAME : ReadDEFINEDNAME(AStream);
|
||||
INT_EXCEL_ID_EOF : SectionEOF := True;
|
||||
INT_EXCEL_ID_EXTERNSHEET : ReadEXTERNSHEET(AStream);
|
||||
INT_EXCEL_ID_SST : ReadSST(AStream);
|
||||
INT_EXCEL_ID_CODEPAGE : ReadCodepage(AStream);
|
||||
INT_EXCEL_ID_FONT : ReadFont(AStream);
|
||||
INT_EXCEL_ID_FORMAT : ReadFormat(AStream);
|
||||
INT_EXCEL_ID_XF : ReadXF(AStream);
|
||||
INT_EXCEL_ID_DATEMODE : ReadDateMode(AStream);
|
||||
INT_EXCEL_ID_PALETTE : ReadPalette(AStream);
|
||||
else
|
||||
INT_EXCEL_ID_BOF : ;
|
||||
INT_EXCEL_ID_BOUNDSHEET : ReadBoundSheet(AStream);
|
||||
INT_EXCEL_ID_CODEPAGE : ReadCodepage(AStream);
|
||||
INT_EXCEL_ID_DATEMODE : ReadDateMode(AStream);
|
||||
INT_EXCEL_ID_DEFINEDNAME : ReadDEFINEDNAME(AStream);
|
||||
INT_EXCEL_ID_EOF : SectionEOF := True;
|
||||
INT_EXCEL_ID_EXTERNSHEET : ReadEXTERNSHEET(AStream);
|
||||
INT_EXCEL_ID_FONT : ReadFont(AStream);
|
||||
INT_EXCEL_ID_FORMAT : ReadFormat(AStream);
|
||||
INT_EXCEL_ID_PALETTE : ReadPalette(AStream);
|
||||
INT_EXCEL_ID_PASSWORD : ReadPASSWORD(AStream);
|
||||
INT_EXCEL_ID_PROTECT : ReadPROTECT(AStream);
|
||||
INT_EXCEL_ID_SST : ReadSST(AStream);
|
||||
INT_EXCEL_ID_WINDOWPROTECT : ReadWindowProtect(AStream);
|
||||
INT_EXCEL_ID_XF : ReadXF(AStream);
|
||||
else
|
||||
// nothing
|
||||
end;
|
||||
end;
|
||||
@ -874,6 +880,8 @@ begin
|
||||
INT_EXCEL_ID_OBJ : ReadOBJ(AStream);
|
||||
INT_EXCEL_ID_PAGESETUP : ReadPageSetup(AStream);
|
||||
INT_EXCEL_ID_PANE : ReadPane(AStream);
|
||||
INT_EXCEL_ID_PASSWORD : ReadPASSWORD(AStream, FWorksheet);
|
||||
INT_EXCEL_ID_PROTECT : ReadPROTECT(AStream, FWorksheet);
|
||||
INT_EXCEL_ID_PRINTGRID : ReadPrintGridLines(AStream);
|
||||
INT_EXCEL_ID_PRINTHEADERS : ReadPrintHeaders(AStream);
|
||||
INT_EXCEL_ID_RIGHTMARGIN : ReadMargin(AStream, 1);
|
||||
@ -1678,6 +1686,14 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// Protection
|
||||
case WordLEToN(rec.XFType_Prot_ParentXF) and MASK_XF_PROTECTION of
|
||||
0: fmt.Protection := [];
|
||||
1: fmt.Protection := [cpLockCell];
|
||||
2: fmt.Protection := [cpHideFormulas];
|
||||
3: fmt.Protection := [cpLockCell, cpHideFormulas];
|
||||
end;
|
||||
|
||||
// Add the XF to the internal cell format list
|
||||
FCellFormatList.Add(fmt);
|
||||
end;
|
||||
@ -1776,7 +1792,7 @@ begin
|
||||
|
||||
{ Height of the font in twips = 1/20 of a point }
|
||||
lHeight := WordLEToN(AStream.ReadWord);
|
||||
font.Size := lHeight/20;
|
||||
font.Size := lHeight / 20;
|
||||
|
||||
{ Option flags }
|
||||
lOptions := WordLEToN(AStream.ReadWord);
|
||||
|
@ -16,94 +16,97 @@ uses
|
||||
|
||||
const
|
||||
{ RECORD IDs which didn't change across versions 2-8 }
|
||||
INT_EXCEL_ID_EOF = $000A;
|
||||
INT_EXCEL_ID_HEADER = $0014;
|
||||
INT_EXCEL_ID_FOOTER = $0015;
|
||||
INT_EXCEL_ID_EXTERNSHEET = $0017;
|
||||
INT_EXCEL_ID_NOTE = $001C;
|
||||
INT_EXCEL_ID_SELECTION = $001D;
|
||||
INT_EXCEL_ID_DATEMODE = $0022;
|
||||
INT_EXCEL_ID_LEFTMARGIN = $0026;
|
||||
INT_EXCEL_ID_RIGHTMARGIN = $0027;
|
||||
INT_EXCEL_ID_TOPMARGIN = $0028;
|
||||
INT_EXCEL_ID_BOTTOMMARGIN= $0029;
|
||||
INT_EXCEL_ID_PRINTHEADERS= $002A;
|
||||
INT_EXCEL_ID_PRINTGRID = $002B;
|
||||
INT_EXCEL_ID_CONTINUE = $003C;
|
||||
INT_EXCEL_ID_WINDOW1 = $003D;
|
||||
INT_EXCEL_ID_PANE = $0041;
|
||||
INT_EXCEL_ID_CODEPAGE = $0042;
|
||||
INT_EXCEL_ID_DEFCOLWIDTH = $0055;
|
||||
INT_EXCEL_ID_EOF = $000A;
|
||||
INT_EXCEL_ID_PROTECT = $0012;
|
||||
INT_EXCEL_ID_PASSWORD = $0013;
|
||||
INT_EXCEL_ID_HEADER = $0014;
|
||||
INT_EXCEL_ID_FOOTER = $0015;
|
||||
INT_EXCEL_ID_EXTERNSHEET = $0017;
|
||||
INT_EXCEL_ID_WINDOWPROTECT = $0019;
|
||||
INT_EXCEL_ID_NOTE = $001C;
|
||||
INT_EXCEL_ID_SELECTION = $001D;
|
||||
INT_EXCEL_ID_DATEMODE = $0022;
|
||||
INT_EXCEL_ID_LEFTMARGIN = $0026;
|
||||
INT_EXCEL_ID_RIGHTMARGIN = $0027;
|
||||
INT_EXCEL_ID_TOPMARGIN = $0028;
|
||||
INT_EXCEL_ID_BOTTOMMARGIN = $0029;
|
||||
INT_EXCEL_ID_PRINTHEADERS = $002A;
|
||||
INT_EXCEL_ID_PRINTGRID = $002B;
|
||||
INT_EXCEL_ID_CONTINUE = $003C;
|
||||
INT_EXCEL_ID_WINDOW1 = $003D;
|
||||
INT_EXCEL_ID_PANE = $0041;
|
||||
INT_EXCEL_ID_CODEPAGE = $0042;
|
||||
INT_EXCEL_ID_DEFCOLWIDTH = $0055;
|
||||
|
||||
{ RECORD IDs which did not changed across versions 2-5 }
|
||||
INT_EXCEL_ID_EXTERNCOUNT = $0016; // does not exist in BIFF8
|
||||
INT_EXCEL_ID_EXTERNCOUNT = $0016; // does not exist in BIFF8
|
||||
|
||||
{ RECORD IDs which did not change across versions 2, 5, 8}
|
||||
INT_EXCEL_ID_FORMULA = $0006; // BIFF3: $0206, BIFF4: $0406
|
||||
INT_EXCEL_ID_DEFINEDNAME = $0018; // BIFF3-4: $0218
|
||||
INT_EXCEL_ID_FONT = $0031; // BIFF3-4: $0231
|
||||
INT_EXCEL_ID_FORMULA = $0006; // BIFF3: $0206, BIFF4: $0406
|
||||
INT_EXCEL_ID_DEFINEDNAME = $0018; // BIFF3-4: $0218
|
||||
INT_EXCEL_ID_FONT = $0031; // BIFF3-4: $0231
|
||||
|
||||
{ RECORD IDs which did not change across version 3-8}
|
||||
INT_EXCEL_ID_COLINFO = $007D; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_SHEETPR = $0081; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_HCENTER = $0083; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_VCENTER = $0084; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_COUNTRY = $008C; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_PALETTE = $0092; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_DIMENSIONS = $0200; // BIFF2: $0000
|
||||
INT_EXCEL_ID_BLANK = $0201; // BIFF2: $0001
|
||||
INT_EXCEL_ID_NUMBER = $0203; // BIFF2: $0003
|
||||
INT_EXCEL_ID_LABEL = $0204; // BIFF2: $0004
|
||||
INT_EXCEL_ID_BOOLERROR = $0205; // BIFF2: $0005
|
||||
INT_EXCEL_ID_STRING = $0207; // BIFF2: $0007
|
||||
INT_EXCEL_ID_ROW = $0208; // BIFF2: $0008
|
||||
INT_EXCEL_ID_INDEX = $020B; // BIFF2: $000B
|
||||
INT_EXCEL_ID_DEFROWHEIGHT= $0225; // BIFF2: $0025
|
||||
INT_EXCEL_ID_WINDOW2 = $023E; // BIFF2: $003E
|
||||
INT_EXCEL_ID_RK = $027E; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_STYLE = $0293; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_COLINFO = $007D; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_SHEETPR = $0081; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_HCENTER = $0083; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_VCENTER = $0084; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_COUNTRY = $008C; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_PALETTE = $0092; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_DIMENSIONS = $0200; // BIFF2: $0000
|
||||
INT_EXCEL_ID_BLANK = $0201; // BIFF2: $0001
|
||||
INT_EXCEL_ID_NUMBER = $0203; // BIFF2: $0003
|
||||
INT_EXCEL_ID_LABEL = $0204; // BIFF2: $0004
|
||||
INT_EXCEL_ID_BOOLERROR = $0205; // BIFF2: $0005
|
||||
INT_EXCEL_ID_STRING = $0207; // BIFF2: $0007
|
||||
INT_EXCEL_ID_ROW = $0208; // BIFF2: $0008
|
||||
INT_EXCEL_ID_INDEX = $020B; // BIFF2: $000B
|
||||
INT_EXCEL_ID_DEFROWHEIGHT = $0225; // BIFF2: $0025
|
||||
INT_EXCEL_ID_WINDOW2 = $023E; // BIFF2: $003E
|
||||
INT_EXCEL_ID_RK = $027E; // does not exist in BIFF2
|
||||
INT_EXCEL_ID_STYLE = $0293; // does not exist in BIFF2
|
||||
|
||||
{ RECORD IDs which did not change across version 4-8 }
|
||||
INT_EXCEL_ID_SCL = $00A0; // does not exist before BIFF4
|
||||
INT_EXCEL_ID_PAGESETUP = $00A1; // does not exist before BIFF4
|
||||
INT_EXCEL_ID_FORMAT = $041E; // BIFF2-3: $001E
|
||||
INT_EXCEL_ID_SCL = $00A0; // does not exist before BIFF4
|
||||
INT_EXCEL_ID_PAGESETUP = $00A1; // does not exist before BIFF4
|
||||
INT_EXCEL_ID_FORMAT = $041E; // BIFF2-3: $001E
|
||||
|
||||
{ RECORD IDs which did not change across versions 5-8 }
|
||||
INT_EXCEL_ID_OBJ = $005D; // does not exist before BIFF5
|
||||
INT_EXCEL_ID_BOUNDSHEET = $0085; // Renamed to SHEET in the latest OpenOffice docs, does not exist before 5
|
||||
INT_EXCEL_ID_MULRK = $00BD; // does not exist before BIFF5
|
||||
INT_EXCEL_ID_MULBLANK = $00BE; // does not exist before BIFF5
|
||||
INT_EXCEL_ID_XF = $00E0; // BIFF2:$0043, BIFF3:$0243, BIFF4:$0443
|
||||
INT_EXCEL_ID_RSTRING = $00D6; // does not exist before BIFF5
|
||||
INT_EXCEL_ID_SHAREDFMLA = $04BC; // does not exist before BIFF5
|
||||
INT_EXCEL_ID_BOF = $0809; // BIFF2:$0009, BIFF3:$0209; BIFF4:$0409
|
||||
INT_EXCEL_ID_OBJ = $005D; // does not exist before BIFF5
|
||||
INT_EXCEL_ID_BOUNDSHEET = $0085; // Renamed to SHEET in the latest OpenOffice docs, does not exist before 5
|
||||
INT_EXCEL_ID_MULRK = $00BD; // does not exist before BIFF5
|
||||
INT_EXCEL_ID_MULBLANK = $00BE; // does not exist before BIFF5
|
||||
INT_EXCEL_ID_XF = $00E0; // BIFF2:$0043, BIFF3:$0243, BIFF4:$0443
|
||||
INT_EXCEL_ID_RSTRING = $00D6; // does not exist before BIFF5
|
||||
INT_EXCEL_ID_SHAREDFMLA = $04BC; // does not exist before BIFF5
|
||||
INT_EXCEL_ID_BOF = $0809; // BIFF2:$0009, BIFF3:$0209; BIFF4:$0409
|
||||
|
||||
{ FONT record constants }
|
||||
INT_FONT_WEIGHT_NORMAL = $0190;
|
||||
INT_FONT_WEIGHT_BOLD = $02BC;
|
||||
INT_FONT_WEIGHT_NORMAL = $0190;
|
||||
INT_FONT_WEIGHT_BOLD = $02BC;
|
||||
|
||||
{ CODEPAGE record constants }
|
||||
WORD_ASCII = 367;
|
||||
WORD_CP_437_DOS_US = 437;
|
||||
WORD_CP_850_DOS_Latin1 = 850;
|
||||
WORD_CP_852_DOS_Latin2 = 852;
|
||||
WORD_CP_866_DOS_Cyrillic = 866;
|
||||
WORD_CP_874_Thai = 874;
|
||||
WORD_UTF_16 = 1200; // BIFF 8
|
||||
WORD_CP_1250_Latin2 = 1250;
|
||||
WORD_CP_1251_Cyrillic = 1251;
|
||||
WORD_CP_1252_Latin1 = 1252; // BIFF4-BIFF5
|
||||
WORD_CP_1253_Greek = 1253;
|
||||
WORD_CP_1254_Turkish = 1254;
|
||||
WORD_CP_1255_Hebrew = 1255;
|
||||
WORD_CP_1256_Arabic = 1256;
|
||||
WORD_CP_1257_Baltic = 1257;
|
||||
WORD_CP_1258_Vietnamese = 1258;
|
||||
WORD_CP_1258_Latin1_BIFF2_3 = 32769; // BIFF2-BIFF3
|
||||
WORD_ASCII = 367;
|
||||
WORD_CP_437_DOS_US = 437;
|
||||
WORD_CP_850_DOS_Latin1 = 850;
|
||||
WORD_CP_852_DOS_Latin2 = 852;
|
||||
WORD_CP_866_DOS_Cyrillic = 866;
|
||||
WORD_CP_874_Thai = 874;
|
||||
WORD_UTF_16 = 1200; // BIFF 8
|
||||
WORD_CP_1250_Latin2 = 1250;
|
||||
WORD_CP_1251_Cyrillic = 1251;
|
||||
WORD_CP_1252_Latin1 = 1252; // BIFF4-BIFF5
|
||||
WORD_CP_1253_Greek = 1253;
|
||||
WORD_CP_1254_Turkish = 1254;
|
||||
WORD_CP_1255_Hebrew = 1255;
|
||||
WORD_CP_1256_Arabic = 1256;
|
||||
WORD_CP_1257_Baltic = 1257;
|
||||
WORD_CP_1258_Vietnamese = 1258;
|
||||
WORD_CP_1258_Latin1_BIFF2_3= 32769; // BIFF2-BIFF3
|
||||
|
||||
{ DATEMODE record, 5.28 }
|
||||
DATEMODE_1900_BASE = 1; //1/1/1900 minus 1 day in FPC TDateTime
|
||||
DATEMODE_1904_BASE = 1462; //1/1/1904 in FPC TDateTime
|
||||
DATEMODE_1900_BASE = 1; //1/1/1900 minus 1 day in FPC TDateTime
|
||||
DATEMODE_1904_BASE = 1462; //1/1/1904 in FPC TDateTime
|
||||
|
||||
{ WINDOW1 record constants - BIFF5-BIFF8 }
|
||||
MASK_WINDOW1_OPTION_WINDOW_HIDDEN = $0001;
|
||||
@ -328,7 +331,7 @@ const
|
||||
ROWHEIGHT_EPS = 1E-2;
|
||||
|
||||
type
|
||||
TDateMode=(dm1900, dm1904); //DATEMODE values, 5.28
|
||||
TDateMode = (dm1900, dm1904); //DATEMODE values, 5.28
|
||||
|
||||
// Adjusts Excel float (date, date/time, time) with the file's base date to get a TDateTime
|
||||
function ConvertExcelDateTimeToDateTime
|
||||
@ -451,8 +454,12 @@ type
|
||||
procedure ReadPageSetup(AStream: TStream);
|
||||
// Read PANE record
|
||||
procedure ReadPane(AStream: TStream);
|
||||
// Read PASSWORD record
|
||||
procedure ReadPASSWORD(AStream: TStream; AWorksheet: TsWorksheet = nil);
|
||||
procedure ReadPrintGridLines(AStream: TStream);
|
||||
procedure ReadPrintHeaders(AStream: TStream);
|
||||
// Reads whether the workbook or worksheet is protected
|
||||
procedure ReadPROTECT(AStream: TStream; AWorksheet: TsWorksheet = nil);
|
||||
// Read an RK value cell
|
||||
procedure ReadRKValue(AStream: TStream);
|
||||
// Read the row, column, and XF index at the current stream position
|
||||
@ -491,6 +498,8 @@ type
|
||||
procedure ReadVCENTER(AStream: TStream);
|
||||
// Read WINDOW2 record (gridlines, sheet headers)
|
||||
procedure ReadWindow2(AStream: TStream); virtual;
|
||||
// Read WINDOWPROTECT record
|
||||
procedure ReadWindowProtect(AStream: TStream);
|
||||
procedure ReadWorkbookGlobals(AStream: TStream); virtual;
|
||||
procedure ReadWorksheet(AStream: TStream); virtual;
|
||||
|
||||
@ -2017,6 +2026,35 @@ begin
|
||||
// If BIFF5-BIFF8 there is 1 more byte which is not used here.
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Reads the PASSWORD record containing the encrypted password
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsSpreadBIFFReader.ReadPASSWORD(AStream: TStream;
|
||||
AWorksheet: TsWorksheet = nil);
|
||||
var
|
||||
hash: Word;
|
||||
cinfo: TsCryptoInfo;
|
||||
begin
|
||||
hash := WordLEToN(AStream.ReadWord);
|
||||
if hash = 0 then
|
||||
exit; // no password
|
||||
|
||||
if AWorksheet = nil then begin
|
||||
// Password for workbook protection
|
||||
cinfo := FWorkbook.CryptoInfo;
|
||||
cinfo.PasswordHash := Format('%.4x', [hash]);
|
||||
cinfo.Algorithm := caExcel;
|
||||
FWorkbook.CryptoInfo := cinfo;
|
||||
end else
|
||||
begin
|
||||
// Password for worksheet protection
|
||||
cinfo := AWorksheet.CryptoInfo;
|
||||
cinfo.PasswordHash := Format('%.4x', [hash]);
|
||||
cinfo.Algorithm := caExcel;
|
||||
AWorksheet.CryptoInfo := cinfo;
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Reads whether the gridlines are printed or not
|
||||
-------------------------------------------------------------------------------}
|
||||
@ -2043,6 +2081,28 @@ begin
|
||||
Options := Options + [poPrintHeaders];
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Determines whether the workbook or worksheet is protected
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsSpreadBIFFReader.ReadPROTECT(AStream: TStream;
|
||||
AWorksheet: TsWorksheet = nil);
|
||||
var
|
||||
p: Word;
|
||||
begin
|
||||
p := WordLEToN(AStream.ReadWord);
|
||||
if p = 0 then // not protected
|
||||
exit;
|
||||
|
||||
if AWorksheet = nil then
|
||||
// Workbook protection
|
||||
FWorkbook.Protection := FWorkbook.Protection + [bpLockStructure]
|
||||
else begin
|
||||
// Worksheet protection
|
||||
AWorksheet.Protection := FWorksheet.Protection + [spCells];
|
||||
AWorksheet.Protect(true);
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Reads the row, column and xf index
|
||||
NOT VALID for BIFF2
|
||||
@ -2875,6 +2935,17 @@ begin
|
||||
Unused(AStream);
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFFReader.ReadWindowProtect(AStream: TStream);
|
||||
var
|
||||
p: Word;
|
||||
begin
|
||||
p := WordLEToN(AStream.ReadWord);
|
||||
if p = 0 then // Workbook not protected
|
||||
FWorkbook.Protection := FWorkbook.Protection - [bpLockWindows]
|
||||
else // Workbook protection
|
||||
FWorkbook.Protection := FWorkbook.Protection + [bpLockWindows];
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFFReader.ReadWorksheet(AStream: TStream);
|
||||
begin
|
||||
// To be overridden by BIFF5 and BIFF8
|
||||
|
Reference in New Issue
Block a user