mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-22 15:04:43 +00:00
Small fixes and format
This commit is contained in:
@@ -152,7 +152,11 @@ internal sealed class SevenZipStreamsCompressor(Stream outputStream)
|
||||
uint inputCrc;
|
||||
long inputSize;
|
||||
{
|
||||
#if LEGACY_DOTNET
|
||||
using var lzmaStream = LzmaStream.Create(encoderProperties, false, outCrcStream);
|
||||
#else
|
||||
await using var lzmaStream = LzmaStream.Create(encoderProperties, false, outCrcStream);
|
||||
#endif
|
||||
properties = lzmaStream.Properties;
|
||||
|
||||
(inputCrc, inputSize) = await CopyWithCrcAsync(
|
||||
|
||||
@@ -8,8 +8,11 @@ namespace SharpCompress.Compressors.Deflate;
|
||||
|
||||
public partial class DeflateStream
|
||||
{
|
||||
#if !LEGACY_DOTNET
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public async ValueTask DisposeAsync()
|
||||
#endif
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
@@ -19,9 +22,12 @@ public partial class DeflateStream
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
#else
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
public override async Task FlushAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
@@ -550,15 +550,20 @@ internal class ZlibBaseStream : Stream, IStreamStack
|
||||
}
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
public override async ValueTask DisposeAsync()
|
||||
#else
|
||||
public async ValueTask DisposeAsync()
|
||||
#endif
|
||||
{
|
||||
if (isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
isDisposed = true;
|
||||
#if !LEGACY_DOTNET || NETSTANDARD2_1
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
if (_stream is null)
|
||||
{
|
||||
return;
|
||||
@@ -574,13 +579,19 @@ internal class ZlibBaseStream : Stream, IStreamStack
|
||||
{
|
||||
if (!_leaveOpen)
|
||||
{
|
||||
await _stream.DisposeAsync().ConfigureAwait(false);
|
||||
if (_stream is IAsyncDisposable asyncDisposableStream)
|
||||
{
|
||||
await asyncDisposableStream.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_stream.Dispose();
|
||||
}
|
||||
}
|
||||
_stream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
|
||||
@@ -473,21 +473,30 @@ public class TarFactory
|
||||
stream = writerOptions.CompressionType switch
|
||||
{
|
||||
CompressionType.None => stream,
|
||||
CompressionType.BZip2 => await providers.CreateCompressStreamAsync(
|
||||
CompressionType.BZip2,
|
||||
stream,
|
||||
writerOptions.CompressionLevel,
|
||||
cancellationToken).ConfigureAwait(false),
|
||||
CompressionType.GZip => await providers.CreateCompressStreamAsync(
|
||||
CompressionType.GZip,
|
||||
stream,
|
||||
writerOptions.CompressionLevel,
|
||||
cancellationToken).ConfigureAwait(false),
|
||||
CompressionType.LZip => await providers.CreateCompressStreamAsync(
|
||||
CompressionType.LZip,
|
||||
stream,
|
||||
writerOptions.CompressionLevel,
|
||||
cancellationToken).ConfigureAwait(false),
|
||||
CompressionType.BZip2 => await providers
|
||||
.CreateCompressStreamAsync(
|
||||
CompressionType.BZip2,
|
||||
stream,
|
||||
writerOptions.CompressionLevel,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false),
|
||||
CompressionType.GZip => await providers
|
||||
.CreateCompressStreamAsync(
|
||||
CompressionType.GZip,
|
||||
stream,
|
||||
writerOptions.CompressionLevel,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false),
|
||||
CompressionType.LZip => await providers
|
||||
.CreateCompressStreamAsync(
|
||||
CompressionType.LZip,
|
||||
stream,
|
||||
writerOptions.CompressionLevel,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false),
|
||||
_ => throw new InvalidFormatException(
|
||||
"Tar does not support compression: " + writerOptions.CompressionType
|
||||
),
|
||||
|
||||
@@ -99,8 +99,11 @@ public class TarWrapper(
|
||||
LZipStream.IsLZipFile,
|
||||
LZipStream.IsLZipFileAsync,
|
||||
(stream) => LZipStream.Create(stream, CompressionMode.Decompress),
|
||||
async (stream, _) =>await LZipStream.CreateAsync(stream, CompressionMode.Decompress).ConfigureAwait(false),
|
||||
["tar.lz"]
|
||||
async (stream, _) =>
|
||||
await LZipStream
|
||||
.CreateAsync(stream, CompressionMode.Decompress)
|
||||
.ConfigureAwait(false),
|
||||
["tar.lz"]
|
||||
),
|
||||
new(
|
||||
CompressionType.Xz,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.IO;
|
||||
|
||||
@@ -37,6 +39,9 @@ internal class CountingStream : 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) =>
|
||||
_stream.Read(buffer, offset, count);
|
||||
|
||||
@@ -56,6 +61,28 @@ internal class CountingStream : Stream
|
||||
_bytesWritten++;
|
||||
}
|
||||
|
||||
public override async Task WriteAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
int count,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
await _stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
|
||||
_bytesWritten += count;
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET
|
||||
public override async ValueTask WriteAsync(
|
||||
ReadOnlyMemory<byte> buffer,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
await _stream.WriteAsync(buffer, cancellationToken).ConfigureAwait(false);
|
||||
_bytesWritten += buffer.Length;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
|
||||
@@ -39,11 +39,11 @@ public sealed class LZipCompressionProvider : CompressionProviderBase
|
||||
return LZipStream.Create(source, CompressionMode.Decompress);
|
||||
}
|
||||
|
||||
public override async ValueTask<Stream> CreateDecompressStreamAsync(Stream source, CancellationToken cancellationToken = default) => await LZipStream
|
||||
.CreateAsync(
|
||||
source,
|
||||
CompressionMode.Decompress,
|
||||
cancellationToken: cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
public override async ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await LZipStream
|
||||
.CreateAsync(source, CompressionMode.Decompress, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ public partial class TarWriter : AbstractWriter
|
||||
_finalizeArchiveOnClose = options.FinalizeArchiveOnClose;
|
||||
_headerFormat = options.HeaderFormat;
|
||||
|
||||
|
||||
InitializeStream(destination);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,12 @@ public partial class ZipWriter
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
options.ValidateWithFallback(compressionType, compressionLevel);
|
||||
var compression = ToZipCompressionMethod(options.CompressionType ?? compressionType);
|
||||
|
||||
entryPath = NormalizeFilename(entryPath);
|
||||
options.ModificationDateTime ??= DateTime.Now;
|
||||
options.EntryComment ??= string.Empty;
|
||||
var entry = new ZipCentralDirectoryEntry(
|
||||
compression,
|
||||
entryPath,
|
||||
@@ -109,13 +114,16 @@ public partial class ZipWriter
|
||||
await WriteHeaderAsync(entryPath, options, entry, useZip64, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
streamPosition += headersize;
|
||||
return new ZipWritingStream(
|
||||
this,
|
||||
OutputStream.NotNull(),
|
||||
entry,
|
||||
compression,
|
||||
options.CompressionLevel ?? compressionLevel
|
||||
);
|
||||
return await ZipWritingStream
|
||||
.CreateAsync(
|
||||
this,
|
||||
OutputStream.NotNull(),
|
||||
entry,
|
||||
compression,
|
||||
options.CompressionLevel ?? compressionLevel,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<int> WriteHeaderAsync(
|
||||
|
||||
@@ -392,13 +392,14 @@ public partial class ZipWriter : AbstractWriter
|
||||
private readonly CRC32 crc = new();
|
||||
private readonly ZipCentralDirectoryEntry entry;
|
||||
private readonly Stream originalStream;
|
||||
private readonly Stream writeStream;
|
||||
private Stream writeStream;
|
||||
private readonly ZipWriter writer;
|
||||
private readonly ZipCompressionMethod zipCompressionMethod;
|
||||
private readonly int compressionLevel;
|
||||
private ICompressionProviderHooks? compressionProviderHooks;
|
||||
private CompressionContext? compressionContext;
|
||||
private CountingStream? counting;
|
||||
private MemoryStream? asyncCompressionBuffer;
|
||||
private ulong decompressed;
|
||||
|
||||
// Flag to prevent throwing exceptions on Dispose
|
||||
@@ -410,7 +411,8 @@ public partial class ZipWriter : AbstractWriter
|
||||
Stream originalStream,
|
||||
ZipCentralDirectoryEntry entry,
|
||||
ZipCompressionMethod zipCompressionMethod,
|
||||
int compressionLevel
|
||||
int compressionLevel,
|
||||
Stream? compressionStream = null
|
||||
)
|
||||
{
|
||||
this.writer = writer;
|
||||
@@ -419,7 +421,42 @@ public partial class ZipWriter : AbstractWriter
|
||||
this.entry = entry;
|
||||
this.zipCompressionMethod = zipCompressionMethod;
|
||||
this.compressionLevel = compressionLevel;
|
||||
writeStream = GetWriteStream(originalStream);
|
||||
writeStream = GetWriteStream(compressionStream ?? originalStream);
|
||||
}
|
||||
|
||||
internal static async Task<ZipWritingStream> CreateAsync(
|
||||
ZipWriter writer,
|
||||
Stream originalStream,
|
||||
ZipCentralDirectoryEntry entry,
|
||||
ZipCompressionMethod zipCompressionMethod,
|
||||
int compressionLevel,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var compressionStream = originalStream;
|
||||
MemoryStream? asyncCompressionBuffer = null;
|
||||
if (
|
||||
zipCompressionMethod
|
||||
is ZipCompressionMethod.BZip2
|
||||
or ZipCompressionMethod.LZMA
|
||||
or ZipCompressionMethod.PPMd
|
||||
)
|
||||
{
|
||||
asyncCompressionBuffer = new MemoryStream();
|
||||
compressionStream = asyncCompressionBuffer;
|
||||
}
|
||||
|
||||
var stream = new ZipWritingStream(
|
||||
writer,
|
||||
originalStream,
|
||||
entry,
|
||||
zipCompressionMethod,
|
||||
compressionLevel,
|
||||
compressionStream
|
||||
);
|
||||
stream.asyncCompressionBuffer = asyncCompressionBuffer;
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
return stream;
|
||||
}
|
||||
|
||||
public override bool CanRead => false;
|
||||
@@ -674,43 +711,98 @@ public partial class ZipWriter : AbstractWriter
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
// We check the limits first, because we can keep the archive consistent
|
||||
// if we can prevent the writes from happening
|
||||
if (entry.Zip64HeaderOffset == 0)
|
||||
{
|
||||
var countingCount = counting?.BytesWritten ?? 0;
|
||||
// Pre-check, the counting.Count is not exact, as we do not know the size before having actually compressed it
|
||||
if (
|
||||
limitsExceeded
|
||||
|| ((decompressed + (uint)count) > uint.MaxValue)
|
||||
|| (countingCount + (uint)count) > uint.MaxValue
|
||||
)
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
"Attempted to write a stream that is larger than 4GiB without setting the zip64 option"
|
||||
);
|
||||
}
|
||||
}
|
||||
CheckWriteLimits(count);
|
||||
|
||||
decompressed += (uint)count;
|
||||
crc.SlurpBlock(buffer, offset, count);
|
||||
writeStream.Write(buffer, offset, count);
|
||||
|
||||
if (entry.Zip64HeaderOffset == 0)
|
||||
CheckPostWriteLimits();
|
||||
}
|
||||
|
||||
public override async Task WriteAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
int count,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
CheckWriteLimits(count);
|
||||
|
||||
decompressed += (uint)count;
|
||||
crc.SlurpBlock(buffer, offset, count);
|
||||
await writeStream
|
||||
.WriteAsync(buffer, offset, count, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
CheckPostWriteLimits();
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET
|
||||
public override async ValueTask WriteAsync(
|
||||
ReadOnlyMemory<byte> buffer,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
CheckWriteLimits(buffer.Length);
|
||||
|
||||
decompressed += (uint)buffer.Length;
|
||||
if (System.Runtime.InteropServices.MemoryMarshal.TryGetArray(buffer, out var segment))
|
||||
{
|
||||
var countingCount = counting?.BytesWritten ?? 0;
|
||||
// Post-check, this is accurate
|
||||
if ((decompressed > uint.MaxValue) || countingCount > uint.MaxValue)
|
||||
{
|
||||
// We have written the data, so the archive is now broken
|
||||
// Throwing the exception here, allows us to avoid
|
||||
// throwing an exception in Dispose() which is discouraged
|
||||
// as it can mask other errors
|
||||
limitsExceeded = true;
|
||||
throw new NotSupportedException(
|
||||
"Attempted to write a stream that is larger than 4GiB without setting the zip64 option"
|
||||
);
|
||||
}
|
||||
crc.SlurpBlock(segment.Array!, segment.Offset, segment.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
var array = buffer.ToArray();
|
||||
crc.SlurpBlock(array, 0, array.Length);
|
||||
}
|
||||
await writeStream.WriteAsync(buffer, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
CheckPostWriteLimits();
|
||||
}
|
||||
#endif
|
||||
|
||||
private void CheckWriteLimits(int count)
|
||||
{
|
||||
// We check the limits first, because we can keep the archive consistent
|
||||
// if we can prevent the writes from happening. The compressed byte count
|
||||
// is only an estimate until compression has actually happened.
|
||||
if (entry.Zip64HeaderOffset != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var countingCount = counting?.BytesWritten ?? 0;
|
||||
if (
|
||||
limitsExceeded
|
||||
|| ((decompressed + (uint)count) > uint.MaxValue)
|
||||
|| (countingCount + (uint)count) > uint.MaxValue
|
||||
)
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
"Attempted to write a stream that is larger than 4GiB without setting the zip64 option"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckPostWriteLimits()
|
||||
{
|
||||
if (entry.Zip64HeaderOffset != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var countingCount = counting?.BytesWritten ?? 0;
|
||||
if ((decompressed > uint.MaxValue) || countingCount > uint.MaxValue)
|
||||
{
|
||||
// We have written the data, so the archive is now broken. Throwing
|
||||
// here avoids throwing from Dispose(), which can mask other errors.
|
||||
limitsExceeded = true;
|
||||
throw new NotSupportedException(
|
||||
"Attempted to write a stream that is larger than 4GiB without setting the zip64 option"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,20 +869,26 @@ public partial class ZipWriter : AbstractWriter
|
||||
|
||||
isDisposed = true;
|
||||
|
||||
#if NET48 || NETSTANDARD2_0
|
||||
writeStream.Dispose();
|
||||
#else
|
||||
await writeStream.DisposeAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
if (writeStream is IAsyncDisposable asyncDisposableWriteStream)
|
||||
{
|
||||
await asyncDisposableWriteStream.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeStream.Dispose();
|
||||
}
|
||||
|
||||
if (limitsExceeded)
|
||||
{
|
||||
// We have written invalid data into the archive, so destroy it
|
||||
#if NET48 || NETSTANDARD2_0
|
||||
originalStream.Dispose();
|
||||
#else
|
||||
await originalStream.DisposeAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
if (originalStream is IAsyncDisposable asyncDisposableOriginalStream)
|
||||
{
|
||||
await asyncDisposableOriginalStream.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
originalStream.Dispose();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -805,6 +903,14 @@ public partial class ZipWriter : AbstractWriter
|
||||
var compressedvalue = zip64 ? uint.MaxValue : (uint)countingCount;
|
||||
var decompressedvalue = zip64 ? uint.MaxValue : (uint)entry.Decompressed;
|
||||
|
||||
if (asyncCompressionBuffer is not null)
|
||||
{
|
||||
asyncCompressionBuffer.Position = 0;
|
||||
await asyncCompressionBuffer
|
||||
.CopyToAsync(originalStream, 81920, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (originalStream.CanSeek)
|
||||
{
|
||||
originalStream.Position = (long)(entry.HeaderOffset + 6);
|
||||
|
||||
@@ -130,7 +130,9 @@ public class LeaveOpenBehaviorTests
|
||||
public void LZipStream_Compress_LeaveOpen_False()
|
||||
{
|
||||
using var innerStream = new TestStream(new MemoryStream());
|
||||
using (var lzip = LZipStream.Create(innerStream, CompressionMode.Compress, leaveOpen: false))
|
||||
using (
|
||||
var lzip = LZipStream.Create(innerStream, CompressionMode.Compress, leaveOpen: false)
|
||||
)
|
||||
{
|
||||
lzip.Write(CreateTestData(), 0, CreateTestData().Length);
|
||||
lzip.Finish();
|
||||
@@ -177,7 +179,9 @@ public class LeaveOpenBehaviorTests
|
||||
using var innerStream = new TestStream(memStream);
|
||||
var decompressed = new byte[CreateTestData().Length];
|
||||
|
||||
using (var lzip = LZipStream.Create(innerStream, CompressionMode.Decompress, leaveOpen: false))
|
||||
using (
|
||||
var lzip = LZipStream.Create(innerStream, CompressionMode.Decompress, leaveOpen: false)
|
||||
)
|
||||
{
|
||||
lzip.Read(decompressed, 0, decompressed.Length);
|
||||
}
|
||||
@@ -201,7 +205,9 @@ public class LeaveOpenBehaviorTests
|
||||
using var innerStream = new TestStream(memStream);
|
||||
var decompressed = new byte[CreateTestData().Length];
|
||||
|
||||
using (var lzip = LZipStream.Create(innerStream, CompressionMode.Decompress, leaveOpen: true))
|
||||
using (
|
||||
var lzip = LZipStream.Create(innerStream, CompressionMode.Decompress, leaveOpen: true)
|
||||
)
|
||||
{
|
||||
lzip.Read(decompressed, 0, decompressed.Length);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user