FastReport_2022_VCL/LibD28x64/frxZip.pas
2024-01-01 16:13:08 +01:00

794 lines
25 KiB
ObjectPascal

{******************************************}
{ }
{ FastReport VCL }
{ ZIP archiver support unit }
{ }
{ Copyright (c) 1998-2021 }
{ by Fast Reports Inc. }
{ }
{******************************************}
unit frxZip;
{$I frx.inc}
interface
uses Classes,
{$IFNDEF NONWINFPC}
Windows,
{$ELSE}
{$DEFINE STATIC_EXPORTING_RESULTS}
LCLType, LCLIntf, LCLProc, Types, FileUtil,
{$ENDIF}
{$IFDEF DELPHI16}
ZLib,
{$ELSE}
frxZLib,
{$ENDIF}
frxGZip, frxUtils, frxFileUtils;
type
TfrxZipLocalFileHeader = class;
TfrxZipCentralDirectory = class;
TfrxZipFileHeader = class;
TfrxZipArchive = class(TObject)
private
{$IFDEF Delphi12}
FRootFolder: AnsiString;
{$ELSE}
FRootFolder: String;
{$ENDIF}
FErrors: TStringList;
FFileList: TStringList;
{$IFDEF Delphi12}
FComment: AnsiString;
{$ELSE}
FComment: AnsiString;
{$ENDIF}
FProgress: TNotifyEvent;
function GetCount: Integer;
public
constructor Create;
destructor Destroy; override;
procedure Clear;
{$IFDEF Delphi12}
procedure AddFile(const FileName: AnsiString);
procedure AddDir(const DirName: AnsiString);
procedure SaveToFile(const Filename: AnsiString);
{$ELSE}
procedure AddFile(const FileName: String);
procedure AddDir(const DirName: String);
procedure SaveToFile(const Filename: String);
{$ENDIF}
procedure SaveToStream(const Stream: TStream);
procedure SaveToStreamFromList(const Stream: TStream; FileStreams: TStrings);
property Errors: TStringList read FErrors;
{$IFDEF Delphi12}
property Comment: AnsiString read FComment write FComment;
property RootFolder: AnsiString read FRootFolder write FRootFolder;
{$ELSE}
property Comment: String read FComment write FComment;
property RootFolder: String read FRootFolder write FRootFolder;
{$ENDIF}
property FileCount: Integer read GetCount;
property OnProgress: TNotifyEvent read FProgress write FProgress;
end;
TfrxZipLocalFileHeader = class(TObject)
private
FLocalFileHeaderSignature: Longword;
FVersion: WORD;
FGeneralPurpose: WORD;
FCompressionMethod: WORD;
FCrc32: Longword;
FLastModFileDate: WORD;
FLastModFileTime: WORD;
FCompressedSize: Longword;
FUnCompressedSize: Longword;
{$IFDEF Delphi12}
FExtraField: AnsiString;
FFileName: AnsiString;
{$ELSE}
FExtraField: String;
FFileName: String;
{$ENDIF}
FFileNameLength: WORD;
FExtraFieldLength: WORD;
{$IFDEF Delphi12}
procedure SetExtraField(const Value: AnsiString);
procedure SetFileName(const Value: AnsiString);
{$ELSE}
procedure SetExtraField(const Value: String);
procedure SetFileName(const Value: String);
{$ENDIF}
public
constructor Create;
procedure SaveToStream(const Stream: TStream);
property LocalFileHeaderSignature: Longword read FLocalFileHeaderSignature;
property Version: WORD read FVersion write FVersion;
property GeneralPurpose: WORD read FGeneralPurpose write FGeneralPurpose;
property CompressionMethod: WORD read FCompressionMethod write FCompressionMethod;
property LastModFileTime: WORD read FLastModFileTime write FLastModFileTime;
property LastModFileDate: WORD read FLastModFileDate write FLastModFileDate;
property Crc32: Longword read FCrc32 write FCrc32;
property CompressedSize: Longword read FCompressedSize write FCompressedSize;
property UnCompressedSize: Longword read FUnCompressedSize write FUnCompressedSize;
property FileNameLength: WORD read FFileNameLength write FFileNameLength;
property ExtraFieldLength: WORD read FExtraFieldLength write FExtraFieldLength;
{$IFDEF Delphi12}
property FileName: AnsiString read FFileName write SetFileName;
property ExtraField: AnsiString read FExtraField write SetExtraField;
{$ELSE}
property FileName: String read FFileName write SetFileName;
property ExtraField: String read FExtraField write SetExtraField;
{$ENDIF}
end;
TfrxZipCentralDirectory = class(TObject)
private
FEndOfChentralDirSignature: Longword;
FNumberOfTheDisk: WORD;
FTotalOfEntriesCentralDirOnDisk: WORD;
FNumberOfTheDiskStartCentralDir: WORD;
FTotalOfEntriesCentralDir: WORD;
FSizeOfCentralDir: Longword;
FOffsetStartingDiskDir: Longword;
{$IFDEF Delphi12}
FComment: AnsiString;
{$ELSE}
FComment: String;
{$ENDIF}
FCommentLength: WORD;
{$IFDEF Delphi12}
procedure SetComment(const Value: AnsiString);
{$ELSE}
procedure SetComment(const Value: String);
{$ENDIF}
public
constructor Create;
procedure SaveToStream(const Stream: TStream);
property EndOfChentralDirSignature: Longword read FEndOfChentralDirSignature;
property NumberOfTheDisk: WORD read FNumberOfTheDisk write FNumberOfTheDisk;
property NumberOfTheDiskStartCentralDir: WORD
read FNumberOfTheDiskStartCentralDir write FNumberOfTheDiskStartCentralDir;
property TotalOfEntriesCentralDirOnDisk: WORD
read FTotalOfEntriesCentralDirOnDisk write FTotalOfEntriesCentralDirOnDisk;
property TotalOfEntriesCentralDir: WORD
read FTotalOfEntriesCentralDir write FTotalOfEntriesCentralDir;
property SizeOfCentralDir: Longword read FSizeOfCentralDir write FSizeOfCentralDir;
property OffsetStartingDiskDir: Longword read FOffsetStartingDiskDir write FOffsetStartingDiskDir;
property CommentLength: WORD read FCommentLength write FCommentLength;
{$IFDEF Delphi12}
property Comment: AnsiString read FComment write SetComment;
{$ELSE}
property Comment: String read FComment write SetComment;
{$ENDIF}
end;
TfrxZipFileHeader = class(TObject)
private
FCentralFileHeaderSignature: Longword;
FRelativeOffsetLocalHeader: Longword;
FUnCompressedSize: Longword;
FCompressedSize: Longword;
FCrc32: Longword;
FExternalFileAttribute: Longword;
{$IFDEF Delphi12}
FExtraField: AnsiString;
FFileComment: AnsiString;
FFileName: AnsiString;
{$ELSE}
FExtraField: String;
FFileComment: String;
FFileName: String;
{$ENDIF}
FCompressionMethod: WORD;
FDiskNumberStart: WORD;
FLastModFileDate: WORD;
FLastModFileTime: WORD;
FVersionMadeBy: WORD;
FGeneralPurpose: WORD;
FFileNameLength: WORD;
FInternalFileAttribute: WORD;
FExtraFieldLength: WORD;
FVersionNeeded: WORD;
FFileCommentLength: WORD;
{$IFDEF Delphi12}
procedure SetExtraField(const Value: AnsiString);
procedure SetFileComment(const Value: AnsiString);
procedure SetFileName(const Value: AnsiString);
{$ELSE}
procedure SetExtraField(const Value: String);
procedure SetFileComment(const Value: String);
procedure SetFileName(const Value: String);
{$ENDIF}
public
constructor Create;
procedure SaveToStream(const Stream: TStream);
property CentralFileHeaderSignature: Longword read FCentralFileHeaderSignature;
property VersionMadeBy: WORD read FVersionMadeBy;
property VersionNeeded: WORD read FVersionNeeded;
property GeneralPurpose: WORD read FGeneralPurpose write FGeneralPurpose;
property CompressionMethod: WORD read FCompressionMethod write FCompressionMethod;
property LastModFileTime: WORD read FLastModFileTime write FLastModFileTime;
property LastModFileDate: WORD read FLastModFileDate write FLastModFileDate;
property Crc32: Longword read FCrc32 write FCrc32;
property CompressedSize: Longword read FCompressedSize write FCompressedSize;
property UnCompressedSize: Longword read FUnCompressedSize write FUnCompressedSize;
property FileNameLength: WORD read FFileNameLength write FFileNameLength;
property ExtraFieldLength: WORD read FExtraFieldLength write FExtraFieldLength;
property FileCommentLength: WORD read FFileCommentLength write FFileCommentLength;
property DiskNumberStart: WORD read FDiskNumberStart write FDiskNumberStart;
property InternalFileAttribute: WORD read FInternalFileAttribute write FInternalFileAttribute;
property ExternalFileAttribute: Longword read FExternalFileAttribute write FExternalFileAttribute;
property RelativeOffsetLocalHeader: Longword read FRelativeOffsetLocalHeader write FRelativeOffsetLocalHeader;
{$IFDEF Delphi12}
property FileName: AnsiString read FFileName write SetFileName;
property ExtraField: AnsiString read FExtraField write SetExtraField;
property FileComment: AnsiString read FFileComment write SetFileComment;
{$ELSE}
property FileName: String read FFileName write SetFileName;
property ExtraField: String read FExtraField write SetExtraField;
property FileComment: String read FFileComment write SetFileComment;
{$ENDIF}
end;
TfrxZipLocalFile = class(TObject)
private
FLocalFileHeader: TfrxZipLocalFileHeader;
FFileData: TMemoryStream;
FOffset: Longword;
public
constructor Create;
destructor Destroy; override;
procedure SaveToStream(const Stream: TStream);
property LocalFileHeader: TfrxZipLocalFileHeader read FLocalFileHeader;
property FileData: TMemoryStream read FFileData write FFileData;
property Offset: Longword read FOffset write FOffset;
end;
implementation
uses SysUtils{$IFDEF Delphi12}, AnsiStrings{$ENDIF};
const
ZIP_VERSIONMADEBY = 20;
ZIP_NONE = 0;
ZIP_DEFLATED = 8;
ZIP_MINSIZE = 128;
{ TfrxZipLocalFile }
constructor TfrxZipLocalFile.Create;
begin
FLocalFileHeader := TfrxZipLocalFileHeader.Create;
FOffset := 0;
end;
destructor TfrxZipLocalFile.Destroy;
begin
FLocalFileHeader.Free;
inherited;
end;
procedure TfrxZipLocalFile.SaveToStream(const Stream: TStream);
begin
FLocalFileHeader.SaveToStream(Stream);
FFileData.Position := 0;
FFileData.SaveToStream(Stream);
end;
{ TfrxZipLocalFileHeader }
constructor TfrxZipLocalFileHeader.Create;
begin
inherited;
FLocalFileHeaderSignature := $04034b50;
FVersion := ZIP_VERSIONMADEBY;
FGeneralPurpose := 0;
FCompressionMethod := ZIP_NONE;
FCrc32 := 0;
FLastModFileDate := 0;
FLastModFileTime := 0;
FCompressedSize := 0;
FUnCompressedSize := 0;
FExtraField := '';
FFileName := '';
FFileNameLength := 0;
FExtraFieldLength := 0;
end;
procedure TfrxZipLocalFileHeader.SaveToStream(const Stream: TStream);
begin
Stream.Write(FLocalFileHeaderSignature, 4);
Stream.Write(FVersion, 2);
Stream.Write(FGeneralPurpose, 2);
Stream.Write(FCompressionMethod, 2);
Stream.Write(FLastModFileTime, 2);
Stream.Write(FLastModFileDate, 2);
Stream.Write(FCrc32, 4);
Stream.Write(FCompressedSize, 4);
Stream.Write(FUnCompressedSize, 4);
Stream.Write(FFileNameLength, 2);
Stream.Write(FExtraFieldLength, 2);
if FFileNameLength > 0 then
Stream.Write(FFileName[1], FFileNameLength);
if FExtraFieldLength > 0 then
Stream.Write(FExtraField[1], FExtraFieldLength);
end;
procedure TfrxZipLocalFileHeader.SetExtraField(const Value: {$IFDEF Delphi12}AnsiString{$ELSE}String{$ENDIF});
begin
FExtraField := Value;
FExtraFieldLength := Length(Value);
end;
procedure TfrxZipLocalFileHeader.SetFileName(const Value: {$IFDEF Delphi12}AnsiString{$ELSE}String{$ENDIF});
begin
FFileName := StringReplace(Value,
{$IFDEF Delphi12}AnsiString('\'), AnsiString('/'){$ELSE}'\', '/'{$ENDIF}, [rfReplaceAll]);
FFileNameLength := Length(Value);
end;
{ TfrxZipCentralDirectory }
constructor TfrxZipCentralDirectory.Create;
begin
inherited;
FEndOfChentralDirSignature := $06054b50;
FNumberOfTheDisk := 0;
FNumberOfTheDiskStartCentralDir := 0;
FTotalOfEntriesCentralDirOnDisk := 0;
FTotalOfEntriesCentralDir := 0;
FSizeOfCentralDir := 0;
FOffsetStartingDiskDir := 0;
FCommentLength := 0;
FComment := '';
end;
procedure TfrxZipCentralDirectory.SaveToStream(const Stream: TStream);
begin
Stream.Write(FEndOfChentralDirSignature, 4);
Stream.Write(FNumberOfTheDisk, 2);
Stream.Write(FNumberOfTheDiskStartCentralDir, 2);
Stream.Write(FTotalOfEntriesCentralDirOnDisk, 2);
Stream.Write(FTotalOfEntriesCentralDir, 2);
Stream.Write(FSizeOfCentralDir, 4);
Stream.Write(FOffsetStartingDiskDir, 4);
Stream.Write(FCommentLength, 2);
if FCommentLength > 0 then
Stream.Write(FComment[1], FCommentLength);
end;
procedure TfrxZipCentralDirectory.SetComment(const Value: {$IFDEF Delphi12}AnsiString{$ELSE}String{$ENDIF});
begin
FComment := Value;
FCommentLength := Length(Value);
end;
{ TfrxZipFileHeader }
constructor TfrxZipFileHeader.Create;
begin
FCentralFileHeaderSignature := $02014b50;
FRelativeOffsetLocalHeader := 0;
FUnCompressedSize := 0;
FCompressedSize := 0;
FCrc32 := 0;
FExternalFileAttribute := 0;
FExtraField := '';
FFileComment := '';
FFileName := '';
FCompressionMethod := 0;
FDiskNumberStart := 0;
FLastModFileDate := 0;
FLastModFileTime := 0;
FVersionMadeBy := ZIP_VERSIONMADEBY;
FGeneralPurpose := 0;
FFileNameLength := 0;
FInternalFileAttribute := 0;
FExtraFieldLength := 0;
FVersionNeeded := ZIP_VERSIONMADEBY;
FFileCommentLength := 0;
end;
procedure TfrxZipFileHeader.SaveToStream(const Stream: TStream);
begin
Stream.Write(FCentralFileHeaderSignature, 4);
Stream.Write(FVersionMadeBy, 2);
Stream.Write(FVersionNeeded, 2);
Stream.Write(FGeneralPurpose, 2);
Stream.Write(FCompressionMethod, 2);
Stream.Write(FLastModFileTime, 2);
Stream.Write(FLastModFileDate, 2);
Stream.Write(FCrc32, 4);
Stream.Write(FCompressedSize, 4);
Stream.Write(FUnCompressedSize, 4);
Stream.Write(FFileNameLength, 2);
Stream.Write(FExtraFieldLength, 2);
Stream.Write(FFileCommentLength, 2);
Stream.Write(FDiskNumberStart, 2);
Stream.Write(FInternalFileAttribute, 2);
Stream.Write(FExternalFileAttribute, 4);
Stream.Write(FRelativeOffsetLocalHeader, 4);
Stream.Write(FFilename[1], FFileNameLength);
Stream.Write(FExtraField[1], FExtraFieldLength);
Stream.Write(FFileComment[1], FFileCommentLength);
end;
procedure TfrxZipFileHeader.SetExtraField(const Value: {$IFDEF Delphi12}AnsiString{$ELSE}String{$ENDIF});
begin
FExtraField := Value;
FExtraFieldLength := Length(Value);
end;
procedure TfrxZipFileHeader.SetFileComment(const Value: {$IFDEF Delphi12}AnsiString{$ELSE}String{$ENDIF});
begin
FFileComment := Value;
FFileNameLength := Length(Value);
end;
procedure TfrxZipFileHeader.SetFileName(const Value: {$IFDEF Delphi12}AnsiString{$ELSE}String{$ENDIF});
begin
FFileName := StringReplace(Value,
{$IFDEF Delphi12}AnsiString('\'), AnsiString('/'){$ELSE}'\', '/'{$ENDIF}, [rfReplaceAll]);
FFileNameLength := Length(Value);
end;
{ TfrxZipArchive }
procedure TfrxZipArchive.AddDir(const DirName: {$IFDEF Delphi12}AnsiString{$ELSE}String{$ENDIF});
var
SRec: TSearchRec;
i: Integer;
{$IFDEF Delphi12}
s: AnsiString;
{$ELSE}
s: String;
{$ENDIF}
begin
{$IFDEF Delphi12}
if DirectoryExists(String(DirName)) then
{$ELSE}
if DirectoryExists(DirName) then
{$ENDIF}
begin
s := DirName;
if s[Length(s)] <> PathDelim then
s := s + PathDelim;
{$IFDEF Delphi12}
i := FindFirst(String(s) + '*.*', faDirectory + faArchive, SRec);
{$ELSE}
i := FindFirst(s + '*.*', faDirectory + faArchive, SRec);
{$ENDIF}
try
while i = 0 do
begin
if (SRec.Name <> '.') and (SRec.Name <> '..') then
begin
if (SRec.Attr and faDirectory) = faDirectory then
{$IFDEF Delphi12}
AddDir(s + AnsiString(SRec.Name))
else
AddFile(s + AnsiString(SRec.Name));
{$ELSE}
AddDir(s + SRec.Name)
else
AddFile(s + SRec.Name);
{$ENDIF}
end;
i := FindNext(SRec);
end;
finally
FindClose(SRec);
end;
end;
end;
{$IFDEF Delphi12}
procedure TfrxZipArchive.AddFile(const FileName: AnsiString);
begin
if FileExists(String(FileName)) then
begin
FFileList.Add(String(FileName));
if FRootFolder = '' then
FRootFolder := ExtractFilePath(FileName);
end
else
FErrors.Add('File ' + String(FileName) + ' not found!');
end;
{$ELSE}
procedure TfrxZipArchive.AddFile(const FileName: String);
begin
if FileExists(FileName) then
begin
FFileList.Add(FileName);
if FRootFolder = '' then
FRootFolder := ExtractFilePath(FileName);
end
else
FErrors.Add('File ' + FileName + ' not found!');
end;
{$ENDIF}
procedure TfrxZipArchive.Clear;
begin
FErrors.Clear;
FFileList.Clear;
FRootFolder := '';
FComment := '';
end;
constructor TfrxZipArchive.Create;
begin
FProgress := nil;
FErrors := TStringList.Create;
FFileList := TStringList.Create;
Clear;
end;
destructor TfrxZipArchive.Destroy;
begin
FErrors.Free;
FFileList.Free;
inherited;
end;
function TfrxZipArchive.GetCount: Integer;
begin
Result := FFileList.Count;
end;
procedure TfrxZipArchive.SaveToFile(const FileName: {$IFDEF Delphi12}AnsiString{$ELSE}String{$ENDIF});
var
f: TFileStream;
begin
{$IFDEF Delphi12}
f := TFileStream.Create(String(FileName), fmCreate);
{$ELSE}
f := TFileStream.Create(FileName, fmCreate);
{$ENDIF}
try
SaveToStream(f);
finally
f.Free;
end;
end;
procedure TfrxZipArchive.SaveToStream(const Stream: TStream);
var
i: Integer;
ZipFile: TfrxZipLocalFile;
ZipFileHeader: TfrxZipFileHeader;
ZipDir: TfrxZipCentralDirectory;
FileStream: TFileStream;
TempStream: TMemoryStream;
{$IFDEF Delphi12}
FileName: AnsiString;
{$ELSE}
FileName: String;
{$ENDIF}
CentralStartPos, CentralEndPos: Longword;
{$IFNDEF STATIC_EXPORTING_RESULTS}
LFT, LFT2: TFileTime;
FDate, FTime: WORD;
{$ENDIF}
begin
for i := 0 to FFileList.Count - 1 do
begin
ZipFile := TfrxZipLocalFile.Create;
ZipFile.FileData := TMemoryStream.Create;
try
{$IFDEF Delphi12}
FileName := StringReplace(AnsiString(FFileList[i]), FRootFolder, AnsiString(''), []);
{$ELSE}
FileName := StringReplace(FFileList[i], FRootFolder, '', []);
{$ENDIF}
ZipFile.LocalFileHeader.FileName := FileName;
FileStream := TFileStream.Create(FFileList[i], fmOpenRead + fmShareDenyWrite);
try
if FileStream.Size > ZIP_MINSIZE then
begin
FileStream.Position := 0;
TempStream := TMemoryStream.Create;
try
frxDeflateStream(FileStream, TempStream);
TempStream.Position := 2;
ZipFile.FileData.CopyFrom(TempStream, TempStream.Size - 6);
finally
TempStream.Free;
end;
ZipFile.LocalFileHeader.CompressionMethod := ZIP_DEFLATED;
end
else
begin
ZipFile.FileData.CopyFrom(FileStream, 0);
ZipFile.LocalFileHeader.CompressionMethod := ZIP_NONE;
end;
ZipFile.LocalFileHeader.CompressedSize := ZipFile.FileData.Size;
ZipFile.LocalFileHeader.UnCompressedSize := FileStream.Size;
TempStream := TMemoryStream.Create;
try
TempStream.CopyFrom(FileStream, 0);
ZipFile.LocalFileHeader.Crc32 := frxStreamCRC32(TempStream);
finally
TempStream.Free;
end;
ZipFile.Offset := Stream.Position;
{$IFNDEF STATIC_EXPORTING_RESULTS}
GetFileTime(FileStream.Handle, @LFT, nil, nil);
FileTimeToLocalFileTime(LFT, LFT2);
FileTimeToDosDateTime(LFT2, FDate, FTime);
// {$IFNDEF STATIC_EXPORTING_RESULTS}
ZipFile.LocalFileHeader.LastModFileDate := FDate;
ZipFile.LocalFileHeader.LastModFileTime := FTime;
{$ENDIF}
finally
FileStream.Free;
end;
ZipFile.SaveToStream(Stream);
if Assigned(FProgress) then
FProgress(Self);
finally
ZipFile.FileData.Free;
ZipFile.FileData := nil;
end;
FFileList.Objects[i] := ZipFile;
end;
CentralStartPos := Stream.Position;
for i := 0 to FFileList.Count - 1 do
begin
ZipFile := TfrxZipLocalFile(FFileList.Objects[i]);
ZipFileHeader := TfrxZipFileHeader.Create;
try
ZipFileHeader.CompressionMethod := ZipFile.LocalFileHeader.CompressionMethod;
ZipFileHeader.LastModFileTime := ZipFile.LocalFileHeader.LastModFileTime;
ZipFileHeader.LastModFileDate := ZipFile.LocalFileHeader.LastModFileDate;
ZipFileHeader.GeneralPurpose := ZipFile.LocalFileHeader.GeneralPurpose;
ZipFileHeader.Crc32 := ZipFile.LocalFileHeader.Crc32;
ZipFileHeader.CompressedSize := ZipFile.LocalFileHeader.CompressedSize;
ZipFileHeader.UnCompressedSize := ZipFile.LocalFileHeader.UnCompressedSize;
ZipFileHeader.RelativeOffsetLocalHeader := ZipFile.Offset;
ZipFileHeader.FileName := ZipFile.LocalFileHeader.FileName;
ZipFileHeader.SaveToStream(Stream);
finally
ZipFileHeader.Free;
end;
ZipFile.Free;
end;
CentralEndPos := Stream.Position;
ZipDir := TfrxZipCentralDirectory.Create;
try
ZipDir.TotalOfEntriesCentralDirOnDisk := FFileList.Count;
ZipDir.TotalOfEntriesCentralDir := FFileList.Count;
ZipDir.SizeOfCentralDir := CentralEndPos - CentralStartPos;
ZipDir.OffsetStartingDiskDir := CentralStartPos;
ZipDir.SaveToStream(Stream);
finally
ZipDir.Free;
end;
end;
procedure TfrxZipArchive.SaveToStreamFromList(const Stream: TStream; FileStreams: TStrings);
var
i: Integer;
ZipFile: TfrxZipLocalFile;
ZipFileHeader: TfrxZipFileHeader;
ZipDir: TfrxZipCentralDirectory;
FileStream: TStream;
TempStream: TMemoryStream;
{$IFDEF Delphi12}
FileName: AnsiString;
{$ELSE}
FileName: String;
{$ENDIF}
CentralStartPos, CentralEndPos: Longword;
{$IFNDEF STATIC_EXPORTING_RESULTS}
{LFT, }LFT2: TFileTime;
st: _SYSTEMTIME;
FDate, FTime: WORD;
{$ENDIF}
begin
for i := 0 to FileStreams.Count - 1 do
begin
ZipFile := TfrxZipLocalFile.Create;
ZipFile.FileData := TMemoryStream.Create;
try
{$IFDEF Delphi12}
FileName := StringReplace(AnsiString(FileStreams[i]), FRootFolder, AnsiString(''), []);
{$ELSE}
FileName := StringReplace(FileStreams[i], FRootFolder, '', []);
{$ENDIF}
ZipFile.LocalFileHeader.FileName := FileName;
FileStream := TStream(FileStreams.Objects[i]);// TFileStream.Create(FFileList[i], fmOpenRead + fmShareDenyWrite);
try
if FileStream.Size > ZIP_MINSIZE then
begin
FileStream.Position := 0;
TempStream := TMemoryStream.Create;
try
frxDeflateStream(FileStream, TempStream);
TempStream.Position := 2;
ZipFile.FileData.CopyFrom(TempStream, TempStream.Size - 6);
finally
TempStream.Free;
end;
ZipFile.LocalFileHeader.CompressionMethod := ZIP_DEFLATED;
end
else
begin
ZipFile.FileData.CopyFrom(FileStream, 0);
ZipFile.LocalFileHeader.CompressionMethod := ZIP_NONE;
end;
ZipFile.LocalFileHeader.CompressedSize := ZipFile.FileData.Size;
ZipFile.LocalFileHeader.UnCompressedSize := FileStream.Size;
TempStream := TMemoryStream.Create;
try
TempStream.CopyFrom(FileStream, 0);
ZipFile.LocalFileHeader.Crc32 := frxStreamCRC32(TempStream);
finally
TempStream.Free;
end;
ZipFile.Offset := Stream.Position;
{$IFNDEF STATIC_EXPORTING_RESULTS}
GetLocalTime(st);
SystemTimeToFileTime(st, LFT2);
// GetFileTime(FileStream.Handle, @LFT, nil, nil);
//FileTimeToLocalFileTime(LFT, LFT2);
FileTimeToDosDateTime(LFT2, FDate, FTime);
ZipFile.LocalFileHeader.LastModFileDate := FDate;
ZipFile.LocalFileHeader.LastModFileTime := FTime;
{$ENDIF}
finally
//FileStream.Free;
end;
ZipFile.SaveToStream(Stream);
if Assigned(FProgress) then
FProgress(Self);
finally
ZipFile.FileData.Free;
ZipFile.FileData := nil;
end;
FileStreams.Objects[i] := ZipFile;
end;
CentralStartPos := Stream.Position;
for i := 0 to FileStreams.Count - 1 do
begin
ZipFile := TfrxZipLocalFile(FileStreams.Objects[i]);
ZipFileHeader := TfrxZipFileHeader.Create;
try
ZipFileHeader.CompressionMethod := ZipFile.LocalFileHeader.CompressionMethod;
ZipFileHeader.LastModFileTime := ZipFile.LocalFileHeader.LastModFileTime;
ZipFileHeader.LastModFileDate := ZipFile.LocalFileHeader.LastModFileDate;
ZipFileHeader.GeneralPurpose := ZipFile.LocalFileHeader.GeneralPurpose;
ZipFileHeader.Crc32 := ZipFile.LocalFileHeader.Crc32;
ZipFileHeader.CompressedSize := ZipFile.LocalFileHeader.CompressedSize;
ZipFileHeader.UnCompressedSize := ZipFile.LocalFileHeader.UnCompressedSize;
ZipFileHeader.RelativeOffsetLocalHeader := ZipFile.Offset;
ZipFileHeader.FileName := ZipFile.LocalFileHeader.FileName;
ZipFileHeader.SaveToStream(Stream);
finally
ZipFileHeader.Free;
end;
ZipFile.Free;
end;
CentralEndPos := Stream.Position;
ZipDir := TfrxZipCentralDirectory.Create;
try
ZipDir.TotalOfEntriesCentralDirOnDisk := FileStreams.Count;
ZipDir.TotalOfEntriesCentralDir := FileStreams.Count;
ZipDir.SizeOfCentralDir := CentralEndPos - CentralStartPos;
ZipDir.OffsetStartingDiskDir := CentralStartPos;
ZipDir.SaveToStream(Stream);
finally
ZipDir.Free;
end;
end;
end.