git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.jvcl@19 7f62d464-2af8-f54e-996c-e91b33f51cbe
606 lines
21 KiB
ObjectPascal
606 lines
21 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: JvZlibMultiple.PAS, released on 2001-02-28.
|
|
|
|
The Initial Developer of the Original Code is S?stien Buysse [sbuysse att buypin dott com]
|
|
Portions created by S?stien Buysse are Copyright (C) 2001 S?stien Buysse.
|
|
All Rights Reserved.
|
|
|
|
Contributor(s): Michael Beck [mbeck att bigfoot dott com].
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
|
|
located at http://jvcl.delphi-jedi.org
|
|
|
|
Known Issues:
|
|
2004-07-27 - Read the 'ALL USERS READ THIS' section below.
|
|
-----------------------------------------------------------------------------}
|
|
// $Id: JvZlibMultiple.pas 12505 2009-09-16 18:42:08Z wpostma $
|
|
|
|
{$I jvcl.inc}
|
|
|
|
unit JvZlibMultiple;
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF UNITVERSIONING}
|
|
JclUnitVersioning,
|
|
{$ENDIF UNITVERSIONING}
|
|
{$IFDEF MSWINDOWS}
|
|
Windows, // inline
|
|
{$ENDIF MSWINDOWS}
|
|
SysUtils, Classes, Graphics, Controls, Dialogs,
|
|
JclCompression,
|
|
JvComponentBase;
|
|
|
|
// ----------------------------------------------------------------------------}
|
|
// 2004-07-27 *** ALL USERS READ THIS: (wpostma) ***
|
|
//
|
|
// I have added support for selective extraction and listing archive contents without
|
|
// writing any files to disk. To do this we had to add some parameters to the component events.
|
|
//
|
|
// This will break existing applications that use these events, until they update their
|
|
// event declarations, to add the new parameters to your events.
|
|
//
|
|
// This is something the Delphi IDE should do automatically, but does not do. <grin>
|
|
//
|
|
// The old events for OnDecompressingFile, and OnDecompressedFile
|
|
// look like this:
|
|
// procedure <<TMyForm.MyEventHandlerName>>(Sender: TObject; const FileName: string)
|
|
//
|
|
// The new events have an additional parameter each:
|
|
//
|
|
// OnDecompressingFile -> (Sender: TObject; const FileName: string;
|
|
// {NEW!} var WriteFile: Boolean )
|
|
// OnDecompressedFile -> (Sender: TObject; const FileName: string;
|
|
// {NEW!} const FileSize: Longword )
|
|
//
|
|
// -----------------------------------------------------------------------------}
|
|
|
|
{ November 11, 2005 - yozey
|
|
|
|
NOTE #1
|
|
Added new procedures to pause and terminate the compression process.
|
|
These would be very useful in a threaded environment.
|
|
|
|
NOTE #2 December 22, 2005 - Johann Campbell
|
|
- Added new procedure to list files stored in the zlib file ( basic rewrite of the decompression procedure )
|
|
- Exposed the Pause and Terminate procedures
|
|
|
|
See below.
|
|
}
|
|
|
|
type
|
|
{NEW:}
|
|
TFileBeforeWriteEvent = procedure(Sender: TObject; const FileName: string; var WriteFile: Boolean) of object;
|
|
TFileAfterWriteEvent = procedure(Sender: TObject; const FileName: string; const FileSize: Longword) of object;
|
|
|
|
TFileSkipEvent = procedure (Sender:Tobject;const Filename,errortype,errormessage:String);
|
|
|
|
TFileEvent = procedure(Sender: TObject; const FileName: string) of object;
|
|
TProgressEvent = procedure(Sender: TObject; Position, Total: Integer) of object;
|
|
|
|
TJvZlibMultiple = class(TJvComponent)
|
|
private
|
|
FStorePaths: Boolean;
|
|
FIgnoreExclusive: Boolean; // November 7, 2004 - USE WITH CAUTION !!!!!
|
|
FCompressionLevel: TJclCompressionLevel;
|
|
FOnProgress: TProgressEvent;
|
|
FOnCompressingFile: TFileEvent;
|
|
FOnCompressedFile: TFileEvent;
|
|
FOnCompletedAction: TNotifyEvent;
|
|
FOnFileSkip : TFileSkipEvent;
|
|
|
|
// July 26, 2004: New improved event types for decompression: Allow user to
|
|
// skip writing of files they want skipped on extraction, and if they
|
|
// extract nothing, they can use this "nil extraction" to scan the contents
|
|
// of the file, returning the file names and sizes inside.
|
|
FOnDecompressingFile: TFileBeforeWriteEvent;
|
|
FOnDecompressedFile: TFileAfterWriteEvent;
|
|
FTerminateCompress: Boolean; // Note #1
|
|
FTerminateDecompress: Boolean; // Note #1
|
|
FCompressionPause: Boolean; // Note #1
|
|
FDecompressionPause: Boolean; // Note #1
|
|
FForceDirectoriesFlag: Boolean;
|
|
procedure SetForceDirectoriesFlag(const Value: Boolean); // set true to force directories
|
|
protected
|
|
procedure AddFile(const FileName, Directory, FilePath: string; DestStream: TStream);
|
|
procedure DoProgress(Position, Total: Integer); virtual;
|
|
procedure DoStopCompression; // Note #1
|
|
procedure DoStopDecompression; // Note #1
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
// compresses a list of files (can contain wildcards)
|
|
// NOTE: caller must free returned stream!
|
|
function CompressFiles(Files: TStrings): TStream; overload;
|
|
// compresses a list of files (can contain wildcards)
|
|
// and saves the compressed result to FileName
|
|
procedure CompressFiles(Files: TStrings; const FileName: string); overload;
|
|
// compresses a Directory (recursing if Recursive is true)
|
|
// NOTE: caller must free returned stream!
|
|
function CompressDirectory(Directory: string; Recursive: Boolean): TStream; overload;
|
|
// compresses a Directory (recursing if Recursive is true)
|
|
// and saves the compressed result to FileName
|
|
procedure CompressDirectory(const Directory: string; Recursive: Boolean; const FileName: string); overload;
|
|
// decompresses FileName into Directory. If Overwrite is true, overwrites any existing files with
|
|
// the same name as those in the compressed archive.
|
|
// If RelativePaths is true, the paths in the compressed file are stripped from their drive letter
|
|
procedure DecompressFile(const FileName, Directory: string; Overwrite: Boolean;
|
|
const RelativePaths: Boolean = True);
|
|
// decompresses Stream into Directory optionally overwriting any existing files
|
|
// If RelativePaths is true, any paths in the stream are stripped from their drive letter
|
|
procedure ListStoredFiles(const FileName: string; FileList: TStrings); // Note #2
|
|
procedure DecompressStream(Stream: TStream; Directory: string; Overwrite: Boolean;
|
|
const RelativePaths: Boolean = True);
|
|
procedure StopCompression; // Note #1
|
|
procedure StopDecompression; // Note #1
|
|
property CompressionPaused: Boolean read FCompressionPause write FCompressionPause; // Note #1
|
|
property DecompressionPaused: Boolean read FDecompressionPause write FDecompressionPause; // Note #1
|
|
|
|
property OnFileSkip :TFileSkipEvent read FOnFileSkip write FOnFileSkip;
|
|
|
|
published
|
|
property StorePaths: Boolean read FStorePaths write FStorePaths default True;
|
|
// NOTE : This property allows you to override already opened files - USE WITH CAUTION!!! opened files may still be writing data
|
|
// causing stored files to be different from the final file.
|
|
property IgnoreExclusive: Boolean read FIgnoreExclusive write FIgnoreExclusive default False;
|
|
property CompressionLevel: TJclCompressionLevel read FCompressionLevel write FCompressionLevel default -1;
|
|
property ForceDirectoriesFlag: Boolean read FForceDirectoriesFlag write SetForceDirectoriesFlag default True; // NEW MARCH 2007!
|
|
// NOTE: Changed decompression event parameters. July 26 2004. -WPostma.
|
|
property OnDecompressingFile: TFileBeforeWriteEvent read FOnDecompressingFile write FOnDecompressingFile;
|
|
property OnDecompressedFile: TFileAfterWriteEvent read FOnDecompressedFile write FOnDecompressedFile;
|
|
property OnProgress: TProgressEvent read FOnProgress write FOnProgress;
|
|
property OnCompressingFile: TFileEvent read FOnCompressingFile write FOnCompressingFile;
|
|
property OnCompressedFile: TFileEvent read FOnCompressedFile write FOnCompressedFile;
|
|
property OnCompletedAction: TNotifyEvent read FOnCompletedAction write FOnCompletedAction;
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
const
|
|
UnitVersioning: TUnitVersionInfo = (
|
|
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_39/run/JvZlibMultiple.pas $';
|
|
Revision: '$Revision: 12505 $';
|
|
Date: '$Date: 2009-09-16 20:42:08 +0200 (mer., 16 sept. 2009) $';
|
|
LogPath: 'JVCL\run'
|
|
);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
implementation
|
|
|
|
uses
|
|
JvJCLUtils;
|
|
|
|
{*******************************************************}
|
|
{ Format of the File: }
|
|
{ File Header }
|
|
{ 1 Byte Size of the directory variable }
|
|
{ x bytes Directory of the file }
|
|
{ 1 Byte Size of the filename }
|
|
{ x bytes Filename }
|
|
{ 4 bytes Size of the file (uncompressed) }
|
|
{ 4 bytes Size of the file (compressed) }
|
|
{ Data chunk }
|
|
{ x bytes the compressed chunk }
|
|
{*******************************************************}
|
|
|
|
constructor TJvZlibMultiple.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FStorePaths := True;
|
|
FIgnoreExclusive := False;
|
|
FCompressionLevel := -1;
|
|
FForceDirectoriesFlag := true;
|
|
end;
|
|
|
|
function TJvZlibMultiple.CompressDirectory(Directory: string; Recursive: Boolean): TStream;
|
|
|
|
procedure SearchDirectory(const SDirectory: string);
|
|
var
|
|
SearchRec: TSearchRec;
|
|
Res: Integer;
|
|
fn:String;
|
|
begin
|
|
// (rom) this may not work for network drives and compressed files
|
|
// (rom) because of faAnyFile
|
|
Res := FindFirst(Directory + SDirectory + AllFilesMask, faAnyFile, SearchRec);
|
|
try
|
|
while Res = 0 do
|
|
begin
|
|
if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then
|
|
begin
|
|
if (SearchRec.Attr and faDirectory) = 0 then begin
|
|
try
|
|
fn := Directory + SDirectory + SearchRec.Name;
|
|
AddFile(SearchRec.Name, SDirectory, fn, Result)
|
|
except
|
|
on E:EFOpenError do begin
|
|
if Assigned(FOnFileSkip) then begin
|
|
FOnFileSkip(Self, fn, String(E.ClassName) ,E.Message );
|
|
end;
|
|
end;
|
|
|
|
|
|
end;
|
|
end
|
|
else
|
|
if Recursive then
|
|
SearchDirectory(SDirectory + SearchRec.Name + PathDelim);
|
|
end;
|
|
Res := FindNext(SearchRec);
|
|
end;
|
|
finally
|
|
FindClose(SearchRec);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
{ (RB) Letting this function create a stream is not a good idea;
|
|
see other CompressDirectory function that causes a memory leak }
|
|
Result := TMemoryStream.Create;
|
|
if Directory <> '' then // do not start with '\' if the caller specifies ''.
|
|
Directory := IncludeTrailingPathDelimiter(Directory);
|
|
SearchDirectory('');
|
|
Result.Position := 0;
|
|
end;
|
|
|
|
procedure TJvZlibMultiple.AddFile(const FileName, Directory, FilePath: string;
|
|
DestStream: TStream);
|
|
var
|
|
Stream: TStream;
|
|
FileStream: TFileStream;
|
|
ZStream: TJclZLibCompressStream;
|
|
Buffer: array [0..1023] of Byte;
|
|
Count: Integer;
|
|
FileStreamPos, FileStreamSize: Int64;
|
|
|
|
procedure WriteFileRecord(const Directory, FileName: string; FileSize: Integer; CompressedSize: Integer);
|
|
var
|
|
B: Byte;
|
|
AnsiStr: AnsiString;
|
|
begin
|
|
AnsiStr := AnsiString(Directory);
|
|
if Length(AnsiStr) > 255 then
|
|
SetLength(AnsiStr, 255);
|
|
B := Length(AnsiStr);
|
|
DestStream.Write(B, SizeOf(B));
|
|
DestStream.Write(PAnsiChar(AnsiStr)^, B);
|
|
|
|
AnsiStr := AnsiString(FileName);
|
|
if Length(AnsiStr) > 255 then
|
|
SetLength(AnsiStr, 255);
|
|
B := Length(AnsiStr);
|
|
DestStream.Write(B, SizeOf(B));
|
|
DestStream.Write(PAnsiChar(AnsiStr)^, B);
|
|
|
|
DestStream.Write(FileSize, SizeOf(FileSize));
|
|
DestStream.Write(CompressedSize, SizeOf(CompressedSize));
|
|
end;
|
|
|
|
begin
|
|
Stream := TMemoryStream.Create;
|
|
if not IgnoreExclusive then
|
|
FileStream := TFileStream.Create(FilePath, fmOpenRead or fmShareDenyWrite)
|
|
else
|
|
FileStream := TFileStream.Create(FilePath, fmOpenRead or fmShareDenyNone);
|
|
|
|
|
|
if FileStream.Size=0 then begin
|
|
Stream.Free;
|
|
FileStream.Free;
|
|
exit;
|
|
end;
|
|
|
|
try
|
|
ZStream := TJclZLibCompressStream.Create(Stream, CompressionLevel);
|
|
try
|
|
if Assigned(FOnCompressingFile) then
|
|
FOnCompressingFile(Self, FilePath);
|
|
|
|
FileStreamPos := FileStream.Position;
|
|
FileStreamSize := FileStream.Size;
|
|
{ (RB) ZStream has an OnProgress event, thus CopyFrom can be used }
|
|
repeat
|
|
Count := FileStream.Read(Buffer, SizeOf(Buffer));
|
|
Inc(FileStreamPos, Count);
|
|
if Count > 0 then
|
|
ZStream.Write(Buffer, Count);
|
|
DoProgress(FileStreamPos, FileStreamSize);
|
|
while CompressionPaused do
|
|
Sleep(1);
|
|
until (Count = 0) or FTerminateCompress;
|
|
ZStream.Flush; // Warren added.
|
|
finally
|
|
ZStream.Free;
|
|
end;
|
|
|
|
if Assigned(FOnCompressedFile) then
|
|
FOnCompressedFile(Self, FilePath);
|
|
|
|
if StorePaths then
|
|
WriteFileRecord(Directory, FileName, FileStreamSize, Stream.Size)
|
|
else
|
|
WriteFileRecord('', FileName, FileStreamSize, Stream.Size);
|
|
|
|
DestStream.CopyFrom(Stream, 0);
|
|
finally
|
|
FileStream.Free;
|
|
Stream.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvZlibMultiple.CompressDirectory(const Directory: string;
|
|
Recursive: Boolean; const FileName: string);
|
|
var
|
|
TmpStream: TStream;
|
|
begin
|
|
// don't create file until we save it so we don't accidentally
|
|
// try to compress ourselves!
|
|
DeleteFile(FileName); // make sure we don't compress a previous archive into ourselves
|
|
TmpStream := CompressDirectory(Directory, Recursive);
|
|
try
|
|
TMemoryStream(TmpStream).SaveToFile(FileName);
|
|
finally
|
|
TmpStream.Free;
|
|
end;
|
|
end;
|
|
|
|
function TJvZlibMultiple.CompressFiles(Files: TStrings): TStream;
|
|
var
|
|
I: Integer;
|
|
S1, S2, Common: string;
|
|
begin
|
|
FTerminateCompress := False;
|
|
{ (RB) Letting this function create a stream is not a good idea;
|
|
see other CompressFiles function that causes a memory leak }
|
|
Result := TMemoryStream.Create;
|
|
if Files.Count = 0 then
|
|
Exit;
|
|
|
|
//Find the biggest Common part of all files
|
|
S1 := UpperCase(Files[0]);
|
|
for I := 1 to Files.Count - 1 do
|
|
begin
|
|
S2 := Files[I];
|
|
while (Pos(S1, S2) = 0) and (S1 <> '') do
|
|
S1 := Copy(S1, 1, Length(S1) - 1);
|
|
end;
|
|
{ (RB) This should be Common := S1 (?) }
|
|
Common := S2;
|
|
|
|
//Add the files to the stream
|
|
for I := 0 to Files.Count - 1 do
|
|
begin
|
|
S1 := ExtractFileName(Files[I]);
|
|
S2 := ExtractFilePath(Files[I]);
|
|
S2 := Copy(S2, 1, Length(Common));
|
|
AddFile(S1, S2, Files[I], Result);
|
|
end;
|
|
|
|
Result.Position := 0;
|
|
end;
|
|
|
|
procedure TJvZlibMultiple.CompressFiles(Files: TStrings; const FileName: string);
|
|
var
|
|
TmpStream: TStream;
|
|
begin
|
|
TmpStream := CompressFiles(Files);
|
|
try
|
|
TMemoryStream(TmpStream).SaveToFile(FileName);
|
|
finally
|
|
TmpStream.Free;
|
|
end;
|
|
if Assigned(FOnCompletedAction) then
|
|
FOnCompletedAction(Self);
|
|
end;
|
|
|
|
procedure TJvZlibMultiple.DecompressStream(Stream: TStream;
|
|
Directory: string; Overwrite: Boolean; const RelativePaths: Boolean);
|
|
var
|
|
FileStream: TFileStream;
|
|
ZStream: TJclZLibDecompressStream;
|
|
CStream: TMemoryStream;
|
|
B, LastPos: Byte;
|
|
AnsiS: AnsiString;
|
|
S: string;
|
|
Count, FileSize, I: Integer;
|
|
Buffer: array [0..1023] of Byte;
|
|
TotalByteCount: Longword;
|
|
WriteMe: Boolean; // Allow skipping of files instead of writing them.
|
|
FileStreamSize, StreamSize: Int64;
|
|
fd: string; // name of directory to be made if it doesn't exist (unless we're skipping it)
|
|
begin
|
|
if Directory <> '' then
|
|
Directory := IncludeTrailingPathDelimiter(Directory);
|
|
|
|
StreamSize := Stream.Size; // cache, to not FileSeek on every iteration
|
|
while Stream.Position < StreamSize do
|
|
begin
|
|
//Read and force the directory
|
|
Stream.Read(B, SizeOf(B));
|
|
SetLength(AnsiS, B);
|
|
if B > 0 then
|
|
Stream.Read(AnsiS[1], B);
|
|
S := string(AnsiS);
|
|
|
|
fd := Directory + S;
|
|
if (fd <> '') and (ForceDirectoriesFlag) then
|
|
ForceDirectories(fd);
|
|
|
|
if S <> '' then
|
|
S := IncludeTrailingPathDelimiter(S);
|
|
|
|
//This make files decompress either on Directory or Directory+SavedRelativePath
|
|
if not RelativePaths then
|
|
S := '';
|
|
|
|
//Read filename
|
|
Stream.Read(B, SizeOf(B));
|
|
if B > 0 then
|
|
begin
|
|
AnsiS := AnsiString(S);
|
|
LastPos := Length(AnsiS);
|
|
SetLength(AnsiS, LastPos + B);
|
|
Stream.Read(AnsiS[LastPos + 1], B);
|
|
S := string(AnsiS);
|
|
end;
|
|
|
|
Stream.Read(FileSize, SizeOf(FileSize));
|
|
Stream.Read(I, SizeOf(I));
|
|
CStream := TMemoryStream.Create;
|
|
|
|
try
|
|
CStream.CopyFrom(Stream, I);
|
|
CStream.Position := 0;
|
|
|
|
//Decompress the file
|
|
S := Directory + S;
|
|
if Overwrite or not FileExists(S) then
|
|
begin
|
|
//This fails if Directory isn't empty
|
|
WriteMe := True;
|
|
if Assigned(FOnDecompressingFile) then
|
|
FOnDecompressingFile(Self, S, WriteMe);
|
|
|
|
if WriteMe then
|
|
FileStream := TFileStream.Create(S, fmCreate or fmShareExclusive)
|
|
else
|
|
FileStream := nil; // skip it!
|
|
|
|
ZStream := TJclZLibDecompressStream.Create(CStream);
|
|
try
|
|
TotalByteCount := 0;
|
|
|
|
{ (RB) ZStream has an OnProgress event, thus copyfrom can be used }
|
|
FileStreamSize := 0;
|
|
repeat
|
|
Count := ZStream.Read(Buffer, SizeOf(Buffer));
|
|
if Assigned(FileStream) then
|
|
begin
|
|
Inc(FileStreamSize, FileStream.Write(Buffer, Count));
|
|
DoProgress(FileStreamSize, FileSize);
|
|
while DecompressionPaused do
|
|
Sleep(1);
|
|
end;
|
|
Inc(TotalByteCount, Count);
|
|
until (Count = 0) or FTerminateDecompress;
|
|
if Assigned(FOnDecompressedFile) then
|
|
FOnDecompressedFile(Self, S, TotalByteCount);
|
|
finally
|
|
FreeAndNil(FileStream);
|
|
ZStream.Free;
|
|
end;
|
|
end;
|
|
finally
|
|
CStream.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvZlibMultiple.DecompressFile(const FileName, Directory: string;
|
|
Overwrite: Boolean; const RelativePaths: Boolean);
|
|
var
|
|
Stream: TFileStream;
|
|
begin
|
|
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
|
|
try
|
|
Stream.Position := 0;
|
|
DecompressStream(Stream, Directory, Overwrite, RelativePaths);
|
|
finally
|
|
Stream.Free;
|
|
end;
|
|
if Assigned(FOnCompletedAction) then
|
|
FOnCompletedAction(Self);
|
|
end;
|
|
|
|
procedure TJvZlibMultiple.DoProgress(Position, Total: Integer);
|
|
begin
|
|
if Assigned(FOnProgress) then
|
|
FOnProgress(Self, Position, Total);
|
|
end;
|
|
|
|
procedure TJvZlibMultiple.DoStopCompression;
|
|
begin
|
|
FTerminateCompress := True;
|
|
end;
|
|
|
|
procedure TJvZlibMultiple.DoStopDecompression;
|
|
begin
|
|
FTerminateDecompress := True;
|
|
end;
|
|
|
|
procedure TJvZlibMultiple.SetForceDirectoriesFlag(const Value: Boolean);
|
|
begin
|
|
FForceDirectoriesFlag := Value;
|
|
end;
|
|
|
|
procedure TJvZlibMultiple.StopCompression;
|
|
begin
|
|
DoStopCompression;
|
|
end;
|
|
|
|
procedure TJvZlibMultiple.StopDecompression;
|
|
begin
|
|
DoStopDecompression;
|
|
end;
|
|
|
|
procedure TJvZLibMultiple.ListStoredFiles(const FileName: string; FileList: TStrings);
|
|
var
|
|
ZStream: TFileStream;
|
|
FHByte: Byte;
|
|
FilePos, HeaderPos, CompressedSize, UnCompressedSize: Integer;
|
|
AnsiFileInfo: AnsiString;
|
|
FileInfo: string;
|
|
ZStreamSize: Int64;
|
|
begin
|
|
ZStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
|
|
try
|
|
ZStreamSize := ZStream.Size;
|
|
while ZStream.Position < ZStreamSize do
|
|
begin
|
|
ZStream.Read(FHByte, SizeOf(FHByte));
|
|
SetLength(AnsiFileInfo, FHByte);
|
|
if FHByte > 0 then
|
|
ZStream.Read(AnsiFileInfo[1], FHByte);
|
|
FileInfo := string(AnsiFileInfo);
|
|
|
|
if FileInfo <> '' then
|
|
FileInfo := IncludeTrailingPathDelimiter(FileInfo);
|
|
ZStream.Read(FHByte, SizeOf(FHByte));
|
|
if FHByte > 0 then
|
|
begin
|
|
AnsiFileInfo := AnsiString(FileInfo);
|
|
HeaderPos := Length(AnsiFileInfo);
|
|
SetLength(AnsiFileInfo, HeaderPos + FHByte);
|
|
ZStream.Read(AnsiFileInfo[HeaderPos + 1], FHByte);
|
|
FileInfo := string(AnsiFileInfo);
|
|
end;
|
|
|
|
FileList.Add(FileInfo);
|
|
ZStream.Read(UncompressedSize, SizeOf(UncompressedSize));
|
|
ZStream.Read(CompressedSize, SizeOf(CompressedSize));
|
|
FilePos := ZStream.Position + CompressedSize;
|
|
ZStream.Position := FilePos;
|
|
end;
|
|
finally
|
|
ZStream.Free;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
initialization
|
|
RegisterUnitVersion(HInstance, UnitVersioning);
|
|
|
|
finalization
|
|
UnregisterUnitVersion(HInstance);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
end.
|