You've already forked lazarus-ccr
fpspreadsheet: Add ods reader for cell, sheet and workbook protection. Simplification in xlsx reader for sheet protection. Remove field HashValue from TsCryptoInfo (it is PasswordHash now)
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5791 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -33,6 +33,7 @@ end;
|
||||
function StrToAlgorithm(const AName: String): TsCryptoAlgorithm;
|
||||
begin
|
||||
case AName of
|
||||
// Excel
|
||||
'MD2' : Result := caMD2;
|
||||
'MD4' : Result := caMD4;
|
||||
'MD5' : Result := caMD5;
|
||||
@ -43,7 +44,15 @@ begin
|
||||
'SHA-384' : Result := caSHA384;
|
||||
'SHA-512' : Result := caSHA512;
|
||||
'WHIRLPOOL' : Result := caWHIRLPOOL;
|
||||
else Result := caUnknown;
|
||||
else
|
||||
// Libre/OpenOffice
|
||||
if pos('sha1', AName) > 0 then // http://www.w3.org/2000/09/xmldsig#sha1
|
||||
Result := caSHA1
|
||||
else
|
||||
if pos('sha256', AName) > 0 then // http://www.w3.org/2000/09/xmldsig#sha256
|
||||
Result := caSHA256
|
||||
else
|
||||
Result := caUnknown;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
@ -115,6 +115,7 @@ type
|
||||
procedure ReadColumns(ATableNode: TDOMNode);
|
||||
procedure ReadColumnStyle(AStyleNode: TDOMNode);
|
||||
procedure ReadDateMode(SpreadSheetNode: TDOMNode);
|
||||
procedure ReadDocumentProtection(ANode: TDOMNode);
|
||||
procedure ReadFont(ANode: TDOMNode; var AFontName: String;
|
||||
var AFontSize: Single; var AFontStyle: TsFontStyles; var AFontColor: TsColor;
|
||||
var AFontPosition: TsFontPosition);
|
||||
@ -129,6 +130,7 @@ type
|
||||
procedure ReadRowsAndCells(ATableNode: TDOMNode);
|
||||
procedure ReadRowStyle(AStyleNode: TDOMNode);
|
||||
procedure ReadShapes(ATableNode: TDOMNode);
|
||||
procedure ReadSheetProtection(ANode: TDOMNode; ASheet: TsWorksheet);
|
||||
procedure ReadTableStyle(AStyleNode: TDOMNode);
|
||||
|
||||
protected
|
||||
@ -285,8 +287,7 @@ uses
|
||||
{$IFDEF FPS_VARISBOOL}
|
||||
fpsPatches,
|
||||
{$ENDIF}
|
||||
fpsStrings, fpsStreams, fpsClasses, fpsExprParser,
|
||||
fpsImages;
|
||||
fpsStrings, fpsStreams, fpsCrypto, fpsClasses, fpsExprParser, fpsImages;
|
||||
|
||||
const
|
||||
{ OpenDocument general XML constants }
|
||||
@ -2060,6 +2061,25 @@ begin
|
||||
raise Exception.CreateFmt('Spreadsheet file corrupt: cannot handle null-date format %s', [NullDateSetting]);
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadDocumentProtection(ANode: TDOMNode);
|
||||
var
|
||||
s: String;
|
||||
cinfo: TsCryptoInfo;
|
||||
begin
|
||||
if ANode = nil then
|
||||
exit;
|
||||
|
||||
if GetAttrValue(ANode, 'table:structure-protected') = 'true' then
|
||||
Workbook.Protection := Workbook.Protection + [bpLockStructure]
|
||||
else
|
||||
exit;
|
||||
|
||||
InitCryptoInfo(cinfo);
|
||||
cinfo.PasswordHash := GetAttrValue(ANode, 'table:protection-key');
|
||||
cinfo.Algorithm := StrToAlgorithm(GetAttrValue(ANode, 'table:protection-key-digest-algorithm'));
|
||||
Workbook.CryptoInfo := cinfo;
|
||||
end;
|
||||
|
||||
{ Reads font data from an xml node and returns the font elements. }
|
||||
procedure TsSpreadOpenDocReader.ReadFont(ANode: TDOMNode; var AFontName: String;
|
||||
var AFontSize: Single; var AFontStyle: TsFontStyles; var AFontColor: TsColor;
|
||||
@ -2468,6 +2488,7 @@ begin
|
||||
if not Assigned(SpreadSheetNode) then
|
||||
raise Exception.Create('[TsSpreadOpenDocReader.ReadFromStream] Node "office:spreadsheet" not found.');
|
||||
|
||||
ReadDocumentProtection(SpreadsheetNode);
|
||||
ReadDateMode(SpreadSheetNode);
|
||||
|
||||
//process each table (sheet)
|
||||
@ -2485,6 +2506,8 @@ begin
|
||||
end;
|
||||
FWorkSheet := FWorkbook.AddWorksheet(GetAttrValue(TableNode, 'table:name'), true);
|
||||
tablestyleName := GetAttrValue(TableNode, 'table:style-name');
|
||||
// Read protection
|
||||
ReadSheetProtection(TableNode, FWorksheet);
|
||||
// Collect embedded images
|
||||
ReadShapes(TableNode);
|
||||
// Collect column styles used
|
||||
@ -3882,6 +3905,50 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadSheetProtection(ANode: TDOMNode;
|
||||
ASheet: TsWorksheet);
|
||||
var
|
||||
s: String;
|
||||
sp: TsWorksheetProtections;
|
||||
cinfo: TsCryptoInfo;
|
||||
childNode: TDOMNode;
|
||||
nodeName: String;
|
||||
begin
|
||||
if ANode = nil then
|
||||
exit;
|
||||
s := GetAttrValue(ANode, 'table:protected');
|
||||
if s = 'true' then begin
|
||||
sp := DEFAULT_SHEET_PROTECTION;
|
||||
Include(sp, spCells);
|
||||
|
||||
// These items are ALLOWED (unlike Excel where they are FORBIDDEN).
|
||||
// <loext:table-protection loext:select-unprotected-cells="true" />
|
||||
// <loext:table-protection loext:select-protected-cells="true" />
|
||||
// <loext:table-protection />
|
||||
childNode := ANode.FirstChild;
|
||||
while childNode <> nil do
|
||||
begin
|
||||
nodeName := childnode.NodeName;
|
||||
if nodeName = 'loext:table-protection' then begin
|
||||
s := GetAttrValue(childnode, 'loext:select-unprotected-cells');
|
||||
if s='true' then Exclude(sp, spSelectUnlockedCells)
|
||||
else Include(sp, spSelectUnlockedCells);
|
||||
if s='false' then Exclude(sp, spSelectLockedCells)
|
||||
else Include(sp, spSelectLockedCells);
|
||||
end;
|
||||
childNode := childNode.NextSibling;
|
||||
end;
|
||||
ASheet.Protection := sp;
|
||||
ASheet.Protect(true);
|
||||
|
||||
InitCryptoInfo(cinfo);
|
||||
cinfo.PasswordHash := GetAttrValue(ANode, 'table:protection-key');
|
||||
cinfo.Algorithm := StrToAlgorithm(GetAttrValue(ANode, 'table:protection-key-digest-algorithm'));
|
||||
ASheet.CryptoInfo := cinfo;
|
||||
end else
|
||||
ASheet.Protect(false);
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadStyles(AStylesNode: TDOMNode);
|
||||
var
|
||||
styleNode: TDOMNode;
|
||||
@ -4220,6 +4287,17 @@ begin
|
||||
fmt.VertAlignment := vaBottom;
|
||||
if fmt.VertAlignment <> vaDefault then
|
||||
Include(fmt.UsedFormattingFields, uffVertAlign);
|
||||
|
||||
// Protection
|
||||
s := GetAttrValue(styleChildNode, 'style:cell-protect');
|
||||
if s = 'none' then
|
||||
fmt.Protection := []
|
||||
else if s = 'hidden-and-protected' then
|
||||
fmt.Protection := [cpLockCell, cpHideFormulas]
|
||||
else if s = 'protected' then
|
||||
fmt.Protection := [cpLockCell]
|
||||
else if s = 'formula-hidden' then
|
||||
fmt.Protection := [cpHideFormulas];
|
||||
end
|
||||
else
|
||||
if nodeName = 'style:paragraph-properties' then
|
||||
|
@ -1189,7 +1189,8 @@ begin
|
||||
FActiveCellRow := UNASSIGNED_ROW_COL_INDEX;
|
||||
FActiveCellCol := UNASSIGNED_ROW_COL_INDEX;
|
||||
|
||||
FProtection := DEFAULT_SHEET_PROTECTIONS;
|
||||
FProtection := DEFAULT_SHEET_PROTECTION;
|
||||
InitCryptoInfo(FCryptoInfo);
|
||||
|
||||
FOptions := [soShowGridLines, soShowHeaders];
|
||||
end;
|
||||
@ -7981,6 +7982,10 @@ begin
|
||||
// Add default cell format
|
||||
InitFormatRecord(fmt);
|
||||
AddCellFormat(fmt);
|
||||
|
||||
// Protection
|
||||
InitCryptoInfo(FCryptoInfo);
|
||||
FProtection := [];
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
|
@ -650,7 +650,6 @@ type
|
||||
TsCryptoInfo = record
|
||||
PasswordHash: String;
|
||||
Algorithm: TsCryptoAlgorithm;
|
||||
HashValue: string;
|
||||
SaltValue: string;
|
||||
SpinCount: Integer;
|
||||
end;
|
||||
@ -680,7 +679,7 @@ const
|
||||
spCells, spSort, spSelectLockedCells, spSelectUnlockedCells
|
||||
{, spObjects, spPivotTables, spScenarios} ];
|
||||
|
||||
DEFAULT_SHEET_PROTECTIONS = ALL_SHEET_PROTECTIONS - [spSelectLockedCells, spSelectUnlockedcells];
|
||||
DEFAULT_SHEET_PROTECTION = ALL_SHEET_PROTECTIONS - [spSelectLockedCells, spSelectUnlockedcells];
|
||||
|
||||
DEFAULT_CELL_PROTECTION = [cpLockCell];
|
||||
|
||||
|
@ -2087,7 +2087,6 @@ procedure InitCryptoInfo(out AValue: TsCryptoInfo);
|
||||
begin
|
||||
AValue.PasswordHash := '';
|
||||
AValue.Algorithm := caUnknown;
|
||||
AValue.HashValue := '';
|
||||
AValue.SaltValue := '';
|
||||
AValue.SpinCount := 0;
|
||||
end;
|
||||
|
@ -2043,14 +2043,14 @@ begin
|
||||
|
||||
if AWorksheet = nil then begin
|
||||
// Password for workbook protection
|
||||
cinfo := FWorkbook.CryptoInfo;
|
||||
InitCryptoInfo(cinfo);
|
||||
cinfo.PasswordHash := Format('%.4x', [hash]);
|
||||
cinfo.Algorithm := caExcel;
|
||||
FWorkbook.CryptoInfo := cinfo;
|
||||
end else
|
||||
begin
|
||||
// Password for worksheet protection
|
||||
cinfo := AWorksheet.CryptoInfo;
|
||||
InitCryptoInfo(cinfo);
|
||||
cinfo.PasswordHash := Format('%.4x', [hash]);
|
||||
cinfo.Algorithm := caExcel;
|
||||
AWorksheet.CryptoInfo := cinfo;
|
||||
|
@ -2006,7 +2006,7 @@ procedure TsSpreadOOXMLReader.ReadSheetProtection(ANode: TDOMNode;
|
||||
var
|
||||
s: String;
|
||||
shc: TsCryptoInfo;
|
||||
shp0, shp1: TsWorksheetProtections;
|
||||
shp: TsWorksheetProtections;
|
||||
begin
|
||||
if ANode = nil then
|
||||
exit;
|
||||
@ -2036,100 +2036,83 @@ begin
|
||||
end;
|
||||
AWorksheet.CryptoInfo := shc;
|
||||
|
||||
shp1 := []; // will get "1" to include
|
||||
shp0 := ALL_SHEET_PROTECTIONS; // will get "0" to exclude
|
||||
shp := DEFAULT_SHEET_PROTECTION;
|
||||
|
||||
// Attribute not found -> property = false
|
||||
s := GetAttrValue(ANode, 'sheet');
|
||||
if (s = '1') then
|
||||
Include(shp1, spCells) else
|
||||
Exclude(shp0, spCells);
|
||||
if (s = '1') then Include(shp, spCells) else
|
||||
if (s = '0') or (s = '') then Exclude(shp, spCells);
|
||||
|
||||
s := GetAttrValue(ANode, 'selectLockedCells');
|
||||
if (s = '1') then
|
||||
Include(shp1, spSelectLockedCells) else
|
||||
Exclude(shp0, spSelectLockedCells);
|
||||
if (s = '1') then Include(shp, spSelectLockedCells) else
|
||||
if (s = '0') or (s = '') then Exclude(shp, spSelectLockedCells);
|
||||
|
||||
s := GetAttrValue(ANode, 'selectUnlockedCells');
|
||||
if (s = '1') then
|
||||
Include(shp1, spSelectUnlockedCells) else
|
||||
Exclude(shp0, spSelectUnlockedCells);
|
||||
if (s = '1') then Include(shp, spSelectUnlockedCells) else
|
||||
if (s = '') or (s = '0') then Exclude(shp, spSelectUnlockedCells);
|
||||
|
||||
// these options are currently not supported by fpspreadsheet
|
||||
{
|
||||
s := GetAttrValue(ANode, 'objects');
|
||||
if (s = '1') then
|
||||
Include(shp1, spObjects) else
|
||||
Exclude(shp0, spObjects);
|
||||
if (s = '1') then Include(shp, spObjects) else
|
||||
if (s = '') or (s = '0') then Exclude(shp, spObjects);
|
||||
|
||||
s := GetAttrValue(ANode, 'scenarios');
|
||||
if (s = '1') then
|
||||
Include(shp1, spScenarios) else
|
||||
Exclude(shp0, spScenarios);
|
||||
if (s = '1') then Include(shp, spScenarios) else
|
||||
if (s = '') or (s = '0') then Exclude(shp, spScenarios);
|
||||
}
|
||||
|
||||
// Attribute not found -> property = true
|
||||
{
|
||||
s := GetAttrValue(ANode, 'autoFilter');
|
||||
if (s = '0') then
|
||||
Exclude(shp1, spAutoFilter) else
|
||||
Include(shp0, spAutoFilter);
|
||||
if (s = '0') then Exclude(shp, spAutoFilter) else
|
||||
if (s = '') or (s = '1') then Include(shp, spAutoFilter);
|
||||
}
|
||||
|
||||
s := GetAttrValue(ANode, 'deleteColumns');
|
||||
if (s = '0') then
|
||||
Exclude(shp0, spDeleteColumns) else
|
||||
Include(shp1, spDeleteColumns);
|
||||
if (s = '0') then Exclude(shp, spDeleteColumns) else
|
||||
if (s = '') or (s = '1') then Include(shp, spDeleteColumns);
|
||||
|
||||
s := GetAttrValue(ANode, 'deleteRows');
|
||||
if (s = '0') then
|
||||
Exclude(shp0, spDeleteRows) else
|
||||
Include(shp1, spDeleteRows);
|
||||
if (s = '0') then Exclude(shp, spDeleteRows) else
|
||||
if (s = '') or (s = '1') then Include(shp, spDeleteRows);
|
||||
|
||||
s := GetAttrValue(ANode, 'formatCells');
|
||||
if (s = '0') then
|
||||
Exclude(shp0, spFormatCells) else
|
||||
Include(shp1, spFormatCells);
|
||||
if (s = '0') then Exclude(shp, spFormatCells) else
|
||||
if (s = '') or (s = '1') then Include(shp, spFormatCells);
|
||||
|
||||
s := GetAttrValue(ANode, 'formatColumns');
|
||||
if (s = '0') then
|
||||
Exclude(shp0, spFormatColumns) else
|
||||
Include(shp1, spFormatColumns);
|
||||
if (s = '0') then Exclude(shp, spFormatColumns) else
|
||||
if (s = '') or (s = '1') then Include(shp, spFormatColumns);
|
||||
|
||||
s := GetAttrValue(ANode, 'formatRows');
|
||||
if (s = '0') then
|
||||
Exclude(shp0, spFormatRows) else
|
||||
Include(shp1, spFormatRows);
|
||||
if (s = '0') then Exclude(shp, spFormatRows) else
|
||||
if (s = '') or (s = '1') then Include(shp, spFormatRows);
|
||||
|
||||
s := GetAttrValue(ANode, 'insertColumns');
|
||||
if (s = '0') then
|
||||
Exclude(shp0, spInsertColumns) else
|
||||
Include(shp1, spInsertColumns);
|
||||
if (s = '0') then Exclude(shp, spInsertColumns) else
|
||||
if (s = '') or (s = '1') then Include(shp, spInsertColumns);
|
||||
|
||||
s := GetAttrValue(ANode, 'insertHyperlinks');
|
||||
if (s = '0') then
|
||||
Exclude(shp0, spInsertHyperlinks) else
|
||||
Include(shp1, spInsertHyperlinks);
|
||||
if (s = '0') then Exclude(shp, spInsertHyperlinks) else
|
||||
if (s = '') or (s = '1') then Include(shp, spInsertHyperlinks);
|
||||
|
||||
s := GetAttrValue(ANode, 'insertRows');
|
||||
if (s = '0') then
|
||||
Exclude(shp0, spInsertRows) else
|
||||
Include(shp1, spInsertRows);
|
||||
if (s = '0') then Exclude(shp, spInsertRows) else
|
||||
if (s = '') or (s = '1') then Include(shp, spInsertRows);
|
||||
|
||||
s := GetAttrValue(ANode, 'sort');
|
||||
if (s = '0') then
|
||||
Exclude(shp0, spSort) else
|
||||
Include(shp1, spSort);
|
||||
if (s = '0') then Exclude(shp, spSort) else
|
||||
if (s = '') or (s = '1') then Include(shp, spSort);
|
||||
|
||||
// Currently no pivottable support in fpspreadsheet
|
||||
{
|
||||
s := GetAttrValue(ANode, 'pivotTables');
|
||||
if (s = '0') then
|
||||
Exclude(shp0, spPivotTables) else
|
||||
Include(shp1, spPivotTables);
|
||||
if (s = '0') then Exclude(shp, spPivotTables) else
|
||||
if (s = '') or (s = '1') then Include(shp, spPivotTables);
|
||||
}
|
||||
|
||||
AWorksheet.Protection := shp0 + shp1;
|
||||
AWorksheet.Protection := shp;
|
||||
AWorksheet.Protect(true);
|
||||
end;
|
||||
|
||||
@ -3449,7 +3432,7 @@ begin
|
||||
s := s + ' password="' + AWorksheet.CryptoInfo.PasswordHash + '"'
|
||||
else
|
||||
begin
|
||||
s := s + ' hashValue="' + AWorksheet.CryptoInfo.HashValue + '"';
|
||||
s := s + ' hashValue="' + AWorksheet.CryptoInfo.PasswordHash + '"';
|
||||
|
||||
if AWorksheet.CryptoInfo.Algorithm <> caUnknown then
|
||||
s := s + ' algorithmName="' + AlgorithmToStr(AWorksheet.CryptoInfo.Algorithm) + '"';
|
||||
|
@ -3655,9 +3655,8 @@ begin
|
||||
AStrings.Add('(-) CryptoInfo=');
|
||||
AStrings.Add(Format(' PasswordHash=%s', [Workbook.CryptoInfo.PasswordHash]));
|
||||
AStrings.Add(Format(' Algorithm=%s', [AlgorithmToStr(Workbook.CryptoInfo.Algorithm)]));
|
||||
AStrings.Add(Format(' HashValue=%s', [Workbook.CryptoInfo.HashValue]));
|
||||
AStrings.Add(Format(' SaltValue=%s', [Workbook.CryptoInfo.SaltValue]));
|
||||
AStrings.Add(Format(' SplinCount=%d', [Workbook.CryptoInfo.SpinCount]));
|
||||
AStrings.Add(Format(' SpinCount=%d', [Workbook.CryptoInfo.SpinCount]));
|
||||
end else
|
||||
AStrings.Add('(+) CryptoInfo=(dblclick for more...)');
|
||||
|
||||
@ -3839,9 +3838,8 @@ begin
|
||||
AStrings.Add('(-) CryptoInfo=');
|
||||
AStrings.Add(Format(' PasswordHash=%s', [Worksheet.CryptoInfo.PasswordHash]));
|
||||
AStrings.Add(Format(' Algorithm=%s', [AlgorithmToStr(Worksheet.CryptoInfo.Algorithm)]));
|
||||
AStrings.Add(Format(' HashValue=%s', [Worksheet.CryptoInfo.HashValue]));
|
||||
AStrings.Add(Format(' SaltValue=%s', [Worksheet.CryptoInfo.SaltValue]));
|
||||
AStrings.Add(Format(' SplinCount=%d', [Worksheet.CryptoInfo.SpinCount]));
|
||||
AStrings.Add(Format(' SpinCount=%d', [Worksheet.CryptoInfo.SpinCount]));
|
||||
end else
|
||||
AStrings.Add('(+) CryptoInfo=(dblclick for more...)');
|
||||
|
||||
|
Reference in New Issue
Block a user