FIX: Test zip archive with ZipDataDescriptor

This commit is contained in:
Alexander Koblov 2016-03-11 19:36:29 +00:00
commit b6d251f32c
3 changed files with 143 additions and 22 deletions

View file

@ -1169,6 +1169,7 @@ var
LFH : TAbZipLocalFileHeader;
Zip64Field : PZip64LocalHeaderRec;
ZipArchive : TAbZipArchive;
DD : TAbZipDataDescriptor = nil;
begin
ZipArchive := TAbZipArchive(Sender);
@ -1190,6 +1191,12 @@ begin
{get the item's local file header}
ZipArchive.FStream.Seek(Item.RelativeOffset, soBeginning);
LFH.LoadFromStream(ZipArchive.FStream);
if LFH.HasDataDescriptor then
begin
DD := TAbZipDataDescriptor.Create;
ZipArchive.FStream.Seek(Item.CompressedSize, soCurrent);
DD.LoadFromStream(ZipArchive.FStream);
end;
ZipArchive.FStream.Seek(Item.RelativeOffset, soBeginning);
{currently a single exception is raised for any LFH error}
@ -1201,14 +1208,28 @@ begin
raise EAbZipInvalidLFH.Create;
if (LFH.LastModFileDate <> Item.LastModFileDate) then
raise EAbZipInvalidLFH.Create;
if (LFH.CRC32 <> Item.CRC32) then
raise EAbZipInvalidLFH.Create;
if Assigned(DD) then
begin
if (DD.CRC32 <> Item.CRC32) then
raise EAbZipInvalidLFH.Create;
end
else begin
if (LFH.CRC32 <> Item.CRC32) then
raise EAbZipInvalidLFH.Create;
end;
if LFH.ExtraField.Get(Ab_Zip64SubfieldID, Pointer(Zip64Field), FieldSize) then begin
if (Zip64Field.CompressedSize <> Item.CompressedSize) then
raise EAbZipInvalidLFH.Create;
if (Zip64Field.UncompressedSize <> Item.UncompressedSize) then
raise EAbZipInvalidLFH.Create;
end
else if Assigned(DD) then
begin
if (DD.CompressedSize <> Item.CompressedSize) then
raise EAbZipInvalidLFH.Create;
if (DD.UncompressedSize <> Item.UncompressedSize) then
raise EAbZipInvalidLFH.Create;
end
else begin
if (LFH.CompressedSize <> Item.CompressedSize) then
raise EAbZipInvalidLFH.Create;
@ -1223,6 +1244,7 @@ begin
finally
BitBucket.Free;
LFH.Free;
DD.Free;
end;
end;

View file

@ -206,6 +206,7 @@ type
FCompressedSize : Int64;
FUncompressedSize : Int64;
public {methods}
procedure LoadFromStream( Stream : TStream );
procedure SaveToStream( Stream : TStream );
public {properties}
property CRC32 : Longint
@ -911,6 +912,17 @@ begin
end;
{============================================================================}
{ TAbZipDataDescriptor implementation ====================================== }
procedure TAbZipDataDescriptor.LoadFromStream(Stream: TStream);
var
Signature: LongInt = 0;
begin
Stream.Read(Signature, SizeOf(Ab_ZipDataDescriptorSignature));
if (Signature <> Ab_ZipDataDescriptorSignature) then Exit;
Stream.Read(FCRC32, SizeOf(FCRC32));
Stream.Read(FCompressedSize, SizeOf(LongWord));
Stream.Read(FUncompressedSize, SizeOf(LongWord));
end;
{ -------------------------------------------------------------------------- }
procedure TAbZipDataDescriptor.SaveToStream( Stream : TStream );
begin
Stream.Write( Ab_ZipDataDescriptorSignature, sizeof( Ab_ZipDataDescriptorSignature ) );

View file

@ -1716,6 +1716,67 @@ Index: AbUnzPrc.pas
try
try {OutStream}
DoExtract(ZipArchive, Item, InStream, OutStream);
@@ -1141,6 +1169,7 @@
LFH : TAbZipLocalFileHeader;
Zip64Field : PZip64LocalHeaderRec;
ZipArchive : TAbZipArchive;
+ DD : TAbZipDataDescriptor = nil;
begin
ZipArchive := TAbZipArchive(Sender);
@@ -1162,6 +1191,12 @@
{get the item's local file header}
ZipArchive.FStream.Seek(Item.RelativeOffset, soBeginning);
LFH.LoadFromStream(ZipArchive.FStream);
+ if LFH.HasDataDescriptor then
+ begin
+ DD := TAbZipDataDescriptor.Create;
+ ZipArchive.FStream.Seek(Item.CompressedSize, soCurrent);
+ 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 @@
raise EAbZipInvalidLFH.Create;
if (LFH.LastModFileDate <> Item.LastModFileDate) then
raise EAbZipInvalidLFH.Create;
- if (LFH.CRC32 <> Item.CRC32) then
- raise EAbZipInvalidLFH.Create;
+ if Assigned(DD) then
+ begin
+ if (DD.CRC32 <> Item.CRC32) then
+ raise EAbZipInvalidLFH.Create;
+ end
+ else begin
+ if (LFH.CRC32 <> Item.CRC32) then
+ raise EAbZipInvalidLFH.Create;
+ end;
if LFH.ExtraField.Get(Ab_Zip64SubfieldID, Pointer(Zip64Field), FieldSize) then begin
if (Zip64Field.CompressedSize <> Item.CompressedSize) then
raise EAbZipInvalidLFH.Create;
@@ -1181,6 +1223,13 @@
if (Zip64Field.UncompressedSize <> Item.UncompressedSize) then
raise EAbZipInvalidLFH.Create;
end
+ else if Assigned(DD) then
+ begin
+ if (DD.CompressedSize <> Item.CompressedSize) then
+ raise EAbZipInvalidLFH.Create;
+ if (DD.UncompressedSize <> Item.UncompressedSize) then
+ raise EAbZipInvalidLFH.Create;
+ end
else begin
if (LFH.CompressedSize <> Item.CompressedSize) then
raise EAbZipInvalidLFH.Create;
@@ -1195,6 +1244,7 @@
finally
BitBucket.Free;
LFH.Free;
+ DD.Free;
end;
end;
Index: AbUtils.pas
===================================================================
--- AbUtils.pas (revision 512)
@ -2409,7 +2470,15 @@ Index: AbZipTyp.pas
TAbZipSupportedMethod =
(smStored, smDeflated, smBestMethod);
@@ -407,6 +407,7 @@
@@ -206,6 +206,7 @@
FCompressedSize : Int64;
FUncompressedSize : Int64;
public {methods}
+ procedure LoadFromStream( Stream : TStream );
procedure SaveToStream( Stream : TStream );
public {properties}
property CRC32 : Longint
@@ -407,6 +408,7 @@
function GetLastModFileDate : Word; override;
function GetLastModFileTime : Word; override;
function GetNativeFileAttributes : LongInt; override;
@ -2417,7 +2486,7 @@ Index: AbZipTyp.pas
procedure SetCompressedSize( const Value : Int64 ); override;
procedure SetCRC32( const Value : Longint ); override;
procedure SetExternalFileAttributes( Value : LongWord ); override;
@@ -530,8 +531,8 @@
@@ -530,8 +532,8 @@
override;
destructor Destroy;
override;
@ -2428,7 +2497,7 @@ Index: AbZipTyp.pas
public {properties}
property CompressionMethodToUse : TAbZipSupportedMethod
@@ -620,11 +621,14 @@
@@ -620,11 +622,14 @@
{$ENDIF}
{$ENDIF}
Math,
@ -2445,7 +2514,7 @@ Index: AbZipTyp.pas
function VerifyZip(Strm : TStream) : TAbArchiveType;
{ determine if stream appears to be in PkZip format }
@@ -638,20 +642,31 @@
@@ -638,20 +643,31 @@
Result := atUnknown;
try
Strm.Position := 0;
@ -2491,7 +2560,7 @@ Index: AbZipTyp.pas
end;
end;
except
@@ -733,8 +748,7 @@
@@ -733,8 +749,7 @@
leaves stream positioned at start of structure or at original
position if not found }
const
@ -2501,7 +2570,7 @@ Index: AbZipTyp.pas
var
StartPos : Int64;
TailRec : TAbZipEndOfCentralDirectoryRecord;
@@ -741,7 +755,6 @@
@@ -741,7 +756,6 @@
Buffer : PAnsiChar;
Offset : Int64;
TestPos : PAnsiChar;
@ -2509,7 +2578,7 @@ Index: AbZipTyp.pas
BytesRead : Int64;
BufSize : Int64;
CommentLen: integer;
@@ -767,7 +780,7 @@
@@ -767,7 +781,7 @@
stream; we need to search for the tail signature}
{get a buffer}
@ -2518,7 +2587,7 @@ Index: AbZipTyp.pas
GetMem(Buffer, BufSize);
try
@@ -774,57 +787,41 @@
@@ -774,57 +788,41 @@
{start out searching backwards}
Offset := -BufSize;
@ -2603,7 +2672,25 @@ Index: AbZipTyp.pas
end;
{if we reach this point, the CD tail is not present}
@@ -1195,12 +1192,13 @@
@@ -914,6 +912,17 @@
end;
{============================================================================}
{ TAbZipDataDescriptor implementation ====================================== }
+procedure TAbZipDataDescriptor.LoadFromStream(Stream: TStream);
+var
+ Signature: LongInt = 0;
+begin
+ Stream.Read(Signature, SizeOf(Ab_ZipDataDescriptorSignature));
+ if (Signature <> Ab_ZipDataDescriptorSignature) then Exit;
+ Stream.Read(FCRC32, SizeOf(FCRC32));
+ Stream.Read(FCompressedSize, SizeOf(LongWord));
+ Stream.Read(FUncompressedSize, SizeOf(LongWord));
+end;
+{ -------------------------------------------------------------------------- }
procedure TAbZipDataDescriptor.SaveToStream( Stream : TStream );
begin
Stream.Write( Ab_ZipDataDescriptorSignature, sizeof( Ab_ZipDataDescriptorSignature ) );
@@ -1195,12 +1204,13 @@
{ TAbZipDirectoryFileFooter implementation ================================= }
function TAbZipDirectoryFileFooter.GetIsZip64: Boolean;
begin
@ -2623,7 +2710,7 @@ Index: AbZipTyp.pas
end;
{ -------------------------------------------------------------------------- }
procedure TAbZipDirectoryFileFooter.LoadFromStream( Stream : TStream );
@@ -1407,6 +1405,22 @@
@@ -1407,6 +1417,22 @@
Result := FItemInfo.FileName;
end;
{ -------------------------------------------------------------------------- }
@ -2646,7 +2733,7 @@ Index: AbZipTyp.pas
function TAbZipItem.GetShannonFanoTreeCount : Byte;
begin
Result := FItemInfo.ShannonFanoTreeCount;
@@ -1430,12 +1444,13 @@
@@ -1430,12 +1456,13 @@
UnicodeName: UnicodeString;
UTF8Name: AnsiString;
XceedField: PXceedUnicodePathRec;
@ -2662,7 +2749,7 @@ Index: AbZipTyp.pas
else if FItemInfo.ExtraField.Get(Ab_InfoZipUnicodePathSubfieldID, Pointer(InfoZipField), FieldSize) and
(FieldSize > SizeOf(TInfoZipUnicodePathRec)) and
(InfoZipField.Version = 1) and
@@ -1442,7 +1457,7 @@
@@ -1442,7 +1469,7 @@
(InfoZipField.NameCRC32 = AbCRC32Of(FItemInfo.FileName)) then begin
SetString(UTF8Name, InfoZipField.UnicodeName,
FieldSize - SizeOf(TInfoZipUnicodePathRec) + 1);
@ -2671,7 +2758,7 @@ Index: AbZipTyp.pas
end
else if FItemInfo.ExtraField.Get(Ab_XceedUnicodePathSubfieldID, Pointer(XceedField), FieldSize) and
(FieldSize > SizeOf(TXceedUnicodePathRec)) and
@@ -1449,16 +1464,28 @@
@@ -1449,16 +1476,28 @@
(XceedField.Signature = Ab_XceedUnicodePathSignature) and
(XceedField.Length * SizeOf(WideChar) = FieldSize - SizeOf(TXceedUnicodePathRec) + SizeOf(WideChar)) then begin
SetString(UnicodeName, XceedField.UnicodeName, XceedField.Length);
@ -2708,7 +2795,7 @@ Index: AbZipTyp.pas
{ read ZIP64 extended header }
FUncompressedSize := FItemInfo.UncompressedSize;
@@ -1596,24 +1623,20 @@
@@ -1596,24 +1635,20 @@
{$IFDEF MSWINDOWS}
FItemInfo.IsUTF8 := False;
HostOS := hosDOS;
@ -2738,7 +2825,7 @@ Index: AbZipTyp.pas
{$ENDIF}
UseExtraField := False;
@@ -1626,7 +1649,7 @@
@@ -1626,7 +1661,7 @@
end;
if UseExtraField then begin
@ -2747,7 +2834,7 @@ Index: AbZipTyp.pas
FieldSize := SizeOf(TInfoZipUnicodePathRec) + Length(UTF8Name) - 1;
GetMem(InfoZipField, FieldSize);
try
@@ -1762,11 +1785,11 @@
@@ -1762,11 +1797,11 @@
inherited Destroy;
end;
{ -------------------------------------------------------------------------- }
@ -2762,7 +2849,7 @@ Index: AbZipTyp.pas
Result := TAbZipItem.Create;
with TAbZipItem( Result ) do begin
CompressionMethod := cmDeflated;
@@ -1773,9 +1796,17 @@
@@ -1773,9 +1808,17 @@
GeneralPurposeBitFlag := 0;
CompressedSize := 0;
CRC32 := 0;
@ -2782,7 +2869,7 @@ Index: AbZipTyp.pas
end;
end;
{ -------------------------------------------------------------------------- }
@@ -1930,8 +1961,8 @@
@@ -1930,8 +1973,8 @@
AbStripDots( lValue );
for i := 1 to Length( lValue ) do
@ -2793,7 +2880,7 @@ Index: AbZipTyp.pas
Result := lValue;
end;
{ -------------------------------------------------------------------------- }
@@ -1983,7 +2014,7 @@
@@ -1983,7 +2026,7 @@
FStatus := asInvalid; //TODO: Status updates are extremely inconsistent
raise EAbUserAbort.Create;
end;
@ -2802,7 +2889,7 @@ Index: AbZipTyp.pas
TailPosition := FindCentralDirectoryTail( FStream );
end;
end;
@@ -2302,7 +2333,7 @@
@@ -2302,7 +2345,7 @@
if FOwnsStream then begin
{need new stream to write}
FreeAndNil(FStream);