fpspreadsheet: Use file header to distinguish between Excel2, Excel5 and Excel8 file formats, avoids the exception when trying an incorrect file format.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3744 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-11-18 13:53:27 +00:00
parent 396caef541
commit 0f3a6dcbfb
2 changed files with 90 additions and 4 deletions

View File

@ -977,7 +977,10 @@ type
{ Base methods }
constructor Create;
destructor Destroy; override;
class function GetFormatFromFileName(const AFileName: TFileName; out SheetType: TsSpreadsheetFormat): Boolean;
class function GetFormatFromFileHeader(const AFileName: TFileName;
out SheetType: TsSpreadsheetFormat): Boolean;
class function GetFormatFromFileName(const AFileName: TFileName;
out SheetType: TsSpreadsheetFormat): Boolean;
function CreateSpreadReader(AFormat: TsSpreadsheetFormat): TsCustomSpreadReader;
function CreateSpreadWriter(AFormat: TsSpreadsheetFormat): TsCustomSpreadWriter;
procedure ReadFromFile(AFileName: string; AFormat: TsSpreadsheetFormat); overload;
@ -6287,6 +6290,83 @@ begin
inherited Destroy;
end;
{@@ ----------------------------------------------------------------------------
Helper method for determining the spreadsheet type. Read the first few bytes
of a file and determines the spreadsheet type from the characteristic
signature. Only implemented for xls files where several file types have the
same extension
-------------------------------------------------------------------------------}
class function TsWorkbook.GetFormatFromFileHeader(const AFileName: TFileName;
out SheetType: TsSpreadsheetFormat): Boolean;
const
BIFF2_HEADER: array[0..15] of byte = (
$09,$00, $04,$00, $00,$00, $10,$00, $31,$00, $0A,$00, $C8,$00, $00,$00);
BIFF58_HEADER: array[0..15] of byte = (
$D0,$CF, $11,$E0, $A1,$B1, $1A,$E1, $00,$00, $00,$00, $00,$00, $00,$00);
BIFF5_MARKER: array[0..7] of widechar = (
'B', 'o', 'o', 'k', #0, #0, #0, #0);
BIFF8_MARKER:array[0..7] of widechar = (
'W', 'o', 'r', 'k', 'b', 'o', 'o', 'k');
var
buf: packed array[0..16] of byte;
stream: TStream;
i: Integer;
ok: Boolean;
begin
Result := false;
stream := TFileStream.Create(AFileName, fmOpenRead + fmShareDenyNone);
try
// Read first 16 bytes
stream.ReadBuffer(buf, 16);
// Check for Excel 2#
ok := true;
for i:=0 to 15 do
if buf[i] <> BIFF2_HEADER[i] then
begin
ok := false;
break;
end;
if ok then
begin
SheetType := sfExcel2;
Exit(True);
end;
// Check for Excel 5 or 8
for i:=0 to 15 do
if buf[i] <> BIFF58_HEADER[i] then
exit;
// Further information begins at offset $480:
stream.Position := $480;
stream.ReadBuffer(buf, 16);
// Check for Excel5
ok := true;
for i:=0 to 7 do
if WideChar(buf[i*2]) <> BIFF5_MARKER[i] then
begin
ok := false;
break;
end;
if ok then
begin
SheetType := sfExcel5;
Exit(True);
end;
// Check for Excel8
ok := true;
for i:=0 to 7 do
if WideChar(buf[i*2]) <> BIFF8_MARKER[i] then
exit;
SheetType := sfExcel8;
Exit(True);
finally
stream.Free;
end;
end;
{@@ ----------------------------------------------------------------------------
Helper method for determining the spreadsheet type from the file type extension
@ -6447,7 +6527,11 @@ begin
if not FileExists(AFileName) then
raise Exception.CreateFmt(rsFileNotFound, [AFileName]);
valid := GetFormatFromFileName(AFileName, SheetType);
if Lowercase(ExtractFileExt(AFileName))=STR_EXCEL_EXTENSION then
valid := GetFormatFromFileHeader(AFileName, SheetType)
else
valid := GetFormatFromFileName(AFileName, SheetType);
if valid then
begin
if SheetType = sfExcel8 then

View File

@ -1574,7 +1574,8 @@ var
fnt: TsFont;
begin
fnt := GetCellFont(ACell);
ItemIndex := Items.IndexOf(fnt.FontName);
if fnt <> nil then
ItemIndex := Items.IndexOf(fnt.FontName);
end;
procedure TsFontNameCombobox.Populate;
@ -1611,7 +1612,8 @@ var
fnt: TsFont;
begin
fnt := GetCellFont(ACell);
ItemIndex := Items.IndexOf(Format('%.0f', [fnt.Size]));
if fnt <> nil then
ItemIndex := Items.IndexOf(Format('%.0f', [fnt.Size]));
end;
procedure TsFontSizeCombobox.Populate;