From 29f06b753adf2c438647a7aa40ff094a859263a2 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 30 Apr 2026 13:07:34 +0100 Subject: [PATCH] add Crc32Stream write async --- src/SharpCompress/Crypto/Crc32Stream.cs | 41 +++++++++++++++++++++++++ tests/SharpCompress.Test/ADCTest.cs | 35 +++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/src/SharpCompress/Crypto/Crc32Stream.cs b/src/SharpCompress/Crypto/Crc32Stream.cs index 4a65587e..a9ca3b90 100644 --- a/src/SharpCompress/Crypto/Crc32Stream.cs +++ b/src/SharpCompress/Crypto/Crc32Stream.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using System.Threading; +using System.Threading.Tasks; namespace SharpCompress.Crypto; @@ -34,9 +36,26 @@ public sealed class Crc32Stream : Stream public override void Flush() => stream.Flush(); + public override async Task FlushAsync(CancellationToken cancellationToken) => + await stream.FlushAsync(cancellationToken).ConfigureAwait(false); + public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException(); + public override Task ReadAsync( + byte[] buffer, + int offset, + int count, + CancellationToken cancellationToken + ) => throw new NotSupportedException(); + +#if !LEGACY_DOTNET + public override ValueTask ReadAsync( + Memory buffer, + CancellationToken cancellationToken = default + ) => throw new NotSupportedException(); +#endif + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); public override void SetLength(long value) => throw new NotSupportedException(); @@ -57,6 +76,28 @@ public sealed class Crc32Stream : Stream seed = CalculateCrc(_table, seed, buffer.AsSpan(offset, count)); } + public override async Task WriteAsync( + byte[] buffer, + int offset, + int count, + CancellationToken cancellationToken + ) + { + await stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + seed = CalculateCrc(_table, seed, buffer.AsSpan(offset, count)); + } + +#if !LEGACY_DOTNET + public override async ValueTask WriteAsync( + ReadOnlyMemory buffer, + CancellationToken cancellationToken = default + ) + { + await stream.WriteAsync(buffer, cancellationToken).ConfigureAwait(false); + seed = CalculateCrc(_table, seed, buffer.Span); + } +#endif + public override void WriteByte(byte value) { stream.WriteByte(value); diff --git a/tests/SharpCompress.Test/ADCTest.cs b/tests/SharpCompress.Test/ADCTest.cs index 8ef40a17..cb2b00a9 100644 --- a/tests/SharpCompress.Test/ADCTest.cs +++ b/tests/SharpCompress.Test/ADCTest.cs @@ -23,7 +23,10 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +using System; using System.IO; +using System.Threading; +using System.Threading.Tasks; using SharpCompress.Compressors.ADC; using SharpCompress.Compressors.Deflate; using SharpCompress.Crypto; @@ -121,4 +124,36 @@ public class AdcTest : TestBase Assert.Equal(crc32, crc32A); Assert.Equal(crc32, crc32B); } + + [Fact] + public async Task TestCrc32StreamWriteAsync() + { + var buffer = File.ReadAllBytes(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + var crc32 = Crc32Stream.Compute(buffer); + + using var memory = new MemoryStream(); + using var crcStream = new Crc32Stream(memory, 0xEDB88320, 0xFFFFFFFF); + + await crcStream.WriteAsync(buffer, 0, buffer.Length, CancellationToken.None); + + Assert.Equal(buffer, memory.ToArray()); + Assert.Equal(crc32, crcStream.Crc); + } + +#if !LEGACY_DOTNET + [Fact] + public async Task TestCrc32StreamWriteMemoryAsync() + { + var buffer = File.ReadAllBytes(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + var crc32 = Crc32Stream.Compute(buffer); + + using var memory = new MemoryStream(); + using var crcStream = new Crc32Stream(memory, 0xEDB88320, 0xFFFFFFFF); + + await crcStream.WriteAsync(buffer.AsMemory(), CancellationToken.None); + + Assert.Equal(buffer, memory.ToArray()); + Assert.Equal(crc32, crcStream.Crc); + } +#endif }