Imported Upstream version 5.10.0.47

Former-commit-id: d0813289fa2d35e1f8ed77530acb4fb1df441bc0
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-01-24 17:04:36 +00:00
parent 88ff76fe28
commit e46a49ecf1
5927 changed files with 226314 additions and 129848 deletions

View File

@@ -6,6 +6,5 @@
<AssemblyKey>ECMA</AssemblyKey>
<IsNETCoreApp>true</IsNETCoreApp>
<IsUAP>true</IsUAP>
<IsNetFxNETStandard>true</IsNetFxNETStandard>
</PropertyGroup>
</Project>

View File

@@ -4,7 +4,6 @@
<BuildConfigurations>
netcoreapp;
uap;
netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>

View File

@@ -7,8 +7,6 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
<ItemGroup>

View File

@@ -5,7 +5,6 @@
netcoreapp-Unix;
netcoreapp-Windows_NT;
uap-Windows_NT;
netfx-Windows_NT;
</BuildConfigurations>
</PropertyGroup>
</Project>

View File

@@ -33,13 +33,7 @@ internal static partial class Interop
[DllImport(Libraries.CompressionNative, EntryPoint = "CompressionNative_InflateEnd")]
internal static extern ZLibNative.ErrorCode InflateEnd(ref ZLibNative.ZStream stream);
internal static unsafe uint crc32(uint crc, byte[] buffer, int offset, int len)
{
fixed (byte* buf = &buffer[offset])
return Crc32(crc, buf, len);
}
[DllImport(Libraries.CompressionNative, EntryPoint = "CompressionNative_Crc32")]
private static extern unsafe uint Crc32(uint crc, byte* buffer, int len);
internal static extern unsafe uint crc32(uint crc, byte* buffer, int len);
}
}

View File

