You've already forked lazarus-ccr
fpspreadsheet: Improved password handling and format detection for the decryption readers.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8913 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -156,7 +156,7 @@ type
|
||||
var AFontColor: TsColor);
|
||||
function ReadHeaderFooterText(ANode: TDOMNode): String;
|
||||
procedure ReadMetaData(ANode: TDOMNode);
|
||||
procedure ReadMetaInfManifest(ANode: TDOMNode; out IsEncrypted: Boolean);
|
||||
procedure ReadMetaInfManifest(ANode: TDOMNode);
|
||||
procedure ReadPictures(AStream: TStream);
|
||||
procedure ReadPrintRanges(ATableNode: TDOMNode; ASheet: TsBasicWorksheet);
|
||||
procedure ReadRowsAndCells(ATableNode: TDOMNode);
|
||||
@ -177,6 +177,7 @@ type
|
||||
protected
|
||||
FPointSeparatorSettings: TFormatSettings;
|
||||
procedure AddBuiltinNumFormats; override;
|
||||
function NeedsPassword(AStream: TStream): Boolean; override;
|
||||
procedure ReadAutomaticStyles(AStylesNode: TDOMNode);
|
||||
procedure ReadMasterStyles(AStylesNode: TDOMNode);
|
||||
procedure ReadNumFormats(AStylesNode: TDOMNode);
|
||||
@ -203,7 +204,6 @@ type
|
||||
|
||||
function Decrypt(AStream: TStream; ADecryptionInfo: TsOpenDocManifestFileEntry;
|
||||
APassword: String; ADestStream: TStream; out AErrorMsg: String): Boolean; virtual;
|
||||
function SupportsDecryption: Boolean; virtual;
|
||||
function UnzipToStream(AStream: TStream; AZippedFile: String;
|
||||
ADestStream: TStream): Boolean; virtual;
|
||||
function UnzipToStream(AStream: TStream; AZippedFile: String;
|
||||
@ -1630,6 +1630,22 @@ begin
|
||||
Result := -1;
|
||||
end;
|
||||
|
||||
{ Returns true if the file is password-protected, i.e. if there are entries
|
||||
in the META-INF/manifest.xml while contain decryption information. }
|
||||
function TsSpreadOpenDocReader.NeedsPassword(AStream: TStream): Boolean;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
Unused(AStream);
|
||||
for i := 0 to FManifestFileEntries.Count-1 do
|
||||
if TsOpenDocManifestFileEntry(FManifestFileEntries[i]).Encrypted then
|
||||
begin
|
||||
Result := true;
|
||||
exit;
|
||||
end;
|
||||
Result := false;
|
||||
end;
|
||||
|
||||
function TsSpreadOpenDocReader.NodeIsEmptyCell(ACellNode: TDOMNode): Boolean;
|
||||
var
|
||||
valuestr: String;
|
||||
@ -2062,8 +2078,7 @@ end;
|
||||
|
||||
// Reads the file META-INF/manifest.xml. It is never encrypted and contains
|
||||
// decryption information.
|
||||
procedure TsSpreadOpenDocReader.ReadMetaInfManifest(ANode: TDOMNode;
|
||||
out IsEncrypted: Boolean);
|
||||
procedure TsSpreadOpenDocReader.ReadMetaInfManifest(ANode: TDOMNode);
|
||||
|
||||
function GetAlgorithmName(ASubNode: TDOMNode; AttrName: String): String;
|
||||
var
|
||||
@ -2093,7 +2108,6 @@ var
|
||||
nodeName: String;
|
||||
entry: TsOpenDocManifestFileEntry;
|
||||
begin
|
||||
IsEncrypted := false;
|
||||
while ANode <> nil do
|
||||
begin
|
||||
nodeName := ANode.NodeName;
|
||||
@ -2107,7 +2121,6 @@ begin
|
||||
nodeName := encryptionDataNode.NodeName;
|
||||
if nodeName = 'manifest:encryption-data' then
|
||||
begin
|
||||
IsEncrypted := true;
|
||||
entry.Encrypted := true;
|
||||
entry.EncryptionData_ChecksumType := GetAlgorithmName(encryptionDataNode, 'manifest:checksum-type');
|
||||
entry.EncryptionData_Checksum := GetAttrValue(encryptionDataNode, 'manifest:checksum');
|
||||
@ -2924,9 +2937,8 @@ begin
|
||||
ReadXMLStream(Doc, XMLStream);
|
||||
if Assigned(Doc) then
|
||||
begin
|
||||
ReadMetaInfManifest(Doc.DocumentElement.FindNode('manifest:file-entry'), isEncrypted);
|
||||
if isEncrypted and not SupportsDecryption then
|
||||
raise EFpSpreadsheetReader.Create('File is encrypted.');
|
||||
ReadMetaInfManifest(Doc.DocumentElement.FindNode('manifest:file-entry'));
|
||||
CheckPassword(XMLStream, APassword);
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
@ -5612,13 +5624,6 @@ begin
|
||||
Result := false;
|
||||
end;
|
||||
|
||||
{ If a descendant reader class supports decryption it must return true
|
||||
here. The standard ods reader is not able to read encrypted file content. }
|
||||
function TsSpreadOpenDocReader.SupportsDecryption: Boolean;
|
||||
begin
|
||||
Result := false;
|
||||
end;
|
||||
|
||||
function TsSpreadOpenDocReader.UnzipToStream(AStream: TStream;
|
||||
AZippedFile: String; ADestStream: TStream): Boolean;
|
||||
begin
|
||||
|
@ -48,12 +48,16 @@ type
|
||||
public
|
||||
{ File format detection }
|
||||
class function CheckFileFormat(AStream: TStream): boolean; virtual; abstract;
|
||||
{ General writing methods }
|
||||
{ General reading methods }
|
||||
procedure ReadFromFile(AFileName: string; APassword: String = '';
|
||||
AParams: TsStreamParams = []); virtual; abstract;
|
||||
procedure ReadFromStream(AStream: TStream; APassword: String = '';
|
||||
AParams: TsStreamParams = []); virtual; abstract;
|
||||
procedure ReadFromStrings(AStrings: TStrings; AParams: TsStreamParams = []); virtual; abstract;
|
||||
{ Related to password-protected files }
|
||||
procedure CheckPassword(AStream: TStream; var APassword: String); virtual;
|
||||
function NeedsPassword(AStream: TStream): Boolean; virtual;
|
||||
function SupportsDecryption: Boolean; virtual;
|
||||
end;
|
||||
|
||||
{ TsBasicSpreadWriter }
|
||||
@ -263,6 +267,53 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
{------------------------------------------------------------------------------}
|
||||
{ TsBasicSpreadReader }
|
||||
{------------------------------------------------------------------------------}
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Checks whether the currently processed stream is password-protected.
|
||||
If true, it checks whether the reader class supports decryption and makes
|
||||
sure that a password is provided to the calling routine (ReadFromStream).
|
||||
Exceptions are raised in the error cases.
|
||||
Must be called at the beginning of ReadFromStream when the stream potentially
|
||||
can be decrypted in order to provide the user a reasonable error message.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsBasicSpreadReader.CheckPassword(AStream: TStream;
|
||||
var APassword: String);
|
||||
begin
|
||||
if NeedsPassword(AStream) then
|
||||
begin
|
||||
if SupportsDecryption then
|
||||
begin
|
||||
if (APassword = '') and Assigned(FWorkbook.OnQueryPassword) then
|
||||
APassword := FWorkbook.OnQueryPassword();
|
||||
if (APassword = '') then
|
||||
raise EFpSpreadsheetReader.Create('Password required to open this workbook.');
|
||||
end else
|
||||
raise EFpSpreadsheetReader.Create('File is encrypted.');
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Should return whether the workbook to be loaded is password-protected by
|
||||
encryption.
|
||||
-------------------------------------------------------------------------------}
|
||||
function TsBasicSpreadReader.NeedsPassword(AStream: TStream): Boolean;
|
||||
begin
|
||||
Unused(AStream);
|
||||
Result := false;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Returns true if this reader class is able to decrypt a password-protected
|
||||
workbook file/stream.
|
||||
-------------------------------------------------------------------------------}
|
||||
function TsBasicSpreadReader.SupportsDecryption: Boolean;
|
||||
begin
|
||||
Result := false;
|
||||
end;
|
||||
|
||||
{------------------------------------------------------------------------------}
|
||||
{ TsBasicSpreadWriter }
|
||||
{------------------------------------------------------------------------------}
|
||||
@ -507,7 +558,9 @@ end;
|
||||
Opens the file and calls ReadFromStream. Data are stored in the workbook
|
||||
specified during construction.
|
||||
|
||||
@param AFileName The input file name.
|
||||
@param (AFileName The input file name.)
|
||||
@param (APassword The password needed to open a password-protected workbook.
|
||||
Note: Password-protected files are not supported by all readers.)
|
||||
@see TsWorkbook
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsCustomSpreadReader.ReadFromFile(AFileName: string;
|
||||
@ -545,11 +598,9 @@ end;
|
||||
|
||||
Its basic implementation here assumes that the stream is a TStringStream and
|
||||
the data are provided by calling ReadFromStrings. This mechanism is valid
|
||||
for wikitables.
|
||||
for wiki-tables.
|
||||
|
||||
Data will be stored in the workbook defined at construction.
|
||||
|
||||
@param AData Workbook which is filled by the data from the stream.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsCustomSpreadReader.ReadFromStream(AStream: TStream;
|
||||
APassword: String; AParams: TsStreamParams = []);
|
||||
@ -573,7 +624,7 @@ end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Reads workbook data from a string list. This abstract implementation does
|
||||
nothing and raises an exception. Must be overridden, like for wikitables.
|
||||
nothing and raises an exception. Must be overridden, like for wiki-tables.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsCustomSpreadReader.ReadFromStrings(AStrings: TStrings;
|
||||
AParams: TsStreamParams = []);
|
||||
@ -593,8 +644,8 @@ end;
|
||||
Creates an internal instance of the number format list according to the
|
||||
file format being read/written.
|
||||
|
||||
@param AWorkbook Workbook from with the file is written. This parameter is
|
||||
passed from the workbook which creates the writer.
|
||||
@param (AWorkbook Workbook from which the file is written. This parameter is
|
||||
passed from the workbook which creates the writer.)
|
||||
-------------------------------------------------------------------------------}
|
||||
constructor TsCustomSpreadWriter.Create(AWorkbook: TsBasicWorkbook);
|
||||
begin
|
||||
|
@ -1228,6 +1228,8 @@ type
|
||||
property Keywords: TStrings read FKeywords write FKeywords;
|
||||
end;
|
||||
|
||||
TsOnQueryPassword = function: String of object;
|
||||
|
||||
{@@ Basic worksheet class to avoid circular unit references. It has only those
|
||||
properties and methods which do not require any other unit than fpstypes. }
|
||||
TsBasicWorksheet = class
|
||||
@ -1256,6 +1258,7 @@ type
|
||||
TsBasicWorkbook = class
|
||||
private
|
||||
FLog: TStringList;
|
||||
FOnQueryPassword: TsOnQueryPassword;
|
||||
function GetErrorMsg: String;
|
||||
protected
|
||||
FFileName: String;
|
||||
@ -1292,6 +1295,8 @@ type
|
||||
property Protection: TsWorkbookProtections read FProtection write FProtection;
|
||||
{@@ Units of row heights and column widths }
|
||||
property Units: TsSizeUnits read FUnits;
|
||||
{@@ Event returning the password to open a password-protected workbook }
|
||||
property OnQueryPassword: TsOnQueryPassword read FOnQueryPassword write FOnQueryPassword;
|
||||
end;
|
||||
|
||||
{@@ Ancestor of the fpSpreadsheet exceptions }
|
||||
|
@ -141,6 +141,8 @@ type
|
||||
protected
|
||||
FFirstNumFormatIndexInFile: Integer;
|
||||
procedure AddBuiltinNumFormats; override;
|
||||
class function IsEncrypted(AStream: TStream): Boolean;
|
||||
function NeedsPassword(AStream: TStream): Boolean; override;
|
||||
public
|
||||
constructor Create(AWorkbook: TsBasicWorkbook); override;
|
||||
destructor Destroy; override;
|
||||
@ -359,6 +361,8 @@ const
|
||||
|
||||
LAST_PALETTE_INDEX = 63;
|
||||
|
||||
CFB_SIGNATURE = $E11AB1A1E011CFD0; // Compound File Binary Signature
|
||||
|
||||
type
|
||||
TFillListData = class
|
||||
PatternType: String;
|
||||
@ -951,6 +955,25 @@ begin
|
||||
Result := TMemoryStream.Create;
|
||||
end;
|
||||
|
||||
{ Checks the file header for the signature of the decrypted file format. }
|
||||
class function TsSpreadOOXMLReader.IsEncrypted(AStream: TStream): Boolean;
|
||||
var
|
||||
p: Int64;
|
||||
buf: Cardinal;
|
||||
begin
|
||||
p := AStream.Position;
|
||||
AStream.Position := 0;
|
||||
AStream.Read(buf, SizeOf(buf));
|
||||
Result := (buf = Cardinal(CFB_SIGNATURE));
|
||||
AStream.Position := p;
|
||||
end;
|
||||
|
||||
{ Returns TRUE if the file is encrypted and requires a password. }
|
||||
function TsSpreadOOXMLReader.NeedsPassword(AStream: TStream): Boolean;
|
||||
begin
|
||||
Result := IsEncrypted(AStream);
|
||||
end;
|
||||
|
||||
procedure TsSpreadOOXMLReader.ReadActiveSheet(ANode: TDOMNode;
|
||||
out ActiveSheetIndex: Integer);
|
||||
var
|
||||
@ -4411,6 +4434,8 @@ begin
|
||||
Unused(APassword, AParams);
|
||||
Doc := nil;
|
||||
|
||||
CheckPassword(AStream, APassword);
|
||||
|
||||
try
|
||||
// Retrieve theme colors
|
||||
XMLStream := CreateXMLStream;
|
||||
|
@ -10,7 +10,7 @@ uses
|
||||
{$IFDEF UNZIP_ABBREVIA}
|
||||
ABUnzper,
|
||||
{$ENDIF}
|
||||
fpsTypes, fpsOpenDocument;
|
||||
fpsTypes, fpsUtils, fpsOpenDocument;
|
||||
|
||||
type
|
||||
TsSpreadOpenDocReaderCrypto = class(TsSpreadOpenDocReader)
|
||||
@ -141,7 +141,6 @@ begin
|
||||
raise EFpSpreadsheetReader.Create('Unsupported key generation method ' + ADecryptionInfo.KeyDerivationName);
|
||||
end;
|
||||
|
||||
|
||||
{ Tells the calling routine that this reader is able to decrypt ods files. }
|
||||
function TsSpreadOpenDocReaderCrypto.SupportsDecryption: Boolean;
|
||||
begin
|
||||
|
@ -18,7 +18,7 @@ uses
|
||||
CFB_Signature = $E11AB1A1E011CFD0; // Compound File Binary Signature
|
||||
// Weird is the documentation is equal to
|
||||
// $D0CF11E0A1B11AE1, but here is inversed
|
||||
// maybe related to litle endian thing?!!
|
||||
// maybe related to little endian thing?!!
|
||||
|
||||
// EncryptionHeaderFlags as defined in 2.3.1 [MS-OFFCRYPTO]
|
||||
ehfAES = $00000004;
|
||||
|
@ -6,11 +6,17 @@ interface
|
||||
|
||||
uses
|
||||
Classes,
|
||||
fpstypes, xlsxooxml, xlsxdecrypter;
|
||||
fpstypes, fpsUtils, xlsxooxml, xlsxdecrypter;
|
||||
|
||||
type
|
||||
TsSpreadOOXMLReaderCrypto = class(TsSpreadOOXMLReader)
|
||||
private
|
||||
FNeedsPassword: Boolean;
|
||||
protected
|
||||
function NeedsPassword(AStream: TStream): Boolean; override;
|
||||
function SupportsDecryption: Boolean; override;
|
||||
public
|
||||
class function CheckFileFormat(AStream: TStream): boolean; override;
|
||||
procedure ReadFromStream(AStream: TStream; APassword: String = '';
|
||||
AParams: TsStreamParams = []); override;
|
||||
end;
|
||||
@ -24,17 +30,34 @@ implementation
|
||||
uses
|
||||
fpsReaderWriter;
|
||||
|
||||
class function TsSpreadOOXMLReaderCrypto.CheckFileFormat(AStream: TStream): boolean;
|
||||
begin
|
||||
Result := inherited; // This checks for a normal xlsx format ...
|
||||
if not Result then
|
||||
Result := IsEncrypted(AStream); // ... and this for a decrypted one.
|
||||
end;
|
||||
|
||||
function TsSpreadOOXMLReaderCrypto.NeedsPassword(AStream: TStream): Boolean;
|
||||
begin
|
||||
Unused(AStream);
|
||||
Result := FNeedsPassword;
|
||||
end;
|
||||
|
||||
procedure TsSpreadOOXMLReaderCrypto.ReadFromStream(AStream: TStream;
|
||||
APassword: String = ''; AParams: TsStreamParams = []);
|
||||
var
|
||||
ExcelDecrypt : TExcelFileDecryptor;
|
||||
DecryptedStream: TStream;
|
||||
begin
|
||||
FNeedsPassword := false;
|
||||
|
||||
ExcelDecrypt := TExcelFileDecryptor.Create;
|
||||
try
|
||||
AStream.Position := 0;
|
||||
if ExcelDecrypt.isEncryptedAndSupported(AStream) then
|
||||
begin
|
||||
FNeedsPassword := true;
|
||||
CheckPassword(AStream, APassword);
|
||||
DecryptedStream := TMemoryStream.Create;
|
||||
try
|
||||
ExcelDecrypt.Decrypt(AStream, DecryptedStream, UnicodeString(APassword));
|
||||
@ -42,12 +65,9 @@ begin
|
||||
AStream.Free;
|
||||
AStream := TMemoryStream.Create;
|
||||
DecryptedStream.Position := 0;
|
||||
|
||||
TMemoryStream(decryptedStream).SaveToFile('decr.zip');
|
||||
DecryptedStream.Position := 0;
|
||||
|
||||
AStream.CopyFrom(DecryptedStream, DecryptedStream.Size);
|
||||
AStream.Position := 0;
|
||||
FNeedsPassword := false; // AStream is not encrypted any more.
|
||||
finally
|
||||
DecryptedStream.Free;
|
||||
end;
|
||||
@ -60,6 +80,11 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TsSpreadOOXMLReaderCrypto.SupportsDecryption: Boolean;
|
||||
begin
|
||||
Result := true;
|
||||
end;
|
||||
|
||||
|
||||
initialization
|
||||
|
||||
|
@ -27,8 +27,8 @@ unit fpspreadsheetctrls;
|
||||
interface
|
||||
|
||||
uses
|
||||
LMessages, LResources, LCLVersion,
|
||||
Classes, Graphics, SysUtils, Controls, StdCtrls, ComCtrls, ValEdit, ActnList,
|
||||
LCLType, LCLIntf, LCLProc, LCLVersion, LMessages, LResources,
|
||||
Classes, Types, Graphics, SysUtils, Controls, StdCtrls, ComCtrls, ValEdit, ActnList,
|
||||
fpstypes, fpspreadsheet;
|
||||
|
||||
const
|
||||
@ -70,6 +70,7 @@ type
|
||||
FPendingOperation: TsCopyOperation;
|
||||
FOptions: TsWorkbookOptions;
|
||||
FOnError: TsWorkbookSourceErrorEvent;
|
||||
FOnQueryPassword: TsOnQueryPassword;
|
||||
|
||||
// Getters / setters
|
||||
function GetFileFormat: TsSpreadsheetFormat;
|
||||
@ -96,10 +97,11 @@ type
|
||||
|
||||
protected
|
||||
procedure AbortSelection;
|
||||
function DoQueryPassword: String;
|
||||
procedure DoShowError(const AErrorMsg: String);
|
||||
procedure InternalCreateNewWorkbook(AWorkbook: TsWorkbook = nil);
|
||||
procedure InternalLoadFromFile(AFileName: string; AAutoDetect: Boolean;
|
||||
AFormatID: TsSpreadFormatID; AWorksheetIndex: Integer = -1);
|
||||
AFormatID: TsSpreadFormatID; AWorksheetIndex: Integer; APassword: String);
|
||||
procedure InternalLoadFromWorkbook(AWorkbook: TsWorkbook;
|
||||
AWorksheetIndex: Integer = -1);
|
||||
procedure Loaded; override;
|
||||
@ -116,15 +118,13 @@ type
|
||||
public
|
||||
procedure CreateNewWorkbook;
|
||||
|
||||
procedure LoadFromProtectedSpreadsheetFile(AFileName: String;
|
||||
AFormatID: TsSpreadFormatID; APassword: String; AWorksheetIndex: Integer = -1);
|
||||
procedure LoadFromSpreadsheetFile(AFileName: string;
|
||||
AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = -1); overload;
|
||||
procedure LoadFromSpreadsheetFile(AFileName: string;
|
||||
AFormatID: TsSpreadFormatID = sfidUnknown; AWorksheetIndex: Integer = -1); overload;
|
||||
procedure LoadFromWorkbook(AWorkbook: TsWorkbook; AWorksheetIndex: Integer = -1);
|
||||
{
|
||||
procedure LoadFromSpreadsheetFile(AFileName: string;
|
||||
AWorksheetIndex: Integer = -1); overload;
|
||||
}
|
||||
|
||||
procedure SaveToSpreadsheetFile(AFileName: string;
|
||||
AOverwriteExisting: Boolean = true); overload;
|
||||
@ -133,9 +133,6 @@ type
|
||||
procedure SaveToSpreadsheetFile(AFileName: string; AFormatID: TsSpreadFormatID;
|
||||
AOverwriteExisting: Boolean = true); overload;
|
||||
|
||||
// procedure DisableControls;
|
||||
// procedure EnableControls;
|
||||
|
||||
procedure SelectCell(ASheetRow, ASheetCol: Cardinal);
|
||||
procedure SelectWorksheet(AWorkSheet: TsWorksheet);
|
||||
|
||||
@ -183,6 +180,8 @@ type
|
||||
{@@ A message box is displayey if an error occurs during loading of a
|
||||
spreadsheet. This behavior can be replaced by means of the event OnError. }
|
||||
property OnError: TsWorkbookSourceErrorEvent read FOnError write FOnError;
|
||||
{@@ Event fired when a password is required. Handler must return the pwd. }
|
||||
property OnQueryPassword: TsOnQueryPassword read FOnQueryPassword write FOnQueryPassword;
|
||||
end;
|
||||
|
||||
|
||||
@ -710,8 +709,7 @@ function ScalePPI(ALength: Integer): Integer;
|
||||
implementation
|
||||
|
||||
uses
|
||||
Types, Math, StrUtils, TypInfo, LCLType, LCLIntf, LCLProc,
|
||||
Dialogs, Forms, Clipbrd,
|
||||
Math, StrUtils, TypInfo, Dialogs, Forms, Clipbrd,
|
||||
fpsStrings, fpsCrypto, fpsReaderWriter, fpsUtils, fpsNumFormat, fpsImages,
|
||||
fpsHTMLUtils, fpsExprParser;
|
||||
|
||||
@ -1016,6 +1014,22 @@ begin
|
||||
SelectWorksheet(FWorksheet);
|
||||
end;
|
||||
|
||||
function TsWorkbookSource.DoQueryPassword: String;
|
||||
var
|
||||
crs: TCursor;
|
||||
begin
|
||||
crs := Screen.Cursor;
|
||||
Screen.Cursor := crDefault;
|
||||
try
|
||||
if Assigned(FOnQueryPassword) then
|
||||
Result := FOnQueryPassword()
|
||||
else
|
||||
Result := InputBox('Password required to open workbook', 'Password', '');
|
||||
finally
|
||||
Screen.Cursor := crs;
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
An error has occured during loading of the workbook. Shows a message box by
|
||||
default. But a different behavior can be obtained by means of the OnError
|
||||
@ -1137,20 +1151,23 @@ end;
|
||||
for the loader.
|
||||
Is ignored when AAutoDetect is @false.)
|
||||
@param(AWorksheetIndex Index of the worksheet to be selected after loading.)
|
||||
@param(APassword Password to open encrypted workbook. Note: this is
|
||||
supported only by ods and xlsx readers.)
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorkbookSource.InternalLoadFromFile(AFileName: string;
|
||||
AAutoDetect: Boolean; AFormatID: TsSpreadFormatID;
|
||||
AWorksheetIndex: Integer = -1);
|
||||
AAutoDetect: Boolean; AFormatID: TsSpreadFormatID; AWorksheetIndex: Integer;
|
||||
APassword: String);
|
||||
var
|
||||
book: TsWorkbook;
|
||||
begin
|
||||
book := TsWorkbook.Create;
|
||||
try
|
||||
book.Options := FOptions;
|
||||
book.OnQueryPassword := @DoQueryPassword;
|
||||
if AAutoDetect then
|
||||
book.ReadfromFile(AFileName)
|
||||
book.ReadfromFile(AFileName, APassword)
|
||||
else
|
||||
book.ReadFromFile(AFileName, AFormatID);
|
||||
book.ReadFromFile(AFileName, AFormatID, APassword);
|
||||
InternalLoadFromWorkbook(book, AWorksheetIndex);
|
||||
except
|
||||
// book is normally used as current workbook. But it must be destroyed
|
||||
@ -1220,9 +1237,11 @@ begin
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Public spreadsheet loader to be used if file format is known.
|
||||
Public loader of a spreadsheet file.
|
||||
|
||||
Call this methdd for both built-in and user-provided file formats.
|
||||
Call this method for both built-in and user-provided file formats.
|
||||
|
||||
If the workbook is password-protected the password is prompted by a dialog.
|
||||
|
||||
@param(AFilename Name of the spreadsheet file to be loaded.)
|
||||
@param(AFormatID Identifier of the spreadsheet file format assumed
|
||||
@ -1236,7 +1255,7 @@ var
|
||||
autodetect: Boolean;
|
||||
begin
|
||||
autodetect := (AFormatID = sfidUnknown);
|
||||
InternalLoadFromFile(AFileName, autodetect, AFormatID, AWorksheetIndex);
|
||||
InternalLoadFromFile(AFileName, autodetect, AFormatID, AWorksheetIndex, '');
|
||||
end;
|
||||
(*
|
||||
{@@ ------------------------------------------------------------------------------
|
||||
@ -1272,6 +1291,26 @@ begin
|
||||
InternalLoadFromWorkbook(AWorkbook, AWorksheetIndex);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Public loader of a spreadsheet file.
|
||||
|
||||
Should be called in case of password-protected files when the password is
|
||||
already known and no password dialog should appear.
|
||||
|
||||
Call this method for both built-in and user-provided file formats.
|
||||
|
||||
@param(AFilename Name of the spreadsheet file to be loaded.)
|
||||
@param(AFormatID Identifier of the spreadsheet file format assumed
|
||||
for the file.)
|
||||
@param(AWorksheetIndex Index of the worksheet to be selected after loading.
|
||||
(If empty then the active worksheet is loaded) )
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorkbookSource.LoadFromProtectedSpreadsheetFile(AFileName: String;
|
||||
AFormatID: TsSpreadFormatID; APassword: String; AWorksheetIndex: Integer = -1);
|
||||
begin
|
||||
InternalLoadFromFile(AFileName, false, AFormatID, AWorksheetIndex, APassword);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Notifies listeners of workbook, worksheet, cell, or selection changes.
|
||||
The changed item is identified by the parameter AChangedItems.
|
||||
|
Reference in New Issue
Block a user