Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public partial class ZipArchiveEntry
private List<ZipGenericExtraField>? _cdUnknownExtraFields;
private List<ZipGenericExtraField>? _lhUnknownExtraFields;
private byte[] _fileComment;
private readonly CompressionLevel? _compressionLevel;
private readonly CompressionLevel _compressionLevel;

// Initializes a ZipArchiveEntry instance for an existing archive entry.
internal ZipArchiveEntry(ZipArchive archive, ZipCentralDirectoryFileHeader cd)
Expand Down Expand Up @@ -86,7 +86,7 @@ internal ZipArchiveEntry(ZipArchive archive, ZipCentralDirectoryFileHeader cd)

_fileComment = cd.FileComment;

_compressionLevel = MapCompressionLevel(_generalPurposeBitFlag);
_compressionLevel = MapCompressionLevel(_generalPurposeBitFlag, CompressionMethod);
}

// Initializes a ZipArchiveEntry instance for a new archive entry with a specified compression level.
Expand All @@ -98,7 +98,7 @@ internal ZipArchiveEntry(ZipArchive archive, string entryName, CompressionLevel
{
CompressionMethod = CompressionMethodValues.Stored;
}
_generalPurposeBitFlag = MapDeflateCompressionOption(_generalPurposeBitFlag, _compressionLevel);
_generalPurposeBitFlag = MapDeflateCompressionOption(_generalPurposeBitFlag, _compressionLevel, CompressionMethod);
}

// Initializes a ZipArchiveEntry instance for a new archive entry.
Expand All @@ -112,9 +112,9 @@ internal ZipArchiveEntry(ZipArchive archive, string entryName)
_versionMadeByPlatform = CurrentZipPlatform;
_versionMadeBySpecification = ZipVersionNeededValues.Default;
_versionToExtract = ZipVersionNeededValues.Default; // this must happen before following two assignment
_compressionLevel = null;
_generalPurposeBitFlag = MapDeflateCompressionOption(0, _compressionLevel);
_compressionLevel = CompressionLevel.Optimal;
CompressionMethod = CompressionMethodValues.Deflate;
_generalPurposeBitFlag = MapDeflateCompressionOption(0, _compressionLevel, CompressionMethod);
_lastModified = DateTimeOffset.Now;

_compressedSize = 0; // we don't know these yet
Expand Down Expand Up @@ -632,7 +632,7 @@ private CheckSumAndSizeWriteStream GetDataCompressor(Stream backingStream, bool
case CompressionMethodValues.Deflate:
case CompressionMethodValues.Deflate64:
default:
compressorStream = new DeflateStream(backingStream, _compressionLevel ?? CompressionLevel.Optimal, leaveBackingStreamOpen);
compressorStream = new DeflateStream(backingStream, _compressionLevel, leaveBackingStreamOpen);
break;

}
Expand Down Expand Up @@ -799,31 +799,39 @@ private bool IsOpenable(bool needToUncompress, bool needToLoadIntoMemory, out st

private bool SizesTooLarge() => _compressedSize > uint.MaxValue || _uncompressedSize > uint.MaxValue;

private static CompressionLevel? MapCompressionLevel(BitFlagValues generalPurposeBitFlag)
private static CompressionLevel MapCompressionLevel(BitFlagValues generalPurposeBitFlag, CompressionMethodValues compressionMethod)
{
// Information about the Deflate compression option is stored in bits 1 and 2 of the general purpose bit flags.
int deflateCompressionOption = (int)generalPurposeBitFlag & 0x6;
// If the compression method is not Deflate, the Deflate compression option is invalid - default to NoCompression.
int deflateCompressionOption = compressionMethod == CompressionMethodValues.Deflate || compressionMethod == CompressionMethodValues.Deflate64
? (int)generalPurposeBitFlag & 0x6
: 6;

return deflateCompressionOption switch
return deflateCompressionOption switch
{
0 => CompressionLevel.Optimal,
2 => CompressionLevel.SmallestSize,
4 => CompressionLevel.Fastest,
6 => CompressionLevel.NoCompression,
_ => null
_ => CompressionLevel.Optimal
};
}

private static BitFlagValues MapDeflateCompressionOption(BitFlagValues generalPurposeBitFlag, CompressionLevel? compressionLevel)
private static BitFlagValues MapDeflateCompressionOption(BitFlagValues generalPurposeBitFlag, CompressionLevel compressionLevel, CompressionMethodValues compressionMethod)
{
ushort deflateCompressionOptions = compressionLevel switch
{
CompressionLevel.Optimal => 0,
CompressionLevel.SmallestSize => 2,
CompressionLevel.Fastest => 4,
CompressionLevel.NoCompression => 6,
_ => 0
};
ushort deflateCompressionOptions = (ushort)(
// The Deflate compression level is only valid if the compression method is actually Deflate (or Deflate64). If it's not, the
// value of the two bits is undefined and they should be zeroed out.
compressionMethod == CompressionMethodValues.Deflate || compressionMethod == CompressionMethodValues.Deflate64
? compressionLevel switch
{
CompressionLevel.Optimal => 0,
CompressionLevel.SmallestSize => 2,
CompressionLevel.Fastest => 4,
CompressionLevel.NoCompression => 6,
_ => 0
}
: 0);

return (BitFlagValues)(((int)generalPurposeBitFlag & ~0x6) | deflateCompressionOptions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ public static void CreateUncompressedArchive()
// bit flags correctly. It verifies that these have been set by reading from the MemoryStream manually, and by
// reopening the generated file to confirm that the compression levels match.
[Theory]
[InlineData(CompressionLevel.NoCompression, 6)]
// Special-case NoCompression: in this case, the CompressionMethod becomes Stored and the bits are unset.
[InlineData(CompressionLevel.NoCompression, 0)]
[InlineData(CompressionLevel.Optimal, 0)]
[InlineData(CompressionLevel.SmallestSize, 2)]
[InlineData(CompressionLevel.Fastest, 4)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ internal static void GetZipCompressionMethodFromOpcCompressionOption(
break;
case CompressionOption.Maximum:
{
#if (!NETSTANDARD2_0 && !NETFRAMEWORK)
#if NET
compressionLevel = CompressionLevel.SmallestSize;
#else
compressionLevel = CompressionLevel.Optimal;
Expand Down