mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-13 21:22:22 +00:00
Compare commits
4 Commits
master
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c825ae91a1 | ||
|
|
6478723a8d | ||
|
|
2c7e9b9c21 | ||
|
|
7f3da598d1 |
4
.github/workflows/nuget-release.yml
vendored
4
.github/workflows/nuget-release.yml
vendored
@@ -53,9 +53,9 @@ jobs:
|
||||
name: ${{ matrix.os }}-nuget-package
|
||||
path: artifacts/*.nupkg
|
||||
|
||||
# Push to NuGet.org only for version tag pushes (Windows only)
|
||||
# Push to NuGet.org using C# build target (Windows only, not on PRs)
|
||||
- name: Push to NuGet
|
||||
if: success() && matrix.os == 'windows-latest' && startsWith(github.ref, 'refs/tags/')
|
||||
if: success() && matrix.os == 'windows-latest' && github.event_name != 'pull_request'
|
||||
run: dotnet run --project build/build.csproj -- push-to-nuget
|
||||
env:
|
||||
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
|
||||
|
||||
15
AGENTS.md
15
AGENTS.md
@@ -103,11 +103,8 @@ tests/
|
||||
### Factory Pattern
|
||||
Factory implementations can implement one or more interfaces (`IArchiveFactory`, `IReaderFactory`, `IWriterFactory`) depending on format capabilities:
|
||||
- `ArchiveFactory.OpenArchive()` - Opens archive API objects from seekable streams/files
|
||||
- `ArchiveFactory.OpenAsyncArchive()` - Opens async archive API objects for async archive use cases
|
||||
- `ReaderFactory.OpenReader()` - Auto-detects and opens forward-only readers
|
||||
- `ReaderFactory.OpenAsyncReader()` - Auto-detects and opens forward-only async readers
|
||||
- `WriterFactory.OpenWriter()` - Creates a writer for a specified `ArchiveType`
|
||||
- `WriterFactory.OpenAsyncWriter()` - Creates an async writer for async write scenarios
|
||||
- Factories located in: `src/SharpCompress/Factories/`
|
||||
|
||||
## Nullable Reference Types
|
||||
@@ -135,9 +132,6 @@ SharpCompress supports multiple archive and compression formats:
|
||||
### Async/Await Patterns
|
||||
- All I/O operations support async/await with `CancellationToken`
|
||||
- Async methods follow the naming convention: `MethodNameAsync`
|
||||
- For async archive scenarios, prefer `ArchiveFactory.OpenAsyncArchive(...)` over sync `OpenArchive(...)`.
|
||||
- For async forward-only read scenarios, prefer `ReaderFactory.OpenAsyncReader(...)` over sync `OpenReader(...)`.
|
||||
- For async write scenarios, prefer `WriterFactory.OpenAsyncWriter(...)` over sync `OpenWriter(...)`.
|
||||
- Key async methods:
|
||||
- `WriteEntryToAsync` - Extract entry asynchronously
|
||||
- `WriteAllToDirectoryAsync` - Extract all entries asynchronously
|
||||
@@ -205,8 +199,7 @@ SharpCompress supports multiple archive and compression formats:
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Don't mix Archive and Reader APIs** - Archive needs seekable stream, Reader doesn't
|
||||
2. **Don't mix sync and async open paths** - For async workflows use `OpenAsyncArchive`/`OpenAsyncReader`/`OpenAsyncWriter`, not `OpenArchive`/`OpenReader`/`OpenWriter`
|
||||
3. **Solid archives (Rar, 7Zip)** - Use `ExtractAllEntries()` for best performance, not individual entry extraction
|
||||
4. **Stream disposal** - Always set `LeaveStreamOpen` explicitly when needed (default is to close)
|
||||
5. **Tar + non-seekable stream** - Must provide file size or it will throw
|
||||
6. **Format detection** - Use `ReaderFactory.OpenReader()` / `ReaderFactory.OpenAsyncReader()` for auto-detection, test with actual archive files
|
||||
2. **Solid archives (Rar, 7Zip)** - Use `ExtractAllEntries()` for best performance, not individual entry extraction
|
||||
3. **Stream disposal** - Always set `LeaveStreamOpen` explicitly when needed (default is to close)
|
||||
4. **Tar + non-seekable stream** - Must provide file size or it will throw
|
||||
5. **Format detection** - Use `ReaderFactory.OpenReader()` for auto-detection, test with actual archive files
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<PackageVersion Include="AwesomeAssertions" Version="9.3.0" />
|
||||
<PackageVersion Include="Glob" Version="1.1.9" />
|
||||
<PackageVersion Include="JetBrains.Profiler.SelfApi" Version="2.5.16" />
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.0" />
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||
<PackageVersion Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
||||
<PackageVersion Include="SimpleExec" Version="13.0.0" />
|
||||
|
||||
@@ -16,10 +16,6 @@ Post Issues on Github!
|
||||
|
||||
Check the [Supported Formats](docs/FORMATS.md) and [Basic Usage.](docs/USAGE.md)
|
||||
|
||||
## Custom Compression Providers
|
||||
|
||||
If you need to swap out SharpCompress’s built-in codecs, the `Providers` property (and `WithProviders(...)` extensions) on `ReaderOptions` and `WriterOptions` lets you supply a `CompressionProviderRegistry`. The selected registry is used by Reader/Writer APIs, Archive APIs, and async extraction paths, so the same provider choice is applied consistently across open/read/write flows. The default registry is already wired up, so customization is only necessary when you want to plug in alternatives such as `SystemGZipCompressionProvider` or a third-party `CompressionProvider`. See [docs/USAGE.md#custom-compression-providers](docs/USAGE.md#custom-compression-providers) for guided examples.
|
||||
|
||||
## Recommended Formats
|
||||
|
||||
In general, I recommend GZip (Deflate)/BZip2 (BZip)/LZip (LZMA) as the simplicity of the formats lend to better long term archival as well as the streamability. Tar is often used in conjunction for multiple files in a single archive (e.g. `.tar.gz`)
|
||||
|
||||
24
docs/API.md
24
docs/API.md
@@ -95,7 +95,7 @@ using (var archive = ZipArchive.OpenArchive("file.zip"))
|
||||
}
|
||||
|
||||
// Async extraction (requires IAsyncArchive)
|
||||
await using (var asyncArchive = await ZipArchive.OpenAsyncArchive("file.zip"))
|
||||
using (var asyncArchive = await ZipArchive.OpenAsyncArchive("file.zip"))
|
||||
{
|
||||
await asyncArchive.WriteToDirectoryAsync(
|
||||
@"C:\output",
|
||||
@@ -177,7 +177,7 @@ using (var reader = ReaderFactory.OpenReader(stream))
|
||||
|
||||
// Async variants (use OpenAsyncReader to get IAsyncReader)
|
||||
using (var stream = File.OpenRead("file.zip"))
|
||||
await using (var reader = await ReaderFactory.OpenAsyncReader(stream))
|
||||
using (var reader = await ReaderFactory.OpenAsyncReader(stream))
|
||||
{
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
@@ -318,24 +318,6 @@ WriterOptions: write-time behavior (compression type/level, encoding, stream own
|
||||
ZipWriterEntryOptions: per-entry ZIP overrides (compression, level, timestamps, comments, zip64)
|
||||
```
|
||||
|
||||
### Compression Providers
|
||||
|
||||
`ReaderOptions` and `WriterOptions` expose a `Providers` registry that controls which `ICompressionProvider` implementations are used for each `CompressionType`. The registry defaults to `CompressionProviderRegistry.Default`, so you only need to set it if you want to swap in a custom provider (for example the `SystemGZipCompressionProvider`). The selected registry is honored by Reader/Writer APIs, Archive APIs, and async entry-stream extraction paths.
|
||||
|
||||
```csharp
|
||||
var registry = CompressionProviderRegistry.Default.With(new SystemGZipCompressionProvider());
|
||||
var readerOptions = ReaderOptions.ForOwnedFile().WithProviders(registry);
|
||||
var writerOptions = new WriterOptions(CompressionType.GZip)
|
||||
{
|
||||
CompressionLevel = 6,
|
||||
}.WithProviders(registry);
|
||||
|
||||
using var reader = ReaderFactory.OpenReader(input, readerOptions);
|
||||
using var writer = WriterFactory.OpenWriter(output, ArchiveType.GZip, writerOptions);
|
||||
```
|
||||
|
||||
When a format needs additional initialization/finalization data (LZMA, PPMd, etc.) the registry exposes `GetCompressingProvider` which returns the `ICompressionProviderHooks` contract; the rest of the API continues to flow through `Providers`, including pre/properties/post compression hook data.
|
||||
|
||||
---
|
||||
|
||||
## Compression Types
|
||||
@@ -427,7 +409,7 @@ cts.CancelAfter(TimeSpan.FromMinutes(5));
|
||||
|
||||
try
|
||||
{
|
||||
await using (var archive = await ZipArchive.OpenAsyncArchive("archive.zip"))
|
||||
using (var archive = await ZipArchive.OpenAsyncArchive("archive.zip"))
|
||||
{
|
||||
await archive.WriteToDirectoryAsync(
|
||||
@"C:\output",
|
||||
|
||||
@@ -206,29 +206,6 @@ foreach(var entry in archive.Entries)
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Compression Providers
|
||||
|
||||
By default `ReaderOptions` and `WriterOptions` already include `CompressionProviderRegistry.Default` via their `Providers` property, so you can read and write without touching the registry yet still get SharpCompress’s built-in implementations.
|
||||
|
||||
The configured registry is used consistently across Reader APIs, Writer APIs, Archive APIs, and async entry-stream extraction, including compressed TAR wrappers and ZIP async decompression.
|
||||
|
||||
To replace a specific algorithm (for example to use `System.IO.Compression` for GZip or Deflate), create a modified registry and pass it through the same options:
|
||||
|
||||
```C#
|
||||
var systemGZip = new SystemGZipCompressionProvider();
|
||||
var customRegistry = CompressionProviderRegistry.Default.With(systemGZip);
|
||||
|
||||
var readerOptions = ReaderOptions.ForOwnedFile()
|
||||
.WithProviders(customRegistry);
|
||||
using var reader = ReaderFactory.OpenReader(stream, readerOptions);
|
||||
|
||||
var writerOptions = new WriterOptions(CompressionType.GZip)
|
||||
.WithProviders(customRegistry);
|
||||
using var writer = WriterFactory.OpenWriter(outputStream, ArchiveType.GZip, writerOptions);
|
||||
```
|
||||
|
||||
The registry also exposes `GetCompressingProvider` (now returning `ICompressionProviderHooks`) when a compression format needs pre- or post-stream data (e.g., LZMA/PPMd). Implementations that need extra headers can supply those bytes through the `ICompressionProviderHooks` members while the rest of the API still works through the `Providers` property.
|
||||
|
||||
## Async Examples
|
||||
|
||||
### Async Reader Examples
|
||||
|
||||
@@ -22,9 +22,7 @@ public static partial class ArchiveFactory
|
||||
readerOptions ??= ReaderOptions.ForExternalStream;
|
||||
var factory = await FindFactoryAsync<IArchiveFactory>(stream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return await factory
|
||||
.OpenAsyncArchive(stream, readerOptions, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return factory.OpenAsyncArchive(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
@@ -47,9 +45,7 @@ public static partial class ArchiveFactory
|
||||
|
||||
var factory = await FindFactoryAsync<IArchiveFactory>(fileInfo, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return await factory
|
||||
.OpenAsyncArchive(fileInfo, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return factory.OpenAsyncArchive(fileInfo, options);
|
||||
}
|
||||
|
||||
public static async ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
|
||||
@@ -2,9 +2,12 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Factories;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
|
||||
@@ -77,7 +77,7 @@ public partial class GZipArchive
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return new((IAsyncReader)GZipReader.OpenReader(stream, ReaderOptions));
|
||||
return new((IAsyncReader)GZipReader.OpenReader(stream));
|
||||
}
|
||||
|
||||
protected override async IAsyncEnumerable<GZipArchiveEntry> LoadEntriesAsync(
|
||||
@@ -88,7 +88,7 @@ public partial class GZipArchive
|
||||
yield return new GZipArchiveEntry(
|
||||
this,
|
||||
await GZipFilePart
|
||||
.CreateAsync(stream, ReaderOptions.ArchiveEncoding, ReaderOptions.Providers)
|
||||
.CreateAsync(stream, ReaderOptions.ArchiveEncoding)
|
||||
.ConfigureAwait(false),
|
||||
ReaderOptions
|
||||
);
|
||||
|
||||
@@ -20,15 +20,14 @@ public partial class GZipArchive
|
||||
>
|
||||
#endif
|
||||
{
|
||||
public static ValueTask<IWritableAsyncArchive<GZipWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return OpenAsyncArchive(new FileInfo(path), readerOptions, cancellationToken);
|
||||
return (IWritableAsyncArchive<GZipWriterOptions>)
|
||||
OpenArchive(new FileInfo(path), readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
public static IWritableArchive<GZipWriterOptions> OpenArchive(
|
||||
@@ -104,50 +103,30 @@ public partial class GZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<GZipWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(stream, readerOptions));
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(stream, readerOptions);
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<GZipWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(fileInfo, readerOptions));
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<GZipWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(streams, readerOptions));
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(streams, readerOptions);
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<GZipWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(fileInfos, readerOptions));
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(fileInfos, readerOptions);
|
||||
|
||||
public static IWritableArchive<GZipWriterOptions> CreateArchive() => new GZipArchive();
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<GZipWriterOptions>> CreateAsyncArchive() =>
|
||||
new(new GZipArchive());
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> CreateAsyncArchive() =>
|
||||
new GZipArchive();
|
||||
|
||||
public static bool IsGZipFile(string filePath) => IsGZipFile(new FileInfo(filePath));
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ public partial class GZipArchive
|
||||
var stream = volumes.Single().Stream;
|
||||
yield return new GZipArchiveEntry(
|
||||
this,
|
||||
GZipFilePart.Create(stream, ReaderOptions.ArchiveEncoding, ReaderOptions.Providers),
|
||||
GZipFilePart.Create(stream, ReaderOptions.ArchiveEncoding),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
@@ -96,6 +96,6 @@ public partial class GZipArchive
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return GZipReader.OpenReader(stream, ReaderOptions);
|
||||
return GZipReader.OpenReader(stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,20 +24,10 @@ public class GZipArchiveEntry : GZipEntry, IArchiveEntry
|
||||
return Parts.Single().GetCompressedStream().NotNull();
|
||||
}
|
||||
|
||||
public async ValueTask<Stream> OpenEntryStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public ValueTask<Stream> OpenEntryStreamAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Reset the stream position if seekable
|
||||
var part = (GZipFilePart)Parts.Single();
|
||||
var rawStream = part.GetRawStream();
|
||||
if (rawStream.CanSeek && rawStream.Position != part.EntryStartPosition)
|
||||
{
|
||||
rawStream.Position = part.EntryStartPosition;
|
||||
}
|
||||
return (
|
||||
await Parts.Single().GetCompressedStreamAsync(cancellationToken).ConfigureAwait(false)
|
||||
).NotNull();
|
||||
// GZip synchronous implementation is fast enough, just wrap it
|
||||
return new(OpenEntryStream());
|
||||
}
|
||||
|
||||
#region IArchiveEntry Members
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Factories;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
@@ -33,13 +32,7 @@ public interface IArchiveFactory : IFactory
|
||||
/// </summary>
|
||||
/// <param name="stream">An open, readable and seekable stream.</param>
|
||||
/// <param name="readerOptions">reading options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> containing the opened async archive.</returns>
|
||||
ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null);
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
@@ -54,10 +47,5 @@ public interface IArchiveFactory : IFactory
|
||||
/// <param name="fileInfo">the file to open.</param>
|
||||
/// <param name="readerOptions">reading options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> containing the opened async archive.</returns>
|
||||
ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#if NET8_0_OR_GREATER
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
@@ -19,22 +18,19 @@ public interface IArchiveOpenable<TSync, TASync>
|
||||
|
||||
public static abstract TSync OpenArchive(Stream stream, ReaderOptions? readerOptions = null);
|
||||
|
||||
public static abstract ValueTask<TASync> OpenAsyncArchive(
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
|
||||
public static abstract ValueTask<TASync> OpenAsyncArchive(
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
|
||||
public static abstract ValueTask<TASync> OpenAsyncArchive(
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
@@ -21,16 +20,14 @@ public interface IMultiArchiveOpenable<TSync, TASync>
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
|
||||
public static abstract ValueTask<TASync> OpenAsyncArchive(
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
|
||||
public static abstract ValueTask<TASync> OpenAsyncArchive(
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
@@ -9,6 +8,6 @@ public interface IWritableArchiveOpenable<TOptions>
|
||||
where TOptions : IWriterOptions
|
||||
{
|
||||
public static abstract IWritableArchive<TOptions> CreateArchive();
|
||||
public static abstract ValueTask<IWritableAsyncArchive<TOptions>> CreateAsyncArchive();
|
||||
public static abstract IWritableAsyncArchive<TOptions> CreateAsyncArchive();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -20,15 +20,13 @@ public partial class RarArchive
|
||||
IMultiArchiveOpenable<IRarArchive, IRarAsyncArchive>
|
||||
#endif
|
||||
{
|
||||
public static ValueTask<IRarAsyncArchive> OpenAsyncArchive(
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return new((IRarAsyncArchive)OpenArchive(new FileInfo(path), readerOptions));
|
||||
return (IRarAsyncArchive)OpenArchive(new FileInfo(path), readerOptions);
|
||||
}
|
||||
|
||||
public static IRarArchive OpenArchive(string filePath, ReaderOptions? options = null)
|
||||
@@ -100,44 +98,36 @@ public partial class RarArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static ValueTask<IRarAsyncArchive> OpenAsyncArchive(
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IRarAsyncArchive)OpenArchive(stream, readerOptions));
|
||||
return (IRarAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IRarAsyncArchive> OpenAsyncArchive(
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IRarAsyncArchive)OpenArchive(fileInfo, readerOptions));
|
||||
return (IRarAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IRarAsyncArchive> OpenAsyncArchive(
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IRarAsyncArchive)OpenArchive(streams, readerOptions));
|
||||
return (IRarAsyncArchive)OpenArchive(streams, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IRarAsyncArchive> OpenAsyncArchive(
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IRarAsyncArchive)OpenArchive(fileInfos, readerOptions));
|
||||
return (IRarAsyncArchive)OpenArchive(fileInfos, readerOptions);
|
||||
}
|
||||
|
||||
public static bool IsRarFile(string filePath) => IsRarFile(new FileInfo(filePath));
|
||||
|
||||
@@ -16,17 +16,10 @@ public partial class SevenZipArchive
|
||||
IMultiArchiveOpenable<IArchive, IAsyncArchive>
|
||||
#endif
|
||||
{
|
||||
public static ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncArchive OpenAsyncArchive(string path, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty("path");
|
||||
return new(
|
||||
(IAsyncArchive)OpenArchive(new FileInfo(path), readerOptions ?? new ReaderOptions())
|
||||
);
|
||||
return (IAsyncArchive)OpenArchive(new FileInfo(path), readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
public static IArchive OpenArchive(string filePath, ReaderOptions? readerOptions = null)
|
||||
@@ -93,44 +86,33 @@ public partial class SevenZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(stream, readerOptions));
|
||||
return (IAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
public static IAsyncArchive OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(fileInfo, readerOptions));
|
||||
return (IAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
public static IAsyncArchive OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(streams, readerOptions));
|
||||
return (IAsyncArchive)OpenArchive(streams, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
public static IAsyncArchive OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(fileInfos, readerOptions));
|
||||
return (IAsyncArchive)OpenArchive(fileInfos, readerOptions);
|
||||
}
|
||||
|
||||
public static bool IsSevenZipFile(string filePath) => IsSevenZipFile(new FileInfo(filePath));
|
||||
|
||||
@@ -89,32 +89,26 @@ public partial class TarArchive
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return new((IAsyncReader)new TarReader(stream, ReaderOptions, _compressionType));
|
||||
return new((IAsyncReader)TarReader.OpenReader(stream));
|
||||
}
|
||||
|
||||
protected override async IAsyncEnumerable<TarArchiveEntry> LoadEntriesAsync(
|
||||
IAsyncEnumerable<TarVolume> volumes
|
||||
)
|
||||
{
|
||||
var sourceStream = (await volumes.SingleAsync().ConfigureAwait(false)).Stream;
|
||||
var stream = await GetStreamAsync(sourceStream).ConfigureAwait(false);
|
||||
var stream = (await volumes.SingleAsync().ConfigureAwait(false)).Stream;
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
stream.Position = 0;
|
||||
}
|
||||
|
||||
var streamingMode =
|
||||
_compressionType == CompressionType.None
|
||||
? StreamingMode.Seekable
|
||||
: StreamingMode.Streaming;
|
||||
|
||||
// Always use async header reading in LoadEntriesAsync for consistency
|
||||
{
|
||||
// Use async header reading for async-only streams
|
||||
TarHeader? previousHeader = null;
|
||||
await foreach (
|
||||
var header in TarHeaderFactory.ReadHeaderAsync(
|
||||
streamingMode,
|
||||
StreamingMode.Seekable,
|
||||
stream,
|
||||
ReaderOptions.ArchiveEncoding
|
||||
)
|
||||
@@ -132,10 +126,7 @@ public partial class TarArchive
|
||||
{
|
||||
var entry = new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(
|
||||
previousHeader,
|
||||
_compressionType == CompressionType.None ? stream : null
|
||||
),
|
||||
new TarFilePart(previousHeader, stream),
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
@@ -160,10 +151,7 @@ public partial class TarArchive
|
||||
}
|
||||
yield return new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(
|
||||
header,
|
||||
_compressionType == CompressionType.None ? stream : null
|
||||
),
|
||||
new TarFilePart(header, stream),
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.Factories;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Writers.Tar;
|
||||
@@ -38,9 +37,12 @@ public partial class TarArchive
|
||||
)
|
||||
{
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
return OpenArchive(
|
||||
[fileInfo],
|
||||
readerOptions ?? new ReaderOptions() { LeaveStreamOpen = false }
|
||||
return new TarArchive(
|
||||
new SourceStream(
|
||||
fileInfo,
|
||||
i => ArchiveVolumeFactory.GetFilePart(i, fileInfo),
|
||||
readerOptions ?? new ReaderOptions() { LeaveStreamOpen = false }
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -51,17 +53,13 @@ public partial class TarArchive
|
||||
{
|
||||
fileInfos.NotNull(nameof(fileInfos));
|
||||
var files = fileInfos.ToArray();
|
||||
var sourceStream = new SourceStream(
|
||||
files[0],
|
||||
i => i < files.Length ? files[i] : null,
|
||||
readerOptions ?? new ReaderOptions() { LeaveStreamOpen = false }
|
||||
return new TarArchive(
|
||||
new SourceStream(
|
||||
files[0],
|
||||
i => i < files.Length ? files[i] : null,
|
||||
readerOptions ?? new ReaderOptions() { LeaveStreamOpen = false }
|
||||
)
|
||||
);
|
||||
var compressionType = TarFactory.GetCompressionType(
|
||||
sourceStream,
|
||||
sourceStream.ReaderOptions.Providers
|
||||
);
|
||||
sourceStream.Seek(0, SeekOrigin.Begin);
|
||||
return new TarArchive(sourceStream, compressionType);
|
||||
}
|
||||
|
||||
public static IWritableArchive<TarWriterOptions> OpenArchive(
|
||||
@@ -71,17 +69,13 @@ public partial class TarArchive
|
||||
{
|
||||
streams.NotNull(nameof(streams));
|
||||
var strms = streams.ToArray();
|
||||
var sourceStream = new SourceStream(
|
||||
strms[0],
|
||||
i => i < strms.Length ? strms[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
return new TarArchive(
|
||||
new SourceStream(
|
||||
strms[0],
|
||||
i => i < strms.Length ? strms[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
var compressionType = TarFactory.GetCompressionType(
|
||||
sourceStream,
|
||||
sourceStream.ReaderOptions.Providers
|
||||
);
|
||||
sourceStream.Seek(0, SeekOrigin.Begin);
|
||||
return new TarArchive(sourceStream, compressionType);
|
||||
}
|
||||
|
||||
public static IWritableArchive<TarWriterOptions> OpenArchive(
|
||||
@@ -96,113 +90,35 @@ public partial class TarArchive
|
||||
throw new ArgumentException("Stream must be seekable", nameof(stream));
|
||||
}
|
||||
|
||||
return OpenArchive([stream], readerOptions);
|
||||
return new TarArchive(
|
||||
new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())
|
||||
);
|
||||
}
|
||||
|
||||
public static async ValueTask<IWritableAsyncArchive<TarWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
stream.NotNull(nameof(stream));
|
||||
var sourceStream = new SourceStream(
|
||||
stream,
|
||||
i => null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
);
|
||||
var compressionType = await TarFactory
|
||||
.GetCompressionTypeAsync(
|
||||
sourceStream,
|
||||
sourceStream.ReaderOptions.Providers,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
sourceStream.Seek(0, SeekOrigin.Begin);
|
||||
return new TarArchive(sourceStream, compressionType);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(stream, readerOptions);
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<TarWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return OpenAsyncArchive(new FileInfo(path), readerOptions, cancellationToken);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(new FileInfo(path), readerOptions);
|
||||
|
||||
public static async ValueTask<IWritableAsyncArchive<TarWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
readerOptions ??= new ReaderOptions() { LeaveStreamOpen = false };
|
||||
var sourceStream = new SourceStream(fileInfo, i => null, readerOptions);
|
||||
var compressionType = await TarFactory
|
||||
.GetCompressionTypeAsync(
|
||||
sourceStream,
|
||||
sourceStream.ReaderOptions.Providers,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
sourceStream.Seek(0, SeekOrigin.Begin);
|
||||
return new TarArchive(sourceStream, compressionType);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
public static async ValueTask<IWritableAsyncArchive<TarWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
streams.NotNull(nameof(streams));
|
||||
var strms = streams.ToArray();
|
||||
var sourceStream = new SourceStream(
|
||||
strms[0],
|
||||
i => i < strms.Length ? strms[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
);
|
||||
var compressionType = await TarFactory
|
||||
.GetCompressionTypeAsync(
|
||||
sourceStream,
|
||||
sourceStream.ReaderOptions.Providers,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
sourceStream.Seek(0, SeekOrigin.Begin);
|
||||
return new TarArchive(sourceStream, compressionType);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(streams, readerOptions);
|
||||
|
||||
public static async ValueTask<IWritableAsyncArchive<TarWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
fileInfos.NotNull(nameof(fileInfos));
|
||||
var files = fileInfos.ToArray();
|
||||
var sourceStream = new SourceStream(
|
||||
files[0],
|
||||
i => i < files.Length ? files[i] : null,
|
||||
readerOptions ?? new ReaderOptions() { LeaveStreamOpen = false }
|
||||
);
|
||||
var compressionType = await TarFactory
|
||||
.GetCompressionTypeAsync(
|
||||
sourceStream,
|
||||
sourceStream.ReaderOptions.Providers,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
sourceStream.Seek(0, SeekOrigin.Begin);
|
||||
return new TarArchive(sourceStream, compressionType);
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(fileInfos, readerOptions);
|
||||
|
||||
public static bool IsTarFile(string filePath) => IsTarFile(new FileInfo(filePath));
|
||||
|
||||
@@ -267,6 +183,5 @@ public partial class TarArchive
|
||||
|
||||
public static IWritableArchive<TarWriterOptions> CreateArchive() => new TarArchive();
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<TarWriterOptions>> CreateAsyncArchive() =>
|
||||
new(new TarArchive());
|
||||
public static IWritableAsyncArchive<TarWriterOptions> CreateAsyncArchive() => new TarArchive();
|
||||
}
|
||||
|
||||
@@ -5,113 +5,35 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Tar;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Providers;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Tar;
|
||||
using SharpCompress.Writers;
|
||||
using SharpCompress.Writers.Tar;
|
||||
using Constants = SharpCompress.Common.Constants;
|
||||
|
||||
namespace SharpCompress.Archives.Tar;
|
||||
|
||||
public partial class TarArchive
|
||||
: AbstractWritableArchive<TarArchiveEntry, TarVolume, TarWriterOptions>
|
||||
{
|
||||
private readonly CompressionType _compressionType;
|
||||
|
||||
protected override IEnumerable<TarVolume> LoadVolumes(SourceStream sourceStream)
|
||||
{
|
||||
sourceStream.NotNull("SourceStream is null").LoadAllParts();
|
||||
return new TarVolume(sourceStream, ReaderOptions, 1).AsEnumerable();
|
||||
}
|
||||
|
||||
internal TarArchive(SourceStream sourceStream, CompressionType compressionType)
|
||||
: base(ArchiveType.Tar, sourceStream)
|
||||
{
|
||||
_compressionType = compressionType;
|
||||
}
|
||||
private TarArchive(SourceStream sourceStream)
|
||||
: base(ArchiveType.Tar, sourceStream) { }
|
||||
|
||||
private TarArchive()
|
||||
: base(ArchiveType.Tar) { }
|
||||
|
||||
private Stream GetStream(Stream stream) =>
|
||||
_compressionType switch
|
||||
{
|
||||
CompressionType.BZip2 => ReaderOptions.Providers.CreateDecompressStream(
|
||||
CompressionType.BZip2,
|
||||
stream
|
||||
),
|
||||
CompressionType.GZip => ReaderOptions.Providers.CreateDecompressStream(
|
||||
CompressionType.GZip,
|
||||
stream,
|
||||
CompressionContext.FromStream(stream).WithReaderOptions(ReaderOptions)
|
||||
),
|
||||
CompressionType.ZStandard => ReaderOptions.Providers.CreateDecompressStream(
|
||||
CompressionType.ZStandard,
|
||||
stream
|
||||
),
|
||||
CompressionType.LZip => ReaderOptions.Providers.CreateDecompressStream(
|
||||
CompressionType.LZip,
|
||||
stream
|
||||
),
|
||||
CompressionType.Xz => ReaderOptions.Providers.CreateDecompressStream(
|
||||
CompressionType.Xz,
|
||||
stream
|
||||
),
|
||||
CompressionType.Lzw => ReaderOptions.Providers.CreateDecompressStream(
|
||||
CompressionType.Lzw,
|
||||
stream
|
||||
),
|
||||
CompressionType.None => stream,
|
||||
_ => throw new NotSupportedException("Invalid compression type: " + _compressionType),
|
||||
};
|
||||
|
||||
private ValueTask<Stream> GetStreamAsync(
|
||||
Stream stream,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
_compressionType switch
|
||||
{
|
||||
CompressionType.BZip2 => ReaderOptions.Providers.CreateDecompressStreamAsync(
|
||||
CompressionType.BZip2,
|
||||
stream,
|
||||
cancellationToken
|
||||
),
|
||||
CompressionType.GZip => ReaderOptions.Providers.CreateDecompressStreamAsync(
|
||||
CompressionType.GZip,
|
||||
stream,
|
||||
CompressionContext.FromStream(stream).WithReaderOptions(ReaderOptions),
|
||||
cancellationToken
|
||||
),
|
||||
CompressionType.ZStandard => ReaderOptions.Providers.CreateDecompressStreamAsync(
|
||||
CompressionType.ZStandard,
|
||||
stream,
|
||||
cancellationToken
|
||||
),
|
||||
CompressionType.LZip => ReaderOptions.Providers.CreateDecompressStreamAsync(
|
||||
CompressionType.LZip,
|
||||
stream,
|
||||
cancellationToken
|
||||
),
|
||||
CompressionType.Xz => ReaderOptions.Providers.CreateDecompressStreamAsync(
|
||||
CompressionType.Xz,
|
||||
stream,
|
||||
cancellationToken
|
||||
),
|
||||
CompressionType.Lzw => ReaderOptions.Providers.CreateDecompressStreamAsync(
|
||||
CompressionType.Lzw,
|
||||
stream,
|
||||
cancellationToken
|
||||
),
|
||||
CompressionType.None => new ValueTask<Stream>(stream),
|
||||
_ => throw new NotSupportedException("Invalid compression type: " + _compressionType),
|
||||
};
|
||||
|
||||
protected override IEnumerable<TarArchiveEntry> LoadEntries(IEnumerable<TarVolume> volumes)
|
||||
{
|
||||
var stream = GetStream(volumes.Single().Stream);
|
||||
var stream = volumes.Single().Stream;
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
stream.Position = 0;
|
||||
@@ -119,9 +41,7 @@ public partial class TarArchive
|
||||
TarHeader? previousHeader = null;
|
||||
foreach (
|
||||
var header in TarHeaderFactory.ReadHeader(
|
||||
_compressionType == CompressionType.None
|
||||
? StreamingMode.Seekable
|
||||
: StreamingMode.Streaming,
|
||||
StreamingMode.Seekable,
|
||||
stream,
|
||||
ReaderOptions.ArchiveEncoding
|
||||
)
|
||||
@@ -139,10 +59,7 @@ public partial class TarArchive
|
||||
{
|
||||
var entry = new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(
|
||||
previousHeader,
|
||||
_compressionType == CompressionType.None ? stream : null
|
||||
),
|
||||
new TarFilePart(previousHeader, stream),
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
@@ -165,10 +82,7 @@ public partial class TarArchive
|
||||
}
|
||||
yield return new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(
|
||||
header,
|
||||
_compressionType == CompressionType.None ? stream : null
|
||||
),
|
||||
new TarFilePart(header, stream),
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
@@ -240,6 +154,6 @@ public partial class TarArchive
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return new TarReader(stream, ReaderOptions, _compressionType);
|
||||
return TarReader.OpenReader(stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,12 +55,7 @@ public partial class ZipArchive
|
||||
|
||||
yield return new ZipArchiveEntry(
|
||||
this,
|
||||
new SeekableZipFilePart(
|
||||
headerFactory.NotNull(),
|
||||
deh,
|
||||
s,
|
||||
ReaderOptions.Providers
|
||||
),
|
||||
new SeekableZipFilePart(headerFactory.NotNull(), deh, s),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
|
||||
@@ -95,55 +95,30 @@ public partial class ZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<ZipWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(path, readerOptions));
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(path, readerOptions);
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<ZipWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(stream, readerOptions));
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(stream, readerOptions);
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<ZipWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(fileInfo, readerOptions));
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<ZipWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(streams, readerOptions));
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(streams, readerOptions);
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<ZipWriterOptions>> OpenAsyncArchive(
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(fileInfos, readerOptions));
|
||||
}
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(fileInfos, readerOptions);
|
||||
|
||||
public static bool IsZipFile(string filePath, string? password = null) =>
|
||||
IsZipFile(new FileInfo(filePath), password);
|
||||
@@ -248,8 +223,7 @@ public partial class ZipArchive
|
||||
|
||||
public static IWritableArchive<ZipWriterOptions> CreateArchive() => new ZipArchive();
|
||||
|
||||
public static ValueTask<IWritableAsyncArchive<ZipWriterOptions>> CreateAsyncArchive() =>
|
||||
new(new ZipArchive());
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> CreateAsyncArchive() => new ZipArchive();
|
||||
|
||||
public static async ValueTask<bool> IsZipMultiAsync(
|
||||
Stream stream,
|
||||
|
||||
@@ -96,12 +96,7 @@ public partial class ZipArchive
|
||||
|
||||
yield return new ZipArchiveEntry(
|
||||
this,
|
||||
new SeekableZipFilePart(
|
||||
headerFactory.NotNull(),
|
||||
deh,
|
||||
s,
|
||||
ReaderOptions.Providers
|
||||
),
|
||||
new SeekableZipFilePart(headerFactory.NotNull(), deh, s),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
@@ -176,6 +171,6 @@ public partial class ZipArchive
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return new((IAsyncReader)ZipReader.OpenReader(stream, ReaderOptions, Entries));
|
||||
return new((IAsyncReader)ZipReader.OpenReader(stream));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,7 @@ public partial class GZipEntry
|
||||
)
|
||||
{
|
||||
yield return new GZipEntry(
|
||||
await GZipFilePart
|
||||
.CreateAsync(stream, options.ArchiveEncoding, options.Providers)
|
||||
.ConfigureAwait(false),
|
||||
await GZipFilePart.CreateAsync(stream, options.ArchiveEncoding).ConfigureAwait(false),
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,10 +46,7 @@ public partial class GZipEntry : Entry
|
||||
|
||||
internal static IEnumerable<GZipEntry> GetEntries(Stream stream, ReaderOptions options)
|
||||
{
|
||||
yield return new GZipEntry(
|
||||
GZipFilePart.Create(stream, options.ArchiveEncoding, options.Providers),
|
||||
options
|
||||
);
|
||||
yield return new GZipEntry(GZipFilePart.Create(stream, options.ArchiveEncoding), options);
|
||||
}
|
||||
|
||||
// Async methods moved to GZipEntry.Async.cs
|
||||
|
||||
@@ -5,9 +5,7 @@ using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.GZip;
|
||||
|
||||
@@ -16,11 +14,10 @@ internal sealed partial class GZipFilePart
|
||||
internal static async ValueTask<GZipFilePart> CreateAsync(
|
||||
Stream stream,
|
||||
IArchiveEncoding archiveEncoding,
|
||||
CompressionProviderRegistry compressionProviders,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var part = new GZipFilePart(stream, archiveEncoding, compressionProviders);
|
||||
var part = new GZipFilePart(stream, archiveEncoding);
|
||||
|
||||
await part.ReadAndValidateGzipHeaderAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (stream.CanSeek)
|
||||
@@ -134,14 +131,4 @@ internal sealed partial class GZipFilePart
|
||||
var buffer = list.ToArray();
|
||||
return ArchiveEncoding.Decode(buffer);
|
||||
}
|
||||
|
||||
internal override async ValueTask<Stream?> GetCompressedStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// GZip uses Deflate compression
|
||||
return await _compressionProviders
|
||||
.CreateDecompressStreamAsync(CompressionType.Deflate, _stream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.IO;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.GZip;
|
||||
|
||||
@@ -13,15 +12,10 @@ internal sealed partial class GZipFilePart : FilePart
|
||||
{
|
||||
private string? _name;
|
||||
private readonly Stream _stream;
|
||||
private readonly CompressionProviderRegistry _compressionProviders;
|
||||
|
||||
internal static GZipFilePart Create(
|
||||
Stream stream,
|
||||
IArchiveEncoding archiveEncoding,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
internal static GZipFilePart Create(Stream stream, IArchiveEncoding archiveEncoding)
|
||||
{
|
||||
var part = new GZipFilePart(stream, archiveEncoding, compressionProviders);
|
||||
var part = new GZipFilePart(stream, archiveEncoding);
|
||||
|
||||
part.ReadAndValidateGzipHeader();
|
||||
if (stream.CanSeek)
|
||||
@@ -41,16 +35,8 @@ internal sealed partial class GZipFilePart : FilePart
|
||||
return part;
|
||||
}
|
||||
|
||||
private GZipFilePart(
|
||||
Stream stream,
|
||||
IArchiveEncoding archiveEncoding,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
: base(archiveEncoding)
|
||||
{
|
||||
_stream = stream;
|
||||
_compressionProviders = compressionProviders;
|
||||
}
|
||||
private GZipFilePart(Stream stream, IArchiveEncoding archiveEncoding)
|
||||
: base(archiveEncoding) => _stream = stream;
|
||||
|
||||
internal long EntryStartPosition { get; private set; }
|
||||
|
||||
@@ -60,11 +46,13 @@ internal sealed partial class GZipFilePart : FilePart
|
||||
|
||||
internal override string? FilePartName => _name;
|
||||
|
||||
internal override Stream GetCompressedStream()
|
||||
{
|
||||
//GZip uses Deflate compression, at this point we need a deflate stream
|
||||
return _compressionProviders.CreateDecompressStream(CompressionType.Deflate, _stream);
|
||||
}
|
||||
internal override Stream GetCompressedStream() =>
|
||||
new DeflateStream(
|
||||
_stream,
|
||||
CompressionMode.Decompress,
|
||||
CompressionLevel.Default,
|
||||
leaveOpen: true
|
||||
);
|
||||
|
||||
internal override Stream GetRawStream() => _stream;
|
||||
|
||||
|
||||
@@ -15,9 +15,7 @@ public partial class LzwEntry
|
||||
)
|
||||
{
|
||||
yield return new LzwEntry(
|
||||
await LzwFilePart
|
||||
.CreateAsync(stream, options.ArchiveEncoding, options.Providers, cancellationToken)
|
||||
.ConfigureAwait(false),
|
||||
await LzwFilePart.CreateAsync(stream, options.ArchiveEncoding, cancellationToken),
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,10 +46,7 @@ public partial class LzwEntry : Entry
|
||||
|
||||
internal static IEnumerable<LzwEntry> GetEntries(Stream stream, ReaderOptions options)
|
||||
{
|
||||
yield return new LzwEntry(
|
||||
LzwFilePart.Create(stream, options.ArchiveEncoding, options.Providers),
|
||||
options
|
||||
);
|
||||
yield return new LzwEntry(LzwFilePart.Create(stream, options.ArchiveEncoding), options);
|
||||
}
|
||||
|
||||
// Async methods moved to LzwEntry.Async.cs
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
@@ -11,25 +9,15 @@ internal sealed partial class LzwFilePart
|
||||
internal static async ValueTask<LzwFilePart> CreateAsync(
|
||||
Stream stream,
|
||||
IArchiveEncoding archiveEncoding,
|
||||
CompressionProviderRegistry compressionProviders,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var part = new LzwFilePart(stream, archiveEncoding, compressionProviders);
|
||||
var part = new LzwFilePart(stream, archiveEncoding);
|
||||
|
||||
// For non-seekable streams, we can't track position, so use 0 since the stream will be
|
||||
// read sequentially from its current position.
|
||||
part.EntryStartPosition = stream.CanSeek ? stream.Position : 0;
|
||||
return part;
|
||||
}
|
||||
|
||||
internal override async ValueTask<Stream?> GetCompressedStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
return await _compressionProviders
|
||||
.CreateDecompressStreamAsync(CompressionType.Lzw, _stream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Providers;
|
||||
using SharpCompress.Compressors.Lzw;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
@@ -8,15 +7,10 @@ internal sealed partial class LzwFilePart : FilePart
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
private readonly string? _name;
|
||||
private readonly CompressionProviderRegistry _compressionProviders;
|
||||
|
||||
internal static LzwFilePart Create(
|
||||
Stream stream,
|
||||
IArchiveEncoding archiveEncoding,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
internal static LzwFilePart Create(Stream stream, IArchiveEncoding archiveEncoding)
|
||||
{
|
||||
var part = new LzwFilePart(stream, archiveEncoding, compressionProviders);
|
||||
var part = new LzwFilePart(stream, archiveEncoding);
|
||||
|
||||
// For non-seekable streams, we can't track position, so use 0 since the stream will be
|
||||
// read sequentially from its current position.
|
||||
@@ -24,16 +18,11 @@ internal sealed partial class LzwFilePart : FilePart
|
||||
return part;
|
||||
}
|
||||
|
||||
private LzwFilePart(
|
||||
Stream stream,
|
||||
IArchiveEncoding archiveEncoding,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
private LzwFilePart(Stream stream, IArchiveEncoding archiveEncoding)
|
||||
: base(archiveEncoding)
|
||||
{
|
||||
_stream = stream;
|
||||
_name = DeriveFileName(stream);
|
||||
_compressionProviders = compressionProviders;
|
||||
}
|
||||
|
||||
internal long EntryStartPosition { get; private set; }
|
||||
@@ -41,7 +30,7 @@ internal sealed partial class LzwFilePart : FilePart
|
||||
internal override string? FilePartName => _name;
|
||||
|
||||
internal override Stream GetCompressedStream() =>
|
||||
_compressionProviders.CreateDecompressStream(CompressionType.Lzw, _stream);
|
||||
new LzwStream(_stream) { IsStreamOwner = false };
|
||||
|
||||
internal override Stream GetRawStream() => _stream;
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.Options;
|
||||
|
||||
public interface IReaderOptions
|
||||
@@ -9,40 +6,10 @@ public interface IReaderOptions
|
||||
IProgressOptions,
|
||||
IExtractionOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Look for RarArchive (Check for self-extracting archives or cases where RarArchive isn't at the start of the file)
|
||||
/// </summary>
|
||||
bool LookForHeader { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Password for encrypted archives.
|
||||
/// </summary>
|
||||
string? Password { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Disable checking for incomplete archives.
|
||||
/// </summary>
|
||||
bool DisableCheckIncomplete { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Buffer size for stream operations.
|
||||
/// </summary>
|
||||
int BufferSize { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Provide a hint for the extension of the archive being read, can speed up finding the correct decoder.
|
||||
/// </summary>
|
||||
string? ExtensionHint { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the rewindable buffer for non-seekable streams.
|
||||
/// </summary>
|
||||
int? RewindableBufferSize { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Registry of compression providers.
|
||||
/// Defaults to <see cref="CompressionProviderRegistry.Default" /> but can be replaced with custom providers.
|
||||
/// Use this to provide alternative decompression implementations.
|
||||
/// </summary>
|
||||
CompressionProviderRegistry Providers { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,28 +1,9 @@
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Options for configuring writer behavior when creating archives.
|
||||
/// </summary>
|
||||
public interface IWriterOptions : IStreamOptions, IEncodingOptions, IProgressOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The compression type to use for the archive.
|
||||
/// </summary>
|
||||
CompressionType CompressionType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The compression level to be used when the compression type supports variable levels.
|
||||
/// </summary>
|
||||
int CompressionLevel { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Registry of compression providers.
|
||||
/// Defaults to <see cref="CompressionProviderRegistry.Default" /> but can be replaced with custom providers, such as
|
||||
/// System.IO.Compression for Deflate/GZip on modern .NET.
|
||||
/// </summary>
|
||||
CompressionProviderRegistry Providers { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.Zip;
|
||||
|
||||
@@ -13,10 +11,9 @@ internal partial class SeekableZipFilePart : ZipFilePart
|
||||
internal SeekableZipFilePart(
|
||||
SeekableZipHeaderFactory headerFactory,
|
||||
DirectoryEntryHeader header,
|
||||
Stream stream,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
Stream stream
|
||||
)
|
||||
: base(header, stream, compressionProviders) => _headerFactory = headerFactory;
|
||||
: base(header, stream) => _headerFactory = headerFactory;
|
||||
|
||||
internal override Stream GetCompressedStream()
|
||||
{
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.Zip;
|
||||
|
||||
@@ -10,12 +9,8 @@ internal sealed partial class StreamingZipFilePart : ZipFilePart
|
||||
{
|
||||
private Stream? _decompressionStream;
|
||||
|
||||
internal StreamingZipFilePart(
|
||||
ZipFileEntry header,
|
||||
Stream stream,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
: base(header, stream, compressionProviders) { }
|
||||
internal StreamingZipFilePart(ZipFileEntry header, Stream stream)
|
||||
: base(header, stream) { }
|
||||
|
||||
protected override Stream CreateBaseStream() => Header.PackedStream.NotNull();
|
||||
|
||||
@@ -52,6 +47,11 @@ internal sealed partial class StreamingZipFilePart : ZipFilePart
|
||||
// If we had TotalIn / TotalOut we could have used them
|
||||
Header.CompressedSize = _decompressionStream.Position;
|
||||
|
||||
if (_decompressionStream is DeflateStream deflateStream)
|
||||
{
|
||||
stream.Position = 0;
|
||||
}
|
||||
|
||||
Skipped = true;
|
||||
}
|
||||
var reader = new BinaryReader(stream, System.Text.Encoding.Default, leaveOpen: true);
|
||||
|
||||
@@ -10,10 +10,6 @@ public class ZipEntry : Entry
|
||||
{
|
||||
private readonly ZipFilePart? _filePart;
|
||||
|
||||
// WinZip AES extra data constants
|
||||
private const int MinimumWinZipAesExtraDataLength = 7;
|
||||
private const int WinZipAesCompressionMethodOffset = 5;
|
||||
|
||||
internal ZipEntry(ZipFilePart? filePart, IReaderOptions readerOptions)
|
||||
: base(readerOptions)
|
||||
{
|
||||
@@ -37,54 +33,24 @@ public class ZipEntry : Entry
|
||||
CreatedTime = times?.UnicodeTimes.Item3;
|
||||
}
|
||||
|
||||
public override CompressionType CompressionType
|
||||
{
|
||||
get
|
||||
public override CompressionType CompressionType =>
|
||||
_filePart?.Header.CompressionMethod switch
|
||||
{
|
||||
var compressionMethod = GetActualCompressionMethod();
|
||||
return compressionMethod switch
|
||||
{
|
||||
ZipCompressionMethod.BZip2 => CompressionType.BZip2,
|
||||
ZipCompressionMethod.Deflate => CompressionType.Deflate,
|
||||
ZipCompressionMethod.Deflate64 => CompressionType.Deflate64,
|
||||
ZipCompressionMethod.LZMA => CompressionType.LZMA,
|
||||
ZipCompressionMethod.PPMd => CompressionType.PPMd,
|
||||
ZipCompressionMethod.None => CompressionType.None,
|
||||
ZipCompressionMethod.Shrink => CompressionType.Shrink,
|
||||
ZipCompressionMethod.Reduce1 => CompressionType.Reduce1,
|
||||
ZipCompressionMethod.Reduce2 => CompressionType.Reduce2,
|
||||
ZipCompressionMethod.Reduce3 => CompressionType.Reduce3,
|
||||
ZipCompressionMethod.Reduce4 => CompressionType.Reduce4,
|
||||
ZipCompressionMethod.Explode => CompressionType.Explode,
|
||||
ZipCompressionMethod.ZStandard => CompressionType.ZStandard,
|
||||
_ => CompressionType.Unknown,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private ZipCompressionMethod GetActualCompressionMethod()
|
||||
{
|
||||
if (_filePart?.Header.CompressionMethod != ZipCompressionMethod.WinzipAes)
|
||||
{
|
||||
return _filePart?.Header.CompressionMethod ?? ZipCompressionMethod.None;
|
||||
}
|
||||
|
||||
// For WinZip AES, the actual compression method is stored in the extra data
|
||||
var aesExtraData = _filePart.Header.Extra.FirstOrDefault(x =>
|
||||
x.Type == ExtraDataType.WinZipAes
|
||||
);
|
||||
|
||||
if (aesExtraData is null || aesExtraData.DataBytes.Length < MinimumWinZipAesExtraDataLength)
|
||||
{
|
||||
return ZipCompressionMethod.WinzipAes;
|
||||
}
|
||||
|
||||
// The compression method is at offset 5 in the extra data
|
||||
return (ZipCompressionMethod)
|
||||
System.Buffers.Binary.BinaryPrimitives.ReadUInt16LittleEndian(
|
||||
aesExtraData.DataBytes.AsSpan(WinZipAesCompressionMethodOffset)
|
||||
);
|
||||
}
|
||||
ZipCompressionMethod.BZip2 => CompressionType.BZip2,
|
||||
ZipCompressionMethod.Deflate => CompressionType.Deflate,
|
||||
ZipCompressionMethod.Deflate64 => CompressionType.Deflate64,
|
||||
ZipCompressionMethod.LZMA => CompressionType.LZMA,
|
||||
ZipCompressionMethod.PPMd => CompressionType.PPMd,
|
||||
ZipCompressionMethod.None => CompressionType.None,
|
||||
ZipCompressionMethod.Shrink => CompressionType.Shrink,
|
||||
ZipCompressionMethod.Reduce1 => CompressionType.Reduce1,
|
||||
ZipCompressionMethod.Reduce2 => CompressionType.Reduce2,
|
||||
ZipCompressionMethod.Reduce3 => CompressionType.Reduce3,
|
||||
ZipCompressionMethod.Reduce4 => CompressionType.Reduce4,
|
||||
ZipCompressionMethod.Explode => CompressionType.Explode,
|
||||
ZipCompressionMethod.ZStandard => CompressionType.ZStandard,
|
||||
_ => CompressionType.Unknown,
|
||||
};
|
||||
|
||||
public override long Crc => _filePart?.Header.Crc ?? 0;
|
||||
|
||||
|
||||
@@ -6,8 +6,17 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace SharpCompress.Common.Zip;
|
||||
|
||||
@@ -114,7 +123,6 @@ internal abstract partial class ZipFilePart
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// Handle special cases first
|
||||
switch (method)
|
||||
{
|
||||
case ZipCompressionMethod.None:
|
||||
@@ -126,24 +134,98 @@ internal abstract partial class ZipFilePart
|
||||
|
||||
return stream;
|
||||
}
|
||||
case ZipCompressionMethod.WinzipAes:
|
||||
case ZipCompressionMethod.Shrink:
|
||||
{
|
||||
return await CreateWinzipAesDecompressionStreamAsync(stream, cancellationToken)
|
||||
return await ShrinkStream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
CompressionMode.Decompress,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.Reduce1:
|
||||
{
|
||||
return await ReduceStream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
1,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.Reduce2:
|
||||
{
|
||||
return await ReduceStream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
2,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.Reduce3:
|
||||
{
|
||||
return await ReduceStream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
3,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.Reduce4:
|
||||
{
|
||||
return await ReduceStream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
4,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.Explode:
|
||||
{
|
||||
return await ExplodeStream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
Header.Flags,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
var compressionType = ToCompressionType(method);
|
||||
var providers = GetProviders();
|
||||
var context = new CompressionContext
|
||||
{
|
||||
InputSize = Header.CompressedSize,
|
||||
OutputSize = Header.UncompressedSize,
|
||||
CanSeek = stream.CanSeek,
|
||||
};
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case ZipCompressionMethod.Deflate:
|
||||
{
|
||||
return new DeflateStream(stream, CompressionMode.Decompress);
|
||||
}
|
||||
case ZipCompressionMethod.Deflate64:
|
||||
{
|
||||
return new Deflate64Stream(stream, CompressionMode.Decompress);
|
||||
}
|
||||
case ZipCompressionMethod.BZip2:
|
||||
{
|
||||
return await BZip2Stream
|
||||
.CreateAsync(
|
||||
stream,
|
||||
CompressionMode.Decompress,
|
||||
false,
|
||||
cancellationToken: cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.LZMA:
|
||||
{
|
||||
if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted))
|
||||
@@ -152,108 +234,81 @@ internal abstract partial class ZipFilePart
|
||||
}
|
||||
var buffer = new byte[4];
|
||||
await stream.ReadFullyAsync(buffer, 0, 4, cancellationToken).ConfigureAwait(false);
|
||||
var version = BinaryPrimitives.ReadUInt16LittleEndian(buffer.AsSpan(0, 2));
|
||||
var propsSize = BinaryPrimitives.ReadUInt16LittleEndian(buffer.AsSpan(2, 2));
|
||||
var props = new byte[propsSize];
|
||||
await stream
|
||||
.ReadFullyAsync(props, 0, propsSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
context = context with
|
||||
{
|
||||
Properties = props,
|
||||
InputSize =
|
||||
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,
|
||||
OutputSize = FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
|
||||
? -1
|
||||
: Header.UncompressedSize,
|
||||
};
|
||||
|
||||
return await providers
|
||||
.CreateDecompressStreamAsync(
|
||||
compressionType,
|
||||
return await LzmaStream
|
||||
.CreateAsync(
|
||||
props,
|
||||
stream,
|
||||
context,
|
||||
cancellationToken
|
||||
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,
|
||||
FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
|
||||
? -1
|
||||
: Header.UncompressedSize
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.Xz:
|
||||
{
|
||||
return new XZStream(stream);
|
||||
}
|
||||
case ZipCompressionMethod.ZStandard:
|
||||
{
|
||||
return new DecompressionStream(stream);
|
||||
}
|
||||
case ZipCompressionMethod.PPMd:
|
||||
{
|
||||
var props = new byte[2];
|
||||
await stream.ReadFullyAsync(props, 0, 2, cancellationToken).ConfigureAwait(false);
|
||||
context = context with { Properties = props };
|
||||
return await providers
|
||||
.CreateDecompressStreamAsync(
|
||||
compressionType,
|
||||
stream,
|
||||
context,
|
||||
cancellationToken
|
||||
)
|
||||
return await PpmdStream
|
||||
.CreateAsync(new PpmdProperties(props), stream, false, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.Explode:
|
||||
case ZipCompressionMethod.WinzipAes:
|
||||
{
|
||||
context = context with { FormatOptions = Header.Flags };
|
||||
return await providers
|
||||
.CreateDecompressStreamAsync(
|
||||
compressionType,
|
||||
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 await CreateDecompressionStreamAsync(
|
||||
stream,
|
||||
context,
|
||||
(ZipCompressionMethod)
|
||||
BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5)),
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
default:
|
||||
{
|
||||
return await providers
|
||||
.CreateDecompressStreamAsync(
|
||||
compressionType,
|
||||
stream,
|
||||
context,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
throw new NotSupportedException("CompressionMethod: " + Header.CompressionMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<Stream> CreateWinzipAesDecompressionStreamAsync(
|
||||
Stream stream,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
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 await CreateDecompressionStreamAsync(
|
||||
stream,
|
||||
(ZipCompressionMethod)
|
||||
BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5)),
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,25 +15,17 @@ using SharpCompress.Compressors.Shrink;
|
||||
using SharpCompress.Compressors.Xz;
|
||||
using SharpCompress.Compressors.ZStandard;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.Zip;
|
||||
|
||||
internal abstract partial class ZipFilePart : FilePart
|
||||
{
|
||||
private readonly CompressionProviderRegistry _compressionProviders;
|
||||
|
||||
internal ZipFilePart(
|
||||
ZipFileEntry header,
|
||||
Stream stream,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
internal ZipFilePart(ZipFileEntry header, Stream stream)
|
||||
: base(header.ArchiveEncoding)
|
||||
{
|
||||
Header = header;
|
||||
header.Part = this;
|
||||
BaseStream = stream;
|
||||
_compressionProviders = compressionProviders;
|
||||
}
|
||||
|
||||
internal Stream BaseStream { get; }
|
||||
@@ -72,37 +64,8 @@ internal abstract partial class ZipFilePart : FilePart
|
||||
protected bool LeaveStreamOpen =>
|
||||
FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) || Header.IsZip64;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the compression provider registry, falling back to default if not set.
|
||||
/// </summary>
|
||||
protected CompressionProviderRegistry GetProviders() => _compressionProviders;
|
||||
|
||||
/// <summary>
|
||||
/// Converts ZipCompressionMethod to CompressionType.
|
||||
/// </summary>
|
||||
protected static CompressionType ToCompressionType(ZipCompressionMethod method) =>
|
||||
method switch
|
||||
{
|
||||
ZipCompressionMethod.None => CompressionType.None,
|
||||
ZipCompressionMethod.Deflate => CompressionType.Deflate,
|
||||
ZipCompressionMethod.Deflate64 => CompressionType.Deflate64,
|
||||
ZipCompressionMethod.BZip2 => CompressionType.BZip2,
|
||||
ZipCompressionMethod.LZMA => CompressionType.LZMA,
|
||||
ZipCompressionMethod.PPMd => CompressionType.PPMd,
|
||||
ZipCompressionMethod.ZStandard => CompressionType.ZStandard,
|
||||
ZipCompressionMethod.Xz => CompressionType.Xz,
|
||||
ZipCompressionMethod.Shrink => CompressionType.Shrink,
|
||||
ZipCompressionMethod.Reduce1 => CompressionType.Reduce1,
|
||||
ZipCompressionMethod.Reduce2 => CompressionType.Reduce2,
|
||||
ZipCompressionMethod.Reduce3 => CompressionType.Reduce3,
|
||||
ZipCompressionMethod.Reduce4 => CompressionType.Reduce4,
|
||||
ZipCompressionMethod.Explode => CompressionType.Explode,
|
||||
_ => throw new NotSupportedException($"Unsupported compression method: {method}"),
|
||||
};
|
||||
|
||||
protected Stream CreateDecompressionStream(Stream stream, ZipCompressionMethod method)
|
||||
{
|
||||
// Handle special cases first
|
||||
switch (method)
|
||||
{
|
||||
case ZipCompressionMethod.None:
|
||||
@@ -111,29 +74,76 @@ internal abstract partial class ZipFilePart : FilePart
|
||||
{
|
||||
return new DataDescriptorStream(stream);
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
case ZipCompressionMethod.WinzipAes:
|
||||
case ZipCompressionMethod.Shrink:
|
||||
{
|
||||
return CreateWinzipAesDecompressionStream(stream);
|
||||
return new ShrinkStream(
|
||||
stream,
|
||||
CompressionMode.Decompress,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize
|
||||
);
|
||||
}
|
||||
case ZipCompressionMethod.Reduce1:
|
||||
{
|
||||
return ReduceStream.Create(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
1
|
||||
);
|
||||
}
|
||||
case ZipCompressionMethod.Reduce2:
|
||||
{
|
||||
return ReduceStream.Create(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
2
|
||||
);
|
||||
}
|
||||
case ZipCompressionMethod.Reduce3:
|
||||
{
|
||||
return ReduceStream.Create(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
3
|
||||
);
|
||||
}
|
||||
case ZipCompressionMethod.Reduce4:
|
||||
{
|
||||
return ReduceStream.Create(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
4
|
||||
);
|
||||
}
|
||||
case ZipCompressionMethod.Explode:
|
||||
{
|
||||
return ExplodeStream.Create(
|
||||
stream,
|
||||
Header.CompressedSize,
|
||||
Header.UncompressedSize,
|
||||
Header.Flags
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the compression type and providers
|
||||
var compressionType = ToCompressionType(method);
|
||||
var providers = GetProviders();
|
||||
|
||||
// Build context with header information
|
||||
var context = new CompressionContext
|
||||
{
|
||||
InputSize = Header.CompressedSize,
|
||||
OutputSize = Header.UncompressedSize,
|
||||
CanSeek = stream.CanSeek,
|
||||
};
|
||||
|
||||
// Handle methods that need special context
|
||||
switch (method)
|
||||
{
|
||||
case ZipCompressionMethod.Deflate:
|
||||
{
|
||||
return new DeflateStream(stream, CompressionMode.Decompress);
|
||||
}
|
||||
case ZipCompressionMethod.Deflate64:
|
||||
{
|
||||
return new Deflate64Stream(stream, CompressionMode.Decompress);
|
||||
}
|
||||
case ZipCompressionMethod.BZip2:
|
||||
{
|
||||
return BZip2Stream.Create(stream, CompressionMode.Decompress, false);
|
||||
}
|
||||
case ZipCompressionMethod.LZMA:
|
||||
{
|
||||
if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted))
|
||||
@@ -148,71 +158,71 @@ internal abstract partial class ZipFilePart : FilePart
|
||||
)
|
||||
)
|
||||
{
|
||||
reader.ReadUInt16(); // LZMA version
|
||||
var propsLength = reader.ReadUInt16();
|
||||
var props = new byte[propsLength];
|
||||
reader.ReadUInt16(); //LZMA version
|
||||
var props = new byte[reader.ReadUInt16()];
|
||||
reader.Read(props, 0, props.Length);
|
||||
context = context with
|
||||
{
|
||||
Properties = props,
|
||||
InputSize =
|
||||
Header.CompressedSize > 0
|
||||
? Header.CompressedSize - 4 - props.Length
|
||||
: -1,
|
||||
OutputSize = FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
|
||||
return LzmaStream.Create(
|
||||
props,
|
||||
stream,
|
||||
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,
|
||||
FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
|
||||
? -1
|
||||
: Header.UncompressedSize,
|
||||
};
|
||||
return providers.CreateDecompressStream(compressionType, stream, context);
|
||||
: Header.UncompressedSize
|
||||
);
|
||||
}
|
||||
}
|
||||
case ZipCompressionMethod.Xz:
|
||||
{
|
||||
return new XZStream(stream);
|
||||
}
|
||||
case ZipCompressionMethod.ZStandard:
|
||||
{
|
||||
return new DecompressionStream(stream);
|
||||
}
|
||||
case ZipCompressionMethod.PPMd:
|
||||
{
|
||||
Span<byte> props = stackalloc byte[2];
|
||||
stream.ReadFully(props);
|
||||
context = context with { Properties = props.ToArray() };
|
||||
return providers.CreateDecompressStream(compressionType, stream, context);
|
||||
return PpmdStream.Create(new PpmdProperties(props), stream, false);
|
||||
}
|
||||
case ZipCompressionMethod.Explode:
|
||||
case ZipCompressionMethod.WinzipAes:
|
||||
{
|
||||
context = context with { FormatOptions = Header.Flags };
|
||||
return providers.CreateDecompressStream(compressionType, stream, context);
|
||||
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))
|
||||
);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException("CompressionMethod: " + Header.CompressionMethod);
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
@@ -3,11 +3,10 @@ using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Compressors.BZip2;
|
||||
|
||||
public sealed partial class BZip2Stream : Stream, IFinishable
|
||||
public sealed partial class BZip2Stream : Stream
|
||||
{
|
||||
private Stream stream = default!;
|
||||
private bool isDisposed;
|
||||
|
||||
@@ -32,8 +32,6 @@ using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Compressors.Deflate;
|
||||
|
||||
@@ -55,23 +53,8 @@ public partial class GZipStream : Stream
|
||||
public GZipStream(Stream stream, CompressionMode mode)
|
||||
: this(stream, mode, CompressionLevel.Default, Encoding.UTF8) { }
|
||||
|
||||
public GZipStream(Stream stream, CompressionMode mode, IReaderOptions readerOptions)
|
||||
: this(stream, mode, CompressionLevel.Default, readerOptions) { }
|
||||
|
||||
public GZipStream(
|
||||
Stream stream,
|
||||
CompressionMode mode,
|
||||
CompressionLevel level,
|
||||
IReaderOptions readerOptions
|
||||
)
|
||||
: this(
|
||||
stream,
|
||||
mode,
|
||||
level,
|
||||
(
|
||||
readerOptions ?? throw new ArgumentNullException(nameof(readerOptions))
|
||||
).ArchiveEncoding.GetEncoding()
|
||||
) { }
|
||||
public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level)
|
||||
: this(stream, mode, level, Encoding.UTF8) { }
|
||||
|
||||
public GZipStream(
|
||||
Stream stream,
|
||||
|
||||
@@ -6,7 +6,6 @@ using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Crypto;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Compressors.LZMA;
|
||||
|
||||
@@ -18,7 +17,7 @@ namespace SharpCompress.Compressors.LZMA;
|
||||
/// <summary>
|
||||
/// Stream supporting the LZIP format, as documented at http://www.nongnu.org/lzip/manual/lzip_manual.html
|
||||
/// </summary>
|
||||
public sealed partial class LZipStream : Stream, IFinishable
|
||||
public sealed partial class LZipStream : Stream
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
private readonly CountingStream? _countingWritableSubStream;
|
||||
|
||||
@@ -96,28 +96,4 @@ public abstract class Factory : IFactory
|
||||
stream.Rewind();
|
||||
return false;
|
||||
}
|
||||
|
||||
internal virtual async ValueTask<IAsyncReader?> TryOpenReaderAsync(
|
||||
SharpCompressStream stream,
|
||||
ReaderOptions options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (this is IReaderFactory readerFactory)
|
||||
{
|
||||
stream.Rewind();
|
||||
if (
|
||||
await IsArchiveAsync(stream, options.Password, cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
stream.Rewind(true);
|
||||
return await readerFactory
|
||||
.OpenAsyncReader(stream, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
stream.Rewind();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Archives;
|
||||
@@ -9,7 +10,6 @@ using SharpCompress.Archives.Tar;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Providers;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.GZip;
|
||||
using SharpCompress.Readers.Tar;
|
||||
@@ -63,26 +63,12 @@ public class GZipFactory
|
||||
GZipArchive.OpenArchive(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(stream, readerOptions));
|
||||
}
|
||||
public IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null) =>
|
||||
(IAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(fileInfo, readerOptions));
|
||||
}
|
||||
public IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
|
||||
(IAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -128,11 +114,7 @@ public class GZipFactory
|
||||
if (GZipArchive.IsGZipFile(sharpCompressStream))
|
||||
{
|
||||
sharpCompressStream.Rewind();
|
||||
using var testStream = options.Providers.CreateDecompressStream(
|
||||
CompressionType.GZip,
|
||||
SharpCompressStream.CreateNonDisposing(sharpCompressStream),
|
||||
CompressionContext.FromStream(sharpCompressStream).WithReaderOptions(options)
|
||||
);
|
||||
var testStream = new GZipStream(sharpCompressStream, CompressionMode.Decompress);
|
||||
if (TarArchive.IsTarFile(testStream))
|
||||
{
|
||||
sharpCompressStream.StopRecording();
|
||||
|
||||
@@ -58,12 +58,7 @@ public class LzwFactory : Factory, IReaderFactory
|
||||
if (LzwStream.IsLzwStream(sharpCompressStream))
|
||||
{
|
||||
sharpCompressStream.Rewind();
|
||||
using (
|
||||
var testStream = options.Providers.CreateDecompressStream(
|
||||
CompressionType.Lzw,
|
||||
SharpCompressStream.CreateNonDisposing(sharpCompressStream)
|
||||
)
|
||||
)
|
||||
using (var testStream = new LzwStream(sharpCompressStream) { IsStreamOwner = false })
|
||||
{
|
||||
if (TarArchive.IsTarFile(testStream))
|
||||
{
|
||||
@@ -92,7 +87,7 @@ public class LzwFactory : Factory, IReaderFactory
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return LzwReader.OpenAsyncReader(stream, options);
|
||||
return new(LzwReader.OpenAsyncReader(stream, options));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -54,30 +54,16 @@ public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReade
|
||||
RarArchive.OpenArchive(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(stream, readerOptions));
|
||||
}
|
||||
public IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null) =>
|
||||
(IAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
|
||||
RarArchive.OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(fileInfo, readerOptions));
|
||||
}
|
||||
public IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
|
||||
(IAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -49,30 +49,16 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory
|
||||
SevenZipArchive.OpenArchive(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(stream, readerOptions));
|
||||
}
|
||||
public IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null) =>
|
||||
SevenZipArchive.OpenAsyncArchive(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
|
||||
SevenZipArchive.OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(fileInfo, readerOptions));
|
||||
}
|
||||
public IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
|
||||
SevenZipArchive.OpenAsyncArchive(fileInfo, readerOptions);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -88,7 +74,7 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory
|
||||
public IAsyncArchive OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IAsyncArchive)OpenArchive(streams, readerOptions);
|
||||
) => SevenZipArchive.OpenAsyncArchive(streams, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IArchive OpenArchive(
|
||||
@@ -100,7 +86,7 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory
|
||||
public IAsyncArchive OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IAsyncArchive)OpenArchive(fileInfos, readerOptions);
|
||||
) => SevenZipArchive.OpenAsyncArchive(fileInfos, readerOptions);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -8,7 +9,6 @@ using SharpCompress.Archives.Tar;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Providers;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Tar;
|
||||
using SharpCompress.Writers;
|
||||
@@ -50,7 +50,6 @@ public class TarFactory
|
||||
/// <inheritdoc/>
|
||||
public override bool IsArchive(Stream stream, string? password = null)
|
||||
{
|
||||
var providers = CompressionProviderRegistry.Default;
|
||||
var sharpCompressStream = new SharpCompressStream(stream);
|
||||
sharpCompressStream.StartRecording();
|
||||
foreach (var wrapper in TarWrapper.Wrappers)
|
||||
@@ -59,11 +58,7 @@ public class TarFactory
|
||||
if (wrapper.IsMatch(sharpCompressStream))
|
||||
{
|
||||
sharpCompressStream.Rewind();
|
||||
var decompressedStream = CreateProbeDecompressionStream(
|
||||
sharpCompressStream,
|
||||
wrapper.CompressionType,
|
||||
providers
|
||||
);
|
||||
var decompressedStream = wrapper.CreateStream(sharpCompressStream);
|
||||
if (TarArchive.IsTarFile(decompressedStream))
|
||||
{
|
||||
sharpCompressStream.Rewind();
|
||||
@@ -82,7 +77,6 @@ public class TarFactory
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var providers = CompressionProviderRegistry.Default;
|
||||
var sharpCompressStream = new SharpCompressStream(stream);
|
||||
sharpCompressStream.StartRecording();
|
||||
foreach (var wrapper in TarWrapper.Wrappers)
|
||||
@@ -95,12 +89,8 @@ public class TarFactory
|
||||
)
|
||||
{
|
||||
sharpCompressStream.Rewind();
|
||||
var decompressedStream = await CreateProbeDecompressionStreamAsync(
|
||||
sharpCompressStream,
|
||||
wrapper.CompressionType,
|
||||
providers,
|
||||
cancellationToken: cancellationToken
|
||||
)
|
||||
var decompressedStream = await wrapper
|
||||
.CreateStreamAsync(sharpCompressStream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (
|
||||
await TarArchive
|
||||
@@ -119,125 +109,6 @@ public class TarFactory
|
||||
|
||||
#endregion
|
||||
|
||||
private static Stream CreateProbeDecompressionStream(
|
||||
Stream stream,
|
||||
CompressionType compressionType,
|
||||
CompressionProviderRegistry providers,
|
||||
IReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
var nonDisposingStream = SharpCompressStream.CreateNonDisposing(stream);
|
||||
if (compressionType == CompressionType.None)
|
||||
{
|
||||
return nonDisposingStream;
|
||||
}
|
||||
|
||||
if (compressionType == CompressionType.GZip && readerOptions is not null)
|
||||
{
|
||||
return providers.CreateDecompressStream(
|
||||
compressionType,
|
||||
nonDisposingStream,
|
||||
CompressionContext.FromStream(nonDisposingStream).WithReaderOptions(readerOptions)
|
||||
);
|
||||
}
|
||||
|
||||
return providers.CreateDecompressStream(compressionType, nonDisposingStream);
|
||||
}
|
||||
|
||||
private static async ValueTask<Stream> CreateProbeDecompressionStreamAsync(
|
||||
Stream stream,
|
||||
CompressionType compressionType,
|
||||
CompressionProviderRegistry providers,
|
||||
IReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var nonDisposingStream = SharpCompressStream.CreateNonDisposing(stream);
|
||||
if (compressionType == CompressionType.None)
|
||||
{
|
||||
return nonDisposingStream;
|
||||
}
|
||||
|
||||
if (compressionType == CompressionType.GZip && readerOptions is not null)
|
||||
{
|
||||
return await providers
|
||||
.CreateDecompressStreamAsync(
|
||||
compressionType,
|
||||
nonDisposingStream,
|
||||
CompressionContext
|
||||
.FromStream(nonDisposingStream)
|
||||
.WithReaderOptions(readerOptions),
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return await providers
|
||||
.CreateDecompressStreamAsync(compressionType, nonDisposingStream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static CompressionType GetCompressionType(
|
||||
Stream stream,
|
||||
CompressionProviderRegistry? providers = null
|
||||
)
|
||||
{
|
||||
providers ??= CompressionProviderRegistry.Default;
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
foreach (var wrapper in TarWrapper.Wrappers)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (wrapper.IsMatch(stream))
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
var decompressedStream = CreateProbeDecompressionStream(
|
||||
stream,
|
||||
wrapper.CompressionType,
|
||||
providers
|
||||
);
|
||||
if (TarArchive.IsTarFile(decompressedStream))
|
||||
{
|
||||
return wrapper.CompressionType;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
|
||||
public static async ValueTask<CompressionType> GetCompressionTypeAsync(
|
||||
Stream stream,
|
||||
CompressionProviderRegistry? providers = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
providers ??= CompressionProviderRegistry.Default;
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
foreach (var wrapper in TarWrapper.Wrappers)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (await wrapper.IsMatchAsync(stream, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
var decompressedStream = await CreateProbeDecompressionStreamAsync(
|
||||
stream,
|
||||
wrapper.CompressionType,
|
||||
providers,
|
||||
cancellationToken: cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
if (
|
||||
await TarArchive
|
||||
.IsTarFileAsync(decompressedStream, cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
return wrapper.CompressionType;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
|
||||
#region IArchiveFactory
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -245,28 +116,16 @@ public class TarFactory
|
||||
TarArchive.OpenArchive(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await TarArchive
|
||||
.OpenAsyncArchive(stream, readerOptions, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
public IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null) =>
|
||||
(IAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
|
||||
TarArchive.OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await TarArchive
|
||||
.OpenAsyncArchive(fileInfo, readerOptions, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
public IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
|
||||
(IAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -312,12 +171,7 @@ public class TarFactory
|
||||
if (wrapper.IsMatch(sharpCompressStream))
|
||||
{
|
||||
sharpCompressStream.Rewind();
|
||||
var decompressedStream = CreateProbeDecompressionStream(
|
||||
sharpCompressStream,
|
||||
wrapper.CompressionType,
|
||||
options.Providers,
|
||||
options
|
||||
);
|
||||
var decompressedStream = wrapper.CreateStream(sharpCompressStream);
|
||||
if (TarArchive.IsTarFile(decompressedStream))
|
||||
{
|
||||
sharpCompressStream.StopRecording();
|
||||
@@ -349,13 +203,8 @@ public class TarFactory
|
||||
)
|
||||
{
|
||||
sharpCompressStream.Rewind();
|
||||
var decompressedStream = await CreateProbeDecompressionStreamAsync(
|
||||
sharpCompressStream,
|
||||
wrapper.CompressionType,
|
||||
options.Providers,
|
||||
options,
|
||||
cancellationToken
|
||||
)
|
||||
var decompressedStream = await wrapper
|
||||
.CreateStreamAsync(sharpCompressStream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (
|
||||
await TarArchive
|
||||
@@ -369,9 +218,7 @@ public class TarFactory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sharpCompressStream.Rewind();
|
||||
return (IAsyncReader)TarReader.OpenReader(sharpCompressStream, options);
|
||||
return (IAsyncReader)TarReader.OpenReader(stream, options);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -127,30 +127,16 @@ public class ZipFactory
|
||||
ZipArchive.OpenArchive(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(stream, readerOptions));
|
||||
}
|
||||
public IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null) =>
|
||||
(IAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
|
||||
ZipArchive.OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(fileInfo, readerOptions));
|
||||
}
|
||||
public IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
|
||||
(IAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -206,22 +206,8 @@ internal partial class SharpCompressStream : Stream, IStreamStack
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_isPassthrough)
|
||||
{
|
||||
return stream.Length;
|
||||
}
|
||||
|
||||
if (_ringBuffer is not null)
|
||||
{
|
||||
return _ringBuffer.Length;
|
||||
}
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
public override long Length =>
|
||||
_isPassthrough ? stream.Length : throw new NotSupportedException();
|
||||
|
||||
public override long Position
|
||||
{
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Providers;
|
||||
|
||||
/// <summary>
|
||||
/// Provides context information for compression operations.
|
||||
/// Carries format-specific parameters that some compression types require.
|
||||
/// </summary>
|
||||
public sealed record CompressionContext
|
||||
{
|
||||
/// <summary>
|
||||
/// The size of the input data, or -1 if unknown.
|
||||
/// </summary>
|
||||
public long InputSize { get; init; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The expected output size, or -1 if unknown.
|
||||
/// </summary>
|
||||
public long OutputSize { get; init; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Properties bytes for the compression format (e.g., LZMA properties).
|
||||
/// </summary>
|
||||
public byte[]? Properties { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the underlying stream supports seeking.
|
||||
/// </summary>
|
||||
public bool CanSeek { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional format-specific options.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is consumed by provider implementations that need caller-supplied metadata
|
||||
/// that is not tied to ReaderOptions. For archive header encoding, use <see cref="ReaderOptions"/> instead.
|
||||
/// Examples of valid FormatOptions values include compression properties (e.g., LZMA properties),
|
||||
/// format flags, or algorithm-specific configuration.
|
||||
/// </remarks>
|
||||
public object? FormatOptions { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CompressionContext from a stream.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to extract context from.</param>
|
||||
/// <returns>A CompressionContext populated from the stream.</returns>
|
||||
public static CompressionContext FromStream(Stream stream) =>
|
||||
new() { CanSeek = stream.CanSeek, InputSize = stream.CanSeek ? stream.Length : -1 };
|
||||
|
||||
/// <summary>
|
||||
/// Reader options for accessing archive metadata such as header encoding.
|
||||
/// </summary>
|
||||
public IReaderOptions? ReaderOptions { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="CompressionContext"/> with the specified reader options.
|
||||
/// </summary>
|
||||
/// <param name="readerOptions">The reader options to set.</param>
|
||||
/// <returns>A new <see cref="CompressionContext"/> instance.</returns>
|
||||
public CompressionContext WithReaderOptions(IReaderOptions? readerOptions) =>
|
||||
this with
|
||||
{
|
||||
ReaderOptions = readerOptions,
|
||||
};
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System.Text;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Providers;
|
||||
|
||||
public static class CompressionContextExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolves the archive header encoding from <see cref="CompressionContext.ReaderOptions"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Returns <see cref="ReaderOptions.ArchiveEncoding"/> when ReaderOptions is set,
|
||||
/// otherwise falls back to UTF-8.
|
||||
/// </remarks>
|
||||
public static Encoding ResolveArchiveEncoding(this CompressionContext context) =>
|
||||
context.ReaderOptions?.ArchiveEncoding.GetEncoding() ?? Encoding.UTF8;
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Providers;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for compression providers that provides default async implementations
|
||||
/// delegating to synchronous methods. Providers can inherit from this class for
|
||||
/// simpler implementations or implement ICompressionProvider directly for full control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This base class implements the async methods by calling the synchronous versions.
|
||||
/// Providers that need true async implementations should override these methods.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public abstract class CompressionProviderBase : ICompressionProvider
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public abstract CompressionType CompressionType { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract bool SupportsCompression { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract bool SupportsDecompression { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract Stream CreateCompressStream(Stream destination, int compressionLevel);
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Stream CreateCompressStream(
|
||||
Stream destination,
|
||||
int compressionLevel,
|
||||
CompressionContext context
|
||||
) => CreateCompressStream(destination, compressionLevel);
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract Stream CreateDecompressStream(Stream source);
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Stream CreateDecompressStream(Stream source, CompressionContext context) =>
|
||||
CreateDecompressStream(source);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously creates a compression stream.
|
||||
/// Default implementation delegates to the synchronous CreateCompressStream.
|
||||
/// </summary>
|
||||
public virtual ValueTask<Stream> CreateCompressStreamAsync(
|
||||
Stream destination,
|
||||
int compressionLevel,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new ValueTask<Stream>(CreateCompressStream(destination, compressionLevel));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously creates a compression stream with context.
|
||||
/// Default implementation delegates to the synchronous CreateCompressStream with context.
|
||||
/// </summary>
|
||||
public virtual ValueTask<Stream> CreateCompressStreamAsync(
|
||||
Stream destination,
|
||||
int compressionLevel,
|
||||
CompressionContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
return CreateCompressStreamAsync(destination, compressionLevel, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously creates a decompression stream.
|
||||
/// Default implementation delegates to the synchronous CreateDecompressStream.
|
||||
/// </summary>
|
||||
public virtual ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new ValueTask<Stream>(CreateDecompressStream(source));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously creates a decompression stream with context.
|
||||
/// Default implementation delegates to the synchronous CreateDecompressStream with context.
|
||||
/// </summary>
|
||||
public virtual ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CompressionContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
return CreateDecompressStreamAsync(source, cancellationToken);
|
||||
}
|
||||
|
||||
protected static void ValidateRequiredSizes(CompressionContext context, string algorithmName)
|
||||
{
|
||||
if (context.InputSize < 0 || context.OutputSize < 0)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"{algorithmName} decompression requires InputSize and OutputSize in CompressionContext.",
|
||||
nameof(context)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected static T RequireFormatOption<T>(
|
||||
CompressionContext context,
|
||||
string algorithmName,
|
||||
string optionName
|
||||
)
|
||||
{
|
||||
if (context.FormatOptions is not T options)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"{algorithmName} decompression requires {optionName} in CompressionContext.FormatOptions.",
|
||||
nameof(context)
|
||||
);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
@@ -1,321 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Providers.Default;
|
||||
|
||||
namespace SharpCompress.Providers;
|
||||
|
||||
/// <summary>
|
||||
/// A registry of compression providers, keyed by CompressionType.
|
||||
/// Used to resolve which implementation to use for a given compression type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This class is immutable. Use the <c>With</c> method to create modified copies
|
||||
/// that add or replace providers:
|
||||
/// </para>
|
||||
/// <code>
|
||||
/// var customRegistry = CompressionProviderRegistry.Default
|
||||
/// .With(new MyCustomGZipProvider());
|
||||
/// var options = new WriterOptions(CompressionType.GZip)
|
||||
/// {
|
||||
/// Providers = customRegistry
|
||||
/// };
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
public sealed class CompressionProviderRegistry
|
||||
{
|
||||
/// <summary>
|
||||
/// The default registry using SharpCompress internal implementations.
|
||||
/// </summary>
|
||||
public static CompressionProviderRegistry Default { get; } = CreateDefault();
|
||||
|
||||
/// <summary>
|
||||
/// The empty registry for tests
|
||||
/// </summary>
|
||||
public static CompressionProviderRegistry Empty { get; } = CreateEmpty();
|
||||
|
||||
private readonly Dictionary<CompressionType, ICompressionProvider> _providers;
|
||||
|
||||
private CompressionProviderRegistry(
|
||||
Dictionary<CompressionType, ICompressionProvider> providers
|
||||
) => _providers = providers;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the provider for a given compression type, or null if none is registered.
|
||||
/// </summary>
|
||||
/// <param name="type">The compression type to look up.</param>
|
||||
/// <returns>The provider for the type, or null if not found.</returns>
|
||||
public ICompressionProvider? GetProvider(CompressionType type)
|
||||
{
|
||||
_providers.TryGetValue(type, out var provider);
|
||||
return provider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
/// <returns>A compression stream.</returns>
|
||||
/// <exception cref="InvalidOperationException">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 InvalidOperationException(
|
||||
$"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="InvalidOperationException">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 InvalidOperationException(
|
||||
$"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="InvalidOperationException">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 InvalidOperationException(
|
||||
$"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="InvalidOperationException">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 InvalidOperationException(
|
||||
$"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>
|
||||
/// <exception cref="InvalidOperationException">If no provider is registered for the type.</exception>
|
||||
/// <exception cref="NotSupportedException">If the provider does not support compression.</exception>
|
||||
public ValueTask<Stream> CreateCompressStreamAsync(
|
||||
CompressionType type,
|
||||
Stream destination,
|
||||
int level,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var provider = GetProvider(type);
|
||||
if (provider is null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"No compression provider registered for type: {type}"
|
||||
);
|
||||
}
|
||||
return provider.CreateCompressStreamAsync(destination, level, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously 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>
|
||||
/// <exception cref="InvalidOperationException">If no provider is registered for the type.</exception>
|
||||
/// <exception cref="NotSupportedException">If the provider does not support decompression.</exception>
|
||||
public ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
CompressionType type,
|
||||
Stream source,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var provider = GetProvider(type);
|
||||
if (provider is null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"No compression provider registered for type: {type}"
|
||||
);
|
||||
}
|
||||
return provider.CreateDecompressStreamAsync(source, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously 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>
|
||||
/// <exception cref="InvalidOperationException">If no provider is registered for the type.</exception>
|
||||
/// <exception cref="NotSupportedException">If the provider does not support compression.</exception>
|
||||
public ValueTask<Stream> CreateCompressStreamAsync(
|
||||
CompressionType type,
|
||||
Stream destination,
|
||||
int level,
|
||||
CompressionContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var provider = GetProvider(type);
|
||||
if (provider is null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"No compression provider registered for type: {type}"
|
||||
);
|
||||
}
|
||||
return provider.CreateCompressStreamAsync(destination, level, context, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously 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>
|
||||
/// <exception cref="InvalidOperationException">If no provider is registered for the type.</exception>
|
||||
/// <exception cref="NotSupportedException">If the provider does not support decompression.</exception>
|
||||
public ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
CompressionType type,
|
||||
Stream source,
|
||||
CompressionContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var provider = GetProvider(type);
|
||||
if (provider is null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"No compression provider registered for type: {type}"
|
||||
);
|
||||
}
|
||||
return provider.CreateDecompressStreamAsync(source, context, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the provider as an ICompressionProviderHooks if it supports complex initialization.
|
||||
/// </summary>
|
||||
/// <param name="type">The compression type.</param>
|
||||
/// <returns>The compressing provider, or null if the provider doesn't support complex initialization.</returns>
|
||||
public ICompressionProviderHooks? GetCompressingProvider(CompressionType type)
|
||||
{
|
||||
var provider = GetProvider(type);
|
||||
return provider as ICompressionProviderHooks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new registry with the specified provider added or replaced.
|
||||
/// </summary>
|
||||
/// <param name="provider">The provider to add or replace.</param>
|
||||
/// <returns>A new registry instance with the provider included.</returns>
|
||||
/// <exception cref="ArgumentNullException">If provider is null.</exception>
|
||||
public CompressionProviderRegistry With(ICompressionProvider provider)
|
||||
{
|
||||
if (provider is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(provider));
|
||||
}
|
||||
|
||||
var newProviders = new Dictionary<CompressionType, ICompressionProvider>(_providers)
|
||||
{
|
||||
[provider.CompressionType] = provider,
|
||||
};
|
||||
|
||||
return new CompressionProviderRegistry(newProviders);
|
||||
}
|
||||
|
||||
private static CompressionProviderRegistry CreateDefault()
|
||||
{
|
||||
var providers = new Dictionary<CompressionType, ICompressionProvider>
|
||||
{
|
||||
[CompressionType.Deflate] = new DeflateCompressionProvider(),
|
||||
[CompressionType.GZip] = new GZipCompressionProvider(),
|
||||
[CompressionType.BZip2] = new BZip2CompressionProvider(),
|
||||
[CompressionType.ZStandard] = new ZStandardCompressionProvider(),
|
||||
[CompressionType.LZip] = new LZipCompressionProvider(),
|
||||
[CompressionType.Xz] = new XzCompressionProvider(),
|
||||
[CompressionType.Lzw] = new LzwCompressionProvider(),
|
||||
[CompressionType.Deflate64] = new Deflate64CompressionProvider(),
|
||||
[CompressionType.Shrink] = new ShrinkCompressionProvider(),
|
||||
[CompressionType.Reduce1] = new Reduce1CompressionProvider(),
|
||||
[CompressionType.Reduce2] = new Reduce2CompressionProvider(),
|
||||
[CompressionType.Reduce3] = new Reduce3CompressionProvider(),
|
||||
[CompressionType.Reduce4] = new Reduce4CompressionProvider(),
|
||||
[CompressionType.Explode] = new ExplodeCompressionProvider(),
|
||||
[CompressionType.LZMA] = new LzmaCompressingProvider(),
|
||||
[CompressionType.PPMd] = new PpmdCompressingProvider(),
|
||||
};
|
||||
|
||||
return new CompressionProviderRegistry(providers);
|
||||
}
|
||||
|
||||
private static CompressionProviderRegistry CreateEmpty()
|
||||
{
|
||||
var providers = new Dictionary<CompressionType, ICompressionProvider>();
|
||||
return new CompressionProviderRegistry(providers);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Providers;
|
||||
|
||||
public abstract class ContextRequiredDecompressionProviderBase : DecompressionOnlyProviderBase
|
||||
{
|
||||
protected abstract string DecompressionContextRequirementDescription { get; }
|
||||
|
||||
protected virtual string DecompressionContextRequirementSuffix => string.Empty;
|
||||
|
||||
public sealed override Stream CreateDecompressStream(Stream source) =>
|
||||
throw new InvalidOperationException(
|
||||
$"{DecompressionContextRequirementDescription}. "
|
||||
+ $"Use CreateDecompressStream(Stream, CompressionContext) overload{DecompressionContextRequirementSuffix}."
|
||||
);
|
||||
|
||||
public sealed override ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
throw new InvalidOperationException(
|
||||
$"{DecompressionContextRequirementDescription}. "
|
||||
+ "Use CreateDecompressStreamAsync(Stream, CompressionContext, CancellationToken) "
|
||||
+ $"overload{DecompressionContextRequirementSuffix}."
|
||||
);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Providers;
|
||||
|
||||
public abstract class DecompressionOnlyProviderBase : CompressionProviderBase
|
||||
{
|
||||
public override bool SupportsCompression => false;
|
||||
public override bool SupportsDecompression => true;
|
||||
|
||||
protected abstract string CompressionNotSupportedMessage { get; }
|
||||
|
||||
public sealed override Stream CreateCompressStream(Stream destination, int compressionLevel) =>
|
||||
throw new NotSupportedException(CompressionNotSupportedMessage);
|
||||
|
||||
public sealed override Stream CreateCompressStream(
|
||||
Stream destination,
|
||||
int compressionLevel,
|
||||
CompressionContext context
|
||||
) => throw new NotSupportedException(CompressionNotSupportedMessage);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.BZip2;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides BZip2 compression using SharpCompress's internal implementation.
|
||||
/// </summary>
|
||||
public sealed class BZip2CompressionProvider : CompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.BZip2;
|
||||
public override bool SupportsCompression => true;
|
||||
public override bool SupportsDecompression => true;
|
||||
|
||||
public override Stream CreateCompressStream(Stream destination, int compressionLevel)
|
||||
{
|
||||
// BZip2 doesn't use compressionLevel parameter in this implementation
|
||||
return BZip2Stream.Create(destination, CompressionMode.Compress, false);
|
||||
}
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source)
|
||||
{
|
||||
return BZip2Stream.Create(source, CompressionMode.Decompress, false);
|
||||
}
|
||||
|
||||
public override async ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
return await BZip2Stream
|
||||
.CreateAsync(source, CompressionMode.Decompress, false, false, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.Deflate64;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides Deflate64 decompression using SharpCompress's internal implementation.
|
||||
/// Note: Deflate64 compression is not supported; this provider is decompression-only.
|
||||
/// </summary>
|
||||
public sealed class Deflate64CompressionProvider : DecompressionOnlyProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.Deflate64;
|
||||
protected override string CompressionNotSupportedMessage =>
|
||||
"Deflate64 compression is not supported by SharpCompress's internal implementation.";
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source)
|
||||
{
|
||||
return new Deflate64Stream(source, CompressionMode.Decompress);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides Deflate compression using SharpCompress's internal implementation.
|
||||
/// </summary>
|
||||
public sealed class DeflateCompressionProvider : CompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.Deflate;
|
||||
public override bool SupportsCompression => true;
|
||||
public override bool SupportsDecompression => true;
|
||||
|
||||
public override Stream CreateCompressStream(Stream destination, int compressionLevel)
|
||||
{
|
||||
var level = (CompressionLevel)compressionLevel;
|
||||
return new DeflateStream(destination, CompressionMode.Compress, level);
|
||||
}
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source)
|
||||
{
|
||||
return new DeflateStream(source, CompressionMode.Decompress);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.Compressors.Explode;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides Explode decompression using SharpCompress's internal implementation.
|
||||
/// Note: Explode compression is not supported; this provider is decompression-only.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Explode requires compressed size, uncompressed size, and flags which must be provided via CompressionContext.
|
||||
/// </remarks>
|
||||
public sealed class ExplodeCompressionProvider : ContextRequiredDecompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.Explode;
|
||||
protected override string CompressionNotSupportedMessage =>
|
||||
"Explode compression is not supported by SharpCompress's internal implementation.";
|
||||
|
||||
protected override string DecompressionContextRequirementDescription =>
|
||||
"Explode decompression requires compressed size, uncompressed size, and flags";
|
||||
|
||||
protected override string DecompressionContextRequirementSuffix => " with FormatOptions";
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source, CompressionContext context)
|
||||
{
|
||||
ValidateRequiredSizes(context, "Explode");
|
||||
var flags = RequireFormatOption<HeaderFlags>(context, "Explode", "HeaderFlags");
|
||||
|
||||
return ExplodeStream.Create(source, context.InputSize, context.OutputSize, flags);
|
||||
}
|
||||
|
||||
public override async ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CompressionContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
ValidateRequiredSizes(context, "Explode");
|
||||
var flags = RequireFormatOption<HeaderFlags>(context, "Explode", "HeaderFlags");
|
||||
|
||||
return await ExplodeStream
|
||||
.CreateAsync(source, context.InputSize, context.OutputSize, flags, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides GZip compression using SharpCompress's internal implementation.
|
||||
/// </summary>
|
||||
public sealed class GZipCompressionProvider : CompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.GZip;
|
||||
public override bool SupportsCompression => true;
|
||||
public override bool SupportsDecompression => true;
|
||||
|
||||
public override Stream CreateCompressStream(Stream destination, int compressionLevel)
|
||||
{
|
||||
var level = (CompressionLevel)compressionLevel;
|
||||
return new GZipStream(destination, CompressionMode.Compress, level, Encoding.UTF8);
|
||||
}
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source)
|
||||
{
|
||||
return new GZipStream(source, CompressionMode.Decompress);
|
||||
}
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source, CompressionContext context)
|
||||
{
|
||||
return new GZipStream(
|
||||
source,
|
||||
CompressionMode.Decompress,
|
||||
CompressionLevel.Default,
|
||||
context.ResolveArchiveEncoding()
|
||||
);
|
||||
}
|
||||
|
||||
public override ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CompressionContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new ValueTask<Stream>(CreateDecompressStream(source, context));
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides LZip compression using SharpCompress's internal implementation.
|
||||
/// </summary>
|
||||
public sealed class LZipCompressionProvider : CompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.LZip;
|
||||
public override bool SupportsCompression => true;
|
||||
public override bool SupportsDecompression => true;
|
||||
|
||||
public override Stream CreateCompressStream(Stream destination, int compressionLevel)
|
||||
{
|
||||
return new LZipStream(destination, CompressionMode.Compress);
|
||||
}
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source)
|
||||
{
|
||||
return new LZipStream(source, CompressionMode.Decompress);
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides LZMA compression and decompression using SharpCompress's internal implementation.
|
||||
/// This is a complex provider that requires initialization data for compression.
|
||||
/// </summary>
|
||||
public sealed class LzmaCompressingProvider : CompressionProviderBase, ICompressionProviderHooks
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.LZMA;
|
||||
public override bool SupportsCompression => true;
|
||||
public override bool SupportsDecompression => true;
|
||||
|
||||
public override Stream CreateCompressStream(Stream destination, int compressionLevel)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"LZMA compression requires context with CanSeek information. "
|
||||
+ "Use CreateCompressStream(Stream, int, CompressionContext) overload."
|
||||
);
|
||||
}
|
||||
|
||||
public override Stream CreateCompressStream(
|
||||
Stream destination,
|
||||
int compressionLevel,
|
||||
CompressionContext context
|
||||
)
|
||||
{
|
||||
// LZMA stream creation returns the encoder stream
|
||||
// Note: Pre-compression data and properties are handled via ICompressionProviderHooks methods
|
||||
var props = new LzmaEncoderProperties(!context.CanSeek);
|
||||
return LzmaStream.Create(props, false, destination);
|
||||
}
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"LZMA decompression requires properties. "
|
||||
+ "Use CreateDecompressStream(Stream, CompressionContext) overload with Properties."
|
||||
);
|
||||
}
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source, CompressionContext context)
|
||||
{
|
||||
if (context.Properties is null || context.Properties.Length < 5)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"LZMA decompression requires Properties (at least 5 bytes) in CompressionContext.",
|
||||
nameof(context)
|
||||
);
|
||||
}
|
||||
|
||||
return LzmaStream.Create(context.Properties, source, context.InputSize, context.OutputSize);
|
||||
}
|
||||
|
||||
public override ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
throw new InvalidOperationException(
|
||||
"LZMA decompression requires properties. "
|
||||
+ "Use CreateDecompressStreamAsync(Stream, CompressionContext, CancellationToken) overload with Properties."
|
||||
);
|
||||
|
||||
public override async ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CompressionContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (context.Properties is null || context.Properties.Length < 5)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"LZMA decompression requires Properties (at least 5 bytes) in CompressionContext.",
|
||||
nameof(context)
|
||||
);
|
||||
}
|
||||
|
||||
return await LzmaStream
|
||||
.CreateAsync(
|
||||
context.Properties,
|
||||
source,
|
||||
context.InputSize,
|
||||
context.OutputSize,
|
||||
leaveOpen: false
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public byte[]? GetPreCompressionData(CompressionContext context)
|
||||
{
|
||||
// Zip format writes these magic bytes before the LZMA stream
|
||||
return new byte[] { 9, 20, 5, 0 };
|
||||
}
|
||||
|
||||
public byte[]? GetCompressionProperties(Stream stream, CompressionContext context)
|
||||
{
|
||||
// The LZMA stream exposes its properties after creation
|
||||
if (stream is LzmaStream lzmaStream)
|
||||
{
|
||||
return lzmaStream.Properties;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[]? GetPostCompressionData(Stream stream, CompressionContext context)
|
||||
{
|
||||
// No post-compression data needed for LZMA in Zip
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors.Lzw;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides LZW compression decompression using SharpCompress's internal implementation.
|
||||
/// Note: Compression is not supported by this provider.
|
||||
/// </summary>
|
||||
public sealed class LzwCompressionProvider : DecompressionOnlyProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.Lzw;
|
||||
protected override string CompressionNotSupportedMessage =>
|
||||
"LZW compression is not supported by SharpCompress's internal implementation.";
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source)
|
||||
{
|
||||
return new LzwStream(source);
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors.PPMd;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides PPMd compression and decompression using SharpCompress's internal implementation.
|
||||
/// This is a complex provider that requires initialization data for compression.
|
||||
/// </summary>
|
||||
public sealed class PpmdCompressingProvider : CompressionProviderBase, ICompressionProviderHooks
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.PPMd;
|
||||
public override bool SupportsCompression => true;
|
||||
public override bool SupportsDecompression => true;
|
||||
|
||||
public override Stream CreateCompressStream(Stream destination, int compressionLevel)
|
||||
{
|
||||
// Ppmd doesn't use compressionLevel, uses PpmdProperties instead
|
||||
var props = new PpmdProperties();
|
||||
return PpmdStream.Create(props, destination, true);
|
||||
}
|
||||
|
||||
public override Stream CreateCompressStream(
|
||||
Stream destination,
|
||||
int compressionLevel,
|
||||
CompressionContext context
|
||||
)
|
||||
{
|
||||
// Context not used for Ppmd compression, but we could use FormatOptions for custom properties
|
||||
if (context.FormatOptions is PpmdProperties customProps)
|
||||
{
|
||||
return PpmdStream.Create(customProps, destination, true);
|
||||
}
|
||||
|
||||
return CreateCompressStream(destination, compressionLevel);
|
||||
}
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"PPMd decompression requires properties. "
|
||||
+ "Use CreateDecompressStream(Stream, CompressionContext) overload with Properties."
|
||||
);
|
||||
}
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source, CompressionContext context)
|
||||
{
|
||||
if (context.Properties is null || context.Properties.Length < 2)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"PPMd decompression requires Properties (at least 2 bytes) in CompressionContext.",
|
||||
nameof(context)
|
||||
);
|
||||
}
|
||||
|
||||
var props = new PpmdProperties(context.Properties);
|
||||
return PpmdStream.Create(props, source, false);
|
||||
}
|
||||
|
||||
public override ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
throw new InvalidOperationException(
|
||||
"PPMd decompression requires properties. "
|
||||
+ "Use CreateDecompressStreamAsync(Stream, CompressionContext, CancellationToken) overload with Properties."
|
||||
);
|
||||
|
||||
public override async ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CompressionContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (context.Properties is null || context.Properties.Length < 2)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"PPMd decompression requires Properties (at least 2 bytes) in CompressionContext.",
|
||||
nameof(context)
|
||||
);
|
||||
}
|
||||
|
||||
var props = new PpmdProperties(context.Properties);
|
||||
return await PpmdStream
|
||||
.CreateAsync(props, source, false, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public byte[]? GetPreCompressionData(CompressionContext context)
|
||||
{
|
||||
// Ppmd writes its properties before the compressed data
|
||||
if (context.FormatOptions is PpmdProperties customProps)
|
||||
{
|
||||
return customProps.Properties;
|
||||
}
|
||||
|
||||
var defaultProps = new PpmdProperties();
|
||||
return defaultProps.Properties;
|
||||
}
|
||||
|
||||
public byte[]? GetCompressionProperties(Stream stream, CompressionContext context)
|
||||
{
|
||||
// Properties are already written in GetPreCompressionData
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[]? GetPostCompressionData(Stream stream, CompressionContext context)
|
||||
{
|
||||
// No post-compression data needed for Ppmd
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides Reduce1 decompression using SharpCompress's internal implementation.
|
||||
/// Note: Reduce compression is not supported; this provider is decompression-only.
|
||||
/// </summary>
|
||||
public sealed class Reduce1CompressionProvider : ReduceCompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.Reduce1;
|
||||
protected override int Factor => 1;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides Reduce2 decompression using SharpCompress's internal implementation.
|
||||
/// Note: Reduce compression is not supported; this provider is decompression-only.
|
||||
/// </summary>
|
||||
public sealed class Reduce2CompressionProvider : ReduceCompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.Reduce2;
|
||||
protected override int Factor => 2;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides Reduce3 decompression using SharpCompress's internal implementation.
|
||||
/// Note: Reduce compression is not supported; this provider is decompression-only.
|
||||
/// </summary>
|
||||
public sealed class Reduce3CompressionProvider : ReduceCompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.Reduce3;
|
||||
protected override int Factor => 3;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides Reduce4 decompression using SharpCompress's internal implementation.
|
||||
/// Note: Reduce compression is not supported; this provider is decompression-only.
|
||||
/// </summary>
|
||||
public sealed class Reduce4CompressionProvider : ReduceCompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.Reduce4;
|
||||
protected override int Factor => 4;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors.Reduce;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
public abstract class ReduceCompressionProviderBase : ContextRequiredDecompressionProviderBase
|
||||
{
|
||||
protected abstract int Factor { get; }
|
||||
|
||||
protected override string DecompressionContextRequirementDescription =>
|
||||
"Reduce decompression requires compressed and uncompressed sizes";
|
||||
|
||||
protected override string CompressionNotSupportedMessage =>
|
||||
"Reduce compression is not supported by SharpCompress's internal implementation.";
|
||||
|
||||
public sealed override Stream CreateDecompressStream(Stream source, CompressionContext context)
|
||||
{
|
||||
ValidateRequiredSizes(context, "Reduce");
|
||||
return ReduceStream.Create(source, context.InputSize, context.OutputSize, Factor);
|
||||
}
|
||||
|
||||
public sealed override async ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CompressionContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
ValidateRequiredSizes(context, "Reduce");
|
||||
return await ReduceStream
|
||||
.CreateAsync(source, context.InputSize, context.OutputSize, Factor, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.Shrink;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides Shrink decompression using SharpCompress's internal implementation.
|
||||
/// Note: Shrink compression is not supported; this provider is decompression-only.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Shrink requires compressed and uncompressed sizes which must be provided via CompressionContext.
|
||||
/// </remarks>
|
||||
public sealed class ShrinkCompressionProvider : ContextRequiredDecompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.Shrink;
|
||||
protected override string CompressionNotSupportedMessage =>
|
||||
"Shrink compression is not supported by SharpCompress's internal implementation.";
|
||||
|
||||
protected override string DecompressionContextRequirementDescription =>
|
||||
"Shrink decompression requires compressed and uncompressed sizes";
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source, CompressionContext context)
|
||||
{
|
||||
ValidateRequiredSizes(context, "Shrink");
|
||||
|
||||
return new ShrinkStream(
|
||||
source,
|
||||
CompressionMode.Decompress,
|
||||
context.InputSize,
|
||||
context.OutputSize
|
||||
);
|
||||
}
|
||||
|
||||
public override async ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CompressionContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
ValidateRequiredSizes(context, "Shrink");
|
||||
|
||||
return await ShrinkStream
|
||||
.CreateAsync(
|
||||
source,
|
||||
CompressionMode.Decompress,
|
||||
context.InputSize,
|
||||
context.OutputSize,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors.Xz;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides XZ compression decompression using SharpCompress's internal implementation.
|
||||
/// Note: Compression is not supported by this provider.
|
||||
/// </summary>
|
||||
public sealed class XzCompressionProvider : DecompressionOnlyProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.Xz;
|
||||
protected override string CompressionNotSupportedMessage =>
|
||||
"XZ compression is not supported by SharpCompress's internal implementation.";
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source)
|
||||
{
|
||||
return new XZStream(source);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using ZStd = SharpCompress.Compressors.ZStandard;
|
||||
|
||||
namespace SharpCompress.Providers.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Provides ZStandard compression using SharpCompress's internal implementation.
|
||||
/// </summary>
|
||||
public sealed class ZStandardCompressionProvider : CompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.ZStandard;
|
||||
public override bool SupportsCompression => true;
|
||||
public override bool SupportsDecompression => true;
|
||||
|
||||
public override Stream CreateCompressStream(Stream destination, int compressionLevel)
|
||||
{
|
||||
return new ZStd.CompressionStream(destination, compressionLevel);
|
||||
}
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source)
|
||||
{
|
||||
return new ZStd.DecompressionStream(source);
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Providers;
|
||||
|
||||
/// <summary>
|
||||
/// Provides compression and decompression stream creation for a specific compression type.
|
||||
/// Implement this interface to supply alternative compression implementations.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This interface abstracts the creation of compression and decompression streams,
|
||||
/// allowing SharpCompress to use different implementations of the same compression type.
|
||||
/// For example, you can provide an implementation that uses System.IO.Compression
|
||||
/// for Deflate/GZip instead of the internal DotNetZip-derived implementation.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Implementations should be thread-safe for concurrent decompression operations,
|
||||
/// but CreateCompressStream/CreateDecompressStream themselves return new stream instances
|
||||
/// that are not shared.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// For simpler implementations, derive from <see cref="CompressionProviderBase"/> which provides
|
||||
/// default async implementations that delegate to the synchronous methods.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public interface ICompressionProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// The compression type this provider handles.
|
||||
/// </summary>
|
||||
CompressionType CompressionType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this provider supports compression (writing).
|
||||
/// </summary>
|
||||
bool SupportsCompression { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this provider supports decompression (reading).
|
||||
/// </summary>
|
||||
bool SupportsDecompression { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a compression stream that compresses data written to it.
|
||||
/// </summary>
|
||||
/// <param name="destination">The destination stream to write compressed data to.</param>
|
||||
/// <param name="compressionLevel">The compression level (0-9, algorithm-specific).</param>
|
||||
/// <returns>A stream that compresses data written to it.</returns>
|
||||
/// <exception cref="NotSupportedException">Thrown if SupportsCompression is false.</exception>
|
||||
Stream CreateCompressStream(Stream destination, int compressionLevel);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a compression stream with context information.
|
||||
/// </summary>
|
||||
/// <param name="destination">The destination stream.</param>
|
||||
/// <param name="compressionLevel">The compression level.</param>
|
||||
/// <param name="context">Context information about the compression.</param>
|
||||
/// <returns>A compression stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Thrown if SupportsCompression is false.</exception>
|
||||
Stream CreateCompressStream(
|
||||
Stream destination,
|
||||
int compressionLevel,
|
||||
CompressionContext context
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a decompression stream that decompresses data read from it.
|
||||
/// </summary>
|
||||
/// <param name="source">The source stream to read compressed data from.</param>
|
||||
/// <returns>A stream that decompresses data read from it.</returns>
|
||||
/// <exception cref="NotSupportedException">Thrown if SupportsDecompression is false.</exception>
|
||||
Stream CreateDecompressStream(Stream source);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a decompression stream with context information.
|
||||
/// </summary>
|
||||
/// <param name="source">The source stream.</param>
|
||||
/// <param name="context">
|
||||
/// Context information about the decompression. Providers may use
|
||||
/// <see cref="CompressionContext.ReaderOptions"/> for archive header encoding
|
||||
/// (via <see cref="ReaderOptions.ArchiveEncoding"/>) and
|
||||
/// <see cref="CompressionContext.FormatOptions"/> for format-specific metadata
|
||||
/// such as compression properties or algorithm-specific configuration.
|
||||
/// </param>
|
||||
/// <returns>A decompression stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Thrown if SupportsDecompression is false.</exception>
|
||||
Stream CreateDecompressStream(Stream source, CompressionContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously creates a compression stream that compresses data written to it.
|
||||
/// </summary>
|
||||
/// <param name="destination">The destination stream to write compressed data to.</param>
|
||||
/// <param name="compressionLevel">The compression level (0-9, algorithm-specific).</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task containing the compression stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Thrown if SupportsCompression is false.</exception>
|
||||
ValueTask<Stream> CreateCompressStreamAsync(
|
||||
Stream destination,
|
||||
int compressionLevel,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously creates a compression stream with context information.
|
||||
/// </summary>
|
||||
/// <param name="destination">The destination stream.</param>
|
||||
/// <param name="compressionLevel">The compression level.</param>
|
||||
/// <param name="context">Context information about the compression.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task containing the compression stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Thrown if SupportsCompression is false.</exception>
|
||||
ValueTask<Stream> CreateCompressStreamAsync(
|
||||
Stream destination,
|
||||
int compressionLevel,
|
||||
CompressionContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously creates a decompression stream that decompresses data read from it.
|
||||
/// </summary>
|
||||
/// <param name="source">The source stream to read compressed data from.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task containing the decompression stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Thrown if SupportsDecompression is false.</exception>
|
||||
ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously creates a decompression stream with context information.
|
||||
/// </summary>
|
||||
/// <param name="source">The source stream.</param>
|
||||
/// <param name="context">
|
||||
/// Context information about the decompression. Providers may use
|
||||
/// <see cref="CompressionContext.FormatOptions"/> for format-specific metadata
|
||||
/// (for example, archive header encoding).
|
||||
/// </param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task containing the decompression stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Thrown if SupportsDecompression is false.</exception>
|
||||
ValueTask<Stream> CreateDecompressStreamAsync(
|
||||
Stream source,
|
||||
CompressionContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Providers;
|
||||
|
||||
/// <summary>
|
||||
/// Extended compression provider interface for formats that require initialization/finalization data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Some compression formats (like LZMA and PPMd in Zip) require special handling:
|
||||
/// - Data written before compression starts (magic bytes, properties headers)
|
||||
/// - Data written after compression completes (properties, footers)
|
||||
/// This interface extends ICompressionProvider to support these complex initialization patterns
|
||||
/// while keeping the simple ICompressionProvider interface for formats that don't need it.
|
||||
/// </remarks>
|
||||
public interface ICompressionProviderHooks : ICompressionProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets initialization data to write before compression starts.
|
||||
/// Returns null if no pre-compression data is needed.
|
||||
/// </summary>
|
||||
/// <param name="context">Context information.</param>
|
||||
/// <returns>Bytes to write before compression, or null.</returns>
|
||||
byte[]? GetPreCompressionData(CompressionContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Gets properties/data to write after creating the compression stream but before writing data.
|
||||
/// Returns null if no properties are needed.
|
||||
/// </summary>
|
||||
/// <param name="stream">The compression stream that was created.</param>
|
||||
/// <param name="context">Context information.</param>
|
||||
/// <returns>Bytes to write after stream creation, or null.</returns>
|
||||
byte[]? GetCompressionProperties(Stream stream, CompressionContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Gets data to write after compression is complete.
|
||||
/// Returns null if no post-compression data is needed.
|
||||
/// </summary>
|
||||
/// <param name="stream">The compression stream.</param>
|
||||
/// <param name="context">Context information.</param>
|
||||
/// <returns>Bytes to write after compression, or null.</returns>
|
||||
byte[]? GetPostCompressionData(Stream stream, CompressionContext context);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
namespace SharpCompress.Providers;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for compression streams that require explicit finalization
|
||||
/// before disposal to ensure all compressed data is flushed properly.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Some compression formats (notably BZip2 and LZip) require explicit
|
||||
/// finalization to write trailer/footer data. Implementing this interface
|
||||
/// allows generic code to handle finalization without knowing the specific stream type.
|
||||
/// </remarks>
|
||||
public interface IFinishable
|
||||
{
|
||||
/// <summary>
|
||||
/// Finalizes the compression, flushing any remaining buffered data
|
||||
/// and writing format-specific trailer/footer bytes.
|
||||
/// </summary>
|
||||
void Finish();
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Providers.System;
|
||||
|
||||
/// <summary>
|
||||
/// Provides Deflate compression using System.IO.Compression.DeflateStream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// On modern .NET (5+), System.IO.Compression uses hardware-accelerated zlib
|
||||
/// and is significantly faster than SharpCompress's pure C# implementation.
|
||||
/// </remarks>
|
||||
public sealed class SystemDeflateCompressionProvider : CompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.Deflate;
|
||||
public override bool SupportsCompression => true;
|
||||
public override bool SupportsDecompression => true;
|
||||
|
||||
public override Stream CreateCompressStream(Stream destination, int compressionLevel)
|
||||
{
|
||||
var bclLevel = MapCompressionLevel(compressionLevel);
|
||||
return new DeflateStream(destination, bclLevel, leaveOpen: false);
|
||||
}
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source)
|
||||
{
|
||||
return new DeflateStream(
|
||||
source,
|
||||
global::System.IO.Compression.CompressionMode.Decompress,
|
||||
leaveOpen: false
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps SharpCompress compression level (0-9) to BCL CompressionLevel.
|
||||
/// </summary>
|
||||
private static global::System.IO.Compression.CompressionLevel MapCompressionLevel(int level)
|
||||
{
|
||||
// Map 0-9 to appropriate BCL levels
|
||||
return level switch
|
||||
{
|
||||
0 => global::System.IO.Compression.CompressionLevel.NoCompression,
|
||||
<= 2 => global::System.IO.Compression.CompressionLevel.Fastest,
|
||||
#if NET7_0_OR_GREATER
|
||||
>= 8 => global::System.IO.Compression.CompressionLevel.SmallestSize,
|
||||
#endif
|
||||
_ => global::System.IO.Compression.CompressionLevel.Optimal,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Providers.System;
|
||||
|
||||
/// <summary>
|
||||
/// Provides GZip compression using System.IO.Compression.GZipStream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// On modern .NET (5+), System.IO.Compression uses hardware-accelerated zlib
|
||||
/// and is significantly faster than SharpCompress's pure C# implementation.
|
||||
/// </remarks>
|
||||
public sealed class SystemGZipCompressionProvider : CompressionProviderBase
|
||||
{
|
||||
public override CompressionType CompressionType => CompressionType.GZip;
|
||||
public override bool SupportsCompression => true;
|
||||
public override bool SupportsDecompression => true;
|
||||
|
||||
public override Stream CreateCompressStream(Stream destination, int compressionLevel)
|
||||
{
|
||||
var bclLevel = MapCompressionLevel(compressionLevel);
|
||||
return new GZipStream(destination, bclLevel, leaveOpen: false);
|
||||
}
|
||||
|
||||
public override Stream CreateDecompressStream(Stream source)
|
||||
{
|
||||
return new GZipStream(
|
||||
source,
|
||||
global::System.IO.Compression.CompressionMode.Decompress,
|
||||
leaveOpen: false
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps SharpCompress compression level (0-9) to BCL CompressionLevel.
|
||||
/// </summary>
|
||||
private static global::System.IO.Compression.CompressionLevel MapCompressionLevel(int level)
|
||||
{
|
||||
// Map 0-9 to appropriate BCL levels
|
||||
return level switch
|
||||
{
|
||||
0 => global::System.IO.Compression.CompressionLevel.NoCompression,
|
||||
<= 2 => global::System.IO.Compression.CompressionLevel.Fastest,
|
||||
#if NET7_0_OR_GREATER
|
||||
>= 8 => global::System.IO.Compression.CompressionLevel.SmallestSize,
|
||||
#endif
|
||||
_ => global::System.IO.Compression.CompressionLevel.Optimal,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -43,10 +43,7 @@ public abstract partial class AbstractReader<TEntry, TVolume>
|
||||
}
|
||||
if (_entriesForCurrentReadStreamAsync is null)
|
||||
{
|
||||
return await LoadStreamForReadingAsync(
|
||||
await RequestInitialStreamAsync(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
return await LoadStreamForReadingAsync(RequestInitialStream()).ConfigureAwait(false);
|
||||
}
|
||||
if (!_wroteCurrentEntry)
|
||||
{
|
||||
|
||||
@@ -2,8 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
@@ -142,10 +140,6 @@ public abstract partial class AbstractReader<TEntry, TVolume> : IReader, IAsyncR
|
||||
protected virtual Stream RequestInitialStream() =>
|
||||
Volume.NotNull("Volume isn't loaded.").Stream;
|
||||
|
||||
protected virtual ValueTask<Stream> RequestInitialStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
) => new(RequestInitialStream());
|
||||
|
||||
internal virtual bool NextEntryForCurrentStream() =>
|
||||
_entriesForCurrentReadStream.NotNull().MoveNext();
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Readers.Ace;
|
||||
@@ -35,25 +33,15 @@ public partial class AceReader
|
||||
return new MultiVolumeAceReader(streams, options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return new((IAsyncReader)OpenReader(new FileInfo(path), readerOptions));
|
||||
return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(stream, readerOptions));
|
||||
return (IAsyncReader)OpenReader(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static IAsyncReader OpenAsyncReader(
|
||||
@@ -65,14 +53,12 @@ public partial class AceReader
|
||||
return new MultiVolumeAceReader(streams, options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
public static IAsyncReader OpenAsyncReader(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(fileInfo, readerOptions));
|
||||
return (IAsyncReader)OpenReader(fileInfo, readerOptions);
|
||||
}
|
||||
|
||||
public static IReader OpenReader(string filePath, ReaderOptions? readerOptions = null)
|
||||
|
||||
@@ -1,42 +1,28 @@
|
||||
#if NET8_0_OR_GREATER
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Readers.Arc;
|
||||
|
||||
public partial class ArcReader : IReaderOpenable
|
||||
{
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return new((IAsyncReader)OpenReader(new FileInfo(path), readerOptions));
|
||||
return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(stream, readerOptions));
|
||||
return (IAsyncReader)OpenReader(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
public static IAsyncReader OpenAsyncReader(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(fileInfo, readerOptions));
|
||||
return (IAsyncReader)OpenReader(fileInfo, readerOptions);
|
||||
}
|
||||
|
||||
public static IReader OpenReader(string filePath, ReaderOptions? readerOptions = null)
|
||||
|
||||
@@ -1,42 +1,28 @@
|
||||
#if NET8_0_OR_GREATER
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Readers.Arj;
|
||||
|
||||
public partial class ArjReader : IReaderOpenable
|
||||
{
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return new((IAsyncReader)OpenReader(new FileInfo(path), readerOptions));
|
||||
return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(stream, readerOptions));
|
||||
return (IAsyncReader)OpenReader(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
public static IAsyncReader OpenAsyncReader(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(fileInfo, readerOptions));
|
||||
return (IAsyncReader)OpenReader(fileInfo, readerOptions);
|
||||
}
|
||||
|
||||
public static IReader OpenReader(string filePath, ReaderOptions? readerOptions = null)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Readers.GZip;
|
||||
|
||||
@@ -9,35 +7,23 @@ public partial class GZipReader
|
||||
: IReaderOpenable
|
||||
#endif
|
||||
{
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return new((IAsyncReader)OpenReader(new FileInfo(path), readerOptions));
|
||||
return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(stream, readerOptions));
|
||||
return (IAsyncReader)OpenReader(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
public static IAsyncReader OpenAsyncReader(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(fileInfo, readerOptions));
|
||||
return (IAsyncReader)OpenReader(fileInfo, readerOptions);
|
||||
}
|
||||
|
||||
public static IReader OpenReader(string filePath, ReaderOptions? readerOptions = null)
|
||||
|
||||
@@ -9,18 +9,18 @@ public interface IReaderFactory : Factories.IFactory
|
||||
/// <summary>
|
||||
/// Opens a Reader for Non-seeking usage.
|
||||
/// </summary>
|
||||
/// <param name="stream">An open, readable stream.</param>
|
||||
/// <param name="options">Reader options.</param>
|
||||
/// <returns>The opened reader.</returns>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
IReader OpenReader(Stream stream, ReaderOptions? options);
|
||||
|
||||
/// <summary>
|
||||
/// Opens a Reader for Non-seeking usage asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="stream">An open, readable stream.</param>
|
||||
/// <param name="options">Reader options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> containing the opened async reader.</returns>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#if NET8_0_OR_GREATER
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Readers;
|
||||
|
||||
@@ -16,22 +15,19 @@ public interface IReaderOpenable
|
||||
|
||||
public static abstract IReader OpenReader(Stream stream, ReaderOptions? readerOptions = null);
|
||||
|
||||
public static abstract ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
public static abstract IAsyncReader OpenAsyncReader(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
|
||||
public static abstract ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
public static abstract IAsyncReader OpenAsyncReader(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
|
||||
public static abstract ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
public static abstract IAsyncReader OpenAsyncReader(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Readers.Lzw;
|
||||
|
||||
@@ -9,35 +7,23 @@ public partial class LzwReader
|
||||
: IReaderOpenable
|
||||
#endif
|
||||
{
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return new((IAsyncReader)OpenReader(new FileInfo(path), readerOptions));
|
||||
return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(stream, readerOptions));
|
||||
return (IAsyncReader)OpenReader(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
public static IAsyncReader OpenAsyncReader(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(fileInfo, readerOptions));
|
||||
return (IAsyncReader)OpenReader(fileInfo, readerOptions);
|
||||
}
|
||||
|
||||
public static IReader OpenReader(string filePath, ReaderOptions? readerOptions = null)
|
||||
|
||||
@@ -1,42 +1,28 @@
|
||||
#if NET8_0_OR_GREATER
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Readers.Rar;
|
||||
|
||||
public partial class RarReader : IReaderOpenable
|
||||
{
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return new((IAsyncReader)OpenReader(new FileInfo(path), readerOptions));
|
||||
return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(stream, readerOptions));
|
||||
return (IAsyncReader)OpenReader(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
public static IAsyncReader OpenAsyncReader(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(fileInfo, readerOptions));
|
||||
return (IAsyncReader)OpenReader(fileInfo, readerOptions);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -69,14 +69,20 @@ public static partial class ReaderFactory
|
||||
a.GetSupportedExtensions()
|
||||
.Contains(options.ExtensionHint, StringComparer.CurrentCultureIgnoreCase)
|
||||
);
|
||||
if (testedFactory is not null)
|
||||
if (testedFactory is IReaderFactory readerFactory)
|
||||
{
|
||||
var reader = await testedFactory
|
||||
.TryOpenReaderAsync(sharpCompressStream, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (reader is not null)
|
||||
sharpCompressStream.Rewind();
|
||||
if (
|
||||
await testedFactory
|
||||
.IsArchiveAsync(sharpCompressStream, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
return reader;
|
||||
sharpCompressStream.Rewind();
|
||||
sharpCompressStream.StopRecording();
|
||||
return await readerFactory
|
||||
.OpenAsyncReader(sharpCompressStream, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
sharpCompressStream.Rewind();
|
||||
@@ -88,12 +94,19 @@ public static partial class ReaderFactory
|
||||
{
|
||||
continue; // Already tested above
|
||||
}
|
||||
var reader = await factory
|
||||
.TryOpenReaderAsync(sharpCompressStream, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (reader is not null)
|
||||
sharpCompressStream.Rewind();
|
||||
if (
|
||||
factory is IReaderFactory readerFactory
|
||||
&& await factory
|
||||
.IsArchiveAsync(sharpCompressStream, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
return reader;
|
||||
sharpCompressStream.Rewind();
|
||||
sharpCompressStream.StopRecording();
|
||||
return await readerFactory
|
||||
.OpenAsyncReader(sharpCompressStream, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Factories;
|
||||
using SharpCompress.IO;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Readers;
|
||||
|
||||
@@ -23,6 +21,16 @@ namespace SharpCompress.Readers;
|
||||
/// </remarks>
|
||||
public sealed record ReaderOptions : IReaderOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The default buffer size for stream operations.
|
||||
/// This value (65536 bytes) is preserved for backward compatibility.
|
||||
/// New code should use Constants.BufferSize instead (81920 bytes), which matches .NET's Stream.CopyTo default.
|
||||
/// </summary>
|
||||
[Obsolete(
|
||||
"Use Constants.BufferSize instead. This constant will be removed in a future version."
|
||||
)]
|
||||
public const int DefaultBufferSize = 0x10000;
|
||||
|
||||
/// <summary>
|
||||
/// SharpCompress will keep the supplied streams open. Default is true.
|
||||
/// </summary>
|
||||
@@ -141,14 +149,6 @@ public sealed record ReaderOptions : IReaderOptions
|
||||
/// </remarks>
|
||||
public Action<string, string>? SymbolicLinkHandler { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Registry of compression providers.
|
||||
/// Defaults to <see cref="CompressionProviderRegistry.Default" /> but can be replaced with custom implementations, such as
|
||||
/// System.IO.Compression for Deflate/GZip on modern .NET.
|
||||
/// </summary>
|
||||
public CompressionProviderRegistry Providers { get; init; } =
|
||||
CompressionProviderRegistry.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ReaderOptions instance with default values.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Readers;
|
||||
|
||||
@@ -126,17 +124,4 @@ public static class ReaderOptionsExtensions
|
||||
this ReaderOptions options,
|
||||
Action<string, string>? handler
|
||||
) => options with { SymbolicLinkHandler = handler };
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy with the specified compression provider registry.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentNullException">Thrown if <paramref name="providers"/> is null.</exception>
|
||||
public static ReaderOptions WithProviders(
|
||||
this ReaderOptions options,
|
||||
CompressionProviderRegistry providers
|
||||
)
|
||||
{
|
||||
_ = providers ?? throw new ArgumentNullException(nameof(providers));
|
||||
return options with { Providers = providers };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Archives.GZip;
|
||||
using SharpCompress.Archives.Tar;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Tar;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.BZip2;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Compressors.Lzw;
|
||||
using SharpCompress.Compressors.Xz;
|
||||
using SharpCompress.Compressors.ZStandard;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Readers.Tar;
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Archives.Tar;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Factories;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Readers.Tar;
|
||||
|
||||
@@ -14,133 +8,23 @@ public partial class TarReader
|
||||
: IReaderOpenable
|
||||
#endif
|
||||
{
|
||||
private static Stream CreateProbeDecompressionStream(
|
||||
Stream stream,
|
||||
CompressionType compressionType,
|
||||
CompressionProviderRegistry providers,
|
||||
ReaderOptions options
|
||||
)
|
||||
{
|
||||
var nonDisposingStream = SharpCompressStream.CreateNonDisposing(stream);
|
||||
if (compressionType == CompressionType.None)
|
||||
{
|
||||
return nonDisposingStream;
|
||||
}
|
||||
|
||||
if (compressionType == CompressionType.GZip)
|
||||
{
|
||||
return providers.CreateDecompressStream(
|
||||
compressionType,
|
||||
nonDisposingStream,
|
||||
CompressionContext.FromStream(nonDisposingStream).WithReaderOptions(options)
|
||||
);
|
||||
}
|
||||
|
||||
return providers.CreateDecompressStream(compressionType, nonDisposingStream);
|
||||
}
|
||||
|
||||
private static async ValueTask<Stream> CreateProbeDecompressionStreamAsync(
|
||||
Stream stream,
|
||||
CompressionType compressionType,
|
||||
CompressionProviderRegistry providers,
|
||||
ReaderOptions options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var nonDisposingStream = SharpCompressStream.CreateNonDisposing(stream);
|
||||
if (compressionType == CompressionType.None)
|
||||
{
|
||||
return nonDisposingStream;
|
||||
}
|
||||
|
||||
if (compressionType == CompressionType.GZip)
|
||||
{
|
||||
return await providers
|
||||
.CreateDecompressStreamAsync(
|
||||
compressionType,
|
||||
nonDisposingStream,
|
||||
CompressionContext.FromStream(nonDisposingStream).WithReaderOptions(options),
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return await providers
|
||||
.CreateDecompressStreamAsync(compressionType, nonDisposingStream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return OpenAsyncReader(new FileInfo(path), readerOptions, cancellationToken);
|
||||
return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions);
|
||||
}
|
||||
|
||||
public static async ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
Stream stream,
|
||||
ReaderOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
stream.NotNull(nameof(stream));
|
||||
options ??= new ReaderOptions();
|
||||
var sharpCompressStream = SharpCompressStream.Create(
|
||||
stream,
|
||||
bufferSize: options.RewindableBufferSize
|
||||
);
|
||||
long pos = sharpCompressStream.Position;
|
||||
foreach (var wrapper in TarWrapper.Wrappers)
|
||||
{
|
||||
sharpCompressStream.Position = pos;
|
||||
if (
|
||||
!await wrapper
|
||||
.IsMatchAsync(sharpCompressStream, cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sharpCompressStream.Position = pos;
|
||||
var testStream = await CreateProbeDecompressionStreamAsync(
|
||||
sharpCompressStream,
|
||||
wrapper.CompressionType,
|
||||
options.Providers,
|
||||
options,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
if (
|
||||
await TarArchive.IsTarFileAsync(testStream, cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
sharpCompressStream.Position = pos;
|
||||
return new TarReader(sharpCompressStream, options, wrapper.CompressionType);
|
||||
}
|
||||
|
||||
if (wrapper.CompressionType != CompressionType.None)
|
||||
{
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
}
|
||||
|
||||
sharpCompressStream.Position = pos;
|
||||
return new TarReader(sharpCompressStream, options, CompressionType.None);
|
||||
return (IAsyncReader)OpenReader(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
public static IAsyncReader OpenAsyncReader(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
readerOptions ??= new ReaderOptions() { LeaveStreamOpen = false };
|
||||
return OpenAsyncReader(fileInfo.OpenRead(), readerOptions, cancellationToken);
|
||||
return (IAsyncReader)OpenReader(fileInfo, readerOptions);
|
||||
}
|
||||
|
||||
public static IReader OpenReader(string filePath, ReaderOptions? readerOptions = null)
|
||||
@@ -152,53 +36,6 @@ public partial class TarReader
|
||||
public static IReader OpenReader(FileInfo fileInfo, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
readerOptions ??= new ReaderOptions() { LeaveStreamOpen = false };
|
||||
return OpenReader(fileInfo.OpenRead(), readerOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a TarReader for Non-seeking usage with a single volume
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
public static IReader OpenReader(Stream stream, ReaderOptions? options = null)
|
||||
{
|
||||
stream.NotNull(nameof(stream));
|
||||
options ??= new ReaderOptions();
|
||||
var sharpCompressStream = SharpCompressStream.Create(
|
||||
stream,
|
||||
bufferSize: options.RewindableBufferSize
|
||||
);
|
||||
long pos = sharpCompressStream.Position;
|
||||
foreach (var wrapper in TarWrapper.Wrappers)
|
||||
{
|
||||
sharpCompressStream.Position = pos;
|
||||
if (!wrapper.IsMatch(sharpCompressStream))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sharpCompressStream.Position = pos;
|
||||
var testStream = CreateProbeDecompressionStream(
|
||||
sharpCompressStream,
|
||||
wrapper.CompressionType,
|
||||
options.Providers,
|
||||
options
|
||||
);
|
||||
if (TarArchive.IsTarFile(testStream))
|
||||
{
|
||||
sharpCompressStream.Position = pos;
|
||||
return new TarReader(sharpCompressStream, options, wrapper.CompressionType);
|
||||
}
|
||||
|
||||
if (wrapper.CompressionType != CompressionType.None)
|
||||
{
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
}
|
||||
|
||||
sharpCompressStream.Position = pos;
|
||||
return new TarReader(sharpCompressStream, options, CompressionType.None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Archives.GZip;
|
||||
using SharpCompress.Archives.Tar;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Tar;
|
||||
using SharpCompress.Compressors;
|
||||
@@ -13,7 +13,6 @@ using SharpCompress.Compressors.Lzw;
|
||||
using SharpCompress.Compressors.Xz;
|
||||
using SharpCompress.Compressors.ZStandard;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Readers.Tar;
|
||||
|
||||
@@ -33,77 +32,93 @@ public partial class TarReader : AbstractReader<TarEntry, TarVolume>
|
||||
protected override Stream RequestInitialStream()
|
||||
{
|
||||
var stream = base.RequestInitialStream();
|
||||
|
||||
var providers = Options.Providers;
|
||||
|
||||
return compressionType switch
|
||||
{
|
||||
CompressionType.BZip2 => providers.CreateDecompressStream(
|
||||
CompressionType.BZip2,
|
||||
stream
|
||||
),
|
||||
CompressionType.GZip => providers.CreateDecompressStream(
|
||||
CompressionType.GZip,
|
||||
stream,
|
||||
CompressionContext.FromStream(stream).WithReaderOptions(Options)
|
||||
),
|
||||
CompressionType.ZStandard => providers.CreateDecompressStream(
|
||||
CompressionType.ZStandard,
|
||||
stream
|
||||
),
|
||||
CompressionType.LZip => providers.CreateDecompressStream(CompressionType.LZip, stream),
|
||||
CompressionType.Xz => providers.CreateDecompressStream(CompressionType.Xz, stream),
|
||||
CompressionType.Lzw => providers.CreateDecompressStream(CompressionType.Lzw, stream),
|
||||
CompressionType.BZip2 => BZip2Stream.Create(stream, CompressionMode.Decompress, false),
|
||||
CompressionType.GZip => new GZipStream(stream, CompressionMode.Decompress),
|
||||
CompressionType.ZStandard => new ZStandardStream(stream),
|
||||
CompressionType.LZip => new LZipStream(stream, CompressionMode.Decompress),
|
||||
CompressionType.Xz => new XZStream(stream),
|
||||
CompressionType.Lzw => new LzwStream(stream),
|
||||
CompressionType.None => stream,
|
||||
_ => throw new NotSupportedException("Invalid compression type: " + compressionType),
|
||||
};
|
||||
}
|
||||
|
||||
protected override ValueTask<Stream> RequestInitialStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var stream = base.RequestInitialStream();
|
||||
var providers = Options.Providers;
|
||||
#region OpenReader
|
||||
|
||||
return compressionType switch
|
||||
/// <summary>
|
||||
/// Opens a TarReader for Non-seeking usage with a single volume
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
public static IReader OpenReader(Stream stream, ReaderOptions? options = null)
|
||||
{
|
||||
stream.NotNull(nameof(stream));
|
||||
options = options ?? new ReaderOptions();
|
||||
var sharpCompressStream = SharpCompressStream.Create(
|
||||
stream,
|
||||
bufferSize: options.RewindableBufferSize
|
||||
);
|
||||
long pos = sharpCompressStream.Position;
|
||||
if (GZipArchive.IsGZipFile(sharpCompressStream))
|
||||
{
|
||||
CompressionType.BZip2 => providers.CreateDecompressStreamAsync(
|
||||
CompressionType.BZip2,
|
||||
stream,
|
||||
cancellationToken
|
||||
),
|
||||
CompressionType.GZip => providers.CreateDecompressStreamAsync(
|
||||
CompressionType.GZip,
|
||||
stream,
|
||||
CompressionContext.FromStream(stream).WithReaderOptions(Options),
|
||||
cancellationToken
|
||||
),
|
||||
CompressionType.ZStandard => providers.CreateDecompressStreamAsync(
|
||||
CompressionType.ZStandard,
|
||||
stream,
|
||||
cancellationToken
|
||||
),
|
||||
CompressionType.LZip => providers.CreateDecompressStreamAsync(
|
||||
CompressionType.LZip,
|
||||
stream,
|
||||
cancellationToken
|
||||
),
|
||||
CompressionType.Xz => providers.CreateDecompressStreamAsync(
|
||||
CompressionType.Xz,
|
||||
stream,
|
||||
cancellationToken
|
||||
),
|
||||
CompressionType.Lzw => providers.CreateDecompressStreamAsync(
|
||||
CompressionType.Lzw,
|
||||
stream,
|
||||
cancellationToken
|
||||
),
|
||||
CompressionType.None => new ValueTask<Stream>(stream),
|
||||
_ => throw new NotSupportedException("Invalid compression type: " + compressionType),
|
||||
};
|
||||
sharpCompressStream.Position = pos;
|
||||
var testStream = new GZipStream(sharpCompressStream, CompressionMode.Decompress);
|
||||
if (TarArchive.IsTarFile(testStream))
|
||||
{
|
||||
sharpCompressStream.Position = pos;
|
||||
return new TarReader(sharpCompressStream, options, CompressionType.GZip);
|
||||
}
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
sharpCompressStream.Position = pos;
|
||||
if (BZip2Stream.IsBZip2(sharpCompressStream))
|
||||
{
|
||||
sharpCompressStream.Position = pos;
|
||||
var testStream = BZip2Stream.Create(
|
||||
sharpCompressStream,
|
||||
CompressionMode.Decompress,
|
||||
false
|
||||
);
|
||||
if (TarArchive.IsTarFile(testStream))
|
||||
{
|
||||
sharpCompressStream.Position = pos;
|
||||
return new TarReader(sharpCompressStream, options, CompressionType.BZip2);
|
||||
}
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
sharpCompressStream.Position = pos;
|
||||
if (ZStandardStream.IsZStandard(sharpCompressStream))
|
||||
{
|
||||
sharpCompressStream.Position = pos;
|
||||
var testStream = new ZStandardStream(sharpCompressStream);
|
||||
if (TarArchive.IsTarFile(testStream))
|
||||
{
|
||||
sharpCompressStream.Position = pos;
|
||||
return new TarReader(sharpCompressStream, options, CompressionType.ZStandard);
|
||||
}
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
sharpCompressStream.Position = pos;
|
||||
if (LZipStream.IsLZipFile(sharpCompressStream))
|
||||
{
|
||||
sharpCompressStream.Position = pos;
|
||||
var testStream = new LZipStream(sharpCompressStream, CompressionMode.Decompress);
|
||||
if (TarArchive.IsTarFile(testStream))
|
||||
{
|
||||
sharpCompressStream.Position = pos;
|
||||
return new TarReader(sharpCompressStream, options, CompressionType.LZip);
|
||||
}
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
sharpCompressStream.Position = pos;
|
||||
return new TarReader(sharpCompressStream, options, CompressionType.None);
|
||||
}
|
||||
|
||||
#endregion OpenReader
|
||||
|
||||
protected override IEnumerable<TarEntry> GetEntries(Stream stream) =>
|
||||
TarEntry.GetEntries(
|
||||
StreamingMode.Streaming,
|
||||
@@ -112,4 +127,6 @@ public partial class TarReader : AbstractReader<TarEntry, TarVolume>
|
||||
Options.ArchiveEncoding,
|
||||
Options
|
||||
);
|
||||
|
||||
// GetEntriesAsync moved to TarReader.Async.cs
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Common.Zip;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.Compressors;
|
||||
|
||||
namespace SharpCompress.Readers.Zip;
|
||||
|
||||
@@ -78,11 +77,7 @@ public partial class ZipReader
|
||||
{
|
||||
case ZipHeaderType.LocalEntry:
|
||||
_current = new ZipEntry(
|
||||
new StreamingZipFilePart(
|
||||
(LocalEntryHeader)header,
|
||||
_stream,
|
||||
_options.Providers
|
||||
),
|
||||
new StreamingZipFilePart((LocalEntryHeader)header, _stream),
|
||||
_options
|
||||
);
|
||||
return true;
|
||||
|
||||
@@ -1,42 +1,28 @@
|
||||
#if NET8_0_OR_GREATER
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Readers.Zip;
|
||||
|
||||
public partial class ZipReader : IReaderOpenable
|
||||
{
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return new((IAsyncReader)OpenReader(new FileInfo(path), readerOptions));
|
||||
return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(stream, readerOptions));
|
||||
return (IAsyncReader)OpenReader(stream, readerOptions);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncReader> OpenAsyncReader(
|
||||
public static IAsyncReader OpenAsyncReader(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncReader)OpenReader(fileInfo, readerOptions));
|
||||
return (IAsyncReader)OpenReader(fileInfo, readerOptions);
|
||||
}
|
||||
|
||||
public static IReader OpenReader(string filePath, ReaderOptions? readerOptions = null)
|
||||
|
||||
@@ -74,11 +74,7 @@ public partial class ZipReader : AbstractReader<ZipEntry, ZipVolume>
|
||||
case ZipHeaderType.LocalEntry:
|
||||
{
|
||||
yield return new ZipEntry(
|
||||
new StreamingZipFilePart(
|
||||
(LocalEntryHeader)h,
|
||||
stream,
|
||||
Options.Providers
|
||||
),
|
||||
new StreamingZipFilePart((LocalEntryHeader)h, stream),
|
||||
Options
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,24 +18,14 @@ public sealed partial class GZipWriter : AbstractWriter
|
||||
{
|
||||
destination = SharpCompressStream.CreateNonDisposing(destination);
|
||||
}
|
||||
|
||||
// Use the configured compression providers
|
||||
var providers = WriterOptions.Providers;
|
||||
|
||||
// Create the GZip stream using the provider
|
||||
var compressionStream = providers.CreateCompressStream(
|
||||
CompressionType.GZip,
|
||||
destination,
|
||||
WriterOptions.CompressionLevel
|
||||
InitializeStream(
|
||||
new GZipStream(
|
||||
destination,
|
||||
CompressionMode.Compress,
|
||||
(CompressionLevel)(options?.CompressionLevel ?? (int)CompressionLevel.Default),
|
||||
WriterOptions.ArchiveEncoding.GetEncoding()
|
||||
)
|
||||
);
|
||||
|
||||
// If using internal GZipStream, set the encoding for header filename
|
||||
if (compressionStream is GZipStream gzipStream)
|
||||
{
|
||||
// Note: FileName and LastModified will be set in Write()
|
||||
}
|
||||
|
||||
InitializeStream(compressionStream);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
@@ -54,16 +44,11 @@ public sealed partial class GZipWriter : AbstractWriter
|
||||
{
|
||||
throw new ArgumentException("Can only write a single stream to a GZip file.");
|
||||
}
|
||||
|
||||
// Set metadata on the stream if it's the internal GZipStream
|
||||
if (OutputStream is GZipStream gzipStream)
|
||||
{
|
||||
gzipStream.FileName = filename;
|
||||
gzipStream.LastModified = modificationTime;
|
||||
}
|
||||
|
||||
var stream = (GZipStream)OutputStream;
|
||||
stream.FileName = filename;
|
||||
stream.LastModified = modificationTime;
|
||||
var progressStream = WrapWithProgress(source, filename);
|
||||
progressStream.CopyTo(OutputStream, Constants.BufferSize);
|
||||
progressStream.CopyTo(stream, Constants.BufferSize);
|
||||
_wroteToStream = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Providers;
|
||||
using SharpCompress.Writers;
|
||||
using D = SharpCompress.Compressors.Deflate;
|
||||
|
||||
@@ -68,14 +66,6 @@ public sealed record GZipWriterOptions : IWriterOptions
|
||||
/// </summary>
|
||||
public IProgress<ProgressReport>? Progress { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Registry of compression providers.
|
||||
/// Defaults to <see cref="CompressionProviderRegistry.Default" /> but can be replaced with custom implementations, such as
|
||||
/// System.IO.Compression for GZip on modern .NET.
|
||||
/// </summary>
|
||||
public CompressionProviderRegistry Providers { get; init; } =
|
||||
CompressionProviderRegistry.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GZipWriterOptions instance with default values.
|
||||
/// </summary>
|
||||
@@ -115,7 +105,6 @@ public sealed record GZipWriterOptions : IWriterOptions
|
||||
LeaveStreamOpen = options.LeaveStreamOpen;
|
||||
ArchiveEncoding = options.ArchiveEncoding;
|
||||
Progress = options.Progress;
|
||||
Providers = options.Providers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -128,6 +117,5 @@ public sealed record GZipWriterOptions : IWriterOptions
|
||||
LeaveStreamOpen = options.LeaveStreamOpen;
|
||||
ArchiveEncoding = options.ArchiveEncoding;
|
||||
Progress = options.Progress;
|
||||
Providers = options.Providers;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user