You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RnQ/for.RnQ/RTL/RnQZip.pas

1336 lines
44 KiB
Plaintext

{
This file is part of R&Q.
Under same license
}
unit RnQZip;
{$I ForRnQConfig.inc}
{$I NoRTTI.inc}
{ $IFDEF RNQ}
{$DEFINE ZIP_AES}
{ $ENDIF RNQ}
// ToDo http://www.winzip.com/aes_info.htm
// Copyright 2005 Patrik Spanel
// scilib@sendme.cz
// Written from scratch using InfoZip PKZip file specification application note
// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
// uses the Borland out of the box zlib
// 2005 Added support for streams (LoadFromStream(const ZipFileStream: TStream),SaveToStream(...))
// Nick Naimo added support for folders on 6/29/2004
// Marcin Wojda added exceptions and try finally blocks
// Jarek Stok³osa 11/04/2008 added support for additional file descriptor(LoadFromStream and SaveToStream), add const section;
interface
uses
SysUtils, Classes, Types, Windows, RDGlobal;
type
TZLibStreamHeader = packed record
CMF : Byte;
FLG : Byte;
end;
TFileDescriptor = packed record
Crc32: DWORD; // 4 bytes
CompressedSize: DWORD; // 4 bytes
UncompressedSize: DWORD; // 4 bytes
end;
TCommonFileHeader = packed record
VersionNeededToExtract: WORD; // 2 bytes
GeneralPurposeBitFlag: WORD; // 2 bytes
CompressionMethod: WORD; // 2 bytes
LastModFileTimeDate: DWORD; // 4 bytes
FileDesc: TFileDescriptor;
FilenameLength: WORD; // 2 bytes
ExtraFieldLength: WORD; // 2 bytes
end;
TLocalFile = packed record
LocalFileHeaderSignature: DWORD; // 4 bytes (0x04034b50)
CommonFileHeader: TCommonFileHeader; //
filename: TBytes; //variable size
extrafield: RawByteString; //variable size
CompressedData: RawByteString; //variable size
pass : AnsiString;
{ TODO -oRapid D -cIncrease load speed : Add support of "preview" loading }
DataOffset : Int64;
DataLoaded : Boolean;
function UTFSupport: Boolean;
end;
{$IFDEF ZIP_AES}
TAESExtraData = packed record
HeaderID : WORD; //2 bytes //Extra field header ID (0x9901)
DataSize : WORD; //2 bytes //Data size (currently 7, but subject to possible increase in the future)
Version : WORD; //2 bytes //Integer version number specific to the zip vendor
Vendor : WORD; //2 bytes //2-character vendor ID = 'AE'
AESMode : Byte; //1 byte //Integer mode value indicating AES encryption strength
CompressMethod: WORD; //2 bytes //The actual compression method used to compress the file
end;
{$ENDIF ZIP_AES}
FILE_INT = LongWord;
// {$IFDEF HAS_64_BIT_INT}
BIGINT = INT64;
// {$ELSE}
// BIGINT = LongInt;
// {$ENDIF}
zip64_Extra_Field = packed record
Tag: WORD; { $0001 }
Size: WORD;
Uncompressed_Size: BIGINT;
Compressed_Size: BIGINT;
Relative_Offset: BIGINT;
DiskStart: LongWord;
end;
// zip64_Extra_FieldPtr = ^zip64_Extra_Field;
{
data_descriptor_20 = packed record
crc32: ULONG;
compressed_size: FILE_INT;
uncompressed_size: FILE_INT;
end;
}
data_descriptor_zip64 = packed record
crc32: ULONG;
compressed_size: BIGINT;
uncompressed_size: BIGINT;
end;
NTFS_extra_field = packed record
Tag: WORD; { $000a }
Size: WORD;
Reserved: LongWord;
Tag1: WORD; { $0001 }
Size1: WORD;
Mtime: BIGINT;
Atime: BIGINT;
Ctime: BIGINT;
end;
// NTFS_extra_fieldPtr = ^NTFS_extra_field;
TFileHeader = packed record
CentralFileHeaderSignature: DWORD; // 4 bytes (0x02014b50)
VersionMadeBy: WORD; // 2 bytes
CommonFileHeader: TCommonFileHeader; //
FileCommentLength: WORD; // 2 bytes
DiskNumberStart: WORD; // 2 bytes
InternalFileAttributes: WORD; // 2 bytes
ExternalFileAttributes: DWORD; // 4 bytes
RelativeOffsetOfLocalHeader: DWORD; // 4 bytes
filename: TBytes; //variable size
extrafield: RawByteString; //variable size
fileComment: AnsiString; //variable size
{$IFDEF ZIP_AES}
AESInfo : TAESExtraData; // By Rapid D
{$ENDIF ZIP_AES}
function UTFSupport: Boolean;
end;
TEndOfCentralDir = packed record
EndOfCentralDirSignature: DWORD; // 4 bytes (0x06054b50)
NumberOfThisDisk: WORD; // 2 bytes
NumberOfTheDiskWithTheStart: WORD; // 2 bytes
TotalNumberOfEntriesOnThisDisk: WORD; // 2 bytes
TotalNumberOfEntries: WORD; // 2 bytes
SizeOfTheCentralDirectory: DWORD; // 4 bytes
OffsetOfStartOfCentralDirectory: DWORD; // 4 bytes
ZipfileCommentLength: WORD; // 2 bytes
end;
TZipFile = class(TObject)
private
Files: array of TLocalFile;
CentralDirectory: array of TFileHeader;
EndOfCentralDirectory: TEndOfCentralDir;
public
ZipFileComment: AnsiString;
Password : AnsiString;
// fCompressionLevel : Integer;
private
function GetUncompressed(i: integer): RawByteString;
procedure SetUncompressed(i: integer; const Value: RawByteString);
procedure Uncompress2Stream(I:Integer; Stream : TStream);
function GetDateTime(i: integer): TDateTime;
procedure SetDateTime(i: integer; const Value: TDateTime);
function GetCount: integer;
function GetName(i: integer): string;
procedure SetName(i: integer; const Value: string);
public
function AddFile(const name: string; FAttribute: DWord = 0; const pPass: AnsiString = '';
const pData : RawByteString = '') : Integer;
function AddExtFile(const pFileName : String; const name: string = '';
FAttribute: DWord = 0; const pPass: AnsiString = '') : Integer;
procedure SaveToFile(const filename: string);
procedure SaveToStream(ZipFileStream: TStream);
procedure LoadFromFile(const filename: string; pPreview : Boolean = false);
procedure LoadFromStream(const ZipFileStream: TStream; pPreview: Boolean = false);
function IndexOf(const s: String) : Integer;
Function ExtractToStream(const fn : String; Stream : TStream) : Boolean; Overload;
function ExtractToStream(i : Integer; Stream : TStream) : Boolean; Overload;
function IsEncrypted(i : Integer) : Boolean;
function CheckPassword(I:Integer; const pass : AnsiString) : Boolean;
property Count: integer read GetCount;
// property Uncompressed[i: integer]: AnsiString read GetUncompressed;
//write SetUncompressed;
property Data[i: integer]: RawByteString read GetUncompressed
write SetUncompressed;
// property CompressionLevel : Integer read fCompressionLevel write fCompressionLevel;
property DateTime[i: integer]: TDateTime read GetDateTime write SetDateTime;
property Name[i: integer]: string read GetName write SetName;
end;
EZipFileCRCError = class(Exception);
const
dwLocalFileHeaderSignature = $04034B50;
dwLocalFileDescriptorSignature = $08074B50;
dwCentralFileHeaderSignature = $02014B50;
dwEndOfCentralDirSignature = $06054b50;
wAESEncrSignature = $9901;
function ZipCrc32(crc: Cardinal; const buffer : PByteArray; size: Integer): Cardinal; OverLoad;
function ZipCrc32(crc: Cardinal; const stream : TStream): Cardinal; OverLoad;
//function ZipCRC32(const Data: string): longword;
Function ToZipName(const FileName:String):String;
Function ToDosName(const FileName:String):String;
function CheckZIPFilePass(const zipfn, fn : String; const pass : AnsiString) : Boolean;
implementation
uses
// zlibEx,
OverbyteIcsZLibObj,
OverbyteIcsZLibHigh,
{$IFDEF ZIP_AES}
AES_HMAC,
{$ENDIF ZIP_AES}
{$IFDEF UNICODE}
AnsiStrings,
{$ENDIF UNICODE}
RDFileUtil, RDUtils,
Math;
const
ZL_DEF_COMPRESSIONMETHOD = $8; { Deflate }
ZL_ENCH_COMPRESSIONMETHOD = $9; { Enchanced Deflate }
ZL_DEF_COMPRESSIONINFO = $7; { 32k window for Deflate }
ZL_PRESET_DICT = $20;
ZL_FASTEST_COMPRESSION = $0;
ZL_FAST_COMPRESSION = $1;
ZL_DEFAULT_COMPRESSION = $2;
ZL_MAXIMUM_COMPRESSION = $3;
ZL_FCHECK_MASK = $1F;
ZL_CINFO_MASK = $F0; { mask out leftmost 4 bits }
ZL_FLEVEL_MASK = $C0; { mask out leftmost 2 bits }
ZL_CM_MASK = $0F; { mask out rightmost 4 bits }
//procedure make_crc_table;
var
crc_table:array[0..255]of Cardinal;
crc_table_computed:Boolean;
procedure make_crc_table;
var c:Cardinal;
n,k:Integer;
begin
for n:=0 to 255 do
begin
c:=Cardinal(n);
for k:=0 to 7 do
begin
if Boolean(c and 1) then
c:=$edb88320 xor (c shr 1) else c:=c shr 1;
end;
crc_table[n]:=c;
end;
crc_table_computed:=True;
end;
function update_crc(crc:Cardinal;buf:PByteArray;len:Integer):Cardinal;
var c:Cardinal;
n:Integer;
begin
c:=crc;
if not crc_table_computed then
make_crc_table;
for n:=0 to len-1 do
c:=crc_table[(c xor buf^[n]) and $FF] xor (c shr 8);
Result:=c;
end;
function ZipCrc32(crc: Cardinal; const buffer: PByteArray; size: Integer): Cardinal;
var c:Cardinal;
n:Integer;
begin
c:=crc;
if not crc_table_computed then
make_crc_table;
for n:=0 to size-1 do
c:=crc_table[(c xor buffer^[n]) and $FF] xor (c shr 8);
Result:=c;
end;
function ZipCrc32(crc: Cardinal; const stream : TStream): Cardinal;
var c:Cardinal;
n:Integer;
buf : Byte;
begin
c:=crc;
if not crc_table_computed then
make_crc_table;
stream.Position := 0;
for n:=0 to stream.size-1 do
begin
stream.Read(buf, 1);
c:=crc_table[(c xor buf) and $FF] xor (c shr 8);
end;
Result:=c;
end;
{function ZCrc32(crc: Cardinal; const stream : TStream): Cardinal;
var c:Cardinal;
// n:Integer;
a : byte;
Res : Int64;
buf : array[0..254] of Byte;
begin
c:=crc;
// if not crc_table_computed then
// make_crc_table;
stream.Position := 0;
Res := stream.size;
while Res > 0 do
begin
a := stream.Read(buf, $FF);
c := crc32(c, @buf[0], a) xor $FFFFFFFF;
dec(Res, a);
end;
Result:=c xor $FFFFFFFF;
end;
}
function TFileHeader.UTFSupport: Boolean;
begin
result := Self.CommonFileHeader.GeneralPurposeBitFlag and (1 shl 11) > 0
end;
function TLocalFile.UTFSupport: Boolean;
begin
result := Self.CommonFileHeader.GeneralPurposeBitFlag and (1 shl 11) > 0
end;
{ TZipFile }
procedure TZipFile.SaveToFile(const filename: string);
var
ZipFileStream: TFileStream;
begin
ZipFileStream := TFileStream.Create(filename, fmCreate);
try
SaveToStream(ZipFileStream);
finally
ZipFileStream.Free;
end;
end;
procedure TZipFile.SaveToStream(ZipFileStream: TStream);
var
i: integer;
dw: DWORD;
cfh: TCommonFileHeader;
additionalDescriptor: Boolean;
begin
for i := 0 to High(Files) do
with Files[i] do
begin
CentralDirectory[i].RelativeOffsetOfLocalHeader :=
ZipFileStream.Position;
ZipFileStream.Write(LocalFileHeaderSignature, 4);
if (LocalFileHeaderSignature = (dwLocalFileHeaderSignature)) then
begin
cfh := CommonFileHeader;
additionalDescriptor :=((cfh.GeneralPurposeBitFlag AND 8) = 8);
if additionalDescriptor then
begin
cfh.FileDesc.Crc32 := 0;
cfh.FileDesc.CompressedSize := 0;
cfh.FileDesc.UncompressedSize := 0;
end;
ZipFileStream.Write(cfh, SizeOf(CommonFileHeader));
ZipFileStream.Write(PByte(filename)^,
CommonFileHeader.FilenameLength);
ZipFileStream.Write(PByte(extrafield)^,
CommonFileHeader.ExtraFieldLength);
ZipFileStream.Write(PByte(CompressedData)^,
CommonFileHeader.FileDesc.CompressedSize);
if additionalDescriptor then
begin
dw := dwLocalFileDescriptorSignature;
ZipFileStream.Write(dw, 4);
ZipFileStream.Write(CommonFileHeader.FileDesc, SizeOf(CommonFileHeader.FileDesc));
end
end;
end;
EndOfCentralDirectory.OffsetOfStartOfCentralDirectory :=
ZipFileStream.Position;
for i := 0 to High(CentralDirectory) do
with CentralDirectory[i] do
begin
ZipFileStream.Write(CentralFileHeaderSignature, 4);
ZipFileStream.Write(VersionMadeBy, 2);
ZipFileStream.Write(CommonFileHeader, SizeOf(CommonFileHeader));
ZipFileStream.Write(FileCommentLength, 2);
ZipFileStream.Write(DiskNumberStart, 2);
ZipFileStream.Write(InternalFileAttributes, 2);
ZipFileStream.Write(ExternalFileAttributes, 4);
ZipFileStream.Write(RelativeOffsetOfLocalHeader, 4);
ZipFileStream.Write(PByte(filename)^, length(filename));
ZipFileStream.Write(PByte(extrafield)^, length(extrafield));
ZipFileStream.Write(PByte(fileComment)^, length(fileComment));
end;
with EndOfCentralDirectory do
begin
EndOfCentralDirSignature := dwEndOfCentralDirSignature;
NumberOfThisDisk := 0;
NumberOfTheDiskWithTheStart := 0;
TotalNumberOfEntriesOnThisDisk := High(Files) + 1;
TotalNumberOfEntries := High(Files) + 1;
SizeOfTheCentralDirectory :=
ZipFileStream.Position - OffsetOfStartOfCentralDirectory;
ZipfileCommentLength := length(ZipFileComment);
end;
ZipFileStream.Write(EndOfCentralDirectory, SizeOf(EndOfCentralDirectory));
ZipFileStream.Write(PByte(ZipFileComment)^, length(ZipFileComment));
end;
procedure TZipFile.LoadFromStream(const ZipFileStream: TStream; pPreview : Boolean = false);
var
n: integer;
signature: DWORD;
begin
n := 0;
repeat
signature := 0;
ZipFileStream.Read(signature, 4);
if (ZipFileStream.Position = ZipFileStream.Size) then exit;
until signature = dwLocalFileHeaderSignature;
repeat
begin
if (signature = dwLocalFileHeaderSignature) then
begin
inc(n);
SetLength(Files, n);
SetLength(CentralDirectory, n);
with Files[n - 1] do
begin
LocalFileHeaderSignature := signature;
ZipFileStream.Read(CommonFileHeader, SizeOf(CommonFileHeader));
SetLength(filename, CommonFileHeader.FilenameLength);
ZipFileStream.Read(PByte(filename)^,
CommonFileHeader.FilenameLength);
SetLength(extrafield, CommonFileHeader.ExtraFieldLength);
ZipFileStream.Read(PByte(extrafield)^,
CommonFileHeader.ExtraFieldLength);
{
if ((CommonFileHeader.GeneralPurposeBitFlag and 8) = 8) then
begin
searchSignature := 0;
rawData := '';
repeat
ZipFileStream.Read(searchSignature, 4);
if searchSignature <> dwLocalFileDescriptorSignature then
begin
ZipFileStream.Seek(-4, soFromCurrent);
ZipFileStream.Read(c, SizeOf(c));
rawData := rawData + c;
end;
until searchSignature = dwLocalFileDescriptorSignature;
CompressedData := rawData;
ZipFileStream.Read(CommonFileHeader.FileDescriptor, SizeOf(CommonFileHeader.FileDescriptor));
end
else
begin
SetLength(CompressedData, CommonFileHeader.FileDescriptor.CompressedSize);
ZipFileStream.Read(PChar(CompressedData)^, CommonFileHeader.FileDescriptor.CompressedSize);
end;
}
DataOffset := ZipFileStream.Position;
if pPreview then
begin
DataLoaded := False;
SetLength(CompressedData, 0);
ZipFileStream.Seek(CommonFileHeader.FileDesc.CompressedSize, soCurrent)
end
else
begin
DataLoaded := True;
SetLength(CompressedData, CommonFileHeader.FileDesc.CompressedSize);
ZipFileStream.Read(PByte(CompressedData)^,
CommonFileHeader.FileDesc.CompressedSize);
end;
end;
end;
end;
signature := 0;
ZipFileStream.Read(signature, 4);
until signature <> (dwLocalFileHeaderSignature);
n := 0;
repeat
begin
if (signature = dwCentralFileHeaderSignature) then
begin
inc(n);
with CentralDirectory[n - 1] do
begin
CentralFileHeaderSignature := signature;
ZipFileStream.Read(VersionMadeBy, 2);
ZipFileStream.Read(CommonFileHeader, SizeOf(CommonFileHeader));
ZipFileStream.Read(FileCommentLength, 2);
ZipFileStream.Read(DiskNumberStart, 2);
ZipFileStream.Read(InternalFileAttributes, 2);
ZipFileStream.Read(ExternalFileAttributes, 4);
ZipFileStream.Read(RelativeOffsetOfLocalHeader, 4);
SetLength(filename, CommonFileHeader.FilenameLength);
ZipFileStream.Read(PAnsiChar(filename)^,
CommonFileHeader.FilenameLength);
SetLength(extrafield, CommonFileHeader.ExtraFieldLength);
ZipFileStream.Read(PAnsiChar(extrafield)^,
CommonFileHeader.ExtraFieldLength);
SetLength(fileComment, FileCommentLength);
ZipFileStream.Read(PAnsiChar(fileComment)^, FileCommentLength);
//By Rapid D 20080601 ->
{$IFDEF ZIP_AES}
if (CommonFileHeader.ExtraFieldLength >= SizeOf(TAESExtraData))
and (extrafield[1] = #$01)and(extrafield[2] = #$99) then
begin
CopyMemory(@AESInfo, PAnsiChar(extrafield), SizeOf(TAESExtraData) );
end;
{$ENDIF ZIP_AES}
//
end;
end;
end;
signature := 0;
ZipFileStream.Read(signature, 4);
until signature <> (dwCentralFileHeaderSignature);
if signature = dwEndOfCentralDirSignature then
begin
EndOfCentralDirectory.EndOfCentralDirSignature := Signature;
ZipFileStream.Read(EndOfCentralDirectory.NumberOfThisDisk,
SizeOf(EndOfCentralDirectory) - 4);
SetLength(ZipFileComment, EndOfCentralDirectory.ZipfileCommentLength);
ZipFileStream.Read(PByte(ZipFileComment)^,
EndOfCentralDirectory.ZipfileCommentLength);
end;
end;
procedure TZipFile.LoadFromFile(const filename: string; pPreview : Boolean = false);
var
ZipFileStream: TFileStream;
begin
ZipFileStream := TFileStream.Create(filename, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(ZipFileStream, pPreview);
finally
ZipFileStream.Free;
end;
end;
function TZipFile.GetUncompressed(I:Integer): RawByteString;
var // Decompressor:TDecompressionStream;
ResultStream : TMemoryStream;
UncSize : Int64;
{ CompressedStream:TMemoryStream;
AHeader:AnsiString;
ReadBytes:Integer;
LoadedCrc32:DWORD;}
begin
if (I<0) or (I>High(Files)) then
raise Exception.Create('Index out of range.');
ResultStream := TMemoryStream.Create;
try
Uncompress2Stream(i, ResultStream);
UncSize := ResultStream.Size;
SetLength(Result, UncSize);
if UncSize > 0 then
CopyMemory(Pointer(Result), ResultStream.Memory, UncSize);
except
Result := '';
end;
ResultStream.Free;
end;
function TZipFile.CheckPassword(I:Integer; const pass : AnsiString) : Boolean;
var
// ReadBytes2 : Integer;
l : Integer;
{$IFDEF ZIP_AES}
salt2 : RawByteString;
// key : Ansistring;
pwd_ver : RawByteString;
// pwd_verW : Word;
cx : fcrypt_ctx;
// cx : T_fcrypt_ctx;
s1 : RawByteString;
// data : TData_Type;
{$ENDIF ZIP_AES}
begin
if (I<0) or (I>High(Files)) then
begin
Result := False;
Exit;
end;
if Files[I].CommonFileHeader.CompressionMethod=99 then // Encrypted
begin
// raise EZDecompressionError.CreateFmt('Encryption is not supported',[]);
{$IFDEF ZIP_AES}
// Password := '123';
l := SALT_LENGTH[CentralDirectory[i].AESInfo.AESMode];
// l := SALT_LENGTH(CentralDirectory[i].AESInfo.AESMode);
SetLength(salt2, l);
// CopyMemory(@salt2[1], @Files[I].CompressedData[1], l);
Move(Pointer(Files[I].CompressedData)^, Pointer(salt2)^, l);
AES_HMAC.fcrypt_init(CentralDirectory[i].AESInfo.AESMode, pass, salt2, pwd_ver, cx);
// AES_HMAC.fcrypt_end(cx);
// fcrypt_init(CentralDirectory[i].AESInfo.AESMode, @pass[1], Length(pass), @salt2[1], pwd_verW, cx);
// SetLength(pwd_ver, 2);
// CopyMemory(@pwd_ver[1], @pwd_verW, 2);
s1 := Copy(Files[I].CompressedData, l+1, 2);
if s1 <> pwd_ver then
Result := false
else
{$ENDIF ZIP_AES}
Result := True;
end
else
Result := True;
end;
procedure TZipFile.Uncompress2Stream(I:Integer; Stream : TStream);
var
// Decompressor:TDecompressionStream;
// CompressedStream : TMemoryStream;
// UncompressedStream:TStringStream;
// CompressedStream:TStringStream;
ComprStream:TMemoryStream;
AHeader: RawByteString;
FZLHeader : TZLibStreamHeader;
// ReadBytes:Integer;
// ReadBytes2 : Integer;
l : Integer;
LoadedCrc32:DWORD;
data : Pointer;
{$IFDEF ZIP_AES}
salt2 : RawByteString;
// key : Ansistring;
pwd_ver : RawByteString;
cx : fcrypt_ctx;
s1, s2 : RawByteString;
// data : TData_Type;
dataLen : Integer;
Cont_Size : Integer;
// pwd_verW : word;
// cx : DIFileEncrypt.T_fcrypt_ctx;
{$ENDIF ZIP_AES}
ZLH : Word;
Compress : Byte;
begin
if (I<0) or (I>High(Files)) then
raise Exception.Create('Index out of range.');
if not Files[i].DataLoaded then
raise Exception.Create('File was not decompressed.');
// AHeader:=Chr(120)+Chr(156);
AHeader:=RawByteString(#$78)+#$9C;
ZLH := Files[I].CommonFileHeader.CompressionMethod;
if (ZLH=8)or (ZLH=9)or (ZLH = 99) Then
Begin
// FZLHeader.CMF := $78;
// FZLHeader.FLG := $9C;
FZLHeader.CMF := (ZL_DEF_COMPRESSIONINFO shl 4); { 32k Window size }
FZLHeader.CMF := FZLHeader.CMF or ZL_DEF_COMPRESSIONMETHOD; { Deflate }
Compress := ZL_DEFAULT_COMPRESSION;
Case Files[I].CommonFileHeader.GeneralPurposeBitFlag AND 6 of
0 : Compress := ZL_DEFAULT_COMPRESSION;
2 : Compress := ZL_MAXIMUM_COMPRESSION;
4 : Compress := ZL_FAST_COMPRESSION;
6 : Compress := ZL_FASTEST_COMPRESSION;
End;
FZLHeader.FLG := FZLHeader.FLG or (Compress shl 6);
FZLHeader.FLG := FZLHeader.FLG and not ZL_PRESET_DICT; { no preset dictionary}
FZLHeader.FLG := FZLHeader.FLG and not ZL_FCHECK_MASK;
ZLH := (FZLHeader.CMF * 256) + FZLHeader.FLG;
Inc(FZLHeader.FLG, 31 - (ZLH mod 31));
// Result := Result + Stream.Write(FZLHeader,SizeOf(FZLHeader));
SetLength(AHeader, 2);
AHeader[1] := AnsiChar(FZLHeader.CMF);
AHeader[2] := AnsiChar(FZLHeader.FLG);
End;
Stream.Size := 0;
if Files[I].CommonFileHeader.CompressionMethod=0 then //not compressed
begin
Stream.Write(Files[I].CompressedData[1], length(Files[I].CompressedData));
// Result:=Files[I].CompressedData;
end else
if Files[I].CommonFileHeader.CompressionMethod=99 then // Encrypted
begin
// raise EZDecompressionError.CreateFmt('Encryption is not supported',[]);
{$IFDEF ZIP_AES}
// Password := '123';
l := SALT_LENGTH[CentralDirectory[i].AESInfo.AESMode];
// l := SALT_LENGTH(CentralDirectory[i].AESInfo.AESMode);
SetLength(salt2, l);
Move(Pointer(Files[I].CompressedData)^, Pointer(salt2)^, l);
AES_HMAC.fcrypt_init(CentralDirectory[i].AESInfo.AESMode, Password, salt2, pwd_ver, cx);
// fcrypt_init(CentralDirectory[i].AESInfo.AESMode, @Password[1], Length(Password), @salt2[1], pwd_verW, cx);
// SetLength(pwd_ver, 2);
// CopyMemory(@pwd_ver[1], @pwd_verW, 2);
s1 := Copy(Files[I].CompressedData, l+1, 2);
if s1 <> pwd_ver then
// raise EZDecompressionError.CreateFmt('Wrong password',[]);
raise Exception.Create('Wrong password.');
Cont_Size := l+2;
dataLen := Files[I].CommonFileHeader.FileDesc.CompressedSize - Cont_Size - 10;//MAC_LENGTH;
// if dataLen > 0 then
begin
s2 := Copy(Files[I].CompressedData, Cont_Size + dataLen + 1, 10);
ComprStream := TMemoryStream.Create;
ComprStream.Write(AHeader[1], 2);
ComprStream.Write(Files[I].CompressedData[Cont_Size+1], dataLen);
ComprStream.Position := 0;
data := Pointer(cardinal(ComprStream.Memory)+2);
// data := ComprStream.Memory+2;
// ReadBytes := 0;
// for l := 1 to Files[I].CommonFileHeader.UncompressedSize div SizeOf(buf) do
if dataLen > 0 then
AES_HMAC.fcrypt_decrypt(data, dataLen, cx);
// fcrypt_decrypt(data, dataLen, cx2);
// AES_HMAC.fcrypt_decrypt(data, dataLen, fcrypt_ctx((@cx2)^));
// fcrypt_decrypt(ComprStream.Memory, dataLen, cx);
{ l := dataLen;
while l >= 16 do
begin
fcrypt_decrypt(data, 16, cx);
dec(l, 16);
inc(Cardinal(data), 16);
end;
if l > 0 then
fcrypt_decrypt(data, l, cx);
}
s1 := AES_HMAC.fcrypt_end(cx);
if dataLen > 0 then
if CentralDirectory[i].AESInfo.CompressMethod = 0 then
begin
// ComprStream.Position := 0;
ComprStream.Position := 2;
Stream.CopyFrom(ComprStream, dataLen);
// Stream.Write(data, dataLen);
// Stream.Write(Files[I].CompressedData[Cont_Size+1], dataLen)
// Stream.Write(Files[I].CompressedData[Cont_Size+1], dataLen)
ComprStream.Free;
end
else
begin
ComprStream.Position := 0;
// CompressedStream.CopyFrom(ComprStream, dataLen);
try
ZlibDecompressStream(ComprStream, Stream);
// ZDecompressStream(ComprStream, Stream);
// ReadBytes := Stream.Size;
finally
// UncompressedStream.Free;
// CompressedStream.Free;
ComprStream.Free;
end;
end;
end;
// Files[I].CommonFileHeader.Crc32 := 0;
{$ENDIF ZIP_AES}
end else
begin
// UncompressedStream:=TStringStream.Create(AHeader+Files[I].CompressedData);
// CompressedStream := TStringStream.Create(AHeader+Files[I].CompressedData);
ComprStream := TMemoryStream.Create;
ComprStream.SetSize(Length(AHeader) + Length(Files[I].CompressedData));
CopyMemory(ComprStream.Memory, @AHeader[1], Length(AHeader));
data := ComprStream.Memory;
INT_PTR(data) := INT_PTR(data) + Length(AHeader);
// inc(data, Length(AHeader));
CopyMemory(data, @Files[I].CompressedData[1], Length(Files[I].CompressedData));
ZlibDecompressStream(ComprStream, Stream);
// ZDecompressStream(ComprStream, Stream);
ComprStream.Free;
// LoadedCRC32:=ZipCRC32(Result);
// LoadedCRC32 := ZCrc32($FFFFFFFF, @Result[1], Length(Result)) XOR $FFFFFFFF;
Stream.Position := 0;
LoadedCRC32 := ZipCrc32($FFFFFFFF, Stream) XOR $FFFFFFFF;
// LoadedCRC32 := Crc32($FFFFFFFF, TMemoryStream(Stream).Memory, Stream.Size) XOR $FFFFFFFF;
if LoadedCRC32<>Files[I].CommonFileHeader.FileDesc.Crc32 then
raise EZipFileCRCError.CreateFmt('CRC Error in "%s".',[Files[I].FileName]);
end;
end;
Function TZipFile.ExtractToStream(const fn : String; Stream : TStream) : Boolean;
var
i : Integer;
begin
i := IndexOf(fn);
if i >=0 then
begin
// if not Assigned(Stream) then
// Stream := TMemoryStream.Create;
Stream.Size := 0;
Stream.Position := 0;
Result := ExtractToStream(i, Stream);
end
else
Result := False;
end;
Function TZipFile.ExtractToStream(i : Integer; Stream : TStream) : Boolean;
//var
// S:String;
begin
if (I<0) or (I>High(Files)) then
raise Exception.Create('Index out of range.');
// S:=GetUncompressed(i);
Uncompress2Stream(i, Stream);
// if s > '' then
if (Stream.Size > 0)or(Files[I].CommonFileHeader.FileDesc.UncompressedSize=0) then
begin
// Stream.Write(S[1],length(S));
Result := True;
end
else
Result := False;
// SetLength(s, 0);
end;
procedure TZipFile.SetUncompressed(i: integer; const Value: RawByteString);
const
TestRPNG = RawByteString(#$CC#$7D#$42#$93#$04#$FE#$63#$7C#$B0#$46#$AD#$CE#$8F#$85#$63#$11);
var
// Compressor: TCompressionStream;
// CompressedStream: TStringStream;
resStream : TMemoryStream;
UnComprStream : TMemoryStream;
Data : Pointer;
ComprDataNIL : RawByteString;
ComprSize : Int64;
{$IFDEF ZIP_AES}
isEncr : Boolean;
aesMode : byte;
salt2 : RawByteString;
pwd_ver : RawByteString;
cx : fcrypt_ctx;
// cx : T_fcrypt_ctx;
// pwd_verW : Word;
s1 : RawByteString;
l, ofs : Integer;
// data1 : Pointer;
// EncrSize : Cardinal;
{$ENDIF ZIP_AES}
begin
if i > High(Files) then // exit;
raise Exception.Create('Index out of range.');
// compressedStream := TStringStream.Create('');
try {+}
// compressor := TcompressionStream.Create(CompressedStream, clMax);
// compressor := TcompressionStream.Create(CompressedStream, clDefault);
// compressor := TcompressionStream.Create(clDefault, CompressedStream);
if Value = '' then
begin
ComprSize := 2;
resStream := NIL;
ComprDataNIL := #03#00;
// Files[i].CompressedData := ;
data := @ComprDataNIL[1];
end
else
begin
UnComprStream := TMemoryStream.Create;
UnComprStream.SetSize(Length(Value));
CopyMemory(UnComprStream.Memory, Pointer(Value), Length(Value));
resStream := TMemoryStream.Create;
// ZlibCompressStreamEx(UnComprStream, resStream, clMax, zsZLib, false);
ZlibCompressStreamEx(UnComprStream, resStream, clMax, zsZLib, True);
UnComprStream.Free;
// ZCompressStream(UnComprStream, resStream, clMax);
ComprSize := resStream.Size - 6;
resStream.Position := 0;
Data := resStream.Memory;
inc(INT_PTR(Data), 2);
end;
{$IFDEF ZIP_AES}
isEncr := Files[i].pass > '';
if isEncr then
begin
// salt2 := 'Testing encription';
// salt2 := #$FA#$48#$CB#$73#$F9#$65#$A2#$87#$85#$83#$CE#$79#$60#$3C#$08#$90;
salt2 := TestRPNG;
aesMode := 3;
l := AES_HMAC.SALT_LENGTH[aesMode];
// l := SALT_LENGTH(aesMode);
SetLength(salt2, l);
AES_HMAC.fcrypt_init(aesMode, Files[i].pass, salt2, pwd_ver, cx);
// fcrypt_init(aesMode, @Files[i].pass[1], Length(Files[i].pass), @salt2[1], pwd_verW, cx);
// SetLength(pwd_ver, 2);
// CopyMemory(@pwd_ver[1], @pwd_verW, 2);
if ComprSize > 0 then
begin
// ofs := ComprSize mod 16;
// EncrSize := ComprSize - ofs;
// fcrypt_encrypt(data, EncrSize, cx);
fcrypt_encrypt(data, ComprSize, cx);
{ if ofs > 0 then
begin
data1 := data;
inc(Cardinal(Data1), EncrSize);
fcrypt_encrypt(data1, ofs, cx);
end;}
end;
s1 := AES_HMAC.fcrypt_end(cx);
// SetLength(s1, 10);
// fcrypt_end(@s1[1], cx);
ofs := l + 2 + ComprSize + 10;
SetLength(Files[i].CompressedData, ofs);
ofs := 1;
CopyMemory(@Files[i].CompressedData[ofs], Pointer(salt2), l);
inc(ofs, l); // Salt
CopyMemory(@Files[i].CompressedData[ofs], Pointer(pwd_ver), 2);
inc(ofs, 2); // Pwd_ver
CopyMemory(@Files[i].CompressedData[ofs], Data, ComprSize);
inc(ofs, ComprSize); // Data
CopyMemory(@Files[i].CompressedData[ofs], Pointer(s1), 10);
end
else
{$ENDIF ZIP_AES}
// if Value > '' then
begin
SetLength(Files[i].CompressedData, ComprSize);
CopyMemory(Pointer(Files[i].CompressedData), Data, ComprSize);
end;
if Assigned(resStream) then
resStream.Free;
(* Files[i].CompressedData := Copy(compressedStream.DataString, 3,
length(compressedStream.DataString) - 6);
try {+}
compressor.Write(PByte(Value)^, length(Value));
finally
compressor.Free;
end;
Files[i].CompressedData := Copy(compressedStream.DataString, 3,
length(compressedStream.DataString) - 6);
//strip the 2 byte headers and 4 byte footers
*)
Files[i].LocalFileHeaderSignature := (dwLocalFileHeaderSignature);
with Files[i].CommonFileHeader do
begin
// VersionNeededToExtract := 20;
// GeneralPurposeBitFlag := 0;
// CompressionMethod := 8;
LastModFileTimeDate := DateTimeToFileDate(Now);
// Crc32 := ZipCRC32(Value);
// Crc32 := OverbyteIcsZLibObj.Crc32($FFFFFFFF, @Value[1], Length(Value)) XOR $FFFFFFFF;
{$IFDEF ZIP_AES}
if isEncr then
begin
CompressionMethod := 99;
GeneralPurposeBitFlag := GeneralPurposeBitFlag or 1;
FileDesc.Crc32 := 0;
end
else
{$ENDIF ZIP_AES}
begin
CompressionMethod := 8;
GeneralPurposeBitFlag := GeneralPurposeBitFlag and (not 1);
// Crc32 := ZipCrc32($FFFFFFFF, @Value[1], Length(Value)) XOR $FFFFFFFF;
FileDesc.Crc32 := ZipCrc32($FFFFFFFF, Pointer(Value), Length(Value)) XOR $FFFFFFFF;
end;
FileDesc.CompressedSize := length(Files[i].CompressedData);
FileDesc.UncompressedSize := length(Value);
// FilenameLength := length(Files[i].filename);
// ExtraFieldLength := length(Files[i].extrafield);
end;
with CentralDirectory[i] do
begin
CentralFileHeaderSignature := dwCentralFileHeaderSignature;
// VersionMadeBy := 20;
CommonFileHeader := Files[i].CommonFileHeader;
// FileCommentLength := 0;
// DiskNumberStart := 0;
// InternalFileAttributes := 0;
// ExternalFileAttributes := 0;
// RelativeOffsetOfLocalHeader := 0;
// filename := Files[i].filename;
// extrafield := Files[i].extrafield;
fileComment := '';
end;
finally
// compressedStream.Free;
end;
end;
function TZipFile.AddFile(const name: string; FAttribute: DWord = 0; const pPass: AnsiString = '';
const pData : RawByteString = '') : Integer;
var
h : Integer;
{$IFDEF ZIP_AES}
isEncr : Boolean;
vAES_DATA : TAESExtraData;
// salt2 : RawByteString;
// pwd_ver : RawByteString;
// cx : fcrypt_ctx;
// cx : T_fcrypt_ctx;
// pwd_verW : Word;
// s1 : RawByteString;
// ofs : Integer;
// l : Integer;
// dataLen : Integer;
// Cont_Size : Integer;
{$ENDIF ZIP_AES}
begin
Result := -1;
SetLength(Files, High(Files) + 2);
SetLength(CentralDirectory, length(Files));
h := High(Files);
Files[h].CommonFileHeader.GeneralPurposeBitFlag := Files[h].CommonFileHeader.GeneralPurposeBitFlag or (1 shl 11); // UTF8 support
Files[h].filename := StringToTBytes(name);
Files[h].extrafield := '';
Files[h].pass := pPass;
{$IFDEF ZIP_AES}
isEncr := pPass > '';
Files[h].LocalFileHeaderSignature := dwLocalFileHeaderSignature;
if isEncr then
begin
vAES_DATA.HeaderID := wAESEncrSignature;
vAES_DATA.DataSize := 7;
vAES_DATA.Version := $0002; // The vendor version for AE-2 is 0x0002
vAES_DATA.Vendor := Byte('E') shl 8 + byte('A');
vAES_DATA.AESMode := $03; // $03 - 256-bit encryption key
vAES_DATA.CompressMethod := 8;
SetLength(Files[h].extrafield, SIZEOF(TAESExtraData));
CopyMemory(PAnsiChar(Files[h].extrafield), @vAES_DATA, SizeOf(TAESExtraData));
end;
{$ENDIF ZIP_AES}
with Files[h].CommonFileHeader do
begin
VersionNeededToExtract := 20;
(*
{$IFDEF ZIP_AES}
if isEncr then
begin
CompressionMethod := 99;
GeneralPurposeBitFlag := 1;
CompressedSize := l + 2 + 0 + 10;
end
else
{$ENDIF ZIP_AES}
*)
begin
CompressionMethod := 8;
GeneralPurposeBitFlag := GeneralPurposeBitFlag and (not 1);
FileDesc.CompressedSize := 0;
end;
// GeneralPurposeBitFlag := GeneralPurposeBitFlag or 2; // ZL_MAXIMUM_COMPRESSION
LastModFileTimeDate := DateTimeToFileDate(Now);
FileDesc.Crc32 := 0;
FileDesc.UncompressedSize := 0;
FilenameLength := length(Files[h].filename);
ExtraFieldLength := length(Files[h].extrafield);
end;
with CentralDirectory[h] do
begin
CentralFileHeaderSignature := dwCentralFileHeaderSignature;
VersionMadeBy := 20;
CommonFileHeader := Files[h].CommonFileHeader;
FileCommentLength := 0;
DiskNumberStart := 0;
InternalFileAttributes := 0;
ExternalFileAttributes := FAttribute;
RelativeOffsetOfLocalHeader := 0;
filename := Files[h].filename;
extrafield := Files[h].extrafield;
fileComment := '';
end;
SetUncompressed(h, pData);
{ if Length(data) > 0 then
begin
end
else
Files[h].CompressedData := ''; //start with an empty file
}
Result := h;
end;
function TZipFile.AddExtFile(const pFileName : String; const name: string = '';
FAttribute: DWord = 0; const pPass: AnsiString = '') : Integer;
var
buf : RawByteString;
lFN : String;
begin
buf := loadFileA(pFileName);
if name = '' then
lFN := ExtractFileName(pFileName)
else
lFN := name;
result := AddFile(lFN, FAttribute, pPass, buf);
buf := '';
end;
function TZipFile.GetDateTime(i: integer): TDateTime;
begin
if i > High(Files) then // begin Result:=0; exit; end;
raise Exception.Create('Index out of range.');
result := FileDateToDateTime(Files[i].CommonFileHeader.LastModFileTimeDate);
end;
procedure TZipFile.SetDateTime(i: integer; const Value: TDateTime);
begin
if i > High(Files) then //exit;
raise Exception.Create('Index out of range.');
Files[i].CommonFileHeader.LastModFileTimeDate := DateTimeToFileDate(Value);
end;
function TZipFile.GetCount: integer;
begin
Result := High(Files) + 1;
end;
function TZipFile.GetName(i: integer): string;
begin
if Files[i].UTFSupport then
Result := TBytesToString(Files[i].filename, CP_UTF8)
else
Result := TBytesToString(Files[i].filename, 437)
;
end;
procedure TZipFile.SetName(i: integer; const Value: string);
begin
// Files[i].filename := Value;
if Files[i].UTFSupport then
Files[i].filename := StringToTBytes(Value, CP_UTF8)
else
Files[i].filename := StringToTBytes(Value, 437)
;
end;
function TZipFile.IndexOf(const s: String): Integer;
var
I: Integer;
b: String;
begin
Result := -1;
for I := 0 to Length(Files) - 1 do
begin
if Files[i].UTFSupport then
b := TBytesToString(Files[i].filename, CP_UTF8)
else
b := TBytesToString(Files[i].filename, 437);
if SameText(b, ToZipName(s)) then
begin
Result := i;
Exit;
end
end;
end;
function TZipFile.IsEncrypted(i: Integer): Boolean;
begin
if i > High(Files) then // exit;
raise Exception.Create('Index out of range.');
Result := Files[I].CommonFileHeader.CompressionMethod=99;
end;
{ ZipCRC32 }
//calculates the zipfile CRC32 value from a string
{
function ZipCRC32(const Data: string): longword;
const
CRCtable: array[0..255] of DWORD = (
$00000000, $77073096, $EE0E612C, $990951BA, $076DC419, $706AF48F, $E963A535,
$9E6495A3, $0EDB8832, $79DCB8A4,
$E0D5E91E, $97D2D988, $09B64C2B, $7EB17CBD, $E7B82D07, $90BF1D91, $1DB71064,
$6AB020F2, $F3B97148, $84BE41DE,
$1ADAD47D, $6DDDE4EB, $F4D4B551, $83D385C7, $136C9856, $646BA8C0, $FD62F97A,
$8A65C9EC, $14015C4F, $63066CD9,
$FA0F3D63, $8D080DF5, $3B6E20C8, $4C69105E, $D56041E4, $A2677172, $3C03E4D1,
$4B04D447, $D20D85FD, $A50AB56B,
$35B5A8FA, $42B2986C, $DBBBC9D6, $ACBCF940, $32D86CE3, $45DF5C75, $DCD60DCF,
$ABD13D59, $26D930AC, $51DE003A,
$C8D75180, $BFD06116, $21B4F4B5, $56B3C423, $CFBA9599, $B8BDA50F, $2802B89E,
$5F058808, $C60CD9B2, $B10BE924,
$2F6F7C87, $58684C11, $C1611DAB, $B6662D3D, $76DC4190, $01DB7106, $98D220BC,
$EFD5102A, $71B18589, $06B6B51F,
$9FBFE4A5, $E8B8D433, $7807C9A2, $0F00F934, $9609A88E, $E10E9818, $7F6A0DBB,
$086D3D2D, $91646C97, $E6635C01,
$6B6B51F4, $1C6C6162, $856530D8, $F262004E, $6C0695ED, $1B01A57B, $8208F4C1,
$F50FC457, $65B0D9C6, $12B7E950,
$8BBEB8EA, $FCB9887C, $62DD1DDF, $15DA2D49, $8CD37CF3, $FBD44C65, $4DB26158,
$3AB551CE, $A3BC0074, $D4BB30E2,
$4ADFA541, $3DD895D7, $A4D1C46D, $D3D6F4FB, $4369E96A, $346ED9FC, $AD678846,
$DA60B8D0, $44042D73, $33031DE5,
$AA0A4C5F, $DD0D7CC9, $5005713C, $270241AA, $BE0B1010, $C90C2086, $5768B525,
$206F85B3, $B966D409, $CE61E49F,
$5EDEF90E, $29D9C998, $B0D09822, $C7D7A8B4, $59B33D17, $2EB40D81, $B7BD5C3B,
$C0BA6CAD, $EDB88320, $9ABFB3B6,
$03B6E20C, $74B1D29A, $EAD54739, $9DD277AF, $04DB2615, $73DC1683, $E3630B12,
$94643B84, $0D6D6A3E, $7A6A5AA8,
$E40ECF0B, $9309FF9D, $0A00AE27, $7D079EB1, $F00F9344, $8708A3D2, $1E01F268,
$6906C2FE, $F762575D, $806567CB,
$196C3671, $6E6B06E7, $FED41B76, $89D32BE0, $10DA7A5A, $67DD4ACC, $F9B9DF6F,
$8EBEEFF9, $17B7BE43, $60B08ED5,
$D6D6A3E8, $A1D1937E, $38D8C2C4, $4FDFF252, $D1BB67F1, $A6BC5767, $3FB506DD,
$48B2364B, $D80D2BDA, $AF0A1B4C,
$36034AF6, $41047A60, $DF60EFC3, $A867DF55, $316E8EEF, $4669BE79, $CB61B38C,
$BC66831A, $256FD2A0, $5268E236,
$CC0C7795, $BB0B4703, $220216B9, $5505262F, $C5BA3BBE, $B2BD0B28, $2BB45A92,
$5CB36A04, $C2D7FFA7, $B5D0CF31,
$2CD99E8B, $5BDEAE1D, $9B64C2B0, $EC63F226, $756AA39C, $026D930A, $9C0906A9,
$EB0E363F, $72076785, $05005713,
$95BF4A82, $E2B87A14, $7BB12BAE, $0CB61B38, $92D28E9B, $E5D5BE0D, $7CDCEFB7,
$0BDBDF21, $86D3D2D4, $F1D4E242,
$68DDB3F8, $1FDA836E, $81BE16CD, $F6B9265B, $6FB077E1, $18B74777, $88085AE6,
$FF0F6A70, $66063BCA, $11010B5C,
$8F659EFF, $F862AE69, $616BFFD3, $166CCF45, $A00AE278, $D70DD2EE, $4E048354,
$3903B3C2, $A7672661, $D06016F7,
$4969474D, $3E6E77DB, $AED16A4A, $D9D65ADC, $40DF0B66, $37D83BF0, $A9BCAE53,
$DEBB9EC5, $47B2CF7F, $30B5FFE9,
$BDBDF21C, $CABAC28A, $53B39330, $24B4A3A6, $BAD03605, $CDD70693, $54DE5729,
$23D967BF, $B3667A2E, $C4614AB8,
$5D681B02, $2A6F2B94, $B40BBE37, $C30C8EA1, $5A05DF1B, $2D02EF8D);
var
i: integer;
begin
result := $FFFFFFFF;
for i := 0 to length(Data) - 1 do
result := (result shr 8) xor (CRCtable[byte(result) xor Ord(Data[i + 1])]);
result := result xor $FFFFFFFF;
end;
}
Function ToZipName(const FileName:String):String;
Var
P : Integer;
Begin
Result := FileName;
Result := StringReplace(Result,'\','/',[rfReplaceAll]);
P := Pos(':/',Result);
if P > 0 Then
Begin
System.Delete(Result,1,P+1);
End;
P := Pos('//',Result);
if P > 0 Then
Begin
System.Delete(Result,1,P+1);
P := Pos('/',Result);
if P > 0 Then
Begin
System.Delete(Result,1,P);
P := Pos('/',Result);
if P > 0 Then System.Delete(Result,1,P);
End;
End;
End;
Function ToDosName(const FileName:String):String;
Var
P : Integer;
Begin
Result := FileName;
Result := StringReplace(Result,'\','/',[rfReplaceAll]);
P := Pos(':/',Result);
if P > 0 Then
Begin
System.Delete(Result,1,P+1);
End;
P := Pos('//',Result);
if P > 0 Then
Begin
System.Delete(Result,1,P+1);
P := Pos('/',Result);
if P > 0 Then
Begin
System.Delete(Result,1,P);
P := Pos('/',Result);
if P > 0 Then System.Delete(Result,1,P);
End;
End;
Result := StringReplace(Result,'/','\',[rfReplaceAll]);
End;
function CheckZipFilePass(const zipfn, fn : String; const pass : AnsiString) : Boolean;
var
zp : TZipFile;
i : Integer;
begin
Result := False;
if FileExists(zipfn) then
begin
zp := TZipFile.Create;
zp.LoadFromFile(zipfn);
i := zp.IndexOf(fn);
if i >=0 then
begin
if zp.IsEncrypted(i) then
Result := zp.CheckPassword(i, pass)
else
Result := True;
end;
zp.Free;
end;
end;
end.