Skip to content

fix(zip): dont fail test on 0 sizes and descriptor #736

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/ICSharpCode.SharpZipLib/Zip/ZipConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -472,4 +472,28 @@ public static class ZipConstants

#endregion Header Signatures
}

/// <summary>
/// GeneralBitFlags helper extensions
/// </summary>
public static class GenericBitFlagsExtensions
{
/// <summary>
/// Efficiently check if any of the <see cref="GeneralBitFlags">flags</see> are set without enum un-/boxing
/// </summary>
/// <param name="target"></param>
/// <param name="flags"></param>
/// <returns>Returns whether any of flags are set</returns>
public static bool HasAny(this GeneralBitFlags target, GeneralBitFlags flags)
=> ((int)target & (int)flags) != 0;

/// <summary>
/// Efficiently check if all the <see cref="GeneralBitFlags">flags</see> are set without enum un-/boxing
/// </summary>
/// <param name="target"></param>
/// <param name="flags"></param>
/// <returns>Returns whether the flags are all set</returns>
public static bool HasAll(this GeneralBitFlags target, GeneralBitFlags flags)
=> ((int)target & (int)flags) == (int)flags;
}
}
32 changes: 16 additions & 16 deletions src/ICSharpCode.SharpZipLib/Zip/ZipFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1115,7 +1115,7 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
}

var extractVersion = (short)(ReadLEUshort() & 0x00ff);
var localFlags = (short)ReadLEUshort();
var localFlags = (GeneralBitFlags)ReadLEUshort();
var compressionMethod = (short)ReadLEUshort();
var fileTime = (short)ReadLEUshort();
var fileDate = (short)ReadLEUshort();
Expand All @@ -1142,15 +1142,15 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
size = localExtraData.ReadLong();
compressedSize = localExtraData.ReadLong();

if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0)
if (localFlags.HasAny(GeneralBitFlags.Descriptor))
{
// These may be valid if patched later
if ((size != -1) && (size != entry.Size))
if ((size > 0) && (size != entry.Size))
{
throw new ZipException("Size invalid for descriptor");
}

if ((compressedSize != -1) && (compressedSize != entry.CompressedSize))
if ((compressedSize > 0) && (compressedSize != entry.CompressedSize))
{
throw new ZipException("Compressed size invalid for descriptor");
}
Expand Down Expand Up @@ -1181,7 +1181,7 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extractVersion));
}

if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked)) != 0)
if (localFlags.HasAny(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked))
{
throw new ZipException("The library does not support the zip version required to extract this entry");
}
Expand Down Expand Up @@ -1213,21 +1213,21 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
var localEncoding = _stringCodec.ZipInputEncoding(localFlags);

// Local entry flags dont have reserved bit set on.
if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.ReservedPkware15)) != 0)
if (localFlags.HasAny(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.ReservedPkware15))
{
throw new ZipException("Reserved bit flags cannot be set.");
}

// Encryption requires extract version >= 20
if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))
if (localFlags.HasAny(GeneralBitFlags.Encrypted) && extractVersion < 20)
{
throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion));
}

// Strong encryption requires encryption flag to be set and extract version >= 50.
if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)
if (localFlags.HasAny(GeneralBitFlags.StrongEncryption))
{
if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0)
if (!localFlags.HasAny(GeneralBitFlags.Encrypted))
{
throw new ZipException("Strong encryption flag set but encryption flag is not set");
}
Expand All @@ -1239,13 +1239,13 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
}

// Patched entries require extract version >= 27
if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27))
if (localFlags.HasAny(GeneralBitFlags.Patched) && extractVersion < 27)
{
throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
}

// Central header flags match local entry flags.
if (localFlags != entry.Flags)
if ((int)localFlags != entry.Flags)
{
throw new ZipException("Central header/local header flags mismatch");
}
Expand All @@ -1262,23 +1262,23 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
}

// Strong encryption and extract version match
if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)
if (localFlags.HasAny(GeneralBitFlags.StrongEncryption))
{
if (extractVersion < 62)
{
throw new ZipException("Strong encryption flag set but version not high enough");
}
}

if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0)
if (localFlags.HasAny(GeneralBitFlags.HeaderMasked))
{
if ((fileTime != 0) || (fileDate != 0))
{
throw new ZipException("Header masked set but date/time values non-zero");
}
}

if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0)
if (!localFlags.HasAny(GeneralBitFlags.Descriptor))
{
if (crcValue != (uint)entry.Crc)
{
Expand Down Expand Up @@ -1348,7 +1348,7 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)

// Size can be verified only if it is known in the local header.
// it will always be known in the central header.
if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
if (!localFlags.HasAny(GeneralBitFlags.Descriptor) ||
((size > 0 || compressedSize > 0) && entry.Size > 0))
{
if ((size != 0)
Expand Down Expand Up @@ -2507,7 +2507,7 @@ private void CopyBytes(ZipUpdate update, Stream destination, Stream source,
/// <returns>The descriptor size, zero if there isn't one.</returns>
private static int GetDescriptorSize(ZipUpdate update, bool includingSignature)
{
if (!((GeneralBitFlags)update.Entry.Flags).HasFlag(GeneralBitFlags.Descriptor))
if (!((GeneralBitFlags)update.Entry.Flags).HasAny(GeneralBitFlags.Descriptor))
return 0;

var descriptorWithSignature = update.Entry.LocalHeaderRequiresZip64
Expand Down