fpspreadsheet: Further improvement of file format detection. Use it in BIFFExplorer as well.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3907 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2015-01-29 11:39:01 +00:00
parent b765956574
commit f4bf29da87
2 changed files with 47 additions and 43 deletions

View File

@ -6420,8 +6420,8 @@ end;
class function TsWorkbook.GetFormatFromFileHeader(const AFileName: TFileName; class function TsWorkbook.GetFormatFromFileHeader(const AFileName: TFileName;
out SheetType: TsSpreadsheetFormat): Boolean; out SheetType: TsSpreadsheetFormat): Boolean;
const const
BIFF2_HEADER: array[0..15] of byte = ( BIFF2_HEADER: array[0..3] of byte = (
$09,$00, $04,$00, $00,$00, $10,$00, $31,$00, $0A,$00, $C8,$00, $00,$00); $09,$00, $04,$00); // they are common to all BIFF2 files that I've seen
BIFF58_HEADER: array[0..7] of byte = ( BIFF58_HEADER: array[0..7] of byte = (
$D0,$CF, $11,$E0, $A1,$B1, $1A,$E1); $D0,$CF, $11,$E0, $A1,$B1, $1A,$E1);
@ -6440,7 +6440,7 @@ const
end; end;
var var
buf: packed array[0..16] of byte = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); buf: packed array[0..7] of byte = (0,0,0,0,0,0,0,0);
stream: TStream; stream: TStream;
i: Integer; i: Integer;
ok: Boolean; ok: Boolean;
@ -6448,12 +6448,12 @@ begin
Result := false; Result := false;
stream := TFileStream.Create(AFileName, fmOpenRead + fmShareDenyNone); stream := TFileStream.Create(AFileName, fmOpenRead + fmShareDenyNone);
try try
// Read first 16 bytes // Read first 8 bytes
stream.ReadBuffer(buf, 16); stream.ReadBuffer(buf, 8);
// Check for Excel 2 // Check for Excel 2
ok := true; ok := true;
for i:=0 to 15 do for i:=0 to High(BIFF2_HEADER) do
if buf[i] <> BIFF2_HEADER[i] then if buf[i] <> BIFF2_HEADER[i] then
begin begin
ok := false; ok := false;
@ -6466,7 +6466,7 @@ begin
end; end;
// Check for Excel 5 or 8 // Check for Excel 5 or 8
for i:=0 to 7 do for i:=0 to High(BIFF58_HEADER) do
if buf[i] <> BIFF58_HEADER[i] then if buf[i] <> BIFF58_HEADER[i] then
exit; exit;

View File

@ -19,6 +19,9 @@ function GetFormatFromFileHeader(const AFileName: TFileName;
implementation implementation
uses
uvirtuallayer_ole;
function CreateIni : TCustomIniFile; function CreateIni : TCustomIniFile;
var var
cfg : string; cfg : string;
@ -89,31 +92,40 @@ end;
function GetFormatFromFileHeader(const AFileName: TFileName; function GetFormatFromFileHeader(const AFileName: TFileName;
out SheetType: TsSpreadsheetFormat): Boolean; out SheetType: TsSpreadsheetFormat): Boolean;
const const
BIFF2_HEADER: array[0..15] of byte = ( BIFF2_HEADER: array[0..3] of byte = (
$09,$00, $04,$00, $00,$00, $10,$00, $31,$00, $0A,$00, $C8,$00, $00,$00); $09,$00, $04,$00); // they are common to all BIFF2 files that I've seen
BIFF58_HEADER: array[0..15] of byte = ( BIFF58_HEADER: array[0..7] of byte = (
$D0,$CF, $11,$E0, $A1,$B1, $1A,$E1, $00,$00, $00,$00, $00,$00, $00,$00); $D0,$CF, $11,$E0, $A1,$B1, $1A,$E1);
BIFF5_MARKER: array[0..7] of widechar = (
'B', 'o', 'o', 'k', #0, #0, #0, #0); function ValidOLEStream(AStream: TStream; AName: String): Boolean;
BIFF8_MARKER:array[0..7] of widechar = (
'W', 'o', 'r', 'k', 'b', 'o', 'o', 'k');
var var
buf: packed array[0..16] of byte; fsOLE: TVirtualLayer_OLE;
begin
AStream.Position := 0;
fsOLE := TVirtualLayer_OLE.Create(AStream);
try
fsOLE.Initialize;
Result := fsOLE.FileExists('/'+AName);
finally
fsOLE.Free;
end;
end;
var
buf: packed array[0..7] of byte = (0,0,0,0,0,0,0,0);
stream: TStream; stream: TStream;
i: Integer; i: Integer;
ok: Boolean; ok: Boolean;
begin begin
buf[0] := 0; // Silence the compiler...
Result := false; Result := false;
stream := TFileStream.Create(AFileName, fmOpenRead + fmShareDenyNone); stream := TFileStream.Create(AFileName, fmOpenRead + fmShareDenyNone);
try try
// Read first 16 bytes // Read first 8 bytes
stream.ReadBuffer(buf, 16); stream.ReadBuffer(buf, 8);
// Check for Excel 2# // Check for Excel 2
ok := true; ok := true;
for i:=0 to 15 do for i:=0 to High(BIFF2_HEADER) do
if buf[i] <> BIFF2_HEADER[i] then if buf[i] <> BIFF2_HEADER[i] then
begin begin
ok := false; ok := false;
@ -126,32 +138,24 @@ begin
end; end;
// Check for Excel 5 or 8 // Check for Excel 5 or 8
for i:=0 to 15 do for i:=0 to High(BIFF58_HEADER) do
if buf[i] <> BIFF58_HEADER[i] then if buf[i] <> BIFF58_HEADER[i] then
exit; exit;
// Further information begins at offset $480: // Now we know that the file is a Microsoft compound document.
stream.Position := $480;
stream.ReadBuffer(buf, 16); // We check for Excel 5 in which the stream is named "Book"
// Check for Excel5 if ValidOLEStream(stream, 'Book') then begin
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; SheetType := sfExcel5;
Exit(True); exit(True);
end; end;
// Check for Excel8
for i:=0 to 7 do // Now we check for Excel 8 which names the stream "Workbook"
if WideChar(buf[i*2]) <> BIFF8_MARKER[i] then if ValidOLEStream(stream, 'Workbook') then begin
exit(false);
SheetType := sfExcel8; SheetType := sfExcel8;
Exit(True); exit(True);
end;
finally finally
stream.Free; stream.Free;
end; end;