Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ internal ZipArchiveEntry() { }
[System.Diagnostics.CodeAnalysis.AllowNullAttribute]
public string Comment { get { throw null; } set { } }
public long CompressedLength { get { throw null; } }
public System.IO.Compression.ZipCompressionMethod CompressionMethod { get { throw null; } }
[System.CLSCompliantAttribute(false)]
public uint Crc32 { get { throw null; } }
public int ExternalAttributes { get { throw null; } set { } }
Expand All @@ -135,6 +136,12 @@ public enum ZipArchiveMode
Create = 1,
Update = 2,
}
public enum ZipCompressionMethod
{
Stored = 0,
Deflate = 8,
Deflate64 = 9,
}
public sealed partial class ZLibCompressionOptions
{
public ZLibCompressionOptions() { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
<Compile Include="System\IO\Compression\PositionPreservingWriteOnlyStreamWrapper.cs" />
<Compile Include="System\IO\Compression\ZLibCompressionOptions.cs" />
<Compile Include="System\IO\Compression\ZLibStream.cs" />
<Compile Include="System\IO\Compression\ZipCompressionMethod.cs" />
<Compile Include="$(CommonPath)System\Obsoletions.cs"
Link="Common\System\Obsoletions.cs" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ internal sealed partial class DeflateManagedStream : Stream
private int _asyncOperations;

// A specific constructor to allow decompression of Deflate64
internal DeflateManagedStream(Stream stream, ZipArchiveEntry.CompressionMethodValues method, long uncompressedSize = -1)
internal DeflateManagedStream(Stream stream, ZipCompressionMethod method, long uncompressedSize = -1)
{
ArgumentNullException.ThrowIfNull(stream);

if (!stream.CanRead)
throw new ArgumentException(SR.NotSupported_UnreadableStream, nameof(stream));

Debug.Assert(method == ZipArchiveEntry.CompressionMethodValues.Deflate64);
Debug.Assert(method == ZipCompressionMethod.Deflate64);

_inflater = new InflaterManaged(method == ZipArchiveEntry.CompressionMethodValues.Deflate64, uncompressedSize);
_inflater = new InflaterManaged(method == ZipCompressionMethod.Deflate64, uncompressedSize);

_stream = stream;
_buffer = new byte[DefaultBufferSize];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ private async Task<MemoryStream> GetUncompressedDataAsync(CancellationToken canc
}

// if they start modifying it and the compression method is not "store", we should make sure it will get deflated
if (CompressionMethod != CompressionMethodValues.Stored)
if (CompressionMethod != ZipCompressionMethod.Stored)
{
CompressionMethod = CompressionMethodValues.Deflate;
CompressionMethod = ZipCompressionMethod.Deflate;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public partial class ZipArchiveEntry
private ZipVersionNeededValues _versionToExtract;
private BitFlagValues _generalPurposeBitFlag;
private readonly bool _isEncrypted;
private CompressionMethodValues _storedCompressionMethod;
private ZipCompressionMethod _storedCompressionMethod;
private DateTimeOffset _lastModified;
private long _compressedSize;
private long _uncompressedSize;
Expand Down Expand Up @@ -66,7 +66,7 @@ internal ZipArchiveEntry(ZipArchive archive, ZipCentralDirectoryFileHeader cd)
_versionToExtract = (ZipVersionNeededValues)cd.VersionNeededToExtract;
_generalPurposeBitFlag = (BitFlagValues)cd.GeneralPurposeBitFlag;
_isEncrypted = (_generalPurposeBitFlag & BitFlagValues.IsEncrypted) != 0;
CompressionMethod = (CompressionMethodValues)cd.CompressionMethod;
CompressionMethod = (ZipCompressionMethod)cd.CompressionMethod;
_lastModified = new DateTimeOffset(ZipHelper.DosTimeToDateTime(cd.LastModified));
_compressedSize = cd.CompressedSize;
_uncompressedSize = cd.UncompressedSize;
Expand Down Expand Up @@ -104,7 +104,7 @@ internal ZipArchiveEntry(ZipArchive archive, string entryName, CompressionLevel
_compressionLevel = compressionLevel;
if (_compressionLevel == CompressionLevel.NoCompression)
{
CompressionMethod = CompressionMethodValues.Stored;
CompressionMethod = ZipCompressionMethod.Stored;
}
_generalPurposeBitFlag = MapDeflateCompressionOption(_generalPurposeBitFlag, _compressionLevel, CompressionMethod);
}
Expand All @@ -121,7 +121,7 @@ internal ZipArchiveEntry(ZipArchive archive, string entryName)
_versionMadeBySpecification = ZipVersionNeededValues.Default;
_versionToExtract = ZipVersionNeededValues.Default; // this must happen before following two assignment
_compressionLevel = CompressionLevel.Optimal;
CompressionMethod = CompressionMethodValues.Deflate;
CompressionMethod = ZipCompressionMethod.Deflate;
_generalPurposeBitFlag = MapDeflateCompressionOption(0, _compressionLevel, CompressionMethod);
_lastModified = DateTimeOffset.Now;

Expand Down Expand Up @@ -173,6 +173,22 @@ internal ZipArchiveEntry(ZipArchive archive, string entryName)
/// </summary>
public bool IsEncrypted => _isEncrypted;

/// <summary>
/// Gets the compression method used to compress the entry.
/// </summary>
public ZipCompressionMethod CompressionMethod
{
get => _storedCompressionMethod;
private set
{
if (value == ZipCompressionMethod.Deflate)
VersionToExtractAtLeast(ZipVersionNeededValues.Deflate);
else if (value == ZipCompressionMethod.Deflate64)
VersionToExtractAtLeast(ZipVersionNeededValues.Deflate64);
_storedCompressionMethod = value;
}
}

/// <summary>
/// The compressed size of the entry. If the archive that the entry belongs to is in Create mode, attempts to get this property will always throw an exception. If the archive that the entry belongs to is in update mode, this property will only be valid if the entry has not been opened.
/// </summary>
Expand Down Expand Up @@ -439,27 +455,15 @@ private MemoryStream GetUncompressedData()
}

// if they start modifying it and the compression method is not "store", we should make sure it will get deflated
if (CompressionMethod != CompressionMethodValues.Stored)
if (CompressionMethod != ZipCompressionMethod.Stored)
{
CompressionMethod = CompressionMethodValues.Deflate;
CompressionMethod = ZipCompressionMethod.Deflate;
}
}

return _storedUncompressedData;
}

private CompressionMethodValues CompressionMethod
{
get { return _storedCompressionMethod; }
set
{
if (value == CompressionMethodValues.Deflate)
VersionToExtractAtLeast(ZipVersionNeededValues.Deflate);
else if (value == CompressionMethodValues.Deflate64)
VersionToExtractAtLeast(ZipVersionNeededValues.Deflate64);
_storedCompressionMethod = value;
}
}
// does almost everything you need to do to forget about this entry
// writes the local header/data, gets rid of all the data,
// closes all of the streams except for the very outermost one that
Expand Down Expand Up @@ -714,20 +718,20 @@ private CheckSumAndSizeWriteStream GetDataCompressor(Stream backingStream, bool
// changed to Stored.
//
// Note: Deflate64 is not supported on all platforms
Debug.Assert(CompressionMethod == CompressionMethodValues.Deflate
|| CompressionMethod == CompressionMethodValues.Stored);
Debug.Assert(CompressionMethod == ZipCompressionMethod.Deflate
|| CompressionMethod == ZipCompressionMethod.Stored);
Func<Stream> compressorStreamFactory;

bool isIntermediateStream = true;

switch (CompressionMethod)
{
case CompressionMethodValues.Stored:
case ZipCompressionMethod.Stored:
compressorStreamFactory = () => backingStream;
isIntermediateStream = false;
break;
case CompressionMethodValues.Deflate:
case CompressionMethodValues.Deflate64:
case ZipCompressionMethod.Deflate:
case ZipCompressionMethod.Deflate64:
default:
compressorStreamFactory = () => new DeflateStream(backingStream, _compressionLevel, leaveBackingStreamOpen);
break;
Expand Down Expand Up @@ -756,17 +760,17 @@ private Stream GetDataDecompressor(Stream compressedStreamToRead)
Stream? uncompressedStream;
switch (CompressionMethod)
{
case CompressionMethodValues.Deflate:
case ZipCompressionMethod.Deflate:
uncompressedStream = new DeflateStream(compressedStreamToRead, CompressionMode.Decompress, _uncompressedSize);
break;
case CompressionMethodValues.Deflate64:
uncompressedStream = new DeflateManagedStream(compressedStreamToRead, CompressionMethodValues.Deflate64, _uncompressedSize);
case ZipCompressionMethod.Deflate64:
uncompressedStream = new DeflateManagedStream(compressedStreamToRead, ZipCompressionMethod.Deflate64, _uncompressedSize);
break;
case CompressionMethodValues.Stored:
case ZipCompressionMethod.Stored:
default:
// we can assume that only deflate/deflate64/stored are allowed because we assume that
// IsOpenable is checked before this function is called
Debug.Assert(CompressionMethod == CompressionMethodValues.Stored);
Debug.Assert(CompressionMethod == ZipCompressionMethod.Stored);

uncompressedStream = compressedStreamToRead;
break;
Expand Down Expand Up @@ -867,15 +871,11 @@ private bool IsOpenableInitialVerifications(bool needToUncompress, out string? m
message = null;
if (needToUncompress)
{
if (CompressionMethod != CompressionMethodValues.Stored &&
CompressionMethod != CompressionMethodValues.Deflate &&
CompressionMethod != CompressionMethodValues.Deflate64)
if (CompressionMethod != ZipCompressionMethod.Stored &&
CompressionMethod != ZipCompressionMethod.Deflate &&
CompressionMethod != ZipCompressionMethod.Deflate64)
{
message = CompressionMethod switch
{
CompressionMethodValues.BZip2 or CompressionMethodValues.LZMA => SR.Format(SR.UnsupportedCompressionMethod, CompressionMethod.ToString()),
_ => SR.UnsupportedCompression,
};
message = SR.UnsupportedCompression;
return false;
}
}
Expand Down Expand Up @@ -923,11 +923,11 @@ private bool IsOpenableFinalVerifications(bool needToLoadIntoMemory, long offset

private bool AreSizesTooLarge => _compressedSize > uint.MaxValue || _uncompressedSize > uint.MaxValue;

private static CompressionLevel MapCompressionLevel(BitFlagValues generalPurposeBitFlag, CompressionMethodValues compressionMethod)
private static CompressionLevel MapCompressionLevel(BitFlagValues generalPurposeBitFlag, ZipCompressionMethod compressionMethod)
{
// Information about the Deflate compression option is stored in bits 1 and 2 of the general purpose bit flags.
// If the compression method is not Deflate, the Deflate compression option is invalid - default to NoCompression.
if (compressionMethod == CompressionMethodValues.Deflate || compressionMethod == CompressionMethodValues.Deflate64)
if (compressionMethod == ZipCompressionMethod.Deflate || compressionMethod == ZipCompressionMethod.Deflate64)
{
return ((int)generalPurposeBitFlag & 0x6) switch
{
Expand All @@ -944,12 +944,12 @@ private static CompressionLevel MapCompressionLevel(BitFlagValues generalPurpose
}
}

private static BitFlagValues MapDeflateCompressionOption(BitFlagValues generalPurposeBitFlag, CompressionLevel compressionLevel, CompressionMethodValues compressionMethod)
private static BitFlagValues MapDeflateCompressionOption(BitFlagValues generalPurposeBitFlag, CompressionLevel compressionLevel, ZipCompressionMethod compressionMethod)
{
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
compressionMethod == ZipCompressionMethod.Deflate || compressionMethod == ZipCompressionMethod.Deflate64
? compressionLevel switch
{
CompressionLevel.Optimal => 0,
Expand Down Expand Up @@ -982,7 +982,7 @@ private bool WriteLocalFileHeaderInitialize(bool isEmptyFile, bool forceWrite, o
// if we already know that we have an empty file don't worry about anything, just do a straight shot of the header
if (isEmptyFile)
{
CompressionMethod = CompressionMethodValues.Stored;
CompressionMethod = ZipCompressionMethod.Stored;
compressedSizeTruncated = 0;
uncompressedSizeTruncated = 0;
Debug.Assert(_uncompressedSize == 0);
Expand Down Expand Up @@ -1627,15 +1627,6 @@ internal enum BitFlagValues : ushort
UnicodeFileNameAndComment = 0x800
}

internal enum CompressionMethodValues : ushort
{
Stored = 0x0,
Deflate = 0x8,
Deflate64 = 0x9,
BZip2 = 0xC,
LZMA = 0xE
}

internal sealed class LocalHeaderOffsetComparer : Comparer<ZipArchiveEntry>
{
private static readonly LocalHeaderOffsetComparer s_instance = new LocalHeaderOffsetComparer();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.IO.Compression
{
/// <summary>
/// Specifies the compression method used to compress an entry in a zip archive.
/// </summary>
/// <remarks>
/// The values correspond to the compression method values described in the ZIP File Format Specification (APPNOTE.TXT section 4.4.5).
/// </remarks>
public enum ZipCompressionMethod
{
/// <summary>
/// The entry is stored (no compression).
/// </summary>
Stored = 0x0,

/// <summary>
/// The entry is compressed using the Deflate algorithm.
/// </summary>
Deflate = 0x8,

/// <summary>
/// The entry is compressed using the Deflate64 algorithm.
/// </summary>
Deflate64 = 0x9,
}
}
Loading
Loading