mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-28 10:02:14 +00:00
ADD: Zip - extract WinZip AES encrypted archives
This commit is contained in:
parent
7904ec884e
commit
7fdf1222ee
4 changed files with 354 additions and 25 deletions
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<Version Value="9"/>
|
||||
<Version Value="10"/>
|
||||
<PathDelim Value="\"/>
|
||||
<General>
|
||||
<SessionStorage Value="InProjectDir"/>
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
<VersionInfo>
|
||||
<UseVersionInfo Value="True"/>
|
||||
<MinorVersionNr Value="1"/>
|
||||
<StringTable FileDescription="ZIP WCX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2017 Alexander Koblov" ProductVersion=""/>
|
||||
<StringTable FileDescription="ZIP WCX plugin for Double Commander" LegalCopyright="Copyright (C) 2006-2017 Alexander Koblov"/>
|
||||
</VersionInfo>
|
||||
<BuildModes Count="2">
|
||||
<Item1 Name="Release" Default="True"/>
|
||||
|
|
@ -85,17 +85,24 @@ end;"/>
|
|||
<LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
|
||||
</local>
|
||||
</RunParams>
|
||||
<RequiredPackages Count="1">
|
||||
<RequiredPackages Count="2">
|
||||
<Item1>
|
||||
<PackageName Value="dcpcrypt"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<PackageName Value="doublecmd_common"/>
|
||||
<MinVersion Minor="2" Valid="True"/>
|
||||
</Item1>
|
||||
</Item2>
|
||||
</RequiredPackages>
|
||||
<Units Count="1">
|
||||
<Units Count="2">
|
||||
<Unit0>
|
||||
<Filename Value="Zip.dpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit0>
|
||||
<Unit1>
|
||||
<Filename Value="ZipFunc.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit1>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ uses
|
|||
AbSWStm,
|
||||
AbUnzOutStm,
|
||||
AbUtils,
|
||||
AbWinZipAes,
|
||||
DCClassesUtf8;
|
||||
|
||||
{ -------------------------------------------------------------------------- }
|
||||
|
|
@ -979,6 +980,9 @@ var
|
|||
Tries : Integer;
|
||||
CheckValue : LongInt;
|
||||
DecryptStream: TAbDfDecryptStream;
|
||||
FieldSize: Word;
|
||||
WinZipAesField: PWinZipAesRec = nil;
|
||||
AesDecryptStream: TAbWinZipAesDecryptStream;
|
||||
begin
|
||||
{ validate }
|
||||
if (Lo(Item.VersionNeededToExtract) > Ab_ZipVersion) then
|
||||
|
|
@ -1013,6 +1017,12 @@ begin
|
|||
{ get decrypting stream }
|
||||
if Item.IsEncrypted then begin
|
||||
try
|
||||
{ check WinZip AES extra field }
|
||||
if Item.ExtraField.Get(Ab_WinZipAesID, Pointer(WinZipAesField), FieldSize) then
|
||||
begin
|
||||
{ get real compression method }
|
||||
Item.CompressionMethod := TAbZipCompressionMethod(WinZipAesField.Method);
|
||||
end;
|
||||
{ need to decrypt }
|
||||
Tries := 0;
|
||||
Abort := False;
|
||||
|
|
@ -1021,14 +1031,27 @@ begin
|
|||
if Abort then
|
||||
raise EAbUserAbort.Create;
|
||||
{ check for valid password }
|
||||
DecryptStream := TAbDfDecryptStream.Create(Result,
|
||||
CheckValue, ZipArchive.Password);
|
||||
if DecryptStream.IsValid then begin
|
||||
DecryptStream.OwnsStream := True;
|
||||
Result := DecryptStream;
|
||||
Break;
|
||||
if Assigned(WinZipAesField) then
|
||||
begin
|
||||
AesDecryptStream := TAbWinZipAesDecryptStream.Create(Result,
|
||||
WinZipAesField, ZipArchive.Password);
|
||||
if AesDecryptStream.IsValid then begin
|
||||
AesDecryptStream.OwnsStream := True;
|
||||
Result := AesDecryptStream;
|
||||
Break;
|
||||
end;
|
||||
FreeAndNil(AesDecryptStream);
|
||||
end
|
||||
else begin
|
||||
DecryptStream := TAbDfDecryptStream.Create(Result,
|
||||
CheckValue, ZipArchive.Password);
|
||||
if DecryptStream.IsValid then begin
|
||||
DecryptStream.OwnsStream := True;
|
||||
Result := DecryptStream;
|
||||
Break;
|
||||
end;
|
||||
FreeAndNil(DecryptStream);
|
||||
end;
|
||||
FreeAndNil(DecryptStream);
|
||||
{ prompt again }
|
||||
Inc(Tries);
|
||||
if (Tries > ZipArchive.PasswordRetries) then
|
||||
|
|
@ -1045,6 +1068,7 @@ end;
|
|||
procedure DoExtract(aZipArchive: TAbZipArchive; aItem: TAbZipItem;
|
||||
aInStream, aOutStream: TStream);
|
||||
var
|
||||
Wrong: Boolean;
|
||||
OutStream : TAbUnzipOutputStream;
|
||||
begin
|
||||
if aItem.UncompressedSize = 0 then
|
||||
|
|
@ -1098,12 +1122,21 @@ begin
|
|||
end;
|
||||
|
||||
{ check CRC }
|
||||
if OutStream.CRC32 <> aItem.CRC32 then
|
||||
if not (aInStream is TAbWinZipAesDecryptStream) then
|
||||
Wrong := (OutStream.CRC32 <> aItem.CRC32)
|
||||
else begin
|
||||
Wrong := not TAbWinZipAesDecryptStream(aInStream).Verify;
|
||||
if TAbWinZipAesDecryptStream(aInStream).ExtraField.Version = 1 then
|
||||
Wrong := Wrong and (OutStream.CRC32 <> aItem.CRC32);
|
||||
end;
|
||||
if Wrong then
|
||||
begin
|
||||
if Assigned(aZipArchive.OnProcessItemFailure) then
|
||||
aZipArchive.OnProcessItemFailure(aZipArchive, aItem, ptExtract,
|
||||
ecAbbrevia, AbZipBadCRC)
|
||||
else
|
||||
raise EAbZipBadCRC.Create;
|
||||
end;
|
||||
finally
|
||||
OutStream.Free;
|
||||
end;
|
||||
|
|
|
|||
199
plugins/wcx/zip/src/fparchive/abwinzipaes.pas
Normal file
199
plugins/wcx/zip/src/fparchive/abwinzipaes.pas
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
(* ***** BEGIN LICENSE BLOCK *****
|
||||
*
|
||||
* WinZip AES decryption stream
|
||||
*
|
||||
* Copyright (C) 2017 Alexander Koblov (alexx2000@mail.ru)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** *)
|
||||
|
||||
unit AbWinZipAes;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, DCPrijndael, HMAC;
|
||||
|
||||
const
|
||||
Ab_WinZipAesID : Word = $9901;
|
||||
|
||||
type
|
||||
|
||||
{ TWinZipAesRec }
|
||||
|
||||
PWinZipAesRec = ^TWinZipAesRec;
|
||||
TWinZipAesRec = packed record
|
||||
Version: Word;
|
||||
Vendor: Word;
|
||||
Strength: Byte;
|
||||
Method: Word;
|
||||
end;
|
||||
|
||||
{ TAbWinZipAesDecryptStream }
|
||||
|
||||
TAbWinZipAesDecryptStream = class(TStream)
|
||||
private
|
||||
FKey : TBytes;
|
||||
FOwnsStream : Boolean;
|
||||
FReady : Boolean;
|
||||
FStream : TStream;
|
||||
FDataStream : TStream;
|
||||
FPassword : AnsiString;
|
||||
FContext : THMAC_Context;
|
||||
FDecoder : TDCP_rijndael;
|
||||
FExtraField : TWinZipAesRec;
|
||||
public
|
||||
constructor Create(aStream : TStream;
|
||||
aExtraField: PWinZipAesRec;
|
||||
const aPassword : AnsiString);
|
||||
destructor Destroy; override;
|
||||
|
||||
function IsValid : Boolean;
|
||||
function Verify : Boolean;
|
||||
|
||||
function Read(var aBuffer; aCount : Longint) : Longint; override;
|
||||
function Seek(aOffset : Longint; aOrigin : Word) : Longint; override;
|
||||
function Write(const aBuffer; aCount : Longint) : Longint; override;
|
||||
|
||||
property ExtraField : TWinZipAesRec read FExtraField;
|
||||
property OwnsStream : Boolean read FOwnsStream write FOwnsStream;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
AbUnzOutStm, DCPcrypt2, SHA1, Hash, kdf;
|
||||
|
||||
const
|
||||
CTR : array[0..15] of Byte = (1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
const
|
||||
MAC_LENGTH = 10;
|
||||
PWD_VER_LENGTH = 2;
|
||||
KEY_LENGTH: array[1..3] of Byte = (16, 24, 32);
|
||||
SALT_LENGTH: array[1..3] of Byte = (8, 12, 16);
|
||||
|
||||
{ TAbWinZipAesDecryptStream }
|
||||
|
||||
constructor TAbWinZipAesDecryptStream.Create(aStream: TStream;
|
||||
aExtraField: PWinZipAesRec; const aPassword: AnsiString);
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
FStream := aStream;
|
||||
FExtraField := aExtraField^;
|
||||
FPassword := aPassword;
|
||||
|
||||
FDecoder := TDCP_rijndael.Create(nil);
|
||||
end;
|
||||
|
||||
destructor TAbWinZipAesDecryptStream.Destroy;
|
||||
begin
|
||||
FDecoder.Free;
|
||||
FDataStream.Free;
|
||||
if FOwnsStream then
|
||||
FStream.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TAbWinZipAesDecryptStream.IsValid: Boolean;
|
||||
var
|
||||
F: WordRec;
|
||||
Salt: AnsiString;
|
||||
HashDesc: PHashDesc;
|
||||
AKeyLength: Integer;
|
||||
ASaltLength: Integer;
|
||||
AExtraLength: Integer;
|
||||
begin
|
||||
// Integer mode value indicating AES encryption strength
|
||||
if not FExtraField.Strength in [1..3] then Exit(False);
|
||||
|
||||
AKeyLength := KEY_LENGTH[FExtraField.Strength];
|
||||
ASaltLength := SALT_LENGTH[FExtraField.Strength];
|
||||
AExtraLength := AKeyLength * 2 + PWD_VER_LENGTH;
|
||||
|
||||
SetLength(FKey, AExtraLength);
|
||||
HashDesc:= FindHash_by_ID(_SHA1);
|
||||
|
||||
// Read salt value
|
||||
SetLength(Salt, ASaltLength);
|
||||
FStream.Read(Salt[1], ASaltLength);
|
||||
// Read password verification value
|
||||
FStream.Read({%H-}F, PWD_VER_LENGTH);
|
||||
|
||||
pbkdf2(HashDesc, Pointer(FPassword), Length(FPassword),
|
||||
Pointer(Salt), Length(Salt), 1000, FKey[0], AExtraLength);
|
||||
|
||||
Result := (FKey[AExtraLength - 2] = F.Lo) and (FKey[AExtraLength - 1] = F.Hi);
|
||||
|
||||
if Result then
|
||||
begin
|
||||
FReady := True;
|
||||
FDecoder.Init(FKey[0], AKeyLength * 8, @CTR[0]);
|
||||
// Initialize for authentication using second key part
|
||||
hmac_init(FContext, HashDesc, @FKey[AKeyLength], AKeyLength);
|
||||
// Create encrypted file data stream
|
||||
AExtraLength := ASaltLength + PWD_VER_LENGTH + MAC_LENGTH;
|
||||
FDataStream := TAbUnzipSubsetStream.Create(FStream, FStream.Size - AExtraLength);
|
||||
end
|
||||
else begin
|
||||
FReady := False;
|
||||
FStream.Seek(-(ASaltLength + PWD_VER_LENGTH), soCurrent);
|
||||
end
|
||||
end;
|
||||
|
||||
function TAbWinZipAesDecryptStream.Verify: Boolean;
|
||||
var
|
||||
AMac: THashDigest;
|
||||
ABuffer: array[0..MAC_LENGTH - 1] of Byte;
|
||||
begin
|
||||
hmac_final(FContext, {%H-}AMac);
|
||||
FStream.Read({%H-}ABuffer[0], MAC_LENGTH);
|
||||
Result := CompareByte(ABuffer[0], AMac[0], MAC_LENGTH) = 0;
|
||||
end;
|
||||
|
||||
function TAbWinZipAesDecryptStream.Read(var aBuffer; aCount: Longint): Longint;
|
||||
begin
|
||||
Assert(FReady, 'TAbWinZipAesDecryptStream.Read: the stream header has not been verified');
|
||||
Result := FDataStream.Read(aBuffer, aCount);
|
||||
if Result > 0 then
|
||||
begin
|
||||
hmac_updateXL(FContext, @aBuffer, Result);
|
||||
FDecoder.DecryptCTR(aBuffer, aBuffer, Result);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TAbWinZipAesDecryptStream.Seek(aOffset: Longint; aOrigin: Word): Longint;
|
||||
begin
|
||||
Result := FDataStream.Seek(aOffset, aOrigin);
|
||||
end;
|
||||
|
||||
function TAbWinZipAesDecryptStream.Write(const aBuffer; aCount: Longint): Longint;
|
||||
begin
|
||||
Assert(False, 'TAbWinZipAesDecryptStream.Write: the stream is read-only');
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
|
@ -1713,17 +1713,18 @@ Index: AbUnzPrc.pas
|
|||
AbBitBkt,
|
||||
AbConst,
|
||||
AbDfBase,
|
||||
@@ -153,7 +156,8 @@
|
||||
@@ -153,7 +156,9 @@
|
||||
AbSpanSt,
|
||||
AbSWStm,
|
||||
AbUnzOutStm,
|
||||
- AbUtils;
|
||||
+ AbUtils,
|
||||
+ AbWinZipAes,
|
||||
+ DCClassesUtf8;
|
||||
|
||||
{ -------------------------------------------------------------------------- }
|
||||
procedure AbReverseBits(var W : Word);
|
||||
@@ -944,11 +948,30 @@
|
||||
@@ -944,11 +949,30 @@
|
||||
InStream.ReadBuffer(Header, SizeOf(Header));
|
||||
SetLength(Properties, Header.PropSize);
|
||||
InStream.ReadBuffer(Properties[0], Header.PropSize);
|
||||
|
|
@ -1756,7 +1757,73 @@ Index: AbUnzPrc.pas
|
|||
function ExtractPrep(ZipArchive: TAbZipArchive; Item: TAbZipItem): TStream;
|
||||
var
|
||||
LFH : TAbZipLocalFileHeader;
|
||||
@@ -1062,6 +1085,11 @@
|
||||
@@ -956,6 +980,9 @@
|
||||
Tries : Integer;
|
||||
CheckValue : LongInt;
|
||||
DecryptStream: TAbDfDecryptStream;
|
||||
+ FieldSize: Word;
|
||||
+ WinZipAesField: PWinZipAesRec = nil;
|
||||
+ AesDecryptStream: TAbWinZipAesDecryptStream;
|
||||
begin
|
||||
{ validate }
|
||||
if (Lo(Item.VersionNeededToExtract) > Ab_ZipVersion) then
|
||||
@@ -990,6 +1017,12 @@
|
||||
{ get decrypting stream }
|
||||
if Item.IsEncrypted then begin
|
||||
try
|
||||
+ { check WinZip AES extra field }
|
||||
+ if Item.ExtraField.Get(Ab_WinZipAesID, Pointer(WinZipAesField), FieldSize) then
|
||||
+ begin
|
||||
+ { get real compression method }
|
||||
+ Item.CompressionMethod := TAbZipCompressionMethod(WinZipAesField.Method);
|
||||
+ end;
|
||||
{ need to decrypt }
|
||||
Tries := 0;
|
||||
Abort := False;
|
||||
@@ -998,14 +1031,27 @@
|
||||
if Abort then
|
||||
raise EAbUserAbort.Create;
|
||||
{ check for valid password }
|
||||
- DecryptStream := TAbDfDecryptStream.Create(Result,
|
||||
- CheckValue, ZipArchive.Password);
|
||||
- if DecryptStream.IsValid then begin
|
||||
- DecryptStream.OwnsStream := True;
|
||||
- Result := DecryptStream;
|
||||
- Break;
|
||||
+ if Assigned(WinZipAesField) then
|
||||
+ begin
|
||||
+ AesDecryptStream := TAbWinZipAesDecryptStream.Create(Result,
|
||||
+ WinZipAesField, ZipArchive.Password);
|
||||
+ if AesDecryptStream.IsValid then begin
|
||||
+ AesDecryptStream.OwnsStream := True;
|
||||
+ Result := AesDecryptStream;
|
||||
+ Break;
|
||||
+ end;
|
||||
+ FreeAndNil(AesDecryptStream);
|
||||
+ end
|
||||
+ else begin
|
||||
+ DecryptStream := TAbDfDecryptStream.Create(Result,
|
||||
+ CheckValue, ZipArchive.Password);
|
||||
+ if DecryptStream.IsValid then begin
|
||||
+ DecryptStream.OwnsStream := True;
|
||||
+ Result := DecryptStream;
|
||||
+ Break;
|
||||
+ end;
|
||||
+ FreeAndNil(DecryptStream);
|
||||
end;
|
||||
- FreeAndNil(DecryptStream);
|
||||
{ prompt again }
|
||||
Inc(Tries);
|
||||
if (Tries > ZipArchive.PasswordRetries) then
|
||||
@@ -1022,6 +1068,7 @@
|
||||
procedure DoExtract(aZipArchive: TAbZipArchive; aItem: TAbZipItem;
|
||||
aInStream, aOutStream: TStream);
|
||||
var
|
||||
+ Wrong: Boolean;
|
||||
OutStream : TAbUnzipOutputStream;
|
||||
begin
|
||||
if aItem.UncompressedSize = 0 then
|
||||
@@ -1062,6 +1109,11 @@
|
||||
DecompressWavPack(aInStream, OutStream);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
|
@ -1768,7 +1835,30 @@ Index: AbUnzPrc.pas
|
|||
cmShrunk..cmImploded: begin
|
||||
DoLegacyUnzip(aZipArchive, aItem, aInStream, OutStream);
|
||||
end;
|
||||
@@ -1111,7 +1139,7 @@
|
||||
@@ -1070,12 +1122,21 @@
|
||||
end;
|
||||
|
||||
{ check CRC }
|
||||
- if OutStream.CRC32 <> aItem.CRC32 then
|
||||
+ if not (aInStream is TAbWinZipAesDecryptStream) then
|
||||
+ Wrong := (OutStream.CRC32 <> aItem.CRC32)
|
||||
+ else begin
|
||||
+ Wrong := not TAbWinZipAesDecryptStream(aInStream).Verify;
|
||||
+ if TAbWinZipAesDecryptStream(aInStream).ExtraField.Version = 1 then
|
||||
+ Wrong := Wrong and (OutStream.CRC32 <> aItem.CRC32);
|
||||
+ end;
|
||||
+ if Wrong then
|
||||
+ begin
|
||||
if Assigned(aZipArchive.OnProcessItemFailure) then
|
||||
aZipArchive.OnProcessItemFailure(aZipArchive, aItem, ptExtract,
|
||||
ecAbbrevia, AbZipBadCRC)
|
||||
else
|
||||
raise EAbZipBadCRC.Create;
|
||||
+ end;
|
||||
finally
|
||||
OutStream.Free;
|
||||
end;
|
||||
@@ -1111,7 +1172,7 @@
|
||||
else begin
|
||||
InStream := ExtractPrep(ZipArchive, Item);
|
||||
try
|
||||
|
|
@ -1777,15 +1867,15 @@ Index: AbUnzPrc.pas
|
|||
try
|
||||
try {OutStream}
|
||||
DoExtract(ZipArchive, Item, InStream, OutStream);
|
||||
@@ -1141,6 +1169,7 @@
|
||||
@@ -1141,6 +1202,7 @@
|
||||
LFH : TAbZipLocalFileHeader;
|
||||
Zip64Field : PZip64LocalHeaderRec;
|
||||
ZipArchive : TAbZipArchive;
|
||||
+ DD : TAbZipDataDescriptor = nil;
|
||||
begin
|
||||
ZipArchive := TAbZipArchive(Sender);
|
||||
|
||||
@@ -1162,6 +1191,12 @@
|
||||
|
||||
@@ -1162,6 +1224,12 @@
|
||||
{get the item's local file header}
|
||||
ZipArchive.FStream.Seek(Item.RelativeOffset, soBeginning);
|
||||
LFH.LoadFromStream(ZipArchive.FStream);
|
||||
|
|
@ -1796,9 +1886,9 @@ Index: AbUnzPrc.pas
|
|||
+ DD.LoadFromStream(ZipArchive.FStream);
|
||||
+ end;
|
||||
ZipArchive.FStream.Seek(Item.RelativeOffset, soBeginning);
|
||||
|
||||
|
||||
{currently a single exception is raised for any LFH error}
|
||||
@@ -1173,8 +1208,15 @@
|
||||
@@ -1173,8 +1241,15 @@
|
||||
raise EAbZipInvalidLFH.Create;
|
||||
if (LFH.LastModFileDate <> Item.LastModFileDate) then
|
||||
raise EAbZipInvalidLFH.Create;
|
||||
|
|
@ -1816,7 +1906,7 @@ Index: AbUnzPrc.pas
|
|||
if LFH.ExtraField.Get(Ab_Zip64SubfieldID, Pointer(Zip64Field), FieldSize) then begin
|
||||
if (Zip64Field.CompressedSize <> Item.CompressedSize) then
|
||||
raise EAbZipInvalidLFH.Create;
|
||||
@@ -1181,6 +1223,13 @@
|
||||
@@ -1181,6 +1256,13 @@
|
||||
if (Zip64Field.UncompressedSize <> Item.UncompressedSize) then
|
||||
raise EAbZipInvalidLFH.Create;
|
||||
end
|
||||
|
|
@ -1830,13 +1920,13 @@ Index: AbUnzPrc.pas
|
|||
else begin
|
||||
if (LFH.CompressedSize <> Item.CompressedSize) then
|
||||
raise EAbZipInvalidLFH.Create;
|
||||
@@ -1195,6 +1244,7 @@
|
||||
@@ -1195,6 +1277,7 @@
|
||||
finally
|
||||
BitBucket.Free;
|
||||
LFH.Free;
|
||||
+ DD.Free;
|
||||
end;
|
||||
|
||||
|
||||
end;
|
||||
Index: AbUtils.pas
|
||||
===================================================================
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue