Skip to content
Draft
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
3 changes: 3 additions & 0 deletions src/libraries/Common/src/Interop/Interop.zlib.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,8 @@ internal static unsafe partial ZLibNative.ErrorCode DeflateInit2_(

[LibraryImport(Libraries.CompressionNative, EntryPoint = "CompressionNative_Crc32")]
internal static unsafe partial uint crc32(uint crc, byte* buffer, int len);

[LibraryImport(Libraries.CompressionNative, EntryPoint = "CompressionNative_CompressBound")]
internal static partial uint compressBound(uint sourceLen);
}
}
60 changes: 60 additions & 0 deletions src/libraries/System.IO.Compression/ref/System.IO.Compression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,26 @@ public enum CompressionMode
Decompress = 0,
Compress = 1,
}
public sealed partial class DeflateDecoder : System.IDisposable
{
public DeflateDecoder() { }
public System.Buffers.OperationStatus Decompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesConsumed, out int bytesWritten) { throw null; }
public void Dispose() { }
public static bool TryDecompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
}
public sealed partial class DeflateEncoder : System.IDisposable
{
public DeflateEncoder() { }
public DeflateEncoder(System.IO.Compression.CompressionLevel compressionLevel) { }
public DeflateEncoder(System.IO.Compression.CompressionLevel compressionLevel, System.IO.Compression.ZLibCompressionStrategy strategy) { }
public DeflateEncoder(System.IO.Compression.ZLibCompressionOptions options) { }
public System.Buffers.OperationStatus Compress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesConsumed, out int bytesWritten, bool isFinalBlock) { throw null; }
public void Dispose() { }
public System.Buffers.OperationStatus Flush(System.Span<byte> destination, out int bytesWritten) { throw null; }
public static long GetMaxCompressedLength(long inputSize) { throw null; }
public static bool TryCompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
public static bool TryCompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten, System.IO.Compression.CompressionLevel compressionLevel) { throw null; }
}
public partial class DeflateStream : System.IO.Stream
{
public DeflateStream(System.IO.Stream stream, System.IO.Compression.CompressionLevel compressionLevel) { }
Expand Down Expand Up @@ -54,6 +74,26 @@ public override void Write(System.ReadOnlySpan<byte> buffer) { }
public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory<byte> buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public override void WriteByte(byte value) { }
}
public sealed partial class GZipDecoder : System.IDisposable
{
public GZipDecoder() { }
public System.Buffers.OperationStatus Decompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesConsumed, out int bytesWritten) { throw null; }
public void Dispose() { }
public static bool TryDecompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
}
public sealed partial class GZipEncoder : System.IDisposable
{
public GZipEncoder() { }
public GZipEncoder(System.IO.Compression.CompressionLevel compressionLevel) { }
public GZipEncoder(System.IO.Compression.CompressionLevel compressionLevel, System.IO.Compression.ZLibCompressionStrategy strategy) { }
public GZipEncoder(System.IO.Compression.ZLibCompressionOptions options) { }
public System.Buffers.OperationStatus Compress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesConsumed, out int bytesWritten, bool isFinalBlock) { throw null; }
public void Dispose() { }
public System.Buffers.OperationStatus Flush(System.Span<byte> destination, out int bytesWritten) { throw null; }
public static long GetMaxCompressedLength(long inputSize) { throw null; }
public static bool TryCompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
public static bool TryCompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten, System.IO.Compression.CompressionLevel compressionLevel) { throw null; }
}
public partial class GZipStream : System.IO.Stream
{
public GZipStream(System.IO.Stream stream, System.IO.Compression.CompressionLevel compressionLevel) { }
Expand Down Expand Up @@ -158,6 +198,26 @@ public enum ZLibCompressionStrategy
RunLengthEncoding = 3,
Fixed = 4,
}
public sealed partial class ZLibDecoder : System.IDisposable
{
public ZLibDecoder() { }
public System.Buffers.OperationStatus Decompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesConsumed, out int bytesWritten) { throw null; }
public void Dispose() { }
public static bool TryDecompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
}
public sealed partial class ZLibEncoder : System.IDisposable
{
public ZLibEncoder() { }
public ZLibEncoder(System.IO.Compression.CompressionLevel compressionLevel) { }
public ZLibEncoder(System.IO.Compression.CompressionLevel compressionLevel, System.IO.Compression.ZLibCompressionStrategy strategy) { }
public ZLibEncoder(System.IO.Compression.ZLibCompressionOptions options) { }
public System.Buffers.OperationStatus Compress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesConsumed, out int bytesWritten, bool isFinalBlock) { throw null; }
public void Dispose() { }
public System.Buffers.OperationStatus Flush(System.Span<byte> destination, out int bytesWritten) { throw null; }
public static long GetMaxCompressedLength(long inputSize) { throw null; }
public static bool TryCompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
public static bool TryCompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten, System.IO.Compression.CompressionLevel compressionLevel) { throw null; }
}
public sealed partial class ZLibStream : System.IO.Stream
{
public ZLibStream(System.IO.Stream stream, System.IO.Compression.CompressionLevel compressionLevel) { }
Expand Down
18 changes: 18 additions & 0 deletions src/libraries/System.IO.Compression/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,24 @@
<data name="ZLibErrorUnexpected" xml:space="preserve">
<value>The underlying compression routine returned an unexpected error code: '{0}'.</value>
</data>
<data name="DeflateEncoder_NotInitialized" xml:space="preserve">
<value>The DeflateEncoder has not been initialized. Use the constructor to initialize.</value>
</data>
<data name="DeflateDecoder_NotInitialized" xml:space="preserve">
<value>The DeflateDecoder has not been initialized. Use the constructor to initialize.</value>
</data>
<data name="ZLibEncoder_NotInitialized" xml:space="preserve">
<value>The ZLibEncoder has not been initialized. Use the constructor to initialize.</value>
</data>
<data name="ZLibDecoder_NotInitialized" xml:space="preserve">
<value>The ZLibDecoder has not been initialized. Use the constructor to initialize.</value>
</data>
<data name="GZipEncoder_NotInitialized" xml:space="preserve">
<value>The GZipEncoder has not been initialized. Use the constructor to initialize.</value>
</data>
<data name="GZipDecoder_NotInitialized" xml:space="preserve">
<value>The GZipDecoder has not been initialized. Use the constructor to initialize.</value>
</data>
<data name="CDCorrupt" xml:space="preserve">
<value>Central Directory corrupt.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,13 @@
<Compile Include="System\IO\Compression\Crc32Helper.ZLib.cs" />
<Compile Include="System\IO\Compression\GZipStream.cs" />
<Compile Include="System\IO\Compression\PositionPreservingWriteOnlyStreamWrapper.cs" />
<Compile Include="System\IO\Compression\DeflateDecoder.cs" />
<Compile Include="System\IO\Compression\DeflateEncoder.cs" />
<Compile Include="System\IO\Compression\GZipDecoder.cs" />
<Compile Include="System\IO\Compression\GZipEncoder.cs" />
<Compile Include="System\IO\Compression\ZLibCompressionOptions.cs" />
<Compile Include="System\IO\Compression\ZLibDecoder.cs" />
<Compile Include="System\IO\Compression\ZLibEncoder.cs" />
<Compile Include="System\IO\Compression\ZLibStream.cs" />
<Compile Include="System\IO\Compression\ZipCompressionMethod.cs" />
<Compile Include="$(CommonPath)System\Obsoletions.cs"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace System.IO.Compression
{
/// <summary>
/// Provides methods and static methods to decode data compressed in the Deflate data format in a streamless, non-allocating, and performant manner.
/// </summary>
public sealed class DeflateDecoder : IDisposable
{
private ZLibNative.ZLibStreamHandle? _state;
private bool _disposed;
private bool _finished;

/// <summary>
/// Initializes a new instance of the <see cref="DeflateDecoder"/> class.
/// </summary>
/// <exception cref="IOException">Failed to create the <see cref="DeflateDecoder"/> instance.</exception>
public DeflateDecoder()
: this(ZLibNative.Deflate_DefaultWindowBits)
{
}

internal DeflateDecoder(int windowBits)
{
_disposed = false;
_finished = false;
_state = ZLibNative.ZLibStreamHandle.CreateForInflate(windowBits);
}

/// <summary>
/// Frees and disposes unmanaged resources.
/// </summary>
public void Dispose()
{
_disposed = true;
_state?.Dispose();
_state = null;
}

private void EnsureNotDisposed()
{
ObjectDisposedException.ThrowIf(_disposed, this);
}

private void EnsureInitialized()
{
EnsureNotDisposed();
if (_state is null)
{
throw new InvalidOperationException(SR.DeflateDecoder_NotInitialized);
}
}

/// <summary>
/// Decompresses a read-only byte span into a destination span.
/// </summary>
/// <param name="source">A read-only span of bytes containing the compressed source data.</param>
/// <param name="destination">When this method returns, a byte span where the decompressed data is stored.</param>
/// <param name="bytesConsumed">When this method returns, the total number of bytes that were read from <paramref name="source"/>.</param>
/// <param name="bytesWritten">When this method returns, the total number of bytes that were written to <paramref name="destination"/>.</param>
/// <returns>One of the enumeration values that describes the status with which the span-based operation finished.</returns>
public OperationStatus Decompress(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesConsumed, out int bytesWritten)
{
EnsureInitialized();
Debug.Assert(_state is not null);

bytesConsumed = 0;
bytesWritten = 0;

if (_finished)
{
return OperationStatus.Done;
}

unsafe
{
fixed (byte* inputPtr = &MemoryMarshal.GetReference(source))
fixed (byte* outputPtr = &MemoryMarshal.GetReference(destination))
{
_state.NextIn = (IntPtr)inputPtr;
_state.AvailIn = (uint)source.Length;
_state.NextOut = (IntPtr)outputPtr;
_state.AvailOut = (uint)destination.Length;

ZLibNative.ErrorCode errorCode = _state.Inflate(ZLibNative.FlushCode.NoFlush);

bytesConsumed = source.Length - (int)_state.AvailIn;
bytesWritten = destination.Length - (int)_state.AvailOut;

OperationStatus status = errorCode switch
{
ZLibNative.ErrorCode.Ok => _state.AvailIn == 0 && _state.AvailOut > 0
? OperationStatus.NeedMoreData
: _state.AvailOut == 0
? OperationStatus.DestinationTooSmall
: OperationStatus.NeedMoreData,
ZLibNative.ErrorCode.StreamEnd => OperationStatus.Done,
ZLibNative.ErrorCode.BufError => _state.AvailOut == 0
? OperationStatus.DestinationTooSmall
: OperationStatus.NeedMoreData,
ZLibNative.ErrorCode.DataError => OperationStatus.InvalidData,
_ => OperationStatus.InvalidData
};

// Track if decompression is finished
if (errorCode == ZLibNative.ErrorCode.StreamEnd)
{
_finished = true;
}

return status;
}
}
}

/// <summary>
/// Tries to decompress a source byte span into a destination span.
/// </summary>
/// <param name="source">A read-only span of bytes containing the compressed source data.</param>
/// <param name="destination">When this method returns, a span of bytes where the decompressed data is stored.</param>
/// <param name="bytesWritten">When this method returns, the total number of bytes that were written to <paramref name="destination"/>.</param>
/// <returns><see langword="true"/> if the decompression operation was successful; <see langword="false"/> otherwise.</returns>
public static bool TryDecompress(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
{
using var decoder = new DeflateDecoder();
OperationStatus status = decoder.Decompress(source, destination, out int consumed, out bytesWritten);

return status == OperationStatus.Done && consumed == source.Length;
}
}
}
Loading
Loading