home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2002 March
/
Chip_2002-03_cd1.bin
/
zkuste
/
delphi
/
kompon
/
d5
/
cak
/
CAKDIR.ZIP
/
Cabinet.pas
next >
Wrap
Pascal/Delphi Source File
|
2001-05-01
|
38KB
|
1,278 lines
{++
c a b i n e t . p a s
Copyright (c) 1997 by Alexander Staubo, all rights reserved.
Abstract:
Class framework wrapping around the Microsoft Cabinet SDK FCI and FDI
interfaces.
Known issues:
- Stream errors are not converted to error codes. Error handling in default
file handler/sevent handlers is strictly rudimentary. Exceptions are raised
upon API errors and are not handled responsibly.
- Only one TCabinetReader instance can be active at any time, due to a sordid
little limitation in the FDI API.
- fdintENUMERATE notification message is not handled in this version.
- Error codes in exceptions are not expanded into descriptive strings.
About event handlers:
The default event handlers of TCabinetReader and TCabinetWriter lessen the
work of performing common CAB ops for file-system-based cabinets, but
assume file handles are Win32 file handles; so they are incompatible with
non-file cabinet file handlers by default. This behaviour is controlled by
the FileSupport property of either object; turning this off disables the
file-handle support. For more information, see the component declarations
below.
The default implementation of OnGetTempFile uses the first three characters
in the module file name for the temporary file name.
Revision history:
26/12/1997 02:57 alexs 1.0
Initial release
--}
unit Cabinet;
interface
uses
Classes, SysUtils, Windows,fci,fdi;
{ Options for adding files }
type
TAddFileOption =
(
afoExecuteOnExtract
);
TAddFileOptions = set of TAddFileOption;
{ File type }
TFileType =
(
ftCabinet,
ftSource,
ftDestination
);
{ Compression type }
TCompressionType =
(
ctNone,
ctMsZip,
ctQuantum,
ctLzx
);
{ Parameters for compression }
TCompressionParameters =
record
Compression : TCompressionType;
LzxLevel : 15..21;
QuantumLevel : 1..7;
QuantumMemory : 10..21;
end;
{ CPU type for use in decompression }
TCpuType =
(
cptAuto,
cpt80286,
cpt80386
);
{ Action to take when copying file }
TFileCopyAction =
(
fcaAbort,
fcaSkip,
fcaCopy,
fcaDefaultCopy
);
{ Class forwards }
TCabinetInterface = class;
{ Writer events }
TFileStatusEvent = procedure (Sender : TObject; CompressedSize,
UncompressedSize : Longint; var ResultCode : Integer) of object;
TFolderStatusEvent = procedure (Sender : TObject; SizeCopied,
TotalSize : Longint; var ResultCode : Integer) of object;
TCabinetStatusEvent = procedure (Sender : TObject; PreEstimatedSize,
ActualSize : Longint; var WantedSize : Longint) of object;
TGetNextCabinetEvent = procedure (Sender : TObject;
var CabParameters : TCCAB; var NewCabFileName : string;
PreviousCabEstimatedSize : Longint; var AbortCreation : Boolean) of object;
TFilePlacedEvent = procedure (Sender : TObject; var CabParameters : TCCAB;
const FileName : string; FileLength : Longint; Continuation : Boolean;
var AbortProcessing : Boolean) of object;
TGetTempFileEvent = procedure (Sender : TObject; var TempFileName : string;
var Success : Boolean) of object;
TGetOpenInfoEvent = procedure (Sender : TObject; const FileName : string;
var Date, Time, Attributes : Smallint; var FileHandle,
ResultCode : Longint) of object;
{ Reader events }
TCabinetInfoEvent = procedure (Sender : TObject; const CabinetName,
CabinetDisk, CabinetPath : string; SetId, CabinetNumber : Longint;
var Abort : Boolean) of object;
TPartialFileEvent = procedure (Sender : TObject; const FileName,
FirstCabinetName, FirstCabinetDisk : string;
var Abort : Boolean) of object;
TCopyFileEvent = procedure (Sender : TObject; const FileName : string;
UncompressedSize : Longint; Date, Time, Attribs : Smallint;
var Action : TFileCopyAction; var DestFileHandle : Integer) of object;
TCloseCopiedFileEvent = procedure (Sender : TObject; const FileName : string;
FileHandle : Integer; Date, Time, Attribs : Smallint;
FolderIndex : Integer; Execute : Boolean; var Abort : Boolean) of object;
TNextCabinetEvent = procedure (Sender : TObject; const NextCabinetName,
NextCabinetDisk : string; var CabinetPath : string;
ErrorIndication : TFDIERROR; var Abort : Boolean) of object;
{ Classes }
{ TCabinetFileHandler abstract class -- represents a cabinet-associated file
handler. The class is used for reading source files (when compressing), for
writing destination files (when decompressing) and for reading and writing
to the cabinet file being processed
The methods mimick the behaviour of the C run-time library I/O API (_open,
_close, etc.) and must be implemented to accomodate these aspects. The API
has been augmented with an Win32 error code which is returned to the FCI
and FDI interfaces if they are filled in.
Open
Open a file and return its file handle. The FileType parameter
specifies the type of file to open: source, destination or cabinet.
Read
Read from an opened file.
Write
Write to an opened file.
Close
Close an opened file.
Seek
Seek to a position in an opened file.
Delete
Delete a file. }
TCabinetFileHandler =
class(TComponent)
public
function Open (const FileName : string; OpenFlag, OpenMode : Integer;
var Error : Integer; FileType : TFileType) : Integer; virtual;
abstract;
function Read (FileHandle : Integer; var Buffer;
Count : Integer; var Error : Integer) : Integer; virtual; abstract;
function Write (FileHandle : Integer; var Buffer;
Count : Integer; var Error : Integer) : Integer; virtual; abstract;
function Close (FileHandle : Integer; var Error : Integer)
: Integer; virtual; abstract;
function Seek (FileHandle : Integer; Distance : Longint;
SeekType : Integer; var Error : Integer) : Integer; virtual; abstract;
function Delete (const FileName : string; var Error : Integer)
: Integer; virtual; abstract;
end;
{ TStreamCabinetFileHandler class -- uses a collection of streams for
handling file access. The streams are accessed in the file system }
TStreamCabinetFileHandler =
class(TCabinetFileHandler)
protected
FStreams : TList;
function FindStream (Handle : Integer) : TStream;
public
constructor Create (AOwner : TComponent); override;
destructor Destroy; override;
function Open (const FileName : string; OpenFlag, OpenMode : Integer;
var Error : Integer; FileType : TFileType) : Integer; override;
function Read (FileHandle : Integer; var Buffer;
Count : Integer; var Error : Integer) : Integer; override;
function Write (FileHandle : Integer; var Buffer;
Count : Integer; var Error : Integer) : Integer; override;
function Close (FileHandle : Integer; var Error : Integer) : Integer;
override;
function Seek (FileHandle : Integer; Distance : Longint;
SeekType : Integer; var Error : Integer) : Integer; override;
function Delete (const FileName : string; var Error : Integer) : Integer;
override;
end;
{ TCabinetInterface base class -- abstract cabinet interface.
CabCheck
Check the result of a cabinet operation, and raise an ECabinetError
exception if the error buffer contains an error }
TCabinetInterface =
class(TComponent)
protected
FErrorBuffer : TERF;
FFileHandler : TCabinetFileHandler;
procedure CabCheck (Result : Boolean);
public
property FileHandler : TCabinetFileHandler read FFileHandler write FFileHandler;
end;
{ TCabinetWriter class -- for compressing files into a new cabinet file
DoFileStatus
DoFolderStatus
DoCabinetStatus
DoGetNextCabinet
DoFilePlaced
DoGetTempFile
DoGetOpenInfo
The virtual equivalents of their respective event handlers
(OnFileStatus etc.). These implement the minimal functionality required
for creating cabinets in the file system. In order to work with
non-file-system data, such as memory-mapped files or custom streams,
they must be overridden, or the event handlers assigned, to provide
the additional functionality
Open
Create a cabinet file for compression. CabinetFileName specifies the
file name. DiskName specifies the initial disk name (may be empty).
MaximumCabSize specifies the maximum size of the cabinet.
FolderThreshold specifies the folder threshold, which seems to be the
size, in bytes, of each logical cabinet folder. SetId specifies an
application-specific identifier that is stored in the cabinet
Close
Close the cabinet
AddFile
Add a file to the opened cabinet. SourceFileName specifies the name of
the file to add. DestFileName specifies the name as it is stored in the
cabinet. Specify afoExecuteOnExtract for Options if the file should be
executed upon extraction. Compression specifies the compression
parameters; use the MakeNoCompression, MakeMsZipCompression and
MakeLzxCompression helper functions to construct a value
FlushCabinet
Flush the cabinet. If GetNextCabinet is set to True, the
OnGetNextCabinet event is called to request further cabinet
information
FlushFolder
Flush the current folder and reset the compression state data
Properties:
Context
The FCI context
FailOnIncompressible
Fail compression if a file is found to be incompressible (compressed
size exceeds uncompressed size)
Events:
OnFileStatus
OnFolderStatus
OnCabinetStatus
OnGetNextCabinet
OnFilePlacedEvent
OnGetOpenInfo
OnGetTempFile
}
TCabinetWriter =
class(TCabinetInterface)
protected
FContext : HFCI;
FFailOnIncompressible : Boolean;
FFileSupport : Boolean;
FOnFileStatus : TFileStatusEvent;
FOnFolderStatus : TFolderStatusEvent;
FOnCabinetStatus : TCabinetStatusEvent;
FOnGetNextCabinet : TGetNextCabinetEvent;
FOnFilePlacedEvent : TFilePlacedEvent;
FOnGetOpenInfo : TGetOpenInfoEvent;
FOnGetTempFile : TGetTempFileEvent;
procedure DoFileStatus (CompressedSize, UncompressedSize : Longint;
var ResultCode : Integer); virtual;
procedure DoFolderStatus (SizeCopied, TotalSize : Longint;
var ResultCode : Integer); virtual;
procedure DoCabinetStatus (PreEstimatedSize, ActualSize : Longint;
var WantedSize : Longint); virtual;
procedure DoGetNextCabinet (var CabParameters : TCCAB;
var NewCabFileName : string; PreviousCabEstimatedSize : Longint;
var AbortCreation : Boolean); virtual;
procedure DoFilePlaced (var CabParameters : TCCAB;
const FileName : string; FileLength : Longint; Continuation : Boolean;
var AbortProcessing : Boolean); virtual;
procedure DoGetTempFile (var TempFileName : string;
var Success : Boolean); virtual;
procedure DoGetOpenInfo (const FileName : string; var Date, Time,
Attributes : Smallint; var FileHandle, ResultCode : Longint); virtual;
public
constructor Create (AOwner : TComponent); override;
destructor Destroy; override;
procedure Open (const CabinetFileName, DiskName : string;
MaximumCabSize, FolderThreshold, SetId : Longint);
procedure Close;
procedure AddFile (const SourceFileName, DestFileName : string;
const Options : TAddFileOptions;
const Compression : TCompressionParameters);
procedure FlushCabinet (GetNextCabinet : Boolean);
procedure FlushFolder;
property Context : HFCI read FContext;
published
property FailOnIncompressible : Boolean read FFailOnIncompressible
write FFailOnIncompressible default True;
property FileSupport : Boolean read FFileSupport write FFileSupport
default True;
property OnFileStatus : TFileStatusEvent read FOnFileStatus
write FOnFileStatus;
property OnFolderStatus : TFolderStatusEvent read FOnFolderStatus
write FOnFolderStatus;
property OnCabinetStatus : TCabinetStatusEvent read FOnCabinetStatus
write FOnCabinetStatus;
property OnGetNextCabinet : TGetNextCabinetEvent read FOnGetNextCabinet
write FOnGetNextCabinet;
property OnFilePlacedEvent : TFilePlacedEvent read FOnFilePlacedEvent
write FOnFilePlacedEvent;
property OnGetOpenInfo : TGetOpenInfoEvent read FOnGetOpenInfo
write FOnGetOpenInfo;
property OnGetTempFile : TGetTempFileEvent read FOnGetTempFile
write FOnGetTempFile;
property FileHandler;
end;
{ TCabinetReader class -- for decompressing files from an existing cabinet
file
Open
Opens a cabinet for reading. The associated file handler specified in
the FileHandler property is used to open the cabinet. The return value
is True if the specified file is a valid cabinet file, False if not }
TCabinetReader =
class(TCabinetInterface)
protected
FContext : HFDI;
FCpuType : TCpuType;
FDestinationPath : string;
FOnCabinetInfo : TCabinetInfoEvent;
FOnPartialFile : TPartialFileEvent;
FOnCopyFile : TCopyFileEvent;
FOnCloseCopiedFile : TCloseCopiedFileEvent;
FOnNextCabinet : TNextCabinetEvent;
FFileSupport : Boolean;
procedure DestroyContext;
procedure ContextNeeded;
procedure DoCabinetInfo (const CabinetName, CabinetDisk,
CabinetPath : string; SetId, CabinetNumber : Longint;
var Abort : Boolean); virtual;
procedure DoPartialFile (const FileName, FirstCabinetName,
FirstCabinetDisk : string; var Abort : Boolean); virtual;
procedure DoCopyFile (const FileName : string;
UncompressedSize : Longint; Date, Time, Attribs : Smallint;
var Action : TFileCopyAction; var DestFileHandle : Integer); virtual;
procedure DoCloseCopiedFile (const FileName : string;
FileHandle : Integer; Date, Time, Attribs : Smallint;
FolderIndex : Integer; Execute : Boolean; var Abort : Boolean);
virtual;
procedure DoNextCabinet (const NextCabinetName, NextCabinetDisk : string;
var CabinetPath : string; ErrorIndication : TFDIERROR;
var Abort : Boolean); virtual;
public
constructor Create (AOwner : TComponent); override;
destructor Destroy; override;
function IsCabinet (const FileName : string;
var CabInfo : TFDICABINETINFO) : Boolean;
procedure ExtractFiles (const FileName, DestinationPath : string;
Flags : Integer);
property Context : HFDI read FContext;
published
property CpuType : TCpuType read FCpuType write FCpuType;
property DestinationPath : string read FDestinationPath;
property FileSupport : Boolean read FFileSupport write FFileSupport
default True;
property OnCabinetInfo : TCabinetInfoEvent read FOnCabinetInfo
write FOnCabinetInfo;
property OnPartialFile : TPartialFileEvent read FOnPartialFile
write FOnPartialFile;
property OnCopyFile : TCopyFileEvent read FOnCopyFile write FOnCopyFile;
property OnCloseCopiedFile : TCloseCopiedFileEvent
read FOnCloseCopiedFile write FOnCloseCopiedFile;
property OnNextCabinet : TNextCabinetEvent read FOnNextCabinet
write FOnNextCabinet;
property FileHandler;
end;
{ Exceptions }
ECabinetError =
class(Exception)
ErrorCode : Integer;
ErrorType : Integer;
end;
{ Function declarations }
function MakeNoCompression : TCompressionParameters;
function MakeMsZipCompression : TCompressionParameters;
function MakeLzxCompression (Level : Integer) : TCompressionParameters;
procedure RaiseCabinetError (ErrorCode, ErrorType : Integer);
procedure CheckErf (Erf : TERF);
{ Registration }
procedure Register;
implementation
uses
Utility, Fcntl;
{ Private declarations }
type
TCabinetProcRec =
record
{ FCI/FDI }
FciAlloc : PFNFCIALLOC;
FciFree : PFNFCIFREE;
{ FCI }
FciOpen : PFNFCIOPEN;
FciRead : PFNFCIREAD;
FciWrite : PFNFCIWRITE;
FciClose : PFNFCICLOSE;
FciSeek : PFNFCISEEK;
FciDelete : PFNFCIDELETE;
FciGetTempFile : PFNFCIGETTEMPFILE;
FciFilePlaced : PFNFCIFILEPLACED;
FciGetNextCabinet : PFNFCIGETNEXTCABINET;
FciStatus : PFNFCISTATUS;
FciGetOpenInfo : PFNFCIGETOPENINFO;
{ FDI }
FdiOpen : PFNOPEN;
FdiRead : PFNREAD;
FdiWrite : PFNWRITE;
FdiClose : PFNCLOSE;
FdiSeek : PFNSEEK;
FdiNotify : PFNFDINOTIFY;
end;
{ Standard FCI/FDI procs }
function StdFciAlloc (cb : TULONG) : PVoid; cdecl;
begin
GetMem(Result, cb);
end;
function StdFciFree (memory : PVoid) : Pointer; cdecl;
begin
FreeMem(memory);
Result:=nil; //!! Correct?
end;
{ Standard FCI procs for TCabinetWriter }
function StdFciOpen (pszFile : PChar; oflag : Integer; pmode : Integer;
err : PInteger; pv : Pointer) : Integer; cdecl;
begin
err^:=0;
Result:=TCabinetInterface(pv).FileHandler.Open(string(pszFile), oflag, pmode,
err^, ftCabinet);
end;
function StdFciRead (hf : Integer; memory : PVoid; cb : TUINT;
err : PInteger; pv : Pointer) : TUINT; cdecl;
begin
err^:=0;
Result:=TCabinetInterface(pv).FileHandler.Read(hf, memory^, cb, err^);
end;
function StdFciWrite (hf : Integer; memory : PVoid; cb : TUINT;
err : PInteger; pv : Pointer) : TUINT; cdecl;
begin
err^:=0;
Result:=TCabinetInterface(pv).FileHandler.Write(hf, memory^, cb, err^);
end;
function StdFciClose (hf : Integer; err : PInteger; pv : Pointer) :
Integer; cdecl;
begin
err^:=0;
Result:=TCabinetInterface(pv).FileHandler.Close(hf, err^);
end;
function StdFciSeek (hf : Integer; dist : Longint; seektype : Integer;
err : PInteger; pv : Pointer) : Longint; cdecl;
begin
err^:=0;
Result:=TCabinetInterface(pv).FileHandler.Seek(hf, dist, seektype, err^);
end;
function StdFciDelete (pszFile : PChar; err : PInteger; pv : Pointer) :
Integer; cdecl;
begin
err^:=0;
Result:=TCabinetWriter(pv).FileHandler.Delete(string(pszFile), err^);
end;
function StdFciGetTempFile (pszTempName : PChar; cbTempName : Integer;
pv : Pointer) : Bool; cdecl;
var
Buffer : string;
Success : Boolean;
begin
Buffer:='';
TCabinetWriter(pv).DoGetTempFile(Buffer, Success);
if Success and (Length(Buffer) < cbTempName) then
begin
StrLCopy(pszTempName, PChar(Buffer), cbTempName - 1);
Result:=True;
end
else
Result:=False;
end;
function StdFciFilePlaced (pccab : PCCAB; pszFile : PChar;
cbFile : Longint; fContinuation : Bool; pv : Pointer) : Integer; cdecl;
var
Abort : Boolean;
begin
Abort:=False;
TCabinetWriter(pv).DoFilePlaced(pccab^, string(pszFile), cbFile,
Boolean(fContinuation), Abort);
if Abort then
Result:=-1
else
Result:=0;
end;
function StdFciGetOpenInfo (pszName : PChar; var pdate : TUSHORT;
var ptime : TUSHORT; var pattribs : TUSHORT; err : PInteger;
pv : Pointer) : Integer; cdecl;
var
FileHandle : Integer;
begin
FileHandle:=0;
TCabinetWriter(pv).DoGetOpenInfo(string(pszName), pdate, ptime, pattribs,
FileHandle, err^);
if err^ <> 0 then
Result:=-1
else
Result:=FileHandle;
end;
function StdFciGetNextCabinet (pccab : PCCAB; cbPrevCab : TULONG;
pv : Pointer) : Bool; cdecl;
var
Abort : Boolean;
NewFileName : string;
begin
Abort:=True;
NewFileName:='';
TCabinetWriter(pv).DoGetNextCabinet(pccab^, NewFileName, cbPrevCab, Abort);
if Abort then
begin
Result:=False;
Exit;
end;
StrCopy(pccab^.szCab, PChar(ExtractFileName(NewFileName)));
StrCopy(pccab^.szCabPath, PChar(ExtractFilePath(NewFileName)));
Result:=True;
end;
function StdFciStatus (typeStatus : TUINT; cb1 : TULONG; cb2 : TULONG;
pv : Pointer) : Longint; cdecl;
var
rc : Integer;
begin
rc:=0;
case typeStatus of
statusFile :
TCabinetWriter(pv).DoFileStatus(cb1, cb2, rc);
statusFolder :
TCabinetWriter(pv).DoFolderStatus(cb1, cb2, rc);
statusCabinet :
TCabinetWriter(pv).DoCabinetStatus(cb1, cb2, rc);
else
rc:=-1;
end;
Result:=rc;
end;
{ Standard FDI procs for TCabinetWriter }
var
GlobCabinetReader : TCabinetReader = nil;
function StdFdiOpen (pszFile : PChar; oflag : Integer; pmode : Integer)
: Integer; cdecl;
var
ErrorCode : Integer;
begin
Result:=GlobCabinetReader.FileHandler.Open(string(pszFile), oflag, pmode,
ErrorCode, ftCabinet);
end;
function StdFdiRead (hf : Integer; memory : PVoid; cb : TUINT) : TUINT; cdecl;
var
ErrorCode : Integer;
begin
Result:=GlobCabinetReader.FileHandler.Read(hf, memory^, cb, ErrorCode);
end;
function StdFdiWrite (hf : Integer; memory : PVoid; cb : TUINT) : TUINT; cdecl;
var
ErrorCode : Integer;
begin
Result:=GlobCabinetReader.FileHandler.Write(hf, memory^, cb, ErrorCode);
end;
function StdFdiClose (hf : Integer) : Integer; cdecl;
var
ErrorCode : Integer;
begin
Result:=GlobCabinetReader.FileHandler.Close(hf, ErrorCode);
end;
function StdFdiSeek (hf : Integer; dist : Longint; seektype : Integer)
: Longint; cdecl;
var
ErrorCode : Integer;
begin
Result:=GlobCabinetReader.FileHandler.Seek(hf, dist, seektype,
ErrorCode);
end;
function StdFdiNotify (fdint : TFDINOTIFICATIONTYPE; pfdin : PFDINOTIFICATION)
: Integer; cdecl;
var
Abort : Boolean;
Action : TFileCopyAction;
Handle : Integer;
CabPath : string;
begin
Abort:=False;
case fdint of
fdintCABINET_INFO :
TCabinetReader(pfdin^.pv).DoCabinetInfo(string(pfdin^.psz1),
string(pfdin^.psz2), string(pfdin^.psz3), pfdin^.setID,
pfdin^.iCabinet, Abort);
fdintPARTIAL_FILE :
TCabinetReader(pfdin^.pv).DoPartialFile(string(pfdin^.psz1),
string(pfdin^.psz2), string(pfdin^.psz3), Abort);
fdintCOPY_FILE :
begin
TCabinetReader(pfdin^.pv).DoCopyFile(string(pfdin^.psz1),
pfdin^.cb, pfdin^.date, pfdin^.time, pfdin^.attribs, Action, Handle);
if Action = fcaCopy then
Result:=Handle
else
Result:=Integer(Action) - 1;
Exit;
end;
fdintCLOSE_FILE_INFO :
begin
TCabinetReader(pfdin^.pv).DoCloseCopiedFile(string(pfdin^.psz1),
pfdin^.hf, pfdin^.date, pfdin^.time, pfdin^.attribs, pfdin^.iFolder,
pfdin^.cb = 1, Abort);
if not Abort then
begin
Result:=1;
Exit;
end;
end;
fdintNEXT_CABINET :
begin
CabPath:=string(pfdin^.psz3);
TCabinetReader(pfdin^.pv).DoNextCabinet(string(pfdin^.psz1),
string(pfdin^.psz2), CabPath, pfdin^.fdie, Abort);
StrLCopy(pfdin^.psz3, PChar(CabPath), SizeOf(pfdin^.psz3) - 1);
end;
fdintENUMERATE :
;
end;
if Abort then
Result:=-1
else
Result:=0;
end;
{ Cabinet procs }
const
StdCabinetProcs : TCabinetProcRec =
(
FciAlloc : StdFciAlloc;
FciFree : StdFciFree;
FciOpen : StdFciOpen;
FciRead : StdFciRead;
FciWrite : StdFciWrite;
FciClose : StdFciClose;
FciSeek : StdFciSeek;
FciDelete : StdFciDelete;
FciGetTempFile : StdFciGetTempFile;
FciFilePlaced : StdFciFilePlaced;
FciGetNextCabinet : StdFciGetNextCabinet;
FciStatus : StdFciStatus;
FciGetOpenInfo : StdFciGetOpenInfo;
FdiOpen : StdFdiOpen;
FdiRead : StdFdiRead;
FdiWrite : StdFdiWrite;
FdiClose : StdFdiClose;
FdiSeek : StdFdiSeek;
FdiNotify : StdFdiNotify;
);
{ TStreamCabinetFileHandler }
function TStreamCabinetFileHandler.FindStream (Handle : Integer) : TStream;
var
I : Integer;
begin
for I:=0 to FStreams.Count - 1 do
if TFileStream(FStreams.Items[I]).Handle = Handle then
begin
Result:=TStream(FStreams.Items[I]);
Exit;
end;
Result:=nil;
end;
constructor TStreamCabinetFileHandler.Create (AOwner : TComponent);
begin
inherited Create(AOwner);
FStreams:=TList.Create;
end;
destructor TStreamCabinetFileHandler.Destroy;
var
Stream : TStream;
begin
while FStreams.Count > 0 do
begin
Stream:=FStreams.Last;
Stream.Free;
FStreams.Remove(Stream);
end;
inherited Destroy;
end;
function TStreamCabinetFileHandler.Open (const FileName : string; OpenFlag,
OpenMode : Integer; var Error : Integer; FileType : TFileType) : Integer;
var
Mode : Word;
Stream : TFileStream;
begin
if OpenFlag and _O_CREAT <> 0 then
Mode:=fmCreate
else
begin
Mode:=0;
if OpenFlag and _O_WRONLY <> 0 then
Mode:=Mode or fmOpenWrite
else
Mode:=Mode or fmOpenRead;
if OpenFlag and _O_EXCL <> 0 then
Mode:=Mode or fmShareExclusive
else
Mode:=Mode or fmShareDenyNone;
end;
try
Stream:=TFileStream.Create(FileName, Mode);
except
on EFOpenError do
begin
Error:=GetLastError;
Result:=-1;
Exit;
end;
on EFCreateError do
begin
Error:=GetLastError;
Result:=-1;
Exit;
end;
end;
FStreams.Add(Stream);
Error:=0;
Result:=Stream.Handle;
end;
function TStreamCabinetFileHandler.Read (FileHandle : Integer; var Buffer;
Count : Integer; var Error : Integer) : Integer;
var
Stream : TStream;
begin
Stream:=FindStream(FileHandle);
if Stream <> nil then
begin
Result:=Stream.Read(Buffer, Count);
if Result <> Count then
Error:=GetLastError
else
Error:=0;
end
else
begin
Error:=-1;
Result:=0;
end;
end;
function TStreamCabinetFileHandler.Write (FileHandle : Integer; var Buffer;
Count : Integer; var Error : Integer) : Integer;
var
Stream : TStream;
begin
Stream:=FindStream(FileHandle);
if Stream <> nil then
begin
Result:=Stream.Write(Buffer, Count);
if Result <> Count then
Error:=GetLastError
else
Error:=0;
end
else
begin
Error:=-1;
Result:=0;
end;
end;
function TStreamCabinetFileHandler.Close (FileHandle : Integer;
var Error : Integer) : Integer;
var
Stream : TStream;
begin
Stream:=FindStream(FileHandle);
if Stream <> nil then
begin
FStreams.Remove(Stream);
Stream.Free;
end;
Error:=0;
Result:=0;
end;
function TStreamCabinetFileHandler.Seek (FileHandle : Integer;
Distance : Longint; SeekType : Integer; var Error : Integer) : Integer;
var
Stream : TStream;
begin
Stream:=FindStream(FileHandle);
if Stream <> nil then
begin
Result:=Stream.Seek(Distance, SeekType);
Error:=0;
end
else
begin
Error:=-1;
Result:=0;
end;
end;
function TStreamCabinetFileHandler.Delete (const FileName : string;
var Error : Integer) : Integer;
begin
if not DeleteFile(PChar(FileName)) then
Error:=GetLastError
else
Error:=0;
Result:=0;
end;
{ TCabinetInterface }
procedure TCabinetInterface.CabCheck (Result : Boolean);
begin
if not Result then
CheckErf(FErrorBuffer);
end;
{ TCabinetWriter }
procedure TCabinetWriter.DoFileStatus (CompressedSize,
UncompressedSize : Longint; var ResultCode : Integer);
begin
if Assigned(FOnFileStatus) then
FOnFileStatus(Self, CompressedSize, UncompressedSize, ResultCode);
end;
procedure TCabinetWriter.DoFolderStatus (SizeCopied, TotalSize : Longint;
var ResultCode : Integer);
begin
if Assigned(FOnFolderStatus) then
FOnFolderStatus(Self, SizeCopied, TotalSize, ResultCode);
end;
procedure TCabinetWriter.DoCabinetStatus (PreEstimatedSize,
ActualSize : Longint; var WantedSize : Longint);
begin
if Assigned(FOnCabinetStatus) then
FOnCabinetStatus(Self, PreEstimatedSize, ActualSize, WantedSize);
end;
procedure TCabinetWriter.DoGetNextCabinet (var CabParameters : TCCAB;
var NewCabFileName : string; PreviousCabEstimatedSize : Longint;
var AbortCreation : Boolean);
begin
if Assigned(FOnGetNextCabinet) then
FOnGetNextCabinet(Self, CabParameters, NewCabFileName,
PreviousCabEstimatedSize, AbortCreation);
end;
procedure TCabinetWriter.DoFilePlaced (var CabParameters : TCCAB;
const FileName : string; FileLength : Longint; Continuation : Boolean;
var AbortProcessing : Boolean);
begin
if Assigned(FOnFilePlacedEvent) then
FOnFilePlacedEvent(Self, CabParameters, FileName, FileLength, Continuation,
AbortProcessing);
end;
procedure TCabinetWriter.DoGetTempFile (var TempFileName : string;
var Success : Boolean);
begin
if Assigned(FOnGetTempFile) then
FOnGetTempFile(Self, TempFileName, Success)
else
begin
TempFileName:=GetTempFileNameStr(GetTempPathStr,
Copy(ExtractFileName(ParamStr(0)), 1, 3), 0);
Success:=True;
end
end;
procedure TCabinetWriter.DoGetOpenInfo (const FileName : string; var Date,
Time, Attributes : Smallint; var FileHandle, ResultCode : Longint);
var
FileTime : TFileTime;
begin
if Assigned(FOnGetOpenInfo) then
begin
FOnGetOpenInfo(Self, FileName, Date, Time, Attributes, FileHandle,
ResultCode);
end
else
begin
if FFileSupport then
begin
Attributes:=Word(GetFileAttributes(PChar(FileName)));
if Attributes = Word(-1) then
begin
ResultCode:=GetLastError;
Exit;
end;
end
else
Attributes:=0;
FileHandle:=FFileHandler.Open(FileName, _O_RDONLY or _O_BINARY, 0,
ResultCode, ftSource);
if ResultCode = 0 then
begin
Date:=0;
Time:=0;
if FFileSupport and GetFileTime(FileHandle, nil, nil, @FileTime) then
FileTimeToDosDateTime(FileTime, Word(Date), Word(Time));
end;
end;
end;
constructor TCabinetWriter.Create (AOwner : TComponent);
begin
inherited Create(AOwner);
FFileSupport:=True;
FFailOnIncompressible:=True;
end;
destructor TCabinetWriter.Destroy;
begin
Close;
inherited Destroy;
end;
procedure TCabinetWriter.Open (const CabinetFileName, DiskName : string;
MaximumCabSize, FolderThreshold, SetId : Longint);
var
Parameters : TCCAB;
begin
Close;
FillChar(Parameters, SizeOf(Parameters), 0);
Parameters.cb:=MaximumCabSize;
Parameters.cbFolderThresh:=FolderThreshold;
Parameters.fFailOnIncompressible:=Integer(FFailOnIncompressible);
Parameters.setID:=SetId;
StrCopy(Parameters.szDisk, PChar(DiskName));
StrCopy(Parameters.szCab, PChar(ExtractFileName(CabinetFileName)));
StrCopy(Parameters.szCabPath, PChar(ExtractFilePath(CabinetFileName)));
FContext:=FCICreate(@FErrorBuffer, StdCabinetProcs.FciFilePlaced,
StdCabinetProcs.FciAlloc, StdCabinetProcs.FciFree, StdCabinetProcs.FciOpen,
StdCabinetProcs.FciRead, StdCabinetProcs.FciWrite,
StdCabinetProcs.FciClose, StdCabinetProcs.FciSeek,
StdCabinetProcs.FciDelete, StdCabinetProcs.FciGetTempFile, @Parameters,
Pointer(Self));
CabCheck(FContext <> nil);
end;
procedure TCabinetWriter.Close;
begin
if FContext <> nil then
begin
CabCheck(FCIDestroy(FContext));
FContext:=nil;
end;
end;
procedure TCabinetWriter.AddFile (const SourceFileName, DestFileName : string;
const Options : TAddFileOptions; const Compression : TCompressionParameters);
var
Compress : TCOMP;
begin
Compress:=Integer(Compression.Compression);
case Compression.Compression of
ctQuantum :
Compress:=Compress or
(Compression.QuantumLevel shl tcompSHIFT_QUANTUM_LEVEL) or
(Compression.QuantumMemory shl tcompSHIFT_QUANTUM_MEM);
ctLzx :
Compress:=Compress or (Compression.LzxLevel shl tcompSHIFT_LZX_WINDOW);
end;
CabCheck(FCIAddFile(FContext, PChar(SourceFileName), PChar(DestFileName),
afoExecuteOnExtract in Options, StdCabinetProcs.FciGetNextCabinet,
StdCabinetProcs.FciStatus, StdCabinetProcs.FciGetOpenInfo, Compress));
end;
procedure TCabinetWriter.FlushCabinet (GetNextCabinet : Boolean);
begin
CabCheck(FCIFlushCabinet(FContext, GetNextCabinet,
StdCabinetProcs.FciGetNextCabinet, StdCabinetProcs.FciStatus));
end;
procedure TCabinetWriter.FlushFolder;
begin
CabCheck(FCIFlushFolder(FContext, StdCabinetProcs.FciGetNextCabinet,
StdCabinetProcs.FciStatus));
end;
{ TCabinetReader }
procedure TCabinetReader.DestroyContext;
begin
if FContext <> nil then
begin
GlobCabinetReader:=Self;
CabCheck(FDIDestroy(FContext));
FContext:=nil;
end;
end;
procedure TCabinetReader.ContextNeeded;
begin
if FContext = nil then
begin
GlobCabinetReader:=Self;
FContext:=FDICreate(StdCabinetProcs.FciAlloc, StdCabinetProcs.FciFree,
StdCabinetProcs.FdiOpen, StdCabinetProcs.FdiRead,
StdCabinetProcs.FdiWrite, StdCabinetProcs.FdiClose,
StdCabinetProcs.FdiSeek, Integer(FCpuType) - 1, @FErrorBuffer);
CabCheck(FContext <> nil);
end;
end;
procedure TCabinetReader.DoCabinetInfo (const CabinetName, CabinetDisk,
CabinetPath : string; SetId, CabinetNumber : Longint;
var Abort : Boolean);
begin
if Assigned(FOnCabinetInfo) then
FOnCabinetInfo(Self, CabinetName, CabinetDisk, CabinetPath, SetId,
CabinetNumber, Abort);
end;
procedure TCabinetReader.DoPartialFile (const FileName, FirstCabinetName,
FirstCabinetDisk : string; var Abort : Boolean);
begin
if Assigned(FOnPartialFile) then
FOnPartialFile(Self, FileName, FirstCabinetName, FirstCabinetDisk, Abort);
end;
procedure TCabinetReader.DoCopyFile (const FileName : string;
UncompressedSize : Longint; Date, Time, Attribs : Smallint;
var Action : TFileCopyAction; var DestFileHandle : Integer);
var
ErrorCode : Integer;
begin
if Assigned(FOnCopyFile) then
begin
Action:=fcaCopy;
FOnCopyFile(Self, FileName, UncompressedSize, Date, Time, Attribs, Action,
DestFileHandle);
end
else
Action:=fcaDefaultCopy;
if Action = fcaDefaultCopy then
begin
Action:=fcaCopy;
DestFileHandle:=FFileHandler.Open(FDestinationPath + FileName,
_O_CREAT or _O_BINARY, 0, ErrorCode, ftDestination);
end;
end;
procedure TCabinetReader.DoCloseCopiedFile (const FileName : string;
FileHandle : Integer; Date, Time, Attribs : Smallint;
FolderIndex : Integer; Execute : Boolean; var Abort : Boolean);
var
ErrorCode : Integer;
FileTime : TFileTime;
begin
if Assigned(FOnCloseCopiedFile) then
FOnCloseCopiedFile(Self, FileName, FileHandle, Date, Time, Attribs,
FolderIndex, Execute, Abort)
else
begin
if FFileSupport then
begin
ApiCheck(DosDateTimeToFileTime(Word(Date), Word(Time), FileTime));
ApiCheck(SetFileTime(FileHandle, nil, nil, @FileTime));
end;
FFileHandler.Close(FileHandle, ErrorCode);
if FFileSupport then
ApiCheck(SetFileAttributes(PChar(FDestinationPath + FileName),
Attribs));
end;
end;
procedure TCabinetReader.DoNextCabinet (const NextCabinetName,
NextCabinetDisk : string; var CabinetPath : string;
ErrorIndication : TFDIERROR; var Abort : Boolean);
begin
if Assigned(FOnNextCabinet) then
FOnNextCabinet(Self, NextCabinetName, NextCabinetDisk, CabinetPath,
ErrorIndication, Abort);
end;
constructor TCabinetReader.Create (AOwner : TComponent);
begin
inherited Create(AOwner);
FFileSupport:=True;
end;
destructor TCabinetReader.Destroy;
begin
DestroyContext;
inherited Destroy;
end;
function TCabinetReader.IsCabinet (const FileName : string;
var CabInfo : TFDICABINETINFO) : Boolean;
var
ErrorCode, FileHandle : Integer;
begin
ContextNeeded;
GlobCabinetReader:=Self;
FileHandle:=FFileHandler.Open(FileName, _O_RDONLY or _O_BINARY, 0, ErrorCode,
ftCabinet);
if ErrorCode <> 0 then
RaiseCabinetError(-1, ErrorCode);
try
Result:=FDIIsCabinet(FContext, FileHandle, @CabInfo);
finally
FFileHandler.Close(FileHandle, ErrorCode);
if ErrorCode <> 0 then
RaiseCabinetError(-1, ErrorCode);
end;
end;
procedure TCabinetReader.ExtractFiles (const FileName,
DestinationPath : string; Flags : Integer);
begin
ContextNeeded;
GlobCabinetReader:=Self;
FDestinationPath:=AddBkSlash(DestinationPath);
CabCheck(FDICopy(FContext, PChar(ExtractFileName(FileName)),
PChar(ExtractFilePath(FileName)), Flags, StdCabinetProcs.FdiNotify, nil,
Pointer(Self)));
end;
{ Functions }
function MakeNoCompression : TCompressionParameters;
begin
Result.Compression:=ctNone;
end;
function MakeMsZipCompression : TCompressionParameters;
begin
Result.Compression:=ctMsZip;
end;
function MakeLzxCompression (Level : Integer) : TCompressionParameters;
begin
Result.Compression:=ctLzx;
Result.LzxLevel:=Level;
end;
procedure RaiseCabinetError (ErrorCode, ErrorType : Integer);
var
E : ECabinetError;
begin
E:=ECabinetError.CreateFmt('Cabinet error %d (type %d)',
[ErrorCode, ErrorType]);
E.ErrorCode:=ErrorCode;
E.ErrorType:=ErrorType;
if (ErrorCode<>11) then raise E;
end;
procedure CheckErf (Erf : TERF);
begin
if Bool(Erf.fError) then
RaiseCabinetError(Erf.erfOper, Erf.erfType);
end;
procedure Register;
begin
RegisterComponents('Library', [TCabinetWriter, TCabinetReader,
TStreamCabinetFileHandler]);
end;
end.