mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-14 05:25:41 +00:00
Compare commits
69 Commits
0.45.1
...
adam/fix-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb5394a194 | ||
|
|
7e0091cba5 | ||
|
|
0db412d710 | ||
|
|
8669948221 | ||
|
|
5263f43c29 | ||
|
|
eb5c5faa99 | ||
|
|
67bbdeab3d | ||
|
|
7a9c6b56b7 | ||
|
|
cd1684b81c | ||
|
|
26d49198f0 | ||
|
|
18eb140017 | ||
|
|
d138999445 | ||
|
|
7cef629a06 | ||
|
|
76352df852 | ||
|
|
69a434b0e7 | ||
|
|
39c9d68c4f | ||
|
|
da5cc69a06 | ||
|
|
6c2e27870d | ||
|
|
d667288a87 | ||
|
|
165239c971 | ||
|
|
d68b9d6a86 | ||
|
|
359b1093bc | ||
|
|
ebb8f16e44 | ||
|
|
6931a78bed | ||
|
|
c7dac12cd9 | ||
|
|
a505808549 | ||
|
|
a92f82ef28 | ||
|
|
ae0b4f5c4c | ||
|
|
0e72f5ad9d | ||
|
|
0c21681717 | ||
|
|
f2a9171dd8 | ||
|
|
0e2c33dd78 | ||
|
|
c81e78b5bb | ||
|
|
fb707aa676 | ||
|
|
147dbc878a | ||
|
|
06bd6d9bed | ||
|
|
7f6272807d | ||
|
|
89d948b4e1 | ||
|
|
51c42b89b4 | ||
|
|
5a319ffe2c | ||
|
|
bae660381c | ||
|
|
b2f1d007c6 | ||
|
|
33e9c78626 | ||
|
|
6f50545c31 | ||
|
|
ab1dd45e9c | ||
|
|
cd5da3da5d | ||
|
|
218af5a8b3 | ||
|
|
e786c00767 | ||
|
|
103ae60631 | ||
|
|
98d0f1913e | ||
|
|
8aa93f4e34 | ||
|
|
3689b893db | ||
|
|
fbec7dc083 | ||
|
|
7cf7623438 | ||
|
|
5e4094952a | ||
|
|
99d8eb9265 | ||
|
|
a9a0201ae9 | ||
|
|
5fe248eb45 | ||
|
|
c4fb32a56d | ||
|
|
54a00e2614 | ||
|
|
19ed4d16db | ||
|
|
d220532b16 | ||
|
|
6b035cb76e | ||
|
|
a3e3d9d0aa | ||
|
|
f0da1b3a93 | ||
|
|
04c3b84fc0 | ||
|
|
a9f2d3cf7f | ||
|
|
9c7d27d1e0 | ||
|
|
c48388ead2 |
@@ -299,6 +299,19 @@ dotnet_diagnostic.CA2251.severity = error
|
||||
dotnet_diagnostic.CA2252.severity = none
|
||||
dotnet_diagnostic.CA2254.severity = suggestion
|
||||
|
||||
; High volume analyzers requiring extensive refactoring - set to suggestion temporarily
|
||||
dotnet_diagnostic.CA1835.severity = suggestion
|
||||
dotnet_diagnostic.CA1510.severity = suggestion
|
||||
dotnet_diagnostic.CA1512.severity = suggestion
|
||||
dotnet_diagnostic.CA1844.severity = suggestion
|
||||
dotnet_diagnostic.CA1825.severity = suggestion
|
||||
dotnet_diagnostic.CA1712.severity = suggestion
|
||||
dotnet_diagnostic.CA2022.severity = suggestion
|
||||
dotnet_diagnostic.CA1850.severity = suggestion
|
||||
dotnet_diagnostic.CA2263.severity = suggestion
|
||||
dotnet_diagnostic.CA2012.severity = suggestion
|
||||
dotnet_diagnostic.CA1001.severity = suggestion
|
||||
|
||||
dotnet_diagnostic.CS0169.severity = error
|
||||
dotnet_diagnostic.CS0219.severity = error
|
||||
dotnet_diagnostic.CS0649.severity = suggestion
|
||||
@@ -318,9 +331,9 @@ dotnet_diagnostic.MVC1000.severity = suggestion
|
||||
|
||||
dotnet_diagnostic.RZ10012.severity = error
|
||||
|
||||
dotnet_diagnostic.IDE0004.severity = error # redundant cast
|
||||
dotnet_diagnostic.IDE0004.severity = suggestion # redundant cast
|
||||
dotnet_diagnostic.IDE0005.severity = suggestion
|
||||
dotnet_diagnostic.IDE0007.severity = error # Use var
|
||||
dotnet_diagnostic.IDE0007.severity = suggestion # Use var
|
||||
dotnet_diagnostic.IDE0011.severity = error # Use braces on if statements
|
||||
dotnet_diagnostic.IDE0010.severity = silent # populate switch
|
||||
dotnet_diagnostic.IDE0017.severity = suggestion # initialization can be simplified
|
||||
@@ -334,7 +347,7 @@ dotnet_diagnostic.IDE0028.severity = silent # expression body for accessors
|
||||
dotnet_diagnostic.IDE0032.severity = suggestion # Use auto property
|
||||
dotnet_diagnostic.IDE0033.severity = error # prefer tuple name
|
||||
dotnet_diagnostic.IDE0037.severity = suggestion # simplify anonymous type
|
||||
dotnet_diagnostic.IDE0040.severity = error # modifiers required
|
||||
dotnet_diagnostic.IDE0040.severity = suggestion # modifiers required
|
||||
dotnet_diagnostic.IDE0041.severity = error # simplify null
|
||||
dotnet_diagnostic.IDE0042.severity = error # deconstruct variable
|
||||
dotnet_diagnostic.IDE0044.severity = suggestion # make field only when possible
|
||||
@@ -348,6 +361,12 @@ dotnet_diagnostic.IDE0060.severity = suggestion # unused parameters
|
||||
dotnet_diagnostic.IDE0061.severity = suggestion # local expression body
|
||||
dotnet_diagnostic.IDE0062.severity = suggestion # local to static
|
||||
dotnet_diagnostic.IDE0063.severity = error # simplify using
|
||||
|
||||
[tests/**/*.cs]
|
||||
dotnet_diagnostic.CA1861.severity = suggestion
|
||||
dotnet_diagnostic.IDE0042.severity = suggestion
|
||||
dotnet_diagnostic.IDE0051.severity = suggestion
|
||||
dotnet_diagnostic.IDE0063.severity = suggestion
|
||||
dotnet_diagnostic.IDE0066.severity = suggestion # switch expression
|
||||
dotnet_diagnostic.IDE0072.severity = suggestion # Populate switch - forces population of all cases even when default specified
|
||||
dotnet_diagnostic.IDE0078.severity = suggestion # use pattern matching
|
||||
@@ -359,7 +378,7 @@ dotnet_diagnostic.IDE0200.severity = suggestion # lambda not needed
|
||||
dotnet_diagnostic.IDE1006.severity = suggestion # Naming rule violation: These words cannot contain lower case characters
|
||||
dotnet_diagnostic.IDE0260.severity = suggestion # Use pattern matching
|
||||
dotnet_diagnostic.IDE0270.severity = suggestion # Null check simplifcation
|
||||
dotnet_diagnostic.IDE0290.severity = error # Primary Constructor
|
||||
dotnet_diagnostic.IDE0290.severity = suggestion # Primary Constructor
|
||||
dotnet_diagnostic.IDE0300.severity = suggestion # Collection
|
||||
dotnet_diagnostic.IDE0305.severity = suggestion # Collection ToList
|
||||
|
||||
|
||||
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 using C# build target (Windows only, not on PRs)
|
||||
# Push to NuGet.org only for version tag pushes (Windows only)
|
||||
- name: Push to NuGet
|
||||
if: success() && matrix.os == 'windows-latest' && github.event_name != 'pull_request'
|
||||
if: success() && matrix.os == 'windows-latest' && startsWith(github.ref, 'refs/tags/')
|
||||
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,8 +103,11 @@ 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
|
||||
@@ -132,6 +135,9 @@ 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
|
||||
@@ -199,7 +205,8 @@ 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. **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
|
||||
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
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
|
||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<RunAnalyzersDuringLiveAnalysis>False</RunAnalyzersDuringLiveAnalysis>
|
||||
<RunAnalyzersDuringBuild>False</RunAnalyzersDuringBuild>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
|
||||
|
||||
@@ -16,6 +16,10 @@ 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`)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -114,14 +115,19 @@ Target(
|
||||
{
|
||||
var (version, isPrerelease) = await GetVersion();
|
||||
Console.WriteLine($"VERSION={version}");
|
||||
Console.WriteLine($"PRERELEASE={isPrerelease.ToString().ToLower()}");
|
||||
Console.WriteLine(
|
||||
$"PRERELEASE={isPrerelease.ToString().ToLower(CultureInfo.InvariantCulture)}"
|
||||
);
|
||||
|
||||
// Write to environment file for GitHub Actions
|
||||
var githubOutput = Environment.GetEnvironmentVariable("GITHUB_OUTPUT");
|
||||
if (!string.IsNullOrEmpty(githubOutput))
|
||||
{
|
||||
File.AppendAllText(githubOutput, $"version={version}\n");
|
||||
File.AppendAllText(githubOutput, $"prerelease={isPrerelease.ToString().ToLower()}\n");
|
||||
File.AppendAllText(
|
||||
githubOutput,
|
||||
$"prerelease={isPrerelease.ToString().ToLower(CultureInfo.InvariantCulture)}\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -363,9 +369,13 @@ Target(
|
||||
: "⚪";
|
||||
|
||||
if (timeChange > 25 || memChange > 25)
|
||||
{
|
||||
hasRegressions = true;
|
||||
}
|
||||
if (timeChange < -25 || memChange < -25)
|
||||
{
|
||||
hasImprovements = true;
|
||||
}
|
||||
|
||||
output.Add(
|
||||
$"| {method} | {baseline.Mean} | {current.Mean} | {timeIcon} {timeChange:+0.0;-0.0;0}% | {baseline.Memory} | {current.Memory} | {memIcon} {memChange:+0.0;-0.0;0}% |"
|
||||
@@ -545,7 +555,10 @@ static async Task<string> GetGitOutput(string command, string args)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Git command failed: git {command} {args}\n{ex.Message}", ex);
|
||||
throw new InvalidOperationException(
|
||||
$"Git command failed: git {command} {args}\n{ex.Message}",
|
||||
ex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,7 +588,7 @@ static Dictionary<string, BenchmarkMetric> ParseBenchmarkResults(string markdown
|
||||
var line = lines[i].Trim();
|
||||
|
||||
// Look for table rows with benchmark data
|
||||
if (line.StartsWith("|") && line.Contains("'") && i > 0)
|
||||
if (line.StartsWith('|') && line.Contains("'", StringComparison.Ordinal) && i > 0)
|
||||
{
|
||||
var parts = line.Split('|', StringSplitOptions.TrimEntries);
|
||||
if (parts.Length >= 5)
|
||||
@@ -588,10 +601,10 @@ static Dictionary<string, BenchmarkMetric> ParseBenchmarkResults(string markdown
|
||||
for (int j = parts.Length - 2; j >= 2; j--)
|
||||
{
|
||||
if (
|
||||
parts[j].Contains("KB")
|
||||
|| parts[j].Contains("MB")
|
||||
|| parts[j].Contains("GB")
|
||||
|| parts[j].Contains("B")
|
||||
parts[j].Contains("KB", StringComparison.Ordinal)
|
||||
|| parts[j].Contains("MB", StringComparison.Ordinal)
|
||||
|| parts[j].Contains("GB", StringComparison.Ordinal)
|
||||
|| parts[j].Contains('B')
|
||||
)
|
||||
{
|
||||
memoryStr = parts[j];
|
||||
@@ -624,17 +637,21 @@ static Dictionary<string, BenchmarkMetric> ParseBenchmarkResults(string markdown
|
||||
static double ParseTimeValue(string timeStr)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(timeStr) || timeStr == "N/A" || timeStr == "NA")
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Remove thousands separators and parse
|
||||
timeStr = timeStr.Replace(",", "").Trim();
|
||||
|
||||
var match = Regex.Match(timeStr, @"([\d.]+)\s*(\w+)");
|
||||
if (!match.Success)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var value = double.Parse(match.Groups[1].Value);
|
||||
var unit = match.Groups[2].Value.ToLower();
|
||||
var unit = match.Groups[2].Value.ToLower(CultureInfo.InvariantCulture);
|
||||
|
||||
// Convert to microseconds for comparison
|
||||
return unit switch
|
||||
@@ -650,16 +667,20 @@ static double ParseTimeValue(string timeStr)
|
||||
static double ParseMemoryValue(string memStr)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(memStr) || memStr == "N/A" || memStr == "NA")
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
memStr = memStr.Replace(",", "").Trim();
|
||||
|
||||
var match = Regex.Match(memStr, @"([\d.]+)\s*(\w+)");
|
||||
if (!match.Success)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var value = double.Parse(match.Groups[1].Value);
|
||||
var unit = match.Groups[2].Value.ToUpper();
|
||||
var unit = match.Groups[2].Value.ToUpper(CultureInfo.InvariantCulture);
|
||||
|
||||
// Convert to KB for comparison
|
||||
return unit switch
|
||||
@@ -675,7 +696,9 @@ static double ParseMemoryValue(string memStr)
|
||||
static double CalculateChange(double baseline, double current)
|
||||
{
|
||||
if (baseline == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return ((current - baseline) / baseline) * 100;
|
||||
}
|
||||
|
||||
|
||||
24
docs/API.md
24
docs/API.md
@@ -95,7 +95,7 @@ using (var archive = ZipArchive.OpenArchive("file.zip"))
|
||||
}
|
||||
|
||||
// Async extraction (requires IAsyncArchive)
|
||||
using (var asyncArchive = await ZipArchive.OpenAsyncArchive("file.zip"))
|
||||
await 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"))
|
||||
using (var reader = await ReaderFactory.OpenAsyncReader(stream))
|
||||
await using (var reader = await ReaderFactory.OpenAsyncReader(stream))
|
||||
{
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
@@ -318,6 +318,24 @@ 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
|
||||
@@ -409,7 +427,7 @@ cts.CancelAfter(TimeSpan.FromMinutes(5));
|
||||
|
||||
try
|
||||
{
|
||||
using (var archive = await ZipArchive.OpenAsyncArchive("archive.zip"))
|
||||
await using (var archive = await ZipArchive.OpenAsyncArchive("archive.zip"))
|
||||
{
|
||||
await archive.WriteToDirectoryAsync(
|
||||
@"C:\output",
|
||||
|
||||
@@ -206,6 +206,29 @@ 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,7 +22,9 @@ public static partial class ArchiveFactory
|
||||
readerOptions ??= ReaderOptions.ForExternalStream;
|
||||
var factory = await FindFactoryAsync<IArchiveFactory>(stream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return factory.OpenAsyncArchive(stream, readerOptions);
|
||||
return await factory
|
||||
.OpenAsyncArchive(stream, readerOptions, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
@@ -45,7 +47,9 @@ public static partial class ArchiveFactory
|
||||
|
||||
var factory = await FindFactoryAsync<IArchiveFactory>(fileInfo, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return factory.OpenAsyncArchive(fileInfo, options);
|
||||
return await factory
|
||||
.OpenAsyncArchive(fileInfo, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
|
||||
@@ -2,12 +2,9 @@ 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;
|
||||
|
||||
@@ -40,10 +40,7 @@ public partial class GZipArchive
|
||||
{
|
||||
throw new InvalidFormatException("Only one entry is allowed in a GZip Archive");
|
||||
}
|
||||
await using var writer = new GZipWriter(
|
||||
stream,
|
||||
options as GZipWriterOptions ?? new GZipWriterOptions(options)
|
||||
);
|
||||
await using var writer = new GZipWriter(stream, options);
|
||||
await foreach (
|
||||
var entry in oldEntries.WithCancellation(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
@@ -77,7 +74,7 @@ public partial class GZipArchive
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return new((IAsyncReader)GZipReader.OpenReader(stream));
|
||||
return new((IAsyncReader)GZipReader.OpenReader(stream, ReaderOptions));
|
||||
}
|
||||
|
||||
protected override async IAsyncEnumerable<GZipArchiveEntry> LoadEntriesAsync(
|
||||
@@ -88,7 +85,7 @@ public partial class GZipArchive
|
||||
yield return new GZipArchiveEntry(
|
||||
this,
|
||||
await GZipFilePart
|
||||
.CreateAsync(stream, ReaderOptions.ArchiveEncoding)
|
||||
.CreateAsync(stream, ReaderOptions.ArchiveEncoding, ReaderOptions.Providers)
|
||||
.ConfigureAwait(false),
|
||||
ReaderOptions
|
||||
);
|
||||
|
||||
@@ -20,14 +20,15 @@ public partial class GZipArchive
|
||||
>
|
||||
#endif
|
||||
{
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
public static ValueTask<IWritableAsyncArchive<GZipWriterOptions>> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return (IWritableAsyncArchive<GZipWriterOptions>)
|
||||
OpenArchive(new FileInfo(path), readerOptions ?? new ReaderOptions());
|
||||
return OpenAsyncArchive(new FileInfo(path), readerOptions, cancellationToken);
|
||||
}
|
||||
|
||||
public static IWritableArchive<GZipWriterOptions> OpenArchive(
|
||||
@@ -103,30 +104,50 @@ public partial class GZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
public static ValueTask<IWritableAsyncArchive<GZipWriterOptions>> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(stream, readerOptions);
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(stream, readerOptions));
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
public static ValueTask<IWritableAsyncArchive<GZipWriterOptions>> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(fileInfo, readerOptions);
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(fileInfo, readerOptions));
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
public static ValueTask<IWritableAsyncArchive<GZipWriterOptions>> OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(streams, readerOptions);
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(streams, readerOptions));
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
|
||||
public static ValueTask<IWritableAsyncArchive<GZipWriterOptions>> OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(fileInfos, readerOptions);
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(fileInfos, readerOptions));
|
||||
}
|
||||
|
||||
public static IWritableArchive<GZipWriterOptions> CreateArchive() => new GZipArchive();
|
||||
|
||||
public static IWritableAsyncArchive<GZipWriterOptions> CreateAsyncArchive() =>
|
||||
new GZipArchive();
|
||||
public static ValueTask<IWritableAsyncArchive<GZipWriterOptions>> CreateAsyncArchive() =>
|
||||
new(new GZipArchive());
|
||||
|
||||
public static bool IsGZipFile(string filePath) => IsGZipFile(new FileInfo(filePath));
|
||||
|
||||
|
||||
@@ -67,10 +67,7 @@ public partial class GZipArchive
|
||||
{
|
||||
throw new InvalidFormatException("Only one entry is allowed in a GZip Archive");
|
||||
}
|
||||
using var writer = new GZipWriter(
|
||||
stream,
|
||||
options as GZipWriterOptions ?? new GZipWriterOptions(options)
|
||||
);
|
||||
using var writer = new GZipWriter(stream, options);
|
||||
foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory))
|
||||
{
|
||||
using var entryStream = entry.OpenEntryStream();
|
||||
@@ -87,7 +84,7 @@ public partial class GZipArchive
|
||||
var stream = volumes.Single().Stream;
|
||||
yield return new GZipArchiveEntry(
|
||||
this,
|
||||
GZipFilePart.Create(stream, ReaderOptions.ArchiveEncoding),
|
||||
GZipFilePart.Create(stream, ReaderOptions.ArchiveEncoding, ReaderOptions.Providers),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
@@ -96,6 +93,6 @@ public partial class GZipArchive
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return GZipReader.OpenReader(stream);
|
||||
return GZipReader.OpenReader(stream, ReaderOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,20 @@ public class GZipArchiveEntry : GZipEntry, IArchiveEntry
|
||||
return Parts.Single().GetCompressedStream().NotNull();
|
||||
}
|
||||
|
||||
public ValueTask<Stream> OpenEntryStreamAsync(CancellationToken cancellationToken = default)
|
||||
public async ValueTask<Stream> OpenEntryStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// GZip synchronous implementation is fast enough, just wrap it
|
||||
return new(OpenEntryStream());
|
||||
// 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();
|
||||
}
|
||||
|
||||
#region IArchiveEntry Members
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Factories;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
@@ -32,7 +33,13 @@ public interface IArchiveFactory : IFactory
|
||||
/// </summary>
|
||||
/// <param name="stream">An open, readable and seekable stream.</param>
|
||||
/// <param name="readerOptions">reading options.</param>
|
||||
IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null);
|
||||
/// <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
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
@@ -47,5 +54,10 @@ public interface IArchiveFactory : IFactory
|
||||
/// <param name="fileInfo">the file to open.</param>
|
||||
/// <param name="readerOptions">reading options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null);
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> containing the opened async archive.</returns>
|
||||
ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#if NET8_0_OR_GREATER
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
@@ -18,19 +19,22 @@ public interface IArchiveOpenable<TSync, TASync>
|
||||
|
||||
public static abstract TSync OpenArchive(Stream stream, ReaderOptions? readerOptions = null);
|
||||
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
public static abstract ValueTask<TASync> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
public static abstract ValueTask<TASync> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
public static abstract ValueTask<TASync> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
@@ -20,14 +21,16 @@ public interface IMultiArchiveOpenable<TSync, TASync>
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
public static abstract ValueTask<TASync> OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
public static abstract TASync OpenAsyncArchive(
|
||||
public static abstract ValueTask<TASync> OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
@@ -8,6 +9,6 @@ public interface IWritableArchiveOpenable<TOptions>
|
||||
where TOptions : IWriterOptions
|
||||
{
|
||||
public static abstract IWritableArchive<TOptions> CreateArchive();
|
||||
public static abstract IWritableAsyncArchive<TOptions> CreateAsyncArchive();
|
||||
public static abstract ValueTask<IWritableAsyncArchive<TOptions>> CreateAsyncArchive();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -20,13 +20,15 @@ public partial class RarArchive
|
||||
IMultiArchiveOpenable<IRarArchive, IRarAsyncArchive>
|
||||
#endif
|
||||
{
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
public static ValueTask<IRarAsyncArchive> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return (IRarAsyncArchive)OpenArchive(new FileInfo(path), readerOptions);
|
||||
return new((IRarAsyncArchive)OpenArchive(new FileInfo(path), readerOptions));
|
||||
}
|
||||
|
||||
public static IRarArchive OpenArchive(string filePath, ReaderOptions? options = null)
|
||||
@@ -98,36 +100,44 @@ public partial class RarArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
public static ValueTask<IRarAsyncArchive> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
return (IRarAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IRarAsyncArchive)OpenArchive(stream, readerOptions));
|
||||
}
|
||||
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
public static ValueTask<IRarAsyncArchive> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
return (IRarAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IRarAsyncArchive)OpenArchive(fileInfo, readerOptions));
|
||||
}
|
||||
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
public static ValueTask<IRarAsyncArchive> OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
return (IRarAsyncArchive)OpenArchive(streams, readerOptions);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IRarAsyncArchive)OpenArchive(streams, readerOptions));
|
||||
}
|
||||
|
||||
public static IRarAsyncArchive OpenAsyncArchive(
|
||||
public static ValueTask<IRarAsyncArchive> OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
return (IRarAsyncArchive)OpenArchive(fileInfos, readerOptions);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IRarAsyncArchive)OpenArchive(fileInfos, readerOptions));
|
||||
}
|
||||
|
||||
public static bool IsRarFile(string filePath) => IsRarFile(new FileInfo(filePath));
|
||||
|
||||
@@ -16,10 +16,17 @@ public partial class SevenZipArchive
|
||||
IMultiArchiveOpenable<IArchive, IAsyncArchive>
|
||||
#endif
|
||||
{
|
||||
public static IAsyncArchive OpenAsyncArchive(string path, ReaderOptions? readerOptions = null)
|
||||
public static ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty("path");
|
||||
return (IAsyncArchive)OpenArchive(new FileInfo(path), readerOptions ?? new ReaderOptions());
|
||||
return new(
|
||||
(IAsyncArchive)OpenArchive(new FileInfo(path), readerOptions ?? new ReaderOptions())
|
||||
);
|
||||
}
|
||||
|
||||
public static IArchive OpenArchive(string filePath, ReaderOptions? readerOptions = null)
|
||||
@@ -86,33 +93,44 @@ public partial class SevenZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null)
|
||||
public static ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
return (IAsyncArchive)OpenArchive(stream, readerOptions);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(stream, readerOptions));
|
||||
}
|
||||
|
||||
public static IAsyncArchive OpenAsyncArchive(
|
||||
public static ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
return (IAsyncArchive)OpenArchive(fileInfo, readerOptions);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(fileInfo, readerOptions));
|
||||
}
|
||||
|
||||
public static IAsyncArchive OpenAsyncArchive(
|
||||
public static ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
return (IAsyncArchive)OpenArchive(streams, readerOptions);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(streams, readerOptions));
|
||||
}
|
||||
|
||||
public static IAsyncArchive OpenAsyncArchive(
|
||||
public static ValueTask<IAsyncArchive> OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
return (IAsyncArchive)OpenArchive(fileInfos, readerOptions);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IAsyncArchive)OpenArchive(fileInfos, readerOptions));
|
||||
}
|
||||
|
||||
public static bool IsSevenZipFile(string filePath) => IsSevenZipFile(new FileInfo(filePath));
|
||||
|
||||
@@ -6,7 +6,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.SevenZip;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
using SharpCompress.Compressors.LZMA.Utilities;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
|
||||
@@ -25,10 +25,7 @@ public partial class TarArchive
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
using var writer = new TarWriter(
|
||||
stream,
|
||||
options as TarWriterOptions ?? new TarWriterOptions(options)
|
||||
);
|
||||
using var writer = new TarWriter(stream, options);
|
||||
await foreach (
|
||||
var entry in oldEntries.WithCancellation(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
@@ -89,26 +86,32 @@ public partial class TarArchive
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return new((IAsyncReader)TarReader.OpenReader(stream));
|
||||
return new((IAsyncReader)new TarReader(stream, ReaderOptions, _compressionType));
|
||||
}
|
||||
|
||||
protected override async IAsyncEnumerable<TarArchiveEntry> LoadEntriesAsync(
|
||||
IAsyncEnumerable<TarVolume> volumes
|
||||
)
|
||||
{
|
||||
var stream = (await volumes.SingleAsync().ConfigureAwait(false)).Stream;
|
||||
var sourceStream = (await volumes.SingleAsync().ConfigureAwait(false)).Stream;
|
||||
var stream = await GetStreamAsync(sourceStream).ConfigureAwait(false);
|
||||
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.Seekable,
|
||||
streamingMode,
|
||||
stream,
|
||||
ReaderOptions.ArchiveEncoding
|
||||
)
|
||||
@@ -126,7 +129,10 @@ public partial class TarArchive
|
||||
{
|
||||
var entry = new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(previousHeader, stream),
|
||||
new TarFilePart(
|
||||
previousHeader,
|
||||
_compressionType == CompressionType.None ? stream : null
|
||||
),
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
@@ -151,7 +157,10 @@ public partial class TarArchive
|
||||
}
|
||||
yield return new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(header, stream),
|
||||
new TarFilePart(
|
||||
header,
|
||||
_compressionType == CompressionType.None ? stream : null
|
||||
),
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ 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;
|
||||
@@ -37,12 +38,9 @@ public partial class TarArchive
|
||||
)
|
||||
{
|
||||
fileInfo.NotNull(nameof(fileInfo));
|
||||
return new TarArchive(
|
||||
new SourceStream(
|
||||
fileInfo,
|
||||
i => ArchiveVolumeFactory.GetFilePart(i, fileInfo),
|
||||
readerOptions ?? new ReaderOptions() { LeaveStreamOpen = false }
|
||||
)
|
||||
return OpenArchive(
|
||||
[fileInfo],
|
||||
readerOptions ?? new ReaderOptions() { LeaveStreamOpen = false }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -53,13 +51,17 @@ public partial class TarArchive
|
||||
{
|
||||
fileInfos.NotNull(nameof(fileInfos));
|
||||
var files = fileInfos.ToArray();
|
||||
return new TarArchive(
|
||||
new SourceStream(
|
||||
files[0],
|
||||
i => i < files.Length ? files[i] : null,
|
||||
readerOptions ?? new ReaderOptions() { LeaveStreamOpen = false }
|
||||
)
|
||||
var sourceStream = 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(
|
||||
@@ -69,13 +71,17 @@ public partial class TarArchive
|
||||
{
|
||||
streams.NotNull(nameof(streams));
|
||||
var strms = streams.ToArray();
|
||||
return new TarArchive(
|
||||
new SourceStream(
|
||||
strms[0],
|
||||
i => i < strms.Length ? strms[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
var sourceStream = 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(
|
||||
@@ -90,35 +96,113 @@ public partial class TarArchive
|
||||
throw new ArgumentException("Stream must be seekable", nameof(stream));
|
||||
}
|
||||
|
||||
return new TarArchive(
|
||||
new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())
|
||||
);
|
||||
return OpenArchive([stream], readerOptions);
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
public static async ValueTask<IWritableAsyncArchive<TarWriterOptions>> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(stream, readerOptions);
|
||||
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);
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
public static ValueTask<IWritableAsyncArchive<TarWriterOptions>> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(new FileInfo(path), readerOptions);
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
path.NotNullOrEmpty(nameof(path));
|
||||
return OpenAsyncArchive(new FileInfo(path), readerOptions, cancellationToken);
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
public static async ValueTask<IWritableAsyncArchive<TarWriterOptions>> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(fileInfo, readerOptions);
|
||||
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);
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
public static async ValueTask<IWritableAsyncArchive<TarWriterOptions>> OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(streams, readerOptions);
|
||||
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);
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
|
||||
public static async ValueTask<IWritableAsyncArchive<TarWriterOptions>> OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(fileInfos, readerOptions);
|
||||
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);
|
||||
}
|
||||
|
||||
public static bool IsTarFile(string filePath) => IsTarFile(new FileInfo(filePath));
|
||||
|
||||
@@ -183,5 +267,6 @@ public partial class TarArchive
|
||||
|
||||
public static IWritableArchive<TarWriterOptions> CreateArchive() => new TarArchive();
|
||||
|
||||
public static IWritableAsyncArchive<TarWriterOptions> CreateAsyncArchive() => new TarArchive();
|
||||
public static ValueTask<IWritableAsyncArchive<TarWriterOptions>> CreateAsyncArchive() =>
|
||||
new(new TarArchive());
|
||||
}
|
||||
|
||||
@@ -5,35 +5,113 @@ 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();
|
||||
}
|
||||
|
||||
private TarArchive(SourceStream sourceStream)
|
||||
: base(ArchiveType.Tar, sourceStream) { }
|
||||
internal TarArchive(SourceStream sourceStream, CompressionType compressionType)
|
||||
: base(ArchiveType.Tar, sourceStream)
|
||||
{
|
||||
_compressionType = compressionType;
|
||||
}
|
||||
|
||||
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 = volumes.Single().Stream;
|
||||
var stream = GetStream(volumes.Single().Stream);
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
stream.Position = 0;
|
||||
@@ -41,7 +119,9 @@ public partial class TarArchive
|
||||
TarHeader? previousHeader = null;
|
||||
foreach (
|
||||
var header in TarHeaderFactory.ReadHeader(
|
||||
StreamingMode.Seekable,
|
||||
_compressionType == CompressionType.None
|
||||
? StreamingMode.Seekable
|
||||
: StreamingMode.Streaming,
|
||||
stream,
|
||||
ReaderOptions.ArchiveEncoding
|
||||
)
|
||||
@@ -59,7 +139,10 @@ public partial class TarArchive
|
||||
{
|
||||
var entry = new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(previousHeader, stream),
|
||||
new TarFilePart(
|
||||
previousHeader,
|
||||
_compressionType == CompressionType.None ? stream : null
|
||||
),
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
@@ -82,7 +165,10 @@ public partial class TarArchive
|
||||
}
|
||||
yield return new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(header, stream),
|
||||
new TarFilePart(
|
||||
header,
|
||||
_compressionType == CompressionType.None ? stream : null
|
||||
),
|
||||
CompressionType.None,
|
||||
ReaderOptions
|
||||
);
|
||||
@@ -124,10 +210,7 @@ public partial class TarArchive
|
||||
IEnumerable<TarArchiveEntry> newEntries
|
||||
)
|
||||
{
|
||||
using var writer = new TarWriter(
|
||||
stream,
|
||||
options as TarWriterOptions ?? new TarWriterOptions(options)
|
||||
);
|
||||
using var writer = new TarWriter(stream, options);
|
||||
foreach (var entry in oldEntries.Concat(newEntries))
|
||||
{
|
||||
if (entry.IsDirectory)
|
||||
@@ -154,6 +237,6 @@ public partial class TarArchive
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return TarReader.OpenReader(stream);
|
||||
return new TarReader(stream, ReaderOptions, _compressionType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,12 @@ public partial class ZipArchive
|
||||
|
||||
yield return new ZipArchiveEntry(
|
||||
this,
|
||||
new SeekableZipFilePart(headerFactory.NotNull(), deh, s),
|
||||
new SeekableZipFilePart(
|
||||
headerFactory.NotNull(),
|
||||
deh,
|
||||
s,
|
||||
ReaderOptions.Providers
|
||||
),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
@@ -79,10 +84,7 @@ public partial class ZipArchive
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
using var writer = new ZipWriter(
|
||||
stream,
|
||||
options as ZipWriterOptions ?? new ZipWriterOptions(options)
|
||||
);
|
||||
using var writer = new ZipWriter(stream, options);
|
||||
await foreach (
|
||||
var entry in oldEntries.WithCancellation(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
|
||||
@@ -95,30 +95,55 @@ public partial class ZipArchive
|
||||
);
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
public static ValueTask<IWritableAsyncArchive<ZipWriterOptions>> OpenAsyncArchive(
|
||||
string path,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(path, readerOptions);
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(path, readerOptions));
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
public static ValueTask<IWritableAsyncArchive<ZipWriterOptions>> OpenAsyncArchive(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(stream, readerOptions);
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(stream, readerOptions));
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
public static ValueTask<IWritableAsyncArchive<ZipWriterOptions>> OpenAsyncArchive(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(fileInfo, readerOptions);
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(fileInfo, readerOptions));
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
public static ValueTask<IWritableAsyncArchive<ZipWriterOptions>> OpenAsyncArchive(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(streams, readerOptions);
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(streams, readerOptions));
|
||||
}
|
||||
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
|
||||
public static ValueTask<IWritableAsyncArchive<ZipWriterOptions>> OpenAsyncArchive(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(fileInfos, readerOptions);
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new((IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(fileInfos, readerOptions));
|
||||
}
|
||||
|
||||
public static bool IsZipFile(string filePath, string? password = null) =>
|
||||
IsZipFile(new FileInfo(filePath), password);
|
||||
@@ -223,7 +248,8 @@ public partial class ZipArchive
|
||||
|
||||
public static IWritableArchive<ZipWriterOptions> CreateArchive() => new ZipArchive();
|
||||
|
||||
public static IWritableAsyncArchive<ZipWriterOptions> CreateAsyncArchive() => new ZipArchive();
|
||||
public static ValueTask<IWritableAsyncArchive<ZipWriterOptions>> CreateAsyncArchive() =>
|
||||
new(new ZipArchive());
|
||||
|
||||
public static async ValueTask<bool> IsZipMultiAsync(
|
||||
Stream stream,
|
||||
|
||||
@@ -96,7 +96,12 @@ public partial class ZipArchive
|
||||
|
||||
yield return new ZipArchiveEntry(
|
||||
this,
|
||||
new SeekableZipFilePart(headerFactory.NotNull(), deh, s),
|
||||
new SeekableZipFilePart(
|
||||
headerFactory.NotNull(),
|
||||
deh,
|
||||
s,
|
||||
ReaderOptions.Providers
|
||||
),
|
||||
ReaderOptions
|
||||
);
|
||||
}
|
||||
@@ -122,10 +127,7 @@ public partial class ZipArchive
|
||||
IEnumerable<ZipArchiveEntry> newEntries
|
||||
)
|
||||
{
|
||||
using var writer = new ZipWriter(
|
||||
stream,
|
||||
options as ZipWriterOptions ?? new ZipWriterOptions(options)
|
||||
);
|
||||
using var writer = new ZipWriter(stream, options);
|
||||
foreach (var entry in oldEntries.Concat(newEntries))
|
||||
{
|
||||
if (entry.IsDirectory)
|
||||
@@ -171,6 +173,6 @@ public partial class ZipArchive
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return new((IAsyncReader)ZipReader.OpenReader(stream));
|
||||
return new((IAsyncReader)ZipReader.OpenReader(stream, ReaderOptions, Entries));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Compressors.ArcLzw;
|
||||
using SharpCompress.Compressors.Lzw;
|
||||
using SharpCompress.Compressors.RLE90;
|
||||
using SharpCompress.Compressors.Squeezed;
|
||||
|
||||
@@ -8,6 +8,7 @@ using SharpCompress.Common.GZip;
|
||||
using SharpCompress.Common.Tar;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.Compressors.ArcLzw;
|
||||
using SharpCompress.Compressors.Lzw;
|
||||
using SharpCompress.Compressors.RLE90;
|
||||
using SharpCompress.Compressors.Squeezed;
|
||||
|
||||
@@ -18,7 +18,6 @@ public enum ArjHeaderType
|
||||
|
||||
public abstract partial class ArjHeader
|
||||
{
|
||||
private const int FIRST_HDR_SIZE = 34;
|
||||
private const ushort ARJ_MAGIC = 0xEA60;
|
||||
|
||||
public ArjHeader(ArjHeaderType type)
|
||||
|
||||
@@ -10,9 +10,6 @@ namespace SharpCompress.Common.Arj.Headers;
|
||||
|
||||
public partial class ArjMainHeader : ArjHeader
|
||||
{
|
||||
private const int FIRST_HDR_SIZE = 34;
|
||||
private const ushort ARJ_MAGIC = 0xEA60;
|
||||
|
||||
public ArchiveEncoding ArchiveEncoding { get; }
|
||||
|
||||
public int ArchiverVersionNumber { get; private set; }
|
||||
|
||||
@@ -12,7 +12,9 @@ public partial class GZipEntry
|
||||
)
|
||||
{
|
||||
yield return new GZipEntry(
|
||||
await GZipFilePart.CreateAsync(stream, options.ArchiveEncoding).ConfigureAwait(false),
|
||||
await GZipFilePart
|
||||
.CreateAsync(stream, options.ArchiveEncoding, options.Providers)
|
||||
.ConfigureAwait(false),
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,10 @@ public partial class GZipEntry : Entry
|
||||
|
||||
internal static IEnumerable<GZipEntry> GetEntries(Stream stream, ReaderOptions options)
|
||||
{
|
||||
yield return new GZipEntry(GZipFilePart.Create(stream, options.ArchiveEncoding), options);
|
||||
yield return new GZipEntry(
|
||||
GZipFilePart.Create(stream, options.ArchiveEncoding, options.Providers),
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
// Async methods moved to GZipEntry.Async.cs
|
||||
|
||||
@@ -5,7 +5,9 @@ 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;
|
||||
|
||||
@@ -14,10 +16,11 @@ 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);
|
||||
var part = new GZipFilePart(stream, archiveEncoding, compressionProviders);
|
||||
|
||||
await part.ReadAndValidateGzipHeaderAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (stream.CanSeek)
|
||||
@@ -131,4 +134,14 @@ 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,6 +5,7 @@ using System.IO;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.GZip;
|
||||
|
||||
@@ -12,10 +13,15 @@ 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)
|
||||
internal static GZipFilePart Create(
|
||||
Stream stream,
|
||||
IArchiveEncoding archiveEncoding,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
{
|
||||
var part = new GZipFilePart(stream, archiveEncoding);
|
||||
var part = new GZipFilePart(stream, archiveEncoding, compressionProviders);
|
||||
|
||||
part.ReadAndValidateGzipHeader();
|
||||
if (stream.CanSeek)
|
||||
@@ -35,8 +41,16 @@ internal sealed partial class GZipFilePart : FilePart
|
||||
return part;
|
||||
}
|
||||
|
||||
private GZipFilePart(Stream stream, IArchiveEncoding archiveEncoding)
|
||||
: base(archiveEncoding) => _stream = stream;
|
||||
private GZipFilePart(
|
||||
Stream stream,
|
||||
IArchiveEncoding archiveEncoding,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
: base(archiveEncoding)
|
||||
{
|
||||
_stream = stream;
|
||||
_compressionProviders = compressionProviders;
|
||||
}
|
||||
|
||||
internal long EntryStartPosition { get; private set; }
|
||||
|
||||
@@ -46,13 +60,11 @@ internal sealed partial class GZipFilePart : FilePart
|
||||
|
||||
internal override string? FilePartName => _name;
|
||||
|
||||
internal override Stream GetCompressedStream() =>
|
||||
new DeflateStream(
|
||||
_stream,
|
||||
CompressionMode.Decompress,
|
||||
CompressionLevel.Default,
|
||||
leaveOpen: true
|
||||
);
|
||||
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 GetRawStream() => _stream;
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@ public partial class LzwEntry
|
||||
)
|
||||
{
|
||||
yield return new LzwEntry(
|
||||
await LzwFilePart.CreateAsync(stream, options.ArchiveEncoding, cancellationToken),
|
||||
await LzwFilePart
|
||||
.CreateAsync(stream, options.ArchiveEncoding, options.Providers, cancellationToken)
|
||||
.ConfigureAwait(false),
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,10 @@ public partial class LzwEntry : Entry
|
||||
|
||||
internal static IEnumerable<LzwEntry> GetEntries(Stream stream, ReaderOptions options)
|
||||
{
|
||||
yield return new LzwEntry(LzwFilePart.Create(stream, options.ArchiveEncoding), options);
|
||||
yield return new LzwEntry(
|
||||
LzwFilePart.Create(stream, options.ArchiveEncoding, options.Providers),
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
// Async methods moved to LzwEntry.Async.cs
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
@@ -9,15 +11,25 @@ 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);
|
||||
var part = new LzwFilePart(stream, archiveEncoding, compressionProviders);
|
||||
|
||||
// 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,5 +1,6 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Compressors.Lzw;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.Lzw;
|
||||
|
||||
@@ -7,10 +8,15 @@ 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)
|
||||
internal static LzwFilePart Create(
|
||||
Stream stream,
|
||||
IArchiveEncoding archiveEncoding,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
{
|
||||
var part = new LzwFilePart(stream, archiveEncoding);
|
||||
var part = new LzwFilePart(stream, archiveEncoding, compressionProviders);
|
||||
|
||||
// For non-seekable streams, we can't track position, so use 0 since the stream will be
|
||||
// read sequentially from its current position.
|
||||
@@ -18,11 +24,16 @@ internal sealed partial class LzwFilePart : FilePart
|
||||
return part;
|
||||
}
|
||||
|
||||
private LzwFilePart(Stream stream, IArchiveEncoding archiveEncoding)
|
||||
private LzwFilePart(
|
||||
Stream stream,
|
||||
IArchiveEncoding archiveEncoding,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
: base(archiveEncoding)
|
||||
{
|
||||
_stream = stream;
|
||||
_name = DeriveFileName(stream);
|
||||
_compressionProviders = compressionProviders;
|
||||
}
|
||||
|
||||
internal long EntryStartPosition { get; private set; }
|
||||
@@ -30,7 +41,7 @@ internal sealed partial class LzwFilePart : FilePart
|
||||
internal override string? FilePartName => _name;
|
||||
|
||||
internal override Stream GetCompressedStream() =>
|
||||
new LzwStream(_stream) { IsStreamOwner = false };
|
||||
_compressionProviders.CreateDecompressStream(CompressionType.Lzw, _stream);
|
||||
|
||||
internal override Stream GetRawStream() => _stream;
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.Options;
|
||||
|
||||
public interface IReaderOptions
|
||||
@@ -6,10 +9,40 @@ 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,9 +1,28 @@
|
||||
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; }
|
||||
}
|
||||
|
||||
@@ -91,8 +91,8 @@ internal class AsyncMarkingBinaryReader
|
||||
}
|
||||
|
||||
public async ValueTask<ulong> ReadRarVIntAsync(
|
||||
CancellationToken cancellationToken = default,
|
||||
int maxBytes = 10
|
||||
int maxBytes = 10,
|
||||
CancellationToken cancellationToken = default
|
||||
) => await DoReadRarVIntAsync((maxBytes - 1) * 7, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
private async ValueTask<ulong> DoReadRarVIntAsync(
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
#nullable disable
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
|
||||
namespace SharpCompress.Common.Rar;
|
||||
|
||||
[SuppressMessage(
|
||||
"Security",
|
||||
"CA5350:Do Not Use Weak Cryptographic Algorithms",
|
||||
Justification = "RAR3 key derivation is SHA-1 based by format definition."
|
||||
)]
|
||||
internal class CryptKey3 : ICryptKey
|
||||
{
|
||||
const int AES_128 = 128;
|
||||
|
||||
private string _password;
|
||||
private readonly string _password;
|
||||
|
||||
public CryptKey3(string password) => _password = password ?? "";
|
||||
public CryptKey3(string? password) => _password = password ?? string.Empty;
|
||||
|
||||
public ICryptoTransform Transformer(byte[] salt)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.Rar;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.IO;
|
||||
|
||||
|
||||
@@ -44,9 +44,7 @@ internal sealed partial class ArchiveHeader
|
||||
PosAv = await reader.ReadInt32Async(cancellationToken).ConfigureAwait(false);
|
||||
if (HasFlag(ArchiveFlagsV4.ENCRYPT_VER))
|
||||
{
|
||||
EncryptionVersion = await reader
|
||||
.ReadByteAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
_ = await reader.ReadByteAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ internal sealed partial class ArchiveHeader : RarHeader
|
||||
PosAv = reader.ReadInt32();
|
||||
if (HasFlag(ArchiveFlagsV4.ENCRYPT_VER))
|
||||
{
|
||||
EncryptionVersion = reader.ReadByte();
|
||||
_ = reader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,8 +44,6 @@ internal sealed partial class ArchiveHeader : RarHeader
|
||||
|
||||
internal int? PosAv { get; private set; }
|
||||
|
||||
private byte? EncryptionVersion { get; set; }
|
||||
|
||||
public bool? IsEncrypted => IsRar5 ? null : HasFlag(ArchiveFlagsV4.PASSWORD);
|
||||
|
||||
public bool OldNumberingFormat => !IsRar5 && !HasFlag(ArchiveFlagsV4.NEW_NUMBERING);
|
||||
|
||||
@@ -79,7 +79,7 @@ internal partial class FileHeader
|
||||
CompressionMethod = (byte)((compressionInfo >> 7) & 0x7);
|
||||
WindowSize = IsDirectory ? 0 : ((size_t)0x20000) << ((compressionInfo >> 10) & 0xf);
|
||||
|
||||
HostOs = await reader
|
||||
_ = await reader
|
||||
.ReadRarVIntByteAsync(cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -222,7 +222,7 @@ internal partial class FileHeader
|
||||
.ReadUInt32Async(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
HostOs = await reader.ReadByteAsync(cancellationToken).ConfigureAwait(false);
|
||||
_ = await reader.ReadByteAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
FileCrc = await reader.ReadBytesAsync(4, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ internal partial class FileHeader : RarHeader
|
||||
// Bits 11 - 14 (0x3c00) define the minimum size of dictionary size required to extract data. Value 0 means 128 KB, 1 - 256 KB, ..., 14 - 2048 MB, 15 - 4096 MB.
|
||||
WindowSize = IsDirectory ? 0 : ((size_t)0x20000) << ((compressionInfo >> 10) & 0xf);
|
||||
|
||||
HostOs = reader.ReadRarVIntByte();
|
||||
_ = reader.ReadRarVIntByte();
|
||||
|
||||
var nameSize = reader.ReadRarVIntUInt16();
|
||||
|
||||
@@ -197,7 +197,7 @@ internal partial class FileHeader : RarHeader
|
||||
|
||||
var lowUncompressedSize = reader.ReadUInt32();
|
||||
|
||||
HostOs = reader.ReadByte();
|
||||
_ = reader.ReadByte();
|
||||
|
||||
FileCrc = reader.ReadBytes(4);
|
||||
|
||||
@@ -415,7 +415,6 @@ internal partial class FileHeader : RarHeader
|
||||
|
||||
internal byte[]? R4Salt { get; private set; }
|
||||
internal Rar5CryptoInfo? Rar5CryptoInfo { get; private set; }
|
||||
private byte HostOs { get; set; }
|
||||
internal uint FileAttributes { get; private set; }
|
||||
internal long CompressedSize { get; private set; }
|
||||
internal long UncompressedSize { get; private set; }
|
||||
|
||||
@@ -42,4 +42,20 @@ internal sealed class NewSubHeaderType : IEquatable<NewSubHeaderType>
|
||||
}
|
||||
|
||||
public bool Equals(NewSubHeaderType? other) => other is not null && Equals(other._bytes);
|
||||
|
||||
public override bool Equals(object? obj) => obj is NewSubHeaderType other && Equals(other);
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = 17;
|
||||
foreach (byte value in _bytes)
|
||||
{
|
||||
hash = (hash * 31) + value;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ public abstract class RarVolume : Volume
|
||||
}
|
||||
|
||||
// we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream
|
||||
GetVolumeFileParts().First();
|
||||
_ = GetVolumeFileParts().First();
|
||||
Stream.Position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#nullable disable
|
||||
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
using SharpCompress.Compressors.LZMA.Utilities;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip;
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
using SharpCompress.Compressors.LZMA.Utilities;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip;
|
||||
|
||||
@@ -18,7 +16,7 @@ internal partial class ArchiveDatabase
|
||||
internal List<long> _packSizes = new();
|
||||
internal List<uint?> _packCrCs = new();
|
||||
internal List<CFolder> _folders = new();
|
||||
internal List<int> _numUnpackStreamsVector;
|
||||
internal List<int> _numUnpackStreamsVector = null!;
|
||||
internal List<CFileItem> _files = new();
|
||||
|
||||
internal List<long> _packStreamStartPositions = new();
|
||||
@@ -35,7 +33,7 @@ internal partial class ArchiveDatabase
|
||||
_packSizes.Clear();
|
||||
_packCrCs.Clear();
|
||||
_folders.Clear();
|
||||
_numUnpackStreamsVector = null;
|
||||
_numUnpackStreamsVector = null!;
|
||||
_files.Clear();
|
||||
|
||||
_packStreamStartPositions.Clear();
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Compressors.Deflate64;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
using SharpCompress.Compressors.LZMA.Utilities;
|
||||
using SharpCompress.IO;
|
||||
using BlockType = SharpCompress.Compressors.LZMA.Utilities.BlockType;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip;
|
||||
|
||||
@@ -167,10 +167,6 @@ internal sealed partial class ArchiveReader
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadAndDecodePackedStreamsAsync --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
ReadStreamsInfo(
|
||||
@@ -236,12 +232,7 @@ internal sealed partial class ArchiveReader
|
||||
}
|
||||
return dataVector;
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
finally { }
|
||||
}
|
||||
|
||||
private async ValueTask ReadHeaderAsync(
|
||||
@@ -250,10 +241,6 @@ internal sealed partial class ArchiveReader
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadHeaderAsync --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
var type = ReadId();
|
||||
@@ -264,7 +251,7 @@ internal sealed partial class ArchiveReader
|
||||
type = ReadId();
|
||||
}
|
||||
|
||||
List<byte[]> dataVector = null;
|
||||
List<byte[]>? dataVector = null;
|
||||
if (type == BlockType.AdditionalStreamsInfo)
|
||||
{
|
||||
dataVector = await ReadAndDecodePackedStreamsAsync(
|
||||
@@ -322,9 +309,6 @@ internal sealed partial class ArchiveReader
|
||||
}
|
||||
|
||||
var numFiles = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumFiles: " + numFiles);
|
||||
#endif
|
||||
db._files = new List<CFileItem>(numFiles);
|
||||
for (var i = 0; i < numFiles; i++)
|
||||
{
|
||||
@@ -332,8 +316,8 @@ internal sealed partial class ArchiveReader
|
||||
}
|
||||
|
||||
var emptyStreamVector = new BitVector(numFiles);
|
||||
BitVector emptyFileVector = null;
|
||||
BitVector antiFileVector = null;
|
||||
BitVector emptyFileVector = null!;
|
||||
BitVector antiFileVector = null!;
|
||||
var numEmptyStreams = 0;
|
||||
|
||||
for (; ; )
|
||||
@@ -351,26 +335,14 @@ internal sealed partial class ArchiveReader
|
||||
case BlockType.Name:
|
||||
using (var streamSwitch = new CStreamSwitch())
|
||||
{
|
||||
streamSwitch.Set(this, dataVector);
|
||||
#if DEBUG
|
||||
Log.Write("FileNames:");
|
||||
#endif
|
||||
streamSwitch.Set(this, dataVector ?? []);
|
||||
for (var i = 0; i < db._files.Count; i++)
|
||||
{
|
||||
db._files[i].Name = _currentReader.ReadString();
|
||||
#if DEBUG
|
||||
Log.Write(" " + db._files[i].Name);
|
||||
#endif
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case BlockType.WinAttributes:
|
||||
#if DEBUG
|
||||
Log.Write("WinAttributes:");
|
||||
#endif
|
||||
ReadAttributeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
@@ -384,150 +356,70 @@ internal sealed partial class ArchiveReader
|
||||
}
|
||||
|
||||
db._files[i].Attrib = attr;
|
||||
#if DEBUG
|
||||
Log.Write(
|
||||
" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a")
|
||||
);
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.EmptyStream:
|
||||
emptyStreamVector = ReadBitVector(numFiles);
|
||||
#if DEBUG
|
||||
|
||||
Log.Write("EmptyStream: ");
|
||||
#endif
|
||||
for (var i = 0; i < emptyStreamVector.Length; i++)
|
||||
{
|
||||
if (emptyStreamVector[i])
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write("x");
|
||||
#endif
|
||||
numEmptyStreams++;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write(".");
|
||||
#endif
|
||||
}
|
||||
else { }
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
|
||||
emptyFileVector = new BitVector(numEmptyStreams);
|
||||
antiFileVector = new BitVector(numEmptyStreams);
|
||||
break;
|
||||
case BlockType.EmptyFile:
|
||||
emptyFileVector = ReadBitVector(numEmptyStreams);
|
||||
#if DEBUG
|
||||
Log.Write("EmptyFile: ");
|
||||
for (var i = 0; i < numEmptyStreams; i++)
|
||||
{
|
||||
Log.Write(emptyFileVector[i] ? "x" : ".");
|
||||
}
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.Anti:
|
||||
antiFileVector = ReadBitVector(numEmptyStreams);
|
||||
#if DEBUG
|
||||
Log.Write("Anti: ");
|
||||
for (var i = 0; i < numEmptyStreams; i++)
|
||||
{
|
||||
Log.Write(antiFileVector[i] ? "x" : ".");
|
||||
}
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.StartPos:
|
||||
#if DEBUG
|
||||
Log.Write("StartPos:");
|
||||
#endif
|
||||
ReadNumberVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, long? startPos)
|
||||
{
|
||||
db._files[i].StartPos = startPos;
|
||||
#if DEBUG
|
||||
Log.Write(
|
||||
" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a")
|
||||
);
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.CTime:
|
||||
#if DEBUG
|
||||
Log.Write("CTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, DateTime? time)
|
||||
{
|
||||
db._files[i].CTime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.ATime:
|
||||
#if DEBUG
|
||||
Log.Write("ATime:");
|
||||
#endif
|
||||
ReadDateTimeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, DateTime? time)
|
||||
{
|
||||
db._files[i].ATime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.MTime:
|
||||
#if DEBUG
|
||||
Log.Write("MTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, DateTime? time)
|
||||
{
|
||||
db._files[i].MTime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.Dummy:
|
||||
#if DEBUG
|
||||
Log.Write("Dummy: " + size);
|
||||
#endif
|
||||
for (long j = 0; j < size; j++)
|
||||
{
|
||||
if (ReadByte() != 0)
|
||||
@@ -572,11 +464,6 @@ internal sealed partial class ArchiveReader
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
finally { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@@ -7,20 +5,22 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Compressors.Deflate64;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
using SharpCompress.Compressors.LZMA.Utilities;
|
||||
using SharpCompress.IO;
|
||||
using BlockType = SharpCompress.Compressors.LZMA.Utilities.BlockType;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip;
|
||||
|
||||
internal partial class ArchiveReader
|
||||
{
|
||||
internal Stream _stream;
|
||||
internal Stream _stream = null!;
|
||||
internal Stack<DataReader> _readerStack = new();
|
||||
internal DataReader _currentReader;
|
||||
internal DataReader _currentReader = null!;
|
||||
internal long _streamOrigin;
|
||||
internal long _streamEnding;
|
||||
internal byte[] _header;
|
||||
internal byte[] _header = null!;
|
||||
|
||||
private readonly Dictionary<int, Stream> _cachedStreams = new();
|
||||
|
||||
@@ -54,9 +54,6 @@ internal partial class ArchiveReader
|
||||
{
|
||||
return null;
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine("ReadId: {0}", (BlockType)id);
|
||||
#endif
|
||||
return (BlockType)id;
|
||||
}
|
||||
|
||||
@@ -130,12 +127,12 @@ internal partial class ArchiveReader
|
||||
return ReadBitVector(length);
|
||||
}
|
||||
|
||||
private void ReadNumberVector(List<byte[]> dataVector, int numFiles, Action<int, long?> action)
|
||||
private void ReadNumberVector(List<byte[]>? dataVector, int numFiles, Action<int, long?> action)
|
||||
{
|
||||
var defined = ReadOptionalBitVector(numFiles);
|
||||
|
||||
using var streamSwitch = new CStreamSwitch();
|
||||
streamSwitch.Set(this, dataVector);
|
||||
streamSwitch.Set(this, dataVector ?? []);
|
||||
|
||||
for (var i = 0; i < numFiles; i++)
|
||||
{
|
||||
@@ -164,7 +161,7 @@ internal partial class ArchiveReader
|
||||
}
|
||||
|
||||
private void ReadDateTimeVector(
|
||||
List<byte[]> dataVector,
|
||||
List<byte[]>? dataVector,
|
||||
int numFiles,
|
||||
Action<int, DateTime?> action
|
||||
) =>
|
||||
@@ -175,14 +172,14 @@ internal partial class ArchiveReader
|
||||
);
|
||||
|
||||
private void ReadAttributeVector(
|
||||
List<byte[]> dataVector,
|
||||
List<byte[]>? dataVector,
|
||||
int numFiles,
|
||||
Action<int, uint?> action
|
||||
)
|
||||
{
|
||||
var boolVector = ReadOptionalBitVector(numFiles);
|
||||
using var streamSwitch = new CStreamSwitch();
|
||||
streamSwitch.Set(this, dataVector);
|
||||
streamSwitch.Set(this, dataVector ?? []);
|
||||
for (var i = 0; i < numFiles; i++)
|
||||
{
|
||||
if (boolVector[i])
|
||||
@@ -202,25 +199,14 @@ internal partial class ArchiveReader
|
||||
|
||||
private void GetNextFolderItem(CFolder folder)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- GetNextFolderItem --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
var numCoders = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumCoders: " + numCoders);
|
||||
#endif
|
||||
folder._coders = new List<CCoderInfo>(numCoders);
|
||||
var numInStreams = 0;
|
||||
var numOutStreams = 0;
|
||||
for (var i = 0; i < numCoders; i++)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- Coder --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
var coder = new CCoderInfo();
|
||||
@@ -230,18 +216,6 @@ internal partial class ArchiveReader
|
||||
var idSize = (mainByte & 0xF);
|
||||
var longId = new byte[idSize];
|
||||
ReadBytes(longId, 0, idSize);
|
||||
#if DEBUG
|
||||
Log.WriteLine(
|
||||
"MethodId: "
|
||||
+ string.Join(
|
||||
"",
|
||||
Enumerable
|
||||
.Range(0, idSize)
|
||||
.Select(x => longId[x].ToString("x2"))
|
||||
.ToArray()
|
||||
)
|
||||
);
|
||||
#endif
|
||||
if (idSize > 8)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
@@ -257,21 +231,9 @@ internal partial class ArchiveReader
|
||||
{
|
||||
coder._numInStreams = ReadNum();
|
||||
coder._numOutStreams = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine(
|
||||
"Complex Stream (In: "
|
||||
+ coder._numInStreams
|
||||
+ " - Out: "
|
||||
+ coder._numOutStreams
|
||||
+ ")"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("Simple Stream (In: 1 - Out: 1)");
|
||||
#endif
|
||||
coder._numInStreams = 1;
|
||||
coder._numOutStreams = 1;
|
||||
}
|
||||
@@ -281,15 +243,6 @@ internal partial class ArchiveReader
|
||||
var propsSize = ReadNum();
|
||||
coder._props = new byte[propsSize];
|
||||
ReadBytes(coder._props, 0, propsSize);
|
||||
#if DEBUG
|
||||
Log.WriteLine(
|
||||
"Settings: "
|
||||
+ string.Join(
|
||||
"",
|
||||
coder._props.Select(bt => bt.ToString("x2")).ToArray()
|
||||
)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((mainByte & 0x80) != 0)
|
||||
@@ -300,33 +253,18 @@ internal partial class ArchiveReader
|
||||
numInStreams += coder._numInStreams;
|
||||
numOutStreams += coder._numOutStreams;
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
finally { }
|
||||
}
|
||||
|
||||
var numBindPairs = numOutStreams - 1;
|
||||
folder._bindPairs = new List<CBindPair>(numBindPairs);
|
||||
#if DEBUG
|
||||
Log.WriteLine("BindPairs: " + numBindPairs);
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
for (var i = 0; i < numBindPairs; i++)
|
||||
{
|
||||
var bp = new CBindPair();
|
||||
bp._inIndex = ReadNum();
|
||||
bp._outIndex = ReadNum();
|
||||
folder._bindPairs.Add(bp);
|
||||
#if DEBUG
|
||||
Log.WriteLine("#" + i + " - In: " + bp._inIndex + " - Out: " + bp._outIndex);
|
||||
#endif
|
||||
}
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
|
||||
if (numInStreams < numBindPairs)
|
||||
{
|
||||
@@ -342,9 +280,6 @@ internal partial class ArchiveReader
|
||||
{
|
||||
if (folder.FindBindPairForInStream(i) < 0)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("Single PackStream: #" + i);
|
||||
#endif
|
||||
folder._packStreams.Add(i);
|
||||
break;
|
||||
}
|
||||
@@ -357,37 +292,18 @@ internal partial class ArchiveReader
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("Multiple PackStreams ...");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
for (var i = 0; i < numPackStreams; i++)
|
||||
{
|
||||
var num = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("#" + i + " - " + num);
|
||||
#endif
|
||||
folder._packStreams.Add(num);
|
||||
}
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
finally { }
|
||||
}
|
||||
|
||||
private List<uint?> ReadHashDigests(int count)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write("ReadHashDigests:");
|
||||
#endif
|
||||
|
||||
var defined = ReadOptionalBitVector(count);
|
||||
var digests = new List<uint?>(count);
|
||||
for (var i = 0; i < count; i++)
|
||||
@@ -395,23 +311,13 @@ internal partial class ArchiveReader
|
||||
if (defined[i])
|
||||
{
|
||||
var crc = ReadUInt32();
|
||||
#if DEBUG
|
||||
Log.Write(" " + crc.ToString("x8"));
|
||||
#endif
|
||||
digests.Add(crc);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write(" ########");
|
||||
#endif
|
||||
digests.Add(null);
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
return digests;
|
||||
}
|
||||
|
||||
@@ -421,40 +327,21 @@ internal partial class ArchiveReader
|
||||
out List<uint?> packCrCs
|
||||
)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadPackInfo --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
packCrCs = null;
|
||||
packCrCs = null!;
|
||||
|
||||
dataOffset = checked((long)ReadNumber());
|
||||
#if DEBUG
|
||||
Log.WriteLine("DataOffset: " + dataOffset);
|
||||
#endif
|
||||
|
||||
var numPackStreams = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumPackStreams: " + numPackStreams);
|
||||
#endif
|
||||
|
||||
WaitAttribute(BlockType.Size);
|
||||
packSizes = new List<long>(numPackStreams);
|
||||
#if DEBUG
|
||||
Log.Write("Sizes:");
|
||||
#endif
|
||||
for (var i = 0; i < numPackStreams; i++)
|
||||
{
|
||||
var size = checked((long)ReadNumber());
|
||||
#if DEBUG
|
||||
Log.Write(" " + size);
|
||||
#endif
|
||||
packSizes.Add(size);
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
|
||||
BlockType? type;
|
||||
for (; ; )
|
||||
@@ -481,31 +368,19 @@ internal partial class ArchiveReader
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
finally { }
|
||||
}
|
||||
|
||||
private void ReadUnpackInfo(List<byte[]> dataVector, out List<CFolder> folders)
|
||||
private void ReadUnpackInfo(List<byte[]>? dataVector, out List<CFolder> folders)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadUnpackInfo --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
WaitAttribute(BlockType.Folder);
|
||||
var numFolders = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumFolders: {0}", numFolders);
|
||||
#endif
|
||||
|
||||
using (var streamSwitch = new CStreamSwitch())
|
||||
{
|
||||
streamSwitch.Set(this, dataVector);
|
||||
streamSwitch.Set(this, dataVector ?? []);
|
||||
|
||||
//folders.Clear();
|
||||
//folders.Reserve(numFolders);
|
||||
@@ -521,27 +396,15 @@ internal partial class ArchiveReader
|
||||
}
|
||||
|
||||
WaitAttribute(BlockType.CodersUnpackSize);
|
||||
#if DEBUG
|
||||
Log.WriteLine("UnpackSizes:");
|
||||
#endif
|
||||
for (var i = 0; i < numFolders; i++)
|
||||
{
|
||||
var folder = folders[i];
|
||||
#if DEBUG
|
||||
Log.Write(" #" + i + ":");
|
||||
#endif
|
||||
var numOutStreams = folder.GetNumOutStreams();
|
||||
for (var j = 0; j < numOutStreams; j++)
|
||||
{
|
||||
var size = checked((long)ReadNumber());
|
||||
#if DEBUG
|
||||
Log.Write(" " + size);
|
||||
#endif
|
||||
folder._unpackSizes.Add(size);
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
}
|
||||
|
||||
for (; ; )
|
||||
@@ -565,12 +428,7 @@ internal partial class ArchiveReader
|
||||
SkipData();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
finally { }
|
||||
}
|
||||
|
||||
private void ReadSubStreamsInfo(
|
||||
@@ -580,13 +438,9 @@ internal partial class ArchiveReader
|
||||
out List<uint?> digests
|
||||
)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadSubStreamsInfo --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
numUnpackStreamsInFolders = null;
|
||||
numUnpackStreamsInFolders = null!;
|
||||
|
||||
BlockType? type;
|
||||
for (; ; )
|
||||
@@ -595,20 +449,11 @@ internal partial class ArchiveReader
|
||||
if (type == BlockType.NumUnpackStream)
|
||||
{
|
||||
numUnpackStreamsInFolders = new List<int>(folders.Count);
|
||||
#if DEBUG
|
||||
Log.Write("NumUnpackStreams:");
|
||||
#endif
|
||||
for (var i = 0; i < folders.Count; i++)
|
||||
{
|
||||
var num = ReadNum();
|
||||
#if DEBUG
|
||||
Log.Write(" " + num);
|
||||
#endif
|
||||
numUnpackStreamsInFolders.Add(num);
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
if (type is BlockType.Crc or BlockType.Size)
|
||||
@@ -641,26 +486,17 @@ internal partial class ArchiveReader
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#if DEBUG
|
||||
Log.Write("#{0} StreamSizes:", i);
|
||||
#endif
|
||||
long sum = 0;
|
||||
for (var j = 1; j < numSubstreams; j++)
|
||||
{
|
||||
if (type == BlockType.Size)
|
||||
{
|
||||
var size = checked((long)ReadNumber());
|
||||
#if DEBUG
|
||||
Log.Write(" " + size);
|
||||
#endif
|
||||
unpackSizes.Add(size);
|
||||
sum += size;
|
||||
}
|
||||
}
|
||||
unpackSizes.Add(folders[i].GetUnpackSize() - sum);
|
||||
#if DEBUG
|
||||
Log.WriteLine(" - rest: " + unpackSizes.Last());
|
||||
#endif
|
||||
}
|
||||
if (type == BlockType.Size)
|
||||
{
|
||||
@@ -679,7 +515,7 @@ internal partial class ArchiveReader
|
||||
numDigestsTotal += numSubstreams;
|
||||
}
|
||||
|
||||
digests = null;
|
||||
digests = null!;
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
@@ -696,7 +532,7 @@ internal partial class ArchiveReader
|
||||
var folder = folders[i];
|
||||
if (numSubstreams == 1 && folder.UnpackCrcDefined)
|
||||
{
|
||||
digests.Add(folder._unpackCrc.Value);
|
||||
digests.Add(folder._unpackCrc!.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -732,16 +568,11 @@ internal partial class ArchiveReader
|
||||
type = ReadId();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
finally { }
|
||||
}
|
||||
|
||||
private void ReadStreamsInfo(
|
||||
List<byte[]> dataVector,
|
||||
List<byte[]>? dataVector,
|
||||
out long dataOffset,
|
||||
out List<long> packSizes,
|
||||
out List<uint?> packCrCs,
|
||||
@@ -751,19 +582,15 @@ internal partial class ArchiveReader
|
||||
out List<uint?> digests
|
||||
)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadStreamsInfo --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
dataOffset = long.MinValue;
|
||||
packSizes = null;
|
||||
packCrCs = null;
|
||||
folders = null;
|
||||
numUnpackStreamsInFolders = null;
|
||||
unpackSizes = null;
|
||||
digests = null;
|
||||
packSizes = null!;
|
||||
packCrCs = null!;
|
||||
folders = null!;
|
||||
numUnpackStreamsInFolders = null!;
|
||||
unpackSizes = null!;
|
||||
digests = null!;
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
@@ -779,7 +606,7 @@ internal partial class ArchiveReader
|
||||
break;
|
||||
case BlockType.SubStreamsInfo:
|
||||
ReadSubStreamsInfo(
|
||||
folders,
|
||||
folders!,
|
||||
out numUnpackStreamsInFolders,
|
||||
out unpackSizes,
|
||||
out digests
|
||||
@@ -790,20 +617,11 @@ internal partial class ArchiveReader
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
finally { }
|
||||
}
|
||||
|
||||
private List<byte[]> ReadAndDecodePackedStreams(long baseOffset, IPasswordProvider pass)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadAndDecodePackedStreams --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
ReadStreamsInfo(
|
||||
@@ -864,20 +682,11 @@ internal partial class ArchiveReader
|
||||
}
|
||||
return dataVector;
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
finally { }
|
||||
}
|
||||
|
||||
private void ReadHeader(ArchiveDatabase db, IPasswordProvider getTextPassword)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadHeader --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
var type = ReadId();
|
||||
@@ -888,7 +697,7 @@ internal partial class ArchiveReader
|
||||
type = ReadId();
|
||||
}
|
||||
|
||||
List<byte[]> dataVector = null;
|
||||
List<byte[]>? dataVector = null;
|
||||
if (type == BlockType.AdditionalStreamsInfo)
|
||||
{
|
||||
dataVector = ReadAndDecodePackedStreams(
|
||||
@@ -944,9 +753,6 @@ internal partial class ArchiveReader
|
||||
}
|
||||
|
||||
var numFiles = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumFiles: " + numFiles);
|
||||
#endif
|
||||
db._files = new List<CFileItem>(numFiles);
|
||||
for (var i = 0; i < numFiles; i++)
|
||||
{
|
||||
@@ -954,8 +760,8 @@ internal partial class ArchiveReader
|
||||
}
|
||||
|
||||
var emptyStreamVector = new BitVector(numFiles);
|
||||
BitVector emptyFileVector = null;
|
||||
BitVector antiFileVector = null;
|
||||
BitVector emptyFileVector = null!;
|
||||
BitVector antiFileVector = null!;
|
||||
var numEmptyStreams = 0;
|
||||
|
||||
for (; ; )
|
||||
@@ -973,26 +779,14 @@ internal partial class ArchiveReader
|
||||
case BlockType.Name:
|
||||
using (var streamSwitch = new CStreamSwitch())
|
||||
{
|
||||
streamSwitch.Set(this, dataVector);
|
||||
#if DEBUG
|
||||
Log.Write("FileNames:");
|
||||
#endif
|
||||
streamSwitch.Set(this, dataVector ?? []);
|
||||
for (var i = 0; i < db._files.Count; i++)
|
||||
{
|
||||
db._files[i].Name = _currentReader.ReadString();
|
||||
#if DEBUG
|
||||
Log.Write(" " + db._files[i].Name);
|
||||
#endif
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case BlockType.WinAttributes:
|
||||
#if DEBUG
|
||||
Log.Write("WinAttributes:");
|
||||
#endif
|
||||
ReadAttributeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
@@ -1026,150 +820,70 @@ internal partial class ArchiveReader
|
||||
}
|
||||
|
||||
db._files[i].Attrib = attr;
|
||||
#if DEBUG
|
||||
Log.Write(
|
||||
" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a")
|
||||
);
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.EmptyStream:
|
||||
emptyStreamVector = ReadBitVector(numFiles);
|
||||
#if DEBUG
|
||||
|
||||
Log.Write("EmptyStream: ");
|
||||
#endif
|
||||
for (var i = 0; i < emptyStreamVector.Length; i++)
|
||||
{
|
||||
if (emptyStreamVector[i])
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write("x");
|
||||
#endif
|
||||
numEmptyStreams++;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write(".");
|
||||
#endif
|
||||
}
|
||||
else { }
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
|
||||
emptyFileVector = new BitVector(numEmptyStreams);
|
||||
antiFileVector = new BitVector(numEmptyStreams);
|
||||
break;
|
||||
case BlockType.EmptyFile:
|
||||
emptyFileVector = ReadBitVector(numEmptyStreams);
|
||||
#if DEBUG
|
||||
Log.Write("EmptyFile: ");
|
||||
for (var i = 0; i < numEmptyStreams; i++)
|
||||
{
|
||||
Log.Write(emptyFileVector[i] ? "x" : ".");
|
||||
}
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.Anti:
|
||||
antiFileVector = ReadBitVector(numEmptyStreams);
|
||||
#if DEBUG
|
||||
Log.Write("Anti: ");
|
||||
for (var i = 0; i < numEmptyStreams; i++)
|
||||
{
|
||||
Log.Write(antiFileVector[i] ? "x" : ".");
|
||||
}
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.StartPos:
|
||||
#if DEBUG
|
||||
Log.Write("StartPos:");
|
||||
#endif
|
||||
ReadNumberVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, long? startPos)
|
||||
{
|
||||
db._files[i].StartPos = startPos;
|
||||
#if DEBUG
|
||||
Log.Write(
|
||||
" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a")
|
||||
);
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.CTime:
|
||||
#if DEBUG
|
||||
Log.Write("CTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, DateTime? time)
|
||||
{
|
||||
db._files[i].CTime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.ATime:
|
||||
#if DEBUG
|
||||
Log.Write("ATime:");
|
||||
#endif
|
||||
ReadDateTimeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, DateTime? time)
|
||||
{
|
||||
db._files[i].ATime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.MTime:
|
||||
#if DEBUG
|
||||
Log.Write("MTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, DateTime? time)
|
||||
{
|
||||
db._files[i].MTime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.Dummy:
|
||||
#if DEBUG
|
||||
Log.Write("Dummy: " + size);
|
||||
#endif
|
||||
for (long j = 0; j < size; j++)
|
||||
{
|
||||
if (ReadByte() != 0)
|
||||
@@ -1215,12 +929,7 @@ internal partial class ArchiveReader
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
finally { }
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1445,7 +1154,7 @@ internal partial class ArchiveReader
|
||||
|
||||
public override void SetLength(long value) => throw new NotSupportedException();
|
||||
|
||||
private Stream _stream;
|
||||
private Stream? _stream;
|
||||
private long _rem;
|
||||
private int _currentIndex;
|
||||
|
||||
@@ -1457,7 +1166,7 @@ internal partial class ArchiveReader
|
||||
)
|
||||
{
|
||||
OpenFile();
|
||||
_stream.Dispose();
|
||||
_stream.NotNull().Dispose();
|
||||
_stream = null;
|
||||
_currentIndex++;
|
||||
}
|
||||
@@ -1466,12 +1175,10 @@ internal partial class ArchiveReader
|
||||
private void OpenFile()
|
||||
{
|
||||
var index = _startIndex + _currentIndex;
|
||||
#if DEBUG
|
||||
Log.WriteLine(_db._files[index].Name);
|
||||
#endif
|
||||
if (_db._files[index].Crc.HasValue)
|
||||
var crc = _db._files[index].Crc;
|
||||
if (crc.HasValue)
|
||||
{
|
||||
_stream = new CrcCheckStream(_db._files[index].Crc.Value);
|
||||
_stream = new CrcCheckStream(crc.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1568,11 +1275,10 @@ internal partial class ArchiveReader
|
||||
return new ReadOnlySubStream(s, db._files[fileIndex].Size);
|
||||
}
|
||||
|
||||
public void Extract(ArchiveDatabase db, int[] indices)
|
||||
public void Extract(ArchiveDatabase db, int[]? indices)
|
||||
{
|
||||
var allFilesMode = (indices is null);
|
||||
|
||||
var numItems = allFilesMode ? db._files.Count : indices.Length;
|
||||
var allFilesMode = indices is null;
|
||||
var numItems = allFilesMode ? db._files.Count : indices!.Length;
|
||||
|
||||
if (numItems == 0)
|
||||
{
|
||||
@@ -1582,7 +1288,7 @@ internal partial class ArchiveReader
|
||||
var extractFolderInfoVector = new List<CExtractFolderInfo>();
|
||||
for (var i = 0; i < numItems; i++)
|
||||
{
|
||||
var fileIndex = allFilesMode ? i : indices[i];
|
||||
var fileIndex = allFilesMode ? i : indices![i];
|
||||
|
||||
var folderIndex = db._fileIndexToFolderIndexMap[fileIndex];
|
||||
if (folderIndex == -1)
|
||||
@@ -1608,7 +1314,7 @@ internal partial class ArchiveReader
|
||||
}
|
||||
}
|
||||
|
||||
byte[] buffer = null;
|
||||
byte[] buffer = null!;
|
||||
foreach (var efi in extractFolderInfoVector)
|
||||
{
|
||||
int startIndex;
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#nullable disable
|
||||
|
||||
namespace SharpCompress.Common.SevenZip;
|
||||
|
||||
internal class CCoderInfo
|
||||
{
|
||||
internal CMethodId _methodId;
|
||||
internal byte[] _props;
|
||||
internal byte[]? _props;
|
||||
internal int _numInStreams;
|
||||
internal int _numOutStreams;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip;
|
||||
@@ -10,7 +8,7 @@ internal class CFileItem
|
||||
public uint? Attrib { get; internal set; }
|
||||
public uint? ExtendedAttrib { get; internal set; }
|
||||
public uint? Crc { get; internal set; }
|
||||
public string Name { get; internal set; }
|
||||
public string Name { get; internal set; } = string.Empty;
|
||||
|
||||
public bool HasStream { get; internal set; }
|
||||
public bool IsDir { get; internal set; }
|
||||
|
||||
@@ -15,9 +15,6 @@ internal struct CStreamSwitch : IDisposable
|
||||
if (_active)
|
||||
{
|
||||
_active = false;
|
||||
#if DEBUG
|
||||
Log.WriteLine("[end of switch]");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_needRemove)
|
||||
@@ -50,19 +47,11 @@ internal struct CStreamSwitch : IDisposable
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
Log.WriteLine("[switch to stream {0}]", dataIndex);
|
||||
#endif
|
||||
_archive = archive;
|
||||
_archive.AddByteStream(dataVector[dataIndex], 0, dataVector[dataIndex].Length);
|
||||
_needRemove = true;
|
||||
_active = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("[inline data]");
|
||||
#endif
|
||||
}
|
||||
else { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,9 +76,6 @@ internal class DataReader
|
||||
}
|
||||
|
||||
Offset += (int)size;
|
||||
#if DEBUG
|
||||
Log.WriteLine("SkipData {0}", size);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SkipData() => SkipData(checked((long)ReadNumber()));
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -26,7 +27,7 @@ internal sealed partial class TarHeader
|
||||
await WriteUstarAsync(output, cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("This should be impossible...");
|
||||
throw new InvalidOperationException("This should be impossible...");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,9 +59,15 @@ internal sealed partial class TarHeader
|
||||
int splitIndex = -1;
|
||||
for (int i = 0; i < dirSeps.Count; i++)
|
||||
{
|
||||
#if NET8_0_OR_GREATER
|
||||
int count = ArchiveEncoding
|
||||
.GetEncoding()
|
||||
.GetByteCount(fullName.AsSpan(0, dirSeps[i]));
|
||||
#else
|
||||
int count = ArchiveEncoding
|
||||
.GetEncoding()
|
||||
.GetByteCount(fullName.Substring(0, dirSeps[i]));
|
||||
#endif
|
||||
if (count < 155)
|
||||
{
|
||||
splitIndex = dirSeps[i];
|
||||
@@ -73,7 +80,7 @@ internal sealed partial class TarHeader
|
||||
|
||||
if (splitIndex == -1)
|
||||
{
|
||||
throw new Exception(
|
||||
throw new InvalidDataException(
|
||||
$"Tar header USTAR format can not fit file name \"{fullName}\" of length {nameByteCount}! Directory separator not found! Try using GNU Tar format instead!"
|
||||
);
|
||||
}
|
||||
@@ -83,14 +90,14 @@ internal sealed partial class TarHeader
|
||||
|
||||
if (this.ArchiveEncoding.GetEncoding().GetByteCount(namePrefix) >= 155)
|
||||
{
|
||||
throw new Exception(
|
||||
throw new InvalidDataException(
|
||||
$"Tar header USTAR format can not fit file name \"{fullName}\" of length {nameByteCount}! Try using GNU Tar format instead!"
|
||||
);
|
||||
}
|
||||
|
||||
if (this.ArchiveEncoding.GetEncoding().GetByteCount(name) >= 100)
|
||||
{
|
||||
throw new Exception(
|
||||
throw new InvalidDataException(
|
||||
$"Tar header USTAR format can not fit file name \"{fullName}\" of length {nameByteCount}! Try using GNU Tar format instead!"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -51,7 +52,7 @@ internal sealed partial class TarHeader
|
||||
WriteUstar(output);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("This should be impossible...");
|
||||
throw new InvalidOperationException("This should be impossible...");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,9 +89,15 @@ internal sealed partial class TarHeader
|
||||
int splitIndex = -1;
|
||||
for (int i = 0; i < dirSeps.Count; i++)
|
||||
{
|
||||
#if NET8_0_OR_GREATER
|
||||
int count = ArchiveEncoding
|
||||
.GetEncoding()
|
||||
.GetByteCount(fullName.AsSpan(0, dirSeps[i]));
|
||||
#else
|
||||
int count = ArchiveEncoding
|
||||
.GetEncoding()
|
||||
.GetByteCount(fullName.Substring(0, dirSeps[i]));
|
||||
#endif
|
||||
if (count < 155)
|
||||
{
|
||||
splitIndex = dirSeps[i];
|
||||
@@ -103,7 +110,7 @@ internal sealed partial class TarHeader
|
||||
|
||||
if (splitIndex == -1)
|
||||
{
|
||||
throw new Exception(
|
||||
throw new InvalidDataException(
|
||||
$"Tar header USTAR format can not fit file name \"{fullName}\" of length {nameByteCount}! Directory separator not found! Try using GNU Tar format instead!"
|
||||
);
|
||||
}
|
||||
@@ -113,14 +120,14 @@ internal sealed partial class TarHeader
|
||||
|
||||
if (this.ArchiveEncoding.GetEncoding().GetByteCount(namePrefix) >= 155)
|
||||
{
|
||||
throw new Exception(
|
||||
throw new InvalidDataException(
|
||||
$"Tar header USTAR format can not fit file name \"{fullName}\" of length {nameByteCount}! Try using GNU Tar format instead!"
|
||||
);
|
||||
}
|
||||
|
||||
if (this.ArchiveEncoding.GetEncoding().GetByteCount(name) >= 100)
|
||||
{
|
||||
throw new Exception(
|
||||
throw new InvalidDataException(
|
||||
$"Tar header USTAR format can not fit file name \"{fullName}\" of length {nameByteCount}! Try using GNU Tar format instead!"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ namespace SharpCompress.Common.Tar;
|
||||
internal class TarReadOnlySubStream : Stream
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
private readonly bool _useSyncOverAsyncDispose;
|
||||
|
||||
private bool _isDisposed;
|
||||
private long _amountRead;
|
||||
@@ -14,7 +13,6 @@ internal class TarReadOnlySubStream : Stream
|
||||
public TarReadOnlySubStream(Stream stream, long bytesToRead, bool useSyncOverAsyncDispose)
|
||||
{
|
||||
_stream = stream;
|
||||
_useSyncOverAsyncDispose = useSyncOverAsyncDispose;
|
||||
BytesLeftToRead = bytesToRead;
|
||||
}
|
||||
|
||||
@@ -22,6 +20,7 @@ internal class TarReadOnlySubStream : Stream
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -47,6 +46,7 @@ internal class TarReadOnlySubStream : Stream
|
||||
}
|
||||
}
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#if !LEGACY_DOTNET
|
||||
@@ -54,6 +54,7 @@ internal class TarReadOnlySubStream : Stream
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -71,6 +72,7 @@ internal class TarReadOnlySubStream : Stream
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.Zip;
|
||||
|
||||
@@ -11,9 +13,10 @@ internal partial class SeekableZipFilePart : ZipFilePart
|
||||
internal SeekableZipFilePart(
|
||||
SeekableZipHeaderFactory headerFactory,
|
||||
DirectoryEntryHeader header,
|
||||
Stream stream
|
||||
Stream stream,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
: base(header, stream) => _headerFactory = headerFactory;
|
||||
: base(header, stream, compressionProviders) => _headerFactory = headerFactory;
|
||||
|
||||
internal override Stream GetCompressedStream()
|
||||
{
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Common.Zip;
|
||||
|
||||
@@ -9,8 +10,12 @@ internal sealed partial class StreamingZipFilePart : ZipFilePart
|
||||
{
|
||||
private Stream? _decompressionStream;
|
||||
|
||||
internal StreamingZipFilePart(ZipFileEntry header, Stream stream)
|
||||
: base(header, stream) { }
|
||||
internal StreamingZipFilePart(
|
||||
ZipFileEntry header,
|
||||
Stream stream,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
: base(header, stream, compressionProviders) { }
|
||||
|
||||
protected override Stream CreateBaseStream() => Header.PackedStream.NotNull();
|
||||
|
||||
@@ -47,11 +52,6 @@ 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);
|
||||
|
||||
@@ -13,6 +13,7 @@ internal partial class WinzipAesCryptoStream
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
_isDisposed = true;
|
||||
@@ -27,6 +28,7 @@ internal partial class WinzipAesCryptoStream
|
||||
ArrayPool<byte>.Shared.Return(authBytes);
|
||||
await _stream.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
await base.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace SharpCompress.Common.Zip;
|
||||
internal partial class WinzipAesCryptoStream : Stream
|
||||
{
|
||||
private const int BLOCK_SIZE_IN_BYTES = 16;
|
||||
private readonly SymmetricAlgorithm _cipher;
|
||||
private readonly Aes _cipher;
|
||||
private readonly byte[] _counter = new byte[BLOCK_SIZE_IN_BYTES];
|
||||
private readonly Stream _stream;
|
||||
private readonly ICryptoTransform _transform;
|
||||
@@ -35,7 +35,7 @@ internal partial class WinzipAesCryptoStream : Stream
|
||||
_transform = _cipher.CreateEncryptor(winzipAesEncryptionData.KeyBytes, iv);
|
||||
}
|
||||
|
||||
private SymmetricAlgorithm CreateCipher(WinzipAesEncryptionData winzipAesEncryptionData)
|
||||
private Aes CreateCipher(WinzipAesEncryptionData winzipAesEncryptionData)
|
||||
{
|
||||
var cipher = Aes.Create();
|
||||
cipher.BlockSize = BLOCK_SIZE_IN_BYTES * 8;
|
||||
@@ -63,6 +63,7 @@ internal partial class WinzipAesCryptoStream : Stream
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
return;
|
||||
}
|
||||
_isDisposed = true;
|
||||
@@ -88,6 +89,7 @@ internal partial class WinzipAesCryptoStream : Stream
|
||||
}
|
||||
_stream.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private async Task ReadAuthBytesAsync()
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpCompress.Common.Zip;
|
||||
|
||||
[SuppressMessage(
|
||||
"Security",
|
||||
"CA5379:Rfc2898DeriveBytes might be using a weak hash algorithm",
|
||||
Justification = "WinZip AES specification requires PBKDF2 with SHA-1."
|
||||
)]
|
||||
internal class WinzipAesEncryptionData
|
||||
{
|
||||
private const int RFC2898_ITERATIONS = 1000;
|
||||
|
||||
@@ -10,6 +10,10 @@ 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)
|
||||
{
|
||||
@@ -33,24 +37,54 @@ public class ZipEntry : Entry
|
||||
CreatedTime = times?.UnicodeTimes.Item3;
|
||||
}
|
||||
|
||||
public override CompressionType CompressionType =>
|
||||
_filePart?.Header.CompressionMethod switch
|
||||
public override CompressionType CompressionType
|
||||
{
|
||||
get
|
||||
{
|
||||
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,
|
||||
};
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
public override long Crc => _filePart?.Header.Crc ?? 0;
|
||||
|
||||
|
||||
@@ -6,17 +6,8 @@ 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;
|
||||
|
||||
@@ -123,6 +114,7 @@ internal abstract partial class ZipFilePart
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// Handle special cases first
|
||||
switch (method)
|
||||
{
|
||||
case ZipCompressionMethod.None:
|
||||
@@ -134,98 +126,24 @@ internal abstract partial class ZipFilePart
|
||||
|
||||
return stream;
|
||||
}
|
||||
case ZipCompressionMethod.Shrink:
|
||||
case ZipCompressionMethod.WinzipAes:
|
||||
{
|
||||
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
|
||||
)
|
||||
return await CreateWinzipAesDecompressionStreamAsync(stream, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
var compressionType = ToCompressionType(method);
|
||||
var providers = GetProviders();
|
||||
var context = new CompressionContext
|
||||
{
|
||||
InputSize = Header.CompressedSize,
|
||||
OutputSize = Header.UncompressedSize,
|
||||
CanSeek = stream.CanSeek,
|
||||
};
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case ZipCompressionMethod.LZMA:
|
||||
{
|
||||
if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted))
|
||||
@@ -234,81 +152,108 @@ 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);
|
||||
return await LzmaStream
|
||||
.CreateAsync(
|
||||
props,
|
||||
stream,
|
||||
|
||||
context = context with
|
||||
{
|
||||
Properties = props,
|
||||
InputSize =
|
||||
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,
|
||||
FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
|
||||
? -1
|
||||
: Header.UncompressedSize
|
||||
OutputSize = FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
|
||||
? -1
|
||||
: Header.UncompressedSize,
|
||||
};
|
||||
|
||||
return await providers
|
||||
.CreateDecompressStreamAsync(
|
||||
compressionType,
|
||||
stream,
|
||||
context,
|
||||
cancellationToken
|
||||
)
|
||||
.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);
|
||||
return await PpmdStream
|
||||
.CreateAsync(new PpmdProperties(props), stream, false, cancellationToken)
|
||||
context = context with { Properties = props };
|
||||
return await providers
|
||||
.CreateDecompressStreamAsync(
|
||||
compressionType,
|
||||
stream,
|
||||
context,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
case ZipCompressionMethod.WinzipAes:
|
||||
case ZipCompressionMethod.Explode:
|
||||
{
|
||||
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(
|
||||
context = context with { FormatOptions = Header.Flags };
|
||||
return await providers
|
||||
.CreateDecompressStreamAsync(
|
||||
compressionType,
|
||||
stream,
|
||||
(ZipCompressionMethod)
|
||||
BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5)),
|
||||
context,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException("CompressionMethod: " + Header.CompressionMethod);
|
||||
return await providers
|
||||
.CreateDecompressStreamAsync(
|
||||
compressionType,
|
||||
stream,
|
||||
context,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,17 +15,25 @@ 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
|
||||
{
|
||||
internal ZipFilePart(ZipFileEntry header, Stream stream)
|
||||
private readonly CompressionProviderRegistry _compressionProviders;
|
||||
|
||||
internal ZipFilePart(
|
||||
ZipFileEntry header,
|
||||
Stream stream,
|
||||
CompressionProviderRegistry compressionProviders
|
||||
)
|
||||
: base(header.ArchiveEncoding)
|
||||
{
|
||||
Header = header;
|
||||
header.Part = this;
|
||||
BaseStream = stream;
|
||||
_compressionProviders = compressionProviders;
|
||||
}
|
||||
|
||||
internal Stream BaseStream { get; }
|
||||
@@ -64,8 +72,37 @@ 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:
|
||||
@@ -74,155 +111,102 @@ internal abstract partial class ZipFilePart : FilePart
|
||||
{
|
||||
return new DataDescriptorStream(stream);
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
case ZipCompressionMethod.Shrink:
|
||||
case ZipCompressionMethod.WinzipAes:
|
||||
{
|
||||
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
|
||||
);
|
||||
return CreateWinzipAesDecompressionStream(stream);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
// 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.LZMA:
|
||||
{
|
||||
if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted))
|
||||
{
|
||||
throw new NotSupportedException("LZMA with pkware encryption.");
|
||||
}
|
||||
using (
|
||||
var reader = new BinaryReader(
|
||||
stream,
|
||||
System.Text.Encoding.Default,
|
||||
leaveOpen: true
|
||||
)
|
||||
)
|
||||
|
||||
using var reader = new BinaryReader(
|
||||
stream,
|
||||
System.Text.Encoding.Default,
|
||||
leaveOpen: true
|
||||
);
|
||||
reader.ReadUInt16(); // LZMA version
|
||||
var propsLength = reader.ReadUInt16();
|
||||
var props = reader.ReadBytes(propsLength);
|
||||
context = context with
|
||||
{
|
||||
reader.ReadUInt16(); //LZMA version
|
||||
var props = new byte[reader.ReadUInt16()];
|
||||
reader.Read(props, 0, props.Length);
|
||||
return LzmaStream.Create(
|
||||
props,
|
||||
stream,
|
||||
Properties = props,
|
||||
InputSize =
|
||||
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,
|
||||
FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
|
||||
? -1
|
||||
: Header.UncompressedSize
|
||||
);
|
||||
}
|
||||
}
|
||||
case ZipCompressionMethod.Xz:
|
||||
{
|
||||
return new XZStream(stream);
|
||||
}
|
||||
case ZipCompressionMethod.ZStandard:
|
||||
{
|
||||
return new DecompressionStream(stream);
|
||||
OutputSize = FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
|
||||
? -1
|
||||
: Header.UncompressedSize,
|
||||
};
|
||||
return providers.CreateDecompressStream(compressionType, stream, context);
|
||||
}
|
||||
case ZipCompressionMethod.PPMd:
|
||||
{
|
||||
Span<byte> props = stackalloc byte[2];
|
||||
stream.ReadFully(props);
|
||||
return PpmdStream.Create(new PpmdProperties(props), stream, false);
|
||||
context = context with { Properties = props.ToArray() };
|
||||
return providers.CreateDecompressStream(compressionType, stream, context);
|
||||
}
|
||||
case ZipCompressionMethod.WinzipAes:
|
||||
case ZipCompressionMethod.Explode:
|
||||
{
|
||||
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);
|
||||
context = context with { FormatOptions = Header.Flags };
|
||||
return providers.CreateDecompressStream(compressionType, stream, context);
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Compressors.RLE90;
|
||||
|
||||
namespace SharpCompress.Compressors.ArcLzw;
|
||||
|
||||
public partial class ArcLzwStream
|
||||
{
|
||||
public override async Task<int> ReadAsync(
|
||||
|
||||
@@ -3,7 +3,8 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Compressors.RLE90;
|
||||
using SharpCompress.Compressors.Squeezed;
|
||||
|
||||
namespace SharpCompress.Compressors.ArcLzw;
|
||||
|
||||
public partial class ArcLzwStream : Stream
|
||||
{
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
|
||||
namespace SharpCompress.Compressors.ArcLzw;
|
||||
|
||||
public partial class ArcLzwStream
|
||||
{
|
||||
public class BitReader
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Compressors.Arj;
|
||||
|
||||
public sealed partial class LhaStream<C>
|
||||
public sealed partial class LhaStream<TDecoderConfig>
|
||||
{
|
||||
public override async Task<int> ReadAsync(
|
||||
byte[] buffer,
|
||||
@@ -20,7 +21,7 @@ public sealed partial class LhaStream<C>
|
||||
}
|
||||
if (offset < 0 || count < 0 || (offset + count) > buffer.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
}
|
||||
|
||||
if (_producedBytes >= _originalSize)
|
||||
@@ -116,7 +117,7 @@ public sealed partial class LhaStream<C>
|
||||
|
||||
if (numCodes > NUM_TEMP_CODELEN)
|
||||
{
|
||||
throw new Exception("temporary codelen table has invalid size");
|
||||
throw new InvalidDataException("temporary codelen table has invalid size");
|
||||
}
|
||||
|
||||
// read actual lengths
|
||||
@@ -132,7 +133,7 @@ public sealed partial class LhaStream<C>
|
||||
|
||||
if (3 + skip > numCodes)
|
||||
{
|
||||
throw new Exception("temporary codelen table has invalid size");
|
||||
throw new InvalidDataException("temporary codelen table has invalid size");
|
||||
}
|
||||
|
||||
for (int i = 3 + skip; i < numCodes; i++)
|
||||
@@ -161,7 +162,7 @@ public sealed partial class LhaStream<C>
|
||||
|
||||
if (numCodes > NUM_COMMANDS)
|
||||
{
|
||||
throw new Exception("commands codelen table has invalid size");
|
||||
throw new InvalidDataException("commands codelen table has invalid size");
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpCompress.Compressors.Arj;
|
||||
|
||||
[CLSCompliant(true)]
|
||||
public sealed partial class LhaStream<C> : Stream
|
||||
where C : ILhaDecoderConfig, new()
|
||||
public sealed partial class LhaStream<TDecoderConfig> : Stream
|
||||
where TDecoderConfig : ILhaDecoderConfig, new()
|
||||
{
|
||||
private readonly BitReader _bitReader;
|
||||
private readonly Stream _stream;
|
||||
|
||||
private readonly HuffTree _commandTree;
|
||||
private readonly HuffTree _offsetTree;
|
||||
private int _remainingCommands;
|
||||
private (int offset, int count)? _copyProgress;
|
||||
private readonly RingBuffer _ringBuffer;
|
||||
private readonly C _config = new C();
|
||||
private readonly TDecoderConfig _config = new TDecoderConfig();
|
||||
|
||||
private const int NUM_COMMANDS = 510;
|
||||
private const int NUM_TEMP_CODELEN = 20;
|
||||
@@ -27,7 +27,6 @@ public sealed partial class LhaStream<C> : Stream
|
||||
|
||||
public LhaStream(Stream compressedStream, int originalSize)
|
||||
{
|
||||
_stream = compressedStream ?? throw new ArgumentNullException(nameof(compressedStream));
|
||||
_bitReader = new BitReader(compressedStream);
|
||||
_ringBuffer = _config.RingBuffer;
|
||||
_commandTree = new HuffTree(NUM_COMMANDS * 2);
|
||||
@@ -64,7 +63,7 @@ public sealed partial class LhaStream<C> : Stream
|
||||
}
|
||||
if (offset < 0 || count < 0 || (offset + count) > buffer.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
}
|
||||
|
||||
if (_producedBytes >= _originalSize)
|
||||
@@ -137,7 +136,7 @@ public sealed partial class LhaStream<C> : Stream
|
||||
|
||||
if (numCodes > NUM_TEMP_CODELEN)
|
||||
{
|
||||
throw new Exception("temporary codelen table has invalid size");
|
||||
throw new InvalidDataException("temporary codelen table has invalid size");
|
||||
}
|
||||
|
||||
// read actual lengths
|
||||
@@ -152,7 +151,7 @@ public sealed partial class LhaStream<C> : Stream
|
||||
|
||||
if (3 + skip > numCodes)
|
||||
{
|
||||
throw new Exception("temporary codelen table has invalid size");
|
||||
throw new InvalidDataException("temporary codelen table has invalid size");
|
||||
}
|
||||
|
||||
for (int i = 3 + skip; i < numCodes; i++)
|
||||
@@ -180,7 +179,7 @@ public sealed partial class LhaStream<C> : Stream
|
||||
|
||||
if (numCodes > NUM_COMMANDS)
|
||||
{
|
||||
throw new Exception("commands codelen table has invalid size");
|
||||
throw new InvalidDataException("commands codelen table has invalid size");
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
|
||||
@@ -3,10 +3,11 @@ 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
|
||||
public sealed partial class BZip2Stream : Stream, IFinishable
|
||||
{
|
||||
private Stream stream = default!;
|
||||
private bool isDisposed;
|
||||
@@ -54,6 +55,7 @@ public sealed partial class BZip2Stream : Stream
|
||||
{
|
||||
if (isDisposed || leaveOpen)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
return;
|
||||
}
|
||||
isDisposed = true;
|
||||
@@ -61,6 +63,7 @@ public sealed partial class BZip2Stream : Stream
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public CompressionMode Mode { get; private set; }
|
||||
|
||||
@@ -447,6 +447,7 @@ internal sealed class CBZip2OutputStream : Stream
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -460,6 +461,7 @@ internal sealed class CBZip2OutputStream : Stream
|
||||
}
|
||||
bsStream = null;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public void Finish()
|
||||
|
||||
@@ -32,6 +32,8 @@ using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Options;
|
||||
|
||||
namespace SharpCompress.Compressors.Deflate;
|
||||
|
||||
@@ -53,8 +55,23 @@ public partial class GZipStream : Stream
|
||||
public GZipStream(Stream stream, CompressionMode mode)
|
||||
: this(stream, mode, CompressionLevel.Default, Encoding.UTF8) { }
|
||||
|
||||
public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level)
|
||||
: this(stream, mode, level, 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,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
@@ -39,10 +38,6 @@ public sealed partial class Deflate64Stream
|
||||
if (_inflater.Finished())
|
||||
{
|
||||
// if we finished decompressing, we can't have anything left in the outputwindow.
|
||||
Debug.Assert(
|
||||
_inflater.AvailableOutput == 0,
|
||||
"We should have copied all stuff out!"
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
@@ -96,10 +95,6 @@ public sealed partial class Deflate64Stream : Stream
|
||||
if (_inflater.Finished())
|
||||
{
|
||||
// if we finished decompressing, we can't have anything left in the outputwindow.
|
||||
Debug.Assert(
|
||||
_inflater.AvailableOutput == 0,
|
||||
"We should have copied all stuff out!"
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SharpCompress.Compressors.Deflate64;
|
||||
|
||||
internal sealed class DeflateInput
|
||||
@@ -16,10 +14,8 @@ internal sealed class DeflateInput
|
||||
|
||||
internal void ConsumeBytes(int n)
|
||||
{
|
||||
Debug.Assert(n <= Count, "Should use more bytes than what we have in the buffer");
|
||||
StartIndex += n;
|
||||
Count -= n;
|
||||
Debug.Assert(StartIndex + Count <= Buffer.Length, "Input buffer is in invalid state!");
|
||||
}
|
||||
|
||||
internal InputState DumpState() => new(Count, StartIndex);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SharpCompress.Compressors.Deflate64;
|
||||
|
||||
@@ -964,7 +963,6 @@ internal static class FastEncoderStatics
|
||||
{
|
||||
uint newCode = 0;
|
||||
|
||||
Debug.Assert(length > 0 && length <= 16, "Invalid len");
|
||||
do
|
||||
{
|
||||
newCode |= (code & 1);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Compressors.Deflate64;
|
||||
@@ -35,9 +34,6 @@ internal sealed class HuffmanTree
|
||||
private readonly short[] _left;
|
||||
private readonly short[] _right;
|
||||
private readonly byte[] _codeLengthArray;
|
||||
#if DEBUG
|
||||
private uint[]? _codeArrayDebug;
|
||||
#endif
|
||||
|
||||
private readonly int _tableMask;
|
||||
|
||||
@@ -48,12 +44,6 @@ internal sealed class HuffmanTree
|
||||
|
||||
public HuffmanTree(byte[] codeLengths)
|
||||
{
|
||||
Debug.Assert(
|
||||
codeLengths.Length == MAX_LITERAL_TREE_ELEMENTS
|
||||
|| codeLengths.Length == MAX_DIST_TREE_ELEMENTS
|
||||
|| codeLengths.Length == NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS,
|
||||
"we only expect three kinds of Length here"
|
||||
);
|
||||
_codeLengthArray = codeLengths;
|
||||
|
||||
if (_codeLengthArray.Length == MAX_LITERAL_TREE_ELEMENTS)
|
||||
@@ -152,9 +142,6 @@ internal sealed class HuffmanTree
|
||||
private void CreateTable()
|
||||
{
|
||||
var codeArray = CalculateHuffmanCode();
|
||||
#if DEBUG
|
||||
_codeArrayDebug = codeArray;
|
||||
#endif
|
||||
|
||||
var avail = (short)_codeLengthArray.Length;
|
||||
|
||||
@@ -237,11 +224,6 @@ internal sealed class HuffmanTree
|
||||
throw new InvalidFormatException("Deflate64: invalid Huffman data");
|
||||
}
|
||||
|
||||
Debug.Assert(
|
||||
value < 0,
|
||||
"CreateTable: Only negative numbers are used for tree pointers!"
|
||||
);
|
||||
|
||||
if ((start & codeBitMask) == 0)
|
||||
{
|
||||
// if current bit is 0, go change the left array
|
||||
|
||||
@@ -572,7 +572,6 @@ internal sealed class InflaterManaged
|
||||
throw new ZlibException("Deflate64: invalid data");
|
||||
}
|
||||
_extraBits = S_EXTRA_LENGTH_BITS[symbol];
|
||||
Debug.Assert(_extraBits != 0, "We handle other cases separately!");
|
||||
}
|
||||
_length = symbol;
|
||||
goto case InflaterState.HaveInitialLength;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SharpCompress.Compressors.Deflate64;
|
||||
|
||||
@@ -38,8 +37,6 @@ internal sealed class InputBuffer
|
||||
/// <returns>Returns false if input is not sufficient to make this true.</returns>
|
||||
public bool EnsureBitsAvailable(int count)
|
||||
{
|
||||
Debug.Assert(0 < count && count <= 16, "count is invalid.");
|
||||
|
||||
// manual inlining to improve perf
|
||||
if (_bitsInBuffer < count)
|
||||
{
|
||||
@@ -106,8 +103,6 @@ internal sealed class InputBuffer
|
||||
/// <summary>Gets count bits from the input buffer. Returns -1 if not enough bits available.</summary>
|
||||
public int GetBits(int count)
|
||||
{
|
||||
Debug.Assert(0 < count && count <= 16, "count is invalid.");
|
||||
|
||||
if (!EnsureBitsAvailable(count))
|
||||
{
|
||||
return -1;
|
||||
@@ -127,12 +122,6 @@ internal sealed class InputBuffer
|
||||
/// <returns>Returns the number of bytes copied, 0 if no byte is available.</returns>
|
||||
public int CopyTo(byte[] output, int offset, int length)
|
||||
{
|
||||
Debug.Assert(output != null);
|
||||
Debug.Assert(offset >= 0);
|
||||
Debug.Assert(length >= 0);
|
||||
Debug.Assert(offset <= output.Length - length);
|
||||
Debug.Assert((_bitsInBuffer % 8) == 0);
|
||||
|
||||
// Copy the bytes in bitBuffer first.
|
||||
var bytesFromBitBuffer = 0;
|
||||
while (_bitsInBuffer > 0 && length > 0)
|
||||
@@ -175,12 +164,6 @@ internal sealed class InputBuffer
|
||||
/// </summary>
|
||||
public void SetInput(byte[] buffer, int offset, int length)
|
||||
{
|
||||
Debug.Assert(buffer != null);
|
||||
Debug.Assert(offset >= 0);
|
||||
Debug.Assert(length >= 0);
|
||||
Debug.Assert(offset <= buffer.Length - length);
|
||||
Debug.Assert(_start == _end);
|
||||
|
||||
_buffer = buffer;
|
||||
_start = offset;
|
||||
_end = offset + length;
|
||||
@@ -189,10 +172,6 @@ internal sealed class InputBuffer
|
||||
/// <summary>Skip n bits in the buffer.</summary>
|
||||
public void SkipBits(int n)
|
||||
{
|
||||
Debug.Assert(
|
||||
_bitsInBuffer >= n,
|
||||
"No enough bits in the buffer, Did you call EnsureBitsAvailable?"
|
||||
);
|
||||
_bitBuffer >>= n;
|
||||
_bitsInBuffer -= n;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SharpCompress.Compressors.Deflate64;
|
||||
|
||||
@@ -29,7 +28,6 @@ internal sealed class OutputWindow
|
||||
/// <summary>Add a byte to output window.</summary>
|
||||
public void Write(byte b)
|
||||
{
|
||||
Debug.Assert(_bytesUsed < WINDOW_SIZE, "Can't add byte when window is full!");
|
||||
_window[_end++] = b;
|
||||
_end &= WINDOW_MASK;
|
||||
++_bytesUsed;
|
||||
@@ -37,8 +35,6 @@ internal sealed class OutputWindow
|
||||
|
||||
public void WriteLengthDistance(int length, int distance)
|
||||
{
|
||||
Debug.Assert((_bytesUsed + length) <= WINDOW_SIZE, "No Enough space");
|
||||
|
||||
// move backwards distance bytes in the output stream,
|
||||
// and copy length bytes from this position to the output stream.
|
||||
_bytesUsed += length;
|
||||
@@ -143,10 +139,6 @@ internal sealed class OutputWindow
|
||||
}
|
||||
Array.Copy(_window, copyEnd - length, output, offset, length);
|
||||
_bytesUsed -= copied;
|
||||
Debug.Assert(
|
||||
_bytesUsed >= 0,
|
||||
"check this function and find why we copied more bytes than we have"
|
||||
);
|
||||
return copied;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
@@ -278,7 +279,7 @@ public partial class ExplodeStream
|
||||
|
||||
if (literalResult.returnCode != 0)
|
||||
{
|
||||
throw new Exception("Error decoding literal value");
|
||||
throw new InvalidDataException("Error decoding literal value");
|
||||
}
|
||||
|
||||
huftPointer = literalResult.huftPointer;
|
||||
@@ -318,7 +319,7 @@ public partial class ExplodeStream
|
||||
|
||||
if (distanceResult.returnCode != 0)
|
||||
{
|
||||
throw new Exception("Error decoding distance high bits");
|
||||
throw new InvalidDataException("Error decoding distance high bits");
|
||||
}
|
||||
|
||||
huftPointer = distanceResult.huftPointer;
|
||||
@@ -334,7 +335,7 @@ public partial class ExplodeStream
|
||||
|
||||
if (lengthResult.returnCode != 0)
|
||||
{
|
||||
throw new Exception("Error decoding coded length");
|
||||
throw new InvalidDataException("Error decoding coded length");
|
||||
}
|
||||
|
||||
huftPointer = lengthResult.huftPointer;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
|
||||
namespace SharpCompress.Compressors.Explode;
|
||||
@@ -696,7 +697,7 @@ public partial class ExplodeStream : Stream
|
||||
) != 0
|
||||
)
|
||||
{
|
||||
throw new Exception("Error decoding literal value");
|
||||
throw new InvalidDataException("Error decoding literal value");
|
||||
}
|
||||
|
||||
nextByte = (byte)huftPointer.Value;
|
||||
@@ -735,7 +736,7 @@ public partial class ExplodeStream : Stream
|
||||
) != 0
|
||||
)
|
||||
{
|
||||
throw new Exception("Error decoding distance high bits");
|
||||
throw new InvalidDataException("Error decoding distance high bits");
|
||||
}
|
||||
|
||||
distance = windowIndex - (distance + huftPointer.Value); /* construct offset */
|
||||
@@ -751,7 +752,7 @@ public partial class ExplodeStream : Stream
|
||||
) != 0
|
||||
)
|
||||
{
|
||||
throw new Exception("Error decoding coded length");
|
||||
throw new InvalidDataException("Error decoding coded length");
|
||||
}
|
||||
|
||||
length = huftPointer.Value;
|
||||
|
||||
@@ -18,9 +18,9 @@ public sealed class BranchExecFilter
|
||||
ARCH_x86_ALIGNMENT = 1,
|
||||
ARCH_PowerPC_ALIGNMENT = 4,
|
||||
ARCH_IA64_ALIGNMENT = 16,
|
||||
ARCH_ARM_ALIGNMENT = 4,
|
||||
ARCH_ARM_ALIGNMENT = ARCH_PowerPC_ALIGNMENT,
|
||||
ARCH_ARMTHUMB_ALIGNMENT = 2,
|
||||
ARCH_SPARC_ALIGNMENT = 4,
|
||||
ARCH_SPARC_ALIGNMENT = ARCH_PowerPC_ALIGNMENT,
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace SharpCompress.Compressors.Filters;
|
||||
|
||||
internal class DeltaFilter : Filter
|
||||
{
|
||||
private const int DISTANCE_MIN = 1;
|
||||
private const int DISTANCE_MAX = 256;
|
||||
private const int DISTANCE_MASK = DISTANCE_MAX - 1;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
using SharpCompress.Compressors.LZMA.Utilities;
|
||||
|
||||
namespace SharpCompress.Compressors.LZMA;
|
||||
|
||||
|
||||
@@ -88,13 +88,8 @@ internal class Bcj2DecoderStream : DecoderStream2
|
||||
private bool _mFinished;
|
||||
private bool _isDisposed;
|
||||
|
||||
public Bcj2DecoderStream(Stream[] streams, byte[] info, long limit)
|
||||
public Bcj2DecoderStream(Stream[] streams)
|
||||
{
|
||||
if (info != null && info.Length > 0)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
if (streams.Length != 4)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
|
||||
@@ -7,7 +7,7 @@ using SharpCompress.Common.SevenZip;
|
||||
using SharpCompress.Compressors.BZip2;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Compressors.Filters;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
using SharpCompress.Compressors.LZMA.Utilities;
|
||||
using SharpCompress.Compressors.PPMd;
|
||||
using SharpCompress.Compressors.ZStandard;
|
||||
|
||||
@@ -18,7 +18,7 @@ internal static partial class DecoderRegistry
|
||||
internal static async ValueTask<Stream> CreateDecoderStreamAsync(
|
||||
CMethodId id,
|
||||
Stream[] inStreams,
|
||||
byte[] info,
|
||||
byte[]? info,
|
||||
IPasswordProvider pass,
|
||||
long limit,
|
||||
CancellationToken cancellationToken
|
||||
@@ -33,18 +33,26 @@ internal static partial class DecoderRegistry
|
||||
}
|
||||
return inStreams.Single();
|
||||
case K_DELTA:
|
||||
return new DeltaFilter(false, inStreams.Single(), info);
|
||||
return new DeltaFilter(false, inStreams.Single(), info.NotNull());
|
||||
case K_LZMA:
|
||||
case K_LZMA2:
|
||||
return await LzmaStream
|
||||
.CreateAsync(info, inStreams.Single(), -1, limit, null, info.Length < 5, false)
|
||||
.CreateAsync(
|
||||
info.NotNull(),
|
||||
inStreams.Single(),
|
||||
-1,
|
||||
limit,
|
||||
null,
|
||||
info.NotNull().Length < 5,
|
||||
false
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
case CMethodId.K_AES_ID:
|
||||
return new AesDecoderStream(inStreams.Single(), info, pass, limit);
|
||||
return new AesDecoderStream(inStreams.Single(), info.NotNull(), pass, limit);
|
||||
case K_BCJ:
|
||||
return new BCJFilter(false, inStreams.Single());
|
||||
case K_BCJ2:
|
||||
return new Bcj2DecoderStream(inStreams, info, limit);
|
||||
return new Bcj2DecoderStream(inStreams);
|
||||
case K_PPC:
|
||||
return new BCJFilterPPC(false, inStreams.Single());
|
||||
case K_IA64:
|
||||
@@ -71,7 +79,7 @@ internal static partial class DecoderRegistry
|
||||
case K_PPMD:
|
||||
return await PpmdStream
|
||||
.CreateAsync(
|
||||
new PpmdProperties(info),
|
||||
new PpmdProperties(info.NotNull()),
|
||||
inStreams.Single(),
|
||||
false,
|
||||
cancellationToken
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.SevenZip;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
using SharpCompress.Compressors.LZMA.Utilities;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Compressors.LZMA;
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Crypto;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Providers;
|
||||
|
||||
namespace SharpCompress.Compressors.LZMA;
|
||||
|
||||
@@ -17,7 +18,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
|
||||
public sealed partial class LZipStream : Stream, IFinishable
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
private readonly CountingStream? _countingWritableSubStream;
|
||||
@@ -99,6 +100,7 @@ public sealed partial class LZipStream : Stream
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
return;
|
||||
}
|
||||
_disposed = true;
|
||||
@@ -111,6 +113,7 @@ public sealed partial class LZipStream : Stream
|
||||
_originalStream?.Dispose();
|
||||
}
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public CompressionMode Mode { get; }
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SharpCompress.Compressors.LZMA;
|
||||
|
||||
@@ -28,68 +27,44 @@ internal static class Log
|
||||
if (NEEDS_INDENT)
|
||||
{
|
||||
NEEDS_INDENT = false;
|
||||
#if DEBUG_LZMA
|
||||
Debug.Write(INDENT.Peek());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(object value)
|
||||
{
|
||||
EnsureIndent();
|
||||
#if DEBUG_LZMA
|
||||
Debug.Write(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void Write(string text)
|
||||
{
|
||||
EnsureIndent();
|
||||
#if DEBUG_LZMA
|
||||
Debug.Write(text);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void Write(string format, params object[] args)
|
||||
{
|
||||
EnsureIndent();
|
||||
#if DEBUG_LZMA
|
||||
Debug.Write(string.Format(format, args));
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void WriteLine()
|
||||
{
|
||||
#if DEBUG_LZMA
|
||||
Debug.WriteLine("");
|
||||
#endif
|
||||
NEEDS_INDENT = true;
|
||||
}
|
||||
|
||||
public static void WriteLine(object value)
|
||||
{
|
||||
EnsureIndent();
|
||||
#if DEBUG_LZMA
|
||||
Debug.WriteLine(value);
|
||||
#endif
|
||||
NEEDS_INDENT = true;
|
||||
}
|
||||
|
||||
public static void WriteLine(string text)
|
||||
{
|
||||
EnsureIndent();
|
||||
#if DEBUG_LZMA
|
||||
Debug.WriteLine(text);
|
||||
#endif
|
||||
NEEDS_INDENT = true;
|
||||
}
|
||||
|
||||
public static void WriteLine(string format, params object[] args)
|
||||
{
|
||||
EnsureIndent();
|
||||
#if DEBUG_LZMA
|
||||
Debug.WriteLine(string.Format(format, args));
|
||||
#endif
|
||||
NEEDS_INDENT = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,9 +281,6 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
|
||||
}
|
||||
}
|
||||
|
||||
private const uint K_NUM_LEN_SPEC_SYMBOLS =
|
||||
Base.K_NUM_LOW_LEN_SYMBOLS + Base.K_NUM_MID_LEN_SYMBOLS;
|
||||
|
||||
private class LenPriceTableEncoder : LenEncoder
|
||||
{
|
||||
private readonly uint[] _prices = new uint[
|
||||
@@ -1232,12 +1229,6 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
|
||||
}
|
||||
}
|
||||
|
||||
private bool ChangePair(uint smallDist, uint bigDist)
|
||||
{
|
||||
const int kDif = 7;
|
||||
return (smallDist < ((uint)(1) << (32 - kDif)) && bigDist >= (smallDist << kDif));
|
||||
}
|
||||
|
||||
private void WriteEndMarker(uint posState)
|
||||
{
|
||||
if (!_writeEndMark)
|
||||
|
||||
@@ -5,7 +5,7 @@ using SharpCompress.Common.SevenZip;
|
||||
using SharpCompress.Compressors.BZip2;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Compressors.Filters;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
using SharpCompress.Compressors.LZMA.Utilities;
|
||||
using SharpCompress.Compressors.PPMd;
|
||||
using SharpCompress.Compressors.ZStandard;
|
||||
|
||||
@@ -34,7 +34,7 @@ internal static partial class DecoderRegistry
|
||||
internal static Stream CreateDecoderStream(
|
||||
CMethodId id,
|
||||
Stream[] inStreams,
|
||||
byte[] info,
|
||||
byte[]? info,
|
||||
IPasswordProvider pass,
|
||||
long limit
|
||||
)
|
||||
@@ -48,16 +48,16 @@ internal static partial class DecoderRegistry
|
||||
}
|
||||
return inStreams.Single();
|
||||
case K_DELTA:
|
||||
return new DeltaFilter(false, inStreams.Single(), info);
|
||||
return new DeltaFilter(false, inStreams.Single(), info.NotNull());
|
||||
case K_LZMA:
|
||||
case K_LZMA2:
|
||||
return LzmaStream.Create(info, inStreams.Single(), -1, limit);
|
||||
return LzmaStream.Create(info.NotNull(), inStreams.Single(), -1, limit);
|
||||
case CMethodId.K_AES_ID:
|
||||
return new AesDecoderStream(inStreams.Single(), info, pass, limit);
|
||||
return new AesDecoderStream(inStreams.Single(), info.NotNull(), pass, limit);
|
||||
case K_BCJ:
|
||||
return new BCJFilter(false, inStreams.Single());
|
||||
case K_BCJ2:
|
||||
return new Bcj2DecoderStream(inStreams, info, limit);
|
||||
return new Bcj2DecoderStream(inStreams);
|
||||
case K_PPC:
|
||||
return new BCJFilterPPC(false, inStreams.Single());
|
||||
case K_IA64:
|
||||
@@ -75,7 +75,11 @@ internal static partial class DecoderRegistry
|
||||
case K_B_ZIP2:
|
||||
return BZip2Stream.Create(inStreams.Single(), CompressionMode.Decompress, true);
|
||||
case K_PPMD:
|
||||
return PpmdStream.Create(new PpmdProperties(info), inStreams.Single(), false);
|
||||
return PpmdStream.Create(
|
||||
new PpmdProperties(info.NotNull()),
|
||||
inStreams.Single(),
|
||||
false
|
||||
);
|
||||
case K_DEFLATE:
|
||||
return new DeflateStream(inStreams.Single(), CompressionMode.Decompress);
|
||||
case K_ZSTD:
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Compressors.LZMA.Utilites;
|
||||
namespace SharpCompress.Compressors.LZMA.Utilities;
|
||||
|
||||
internal enum BlockType : byte
|
||||
{
|
||||
@@ -37,20 +33,3 @@ internal enum BlockType : byte
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal static class Utils
|
||||
{
|
||||
[Conditional("DEBUG")]
|
||||
public static void Assert(bool expression)
|
||||
{
|
||||
if (!expression)
|
||||
{
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Assertion failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Compressors.LZMA.Utilites;
|
||||
namespace SharpCompress.Compressors.LZMA.Utilities;
|
||||
|
||||
internal partial class CrcBuilderStream : Stream
|
||||
{
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user