@@ -49,12 +49,6 @@ internal static partial class Interop
}
}
internal static unsafe uint crc32(uint crc, byte[] buffer, int offset, int len)
{
fixed (byte* buf = &buffer[offset])
return crc32(crc, buf, len);
}
internal static unsafe ZLibNative.ErrorCode Deflate(ref ZLibNative.ZStream stream, ZLibNative.FlushCode flush)
{
fixed (ZLibNative.ZStream* streamBytes = &stream)

View File

@@ -13,12 +13,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="$(SharedOpenSourcePath)System\IO\Compression\Crc32Helper.cs" />
<Compile Include="$(SharedOpenSourcePath)System\IO\Compression\ZipArchive.cs" />
<Compile Include="$(SharedOpenSourcePath)System\IO\Compression\ZipArchiveEntry.cs" />
<Compile Include="$(SharedOpenSourcePath)System\IO\Compression\ZipArchiveMode.cs" />
@@ -52,12 +49,16 @@
<Compile Include="System\IO\Compression\CompressionLevel.cs" />
<Compile Include="System\IO\Compression\CompressionMode.cs" />
<Compile Include="System\IO\Compression\GZipStream.cs" />
<Compile Include="System\IO\Compression\Crc32Helper.ZLib.cs" />
<Compile Include="System\IO\Compression\DeflateZLib\Deflater.cs" />
<Compile Include="System\IO\Compression\DeflateZLib\DeflateStream.cs" />
<Compile Include="System\IO\Compression\DeflateZLib\Inflater.cs" />
<Compile Include="System\IO\Compression\DeflateZLib\ZLibException.cs" />
<Compile Include="System\IO\Compression\DeflateZLib\ZLibNative.cs" />
<Compile Include="System\IO\Compression\ZLibException.Serialization.cs" />
<Compile Include="System\IO\Compression\ZipArchiveEntry.netcoreapp.cs" />
<Compile Include="System\IO\Compression\ZipCustomStreams.netcoreapp.cs" />
<Compile Include="System\IO\Compression\PositionPreservingWriteOnlyStreamWrapper.netcoreapp.cs" />
<Compile Include="$(CommonPath)\System\IO\PathInternal.cs">
<Link>Common\System\IO\PathInternal.cs</Link>
</Compile>
@@ -65,6 +66,9 @@
<Link>Common\System\IO\StreamHelpers.CopyValidation.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
<Compile Include="System\IO\Compression\Crc32Helper.Managed.cs" />
</ItemGroup>
<!-- Windows specific files -->
<ItemGroup Condition=" '$(TargetsWindows)' == 'true'">
<Compile Include="System\IO\Compression\ZipArchiveEntry.Windows.cs" />

View File

@@ -19,11 +19,8 @@ using System.Diagnostics;
namespace System.IO.Compression
{
/// <summary>
/// This class contains a managed Crc32 function as well as an indirection to the Interop.Zlib.Crc32 call.
/// Since Desktop compression uses this file alongside the Open ZipArchive, we cannot remove it
/// without breaking the Desktop build.
///
/// Note that in CoreFX the ZlibCrc32 function is always called.
/// without breaking the Desktop build. Note that in CoreFX the Zlib Crc32 function is always called.
/// </summary>
internal static class Crc32Helper
{
@@ -31,18 +28,45 @@ namespace System.IO.Compression
// See RFC1952 for details.
public static uint UpdateCrc32(uint crc32, byte[] buffer, int offset, int length)
{
Debug.Assert((buffer != null) && (offset >= 0) && (length >= 0)
&& (offset <= buffer.Length - length), "check the caller");
#if FEATURE_ZLIB
return Interop.zlib.crc32(crc32, buffer, offset, length);
#else
return ManagedCrc32(crc32, buffer, offset, length);
#endif
Debug.Assert((buffer != null) && (offset >= 0) && (length >= 0) && (offset <= buffer.Length - length));
Debug.Assert(BitConverter.IsLittleEndian, "ManagedCrc32 Expects Little Endian");
uint term1, term2, term3 = 0;
crc32 ^= 0xFFFFFFFFU;
int runningLength = (length / 8) * 8;
int endBytes = length - runningLength;
for (int i = 0; i < runningLength / 8; i++)
{
crc32 ^= unchecked((uint)(buffer[offset] | buffer[offset + 1] << 8 | buffer[offset + 2] << 16 | buffer[offset + 3] << 24));
offset += 4;
term1 = s_crcTable_7[crc32 & 0x000000FF] ^
s_crcTable_6[(crc32 >> 8) & 0x000000FF];
term2 = crc32 >> 16;
crc32 = term1 ^
s_crcTable_5[term2 & 0x000000FF] ^
s_crcTable_4[(term2 >> 8) & 0x000000FF];
term3 = unchecked((uint)(buffer[offset] | buffer[offset + 1] << 8 | buffer[offset + 2] << 16 | buffer[offset + 3] << 24));
offset += 4;
term1 = s_crcTable_3[term3 & 0x000000FF] ^
s_crcTable_2[(term3 >> 8) & 0x000000FF];
term2 = term3 >> 16;
crc32 ^= term1 ^
s_crcTable_1[term2 & 0x000000FF] ^
s_crcTable_0[(term2 >> 8) & 0x000000FF];
}
for (int i = 0; i < endBytes; i++)
{
crc32 = s_crcTable_0[(crc32 ^ buffer[offset++]) & 0x000000FF] ^ (crc32 >> 8);
}
crc32 ^= 0xFFFFFFFFU;
return crc32;
}
#if !FEATURE_ZLIB
// Generated tables for managed crc calculation.
// Each table n (starting at 0) contains remainders from the long division of
// all possible byte values, shifted by an offset of (n * 4 bits).
@@ -480,47 +504,5 @@ namespace System.IO.Compression
0x6EAB0882u, 0xA201081Cu, 0xA8C40105u, 0x646E019Bu, 0xEAE10678u,
0x264B06E6u
};
private static uint ManagedCrc32(uint crc32, byte[] buffer, int offset, int length)
{
Debug.Assert(BitConverter.IsLittleEndian, "ManagedCrc32 Expects Little Endian");
uint term1, term2, term3 = 0;
crc32 ^= 0xFFFFFFFFU;
int runningLength = (length / 8) * 8;
int endBytes = length - runningLength;
for (int i = 0; i < runningLength / 8; i++)
{
crc32 ^= unchecked((uint)(buffer[offset] | buffer[offset + 1] << 8 | buffer[offset + 2] << 16 | buffer[offset + 3] << 24));
offset += 4;
term1 = s_crcTable_7[crc32 & 0x000000FF] ^
s_crcTable_6[(crc32 >> 8) & 0x000000FF];
term2 = crc32 >> 16;
crc32 = term1 ^
s_crcTable_5[term2 & 0x000000FF] ^
s_crcTable_4[(term2 >> 8) & 0x000000FF];
term3 = unchecked((uint)(buffer[offset] | buffer[offset + 1] << 8 | buffer[offset + 2] << 16 | buffer[offset + 3] << 24));
offset += 4;
term1 = s_crcTable_3[term3 & 0x000000FF] ^
s_crcTable_2[(term3 >> 8) & 0x000000FF];
term2 = term3 >> 16;
crc32 ^= term1 ^
s_crcTable_1[term2 & 0x000000FF] ^
s_crcTable_0[(term2 >> 8) & 0x000000FF];
}
for (int i = 0; i < endBytes; i++)
{
crc32 = s_crcTable_0[(crc32 ^ buffer[offset++]) & 0x000000FF] ^ (crc32 >> 8);
}
crc32 ^= 0xFFFFFFFFU;
return crc32;
}
#endif
}
}

View File

