mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-22 06:54:40 +00:00
converted a lot of zip items to sync method generator
This commit is contained in:
@@ -25,7 +25,13 @@ the verification workflow, and the record of what is blocked and why.
|
||||
| 0 | `Archives/IArchiveEntryExtensions` (5 methods) | done — `c303856c` |
|
||||
| 1 | `Compressors/Filters/Filter` + 6 XZ branch filters + `Lzma2Filter` (9 methods, 147 lines) | done — verified identical on net48 + net10.0 |
|
||||
| 2 | `IO/` leaf stream shims + `Common/EntryStream` (17 methods, 190 lines) | done — verified identical on net48 + net10.0 |
|
||||
| 3–12 | below | to do |
|
||||
| 3–5 | below | to do |
|
||||
| 6 | ZIP parts & header factories | 6a done; header factories remain |
|
||||
| 7 | Concrete writers | ZIP done; Tar, SevenZip, and remaining writers to do |
|
||||
| 8 | 7-Zip | to do |
|
||||
| 9 | Streaming compressors | Deflate, Zlib, and Deflate64 done; remaining compressors to do |
|
||||
| 10–11 | below | to do |
|
||||
| 12 | Providers | registry done; provider implementations remain |
|
||||
| Rar reader unification | below | to do, needs its own design review |
|
||||
|
||||
---
|
||||
@@ -207,16 +213,17 @@ the async one `new byte[4]`, and the method is 4 lines — `SYNC_ONLY` would be
|
||||
`Arj/HuffmanTree`, `Arj/BitReader`, `Arj/LhaStream` (11 pairs, all ≥0.99), `Arj/LHDecoderStream`,
|
||||
`Squeezed/BitReader`. Best win per line of review — pure parsing, all clean.
|
||||
|
||||
### 6 — Zip parts & header factories · ~250 lines · med risk
|
||||
### 6 — Zip parts & header factories · ~250 lines · med risk · **in progress**
|
||||
|
||||
6a: `ZipFilePart` (incl. `GetCryptoStreamAsync`), `SeekableZipFilePart`, `StreamingZipFilePart`,
|
||||
`GZipFilePart`, `Zip/Headers/ZipFileEntry`, `PkwareTraditionalCryptoStream`, `WinzipAesCryptoStream`.
|
||||
`Zip/Headers/ZipFileEntry`, `PkwareTraditionalCryptoStream`, and `WinzipAesCryptoStream` — **done**.
|
||||
`GZipFilePart` was completed in the prior GZip batch.
|
||||
6b: `ZipHeaderFactory` (`LoadHeaderAsync` identical), `SeekableZipHeaderFactory`.
|
||||
|
||||
### 7 — Concrete writers · ~250 lines · med risk
|
||||
### 7 — Concrete writers · ~250 lines · med risk · **in progress**
|
||||
|
||||
`ZipWriter`, `ZipWritingStream` (`GetWriteStreamAsync` is a 131-line duplicate), `TarWriter`,
|
||||
`SevenZipWriter`, `GZipWriter`.
|
||||
`ZipWriter` and `ZipWritingStream` (`GetWriteStreamAsync` is a 131-line duplicate) — **done**.
|
||||
`TarWriter` and `SevenZipWriter` remain. `GZipWriter` was completed in the prior GZip batch.
|
||||
|
||||
This is the **reachable Writers win**: `AbstractWriter` already implements *both* `IWriter` and
|
||||
`IAsyncWriter` (`AbstractWriter.cs:11`), so `ZipWriter.Async.cs:52
|
||||
@@ -233,14 +240,15 @@ attempt `IWriterExtensions` (see Blocked).
|
||||
Clean: these use the sync `DataReader`, not an async-only reader type. Keep the file split
|
||||
(`ArchiveReader.cs` is 1,377 lines).
|
||||
|
||||
### 9 — Streaming compressors · ~300 lines · med-high risk
|
||||
### 9 — Streaming compressors · ~300 lines · med-high risk · **in progress**
|
||||
|
||||
`Deflate64Stream`, `Deflate/ZlibBaseStream` (`ReadAsync` 192 lines, `WriteAsync`, `FlushAsync`),
|
||||
`DeflateStream`, `GZipStream`, `ZlibStream`, `ZStandard/*`, `Reduce`, `Explode`, `Lzw/LzwStream`
|
||||
(`ReadAsync` 208 lines), `RLE90`, `Shrink`, `ArcLzw`.
|
||||
`Deflate64Stream`, `Deflate/ZlibBaseStream` (`ReadAsync`, `WriteAsync`, `FlushAsync`),
|
||||
`DeflateStream`, and `ZlibStream` — **done**. `GZipStream` was completed in the prior GZip batch.
|
||||
`ZStandard/*`, `Reduce`, `Explode`, `Lzw/LzwStream` (`ReadAsync` 208 lines), `RLE90`, `Shrink`,
|
||||
and `ArcLzw` remain.
|
||||
|
||||
- `ZlibBaseStream` needs `partial` added.
|
||||
- `[SkipSyncVersion]` on all four Deflate-family `DisposeAsync`.
|
||||
- `ZlibBaseStream` is partial. Deflate-family `DisposeAsync`, byte methods, unmatched memory
|
||||
overloads, GZip-header parsing, and finalization remain hand-written.
|
||||
- `RunLength90Stream` is the canonical `SYNC_ONLY` case (see below).
|
||||
- `GZipCompressionProvider.cs:41` returns `new ValueTask<Stream>(...)` from a non-`async` method —
|
||||
not a Zomp rewrite; make it `async` first. (Non-`async` methods that just *return* an `XAsync(...)`
|
||||
@@ -264,11 +272,12 @@ generated `ReadByte()`/`WriteByte()` are emitted without `override` and would hi
|
||||
Fully clean — these use raw `Stream`, **not** the async reader types. The least readable diffs in the
|
||||
repo, so do them last of the mechanical work.
|
||||
|
||||
### 12 — Providers · ~80 lines · low risk
|
||||
### 12 — Providers · ~80 lines · low risk · **in progress**
|
||||
|
||||
`CompressionProviderRegistry` (4 identical pairs), `Default/*` providers (`XStream.CreateAsync(...)`
|
||||
→ `Create(...)` maps cleanly), `CompressionProviderBase`,
|
||||
`ContextRequiredDecompressionProviderBase`. Blocked on the `GZipCompressionProvider` rewrite above.
|
||||
`CompressionProviderRegistry` (4 identical pairs) — **done**. `Default/*` providers
|
||||
(`XStream.CreateAsync(...)` → `Create(...)` maps cleanly), `CompressionProviderBase`, and
|
||||
`ContextRequiredDecompressionProviderBase` remain. The `GZipCompressionProvider` rewrite was
|
||||
completed in the prior GZip batch.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace SharpCompress.Common.Zip.Headers;
|
||||
|
||||
internal abstract partial class ZipFileEntry
|
||||
{
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
internal async ValueTask<PkwareTraditionalEncryptionData> ComposeEncryptionDataAsync(
|
||||
Stream archiveStream,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -15,7 +16,7 @@ internal abstract partial class ZipFileEntry
|
||||
ThrowHelper.ThrowIfNull(archiveStream);
|
||||
|
||||
var buffer = new byte[12];
|
||||
await archiveStream.ReadFullyAsync(buffer, 0, 12, cancellationToken).ConfigureAwait(false);
|
||||
await archiveStream.ReadFullyAsync(buffer, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var encryptionData = PkwareTraditionalEncryptionData.ForRead(Password!, this, buffer);
|
||||
|
||||
|
||||
@@ -42,18 +42,6 @@ internal abstract partial class ZipFileEntry(ZipHeaderType type, IArchiveEncodin
|
||||
|
||||
public string? Password { get; set; }
|
||||
|
||||
internal PkwareTraditionalEncryptionData ComposeEncryptionData(Stream archiveStream)
|
||||
{
|
||||
ThrowHelper.ThrowIfNull(archiveStream);
|
||||
|
||||
var buffer = new byte[12];
|
||||
archiveStream.ReadFully(buffer);
|
||||
|
||||
var encryptionData = PkwareTraditionalEncryptionData.ForRead(Password!, this, buffer);
|
||||
|
||||
return encryptionData;
|
||||
}
|
||||
|
||||
internal WinzipAesEncryptionData? WinzipAesEncryptionData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace SharpCompress.Common.Zip;
|
||||
|
||||
internal partial class PkwareTraditionalCryptoStream
|
||||
{
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task<int> ReadAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
@@ -59,6 +60,7 @@ internal partial class PkwareTraditionalCryptoStream
|
||||
}
|
||||
#endif
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task WriteAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
|
||||
@@ -41,49 +41,6 @@ internal partial class PkwareTraditionalCryptoStream : Stream
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_mode == CryptoMode.Encrypt)
|
||||
{
|
||||
throw new NotSupportedException("This stream does not encrypt via Read()");
|
||||
}
|
||||
|
||||
ThrowHelper.ThrowIfNull(buffer);
|
||||
|
||||
var temp = new byte[count];
|
||||
var readBytes = _stream.Read(temp, 0, count);
|
||||
var decrypted = _encryptor.Decrypt(temp, readBytes);
|
||||
Buffer.BlockCopy(decrypted, 0, buffer, offset, readBytes);
|
||||
return readBytes;
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_mode == CryptoMode.Decrypt)
|
||||
{
|
||||
throw new NotSupportedException("This stream does not Decrypt via Write()");
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] plaintext;
|
||||
if (offset != 0)
|
||||
{
|
||||
plaintext = new byte[count];
|
||||
Buffer.BlockCopy(buffer, offset, plaintext, 0, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
plaintext = buffer;
|
||||
}
|
||||
|
||||
var encrypted = _encryptor.Encrypt(plaintext, count);
|
||||
_stream.Write(encrypted, 0, encrypted.Length);
|
||||
}
|
||||
|
||||
public override void Flush() { }
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace SharpCompress.Common.Zip;
|
||||
|
||||
internal partial class SeekableZipFilePart
|
||||
{
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
internal override async ValueTask<Stream?> GetCompressedStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
@@ -19,6 +20,7 @@ internal partial class SeekableZipFilePart
|
||||
return await base.GetCompressedStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
private async ValueTask LoadLocalHeaderAsync(CancellationToken cancellationToken = default) =>
|
||||
Header = await _headerFactory
|
||||
.GetLocalHeaderAsync(BaseStream, (DirectoryEntryHeader)Header)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.Zip;
|
||||
@@ -18,19 +17,6 @@ internal partial class SeekableZipFilePart : ZipFilePart
|
||||
)
|
||||
: base(header, stream, compressionProviders) => _headerFactory = headerFactory;
|
||||
|
||||
internal override Stream GetCompressedStream()
|
||||
{
|
||||
if (!_isLocalHeaderLoaded)
|
||||
{
|
||||
LoadLocalHeader();
|
||||
_isLocalHeaderLoaded = true;
|
||||
}
|
||||
return base.GetCompressedStream();
|
||||
}
|
||||
|
||||
private void LoadLocalHeader() =>
|
||||
Header = _headerFactory.GetLocalHeader(BaseStream, (DirectoryEntryHeader)Header);
|
||||
|
||||
protected override Stream CreateBaseStream()
|
||||
{
|
||||
BaseStream.Position = Header.DataStartPosition.NotNull();
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace SharpCompress.Common.Zip;
|
||||
|
||||
internal sealed partial class StreamingZipFilePart
|
||||
{
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
internal override async ValueTask<Stream?> GetCompressedStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
@@ -15,17 +16,18 @@ internal sealed partial class StreamingZipFilePart
|
||||
{
|
||||
return Stream.Null;
|
||||
}
|
||||
_decompressionStream = await CreateDecompressionStreamAsync(
|
||||
var decompressionStream = await CreateDecompressionStreamAsync(
|
||||
await GetCryptoStreamAsync(CreateBaseStream(), cancellationToken)
|
||||
.ConfigureAwait(false),
|
||||
Header.CompressionMethod,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
_decompressionStream = decompressionStream;
|
||||
if (LeaveStreamOpen)
|
||||
{
|
||||
return SharpCompressStream.CreateNonDisposing(_decompressionStream);
|
||||
return SharpCompressStream.CreateNonDisposing(decompressionStream);
|
||||
}
|
||||
return _decompressionStream;
|
||||
return decompressionStream;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
@@ -19,23 +18,6 @@ internal sealed partial class StreamingZipFilePart : ZipFilePart
|
||||
|
||||
protected override Stream CreateBaseStream() => Header.PackedStream.NotNull();
|
||||
|
||||
internal override Stream GetCompressedStream()
|
||||
{
|
||||
if (!Header.HasData)
|
||||
{
|
||||
return Stream.Null;
|
||||
}
|
||||
_decompressionStream = CreateDecompressionStream(
|
||||
GetCryptoStream(CreateBaseStream()),
|
||||
Header.CompressionMethod
|
||||
);
|
||||
if (LeaveStreamOpen)
|
||||
{
|
||||
return SharpCompressStream.CreateNonDisposing(_decompressionStream);
|
||||
}
|
||||
return _decompressionStream;
|
||||
}
|
||||
|
||||
internal BinaryReader FixStreamedFileLocation(ref Stream stream)
|
||||
{
|
||||
if (Header.IsDirectory)
|
||||
@@ -45,12 +27,12 @@ internal sealed partial class StreamingZipFilePart : ZipFilePart
|
||||
|
||||
if (Header.HasData && !Skipped)
|
||||
{
|
||||
_decompressionStream ??= GetCompressedStream();
|
||||
var decompressionStream = _decompressionStream ??= GetCompressedStream().NotNull();
|
||||
|
||||
_decompressionStream.Skip();
|
||||
decompressionStream.Skip();
|
||||
|
||||
// If we had TotalIn / TotalOut we could have used them
|
||||
Header.CompressedSize = _decompressionStream.Position;
|
||||
Header.CompressedSize = decompressionStream.Position;
|
||||
|
||||
Skipped = true;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ internal partial class WinzipAesCryptoStream
|
||||
}
|
||||
#endif
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task<int> ReadAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
|
||||
@@ -104,25 +104,6 @@ internal partial class WinzipAesCryptoStream : Stream
|
||||
|
||||
public override void Flush() { }
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_totalBytesLeftToRead == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
var bytesToRead = count;
|
||||
if (count > _totalBytesLeftToRead)
|
||||
{
|
||||
bytesToRead = (int)_totalBytesLeftToRead;
|
||||
}
|
||||
var read = _stream.Read(buffer, offset, bytesToRead);
|
||||
_totalBytesLeftToRead -= read;
|
||||
|
||||
ReadTransformBlocks(buffer, offset, read);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
private void FillCounterOut()
|
||||
{
|
||||
// update the counter
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace SharpCompress.Common.Zip;
|
||||
|
||||
internal abstract partial class ZipFilePart
|
||||
{
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
internal override async ValueTask<Stream?> GetCompressedStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
@@ -35,6 +36,7 @@ internal abstract partial class ZipFilePart
|
||||
return decompressionStream;
|
||||
}
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
protected async ValueTask<Stream> GetCryptoStreamAsync(
|
||||
Stream plainStream,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -242,6 +244,7 @@ internal abstract partial class ZipFilePart
|
||||
}
|
||||
}
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
private async ValueTask<Stream> CreateWinzipAesDecompressionStreamAsync(
|
||||
Stream stream,
|
||||
CancellationToken cancellationToken = default
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.BZip2;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Compressors.Deflate64;
|
||||
using SharpCompress.Compressors.Explode;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Compressors.PPMd;
|
||||
using SharpCompress.Compressors.Reduce;
|
||||
using SharpCompress.Compressors.Shrink;
|
||||
using SharpCompress.Compressors.Xz;
|
||||
using SharpCompress.Compressors.ZStandard;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
@@ -41,23 +28,6 @@ internal abstract partial class ZipFilePart : FilePart
|
||||
|
||||
internal override string? FilePartName => Header.Name;
|
||||
|
||||
internal override Stream GetCompressedStream()
|
||||
{
|
||||
if (!Header.HasData)
|
||||
{
|
||||
return Stream.Null;
|
||||
}
|
||||
var decompressionStream = CreateDecompressionStream(
|
||||
GetCryptoStream(CreateBaseStream()),
|
||||
Header.CompressionMethod
|
||||
);
|
||||
if (LeaveStreamOpen)
|
||||
{
|
||||
return SharpCompressStream.CreateNonDisposing(decompressionStream);
|
||||
}
|
||||
return decompressionStream;
|
||||
}
|
||||
|
||||
internal override Stream GetRawStream()
|
||||
{
|
||||
if (!Header.HasData)
|
||||
@@ -192,101 +162,4 @@ internal abstract partial class ZipFilePart : FilePart
|
||||
// For simple methods, use the basic decompress
|
||||
return providers.CreateDecompressStream(compressionType, stream, context);
|
||||
}
|
||||
|
||||
private Stream CreateWinzipAesDecompressionStream(Stream stream)
|
||||
{
|
||||
var data = Header.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes);
|
||||
if (data is null)
|
||||
{
|
||||
throw new InvalidFormatException("No Winzip AES extra data found.");
|
||||
}
|
||||
if (data.Length != 7)
|
||||
{
|
||||
throw new InvalidFormatException("Winzip data length is not 7.");
|
||||
}
|
||||
var compressedMethod = BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes);
|
||||
|
||||
if (compressedMethod != 0x01 && compressedMethod != 0x02)
|
||||
{
|
||||
throw new InvalidFormatException(
|
||||
"Unexpected vendor version number for WinZip AES metadata"
|
||||
);
|
||||
}
|
||||
|
||||
var vendorId = BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(2));
|
||||
if (vendorId != 0x4541)
|
||||
{
|
||||
throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata");
|
||||
}
|
||||
return CreateDecompressionStream(
|
||||
stream,
|
||||
(ZipCompressionMethod)BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5))
|
||||
);
|
||||
}
|
||||
|
||||
protected Stream GetCryptoStream(Stream plainStream)
|
||||
{
|
||||
var isFileEncrypted = FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted);
|
||||
|
||||
if (Header.CompressedSize == 0 && isFileEncrypted)
|
||||
{
|
||||
throw new NotSupportedException("Cannot encrypt file with unknown size at start.");
|
||||
}
|
||||
|
||||
if (
|
||||
Header.CompressedSize == 0
|
||||
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)
|
||||
)
|
||||
{
|
||||
plainStream = SharpCompressStream.CreateNonDisposing(plainStream); //make sure AES doesn't close
|
||||
}
|
||||
else
|
||||
{
|
||||
plainStream = new ReadOnlySubStream(plainStream, Header.CompressedSize); //make sure AES doesn't close
|
||||
}
|
||||
|
||||
if (isFileEncrypted)
|
||||
{
|
||||
switch (Header.CompressionMethod)
|
||||
{
|
||||
case ZipCompressionMethod.None:
|
||||
case ZipCompressionMethod.Shrink:
|
||||
case ZipCompressionMethod.Reduce1:
|
||||
case ZipCompressionMethod.Reduce2:
|
||||
case ZipCompressionMethod.Reduce3:
|
||||
case ZipCompressionMethod.Reduce4:
|
||||
case ZipCompressionMethod.Deflate:
|
||||
case ZipCompressionMethod.Deflate64:
|
||||
case ZipCompressionMethod.BZip2:
|
||||
case ZipCompressionMethod.LZMA:
|
||||
case ZipCompressionMethod.PPMd:
|
||||
{
|
||||
return new PkwareTraditionalCryptoStream(
|
||||
plainStream,
|
||||
Header.ComposeEncryptionData(plainStream),
|
||||
CryptoMode.Decrypt
|
||||
);
|
||||
}
|
||||
|
||||
case ZipCompressionMethod.WinzipAes:
|
||||
{
|
||||
if (Header.WinzipAesEncryptionData != null)
|
||||
{
|
||||
return new WinzipAesCryptoStream(
|
||||
plainStream,
|
||||
Header.WinzipAesEncryptionData,
|
||||
Header.CompressedSize - 10
|
||||
);
|
||||
}
|
||||
return plainStream;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw new ArchiveOperationException("Header.CompressionMethod is invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
return plainStream;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ public partial class DeflateStream
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush the stream.
|
||||
/// </summary>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task FlushAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_disposed)
|
||||
@@ -38,6 +42,24 @@ public partial class DeflateStream
|
||||
await _baseStream.FlushAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read data from the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// If you wish to use the <c>DeflateStream</c> to compress data while reading, create it with
|
||||
/// <c>CompressionMode.Compress</c> and an uncompressed data stream. Reading then returns
|
||||
/// compressed data. With <c>CompressionMode.Decompress</c>, reading returns decompressed data.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not both.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="buffer">The buffer into which the read data should be placed.</param>
|
||||
/// <param name="offset">The offset within that data array to put the first byte read.</param>
|
||||
/// <param name="count">The number of bytes to read.</param>
|
||||
/// <returns>The number of bytes actually read.</returns>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task<int> ReadAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
@@ -68,6 +90,23 @@ public partial class DeflateStream
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Write data to the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// With <c>CompressionMode.Compress</c>, written uncompressed data is compressed to the
|
||||
/// destination. With <c>CompressionMode.Decompress</c>, written compressed data is decompressed
|
||||
/// to the destination.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not both.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="buffer">The buffer holding data to write to the stream.</param>
|
||||
/// <param name="offset">The offset within that data array to find the first byte to write.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task WriteAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
@@ -270,54 +268,6 @@ public partial class DeflateStream : Stream, IStreamStack
|
||||
|
||||
Stream IStreamStack.BaseStream() => _baseStream;
|
||||
|
||||
/// <summary>
|
||||
/// Flush the stream.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException("DeflateStream");
|
||||
}
|
||||
_baseStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read data from the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// <para>
|
||||
/// If you wish to use the <c>DeflateStream</c> to compress data while
|
||||
/// reading, you can create a <c>DeflateStream</c> with
|
||||
/// <c>CompressionMode.Compress</c>, providing an uncompressed data stream.
|
||||
/// Then call Read() on that <c>DeflateStream</c>, and the data read will be
|
||||
/// compressed as you read. If you wish to use the <c>DeflateStream</c> to
|
||||
/// decompress data while reading, you can create a <c>DeflateStream</c> with
|
||||
/// <c>CompressionMode.Decompress</c>, providing a readable compressed data
|
||||
/// stream. Then call Read() on that <c>DeflateStream</c>, and the data read
|
||||
/// will be decompressed as you read.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not both.
|
||||
/// </para>
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="buffer">The buffer into which the read data should be placed.</param>
|
||||
/// <param name="offset">the offset within that data array to put the first byte read.</param>
|
||||
/// <param name="count">the number of bytes to read.</param>
|
||||
/// <returns>the number of bytes actually read</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException("DeflateStream");
|
||||
}
|
||||
|
||||
return _baseStream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
if (_disposed)
|
||||
@@ -341,44 +291,6 @@ public partial class DeflateStream : Stream, IStreamStack
|
||||
/// <param name="value">this is irrelevant, since it will always throw!</param>
|
||||
public override void SetLength(long value) => throw new NotSupportedException();
|
||||
|
||||
/// <summary>
|
||||
/// Write data to the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// <para>
|
||||
/// If you wish to use the <c>DeflateStream</c> to compress data while
|
||||
/// writing, you can create a <c>DeflateStream</c> with
|
||||
/// <c>CompressionMode.Compress</c>, and a writable output stream. Then call
|
||||
/// <c>Write()</c> on that <c>DeflateStream</c>, providing uncompressed data
|
||||
/// as input. The data sent to the output stream will be the compressed form
|
||||
/// of the data written. If you wish to use the <c>DeflateStream</c> to
|
||||
/// decompress data while writing, you can create a <c>DeflateStream</c> with
|
||||
/// <c>CompressionMode.Decompress</c>, and a writable output stream. Then
|
||||
/// call <c>Write()</c> on that stream, providing previously compressed
|
||||
/// data. The data sent to the output stream will be the decompressed form of
|
||||
/// the data written.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>,
|
||||
/// but not both.
|
||||
/// </para>
|
||||
///
|
||||
/// </remarks>
|
||||
///
|
||||
/// <param name="buffer">The buffer holding data to write to the stream.</param>
|
||||
/// <param name="offset">the offset within that data array to find the first byte to write.</param>
|
||||
/// <param name="count">the number of bytes to write.</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException("DeflateStream");
|
||||
}
|
||||
_baseStream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
if (_disposed)
|
||||
|
||||
@@ -47,7 +47,7 @@ internal enum ZlibStreamFlavor
|
||||
GZIP = 1952,
|
||||
}
|
||||
|
||||
internal class ZlibBaseStream : Stream, IStreamStack
|
||||
internal partial class ZlibBaseStream : Stream, IStreamStack
|
||||
{
|
||||
Stream IStreamStack.BaseStream() => _stream;
|
||||
|
||||
@@ -139,58 +139,7 @@ internal class ZlibBaseStream : Stream, IStreamStack
|
||||
|
||||
private byte[] workingBuffer => _workingBuffer ??= ArrayPool<byte>.Shared.Rent(_bufferSize);
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
// workitem 7159
|
||||
// calculate the CRC on the unccompressed data (before writing)
|
||||
if (crc != null)
|
||||
{
|
||||
crc.SlurpBlock(buffer, offset, count);
|
||||
}
|
||||
|
||||
if (_streamMode == StreamMode.Undefined)
|
||||
{
|
||||
_streamMode = StreamMode.Writer;
|
||||
}
|
||||
else if (_streamMode != StreamMode.Writer)
|
||||
{
|
||||
throw new ZlibException("Cannot Write after Reading.");
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// first reference of z property will initialize the private var _z
|
||||
z.InputBuffer = buffer;
|
||||
_z.NextIn = offset;
|
||||
_z.AvailableBytesIn = count;
|
||||
var done = false;
|
||||
do
|
||||
{
|
||||
_z.OutputBuffer = workingBuffer;
|
||||
_z.NextOut = 0;
|
||||
_z.AvailableBytesOut = _workingBuffer.Length;
|
||||
var rc = (_wantCompress) ? _z.Deflate(_flushMode) : _z.Inflate(_flushMode);
|
||||
if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
|
||||
{
|
||||
throw new ZlibException((_wantCompress ? "de" : "in") + "flating: " + _z.Message);
|
||||
}
|
||||
|
||||
//if (_workingBuffer.Length - _z.AvailableBytesOut > 0)
|
||||
_stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut);
|
||||
|
||||
done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0;
|
||||
|
||||
// If GZIP and de-compress, we're done when 8 bytes remain.
|
||||
if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress)
|
||||
{
|
||||
done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0);
|
||||
}
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task WriteAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
@@ -607,27 +556,7 @@ internal class ZlibBaseStream : Stream, IStreamStack
|
||||
_workingBuffer = null;
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
// Only flush the underlying stream when in write mode
|
||||
// Flushing input streams during read operations is not meaningful
|
||||
// and can cause issues with forward-only/non-seekable streams
|
||||
if (_streamMode == StreamMode.Writer)
|
||||
{
|
||||
_stream.Flush();
|
||||
}
|
||||
else if (z.AvailableBytesIn > 0)
|
||||
{
|
||||
// Rewind the underlying stream by the number of unconsumed bytes in the buffer
|
||||
// This handles the case where the decompressor over-read past the end of the entry
|
||||
if (_stream is IStreamStack stack)
|
||||
{
|
||||
stack.RewindBytes(z.AvailableBytesIn);
|
||||
}
|
||||
z.AvailableBytesIn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task FlushAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
// Only flush the underlying stream when in write mode
|
||||
@@ -670,31 +599,7 @@ internal class ZlibBaseStream : Stream, IStreamStack
|
||||
private bool nomoreinput;
|
||||
private bool isDisposed;
|
||||
|
||||
private string ReadZeroTerminatedString()
|
||||
{
|
||||
var list = new List<byte>();
|
||||
var done = false;
|
||||
do
|
||||
{
|
||||
// workitem 7740
|
||||
var n = _stream.Read(_buf1, 0, 1);
|
||||
if (n != 1)
|
||||
{
|
||||
throw new ZlibException("Unexpected EOF reading GZIP header.");
|
||||
}
|
||||
if (_buf1[0] == 0)
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(_buf1[0]);
|
||||
}
|
||||
} while (!done);
|
||||
var buffer = list.ToArray();
|
||||
return _encoding.GetString(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
private async ValueTask<string> ReadZeroTerminatedStringAsync(
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
@@ -844,192 +749,7 @@ internal class ZlibBaseStream : Stream, IStreamStack
|
||||
return totalBytesRead;
|
||||
}
|
||||
|
||||
public override Int32 Read(Byte[] buffer, Int32 offset, Int32 count)
|
||||
{
|
||||
// According to MS documentation, any implementation of the IO.Stream.Read function must:
|
||||
// (a) throw an exception if offset & count reference an invalid part of the buffer,
|
||||
// or if count < 0, or if buffer is null
|
||||
// (b) return 0 only upon EOF, or if count = 0
|
||||
// (c) if not EOF, then return at least 1 byte, up to <count> bytes
|
||||
|
||||
if (_streamMode == StreamMode.Undefined)
|
||||
{
|
||||
if (!_stream.CanRead)
|
||||
{
|
||||
throw new ZlibException("The stream is not readable.");
|
||||
}
|
||||
|
||||
// for the first read, set up some controls.
|
||||
_streamMode = StreamMode.Reader;
|
||||
|
||||
// (The first reference to _z goes through the private accessor which
|
||||
// may initialize it.)
|
||||
z.AvailableBytesIn = 0;
|
||||
if (_flavor == ZlibStreamFlavor.GZIP)
|
||||
{
|
||||
_gzipHeaderByteCount = _ReadAndValidateGzipHeader();
|
||||
|
||||
// workitem 8501: handle edge case (decompress empty stream)
|
||||
if (_gzipHeaderByteCount == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_streamMode != StreamMode.Reader)
|
||||
{
|
||||
throw new ZlibException("Cannot Read after Writing.");
|
||||
}
|
||||
|
||||
var rc = 0;
|
||||
|
||||
// set up the output of the deflate/inflate codec:
|
||||
_z.OutputBuffer = buffer;
|
||||
_z.NextOut = offset;
|
||||
_z.AvailableBytesOut = count;
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (nomoreinput && _wantCompress)
|
||||
{
|
||||
// no more input data available; therefore we flush to
|
||||
// try to complete the read
|
||||
rc = _z.Deflate(FlushType.Finish);
|
||||
|
||||
if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
|
||||
{
|
||||
throw new ZlibException(
|
||||
String.Format(
|
||||
Constants.DefaultCultureInfo,
|
||||
"Deflating: rc={0} msg={1}",
|
||||
rc,
|
||||
_z.Message
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
rc = (count - _z.AvailableBytesOut);
|
||||
|
||||
// calculate CRC after reading
|
||||
if (crc != null)
|
||||
{
|
||||
crc.SlurpBlock(buffer, offset, rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
ThrowHelper.ThrowIfNull(buffer);
|
||||
ThrowHelper.ThrowIfNegative(count);
|
||||
ThrowHelper.ThrowIfLessThan(offset, buffer.GetLowerBound(0));
|
||||
if ((offset + count) > buffer.GetLength(0))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(count));
|
||||
}
|
||||
|
||||
// This is necessary in case _workingBuffer has been resized. (new byte[])
|
||||
// (The first reference to _workingBuffer goes through the private accessor which
|
||||
// may initialize it.)
|
||||
_z.InputBuffer = workingBuffer;
|
||||
|
||||
do
|
||||
{
|
||||
// need data in _workingBuffer in order to deflate/inflate. Here, we check if we have any.
|
||||
if ((_z.AvailableBytesIn == 0) && (!nomoreinput))
|
||||
{
|
||||
// No data available, so try to Read data from the captive stream.
|
||||
_z.NextIn = 0;
|
||||
_z.AvailableBytesIn = _stream.Read(_workingBuffer, 0, _workingBuffer.Length);
|
||||
if (_z.AvailableBytesIn == 0)
|
||||
{
|
||||
nomoreinput = true;
|
||||
}
|
||||
}
|
||||
|
||||
// we have data in InputBuffer; now compress or decompress as appropriate
|
||||
rc = (_wantCompress) ? _z.Deflate(_flushMode) : _z.Inflate(_flushMode);
|
||||
|
||||
if (nomoreinput && (rc == ZlibConstants.Z_BUF_ERROR))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
|
||||
{
|
||||
throw new ZlibException(
|
||||
String.Format(
|
||||
Constants.DefaultCultureInfo,
|
||||
"{0}flating: rc={1} msg={2}",
|
||||
(_wantCompress ? "de" : "in"),
|
||||
rc,
|
||||
_z.Message
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
(nomoreinput || rc == ZlibConstants.Z_STREAM_END) && (_z.AvailableBytesOut == count)
|
||||
)
|
||||
{
|
||||
break; // nothing more to read
|
||||
}
|
||||
} //while (_z.AvailableBytesOut == count && rc == ZlibConstants.Z_OK);
|
||||
while (_z.AvailableBytesOut > 0 && !nomoreinput && rc == ZlibConstants.Z_OK);
|
||||
|
||||
// workitem 8557
|
||||
// is there more room in output?
|
||||
if (_z.AvailableBytesOut > 0)
|
||||
{
|
||||
if (rc == ZlibConstants.Z_OK && _z.AvailableBytesIn == 0)
|
||||
{
|
||||
// deferred
|
||||
}
|
||||
|
||||
// are we completely done reading?
|
||||
if (nomoreinput)
|
||||
{
|
||||
// and in compression?
|
||||
if (_wantCompress)
|
||||
{
|
||||
// no more input data available; therefore we flush to
|
||||
// try to complete the read
|
||||
rc = _z.Deflate(FlushType.Finish);
|
||||
|
||||
if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
|
||||
{
|
||||
throw new ZlibException(
|
||||
String.Format(
|
||||
Constants.DefaultCultureInfo,
|
||||
"Deflating: rc={0} msg={1}",
|
||||
rc,
|
||||
_z.Message
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc = (count - _z.AvailableBytesOut);
|
||||
|
||||
// calculate CRC after reading
|
||||
if (crc != null)
|
||||
{
|
||||
crc.SlurpBlock(buffer, offset, rc);
|
||||
}
|
||||
|
||||
if (rc == ZlibConstants.Z_STREAM_END && z.AvailableBytesIn != 0 && !_wantCompress)
|
||||
{
|
||||
//rewind the buffer
|
||||
this.RewindBytes(z.AvailableBytesIn);
|
||||
z.AvailableBytesIn = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task<int> ReadAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
|
||||
@@ -8,6 +8,10 @@ namespace SharpCompress.Compressors.Deflate;
|
||||
|
||||
public partial class ZlibStream
|
||||
{
|
||||
/// <summary>
|
||||
/// Flush the stream.
|
||||
/// </summary>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task FlushAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_disposed)
|
||||
@@ -33,6 +37,18 @@ public partial class ZlibStream
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Read data from the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A <c>ZlibStream</c> compresses or decompresses according to its
|
||||
/// <c>CompressionMode</c>. It can be used for <c>Read()</c> or <c>Write()</c>, but not both.
|
||||
/// </remarks>
|
||||
/// <param name="buffer">The buffer into which the read data should be placed.</param>
|
||||
/// <param name="offset">The offset within that data array to put the first byte read.</param>
|
||||
/// <param name="count">The number of bytes to read.</param>
|
||||
/// <returns>The number of bytes actually read.</returns>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task<int> ReadAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
@@ -63,6 +79,17 @@ public partial class ZlibStream
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Write data to the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A <c>ZlibStream</c> compresses or decompresses according to its
|
||||
/// <c>CompressionMode</c>. It can be used for <c>Read()</c> or <c>Write()</c>, but not both.
|
||||
/// </remarks>
|
||||
/// <param name="buffer">The buffer holding data to write to the stream.</param>
|
||||
/// <param name="offset">The offset within that data array to find the first byte to write.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task WriteAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Compressors.Deflate;
|
||||
@@ -231,53 +229,6 @@ public partial class ZlibStream : Stream
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush the stream.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException("ZlibStream");
|
||||
}
|
||||
_baseStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read data from the stream.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
///
|
||||
/// <para>
|
||||
/// If you wish to use the <c>ZlibStream</c> to compress data while reading,
|
||||
/// you can create a <c>ZlibStream</c> with <c>CompressionMode.Compress</c>,
|
||||
/// providing an uncompressed data stream. Then call <c>Read()</c> on that
|
||||
/// <c>ZlibStream</c>, and the data read will be compressed. If you wish to
|
||||
/// use the <c>ZlibStream</c> to decompress data while reading, you can create
|
||||
/// a <c>ZlibStream</c> with <c>CompressionMode.Decompress</c>, providing a
|
||||
/// readable compressed data stream. Then call <c>Read()</c> on that
|
||||
/// <c>ZlibStream</c>, and the data will be decompressed as it is read.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// A <c>ZlibStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but
|
||||
/// not both.
|
||||
/// </para>
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="buffer">The buffer into which the read data should be placed.</param>
|
||||
/// <param name="offset">the offset within that data array to put the first byte read.</param>
|
||||
/// <param name="count">the number of bytes to read.</param>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException("ZlibStream");
|
||||
}
|
||||
return _baseStream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
if (_disposed)
|
||||
@@ -297,41 +248,6 @@ public partial class ZlibStream : Stream
|
||||
/// </summary>
|
||||
public override void SetLength(long value) => throw new NotSupportedException();
|
||||
|
||||
/// <summary>
|
||||
/// Write data to the stream.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
///
|
||||
/// <para>
|
||||
/// If you wish to use the <c>ZlibStream</c> to compress data while writing,
|
||||
/// you can create a <c>ZlibStream</c> with <c>CompressionMode.Compress</c>,
|
||||
/// and a writable output stream. Then call <c>Write()</c> on that
|
||||
/// <c>ZlibStream</c>, providing uncompressed data as input. The data sent to
|
||||
/// the output stream will be the compressed form of the data written. If you
|
||||
/// wish to use the <c>ZlibStream</c> to decompress data while writing, you
|
||||
/// can create a <c>ZlibStream</c> with <c>CompressionMode.Decompress</c>, and a
|
||||
/// writable output stream. Then call <c>Write()</c> on that stream,
|
||||
/// providing previously compressed data. The data sent to the output stream
|
||||
/// will be the decompressed form of the data written.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// A <c>ZlibStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not both.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="buffer">The buffer holding data to write to the stream.</param>
|
||||
/// <param name="offset">the offset within that data array to find the first byte to write.</param>
|
||||
/// <param name="count">the number of bytes to write.</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException("ZlibStream");
|
||||
}
|
||||
_baseStream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
if (_disposed)
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace SharpCompress.Compressors.Deflate64;
|
||||
|
||||
public sealed partial class Deflate64Stream
|
||||
{
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task<int> ReadAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
|
||||
@@ -5,10 +5,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Zip;
|
||||
|
||||
namespace SharpCompress.Compressors.Deflate64;
|
||||
|
||||
@@ -69,50 +66,6 @@ public sealed partial class Deflate64Stream : Stream
|
||||
public override void SetLength(long value) =>
|
||||
throw new NotSupportedException("Deflate64: not supported");
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
ValidateParameters(buffer, offset, count);
|
||||
EnsureNotDisposed();
|
||||
|
||||
int bytesRead;
|
||||
var currentOffset = offset;
|
||||
var remainingCount = count;
|
||||
|
||||
while (true)
|
||||
{
|
||||
bytesRead = _inflater.Inflate(buffer, currentOffset, remainingCount);
|
||||
currentOffset += bytesRead;
|
||||
remainingCount -= bytesRead;
|
||||
|
||||
if (remainingCount == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (_inflater.Finished())
|
||||
{
|
||||
// if we finished decompressing, we can't have anything left in the outputwindow.
|
||||
break;
|
||||
}
|
||||
|
||||
var bytes = _stream.Read(_buffer, 0, _buffer.Length);
|
||||
if (bytes <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (bytes > _buffer.Length)
|
||||
{
|
||||
// The stream is either malicious or poorly implemented and returned a number of
|
||||
// bytes larger than the buffer supplied to it.
|
||||
throw new InvalidFormatException("Deflate64: invalid data");
|
||||
}
|
||||
|
||||
_inflater.SetInput(_buffer, 0, bytes);
|
||||
}
|
||||
|
||||
return count - remainingCount;
|
||||
}
|
||||
|
||||
private void ValidateParameters(byte[] array, int offset, int count)
|
||||
{
|
||||
ThrowHelper.ThrowIfNull(array);
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace SharpCompress.Providers;
|
||||
/// };
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
public sealed class CompressionProviderRegistry
|
||||
public sealed partial class CompressionProviderRegistry
|
||||
{
|
||||
/// <summary>
|
||||
/// The default registry using SharpCompress internal implementations.
|
||||
@@ -61,103 +61,11 @@ public sealed class CompressionProviderRegistry
|
||||
/// <param name="type">The compression type.</param>
|
||||
/// <param name="destination">The destination stream.</param>
|
||||
/// <param name="level">The compression level.</param>
|
||||
/// <returns>A compression stream.</returns>
|
||||
/// <exception cref="ArchiveOperationException">If no provider is registered for the type.</exception>
|
||||
/// <exception cref="NotSupportedException">If the provider does not support compression.</exception>
|
||||
public Stream CreateCompressStream(CompressionType type, Stream destination, int level)
|
||||
{
|
||||
var provider = GetProvider(type);
|
||||
if (provider is null)
|
||||
{
|
||||
throw new ArchiveOperationException(
|
||||
$"No compression provider registered for type: {type}"
|
||||
);
|
||||
}
|
||||
return provider.CreateCompressStream(destination, level);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a decompression stream for the specified type.
|
||||
/// </summary>
|
||||
/// <param name="type">The compression type.</param>
|
||||
/// <param name="source">The source stream.</param>
|
||||
/// <returns>A decompression stream.</returns>
|
||||
/// <exception cref="ArchiveOperationException">If no provider is registered for the type.</exception>
|
||||
/// <exception cref="NotSupportedException">If the provider does not support decompression.</exception>
|
||||
public Stream CreateDecompressStream(CompressionType type, Stream source)
|
||||
{
|
||||
var provider = GetProvider(type);
|
||||
if (provider is null)
|
||||
{
|
||||
throw new ArchiveOperationException(
|
||||
$"No compression provider registered for type: {type}"
|
||||
);
|
||||
}
|
||||
return provider.CreateDecompressStream(source);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a compression stream for the specified type with context.
|
||||
/// </summary>
|
||||
/// <param name="type">The compression type.</param>
|
||||
/// <param name="destination">The destination stream.</param>
|
||||
/// <param name="level">The compression level.</param>
|
||||
/// <param name="context">Context information for the compression.</param>
|
||||
/// <returns>A compression stream.</returns>
|
||||
/// <exception cref="ArchiveOperationException">If no provider is registered for the type.</exception>
|
||||
/// <exception cref="NotSupportedException">If the provider does not support compression.</exception>
|
||||
public Stream CreateCompressStream(
|
||||
CompressionType type,
|
||||
Stream destination,
|
||||
int level,
|
||||
CompressionContext context
|
||||
)
|
||||
{
|
||||
var provider = GetProvider(type);
|
||||
if (provider is null)
|
||||
{
|
||||
throw new ArchiveOperationException(
|
||||
$"No compression provider registered for type: {type}"
|
||||
);
|
||||
}
|
||||
return provider.CreateCompressStream(destination, level, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a decompression stream for the specified type with context.
|
||||
/// </summary>
|
||||
/// <param name="type">The compression type.</param>
|
||||
/// <param name="source">The source stream.</param>
|
||||
/// <param name="context">Context information for the decompression.</param>
|
||||
/// <returns>A decompression stream.</returns>
|
||||
/// <exception cref="ArchiveOperationException">If no provider is registered for the type.</exception>
|
||||
/// <exception cref="NotSupportedException">If the provider does not support decompression.</exception>
|
||||
public Stream CreateDecompressStream(
|
||||
CompressionType type,
|
||||
Stream source,
|
||||
CompressionContext context
|
||||
)
|
||||
{
|
||||
var provider = GetProvider(type);
|
||||
if (provider is null)
|
||||
{
|
||||
throw new ArchiveOperationException(
|
||||
$"No compression provider registered for type: {type}"
|
||||
);
|
||||
}
|
||||
return provider.CreateDecompressStream(source, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously creates a compression stream for the specified type.
|
||||
/// </summary>
|
||||
/// <param name="type">The compression type.</param>
|
||||
/// <param name="destination">The destination stream.</param>
|
||||
/// <param name="level">The compression level.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task containing the compression stream.</returns>
|
||||
/// <returns>A compression stream.</returns>
|
||||
/// <exception cref="ArchiveOperationException">If no provider is registered for the type.</exception>
|
||||
/// <exception cref="NotSupportedException">If the provider does not support compression.</exception>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public ValueTask<Stream> CreateCompressStreamAsync(
|
||||
CompressionType type,
|
||||
Stream destination,
|
||||
@@ -176,14 +84,15 @@ public sealed class CompressionProviderRegistry
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously creates a decompression stream for the specified type.
|
||||
/// Creates a decompression stream for the specified type.
|
||||
/// </summary>
|
||||
/// <param name="type">The compression type.</param>
|
||||
/// <param name="source">The source stream.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task containing the decompression stream.</returns>
|
||||
/// <returns>A decompression stream.</returns>
|
||||
/// <exception cref="ArchiveOperationException">If no provider is registered for the type.</exception>
|
||||
/// <exception cref="NotSupportedException">If the provider does not support decompression.</exception>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
CompressionType type,
|
||||
Stream source,
|
||||
@@ -201,16 +110,17 @@ public sealed class CompressionProviderRegistry
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously creates a compression stream for the specified type with context.
|
||||
/// Creates a compression stream for the specified type with context.
|
||||
/// </summary>
|
||||
/// <param name="type">The compression type.</param>
|
||||
/// <param name="destination">The destination stream.</param>
|
||||
/// <param name="level">The compression level.</param>
|
||||
/// <param name="context">Context information for the compression.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task containing the compression stream.</returns>
|
||||
/// <returns>A compression stream.</returns>
|
||||
/// <exception cref="ArchiveOperationException">If no provider is registered for the type.</exception>
|
||||
/// <exception cref="NotSupportedException">If the provider does not support compression.</exception>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public ValueTask<Stream> CreateCompressStreamAsync(
|
||||
CompressionType type,
|
||||
Stream destination,
|
||||
@@ -230,15 +140,16 @@ public sealed class CompressionProviderRegistry
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously creates a decompression stream for the specified type with context.
|
||||
/// Creates a decompression stream for the specified type with context.
|
||||
/// </summary>
|
||||
/// <param name="type">The compression type.</param>
|
||||
/// <param name="source">The source stream.</param>
|
||||
/// <param name="context">Context information for the decompression.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task containing the decompression stream.</returns>
|
||||
/// <returns>A decompression stream.</returns>
|
||||
/// <exception cref="ArchiveOperationException">If no provider is registered for the type.</exception>
|
||||
/// <exception cref="NotSupportedException">If the provider does not support decompression.</exception>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
CompressionType type,
|
||||
Stream source,
|
||||
|
||||
@@ -47,8 +47,9 @@ public partial class ZipWriter
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously writes an entry to the ZIP archive.
|
||||
/// Writes an entry to the ZIP archive.
|
||||
/// </summary>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async ValueTask WriteAsync(
|
||||
string filename,
|
||||
Stream source,
|
||||
@@ -56,7 +57,9 @@ public partial class ZipWriter
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
#if !SYNC_ONLY
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
#endif
|
||||
await WriteAsync(
|
||||
filename,
|
||||
source,
|
||||
@@ -67,8 +70,9 @@ public partial class ZipWriter
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously writes an entry to the ZIP archive with specified options.
|
||||
/// Writes an entry to the ZIP archive with specified options.
|
||||
/// </summary>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public async ValueTask WriteAsync(
|
||||
string entryPath,
|
||||
Stream source,
|
||||
@@ -76,7 +80,9 @@ public partial class ZipWriter
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
#if !SYNC_ONLY
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
#endif
|
||||
await using var output = await WriteToStreamAsync(
|
||||
entryPath,
|
||||
zipWriterEntryOptions,
|
||||
@@ -84,7 +90,9 @@ public partial class ZipWriter
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
var progressStream = WrapWithProgress(source, entryPath);
|
||||
await progressStream.CopyToAsync(output, 81920, cancellationToken).ConfigureAwait(false);
|
||||
await progressStream
|
||||
.CopyToAsync(output, WriterOptions.BufferSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async ValueTask<ZipWritingStream> WriteToStreamAsync(
|
||||
@@ -168,16 +176,18 @@ public partial class ZipWriter
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously writes a directory entry to the ZIP archive.
|
||||
/// Uses synchronous implementation for directory entries as they are lightweight.
|
||||
/// Writes a directory entry to the ZIP archive.
|
||||
/// </summary>
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async ValueTask WriteDirectoryAsync(
|
||||
string directoryName,
|
||||
DateTime? modificationTime,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
#if !SYNC_ONLY
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
#endif
|
||||
|
||||
var normalizedName = NormalizeDirectoryName(directoryName);
|
||||
if (string.IsNullOrEmpty(normalizedName))
|
||||
@@ -190,6 +200,7 @@ public partial class ZipWriter
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
private async ValueTask WriteDirectoryEntryAsync(
|
||||
string directoryPath,
|
||||
ZipWriterEntryOptions options,
|
||||
|
||||
@@ -77,20 +77,6 @@ public partial class ZipWriter : AbstractWriter
|
||||
_ => throw new InvalidFormatException("Invalid compression method: " + compressionType),
|
||||
};
|
||||
|
||||
public override void Write(string filename, Stream source, DateTime? modificationTime) =>
|
||||
Write(
|
||||
filename,
|
||||
source,
|
||||
new ZipWriterEntryOptions() { ModificationDateTime = modificationTime }
|
||||
);
|
||||
|
||||
public void Write(string entryPath, Stream source, ZipWriterEntryOptions zipWriterEntryOptions)
|
||||
{
|
||||
using var output = WriteToStream(entryPath, zipWriterEntryOptions);
|
||||
var progressStream = WrapWithProgress(source, entryPath);
|
||||
progressStream.CopyTo(output, WriterOptions.BufferSize);
|
||||
}
|
||||
|
||||
public Stream WriteToStream(string entryPath, ZipWriterEntryOptions options)
|
||||
{
|
||||
options.ValidateWithFallback(compressionType, compressionLevel);
|
||||
@@ -162,59 +148,6 @@ public partial class ZipWriter : AbstractWriter
|
||||
return directoryName;
|
||||
}
|
||||
|
||||
public override void WriteDirectory(string directoryName, DateTime? modificationTime)
|
||||
{
|
||||
var normalizedName = NormalizeDirectoryName(directoryName);
|
||||
if (string.IsNullOrEmpty(normalizedName))
|
||||
{
|
||||
return; // Skip empty or root directory
|
||||
}
|
||||
|
||||
var options = new ZipWriterEntryOptions { ModificationDateTime = modificationTime };
|
||||
WriteDirectoryEntry(normalizedName, options);
|
||||
}
|
||||
|
||||
// WriteDirectoryAsync moved to ZipWriter.Async.cs
|
||||
|
||||
private void WriteDirectoryEntry(string directoryPath, ZipWriterEntryOptions options)
|
||||
{
|
||||
var compression = ZipCompressionMethod.None;
|
||||
|
||||
options.ModificationDateTime ??= DateTime.Now;
|
||||
options.EntryComment ??= string.Empty;
|
||||
|
||||
var entry = new ZipCentralDirectoryEntry(
|
||||
compression,
|
||||
directoryPath,
|
||||
(ulong)streamPosition,
|
||||
WriterOptions.ArchiveEncoding
|
||||
)
|
||||
{
|
||||
Comment = options.EntryComment,
|
||||
ModificationTime = options.ModificationDateTime,
|
||||
Crc = 0,
|
||||
Compressed = 0,
|
||||
Decompressed = 0,
|
||||
};
|
||||
|
||||
// Use the archive default setting for zip64 and allow overrides
|
||||
var useZip64 = isZip64;
|
||||
if (options.EnableZip64.HasValue)
|
||||
{
|
||||
useZip64 = options.EnableZip64.Value;
|
||||
}
|
||||
|
||||
var headersize = (uint)WriteHeader(
|
||||
directoryPath,
|
||||
options,
|
||||
entry,
|
||||
useZip64,
|
||||
usesDataDescriptor: false
|
||||
);
|
||||
streamPosition += headersize;
|
||||
entries.Add(entry);
|
||||
}
|
||||
|
||||
private int WriteHeader(
|
||||
string filename,
|
||||
ZipWriterEntryOptions zipWriterEntryOptions,
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace SharpCompress.Writers.Zip;
|
||||
|
||||
public partial class ZipWriter
|
||||
{
|
||||
internal class ZipWritingStream : Stream
|
||||
internal partial class ZipWritingStream : Stream
|
||||
{
|
||||
private readonly CRC32 crc = new();
|
||||
private readonly ZipCentralDirectoryEntry entry;
|
||||
@@ -98,114 +98,7 @@ public partial class ZipWriter
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
private Stream GetWriteStream(Stream writeStream)
|
||||
{
|
||||
counting = new CountingStream(SharpCompressStream.CreateNonDisposing(writeStream));
|
||||
Stream output = counting;
|
||||
|
||||
var providers = writer.WriterOptions.Providers;
|
||||
|
||||
switch (zipCompressionMethod)
|
||||
{
|
||||
case ZipCompressionMethod.None:
|
||||
{
|
||||
return output;
|
||||
}
|
||||
case ZipCompressionMethod.Deflate:
|
||||
{
|
||||
return providers.CreateCompressStream(
|
||||
CompressionType.Deflate,
|
||||
counting,
|
||||
compressionLevel
|
||||
);
|
||||
}
|
||||
case ZipCompressionMethod.BZip2:
|
||||
{
|
||||
return providers.CreateCompressStream(
|
||||
CompressionType.BZip2,
|
||||
counting,
|
||||
compressionLevel
|
||||
);
|
||||
}
|
||||
case ZipCompressionMethod.LZMA:
|
||||
{
|
||||
var compressingProvider = providers.GetCompressingProvider(
|
||||
CompressionType.LZMA
|
||||
);
|
||||
if (compressingProvider is null)
|
||||
{
|
||||
throw new ArchiveOperationException("LZMA compression provider not found.");
|
||||
}
|
||||
|
||||
var context = new CompressionContext { CanSeek = originalStream.CanSeek };
|
||||
compressionProviderHooks = compressingProvider;
|
||||
compressionContext = context;
|
||||
|
||||
var preData = compressingProvider.GetPreCompressionData(context);
|
||||
if (preData is not null)
|
||||
{
|
||||
counting.Write(preData, 0, preData.Length);
|
||||
}
|
||||
|
||||
var lzmaStream = compressingProvider.CreateCompressStream(
|
||||
counting,
|
||||
compressionLevel,
|
||||
context
|
||||
);
|
||||
|
||||
var props = compressingProvider.GetCompressionProperties(lzmaStream, context);
|
||||
if (props is not null)
|
||||
{
|
||||
counting.Write(props, 0, props.Length);
|
||||
}
|
||||
|
||||
return lzmaStream;
|
||||
}
|
||||
case ZipCompressionMethod.PPMd:
|
||||
{
|
||||
var compressingProvider = providers.GetCompressingProvider(
|
||||
CompressionType.PPMd
|
||||
);
|
||||
if (compressingProvider is null)
|
||||
{
|
||||
throw new ArchiveOperationException("PPMd compression provider not found.");
|
||||
}
|
||||
|
||||
var context = new CompressionContext
|
||||
{
|
||||
CanSeek = originalStream.CanSeek,
|
||||
FormatOptions = writer.PpmdProperties,
|
||||
};
|
||||
compressionProviderHooks = compressingProvider;
|
||||
compressionContext = context;
|
||||
|
||||
var preData = compressingProvider.GetPreCompressionData(context);
|
||||
if (preData is not null)
|
||||
{
|
||||
counting.Write(preData, 0, preData.Length);
|
||||
}
|
||||
|
||||
return compressingProvider.CreateCompressStream(
|
||||
counting,
|
||||
compressionLevel,
|
||||
context
|
||||
);
|
||||
}
|
||||
case ZipCompressionMethod.ZStandard:
|
||||
{
|
||||
return providers.CreateCompressStream(
|
||||
CompressionType.ZStandard,
|
||||
counting,
|
||||
compressionLevel
|
||||
);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException("CompressionMethod: " + zipCompressionMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
private async ValueTask<Stream> GetWriteStreamAsync(
|
||||
Stream writeStream,
|
||||
CancellationToken cancellationToken
|
||||
@@ -459,17 +352,7 @@ public partial class ZipWriter
|
||||
|
||||
public override void SetLength(long value) => throw new NotSupportedException();
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
CheckWriteLimits(count);
|
||||
|
||||
decompressed += (uint)count;
|
||||
crc.SlurpBlock(buffer, offset, count);
|
||||
writeStream.Write(buffer, offset, count);
|
||||
|
||||
CheckPostWriteLimits();
|
||||
}
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
public override async Task WriteAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
@@ -477,7 +360,9 @@ public partial class ZipWriter
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
#if !SYNC_ONLY
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
#endif
|
||||
CheckWriteLimits(count);
|
||||
|
||||
decompressed += (uint)count;
|
||||
@@ -556,30 +441,7 @@ public partial class ZipWriter
|
||||
}
|
||||
}
|
||||
|
||||
private void WritePostCompressionData()
|
||||
{
|
||||
if (
|
||||
compressionProviderHooks is null
|
||||
|| compressionContext is null
|
||||
|| counting is null
|
||||
|| zipCompressionMethod == ZipCompressionMethod.None
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var postData = compressionProviderHooks.GetPostCompressionData(
|
||||
writeStream,
|
||||
compressionContext
|
||||
);
|
||||
if (postData is null || postData.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
counting.Write(postData, 0, postData.Length);
|
||||
}
|
||||
|
||||
[Zomp.SyncMethodGenerator.CreateSyncVersion]
|
||||
private async ValueTask WritePostCompressionDataAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (
|
||||
|
||||
@@ -538,4 +538,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +235,21 @@ public class OptionsUsabilityTests : TestBase
|
||||
Assert.Equal(23, source.CopyBufferSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ZipWriter_Uses_WriterOptions_BufferSize_Async()
|
||||
{
|
||||
await using var source = new TrackingReadStream(new byte[100]);
|
||||
await using var destination = new MemoryStream();
|
||||
await using var writer = new ZipWriter(
|
||||
destination,
|
||||
new ZipWriterOptions(CompressionType.None) { BufferSize = 29 }
|
||||
);
|
||||
|
||||
await writer.WriteAsync("buffer-size.txt", source, DateTime.Now);
|
||||
|
||||
Assert.Equal(29, source.CopyBufferSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TarWriter_Uses_WriterOptions_BufferSize_ForTransfer()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user