mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-11-15 17:02:03 +00:00
Merge pull request #1448 from adamhathcock/adam/merge-release-and-update-dependencies
Merge release fixes and update dependencies
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
|
||||
<PackageVersion Include="Bullseye" Version="6.2.0" />
|
||||
<PackageVersion Include="Bullseye" Version="6.3.0" />
|
||||
<PackageVersion Include="AwesomeAssertions" Version="9.6.0" />
|
||||
<PackageVersion Include="Glob" Version="1.1.9" />
|
||||
<PackageVersion Include="JetBrains.Profiler.SelfApi" Version="2.5.18" />
|
||||
@@ -9,16 +9,16 @@
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.10.1" />
|
||||
<PackageVersion Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
||||
<PackageVersion Include="SimpleExec" Version="13.1.0" />
|
||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="8.0.0" />
|
||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="10.0.12" />
|
||||
<PackageVersion Include="xunit.v3" Version="3.2.2" />
|
||||
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
|
||||
<GlobalPackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.401" />
|
||||
<GlobalPackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" />
|
||||
<GlobalPackageReference
|
||||
Include="Microsoft.VisualStudio.Threading.Analyzers"
|
||||
Version="17.14.15"
|
||||
Version="18.12.1"
|
||||
/>
|
||||
<GlobalPackageReference Include="PolySharp" Version="1.16.0" />
|
||||
<GlobalPackageReference Include="Zomp.SyncMethodGenerator" Version="2.0.56" />
|
||||
<GlobalPackageReference Include="Zomp.SyncMethodGenerator" Version="2.0.66" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
"net10.0": {
|
||||
"Bullseye": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.2.0, )",
|
||||
"resolved": "6.2.0",
|
||||
"contentHash": "YWQxe+pvudGSzW1QqnRUlr9XV0xtlNvMxorVaFPqoMH8qAYNxniMQKGrPSiQkgEy0ckn/TAq98E+DIwTSR7vbQ=="
|
||||
"requested": "[6.3.0, )",
|
||||
"resolved": "6.3.0",
|
||||
"contentHash": "yK14DF1aGvyGxIDFwApU1+YJcnXRmuVhGdz7js7eVTBnLvl/4rg20jb43YDhFvifcx7tRD4iOzF6ykoLdvWNfw=="
|
||||
},
|
||||
"Glob": {
|
||||
"type": "Direct",
|
||||
@@ -36,9 +36,9 @@
|
||||
},
|
||||
"Microsoft.VisualStudio.Threading.Analyzers": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.14.15, )",
|
||||
"resolved": "17.14.15",
|
||||
"contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
|
||||
"requested": "[18.12.1, )",
|
||||
"resolved": "18.12.1",
|
||||
"contentHash": "sQt7NpnselT1gP1a7bTfhmfHYV0jbavst/8mOoWTMSjXhXzWPssqgBoIwrxNsgJUa7XQzD2raSRMAFfmlepxNw=="
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
@@ -54,9 +54,9 @@
|
||||
},
|
||||
"Zomp.SyncMethodGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.56, )",
|
||||
"resolved": "2.0.56",
|
||||
"contentHash": "P1iMA1meu0uX8YcPWhkFnpzV3e+QFDDYMU6hMNyofS+pBlLgeVV7QevBmJmJ/mrxA1jujo3cqNaO1IapdfjOlA=="
|
||||
"requested": "[2.0.66, )",
|
||||
"resolved": "2.0.66",
|
||||
"contentHash": "iYnF185851PEX5vnxrhUj2av30HoxvjUlPd0HVVuSAif7TCgc/Noc5xVf9jiLhMlI8Rt9QrJdef3KB8+opAJQA=="
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
|
||||
@@ -107,7 +107,7 @@ The stream overloads of `DetectArchive` and `InspectArchive` preserve the suppli
|
||||
|
||||
Stored (compression method 0) comments are supported up to 16 MiB of unpacked data; larger or unknown-size comments throw `InvalidFormatException`. Comments using other compression methods are skipped without affecting entry extraction.
|
||||
|
||||
Truncated encrypted comment data throws `InvalidFormatException` on synchronous reads or `IncompleteArchiveException` on asynchronous reads. RAR5 KDF counts above 24 are rejected with `CryptographicException` before deriving encryption keys.
|
||||
Truncated encrypted comment data throws `InvalidFormatException` on both synchronous and asynchronous reads. RAR5 KDF counts above 24 are rejected with `CryptographicException` before deriving encryption keys.
|
||||
|
||||
```csharp
|
||||
using var archive = RarArchive.OpenArchive(
|
||||
@@ -502,6 +502,8 @@ archive.SaveTo("output.zip", options);
|
||||
|
||||
### Extraction behavior
|
||||
|
||||
`ZipArchiveEntry.OpenEntryStreamAsync` and `TarArchiveEntry.OpenEntryStreamAsync` are virtual and support newly added writable entries as well as entries read from an archive. Opening a new writable entry checks cancellation, rewinds its supplied stream, and returns a non-owning wrapper. Disposing that wrapper leaves the supplied stream open; archive disposal follows the entry's `closeStream` setting.
|
||||
|
||||
```csharp
|
||||
var options = new ExtractionOptions
|
||||
{
|
||||
@@ -692,6 +694,8 @@ using (var archive = ZipArchive.OpenArchive("archive.zip", options))
|
||||
|
||||
### Async Extract with Cancellation
|
||||
|
||||
Async archive and reader/writer operations dispose SharpCompress resources asynchronously on every target, including .NET Framework 4.8 and .NET Standard 2.0. `SharpCompressStream.DisposeAsync()` and `ZlibStream.DisposeAsync()` are available on every target; stream wrappers forward disposal to runtime `IAsyncDisposable` implementations where available, falling back to synchronous disposal only for streams that do not support it.
|
||||
|
||||
```csharp
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(TimeSpan.FromMinutes(5));
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
- RAR5 encrypted headers and data accept KDF counts from 0 through 24 (the binary logarithm of the PBKDF2 iteration count), matching UnRAR's acceptance limit. Larger counts are rejected before key derivation.
|
||||
- RAR companion filenames use the same exact-match-first, case-insensitive fallback as ZIP, with ambiguous fallback matches rejected.
|
||||
- Encrypted ciphertext must contain complete AES blocks. Truncation throws `InvalidFormatException` on synchronous reads or `IncompleteArchiveException` on asynchronous reads.
|
||||
- Encrypted ciphertext must contain complete AES blocks. Truncation throws `InvalidFormatException` on both synchronous and asynchronous reads.
|
||||
|
||||
### 7Zip Format Notes
|
||||
|
||||
|
||||
@@ -25,7 +25,12 @@ public partial class GZipArchive
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
#if SYNC_ONLY
|
||||
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
|
||||
#else
|
||||
var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
|
||||
await using var scope = stream.DisposeAsyncScope().ConfigureAwait(false);
|
||||
#endif
|
||||
await SaveToAsync(stream, new GZipWriterOptions(CompressionType.GZip), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
@@ -50,9 +55,16 @@ public partial class GZipArchive
|
||||
{
|
||||
if (!entry.IsDirectory)
|
||||
{
|
||||
using var entryStream = await entry
|
||||
#if SYNC_ONLY
|
||||
using var entryStream = entry.OpenEntryStream();
|
||||
#else
|
||||
var entryStream = await entry
|
||||
.OpenEntryStreamAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await using var entryStreamScope = entryStream
|
||||
.DisposeAsyncScope()
|
||||
.ConfigureAwait(false);
|
||||
#endif
|
||||
await writer
|
||||
.WriteAsync(
|
||||
entry.Key.NotNull("Entry Key is null"),
|
||||
@@ -65,9 +77,16 @@ public partial class GZipArchive
|
||||
}
|
||||
foreach (var entry in newEntries.Where(x => !x.IsDirectory))
|
||||
{
|
||||
using var entryStream = await entry
|
||||
#if SYNC_ONLY
|
||||
using var entryStream = entry.OpenEntryStream();
|
||||
#else
|
||||
var entryStream = await entry
|
||||
.OpenEntryStreamAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await using var entryStreamScope = entryStream
|
||||
.DisposeAsyncScope()
|
||||
.ConfigureAwait(false);
|
||||
#endif
|
||||
await writer
|
||||
.WriteAsync(
|
||||
entry.Key.NotNull("Entry Key is null"),
|
||||
|
||||
@@ -164,7 +164,12 @@ public static partial class IArchiveEntryExtensions
|
||||
options,
|
||||
async (x, fm, ct) =>
|
||||
{
|
||||
#if SYNC_ONLY
|
||||
using var fs = File.Open(x, fm);
|
||||
#else
|
||||
var fs = File.Open(x, fm);
|
||||
await using var scope = fs.DisposeAsyncScope().ConfigureAwait(false);
|
||||
#endif
|
||||
await entry
|
||||
.WriteToAsync(fs, options.BufferSize, options, null, ct)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -83,7 +83,8 @@ public static class IWritableAsyncArchiveExtensions
|
||||
)
|
||||
where TOptions : IWriterOptions
|
||||
{
|
||||
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
|
||||
var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
|
||||
await using var scope = stream.DisposeAsyncScope().ConfigureAwait(false);
|
||||
await writableArchive.SaveToAsync(stream, options, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public partial class TarArchive
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
using var writer = new TarWriter(stream, options);
|
||||
await using var writer = new TarWriter(stream, options);
|
||||
await foreach (
|
||||
var entry in oldEntries.WithCancellation(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
@@ -39,7 +39,12 @@ public partial class TarArchive
|
||||
}
|
||||
else
|
||||
{
|
||||
using var entryStream = entry.OpenEntryStream();
|
||||
var entryStream = await entry
|
||||
.OpenEntryStreamAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await using var entryStreamScope = entryStream
|
||||
.DisposeAsyncScope()
|
||||
.ConfigureAwait(false);
|
||||
await writer
|
||||
.WriteAsync(
|
||||
entry.Key.NotNull("Entry Key is null"),
|
||||
@@ -65,7 +70,12 @@ public partial class TarArchive
|
||||
}
|
||||
else
|
||||
{
|
||||
using var entryStream = entry.OpenEntryStream();
|
||||
var entryStream = await entry
|
||||
.OpenEntryStreamAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await using var entryStreamScope = entryStream
|
||||
.DisposeAsyncScope()
|
||||
.ConfigureAwait(false);
|
||||
await writer
|
||||
.WriteAsync(
|
||||
entry.Key.NotNull("Entry Key is null"),
|
||||
|
||||
@@ -20,7 +20,7 @@ public class TarArchiveEntry : TarEntry, IArchiveEntry
|
||||
|
||||
public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream().NotNull();
|
||||
|
||||
public async ValueTask<Stream> OpenEntryStreamAsync(
|
||||
public virtual async ValueTask<Stream> OpenEntryStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
@@ -82,6 +84,15 @@ internal sealed class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiv
|
||||
return SharpCompressStream.CreateNonDisposing(stream);
|
||||
}
|
||||
|
||||
public override ValueTask<Stream> OpenEntryStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
// Writable entries have no archive parts; opening only rewinds the supplied stream.
|
||||
return new(OpenEntryStream());
|
||||
}
|
||||
|
||||
internal override void Close()
|
||||
{
|
||||
if (closeStream && stream is not null)
|
||||
|
||||
@@ -84,7 +84,7 @@ public partial class ZipArchive
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
using var writer = new ZipWriter(stream, options);
|
||||
await using var writer = new ZipWriter(stream, options);
|
||||
await foreach (
|
||||
var entry in oldEntries.WithCancellation(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
@@ -101,7 +101,12 @@ public partial class ZipArchive
|
||||
}
|
||||
else
|
||||
{
|
||||
using var entryStream = entry.OpenEntryStream();
|
||||
var entryStream = await entry
|
||||
.OpenEntryStreamAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await using var entryStreamScope = entryStream
|
||||
.DisposeAsyncScope()
|
||||
.ConfigureAwait(false);
|
||||
await writer
|
||||
.WriteAsync(
|
||||
entry.Key.NotNull("Entry Key is null"),
|
||||
@@ -125,7 +130,12 @@ public partial class ZipArchive
|
||||
}
|
||||
else
|
||||
{
|
||||
using var entryStream = entry.OpenEntryStream();
|
||||
var entryStream = await entry
|
||||
.OpenEntryStreamAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await using var entryStreamScope = entryStream
|
||||
.DisposeAsyncScope()
|
||||
.ConfigureAwait(false);
|
||||
await writer
|
||||
.WriteAsync(
|
||||
entry.Key.NotNull("Entry Key is null"),
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace SharpCompress.Archives.Zip;
|
||||
|
||||
public partial class ZipArchiveEntry
|
||||
{
|
||||
public async ValueTask<Stream> OpenEntryStreamAsync(
|
||||
public virtual async ValueTask<Stream> OpenEntryStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
@@ -83,6 +85,15 @@ internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry
|
||||
return SharpCompressStream.CreateNonDisposing(stream);
|
||||
}
|
||||
|
||||
public override ValueTask<Stream> OpenEntryStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
// Writable entries have no archive parts; opening only rewinds the supplied stream.
|
||||
return new(OpenEntryStream());
|
||||
}
|
||||
|
||||
internal override void Close()
|
||||
{
|
||||
if (closeStream && !isDisposed && stream is not null)
|
||||
|
||||
@@ -122,11 +122,7 @@ internal partial class MarkHeader
|
||||
{
|
||||
if (!leaveStreamOpen)
|
||||
{
|
||||
#if LEGACY_DOTNET && !NETSTANDARD2_1
|
||||
stream.Dispose();
|
||||
#else
|
||||
await stream.DisposeAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
await stream.DisposeAsyncCompat().ConfigureAwait(false);
|
||||
}
|
||||
throw new InvalidFormatException("Error trying to read rar signature.", e);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.Tar;
|
||||
|
||||
internal class TarReadOnlySubStream : Stream
|
||||
internal class TarReadOnlySubStream : AsyncDisposableStream
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
|
||||
@@ -34,7 +35,6 @@ internal class TarReadOnlySubStream : Stream
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET
|
||||
public override async System.Threading.Tasks.ValueTask DisposeAsync()
|
||||
{
|
||||
if (_isDisposed)
|
||||
@@ -49,7 +49,6 @@ internal class TarReadOnlySubStream : Stream
|
||||
GC.SuppressFinalize(this);
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
private long BytesLeftToRead { get; set; }
|
||||
|
||||
|
||||
@@ -7,12 +7,7 @@ public abstract partial class Volume
|
||||
{
|
||||
public virtual async ValueTask DisposeAsync()
|
||||
{
|
||||
#if LEGACY_DOTNET
|
||||
_actualStream.Dispose();
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
#else
|
||||
await _actualStream.DisposeAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
await _actualStream.DisposeAsyncCompat().ConfigureAwait(false);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ namespace SharpCompress.Common.Zip;
|
||||
|
||||
internal partial class WinzipAesCryptoStream
|
||||
{
|
||||
#if !LEGACY_DOTNET
|
||||
public override async ValueTask DisposeAsync()
|
||||
{
|
||||
if (_isDisposed)
|
||||
@@ -31,11 +30,10 @@ internal partial class WinzipAesCryptoStream
|
||||
_authentication.Dispose();
|
||||
_transform.Dispose();
|
||||
_cipher.Dispose();
|
||||
await _stream.DisposeAsync().ConfigureAwait(false);
|
||||
await _stream.DisposeAsyncCompat().ConfigureAwait(false);
|
||||
}
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
private async ValueTask VerifyAuthenticationAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -44,17 +42,37 @@ internal partial class WinzipAesCryptoStream
|
||||
{
|
||||
return;
|
||||
}
|
||||
_authRead = true;
|
||||
var tag = new byte[10];
|
||||
try
|
||||
{
|
||||
await _stream
|
||||
.ReadExactAsync(tag, 0, tag.Length, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
ValidateAuthentication(tag);
|
||||
while (_authenticationTagBytesRead < _authenticationTag.Length)
|
||||
{
|
||||
var read = await _stream
|
||||
.ReadAsync(
|
||||
_authenticationTag,
|
||||
_authenticationTagBytesRead,
|
||||
_authenticationTag.Length - _authenticationTagBytesRead,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
if (read == 0)
|
||||
{
|
||||
throw new IncompleteArchiveException(
|
||||
"Unexpected end of WinZip AES authentication tag."
|
||||
);
|
||||
}
|
||||
_authenticationTagBytesRead += read;
|
||||
}
|
||||
ValidateAuthentication(_authenticationTag);
|
||||
_authRead = true;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Cancellation is transient; keep the tag prefix so disposal can finish verification.
|
||||
throw;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_authRead = true;
|
||||
_authenticationFailure = ExceptionDispatchInfo.Capture(exception);
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@ using System.Buffers.Binary;
|
||||
using System.IO;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Security.Cryptography;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.Zip;
|
||||
|
||||
internal partial class WinzipAesCryptoStream : Stream
|
||||
internal partial class WinzipAesCryptoStream : AsyncDisposableStream
|
||||
{
|
||||
private const int BLOCK_SIZE_IN_BYTES = 16;
|
||||
private readonly Aes _cipher;
|
||||
@@ -15,6 +16,10 @@ internal partial class WinzipAesCryptoStream : Stream
|
||||
private readonly ICryptoTransform _transform;
|
||||
private readonly HMACSHA1 _authentication;
|
||||
private bool _authRead;
|
||||
|
||||
// Retain tag progress across canceled reads, including a subsequent synchronous disposal.
|
||||
private readonly byte[] _authenticationTag = new byte[10];
|
||||
private int _authenticationTagBytesRead;
|
||||
private ExceptionDispatchInfo? _authenticationFailure;
|
||||
private int _nonce = 1;
|
||||
private byte[] _counterOut = new byte[BLOCK_SIZE_IN_BYTES];
|
||||
@@ -83,7 +88,7 @@ internal partial class WinzipAesCryptoStream : Stream
|
||||
{
|
||||
if (!_authRead)
|
||||
{
|
||||
#if LEGACY_DOTNET
|
||||
#if !STREAM_DISPOSEASYNC
|
||||
// Legacy Stream lacks DisposeAsync, including for async-only inputs.
|
||||
#pragma warning disable VSTHRD002 // Avoid problematic synchronous waits
|
||||
#pragma warning disable CA2012
|
||||
@@ -118,15 +123,33 @@ internal partial class WinzipAesCryptoStream : Stream
|
||||
{
|
||||
return;
|
||||
}
|
||||
_authRead = true;
|
||||
var tag = new byte[10];
|
||||
try
|
||||
{
|
||||
_stream.ReadExact(tag, 0, tag.Length);
|
||||
ValidateAuthentication(tag);
|
||||
while (_authenticationTagBytesRead < _authenticationTag.Length)
|
||||
{
|
||||
var read = _stream.Read(
|
||||
_authenticationTag,
|
||||
_authenticationTagBytesRead,
|
||||
_authenticationTag.Length - _authenticationTagBytesRead
|
||||
);
|
||||
if (read == 0)
|
||||
{
|
||||
throw new IncompleteArchiveException(
|
||||
"Unexpected end of WinZip AES authentication tag."
|
||||
);
|
||||
}
|
||||
_authenticationTagBytesRead += read;
|
||||
}
|
||||
ValidateAuthentication(_authenticationTag);
|
||||
_authRead = true;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_authRead = true;
|
||||
_authenticationFailure = ExceptionDispatchInfo.Capture(exception);
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ public sealed partial class BZip2Stream : IAsyncDisposable
|
||||
CancellationToken cancellationToken = default
|
||||
) => await stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public async ValueTask DisposeAsync()
|
||||
@@ -136,7 +136,7 @@ public sealed partial class BZip2Stream : IAsyncDisposable
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
#else
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
|
||||
@@ -707,7 +707,7 @@ internal partial class CBZip2InputStream
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupNoRandPartA();
|
||||
await SetupNoRandPartAAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,7 +792,7 @@ internal partial class CBZip2InputStream
|
||||
z ^= (char)((rNToGo == 1) ? 1 : 0);
|
||||
j2 = 0;
|
||||
currentState = RAND_PART_C_STATE;
|
||||
SetupRandPartC();
|
||||
await SetupRandPartCAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -670,7 +670,7 @@ internal sealed partial class CBZip2OutputStream : IAsyncDisposable
|
||||
await bsStream.FlushAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public async ValueTask DisposeAsync()
|
||||
@@ -696,7 +696,7 @@ internal sealed partial class CBZip2OutputStream : IAsyncDisposable
|
||||
}
|
||||
bsStream = null;
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
#else
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace SharpCompress.Compressors.Deflate;
|
||||
|
||||
public partial class DeflateStream
|
||||
{
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public async ValueTask DisposeAsync()
|
||||
@@ -22,7 +22,7 @@ public partial class DeflateStream
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
#else
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
|
||||
@@ -183,7 +183,7 @@ public partial class GZipStream
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public async ValueTask DisposeAsync()
|
||||
@@ -200,7 +200,7 @@ public partial class GZipStream
|
||||
await BaseStream.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -510,7 +510,7 @@ internal partial class ZlibBaseStream : Stream, IStreamStack
|
||||
}
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public async ValueTask DisposeAsync()
|
||||
@@ -521,7 +521,7 @@ internal partial class ZlibBaseStream : Stream, IStreamStack
|
||||
return;
|
||||
}
|
||||
isDisposed = true;
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
if (_stream is null)
|
||||
|
||||
@@ -21,8 +21,11 @@ public partial class ZlibStream
|
||||
await _baseStream.FlushAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET
|
||||
#if STREAM_DISPOSEASYNC
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public virtual async ValueTask DisposeAsync()
|
||||
#endif
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
@@ -33,9 +36,13 @@ public partial class ZlibStream
|
||||
{
|
||||
await _baseStream.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
#if STREAM_DISPOSEASYNC
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
#else
|
||||
base.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read data from the stream.
|
||||
|
||||
@@ -33,6 +33,9 @@ using SharpCompress.Common;
|
||||
namespace SharpCompress.Compressors.Deflate;
|
||||
|
||||
public partial class ZlibStream : Stream
|
||||
#if !STREAM_DISPOSEASYNC
|
||||
, IAsyncDisposable
|
||||
#endif
|
||||
{
|
||||
private readonly ZlibBaseStream _baseStream;
|
||||
private bool _disposed;
|
||||
|
||||
@@ -200,7 +200,7 @@ internal sealed class Lzma2EncoderStream : Stream
|
||||
|
||||
private static readonly byte[] _endMarker = [0x00];
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public async ValueTask DisposeAsync()
|
||||
@@ -229,7 +229,7 @@ internal sealed class Lzma2EncoderStream : Stream
|
||||
}
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -454,7 +454,7 @@ public partial class LzmaStream
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public async ValueTask DisposeAsync()
|
||||
@@ -494,7 +494,7 @@ public partial class LzmaStream
|
||||
}
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
@@ -160,11 +160,7 @@ public class PpmdStream : Stream, IAsyncDisposable
|
||||
}
|
||||
catch
|
||||
{
|
||||
#if LEGACY_DOTNET && !NETSTANDARD2_1
|
||||
instance.Dispose();
|
||||
#else
|
||||
await instance.DisposeAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -196,7 +192,7 @@ public class PpmdStream : Stream, IAsyncDisposable
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public async ValueTask DisposeAsync()
|
||||
@@ -215,7 +211,7 @@ public class PpmdStream : Stream, IAsyncDisposable
|
||||
_modelH?.Dispose();
|
||||
_modelH = null;
|
||||
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -36,7 +36,9 @@ public partial class XZFooter
|
||||
using (var reader = new BinaryReader(stream))
|
||||
{
|
||||
BackwardSize = (reader.ReadLittleEndianUInt32() + 1) * 4;
|
||||
StreamFlags = reader.ReadBytes(2);
|
||||
StreamFlags = await reader
|
||||
.ReadBytesAsync(2, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
var magBy = await _reader.ReadBytesAsync(2, cancellationToken).ConfigureAwait(false);
|
||||
if (!magBy.AsSpan().SequenceEqual(_magicBytes))
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace SharpCompress.Compressors.ZStandard;
|
||||
|
||||
public partial class CompressionStream
|
||||
{
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
#if STREAM_DISPOSEASYNC
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public async ValueTask DisposeAsync()
|
||||
@@ -16,7 +16,7 @@ public partial class CompressionStream
|
||||
{
|
||||
if (compressor == null)
|
||||
{
|
||||
#if LEGACY_DOTNET
|
||||
#if !STREAM_DISPOSEASYNC
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
@@ -35,7 +35,7 @@ public partial class CompressionStream
|
||||
ReleaseUnmanagedResources();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
#if LEGACY_DOTNET
|
||||
#if !STREAM_DISPOSEASYNC
|
||||
Dispose(true);
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
#else
|
||||
|
||||
@@ -203,7 +203,7 @@ public partial class DecompressionStream : Stream
|
||||
}
|
||||
}
|
||||
|
||||
#if LEGACY_DOTNET && !NETSTANDARD2_1
|
||||
#if !STREAM_DISPOSEASYNC
|
||||
public virtual ValueTask DisposeAsync()
|
||||
{
|
||||
try
|
||||
|
||||
@@ -22,11 +22,11 @@ namespace SharpCompress.IO;
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public abstract class AsyncDisposableStream : Stream
|
||||
#if NO_STREAM_DISPOSEASYNC
|
||||
#if !STREAM_DISPOSEASYNC
|
||||
, IAsyncDisposable
|
||||
#endif
|
||||
{
|
||||
#if NO_STREAM_DISPOSEASYNC
|
||||
#if !STREAM_DISPOSEASYNC
|
||||
public virtual ValueTask DisposeAsync()
|
||||
{
|
||||
Dispose();
|
||||
|
||||
@@ -45,14 +45,12 @@ internal sealed partial class ProgressReportingStream
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !LEGACY_DOTNET
|
||||
public override async ValueTask DisposeAsync()
|
||||
{
|
||||
if (!_leaveOpen)
|
||||
{
|
||||
await _baseStream.DisposeAsync().ConfigureAwait(false);
|
||||
await _baseStream.DisposeAsyncCompat().ConfigureAwait(false);
|
||||
}
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace SharpCompress.IO;
|
||||
/// A stream wrapper that reports progress as data is read from the source.
|
||||
/// Used to track compression or extraction progress by wrapping the source stream.
|
||||
/// </summary>
|
||||
internal sealed partial class ProgressReportingStream : Stream
|
||||
internal sealed partial class ProgressReportingStream : AsyncDisposableStream
|
||||
{
|
||||
private readonly Stream _baseStream;
|
||||
private readonly IProgress<ProgressReport> _progress;
|
||||
|
||||
@@ -28,12 +28,14 @@ internal sealed partial class SeekableSharpCompressStream
|
||||
ReadOnlyMemory<byte> buffer,
|
||||
CancellationToken cancellationToken = default
|
||||
) => _stream.WriteAsync(buffer, cancellationToken);
|
||||
#endif
|
||||
|
||||
public override ValueTask DisposeAsync()
|
||||
public override async ValueTask DisposeAsync()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return base.DisposeAsync();
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (ThrowOnDispose)
|
||||
{
|
||||
@@ -44,11 +46,10 @@ internal sealed partial class SeekableSharpCompressStream
|
||||
_isDisposed = true;
|
||||
if (!LeaveStreamOpen)
|
||||
{
|
||||
_stream.Dispose();
|
||||
await _stream.DisposeAsyncCompat().ConfigureAwait(false);
|
||||
}
|
||||
return base.DisposeAsync();
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override Task WriteAsync(
|
||||
|
||||
@@ -251,8 +251,11 @@ public partial class SharpCompressStream
|
||||
}
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET
|
||||
#if STREAM_DISPOSEASYNC
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public virtual async ValueTask DisposeAsync()
|
||||
#endif
|
||||
{
|
||||
if (!isDisposed)
|
||||
{
|
||||
@@ -267,7 +270,7 @@ public partial class SharpCompressStream
|
||||
{
|
||||
if (!LeaveStreamOpen)
|
||||
{
|
||||
await stream.DisposeAsync().ConfigureAwait(false);
|
||||
await stream.DisposeAsyncCompat().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -276,7 +279,11 @@ public partial class SharpCompressStream
|
||||
_ringBuffer = null;
|
||||
}
|
||||
}
|
||||
#if STREAM_DISPOSEASYNC
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
#else
|
||||
base.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace SharpCompress.IO;
|
||||
/// stream and usage scenario.
|
||||
/// </remarks>
|
||||
public partial class SharpCompressStream : Stream, IStreamStack
|
||||
#if !STREAM_DISPOSEASYNC
|
||||
, IAsyncDisposable
|
||||
#endif
|
||||
{
|
||||
public virtual Stream BaseStream() => stream;
|
||||
|
||||
|
||||
@@ -45,7 +45,8 @@ public static class IAsyncReaderExtensions
|
||||
options,
|
||||
async (x, fm, ct) =>
|
||||
{
|
||||
using var fs = File.Open(x, fm);
|
||||
var fs = File.Open(x, fm);
|
||||
await using var scope = fs.DisposeAsyncScope().ConfigureAwait(false);
|
||||
await CopyEntryToAsync(reader, fs, options, ct).ConfigureAwait(false);
|
||||
},
|
||||
cancellationToken
|
||||
@@ -83,7 +84,8 @@ public static class IAsyncReaderExtensions
|
||||
options,
|
||||
async (x, fm, ct) =>
|
||||
{
|
||||
using var fs = File.Open(x, fm);
|
||||
var fs = File.Open(x, fm);
|
||||
await using var scope = fs.DisposeAsyncScope().ConfigureAwait(false);
|
||||
await CopyEntryToAsync(reader, fs, options, ct).ConfigureAwait(false);
|
||||
},
|
||||
cancellationToken
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net48' Or '$(TargetFramework)' == 'netstandard2.0' Or '$(TargetFramework)' == 'netstandard2.1' ">
|
||||
<DefineConstants>$(DefineConstants);LEGACY_DOTNET</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net48' Or '$(TargetFramework)' == 'netstandard2.0'">
|
||||
<DefineConstants>$(DefineConstants);NO_STREAM_DISPOSEASYNC</DefineConstants>
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.1' Or '$(TargetFramework)' == 'net6.0' Or '$(TargetFramework)' == 'net8.0' Or '$(TargetFramework)' == 'net10.0' ">
|
||||
<DefineConstants>$(DefineConstants);STREAM_DISPOSEASYNC</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net8.0' Or '$(TargetFramework)' == 'net10.0' ">
|
||||
<IsTrimmable>true</IsTrimmable>
|
||||
|
||||
@@ -70,7 +70,8 @@ internal static partial class Utility
|
||||
)
|
||||
{
|
||||
// Use ReadOnlySubStream to limit reading and leverage framework's CopyToAsync
|
||||
using var limitedStream = new IO.ReadOnlySubStream(source, maxLength);
|
||||
var limitedStream = new IO.ReadOnlySubStream(source, maxLength);
|
||||
await using var scope = limitedStream.DisposeAsyncScope().ConfigureAwait(false);
|
||||
await limitedStream
|
||||
.CopyToAsync(destination, bufferSize ?? Constants.BufferSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -77,7 +77,8 @@ public static class IWriterExtensions
|
||||
{
|
||||
throw new ArgumentException("Source does not exist: " + source.FullName);
|
||||
}
|
||||
using var stream = source.OpenRead();
|
||||
var stream = source.OpenRead();
|
||||
await using var scope = stream.DisposeAsyncScope().ConfigureAwait(false);
|
||||
await writer
|
||||
.WriteAsync(entryPath, stream, source.LastWriteTime, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -33,9 +33,9 @@
|
||||
},
|
||||
"Microsoft.VisualStudio.Threading.Analyzers": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.14.15, )",
|
||||
"resolved": "17.14.15",
|
||||
"contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
|
||||
"requested": "[18.12.1, )",
|
||||
"resolved": "18.12.1",
|
||||
"contentHash": "sQt7NpnselT1gP1a7bTfhmfHYV0jbavst/8mOoWTMSjXhXzWPssqgBoIwrxNsgJUa7XQzD2raSRMAFfmlepxNw=="
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
@@ -45,19 +45,20 @@
|
||||
},
|
||||
"System.Text.Encoding.CodePages": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==",
|
||||
"requested": "[10.0.12, )",
|
||||
"resolved": "10.0.12",
|
||||
"contentHash": "rt1G/LdKC6oc3xPyQhMn5vRTp9iTTt1BS9Dx/67TpW9KWgFJ39lyEz0y4CbDksx7iTZEfgG61UsQMoGEXEpF4A==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.5",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
"System.Memory": "4.6.3",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.1.2",
|
||||
"System.ValueTuple": "4.6.2"
|
||||
}
|
||||
},
|
||||
"Zomp.SyncMethodGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.56, )",
|
||||
"resolved": "2.0.56",
|
||||
"contentHash": "P1iMA1meu0uX8YcPWhkFnpzV3e+QFDDYMU6hMNyofS+pBlLgeVV7QevBmJmJ/mrxA1jujo3cqNaO1IapdfjOlA=="
|
||||
"requested": "[2.0.66, )",
|
||||
"resolved": "2.0.66",
|
||||
"contentHash": "iYnF185851PEX5vnxrhUj2av30HoxvjUlPd0HVVuSAif7TCgc/Noc5xVf9jiLhMlI8Rt9QrJdef3KB8+opAJQA=="
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
@@ -118,6 +119,11 @@
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||
}
|
||||
},
|
||||
"System.ValueTuple": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.6.2",
|
||||
"contentHash": "yQgmjfFximrNm9LIV3mL6T5MzjeC+epeE5rl4hXxAlYmxby7RM1dPSkIKXk9HNkl6G54h2JHOmLD46+Pey+IRg=="
|
||||
}
|
||||
},
|
||||
".NETStandard,Version=v2.0": {
|
||||
@@ -152,9 +158,9 @@
|
||||
},
|
||||
"Microsoft.VisualStudio.Threading.Analyzers": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.14.15, )",
|
||||
"resolved": "17.14.15",
|
||||
"contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
|
||||
"requested": "[18.12.1, )",
|
||||
"resolved": "18.12.1",
|
||||
"contentHash": "sQt7NpnselT1gP1a7bTfhmfHYV0jbavst/8mOoWTMSjXhXzWPssqgBoIwrxNsgJUa7XQzD2raSRMAFfmlepxNw=="
|
||||
},
|
||||
"NETStandard.Library": {
|
||||
"type": "Direct",
|
||||
@@ -173,19 +179,19 @@
|
||||
},
|
||||
"System.Text.Encoding.CodePages": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==",
|
||||
"requested": "[10.0.12, )",
|
||||
"resolved": "10.0.12",
|
||||
"contentHash": "rt1G/LdKC6oc3xPyQhMn5vRTp9iTTt1BS9Dx/67TpW9KWgFJ39lyEz0y4CbDksx7iTZEfgG61UsQMoGEXEpF4A==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.5",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
"System.Memory": "4.6.3",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.1.2"
|
||||
}
|
||||
},
|
||||
"Zomp.SyncMethodGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.56, )",
|
||||
"resolved": "2.0.56",
|
||||
"contentHash": "P1iMA1meu0uX8YcPWhkFnpzV3e+QFDDYMU6hMNyofS+pBlLgeVV7QevBmJmJ/mrxA1jujo3cqNaO1IapdfjOlA=="
|
||||
"requested": "[2.0.66, )",
|
||||
"resolved": "2.0.66",
|
||||
"contentHash": "iYnF185851PEX5vnxrhUj2av30HoxvjUlPd0HVVuSAif7TCgc/Noc5xVf9jiLhMlI8Rt9QrJdef3KB8+opAJQA=="
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
@@ -282,9 +288,9 @@
|
||||
},
|
||||
"Microsoft.VisualStudio.Threading.Analyzers": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.14.15, )",
|
||||
"resolved": "17.14.15",
|
||||
"contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
|
||||
"requested": "[18.12.1, )",
|
||||
"resolved": "18.12.1",
|
||||
"contentHash": "sQt7NpnselT1gP1a7bTfhmfHYV0jbavst/8mOoWTMSjXhXzWPssqgBoIwrxNsgJUa7XQzD2raSRMAFfmlepxNw=="
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
@@ -294,18 +300,18 @@
|
||||
},
|
||||
"System.Text.Encoding.CodePages": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==",
|
||||
"requested": "[10.0.12, )",
|
||||
"resolved": "10.0.12",
|
||||
"contentHash": "rt1G/LdKC6oc3xPyQhMn5vRTp9iTTt1BS9Dx/67TpW9KWgFJ39lyEz0y4CbDksx7iTZEfgG61UsQMoGEXEpF4A==",
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.1.2"
|
||||
}
|
||||
},
|
||||
"Zomp.SyncMethodGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.56, )",
|
||||
"resolved": "2.0.56",
|
||||
"contentHash": "P1iMA1meu0uX8YcPWhkFnpzV3e+QFDDYMU6hMNyofS+pBlLgeVV7QevBmJmJ/mrxA1jujo3cqNaO1IapdfjOlA=="
|
||||
"requested": "[2.0.66, )",
|
||||
"resolved": "2.0.66",
|
||||
"contentHash": "iYnF185851PEX5vnxrhUj2av30HoxvjUlPd0HVVuSAif7TCgc/Noc5xVf9jiLhMlI8Rt9QrJdef3KB8+opAJQA=="
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
@@ -332,8 +338,8 @@
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
|
||||
"resolved": "6.1.2",
|
||||
"contentHash": "2hBr6zdbIBTDE3EhK7NSVNdX58uTK6iHW/P/Axmm9sl1xoGSLqDvMtpecn226TNwHByFokYwJmt/aQQNlO5CRw=="
|
||||
}
|
||||
},
|
||||
"net10.0": {
|
||||
@@ -365,9 +371,9 @@
|
||||
},
|
||||
"Microsoft.VisualStudio.Threading.Analyzers": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.14.15, )",
|
||||
"resolved": "17.14.15",
|
||||
"contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
|
||||
"requested": "[18.12.1, )",
|
||||
"resolved": "18.12.1",
|
||||
"contentHash": "sQt7NpnselT1gP1a7bTfhmfHYV0jbavst/8mOoWTMSjXhXzWPssqgBoIwrxNsgJUa7XQzD2raSRMAFfmlepxNw=="
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
@@ -377,9 +383,9 @@
|
||||
},
|
||||
"Zomp.SyncMethodGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.56, )",
|
||||
"resolved": "2.0.56",
|
||||
"contentHash": "P1iMA1meu0uX8YcPWhkFnpzV3e+QFDDYMU6hMNyofS+pBlLgeVV7QevBmJmJ/mrxA1jujo3cqNaO1IapdfjOlA=="
|
||||
"requested": "[2.0.66, )",
|
||||
"resolved": "2.0.66",
|
||||
"contentHash": "iYnF185851PEX5vnxrhUj2av30HoxvjUlPd0HVVuSAif7TCgc/Noc5xVf9jiLhMlI8Rt9QrJdef3KB8+opAJQA=="
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
@@ -428,9 +434,9 @@
|
||||
},
|
||||
"Microsoft.VisualStudio.Threading.Analyzers": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.14.15, )",
|
||||
"resolved": "17.14.15",
|
||||
"contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
|
||||
"requested": "[18.12.1, )",
|
||||
"resolved": "18.12.1",
|
||||
"contentHash": "sQt7NpnselT1gP1a7bTfhmfHYV0jbavst/8mOoWTMSjXhXzWPssqgBoIwrxNsgJUa7XQzD2raSRMAFfmlepxNw=="
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
@@ -440,9 +446,9 @@
|
||||
},
|
||||
"Zomp.SyncMethodGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.56, )",
|
||||
"resolved": "2.0.56",
|
||||
"contentHash": "P1iMA1meu0uX8YcPWhkFnpzV3e+QFDDYMU6hMNyofS+pBlLgeVV7QevBmJmJ/mrxA1jujo3cqNaO1IapdfjOlA=="
|
||||
"requested": "[2.0.66, )",
|
||||
"resolved": "2.0.66",
|
||||
"contentHash": "iYnF185851PEX5vnxrhUj2av30HoxvjUlPd0HVVuSAif7TCgc/Noc5xVf9jiLhMlI8Rt9QrJdef3KB8+opAJQA=="
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
@@ -497,9 +503,9 @@
|
||||
},
|
||||
"Microsoft.VisualStudio.Threading.Analyzers": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.14.15, )",
|
||||
"resolved": "17.14.15",
|
||||
"contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
|
||||
"requested": "[18.12.1, )",
|
||||
"resolved": "18.12.1",
|
||||
"contentHash": "sQt7NpnselT1gP1a7bTfhmfHYV0jbavst/8mOoWTMSjXhXzWPssqgBoIwrxNsgJUa7XQzD2raSRMAFfmlepxNw=="
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
@@ -509,9 +515,9 @@
|
||||
},
|
||||
"Zomp.SyncMethodGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.56, )",
|
||||
"resolved": "2.0.56",
|
||||
"contentHash": "P1iMA1meu0uX8YcPWhkFnpzV3e+QFDDYMU6hMNyofS+pBlLgeVV7QevBmJmJ/mrxA1jujo3cqNaO1IapdfjOlA=="
|
||||
"requested": "[2.0.66, )",
|
||||
"resolved": "2.0.66",
|
||||
"contentHash": "iYnF185851PEX5vnxrhUj2av30HoxvjUlPd0HVVuSAif7TCgc/Noc5xVf9jiLhMlI8Rt9QrJdef3KB8+opAJQA=="
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
|
||||
@@ -36,9 +36,9 @@
|
||||
},
|
||||
"Microsoft.VisualStudio.Threading.Analyzers": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.14.15, )",
|
||||
"resolved": "17.14.15",
|
||||
"contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
|
||||
"requested": "[18.12.1, )",
|
||||
"resolved": "18.12.1",
|
||||
"contentHash": "sQt7NpnselT1gP1a7bTfhmfHYV0jbavst/8mOoWTMSjXhXzWPssqgBoIwrxNsgJUa7XQzD2raSRMAFfmlepxNw=="
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
@@ -48,9 +48,9 @@
|
||||
},
|
||||
"Zomp.SyncMethodGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.56, )",
|
||||
"resolved": "2.0.56",
|
||||
"contentHash": "P1iMA1meu0uX8YcPWhkFnpzV3e+QFDDYMU6hMNyofS+pBlLgeVV7QevBmJmJ/mrxA1jujo3cqNaO1IapdfjOlA=="
|
||||
"requested": "[2.0.66, )",
|
||||
"resolved": "2.0.66",
|
||||
"contentHash": "iYnF185851PEX5vnxrhUj2av30HoxvjUlPd0HVVuSAif7TCgc/Noc5xVf9jiLhMlI8Rt9QrJdef3KB8+opAJQA=="
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
|
||||
@@ -52,9 +52,9 @@
|
||||
},
|
||||
"Microsoft.VisualStudio.Threading.Analyzers": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.14.15, )",
|
||||
"resolved": "17.14.15",
|
||||
"contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
|
||||
"requested": "[18.12.1, )",
|
||||
"resolved": "18.12.1",
|
||||
"contentHash": "sQt7NpnselT1gP1a7bTfhmfHYV0jbavst/8mOoWTMSjXhXzWPssqgBoIwrxNsgJUa7XQzD2raSRMAFfmlepxNw=="
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
@@ -64,9 +64,9 @@
|
||||
},
|
||||
"Zomp.SyncMethodGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.56, )",
|
||||
"resolved": "2.0.56",
|
||||
"contentHash": "P1iMA1meu0uX8YcPWhkFnpzV3e+QFDDYMU6hMNyofS+pBlLgeVV7QevBmJmJ/mrxA1jujo3cqNaO1IapdfjOlA=="
|
||||
"requested": "[2.0.66, )",
|
||||
"resolved": "2.0.66",
|
||||
"contentHash": "iYnF185851PEX5vnxrhUj2av30HoxvjUlPd0HVVuSAif7TCgc/Noc5xVf9jiLhMlI8Rt9QrJdef3KB8+opAJQA=="
|
||||
},
|
||||
"BenchmarkDotNet.Annotations": {
|
||||
"type": "Transitive",
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net10.0' ">
|
||||
<DefineConstants>$(DefineConstants);STREAM_DISPOSEASYNC</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))">
|
||||
<DefineConstants>$(DefineConstants);WINDOWS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Streams;
|
||||
|
||||
public class AsyncDisposalCompatibilityTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async ValueTask SharpCompressStream_Forwards_Async_Disposal(bool seekable)
|
||||
{
|
||||
var source = new AsyncDisposeOnlyStream(seekable);
|
||||
var wrapper = SharpCompressStream.Create(source, 128);
|
||||
await ((IAsyncDisposable)wrapper).DisposeAsync().ConfigureAwait(false);
|
||||
Assert.True(source.AsyncDisposed);
|
||||
await ((IAsyncDisposable)wrapper).DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask Stream_Disposal_Scope_Uses_Runtime_Async_Disposable()
|
||||
{
|
||||
var source = new AsyncDisposeOnlyStream(true);
|
||||
Stream stream = source;
|
||||
await using (stream.DisposeAsyncScope().ConfigureAwait(false)) { }
|
||||
Assert.True(source.AsyncDisposed);
|
||||
}
|
||||
|
||||
private sealed class AsyncDisposeOnlyStream(bool seekable) : AsyncOnlyStream(new MemoryStream())
|
||||
{
|
||||
public override bool CanSeek => seekable;
|
||||
public bool AsyncDisposed { get; private set; }
|
||||
|
||||
public override ValueTask DisposeAsync()
|
||||
{
|
||||
AsyncDisposed = true;
|
||||
return base.DisposeAsync();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && !AsyncDisposed)
|
||||
{
|
||||
throw new NotSupportedException("Synchronous disposal is not supported.");
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ public class BufferPoolLifetimeTests
|
||||
stream.Dispose();
|
||||
}
|
||||
stream.Dispose();
|
||||
#if !LEGACY_DOTNET
|
||||
#if STREAM_DISPOSEASYNC
|
||||
await stream.DisposeAsync();
|
||||
#else
|
||||
await Task.CompletedTask;
|
||||
|
||||
@@ -25,7 +25,7 @@ public class SharpCompressLifetimeTests
|
||||
Assert.NotNull(ring.GetValue(stream));
|
||||
if (asyncDispose)
|
||||
{
|
||||
#if !LEGACY_DOTNET
|
||||
#if STREAM_DISPOSEASYNC
|
||||
await Assert.ThrowsAsync<IOException>(async () => await stream.DisposeAsync());
|
||||
#else
|
||||
Assert.Throws<IOException>(() => stream.Dispose());
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace SharpCompress.Test.Streams;
|
||||
|
||||
public class SharpCompressStreamEdgeAsyncTest
|
||||
{
|
||||
#if !LEGACY_DOTNET
|
||||
#if STREAM_DISPOSEASYNC
|
||||
|
||||
[Fact]
|
||||
public async ValueTask DisposeAsync_WithLeaveStreamOpenTrue_DoesNotDisposeUnderlying()
|
||||
|
||||
@@ -49,7 +49,7 @@ public class SharpCompressStreamErrorAsyncTest
|
||||
}
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET
|
||||
#if STREAM_DISPOSEASYNC
|
||||
[Fact]
|
||||
public async ValueTask DisposeAsync_WithThrowOnDisposeTrue_ThrowsInvalidOperation()
|
||||
{
|
||||
|
||||
@@ -84,7 +84,7 @@ public class SharpCompressStreamPassthroughAsyncTest
|
||||
Assert.Equal(3, ms.Length);
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET
|
||||
#if STREAM_DISPOSEASYNC
|
||||
[Fact]
|
||||
public async ValueTask CreateNonDisposing_DoesNotDisposeUnderlying_Async()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -14,6 +15,120 @@ namespace SharpCompress.Test.Streams;
|
||||
|
||||
public class WinzipAesCryptoStreamTests
|
||||
{
|
||||
public static IEnumerable<object[]> AuthenticationCancellationCases()
|
||||
{
|
||||
foreach (var length in new[] { 0, 33 })
|
||||
{
|
||||
foreach (var tagBytesRead in new[] { 0, 4 })
|
||||
{
|
||||
foreach (var corruption in new[] { "none", "tag", "missing-tag" })
|
||||
{
|
||||
foreach (var completion in new[] { "dispose", "retry", "dispose-async" })
|
||||
{
|
||||
yield return [length, tagBytesRead, corruption, completion];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(AuthenticationCancellationCases))]
|
||||
public async Task Authentication_Resumes_After_Cancelled_Tag_Read(
|
||||
int length,
|
||||
int tagBytesRead,
|
||||
string corruption,
|
||||
string completion
|
||||
)
|
||||
{
|
||||
byte[] salt = [0x10, 0x21, 0x32, 0x43, 0x54, 0x65, 0x76, 0x87];
|
||||
var data = CreateEncryptionData("password", salt);
|
||||
var ciphertext = EncryptCtr(new byte[length], data.KeyBytes);
|
||||
#pragma warning disable CA5350 // WinZip AES mandates HMAC-SHA1-80.
|
||||
using var authentication = new HMACSHA1(data.IvBytes);
|
||||
#pragma warning restore CA5350
|
||||
var bytes = ciphertext.Concat(authentication.ComputeHash(ciphertext).Take(10)).ToArray();
|
||||
if (corruption == "tag")
|
||||
{
|
||||
// Corrupt the prefix, which must survive cancellation and be verified on retry.
|
||||
bytes[length] ^= 1;
|
||||
}
|
||||
else if (corruption == "missing-tag")
|
||||
{
|
||||
bytes = bytes.Take(bytes.Length - 1).ToArray();
|
||||
}
|
||||
using var cancellation = new CancellationTokenSource();
|
||||
using var input = new CancelTagReadStream(bytes, length + tagBytesRead, cancellation);
|
||||
using var stream = new WinzipAesCryptoStream(input, data, length);
|
||||
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () =>
|
||||
await stream.ReadAsync(
|
||||
new byte[Math.Max(1, length)],
|
||||
0,
|
||||
Math.Max(1, length),
|
||||
cancellation.Token
|
||||
)
|
||||
);
|
||||
Assert.Equal(length + tagBytesRead, input.Position);
|
||||
|
||||
var error = await Record.ExceptionAsync(async () =>
|
||||
{
|
||||
if (completion == "dispose")
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
else if (completion == "dispose-async")
|
||||
{
|
||||
await stream.DisposeAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal(0, await stream.ReadAsync(new byte[1], 0, 1, CancellationToken.None));
|
||||
}
|
||||
});
|
||||
if (corruption == "none")
|
||||
{
|
||||
Assert.Null(error);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal(
|
||||
corruption == "tag"
|
||||
? typeof(SharpCompress.Common.InvalidFormatException)
|
||||
: typeof(SharpCompress.Common.IncompleteArchiveException),
|
||||
error?.GetType()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class CancelTagReadStream(
|
||||
byte[] bytes,
|
||||
int cancelPosition,
|
||||
CancellationTokenSource cancellation
|
||||
) : MemoryStream(bytes)
|
||||
{
|
||||
private bool cancelled;
|
||||
|
||||
public override Task<int> ReadAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
int count,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
if (!cancelled)
|
||||
{
|
||||
if (Position == cancelPosition)
|
||||
{
|
||||
cancelled = true;
|
||||
cancellation.Cancel();
|
||||
return Task.FromCanceled<int>(cancellation.Token);
|
||||
}
|
||||
count = Math.Min(count, (int)(cancelPosition - Position));
|
||||
}
|
||||
return base.ReadAsync(buffer, offset, count, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dispose_Verifies_Unread_Ciphertext()
|
||||
{
|
||||
@@ -30,7 +145,6 @@ public class WinzipAesCryptoStreamTests
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET
|
||||
[Fact]
|
||||
public async Task DisposeAsync_Verifies_Unread_Ciphertext()
|
||||
{
|
||||
@@ -48,7 +162,6 @@ public class WinzipAesCryptoStreamTests
|
||||
);
|
||||
await stream.DisposeAsync();
|
||||
}
|
||||
#endif
|
||||
|
||||
[Theory]
|
||||
[InlineData(false, 0)]
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Tar;
|
||||
@@ -229,6 +230,89 @@ public class TarArchiveAsyncTests : ArchiveTests
|
||||
Assert.True(entryStream.IsDisposed);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async ValueTask Tar_New_Entry_OpenEntryStreamAsync_Rewinds_And_Preserves_Ownership(
|
||||
bool closeStream
|
||||
)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes("test");
|
||||
using var source = new TestStream(new MemoryStream(bytes));
|
||||
await using (var archive = await TarArchive.CreateAsyncArchive())
|
||||
{
|
||||
IArchiveEntry entry = await archive.AddEntryAsync(
|
||||
"test.txt",
|
||||
source,
|
||||
closeStream: closeStream,
|
||||
size: source.Length
|
||||
);
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
source.Position = source.Length;
|
||||
using (var opened = await entry.OpenEntryStreamAsync(CancellationToken.None))
|
||||
{
|
||||
using var destination = new MemoryStream();
|
||||
await opened.CopyToAsync(destination, 81920, CancellationToken.None);
|
||||
Assert.Equal(bytes, destination.ToArray());
|
||||
}
|
||||
Assert.False(source.IsDisposed);
|
||||
}
|
||||
}
|
||||
Assert.Equal(closeStream, source.IsDisposed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask Tar_New_Entry_OpenEntryStreamAsync_Cancelled_Does_Not_Rewind()
|
||||
{
|
||||
using var source = new MemoryStream(Encoding.UTF8.GetBytes("test"));
|
||||
await using var archive = await TarArchive.CreateAsyncArchive();
|
||||
var entry = await archive.AddEntryAsync("test.txt", source, size: source.Length);
|
||||
source.Position = source.Length;
|
||||
using var cancellation = new CancellationTokenSource();
|
||||
cancellation.Cancel();
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () =>
|
||||
await entry.OpenEntryStreamAsync(cancellation.Token)
|
||||
);
|
||||
Assert.Equal(source.Length, source.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask Tar_New_Directory_OpenEntryStreamAsync()
|
||||
{
|
||||
await using var archive = await TarArchive.CreateAsyncArchive();
|
||||
var entry = await archive.AddDirectoryEntryAsync("directory");
|
||||
using var opened = await entry.OpenEntryStreamAsync(CancellationToken.None);
|
||||
Assert.Equal(0, opened.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask Tar_Save_New_Entry_Async_Only_Streams()
|
||||
{
|
||||
using var source = new AsyncOnlyStream(new MemoryStream(Encoding.UTF8.GetBytes("test")));
|
||||
using var destination = new MemoryStream();
|
||||
using var output = new AsyncOnlyStream(destination, disposeStream: false);
|
||||
await using (var archive = await TarArchive.CreateAsyncArchive())
|
||||
{
|
||||
await archive.AddEntryAsync("test.txt", source, size: source.Length);
|
||||
await archive.SaveToAsync(
|
||||
output,
|
||||
new TarWriterOptions(CompressionType.None, finalizeArchiveOnClose: true)
|
||||
{
|
||||
LeaveStreamOpen = true,
|
||||
},
|
||||
CancellationToken.None
|
||||
);
|
||||
}
|
||||
destination.Position = 0;
|
||||
await using var reopened = await TarArchive.OpenAsyncArchive(destination);
|
||||
var entry = await reopened.EntriesAsync.SingleAsync();
|
||||
var stream = await entry.OpenEntryStreamAsync(CancellationToken.None);
|
||||
await using var scope = stream.DisposeAsyncScope().ConfigureAwait(false);
|
||||
using var reader = new StreamReader(stream);
|
||||
Assert.Equal("test", await reader.ReadToEndAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask Tar_Random_Write_Add_Async()
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress;
|
||||
using SharpCompress.Archives;
|
||||
@@ -208,6 +209,86 @@ public class ZipArchiveAsyncTests : ArchiveTests
|
||||
Assert.True(entryStream.IsDisposed);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async ValueTask Zip_New_Entry_OpenEntryStreamAsync_Rewinds_And_Preserves_Ownership(
|
||||
bool closeStream
|
||||
)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes("test");
|
||||
using var source = new TestStream(new MemoryStream(bytes));
|
||||
await using (var archive = await ZipArchive.CreateAsyncArchive())
|
||||
{
|
||||
IArchiveEntry entry = await archive.AddEntryAsync(
|
||||
"test.txt",
|
||||
source,
|
||||
closeStream: closeStream,
|
||||
size: source.Length
|
||||
);
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
source.Position = source.Length;
|
||||
using (var opened = await entry.OpenEntryStreamAsync(CancellationToken.None))
|
||||
{
|
||||
using var destination = new MemoryStream();
|
||||
await opened.CopyToAsync(destination, 81920, CancellationToken.None);
|
||||
Assert.Equal(bytes, destination.ToArray());
|
||||
}
|
||||
Assert.False(source.IsDisposed);
|
||||
}
|
||||
}
|
||||
Assert.Equal(closeStream, source.IsDisposed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask Zip_New_Entry_OpenEntryStreamAsync_Cancelled_Does_Not_Rewind()
|
||||
{
|
||||
using var source = new MemoryStream(Encoding.UTF8.GetBytes("test"));
|
||||
await using var archive = await ZipArchive.CreateAsyncArchive();
|
||||
var entry = await archive.AddEntryAsync("test.txt", source, size: source.Length);
|
||||
source.Position = source.Length;
|
||||
using var cancellation = new CancellationTokenSource();
|
||||
cancellation.Cancel();
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () =>
|
||||
await entry.OpenEntryStreamAsync(cancellation.Token)
|
||||
);
|
||||
Assert.Equal(source.Length, source.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask Zip_New_Directory_OpenEntryStreamAsync()
|
||||
{
|
||||
await using var archive = await ZipArchive.CreateAsyncArchive();
|
||||
var entry = await archive.AddDirectoryEntryAsync("directory");
|
||||
using var opened = await entry.OpenEntryStreamAsync(CancellationToken.None);
|
||||
Assert.Equal(0, opened.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask Zip_Save_New_Entry_Async_Only_Streams()
|
||||
{
|
||||
using var source = new AsyncOnlyStream(new MemoryStream(Encoding.UTF8.GetBytes("test")));
|
||||
using var destination = new MemoryStream();
|
||||
using var output = new AsyncOnlyStream(destination, disposeStream: false);
|
||||
await using (var archive = await ZipArchive.CreateAsyncArchive())
|
||||
{
|
||||
await archive.AddEntryAsync("test.txt", source, size: source.Length);
|
||||
await archive.SaveToAsync(
|
||||
output,
|
||||
new ZipWriterOptions(CompressionType.Deflate) { LeaveStreamOpen = true },
|
||||
CancellationToken.None
|
||||
);
|
||||
}
|
||||
destination.Position = 0;
|
||||
await using var reopened = await ZipArchive.OpenAsyncArchive(destination);
|
||||
var entry = await reopened.EntriesAsync.SingleAsync();
|
||||
var stream = await entry.OpenEntryStreamAsync(CancellationToken.None);
|
||||
await using var scope = stream.DisposeAsyncScope().ConfigureAwait(false);
|
||||
using var reader = new StreamReader(stream);
|
||||
Assert.Equal("test", await reader.ReadToEndAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask Zip_Deflate_Entry_Stream_Async()
|
||||
{
|
||||
|
||||
@@ -42,9 +42,9 @@
|
||||
},
|
||||
"Microsoft.VisualStudio.Threading.Analyzers": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.14.15, )",
|
||||
"resolved": "17.14.15",
|
||||
"contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
|
||||
"requested": "[18.12.1, )",
|
||||
"resolved": "18.12.1",
|
||||
"contentHash": "sQt7NpnselT1gP1a7bTfhmfHYV0jbavst/8mOoWTMSjXhXzWPssqgBoIwrxNsgJUa7XQzD2raSRMAFfmlepxNw=="
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
@@ -72,9 +72,9 @@
|
||||
},
|
||||
"Zomp.SyncMethodGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.56, )",
|
||||
"resolved": "2.0.56",
|
||||
"contentHash": "P1iMA1meu0uX8YcPWhkFnpzV3e+QFDDYMU6hMNyofS+pBlLgeVV7QevBmJmJ/mrxA1jujo3cqNaO1IapdfjOlA=="
|
||||
"requested": "[2.0.66, )",
|
||||
"resolved": "2.0.66",
|
||||
"contentHash": "iYnF185851PEX5vnxrhUj2av30HoxvjUlPd0HVVuSAif7TCgc/Noc5xVf9jiLhMlI8Rt9QrJdef3KB8+opAJQA=="
|
||||
},
|
||||
"Microsoft.ApplicationInsights": {
|
||||
"type": "Transitive",
|
||||
@@ -236,6 +236,11 @@
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||
}
|
||||
},
|
||||
"System.ValueTuple": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.6.2",
|
||||
"contentHash": "yQgmjfFximrNm9LIV3mL6T5MzjeC+epeE5rl4hXxAlYmxby7RM1dPSkIKXk9HNkl6G54h2JHOmLD46+Pey+IRg=="
|
||||
},
|
||||
"xunit.analyzers": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.27.0",
|
||||
@@ -311,7 +316,7 @@
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "[8.0.0, )",
|
||||
"System.Text.Encoding.CodePages": "[8.0.0, )"
|
||||
"System.Text.Encoding.CodePages": "[10.0.12, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Bcl.AsyncInterfaces": {
|
||||
@@ -325,12 +330,13 @@
|
||||
},
|
||||
"System.Text.Encoding.CodePages": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==",
|
||||
"requested": "[10.0.12, )",
|
||||
"resolved": "10.0.12",
|
||||
"contentHash": "rt1G/LdKC6oc3xPyQhMn5vRTp9iTTt1BS9Dx/67TpW9KWgFJ39lyEz0y4CbDksx7iTZEfgG61UsQMoGEXEpF4A==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.5",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
"System.Memory": "4.6.3",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.1.2",
|
||||
"System.ValueTuple": "4.6.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -373,9 +379,9 @@
|
||||
},
|
||||
"Microsoft.VisualStudio.Threading.Analyzers": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.14.15, )",
|
||||
"resolved": "17.14.15",
|
||||
"contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
|
||||
"requested": "[18.12.1, )",
|
||||
"resolved": "18.12.1",
|
||||
"contentHash": "sQt7NpnselT1gP1a7bTfhmfHYV0jbavst/8mOoWTMSjXhXzWPssqgBoIwrxNsgJUa7XQzD2raSRMAFfmlepxNw=="
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
@@ -400,9 +406,9 @@
|
||||
},
|
||||
"Zomp.SyncMethodGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.56, )",
|
||||
"resolved": "2.0.56",
|
||||
"contentHash": "P1iMA1meu0uX8YcPWhkFnpzV3e+QFDDYMU6hMNyofS+pBlLgeVV7QevBmJmJ/mrxA1jujo3cqNaO1IapdfjOlA=="
|
||||
"requested": "[2.0.66, )",
|
||||
"resolved": "2.0.66",
|
||||
"contentHash": "iYnF185851PEX5vnxrhUj2av30HoxvjUlPd0HVVuSAif7TCgc/Noc5xVf9jiLhMlI8Rt9QrJdef3KB8+opAJQA=="
|
||||
},
|
||||
"Microsoft.ApplicationInsights": {
|
||||
"type": "Transitive",
|
||||
|
||||
Reference in New Issue
Block a user