@@ -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.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
namespace System.IO.Compression
{
internal static class Crc32Helper
{
// Calculate CRC based on the old CRC and the new bytes
public static unsafe uint UpdateCrc32(uint crc32, byte[] buffer, int offset, int length)
{
Debug.Assert((buffer != null) && (offset >= 0) && (length >= 0) && (offset <= buffer.Length - length));
fixed (byte* bufferPtr = buffer)
{
return Interop.zlib.crc32(crc32, bufferPtr, length);
}
}
public static unsafe uint UpdateCrc32(uint crc32, ReadOnlySpan<byte> buffer)
{
fixed (byte* bufferPtr = &buffer.DangerousGetPinnableReference())
{
return Interop.zlib.crc32(crc32, bufferPtr, buffer.Length);
}
}
}
}

View File

@@ -26,22 +26,6 @@ namespace System.IO.Compression
private bool _wroteHeader;
private bool _wroteBytes;
public DeflateManagedStream(Stream stream, CompressionMode mode) : this(stream, mode, leaveOpen: false)
{
}
// Since a reader is being taken, CompressionMode.Decompress is implied
internal DeflateManagedStream(Stream stream, bool leaveOpen, IFileFormatReader reader)
{
Debug.Assert(reader != null, "The IFileFormatReader passed to the internal DeflateStream constructor must be non-null");
if (stream == null)
throw new ArgumentNullException(nameof(stream));
if (!stream.CanRead)
throw new ArgumentException(SR.NotSupported_UnreadableStream, nameof(stream));
InitializeInflater(stream, leaveOpen, reader);
}
// A specific constructor to allow decompression of Deflate64
internal DeflateManagedStream(Stream stream, ZipArchiveEntry.CompressionMethodValues method)
{
@@ -53,41 +37,6 @@ namespace System.IO.Compression
InitializeInflater(stream, false, null, method);
}
public DeflateManagedStream(Stream stream, CompressionMode mode, bool leaveOpen)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));
switch (mode)
{
case CompressionMode.Decompress:
InitializeInflater(stream, leaveOpen);
break;
case CompressionMode.Compress:
InitializeDeflater(stream, leaveOpen, CompressionLevel.Optimal);
break;
default:
throw new ArgumentException(SR.ArgumentOutOfRange_Enum, nameof(mode));
}
}
// Implies mode = Compress
public DeflateManagedStream(Stream stream, CompressionLevel compressionLevel) : this(stream, compressionLevel, leaveOpen: false)
{
}
// Implies mode = Compress
public DeflateManagedStream(Stream stream, CompressionLevel compressionLevel, bool leaveOpen)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));
InitializeDeflater(stream, leaveOpen, compressionLevel);
}
/// <summary>
/// Sets up this DeflateManagedStream to be used for Inflation/Decompression
/// </summary>
@@ -106,23 +55,6 @@ namespace System.IO.Compression
_buffer = new byte[DefaultBufferSize];
}
/// <summary>
/// Sets up this DeflateManagedStream to be used for Deflation/Compression
/// </summary>
internal void InitializeDeflater(Stream stream, bool leaveOpen, CompressionLevel compressionLevel)
{
Debug.Assert(stream != null);
if (!stream.CanWrite)
throw new ArgumentException(SR.NotSupported_UnwritableStream, nameof(stream));
_deflater = new DeflaterManaged();
_stream = stream;
_mode = CompressionMode.Compress;
_leaveOpen = leaveOpen;
_buffer = new byte[DefaultBufferSize];
}
internal void SetFileFormatWriter(IFileFormatWriter writer)
{
if (writer != null)
@@ -131,8 +63,6 @@ namespace System.IO.Compression
}
}
public Stream BaseStream => _stream;
public override bool CanRead
{
get

View File

@@ -17,29 +17,5 @@ namespace System.IO.Compression
bool ReadFooter(InputBuffer input);
void UpdateWithBytesRead(byte[] buffer, int offset, int bytesToCopy);
void Validate();
/// <summary>
/// A reader corresponds to an expected file format and contains methods
/// to read header/footer data from a file of that format. If the Zlib library
/// is instead being used and the file format is supported, we can simply pass
/// a supported WindowSize and let Zlib do the header/footer parsing for us.
///
/// This Property allows getting of a ZLibWindowSize that can be used in place
/// of manually parsing the raw data stream.
/// </summary>
/// <return>
/// For raw data, return -8..-15
/// For GZip header detection and decoding, return 16..31
/// For GZip and Zlib header detection and decoding, return 32..47
/// </return>
/// <remarks>
/// The windowBits parameter for inflation must be greater than or equal to the
/// windowBits parameter used in deflation.
/// </remarks>
/// <remarks>
/// If the incorrect header information is used, zlib inflation will likely throw a
/// Z_DATA_ERROR exception.
///</remarks>
int ZLibWindowSize { get; }
}
}

View File

@@ -36,12 +36,12 @@ namespace System.IO.Compression
// Extra bits for length code 257 - 285.
private static readonly byte[] s_extraLengthBits =
{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,16,56,62 };
{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,16 };
// The base length for length code 257 - 285.
// The formula to get the real length for a length code is lengthBase[code - 257] + (value stored in extraBits)
private static readonly int[] s_lengthBase =
{ 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,3,0,0 };
{ 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,3};
// The base distance for distance code 0 - 31
// The real distance for a distance code is distanceBasePosition[code] + (value stored in extraBits)
@@ -91,17 +91,6 @@ namespace System.IO.Compression
private IFileFormatReader _formatReader; // class to decode header and footer (e.g. gzip)
public InflaterManaged(bool deflate64)
{
_output = new OutputWindow();
_input = new InputBuffer();
_codeList = new byte[HuffmanTree.MaxLiteralTreeElements + HuffmanTree.MaxDistTreeElements];
_codeLengthTreeCodeLength = new byte[HuffmanTree.NumberOfCodeLengthTreeElements];
_deflate64 = deflate64;
Reset();
}
internal InflaterManaged(IFileFormatReader reader, bool deflate64)
{
_output = new OutputWindow();
@@ -118,13 +107,6 @@ namespace System.IO.Compression
Reset();
}
public void SetFileFormatReader(IFileFormatReader reader)
{
_formatReader = reader;
_hasFormatReader = true;
Reset();
}
private void Reset()
{
_state = _hasFormatReader ?
@@ -139,8 +121,6 @@ namespace System.IO.Compression
public int AvailableOutput => _output.AvailableBytes;
public bool NeedsInput() => _input.NeedsInput();
public int Inflate(byte[] bytes, int offset, int length)
{
// copy bytes from output to outputbytes if we have available bytes
@@ -401,9 +381,10 @@ namespace System.IO.Compression
end_of_block_code_seen = false;
int freeBytes = _output.FreeBytes; // it is a little bit faster than frequently accessing the property
while (freeBytes > 258)
while (freeBytes > 65536)
{
// 258 means we can safely do decoding since maximum repeat length is 258
// With Deflate64 we can have up to a 64kb length, so we ensure at least that much space is available
// in the OutputWindow to avoid overwriting previous unflushed output data.
int symbol;
switch (_state)
@@ -506,7 +487,7 @@ namespace System.IO.Compression
goto case InflaterState.HaveDistCode;
case InflaterState.HaveDistCode:
// To avoid a table lookup we note that for distanceCode >= 2,
// To avoid a table lookup we note that for distanceCode > 3,
// extra_bits = (distanceCode-2) >> 1
int offset;
if (_distanceCode > 3)
@@ -524,7 +505,6 @@ namespace System.IO.Compression
offset = _distanceCode + 1;
}
Debug.Assert(freeBytes >= 258, "following operation is not safe!");
_output.WriteLengthDistance(_length, offset);
freeBytes -= _length;
_state = InflaterState.DecodeTop;

View File

@@ -15,10 +15,13 @@ namespace System.IO.Compression
/// </summary>
internal sealed class OutputWindow
{
private const int WindowSize = 65536;
private const int WindowMask = 65535;
// With Deflate64 we can have up to a 65536 length as well as up to a 65538 distance. This means we need a Window that is at
// least 131074 bytes long so we have space to retrieve up to a full 64kb in lookback and place it in our buffer without
// overwriting existing data. OutputWindow requires that the WindowSize be an exponent of 2, so we round up to 2^18.
private const int WindowSize = 262144;
private const int WindowMask = 262143;
private readonly byte[] _window = new byte[WindowSize]; // The window is 2^15 bytes
private readonly byte[] _window = new byte[WindowSize]; // The window is 2^18 bytes
private int _end; // this is the position to where we should write next byte
private int _bytesUsed; // The number of bytes in the output window which is not consumed.
@@ -34,14 +37,14 @@ namespace System.IO.Compression
public void WriteLengthDistance(int length, int distance)
{
Debug.Assert((_bytesUsed + length) <= WindowSize, "No Enough space");
// move backwards distance bytes in the output stream,
// and copy length bytes from this position to the output stream.
_bytesUsed += length;
int copyStart = (_end - distance) & WindowMask; // start position for coping.
int border = WindowSize - length;
if (copyStart <= border && _end < border)
if (copyStart <= border && _end < border)
{
if (length <= distance)
{

View File

@@ -23,7 +23,7 @@ namespace System.IO.Compression
private int _activeAsyncOperation; // 1 == true, 0 == false
private bool _wroteBytes;
public DeflateStream(Stream stream, CompressionMode mode): this(stream, mode, leaveOpen: false)
public DeflateStream(Stream stream, CompressionMode mode) : this(stream, mode, leaveOpen: false)
{
}
@@ -232,22 +232,38 @@ namespace System.IO.Compression
public override int Read(byte[] array, int offset, int count)
{
EnsureDecompressionMode();
ValidateParameters(array, offset, count);
return ReadCore(new Span<byte>(array, offset, count));
}
public override int Read(Span<byte> destination)
{
if (GetType() != typeof(DeflateStream))
{
// DeflateStream is not sealed, and a derived type may have overridden Read(byte[], int, int) prior
// to this Read(Span<byte>) overload being introduced. In that case, this Read(Span<byte>) overload
// should use the behavior of Read(byte[],int,int) overload.
return base.Read(destination);
}
else
{
return ReadCore(destination);
}
}
internal int ReadCore(Span<byte> destination)
{
EnsureDecompressionMode();
EnsureNotDisposed();
EnsureBufferInitialized();
int bytesRead;
int currentOffset = offset;
int remainingCount = count;
int totalRead = 0;
while (true)
{
bytesRead = _inflater.Inflate(array, currentOffset, remainingCount);
currentOffset += bytesRead;
remainingCount -= bytesRead;
if (remainingCount == 0)
int bytesRead = _inflater.Inflate(destination.Slice(totalRead));
totalRead += bytesRead;
if (totalRead == destination.Length)
{
break;
}
@@ -274,7 +290,7 @@ namespace System.IO.Compression
_inflater.SetInput(_buffer, 0, bytes);
}
return count - remainingCount;
return totalRead;
}
private void ValidateParameters(byte[] array, int offset, int count)
@@ -336,58 +352,73 @@ namespace System.IO.Compression
public override Task<int> ReadAsync(byte[] array, int offset, int count, CancellationToken cancellationToken)
{
// We use this checking order for compat to earlier versions:
ValidateParameters(array, offset, count);
return ReadAsyncMemory(new Memory<byte>(array, offset, count), cancellationToken).AsTask();
}
public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default(CancellationToken))
{
if (GetType() != typeof(DeflateStream))
{
// Ensure that existing streams derived from DeflateStream and that override ReadAsync(byte[],...)
// get their existing behaviors when the newer Memory-based overload is used.
return base.ReadAsync(destination, cancellationToken);
}
else
{
return ReadAsyncMemory(destination, cancellationToken);
}
}
internal ValueTask<int> ReadAsyncMemory(Memory<byte> destination, CancellationToken cancellationToken)
{
EnsureDecompressionMode();
EnsureNoActiveAsyncOperation();
ValidateParameters(array, offset, count);
EnsureNotDisposed();
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled<int>(cancellationToken);
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
}
EnsureBufferInitialized();
Task<int> readTask = null;
bool cleanup = true;
AsyncOperationStarting();
try
{
// Try to read decompressed data in output buffer
int bytesRead = _inflater.Inflate(array, offset, count);
int bytesRead = _inflater.Inflate(destination.Span);
if (bytesRead != 0)
{
// If decompression output buffer is not empty, return immediately.
return Task.FromResult(bytesRead);
return new ValueTask<int>(bytesRead);
}
if (_inflater.Finished())
{
// end of compression stream
return Task.FromResult(0);
return new ValueTask<int>(0);
}
// If there is no data on the output buffer and we are not at
// the end of the stream, we need to get more data from the base stream
readTask = _stream.ReadAsync(_buffer, 0, _buffer.Length, cancellationToken);
if (readTask == null)
{
throw new InvalidOperationException(SR.NotSupported_UnreadableStream);
}
return ReadAsyncCore(readTask, array, offset, count, cancellationToken);
ValueTask<int> readTask = _stream.ReadAsync(_buffer, cancellationToken);
cleanup = false;
return FinishReadAsyncMemory(readTask, destination, cancellationToken);
}
finally
{
// if we haven't started any async work, decrement the counter to end the transaction
if (readTask == null)
if (cleanup)
{
AsyncOperationCompleting();
}
}
}
private async Task<int> ReadAsyncCore(Task<int> readTask, byte[] array, int offset, int count, CancellationToken cancellationToken)
private async ValueTask<int> FinishReadAsyncMemory(
ValueTask<int> readTask, Memory<byte> destination, CancellationToken cancellationToken)
{
try
{
@@ -412,17 +443,13 @@ namespace System.IO.Compression
// Feed the data from base stream into decompression engine
_inflater.SetInput(_buffer, 0, bytesRead);
bytesRead = _inflater.Inflate(array, offset, count);
bytesRead = _inflater.Inflate(destination.Span);
if (bytesRead == 0 && !_inflater.Finished())
{
// We could have read in head information and didn't get any data.
// Read from the base stream again.
readTask = _stream.ReadAsync(_buffer, 0, _buffer.Length, cancellationToken);
if (readTask == null)
{
throw new InvalidOperationException(SR.NotSupported_UnreadableStream);
}
readTask = _stream.ReadAsync(_buffer, cancellationToken);
}
else
{
@@ -438,18 +465,43 @@ namespace System.IO.Compression
public override void Write(byte[] array, int offset, int count)
{
// Validate the state and the parameters
EnsureCompressionMode();
ValidateParameters(array, offset, count);
WriteCore(new ReadOnlySpan<byte>(array, offset, count));
}
public override void Write(ReadOnlySpan<byte> source)
{
if (GetType() != typeof(DeflateStream))
{
// DeflateStream is not sealed, and a derived type may have overridden Write(byte[], int, int) prior
// to this Write(ReadOnlySpan<byte>) overload being introduced. In that case, this Write(ReadOnlySpan<byte>) overload
// should use the behavior of Write(byte[],int,int) overload.
base.Write(source);
}
else
{
WriteCore(source);
}
}
internal void WriteCore(ReadOnlySpan<byte> source)
{
EnsureCompressionMode();
EnsureNotDisposed();
// Write compressed the bytes we already passed to the deflater:
WriteDeflaterOutput();
// Pass new bytes through deflater and write them too:
_deflater.SetInput(array, offset, count);
WriteDeflaterOutput();
_wroteBytes = true;
unsafe
{
// Pass new bytes through deflater and write them too:
fixed (byte* bufferPtr = &source.DangerousGetPinnableReference())
{
_deflater.SetInput(bufferPtr, source.Length);
WriteDeflaterOutput();
_wroteBytes = true;
}
}
}
private void WriteDeflaterOutput()
@@ -591,19 +643,36 @@ namespace System.IO.Compression
public override Task WriteAsync(byte[] array, int offset, int count, CancellationToken cancellationToken)
{
// We use this checking order for compat to earlier versions:
EnsureCompressionMode();
EnsureNoActiveAsyncOperation();
ValidateParameters(array, offset, count);
EnsureNotDisposed();
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled<int>(cancellationToken);
return WriteAsyncCore(array, offset, count, cancellationToken);
return WriteAsyncMemory(new ReadOnlyMemory<byte>(array, offset, count), cancellationToken);
}
private async Task WriteAsyncCore(byte[] array, int offset, int count, CancellationToken cancellationToken)
public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
{
if (GetType() != typeof(DeflateStream))
{
// Ensure that existing streams derived from DeflateStream and that override WriteAsync(byte[],...)
// get their existing behaviors when the newer Memory-based overload is used.
return base.WriteAsync(source, cancellationToken);
}
else
{
return WriteAsyncMemory(source, cancellationToken);
}
}
internal Task WriteAsyncMemory(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
{
EnsureCompressionMode();
EnsureNoActiveAsyncOperation();
EnsureNotDisposed();
return cancellationToken.IsCancellationRequested ?
Task.FromCanceled<int>(cancellationToken) :
WriteAsyncMemoryCore(source, cancellationToken);
}
private async Task WriteAsyncMemoryCore(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
{
AsyncOperationStarting();
try
@@ -611,7 +680,7 @@ namespace System.IO.Compression
await WriteDeflaterOutputAsync(cancellationToken).ConfigureAwait(false);
// Pass new bytes through deflater
_deflater.SetInput(array, offset, count);
_deflater.SetInput(source);
await WriteDeflaterOutputAsync(cancellationToken).ConfigureAwait(false);

View File

@@ -2,9 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Buffers;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;
using System.Security;
using ZErrorCode = System.IO.Compression.ZLibNative.ErrorCode;
@@ -18,7 +18,7 @@ namespace System.IO.Compression
internal sealed class Deflater : IDisposable
{
private ZLibNative.ZLibStreamHandle _zlibStream;
private GCHandle _inputBufferHandle;
private MemoryHandle _inputBufferHandle;
private bool _isDisposed;
private const int minWindowBits = -15; // WindowBits must be between -8..-15 to write no header, 8..15 for a
private const int maxWindowBits = 31; // zlib header, or 24..31 for a GZip header
@@ -83,29 +83,46 @@ namespace System.IO.Compression
if (disposing)
_zlibStream.Dispose();
if (_inputBufferHandle.IsAllocated)
DeallocateInputBufferHandle();
DeallocateInputBufferHandle();
_isDisposed = true;
}
}
public bool NeedsInput() => 0 == _zlibStream.AvailIn;
internal void SetInput(byte[] inputBuffer, int startIndex, int count)
internal unsafe void SetInput(ReadOnlyMemory<byte> inputBuffer)
{
Debug.Assert(NeedsInput(), "We have something left in previous input!");
Debug.Assert(null != inputBuffer);
Debug.Assert(startIndex >= 0 && count >= 0 && count + startIndex <= inputBuffer.Length);
Debug.Assert(!_inputBufferHandle.IsAllocated);
Debug.Assert(_inputBufferHandle.PinnedPointer == null);
if (0 == count)
if (0 == inputBuffer.Length)
{
return;
}
lock (SyncLock)
{
_inputBufferHandle = GCHandle.Alloc(inputBuffer, GCHandleType.Pinned);
_inputBufferHandle = inputBuffer.Retain(pin: true);
_zlibStream.NextIn = _inputBufferHandle.AddrOfPinnedObject() + startIndex;
_zlibStream.NextIn = (IntPtr)_inputBufferHandle.PinnedPointer;
_zlibStream.AvailIn = (uint)inputBuffer.Length;
}
}
internal unsafe void SetInput(byte* inputBufferPtr, int count)
{
Debug.Assert(NeedsInput(), "We have something left in previous input!");
Debug.Assert(inputBufferPtr != null);
Debug.Assert(_inputBufferHandle.PinnedPointer == null);
if (count == 0)
{
return;
}
lock (SyncLock)
{
_zlibStream.NextIn = (IntPtr)inputBufferPtr;
_zlibStream.AvailIn = (uint)count;
}
}
@@ -116,7 +133,6 @@ namespace System.IO.Compression
Debug.Assert(null != outputBuffer, "Can't pass in a null output buffer!");
Debug.Assert(!NeedsInput(), "GetDeflateOutput should only be called after providing input");
Debug.Assert(_inputBufferHandle.IsAllocated);
try
{
@@ -127,8 +143,10 @@ namespace System.IO.Compression
finally
{
// Before returning, make sure to release input buffer if necessary:
if (0 == _zlibStream.AvailIn && _inputBufferHandle.IsAllocated)
if (0 == _zlibStream.AvailIn)
{
DeallocateInputBufferHandle();
}
}
}
@@ -156,7 +174,10 @@ namespace System.IO.Compression
Debug.Assert(null != outputBuffer, "Can't pass in a null output buffer!");
Debug.Assert(outputBuffer.Length > 0, "Can't pass in an empty output buffer!");
Debug.Assert(NeedsInput(), "We have something left in previous input!");
Debug.Assert(!_inputBufferHandle.IsAllocated);
unsafe
{
Debug.Assert(_inputBufferHandle.PinnedPointer == null);
}
// Note: we require that NeedsInput() == true, i.e. that 0 == _zlibStream.AvailIn.
// If there is still input left we should never be getting here; instead we
@@ -174,7 +195,10 @@ namespace System.IO.Compression
Debug.Assert(null != outputBuffer, "Can't pass in a null output buffer!");
Debug.Assert(outputBuffer.Length > 0, "Can't pass in an empty output buffer!");
Debug.Assert(NeedsInput(), "We have something left in previous input!");
Debug.Assert(!_inputBufferHandle.IsAllocated);
unsafe
{
Debug.Assert(_inputBufferHandle.PinnedPointer == null);
}
// Note: we require that NeedsInput() == true, i.e. that 0 == _zlibStream.AvailIn.
// If there is still input left we should never be getting here; instead we
@@ -185,13 +209,11 @@ namespace System.IO.Compression
private void DeallocateInputBufferHandle()
{
Debug.Assert(_inputBufferHandle.IsAllocated);
lock (SyncLock)
{
_zlibStream.AvailIn = 0;
_zlibStream.NextIn = ZLibNative.ZNullPtr;
_inputBufferHandle.Free();
_inputBufferHandle.Dispose();
}
}

View File

@@ -64,6 +64,18 @@ namespace System.IO.Compression
}
}
public unsafe int Inflate(Span<byte> destination)
{
// If Inflate is called on an invalid or unready inflater, return 0 to indicate no bytes have been read.
if (destination.Length == 0)
return 0;
fixed (byte* bufPtr = &destination.DangerousGetPinnableReference())
{
return InflateVerified(bufPtr, destination.Length);
}
}
public unsafe int InflateVerified(byte* bufPtr, int length)
{
// State is valid; attempt inflation

View File

@@ -39,14 +39,6 @@ namespace System.IO.Compression
/// </summary>
public ZLibException() { }
/// <summary>
/// This constructor is provided in compliance with common NetFx design patterns;
/// developers should prefer using the constructor
/// <code>public ZLibException(string message, string zlibErrorContext, ZLibNative.ErrorCode zlibErrorCode, string zlibErrorMessage)</code>.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
public ZLibException(string message) : base(message) { }
/// <summary>
/// This constructor is provided in compliance with common NetFx design patterns;
/// developers should prefer using the constructor
@@ -55,23 +47,5 @@ namespace System.IO.Compression
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="inner">The exception that is the cause of the current exception, or a <code>null</code>.</param>
public ZLibException(string message, Exception innerException) : base(message, innerException) { }
public string ZLibContext
{
[SecurityCritical]
get { return _zlibErrorContext; }
}
public int ZLibErrorCode
{
[SecurityCritical]
get { return (int)_zlibErrorCode; }
}
public string ZLibErrorMessage
{
[SecurityCritical]
get { return _zlibErrorMessage; }
}
}
}

View File

@@ -327,29 +327,6 @@ namespace System.IO.Compression
return errC;
}
/// <summary>
/// This function is equivalent to inflateEnd followed by inflateInit.
/// The stream will keep attributes that may have been set by inflateInit2.
/// </summary>
[SecurityCritical]
public ErrorCode InflateReset(int windowBits)
{
EnsureNotDisposed();
EnsureState(State.InitializedForInflate);
ErrorCode errC = Interop.zlib.InflateEnd(ref _zStream);
if (errC != ErrorCode.Ok)
{
_initializationState = State.Disposed;
return errC;
}
errC = Interop.zlib.InflateInit2_(ref _zStream, windowBits);
_initializationState = State.InitializedForInflate;
return errC;
}
// This can work even after XxflateEnd().
[SecurityCritical]
public string GetErrorMessage() => _zStream.msg != ZNullPtr ? Marshal.PtrToStringAnsi(_zStream.msg) : string.Empty;

View File

@@ -84,6 +84,22 @@ namespace System.IO.Compression
return _deflateStream.Read(array, offset, count);
}
public override int Read(Span<byte> destination)
{
if (GetType() != typeof(GZipStream))
{
// GZipStream is not sealed, and a derived type may have overridden Read(byte[], int, int) prior
// to this Read(Span<byte>) overload being introduced. In that case, this Read(Span<byte>) overload
// should use the behavior of Read(byte[],int,int) overload.
return base.Read(destination);
}
else
{
CheckDeflateStream();
return _deflateStream.ReadCore(destination);
}
}
public override IAsyncResult BeginWrite(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState) =>
TaskToApm.Begin(WriteAsync(array, offset, count, CancellationToken.None), asyncCallback, asyncState);
@@ -96,6 +112,28 @@ namespace System.IO.Compression
_deflateStream.Write(array, offset, count);
}
public override void Write(ReadOnlySpan<byte> source)
{
if (GetType() != typeof(GZipStream))
{
// GZipStream is not sealed, and a derived type may have overridden Write(byte[], int, int) prior
// to this Write(ReadOnlySpan<byte>) overload being introduced. In that case, this Write(ReadOnlySpan<byte>) overload
// should use the behavior of Write(byte[],int,int) overload.
base.Write(source);
}
else
{
CheckDeflateStream();
_deflateStream.WriteCore(source);
}
}
public override void CopyTo(Stream destination, int bufferSize)
{
CheckDeflateStream();
_deflateStream.CopyTo(destination, bufferSize);
}
protected override void Dispose(bool disposing)
{
try
@@ -120,12 +158,44 @@ namespace System.IO.Compression
return _deflateStream.ReadAsync(array, offset, count, cancellationToken);
}
public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default(CancellationToken))
{
if (GetType() != typeof(GZipStream))
{
// GZipStream is not sealed, and a derived type may have overridden ReadAsync(byte[], int, int) prior
// to this ReadAsync(Memory<byte>) overload being introduced. In that case, this ReadAsync(Memory<byte>) overload
// should use the behavior of ReadAsync(byte[],int,int) overload.
return base.ReadAsync(destination, cancellationToken);
}
else
{
CheckDeflateStream();
return _deflateStream.ReadAsyncMemory(destination, cancellationToken);
}
}
public override Task WriteAsync(byte[] array, int offset, int count, CancellationToken cancellationToken)
{
CheckDeflateStream();
return _deflateStream.WriteAsync(array, offset, count, cancellationToken);
}
public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default(CancellationToken))
{
if (GetType() != typeof(GZipStream))
{
// GZipStream is not sealed, and a derived type may have overridden WriteAsync(byte[], int, int) prior
// to this WriteAsync(ReadOnlyMemory<byte>) overload being introduced. In that case, this
// WriteAsync(ReadOnlyMemory<byte>) overload should use the behavior of Write(byte[],int,int) overload.
return base.WriteAsync(source, cancellationToken);
}
else
{
CheckDeflateStream();
return _deflateStream.WriteAsyncMemory(source, cancellationToken);
}
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
CheckDeflateStream();

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace System.IO.Compression
{
internal sealed class PositionPreservingWriteOnlyStreamWrapper : Stream
internal sealed partial class PositionPreservingWriteOnlyStreamWrapper : Stream
{
private readonly Stream _stream;
private long _position;

Some files were not shown because too many files have changed in this diff Show More