Compare commits

..

30 Commits

Author SHA1 Message Date
Adam Hathcock
165239c971 Merge pull request #1213 from adamhathcock/copilot/fix-compression-type-entry
Fix CompressionType for WinZip AES encrypted ZIP entries
2026-02-12 16:33:28 +00:00
copilot-swe-agent[bot]
d68b9d6a86 Final validation - all tests pass, no security issues
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
2026-02-12 15:51:01 +00:00
copilot-swe-agent[bot]
359b1093bc Add named constants for WinZip AES extra data magic numbers
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
2026-02-12 15:47:30 +00:00
copilot-swe-agent[bot]
ebb8f16e44 Fix CompressionType for WinZip AES encrypted entries
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
2026-02-12 15:45:52 +00:00
copilot-swe-agent[bot]
c7dac12cd9 Initial analysis - WinZip AES encrypted entries show CompressionType: Unknown
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
2026-02-12 15:40:59 +00:00
copilot-swe-agent[bot]
a505808549 Initial plan 2026-02-12 15:37:05 +00:00
Adam Hathcock
c81e78b5bb fix async benchmarks 2026-02-12 11:07:11 +00:00
Adam Hathcock
fb707aa676 push to nuget only on tags 2026-02-12 10:56:26 +00:00
Adam Hathcock
147dbc878a Merge pull request #1210 from adamhathcock/adam/issue-1206
OpenAsyncReader, OpenAsyncArchive and others must be async for Tar detection
2026-02-12 10:43:10 +00:00
Adam Hathcock
06bd6d9bed Merge pull request #1202 from adamhathcock/adam/async-benchmarks
update benchmarks to include async paths
2026-02-12 10:37:21 +00:00
Adam Hathcock
7f6272807d update docs 2026-02-12 10:32:20 +00:00
Adam Hathcock
89d948b4e1 use configure await false 2026-02-12 10:29:15 +00:00
Adam Hathcock
51c42b89b4 OpenAsyncArchive has to be async 2026-02-12 10:26:18 +00:00
Adam Hathcock
5a319ffe2c create/open always has to be async for detection 2026-02-12 10:18:43 +00:00
Adam Hathcock
bae660381c TarArchive should use a compression method like TarReader 2026-02-12 09:48:06 +00:00
Adam Hathcock
b2f1d007c6 Clean up some code paths 2026-02-12 08:50:18 +00:00
Adam Hathcock
33e9c78626 Merge pull request #1203 from adamhathcock/adam/issue-1201 2026-02-11 17:41:08 +00:00
Adam Hathcock
6f50545c31 more cleaning 2026-02-11 16:48:37 +00:00
Adam Hathcock
ab1dd45e9c more moved and validated 2026-02-11 16:47:20 +00:00
Adam Hathcock
cd5da3da5d moved and validated more async code 2026-02-11 16:35:41 +00:00
Adam Hathcock
218af5a8b3 validate and make sure rar5 methods are the same 2026-02-11 16:27:53 +00:00
Adam Hathcock
e786c00767 divide async and sync logic 2026-02-11 16:20:51 +00:00
Adam Hathcock
103ae60631 codex found problems 2026-02-11 16:10:55 +00:00
Adam Hathcock
98d0f1913e make sure things compile adam 2026-02-11 14:19:21 +00:00
Adam Hathcock
8aa93f4e34 fix fmt 2026-02-11 14:02:27 +00:00
Adam Hathcock
3689b893db Update tests/SharpCompress.Performance/Benchmarks/SevenZipBenchmarks.cs
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-02-11 14:00:37 +00:00
Adam Hathcock
fbec7dc083 generate github actions baseline 2026-02-11 13:57:06 +00:00
Adam Hathcock
7cf7623438 update benchmarks to include async paths 2026-02-11 13:36:26 +00:00
Adam Hathcock
8a54f253d5 Merge pull request #1200 from adamhathcock/adam/fix-async-7z-seeking 2026-02-11 12:35:18 +00:00
Adam Hathcock
d0baa16502 Fix 7z seeking to be contigous in async too 2026-02-11 12:16:19 +00:00
138 changed files with 4126 additions and 3035 deletions

View File

@@ -299,19 +299,6 @@ 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
@@ -331,9 +318,9 @@ dotnet_diagnostic.MVC1000.severity = suggestion
dotnet_diagnostic.RZ10012.severity = error
dotnet_diagnostic.IDE0004.severity = suggestion # redundant cast
dotnet_diagnostic.IDE0004.severity = error # redundant cast
dotnet_diagnostic.IDE0005.severity = suggestion
dotnet_diagnostic.IDE0007.severity = suggestion # Use var
dotnet_diagnostic.IDE0007.severity = error # 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
@@ -347,7 +334,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 = suggestion # modifiers required
dotnet_diagnostic.IDE0040.severity = error # 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
@@ -361,12 +348,6 @@ 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
@@ -378,7 +359,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 = suggestion # Primary Constructor
dotnet_diagnostic.IDE0290.severity = error # Primary Constructor
dotnet_diagnostic.IDE0300.severity = suggestion # Collection
dotnet_diagnostic.IDE0305.severity = suggestion # Collection ToList

View File

@@ -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 }}

View File

@@ -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

View File

@@ -8,6 +8,8 @@
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RunAnalyzersDuringLiveAnalysis>False</RunAnalyzersDuringLiveAnalysis>
<RunAnalyzersDuringBuild>False</RunAnalyzersDuringBuild>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
@@ -115,19 +114,14 @@ Target(
{
var (version, isPrerelease) = await GetVersion();
Console.WriteLine($"VERSION={version}");
Console.WriteLine(
$"PRERELEASE={isPrerelease.ToString().ToLower(CultureInfo.InvariantCulture)}"
);
Console.WriteLine($"PRERELEASE={isPrerelease.ToString().ToLower()}");
// 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(CultureInfo.InvariantCulture)}\n"
);
File.AppendAllText(githubOutput, $"prerelease={isPrerelease.ToString().ToLower()}\n");
}
}
);
@@ -369,13 +363,9 @@ 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}% |"
@@ -555,10 +545,7 @@ static async Task<string> GetGitOutput(string command, string args)
}
catch (Exception ex)
{
throw new InvalidOperationException(
$"Git command failed: git {command} {args}\n{ex.Message}",
ex
);
throw new Exception($"Git command failed: git {command} {args}\n{ex.Message}", ex);
}
}
@@ -588,7 +575,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("&#39;", StringComparison.Ordinal) && i > 0)
if (line.StartsWith("|") && line.Contains("&#39;") && i > 0)
{
var parts = line.Split('|', StringSplitOptions.TrimEntries);
if (parts.Length >= 5)
@@ -601,10 +588,10 @@ static Dictionary<string, BenchmarkMetric> ParseBenchmarkResults(string markdown
for (int j = parts.Length - 2; j >= 2; j--)
{
if (
parts[j].Contains("KB", StringComparison.Ordinal)
|| parts[j].Contains("MB", StringComparison.Ordinal)
|| parts[j].Contains("GB", StringComparison.Ordinal)
|| parts[j].Contains('B')
parts[j].Contains("KB")
|| parts[j].Contains("MB")
|| parts[j].Contains("GB")
|| parts[j].Contains("B")
)
{
memoryStr = parts[j];
@@ -637,21 +624,17 @@ 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(CultureInfo.InvariantCulture);
var unit = match.Groups[2].Value.ToLower();
// Convert to microseconds for comparison
return unit switch
@@ -667,20 +650,16 @@ 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(CultureInfo.InvariantCulture);
var unit = match.Groups[2].Value.ToUpper();
// Convert to KB for comparison
return unit switch
@@ -696,9 +675,7 @@ static double ParseMemoryValue(string memStr)
static double CalculateChange(double baseline, double current)
{
if (baseline == 0)
{
return 0;
}
return ((current - baseline) / baseline) * 100;
}

View File

@@ -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())
{
@@ -409,7 +409,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",

View File

@@ -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(

View File

@@ -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;

View File

@@ -40,7 +40,10 @@ public partial class GZipArchive
{
throw new InvalidFormatException("Only one entry is allowed in a GZip Archive");
}
await using var writer = new GZipWriter(stream, options);
await using var writer = new GZipWriter(
stream,
options as GZipWriterOptions ?? new GZipWriterOptions(options)
);
await foreach (
var entry in oldEntries.WithCancellation(cancellationToken).ConfigureAwait(false)
)

View File

@@ -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));

View File

@@ -67,7 +67,10 @@ public partial class GZipArchive
{
throw new InvalidFormatException("Only one entry is allowed in a GZip Archive");
}
using var writer = new GZipWriter(stream, options);
using var writer = new GZipWriter(
stream,
options as GZipWriterOptions ?? new GZipWriterOptions(options)
);
foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory))
{
using var entryStream = entry.OpenEntryStream();

View File

@@ -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
);
}

View File

@@ -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
);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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));

View File

@@ -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));

View File

@@ -182,15 +182,15 @@ public partial class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, Sev
);
}
// Wrap with SyncOnlyStream to work around LZMA async bugs
// Return a ReadOnlySubStream that reads from the shared folder stream
return CreateEntryStream(
new SyncOnlyStream(
new ReadOnlySubStream(_currentFolderStream, entry.Size, leaveOpen: true)
)
new ReadOnlySubStream(_currentFolderStream, entry.Size, leaveOpen: true)
);
}
protected override ValueTask<EntryStream> GetEntryStreamAsync(
CancellationToken cancellationToken = default
) => new(GetEntryStream());
public override void Dispose()
{
_currentFolderStream?.Dispose();

View File

@@ -25,7 +25,10 @@ public partial class TarArchive
CancellationToken cancellationToken = default
)
{
using var writer = new TarWriter(stream, options);
using var writer = new TarWriter(
stream,
options as TarWriterOptions ?? new TarWriterOptions(options)
);
await foreach (
var entry in oldEntries.WithCancellation(cancellationToken).ConfigureAwait(false)
)

View File

@@ -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,14 @@ 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.Seek(0, SeekOrigin.Begin);
return new TarArchive(sourceStream, compressionType);
}
public static IWritableArchive<TarWriterOptions> OpenArchive(
@@ -69,13 +68,14 @@ 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.Seek(0, SeekOrigin.Begin);
return new TarArchive(sourceStream, compressionType);
}
public static IWritableArchive<TarWriterOptions> OpenArchive(
@@ -90,35 +90,97 @@ 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, 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, 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, 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, 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 +245,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());
}

View File

@@ -2,38 +2,60 @@ 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.Common.Tar;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.Compressors.BZip2;
using SharpCompress.Compressors.Deflate;
using SharpCompress.Compressors.LZMA;
using SharpCompress.Compressors.Lzw;
using SharpCompress.Compressors.Xz;
using SharpCompress.Compressors.ZStandard;
using SharpCompress.IO;
using SharpCompress.Readers;
using SharpCompress.Readers.Tar;
using SharpCompress.Writers;
using SharpCompress.Writers.Tar;
using CompressionMode = SharpCompress.Compressors.CompressionMode;
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 => BZip2Stream.Create(stream, CompressionMode.Decompress, false),
CompressionType.GZip => new GZipStream(stream, CompressionMode.Decompress),
CompressionType.ZStandard => new ZStandardStream(stream),
CompressionType.LZip => new LZipStream(stream, CompressionMode.Decompress),
CompressionType.Xz => new XZStream(stream),
CompressionType.Lzw => new LzwStream(stream),
CompressionType.None => stream,
_ => throw new NotSupportedException("Invalid compression type: " + _compressionType),
};
protected override 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 +63,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
)
@@ -124,7 +148,10 @@ public partial class TarArchive
IEnumerable<TarArchiveEntry> newEntries
)
{
using var writer = new TarWriter(stream, options);
using var writer = new TarWriter(
stream,
options as TarWriterOptions ?? new TarWriterOptions(options)
);
foreach (var entry in oldEntries.Concat(newEntries))
{
if (entry.IsDirectory)
@@ -151,6 +178,6 @@ public partial class TarArchive
{
var stream = Volumes.Single().Stream;
stream.Position = 0;
return TarReader.OpenReader(stream);
return TarReader.OpenReader(GetStream(stream));
}
}

View File

@@ -79,7 +79,10 @@ public partial class ZipArchive
CancellationToken cancellationToken = default
)
{
using var writer = new ZipWriter(stream, options);
using var writer = new ZipWriter(
stream,
options as ZipWriterOptions ?? new ZipWriterOptions(options)
);
await foreach (
var entry in oldEntries.WithCancellation(cancellationToken).ConfigureAwait(false)
)

View File

@@ -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,

View File

@@ -122,7 +122,10 @@ public partial class ZipArchive
IEnumerable<ZipArchiveEntry> newEntries
)
{
using var writer = new ZipWriter(stream, options);
using var writer = new ZipWriter(
stream,
options as ZipWriterOptions ?? new ZipWriterOptions(options)
);
foreach (var entry in oldEntries.Concat(newEntries))
{
if (entry.IsDirectory)

View File

@@ -2,7 +2,6 @@ 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;

View File

@@ -8,7 +8,6 @@ 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;

View File

@@ -18,6 +18,7 @@ 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)

View File

@@ -10,6 +10,9 @@ 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; }

View File

@@ -91,8 +91,8 @@ internal class AsyncMarkingBinaryReader
}
public async ValueTask<ulong> ReadRarVIntAsync(
int maxBytes = 10,
CancellationToken cancellationToken = default
CancellationToken cancellationToken = default,
int maxBytes = 10
) => await DoReadRarVIntAsync((maxBytes - 1) * 7, cancellationToken).ConfigureAwait(false);
private async ValueTask<ulong> DoReadRarVIntAsync(

View File

@@ -1,17 +1,11 @@
#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;

View File

@@ -44,7 +44,9 @@ internal sealed partial class ArchiveHeader
PosAv = await reader.ReadInt32Async(cancellationToken).ConfigureAwait(false);
if (HasFlag(ArchiveFlagsV4.ENCRYPT_VER))
{
_ = await reader.ReadByteAsync(cancellationToken).ConfigureAwait(false);
EncryptionVersion = await reader
.ReadByteAsync(cancellationToken)
.ConfigureAwait(false);
}
}
}

View File

@@ -29,7 +29,7 @@ internal sealed partial class ArchiveHeader : RarHeader
PosAv = reader.ReadInt32();
if (HasFlag(ArchiveFlagsV4.ENCRYPT_VER))
{
_ = reader.ReadByte();
EncryptionVersion = reader.ReadByte();
}
}
}
@@ -44,6 +44,8 @@ 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);

View File

@@ -79,7 +79,7 @@ internal partial class FileHeader
CompressionMethod = (byte)((compressionInfo >> 7) & 0x7);
WindowSize = IsDirectory ? 0 : ((size_t)0x20000) << ((compressionInfo >> 10) & 0xf);
_ = await reader
HostOs = await reader
.ReadRarVIntByteAsync(cancellationToken: cancellationToken)
.ConfigureAwait(false);
@@ -222,7 +222,7 @@ internal partial class FileHeader
.ReadUInt32Async(cancellationToken)
.ConfigureAwait(false);
_ = await reader.ReadByteAsync(cancellationToken).ConfigureAwait(false);
HostOs = await reader.ReadByteAsync(cancellationToken).ConfigureAwait(false);
FileCrc = await reader.ReadBytesAsync(4, cancellationToken).ConfigureAwait(false);

View File

@@ -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);
_ = reader.ReadRarVIntByte();
HostOs = reader.ReadRarVIntByte();
var nameSize = reader.ReadRarVIntUInt16();
@@ -197,7 +197,7 @@ internal partial class FileHeader : RarHeader
var lowUncompressedSize = reader.ReadUInt32();
_ = reader.ReadByte();
HostOs = reader.ReadByte();
FileCrc = reader.ReadBytes(4);
@@ -415,6 +415,7 @@ 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; }

View File

@@ -42,20 +42,4 @@ 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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -3,7 +3,6 @@ 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;
@@ -27,7 +26,7 @@ internal sealed partial class TarHeader
await WriteUstarAsync(output, cancellationToken).ConfigureAwait(false);
break;
default:
throw new InvalidOperationException("This should be impossible...");
throw new Exception("This should be impossible...");
}
}
@@ -59,15 +58,9 @@ 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];
@@ -80,7 +73,7 @@ internal sealed partial class TarHeader
if (splitIndex == -1)
{
throw new InvalidDataException(
throw new Exception(
$"Tar header USTAR format can not fit file name \"{fullName}\" of length {nameByteCount}! Directory separator not found! Try using GNU Tar format instead!"
);
}
@@ -90,14 +83,14 @@ internal sealed partial class TarHeader
if (this.ArchiveEncoding.GetEncoding().GetByteCount(namePrefix) >= 155)
{
throw new InvalidDataException(
throw new Exception(
$"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 InvalidDataException(
throw new Exception(
$"Tar header USTAR format can not fit file name \"{fullName}\" of length {nameByteCount}! Try using GNU Tar format instead!"
);
}

View File

@@ -3,7 +3,6 @@ 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;
@@ -52,7 +51,7 @@ internal sealed partial class TarHeader
WriteUstar(output);
break;
default:
throw new InvalidOperationException("This should be impossible...");
throw new Exception("This should be impossible...");
}
}
@@ -89,15 +88,9 @@ 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];
@@ -110,7 +103,7 @@ internal sealed partial class TarHeader
if (splitIndex == -1)
{
throw new InvalidDataException(
throw new Exception(
$"Tar header USTAR format can not fit file name \"{fullName}\" of length {nameByteCount}! Directory separator not found! Try using GNU Tar format instead!"
);
}
@@ -120,14 +113,14 @@ internal sealed partial class TarHeader
if (this.ArchiveEncoding.GetEncoding().GetByteCount(namePrefix) >= 155)
{
throw new InvalidDataException(
throw new Exception(
$"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 InvalidDataException(
throw new Exception(
$"Tar header USTAR format can not fit file name \"{fullName}\" of length {nameByteCount}! Try using GNU Tar format instead!"
);
}

View File

@@ -6,6 +6,7 @@ namespace SharpCompress.Common.Tar;
internal class TarReadOnlySubStream : Stream
{
private readonly Stream _stream;
private readonly bool _useSyncOverAsyncDispose;
private bool _isDisposed;
private long _amountRead;
@@ -13,6 +14,7 @@ internal class TarReadOnlySubStream : Stream
public TarReadOnlySubStream(Stream stream, long bytesToRead, bool useSyncOverAsyncDispose)
{
_stream = stream;
_useSyncOverAsyncDispose = useSyncOverAsyncDispose;
BytesLeftToRead = bytesToRead;
}
@@ -20,7 +22,6 @@ internal class TarReadOnlySubStream : Stream
{
if (_isDisposed)
{
base.Dispose(disposing);
return;
}
@@ -46,7 +47,6 @@ internal class TarReadOnlySubStream : Stream
}
}
}
base.Dispose(disposing);
}
#if !LEGACY_DOTNET
@@ -54,7 +54,6 @@ internal class TarReadOnlySubStream : Stream
{
if (_isDisposed)
{
await base.DisposeAsync().ConfigureAwait(false);
return;
}
@@ -72,7 +71,6 @@ internal class TarReadOnlySubStream : Stream
}
GC.SuppressFinalize(this);
await base.DisposeAsync().ConfigureAwait(false);
}
#endif

View File

@@ -13,7 +13,6 @@ internal partial class WinzipAesCryptoStream
{
if (_isDisposed)
{
await base.DisposeAsync().ConfigureAwait(false);
return;
}
_isDisposed = true;
@@ -28,7 +27,6 @@ internal partial class WinzipAesCryptoStream
ArrayPool<byte>.Shared.Return(authBytes);
await _stream.DisposeAsync().ConfigureAwait(false);
}
await base.DisposeAsync().ConfigureAwait(false);
}
#endif

View File

@@ -10,7 +10,7 @@ namespace SharpCompress.Common.Zip;
internal partial class WinzipAesCryptoStream : Stream
{
private const int BLOCK_SIZE_IN_BYTES = 16;
private readonly Aes _cipher;
private readonly SymmetricAlgorithm _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 Aes CreateCipher(WinzipAesEncryptionData winzipAesEncryptionData)
private SymmetricAlgorithm CreateCipher(WinzipAesEncryptionData winzipAesEncryptionData)
{
var cipher = Aes.Create();
cipher.BlockSize = BLOCK_SIZE_IN_BYTES * 8;
@@ -63,7 +63,6 @@ internal partial class WinzipAesCryptoStream : Stream
{
if (_isDisposed)
{
base.Dispose(disposing);
return;
}
_isDisposed = true;
@@ -89,7 +88,6 @@ internal partial class WinzipAesCryptoStream : Stream
}
_stream.Dispose();
}
base.Dispose(disposing);
}
private async Task ReadAuthBytesAsync()

View File

@@ -1,16 +1,10 @@
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;

View File

@@ -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;

View File

@@ -150,22 +150,26 @@ internal abstract partial class ZipFilePart : FilePart
{
throw new NotSupportedException("LZMA with pkware encryption.");
}
using var reader = new BinaryReader(
stream,
System.Text.Encoding.Default,
leaveOpen: true
);
reader.ReadUInt16(); //LZMA version
var props = new byte[reader.ReadUInt16()];
reader.Read(props, 0, props.Length);
return LzmaStream.Create(
props,
stream,
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,
FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
? -1
: Header.UncompressedSize
);
using (
var reader = new BinaryReader(
stream,
System.Text.Encoding.Default,
leaveOpen: true
)
)
{
reader.ReadUInt16(); //LZMA version
var props = new byte[reader.ReadUInt16()];
reader.Read(props, 0, props.Length);
return LzmaStream.Create(
props,
stream,
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,
FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
? -1
: Header.UncompressedSize
);
}
}
case ZipCompressionMethod.Xz:
{

View File

@@ -1,11 +1,10 @@
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(

View File

@@ -3,8 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Compressors.RLE90;
namespace SharpCompress.Compressors.ArcLzw;
using SharpCompress.Compressors.Squeezed;
public partial class ArcLzwStream : Stream
{

View File

@@ -1,7 +1,5 @@
using System;
namespace SharpCompress.Compressors.ArcLzw;
public partial class ArcLzwStream
{
public class BitReader

View File

@@ -1,12 +1,11 @@
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<TDecoderConfig>
public sealed partial class LhaStream<C>
{
public override async Task<int> ReadAsync(
byte[] buffer,
@@ -21,7 +20,7 @@ public sealed partial class LhaStream<TDecoderConfig>
}
if (offset < 0 || count < 0 || (offset + count) > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
throw new ArgumentOutOfRangeException();
}
if (_producedBytes >= _originalSize)
@@ -117,7 +116,7 @@ public sealed partial class LhaStream<TDecoderConfig>
if (numCodes > NUM_TEMP_CODELEN)
{
throw new InvalidDataException("temporary codelen table has invalid size");
throw new Exception("temporary codelen table has invalid size");
}
// read actual lengths
@@ -133,7 +132,7 @@ public sealed partial class LhaStream<TDecoderConfig>
if (3 + skip > numCodes)
{
throw new InvalidDataException("temporary codelen table has invalid size");
throw new Exception("temporary codelen table has invalid size");
}
for (int i = 3 + skip; i < numCodes; i++)
@@ -162,7 +161,7 @@ public sealed partial class LhaStream<TDecoderConfig>
if (numCodes > NUM_COMMANDS)
{
throw new InvalidDataException("commands codelen table has invalid size");
throw new Exception("commands codelen table has invalid size");
}
int index = 0;

View File

@@ -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<TDecoderConfig> : Stream
where TDecoderConfig : ILhaDecoderConfig, new()
public sealed partial class LhaStream<C> : Stream
where C : 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 TDecoderConfig _config = new TDecoderConfig();
private readonly C _config = new C();
private const int NUM_COMMANDS = 510;
private const int NUM_TEMP_CODELEN = 20;
@@ -27,6 +27,7 @@ public sealed partial class LhaStream<TDecoderConfig> : 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);
@@ -63,7 +64,7 @@ public sealed partial class LhaStream<TDecoderConfig> : Stream
}
if (offset < 0 || count < 0 || (offset + count) > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
throw new ArgumentOutOfRangeException();
}
if (_producedBytes >= _originalSize)
@@ -136,7 +137,7 @@ public sealed partial class LhaStream<TDecoderConfig> : Stream
if (numCodes > NUM_TEMP_CODELEN)
{
throw new InvalidDataException("temporary codelen table has invalid size");
throw new Exception("temporary codelen table has invalid size");
}
// read actual lengths
@@ -151,7 +152,7 @@ public sealed partial class LhaStream<TDecoderConfig> : Stream
if (3 + skip > numCodes)
{
throw new InvalidDataException("temporary codelen table has invalid size");
throw new Exception("temporary codelen table has invalid size");
}
for (int i = 3 + skip; i < numCodes; i++)
@@ -179,7 +180,7 @@ public sealed partial class LhaStream<TDecoderConfig> : Stream
if (numCodes > NUM_COMMANDS)
{
throw new InvalidDataException("commands codelen table has invalid size");
throw new Exception("commands codelen table has invalid size");
}
int index = 0;

View File

@@ -1,6 +1,8 @@
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.Compressors.BZip2;
@@ -52,7 +54,6 @@ public sealed partial class BZip2Stream : Stream
{
if (isDisposed || leaveOpen)
{
base.Dispose(disposing);
return;
}
isDisposed = true;
@@ -60,7 +61,6 @@ public sealed partial class BZip2Stream : Stream
{
stream.Dispose();
}
base.Dispose(disposing);
}
public CompressionMode Mode { get; private set; }

View File

@@ -447,7 +447,6 @@ internal sealed class CBZip2OutputStream : Stream
{
if (disposed)
{
base.Dispose(disposing);
return;
}
@@ -461,7 +460,6 @@ internal sealed class CBZip2OutputStream : Stream
}
bsStream = null;
}
base.Dispose(disposing);
}
public void Finish()

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common.Zip.Headers;
@@ -279,7 +278,7 @@ public partial class ExplodeStream
if (literalResult.returnCode != 0)
{
throw new InvalidDataException("Error decoding literal value");
throw new Exception("Error decoding literal value");
}
huftPointer = literalResult.huftPointer;
@@ -319,7 +318,7 @@ public partial class ExplodeStream
if (distanceResult.returnCode != 0)
{
throw new InvalidDataException("Error decoding distance high bits");
throw new Exception("Error decoding distance high bits");
}
huftPointer = distanceResult.huftPointer;
@@ -335,7 +334,7 @@ public partial class ExplodeStream
if (lengthResult.returnCode != 0)
{
throw new InvalidDataException("Error decoding coded length");
throw new Exception("Error decoding coded length");
}
huftPointer = lengthResult.huftPointer;

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.IO.Compression;
using SharpCompress.Common.Zip.Headers;
namespace SharpCompress.Compressors.Explode;
@@ -697,7 +696,7 @@ public partial class ExplodeStream : Stream
) != 0
)
{
throw new InvalidDataException("Error decoding literal value");
throw new Exception("Error decoding literal value");
}
nextByte = (byte)huftPointer.Value;
@@ -736,7 +735,7 @@ public partial class ExplodeStream : Stream
) != 0
)
{
throw new InvalidDataException("Error decoding distance high bits");
throw new Exception("Error decoding distance high bits");
}
distance = windowIndex - (distance + huftPointer.Value); /* construct offset */
@@ -752,7 +751,7 @@ public partial class ExplodeStream : Stream
) != 0
)
{
throw new InvalidDataException("Error decoding coded length");
throw new Exception("Error decoding coded length");
}
length = huftPointer.Value;

View File

@@ -18,9 +18,9 @@ public sealed class BranchExecFilter
ARCH_x86_ALIGNMENT = 1,
ARCH_PowerPC_ALIGNMENT = 4,
ARCH_IA64_ALIGNMENT = 16,
ARCH_ARM_ALIGNMENT = ARCH_PowerPC_ALIGNMENT,
ARCH_ARM_ALIGNMENT = 4,
ARCH_ARMTHUMB_ALIGNMENT = 2,
ARCH_SPARC_ALIGNMENT = ARCH_PowerPC_ALIGNMENT,
ARCH_SPARC_ALIGNMENT = 4,
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -4,6 +4,7 @@ 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;

View File

@@ -99,7 +99,6 @@ public sealed partial class LZipStream : Stream
{
if (_disposed)
{
base.Dispose(disposing);
return;
}
_disposed = true;
@@ -112,7 +111,6 @@ public sealed partial class LZipStream : Stream
_originalStream?.Dispose();
}
}
base.Dispose(disposing);
}
public CompressionMode Mode { get; }

View File

@@ -281,6 +281,9 @@ 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[
@@ -1229,6 +1232,12 @@ 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)

View File

@@ -559,7 +559,6 @@ public partial class LzwStream : Stream
baseInputStream.Dispose();
}
}
base.Dispose(disposing);
}
#endregion Stream Overrides

View File

@@ -21,7 +21,7 @@ public partial class RunLength90Stream
if (offset < 0 || count < 0 || offset + count > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
throw new ArgumentOutOfRangeException();
}
int bytesWritten = 0;

View File

@@ -60,7 +60,7 @@ public partial class RunLength90Stream : Stream
if (offset < 0 || count < 0 || offset + count > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
throw new ArgumentOutOfRangeException();
}
int bytesWritten = 0;

View File

@@ -54,6 +54,7 @@ internal partial class RarBLAKE2spStream : RarStream
internal byte[] b;
internal int bufferPosition;
internal UInt32 lastNodeFlag;
UInt32[] dummy;
public BLAKE2S()
{
@@ -61,6 +62,7 @@ internal partial class RarBLAKE2spStream : RarStream
t = new uint[2];
f = new uint[2];
b = new byte[BLAKE2S_BLOCK_SIZE];
dummy = new uint[2];
}
};

View File

@@ -0,0 +1,603 @@
using System;
using System.Buffers;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.Compressors.Rar.UnpackV1.Decode;
using SharpCompress.Compressors.Rar.UnpackV1.PPM;
using SharpCompress.Compressors.Rar.VM;
namespace SharpCompress.Compressors.Rar.UnpackV1;
internal sealed partial class Unpack
{
public async Task DoUnpackAsync(
FileHeader fileHeader,
Stream readStream,
Stream writeStream,
CancellationToken cancellationToken = default
)
{
destUnpSize = fileHeader.UncompressedSize;
this.fileHeader = fileHeader;
this.readStream = readStream;
this.writeStream = writeStream;
if (!fileHeader.IsSolid)
{
Init();
}
suspended = false;
await DoUnpackAsync(cancellationToken).ConfigureAwait(false);
}
public async Task DoUnpackAsync(CancellationToken cancellationToken = default)
{
if (fileHeader.CompressionMethod == 0)
{
await UnstoreFileAsync(cancellationToken).ConfigureAwait(false);
return;
}
switch (fileHeader.CompressionAlgorithm)
{
case 15:
await unpack15Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
break;
case 20:
case 26:
await unpack20Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
break;
case 29:
case 36:
await Unpack29Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
break;
case 50:
await Unpack5Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
break;
default:
throw new InvalidFormatException(
"unknown rar compression version " + fileHeader.CompressionAlgorithm
);
}
}
private async Task UnstoreFileAsync(CancellationToken cancellationToken = default)
{
var buffer = new byte[(int)Math.Min(0x10000, destUnpSize)];
do
{
var code = await readStream
.ReadAsync(buffer, 0, buffer.Length, cancellationToken)
.ConfigureAwait(false);
if (code == 0 || code == -1)
{
break;
}
code = code < destUnpSize ? code : (int)destUnpSize;
await writeStream.WriteAsync(buffer, 0, code, cancellationToken).ConfigureAwait(false);
destUnpSize -= code;
} while (!suspended && destUnpSize > 0);
}
private async Task Unpack29Async(bool solid, CancellationToken cancellationToken = default)
{
int[] DDecode = new int[PackDef.DC];
byte[] DBits = new byte[PackDef.DC];
int Bits;
if (DDecode[1] == 0)
{
int Dist = 0,
BitLength = 0,
Slot = 0;
for (var I = 0; I < DBitLengthCounts.Length; I++, BitLength++)
{
var count = DBitLengthCounts[I];
for (var J = 0; J < count; J++, Slot++, Dist += (1 << BitLength))
{
DDecode[Slot] = Dist;
DBits[Slot] = (byte)BitLength;
}
}
}
FileExtracted = true;
if (!suspended)
{
UnpInitData(solid);
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return;
}
if ((!solid || !tablesRead) && !ReadTables())
{
return;
}
}
if (ppmError)
{
return;
}
while (true)
{
unpPtr &= PackDef.MAXWINMASK;
if (inAddr > readBorder)
{
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
break;
}
}
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 260 && wrPtr != unpPtr)
{
UnpWriteBuf();
if (destUnpSize < 0)
{
return;
}
if (suspended)
{
FileExtracted = false;
return;
}
}
if (unpBlockType == BlockTypes.BLOCK_PPM)
{
var Ch = ppm.DecodeChar();
if (Ch == -1)
{
ppmError = true;
break;
}
if (Ch == PpmEscChar)
{
var NextCh = ppm.DecodeChar();
if (NextCh == 0)
{
if (!ReadTables())
{
break;
}
continue;
}
if (NextCh == 2 || NextCh == -1)
{
break;
}
if (NextCh == 3)
{
if (!ReadVMCodePPM())
{
break;
}
continue;
}
if (NextCh == 4)
{
int Distance = 0,
Length = 0;
var failed = false;
for (var I = 0; I < 4 && !failed; I++)
{
var ch = ppm.DecodeChar();
if (ch == -1)
{
failed = true;
}
else
{
if (I == 3)
{
Length = ch & 0xff;
}
else
{
Distance = (Distance << 8) + (ch & 0xff);
}
}
}
if (failed)
{
break;
}
CopyString(Length + 32, Distance + 2);
continue;
}
if (NextCh == 5)
{
var Length = ppm.DecodeChar();
if (Length == -1)
{
break;
}
CopyString(Length + 4, 1);
continue;
}
}
window[unpPtr++] = (byte)Ch;
continue;
}
var Number = this.decodeNumber(LD);
if (Number < 256)
{
window[unpPtr++] = (byte)Number;
continue;
}
if (Number >= 271)
{
var Length = LDecode[Number -= 271] + 3;
if ((Bits = LBits[Number]) > 0)
{
Length += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
var DistNumber = this.decodeNumber(DD);
var Distance = DDecode[DistNumber] + 1;
if ((Bits = DBits[DistNumber]) > 0)
{
if (DistNumber > 9)
{
if (Bits > 4)
{
Distance += ((Utility.URShift(GetBits(), (20 - Bits))) << 4);
AddBits(Bits - 4);
}
if (lowDistRepCount > 0)
{
lowDistRepCount--;
Distance += prevLowDist;
}
else
{
var LowDist = this.decodeNumber(LDD);
if (LowDist == 16)
{
lowDistRepCount = PackDef.LOW_DIST_REP_COUNT - 1;
Distance += prevLowDist;
}
else
{
Distance += LowDist;
prevLowDist = LowDist;
}
}
}
else
{
Distance += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
}
if (Distance >= 0x2000)
{
Length++;
if (Distance >= 0x40000L)
{
Length++;
}
}
InsertOldDist(Distance);
InsertLastMatch(Length, Distance);
CopyString(Length, Distance);
continue;
}
if (Number == 256)
{
if (!ReadEndOfBlock())
{
break;
}
continue;
}
if (Number == 257)
{
if (!ReadVMCode())
{
break;
}
continue;
}
if (Number == 258)
{
if (lastLength != 0)
{
CopyString(lastLength, lastDist);
}
continue;
}
if (Number < 263)
{
var DistNum = Number - 259;
var Distance = oldDist[DistNum];
for (var I = DistNum; I > 0; I--)
{
oldDist[I] = oldDist[I - 1];
}
oldDist[0] = Distance;
var LengthNumber = this.decodeNumber(RD);
var Length = LDecode[LengthNumber] + 2;
if ((Bits = LBits[LengthNumber]) > 0)
{
Length += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
InsertLastMatch(Length, Distance);
CopyString(Length, Distance);
continue;
}
if (Number < 272)
{
var Distance = SDDecode[Number -= 263] + 1;
if ((Bits = SDBits[Number]) > 0)
{
Distance += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
InsertOldDist(Distance);
InsertLastMatch(2, Distance);
CopyString(2, Distance);
}
}
UnpWriteBuf();
}
private async Task UnpWriteBufAsync(CancellationToken cancellationToken = default)
{
var WrittenBorder = wrPtr;
var WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK;
for (var I = 0; I < prgStack.Count; I++)
{
var flt = prgStack[I];
if (flt is null)
{
continue;
}
if (flt.NextWindow)
{
flt.NextWindow = false;
continue;
}
var BlockStart = flt.BlockStart;
var BlockLength = flt.BlockLength;
if (((BlockStart - WrittenBorder) & PackDef.MAXWINMASK) < WriteSize)
{
if (WrittenBorder != BlockStart)
{
await UnpWriteAreaAsync(WrittenBorder, BlockStart, cancellationToken)
.ConfigureAwait(false);
WrittenBorder = BlockStart;
WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK;
}
if (BlockLength <= WriteSize)
{
var BlockEnd = (BlockStart + BlockLength) & PackDef.MAXWINMASK;
if (BlockStart < BlockEnd || BlockEnd == 0)
{
rarVM.setMemory(0, window, BlockStart, BlockLength);
}
else
{
var FirstPartLength = PackDef.MAXWINSIZE - BlockStart;
rarVM.setMemory(0, window, BlockStart, FirstPartLength);
rarVM.setMemory(FirstPartLength, window, 0, BlockEnd);
}
var ParentPrg = filters[flt.ParentFilter].Program;
var Prg = flt.Program;
if (ParentPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
{
Prg.GlobalData.Clear();
for (
var i = 0;
i < ParentPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE;
i++
)
{
Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = ParentPrg.GlobalData[
RarVM.VM_FIXEDGLOBALSIZE + i
];
}
}
ExecuteCode(Prg);
if (Prg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
{
if (ParentPrg.GlobalData.Count < Prg.GlobalData.Count)
{
ParentPrg.GlobalData.SetSize(Prg.GlobalData.Count);
}
for (var i = 0; i < Prg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++)
{
ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = Prg.GlobalData[
RarVM.VM_FIXEDGLOBALSIZE + i
];
}
}
else
{
ParentPrg.GlobalData.Clear();
}
var FilteredDataOffset = Prg.FilteredDataOffset;
var FilteredDataSize = Prg.FilteredDataSize;
var FilteredData = ArrayPool<byte>.Shared.Rent(FilteredDataSize);
try
{
Array.Copy(
rarVM.Mem,
FilteredDataOffset,
FilteredData,
0,
FilteredDataSize
);
prgStack[I] = null;
while (I + 1 < prgStack.Count)
{
var NextFilter = prgStack[I + 1];
if (
NextFilter is null
|| NextFilter.BlockStart != BlockStart
|| NextFilter.BlockLength != FilteredDataSize
|| NextFilter.NextWindow
)
{
break;
}
rarVM.setMemory(0, FilteredData, 0, FilteredDataSize);
var pPrg = filters[NextFilter.ParentFilter].Program;
var NextPrg = NextFilter.Program;
if (pPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
{
NextPrg.GlobalData.SetSize(pPrg.GlobalData.Count);
for (
var i = 0;
i < pPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE;
i++
)
{
NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] =
pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i];
}
}
ExecuteCode(NextPrg);
if (NextPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
{
if (pPrg.GlobalData.Count < NextPrg.GlobalData.Count)
{
pPrg.GlobalData.SetSize(NextPrg.GlobalData.Count);
}
for (
var i = 0;
i < NextPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE;
i++
)
{
pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] =
NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i];
}
}
else
{
pPrg.GlobalData.Clear();
}
FilteredDataOffset = NextPrg.FilteredDataOffset;
FilteredDataSize = NextPrg.FilteredDataSize;
if (FilteredData.Length < FilteredDataSize)
{
ArrayPool<byte>.Shared.Return(FilteredData);
FilteredData = ArrayPool<byte>.Shared.Rent(FilteredDataSize);
}
for (var i = 0; i < FilteredDataSize; i++)
{
FilteredData[i] = NextPrg.GlobalData[FilteredDataOffset + i];
}
I++;
prgStack[I] = null;
}
await writeStream
.WriteAsync(FilteredData, 0, FilteredDataSize, cancellationToken)
.ConfigureAwait(false);
writtenFileSize += FilteredDataSize;
destUnpSize -= FilteredDataSize;
WrittenBorder = BlockEnd;
WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK;
}
finally
{
ArrayPool<byte>.Shared.Return(FilteredData);
}
}
else
{
for (var J = I; J < prgStack.Count; J++)
{
var filt = prgStack[J];
if (filt != null && filt.NextWindow)
{
filt.NextWindow = false;
}
}
wrPtr = WrittenBorder;
return;
}
}
}
await UnpWriteAreaAsync(WrittenBorder, unpPtr, cancellationToken).ConfigureAwait(false);
wrPtr = unpPtr;
}
private async Task UnpWriteAreaAsync(
int startPtr,
int endPtr,
CancellationToken cancellationToken = default
)
{
if (endPtr < startPtr)
{
await UnpWriteDataAsync(
window,
startPtr,
-startPtr & PackDef.MAXWINMASK,
cancellationToken
)
.ConfigureAwait(false);
await UnpWriteDataAsync(window, 0, endPtr, cancellationToken).ConfigureAwait(false);
}
else
{
await UnpWriteDataAsync(window, startPtr, endPtr - startPtr, cancellationToken)
.ConfigureAwait(false);
}
}
private async Task UnpWriteDataAsync(
byte[] data,
int offset,
int size,
CancellationToken cancellationToken = default
)
{
if (destUnpSize < 0)
{
return;
}
var writeSize = size;
if (writeSize > destUnpSize)
{
writeSize = (int)destUnpSize;
}
await writeStream
.WriteAsync(data, offset, writeSize, cancellationToken)
.ConfigureAwait(false);
writtenFileSize += size;
destUnpSize -= size;
}
}

View File

@@ -150,25 +150,6 @@ internal sealed partial class Unpack : BitInput, IRarUnpack
DoUnpack();
}
public async System.Threading.Tasks.Task DoUnpackAsync(
FileHeader fileHeader,
Stream readStream,
Stream writeStream,
System.Threading.CancellationToken cancellationToken = default
)
{
destUnpSize = fileHeader.UncompressedSize;
this.fileHeader = fileHeader;
this.readStream = readStream;
this.writeStream = writeStream;
if (!fileHeader.IsSolid)
{
Init();
}
suspended = false;
await DoUnpackAsync(cancellationToken).ConfigureAwait(false);
}
public void DoUnpack()
{
if (fileHeader.CompressionMethod == 0)
@@ -203,42 +184,6 @@ internal sealed partial class Unpack : BitInput, IRarUnpack
}
}
public async System.Threading.Tasks.Task DoUnpackAsync(
System.Threading.CancellationToken cancellationToken = default
)
{
if (fileHeader.CompressionMethod == 0)
{
await UnstoreFileAsync(cancellationToken).ConfigureAwait(false);
return;
}
switch (fileHeader.CompressionAlgorithm)
{
case 15: // rar 1.5 compression
await unpack15Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
break;
case 20: // rar 2.x compression
case 26: // files larger than 2GB
await unpack20Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
break;
case 29: // rar 3.x compression
case 36: // alternative hash
await Unpack29Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
break;
case 50: // rar 5.x compression
await Unpack5Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
break;
default:
throw new InvalidFormatException(
"unknown rar compression version " + fileHeader.CompressionAlgorithm
);
}
}
private void UnstoreFile()
{
Span<byte> buffer = stackalloc byte[(int)Math.Min(0x10000, destUnpSize)];
@@ -255,26 +200,6 @@ internal sealed partial class Unpack : BitInput, IRarUnpack
} while (!suspended && destUnpSize > 0);
}
private async System.Threading.Tasks.Task UnstoreFileAsync(
System.Threading.CancellationToken cancellationToken = default
)
{
var buffer = new byte[(int)Math.Min(0x10000, destUnpSize)];
do
{
var code = await readStream
.ReadAsync(buffer, 0, buffer.Length, cancellationToken)
.ConfigureAwait(false);
if (code == 0 || code == -1)
{
break;
}
code = code < destUnpSize ? code : (int)destUnpSize;
await writeStream.WriteAsync(buffer, 0, code, cancellationToken).ConfigureAwait(false);
destUnpSize -= code;
} while (!suspended && destUnpSize > 0);
}
private void Unpack29(bool solid)
{
Span<int> DDecode = stackalloc int[PackDef.DC];
@@ -553,281 +478,6 @@ internal sealed partial class Unpack : BitInput, IRarUnpack
UnpWriteBuf();
}
private async System.Threading.Tasks.Task Unpack29Async(
bool solid,
System.Threading.CancellationToken cancellationToken = default
)
{
int[] DDecode = new int[PackDef.DC];
byte[] DBits = new byte[PackDef.DC];
int Bits;
if (DDecode[1] == 0)
{
int Dist = 0,
BitLength = 0,
Slot = 0;
for (var I = 0; I < DBitLengthCounts.Length; I++, BitLength++)
{
var count = DBitLengthCounts[I];
for (var J = 0; J < count; J++, Slot++, Dist += (1 << BitLength))
{
DDecode[Slot] = Dist;
DBits[Slot] = (byte)BitLength;
}
}
}
FileExtracted = true;
if (!suspended)
{
UnpInitData(solid);
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return;
}
if ((!solid || !tablesRead) && !ReadTables())
{
return;
}
}
if (ppmError)
{
return;
}
while (true)
{
unpPtr &= PackDef.MAXWINMASK;
if (inAddr > readBorder)
{
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
break;
}
}
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 260 && wrPtr != unpPtr)
{
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
if (destUnpSize < 0)
{
return;
}
if (suspended)
{
FileExtracted = false;
return;
}
}
if (unpBlockType == BlockTypes.BLOCK_PPM)
{
var ch = ppm.DecodeChar();
if (ch == -1)
{
ppmError = true;
break;
}
if (ch == PpmEscChar)
{
var nextCh = ppm.DecodeChar();
if (nextCh == 0)
{
if (!ReadTables())
{
break;
}
continue;
}
if (nextCh == 2 || nextCh == -1)
{
break;
}
if (nextCh == 3)
{
if (!ReadVMCode())
{
break;
}
continue;
}
if (nextCh == 4)
{
uint Distance = 0,
Length = 0;
var failed = false;
for (var I = 0; I < 4 && !failed; I++)
{
var ch2 = ppm.DecodeChar();
if (ch2 == -1)
{
failed = true;
}
else if (I == 3)
{
Length = (uint)ch2;
}
else
{
Distance = (Distance << 8) + (uint)ch2;
}
}
if (failed)
{
break;
}
CopyString(Length + 32, Distance + 2);
continue;
}
if (nextCh == 5)
{
var length = ppm.DecodeChar();
if (length == -1)
{
break;
}
CopyString((uint)(length + 4), 1);
continue;
}
}
window[unpPtr++] = (byte)ch;
continue;
}
var Number = this.decodeNumber(LD);
if (Number < 256)
{
window[unpPtr++] = (byte)Number;
continue;
}
if (Number >= 271)
{
var Length = LDecode[Number -= 271] + 3;
if ((Bits = LBits[Number]) > 0)
{
Length += GetBits() >> (16 - Bits);
AddBits(Bits);
}
var DistNumber = this.decodeNumber(DD);
var Distance = DDecode[DistNumber] + 1;
if ((Bits = DBits[DistNumber]) > 0)
{
if (DistNumber > 9)
{
if (Bits > 4)
{
Distance += (GetBits() >> (20 - Bits)) << 4;
AddBits(Bits - 4);
}
if (lowDistRepCount > 0)
{
lowDistRepCount--;
Distance += prevLowDist;
}
else
{
var LowDist = this.decodeNumber(LDD);
if (LowDist == 16)
{
lowDistRepCount = PackDef.LOW_DIST_REP_COUNT - 1;
Distance += prevLowDist;
}
else
{
Distance += LowDist;
prevLowDist = (int)LowDist;
}
}
}
else
{
Distance += GetBits() >> (16 - Bits);
AddBits(Bits);
}
}
if (Distance >= 0x2000)
{
Length++;
if (Distance >= 0x40000)
{
Length++;
}
}
InsertOldDist(Distance);
lastLength = Length;
CopyString(Length, Distance);
continue;
}
if (Number == 256)
{
if (!ReadEndOfBlock())
{
break;
}
continue;
}
if (Number == 257)
{
if (!ReadVMCode())
{
break;
}
continue;
}
if (Number == 258)
{
if (lastLength != 0)
{
CopyString(lastLength, oldDist[0]);
}
continue;
}
if (Number < 263)
{
var DistNum = Number - 259;
var Distance = (uint)oldDist[DistNum];
for (var I = DistNum; I > 0; I--)
{
oldDist[I] = oldDist[I - 1];
}
oldDist[0] = (int)Distance;
var LengthNumber = this.decodeNumber(RD);
var Length = LDecode[LengthNumber] + 2;
if ((Bits = LBits[LengthNumber]) > 0)
{
Length += GetBits() >> (16 - Bits);
AddBits(Bits);
}
lastLength = Length;
CopyString((uint)Length, Distance);
continue;
}
if (Number < 272)
{
var Distance = SDDecode[Number -= 263] + 1;
if ((Bits = SDBits[Number]) > 0)
{
Distance += GetBits() >> (16 - Bits);
AddBits(Bits);
}
InsertOldDist((uint)Distance);
lastLength = 2;
CopyString(2, (uint)Distance);
}
}
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
}
private void UnpWriteBuf()
{
var WrittenBorder = wrPtr;
@@ -1684,256 +1334,6 @@ internal sealed partial class Unpack : BitInput, IRarUnpack
}
}
private async System.Threading.Tasks.Task UnpWriteBufAsync(
System.Threading.CancellationToken cancellationToken = default
)
{
var WrittenBorder = wrPtr;
var WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK;
for (var I = 0; I < prgStack.Count; I++)
{
var flt = prgStack[I];
if (flt is null)
{
continue;
}
if (flt.NextWindow)
{
flt.NextWindow = false;
continue;
}
var BlockStart = flt.BlockStart;
var BlockLength = flt.BlockLength;
if (((BlockStart - WrittenBorder) & PackDef.MAXWINMASK) < WriteSize)
{
if (WrittenBorder != BlockStart)
{
await UnpWriteAreaAsync(WrittenBorder, BlockStart, cancellationToken)
.ConfigureAwait(false);
WrittenBorder = BlockStart;
WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK;
}
if (BlockLength <= WriteSize)
{
var BlockEnd = (BlockStart + BlockLength) & PackDef.MAXWINMASK;
if (BlockStart < BlockEnd || BlockEnd == 0)
{
rarVM.setMemory(0, window, BlockStart, BlockLength);
}
else
{
var FirstPartLength = PackDef.MAXWINSIZE - BlockStart;
rarVM.setMemory(0, window, BlockStart, FirstPartLength);
rarVM.setMemory(FirstPartLength, window, 0, BlockEnd);
}
var ParentPrg = filters[flt.ParentFilter].Program;
var Prg = flt.Program;
if (ParentPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
{
Prg.GlobalData.Clear();
for (
var i = 0;
i < ParentPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE;
i++
)
{
Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = ParentPrg.GlobalData[
RarVM.VM_FIXEDGLOBALSIZE + i
];
}
}
ExecuteCode(Prg);
if (Prg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
{
if (ParentPrg.GlobalData.Count < Prg.GlobalData.Count)
{
ParentPrg.GlobalData.SetSize(Prg.GlobalData.Count);
}
for (var i = 0; i < Prg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++)
{
ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = Prg.GlobalData[
RarVM.VM_FIXEDGLOBALSIZE + i
];
}
}
else
{
ParentPrg.GlobalData.Clear();
}
var FilteredDataOffset = Prg.FilteredDataOffset;
var FilteredDataSize = Prg.FilteredDataSize;
var FilteredData = ArrayPool<byte>.Shared.Rent(FilteredDataSize);
try
{
Array.Copy(
rarVM.Mem,
FilteredDataOffset,
FilteredData,
0,
FilteredDataSize
);
prgStack[I] = null;
while (I + 1 < prgStack.Count)
{
var NextFilter = prgStack[I + 1];
if (
NextFilter is null
|| NextFilter.BlockStart != BlockStart
|| NextFilter.BlockLength != FilteredDataSize
|| NextFilter.NextWindow
)
{
break;
}
rarVM.setMemory(0, FilteredData, 0, FilteredDataSize);
var pPrg = filters[NextFilter.ParentFilter].Program;
var NextPrg = NextFilter.Program;
if (pPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
{
NextPrg.GlobalData.SetSize(pPrg.GlobalData.Count);
for (
var i = 0;
i < pPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE;
i++
)
{
NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] =
pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i];
}
}
ExecuteCode(NextPrg);
if (NextPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
{
if (pPrg.GlobalData.Count < NextPrg.GlobalData.Count)
{
pPrg.GlobalData.SetSize(NextPrg.GlobalData.Count);
}
for (
var i = 0;
i < NextPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE;
i++
)
{
pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] =
NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i];
}
}
else
{
pPrg.GlobalData.Clear();
}
FilteredDataOffset = NextPrg.FilteredDataOffset;
FilteredDataSize = NextPrg.FilteredDataSize;
if (FilteredData.Length < FilteredDataSize)
{
ArrayPool<byte>.Shared.Return(FilteredData);
FilteredData = ArrayPool<byte>.Shared.Rent(FilteredDataSize);
}
for (var i = 0; i < FilteredDataSize; i++)
{
FilteredData[i] = NextPrg.GlobalData[FilteredDataOffset + i];
}
I++;
prgStack[I] = null;
}
await writeStream
.WriteAsync(FilteredData, 0, FilteredDataSize, cancellationToken)
.ConfigureAwait(false);
writtenFileSize += FilteredDataSize;
destUnpSize -= FilteredDataSize;
WrittenBorder = BlockEnd;
WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK;
}
finally
{
ArrayPool<byte>.Shared.Return(FilteredData);
}
}
else
{
for (var J = I; J < prgStack.Count; J++)
{
var filt = prgStack[J];
if (filt != null && filt.NextWindow)
{
filt.NextWindow = false;
}
}
wrPtr = WrittenBorder;
return;
}
}
}
await UnpWriteAreaAsync(WrittenBorder, unpPtr, cancellationToken).ConfigureAwait(false);
wrPtr = unpPtr;
}
private async System.Threading.Tasks.Task UnpWriteAreaAsync(
int startPtr,
int endPtr,
System.Threading.CancellationToken cancellationToken = default
)
{
if (endPtr < startPtr)
{
await UnpWriteDataAsync(
window,
startPtr,
-startPtr & PackDef.MAXWINMASK,
cancellationToken
)
.ConfigureAwait(false);
await UnpWriteDataAsync(window, 0, endPtr, cancellationToken).ConfigureAwait(false);
}
else
{
await UnpWriteDataAsync(window, startPtr, endPtr - startPtr, cancellationToken)
.ConfigureAwait(false);
}
}
private async System.Threading.Tasks.Task UnpWriteDataAsync(
byte[] data,
int offset,
int size,
System.Threading.CancellationToken cancellationToken = default
)
{
if (destUnpSize < 0)
{
return;
}
var writeSize = size;
if (writeSize > destUnpSize)
{
writeSize = (int)destUnpSize;
}
await writeStream
.WriteAsync(data, offset, writeSize, cancellationToken)
.ConfigureAwait(false);
writtenFileSize += size;
destUnpSize -= size;
}
private void CleanUp()
{
if (ppm != null)

View File

@@ -0,0 +1,162 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Compressors.Rar.UnpackV1.Decode;
namespace SharpCompress.Compressors.Rar.UnpackV1;
internal partial class Unpack
{
private async Task unpack15Async(bool solid, CancellationToken cancellationToken = default)
{
if (suspended)
{
unpPtr = wrPtr;
}
else
{
UnpInitData(solid);
oldUnpInitData(solid);
await unpReadBufAsync(cancellationToken).ConfigureAwait(false);
if (!solid)
{
initHuff();
unpPtr = 0;
}
else
{
unpPtr = wrPtr;
}
--destUnpSize;
}
if (destUnpSize >= 0)
{
getFlagsBuf();
FlagsCnt = 8;
}
while (destUnpSize >= 0)
{
unpPtr &= PackDef.MAXWINMASK;
if (
inAddr > readTop - 30
&& !await unpReadBufAsync(cancellationToken).ConfigureAwait(false)
)
{
break;
}
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr)
{
oldUnpWriteBuf();
if (suspended)
{
return;
}
}
if (StMode != 0)
{
huffDecode();
continue;
}
if (--FlagsCnt < 0)
{
getFlagsBuf();
FlagsCnt = 7;
}
if ((FlagBuf & 0x80) != 0)
{
FlagBuf <<= 1;
if (Nlzb > Nhfb)
{
longLZ();
}
else
{
huffDecode();
}
}
else
{
FlagBuf <<= 1;
if (--FlagsCnt < 0)
{
getFlagsBuf();
FlagsCnt = 7;
}
if ((FlagBuf & 0x80) != 0)
{
FlagBuf <<= 1;
if (Nlzb > Nhfb)
{
huffDecode();
}
else
{
longLZ();
}
}
else
{
FlagBuf <<= 1;
shortLZ();
}
}
}
oldUnpWriteBuf();
}
private async Task<bool> unpReadBufAsync(CancellationToken cancellationToken = default)
{
var dataSize = readTop - inAddr;
if (dataSize < 0)
{
return false;
}
if (inAddr > MAX_SIZE / 2)
{
if (dataSize > 0)
{
Array.Copy(InBuf, inAddr, InBuf, 0, dataSize);
}
inAddr = 0;
readTop = dataSize;
}
else
{
dataSize = readTop;
}
var readCode = await readStream
.ReadAsync(InBuf, dataSize, (MAX_SIZE - dataSize) & ~0xf, cancellationToken)
.ConfigureAwait(false);
if (readCode > 0)
{
readTop += readCode;
}
readBorder = readTop - 30;
return readCode != -1;
}
private async Task oldUnpWriteBufAsync(CancellationToken cancellationToken = default)
{
if (unpPtr < wrPtr)
{
await writeStream
.WriteAsync(window, wrPtr, -wrPtr & PackDef.MAXWINMASK, cancellationToken)
.ConfigureAwait(false);
await writeStream
.WriteAsync(window, 0, unpPtr, cancellationToken)
.ConfigureAwait(false);
}
else
{
await writeStream
.WriteAsync(window, wrPtr, unpPtr - wrPtr, cancellationToken)
.ConfigureAwait(false);
}
wrPtr = unpPtr;
}
}

View File

@@ -316,110 +316,6 @@ internal partial class Unpack
oldUnpWriteBuf();
}
private async System.Threading.Tasks.Task unpack15Async(
bool solid,
System.Threading.CancellationToken cancellationToken = default
)
{
if (suspended)
{
unpPtr = wrPtr;
}
else
{
UnpInitData(solid);
oldUnpInitData(solid);
await unpReadBufAsync(cancellationToken).ConfigureAwait(false);
if (!solid)
{
initHuff();
unpPtr = 0;
}
else
{
unpPtr = wrPtr;
}
--destUnpSize;
}
if (destUnpSize >= 0)
{
getFlagsBuf();
FlagsCnt = 8;
}
while (destUnpSize >= 0)
{
unpPtr &= PackDef.MAXWINMASK;
if (
inAddr > readTop - 30
&& !await unpReadBufAsync(cancellationToken).ConfigureAwait(false)
)
{
break;
}
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr)
{
await oldUnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
if (suspended)
{
return;
}
}
if (StMode != 0)
{
huffDecode();
continue;
}
if (--FlagsCnt < 0)
{
getFlagsBuf();
FlagsCnt = 7;
}
if ((FlagBuf & 0x80) != 0)
{
FlagBuf <<= 1;
if (Nlzb > Nhfb)
{
longLZ();
}
else
{
huffDecode();
}
}
else
{
FlagBuf <<= 1;
if (--FlagsCnt < 0)
{
getFlagsBuf();
FlagsCnt = 7;
}
if ((FlagBuf & 0x80) != 0)
{
FlagBuf <<= 1;
if (Nlzb > Nhfb)
{
huffDecode();
}
else
{
longLZ();
}
}
else
{
FlagBuf <<= 1;
shortLZ();
}
}
}
await oldUnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
}
private bool unpReadBuf()
{
var dataSize = readTop - inAddr;
@@ -455,40 +351,6 @@ internal partial class Unpack
return (readCode != -1);
}
private async System.Threading.Tasks.Task<bool> unpReadBufAsync(
System.Threading.CancellationToken cancellationToken = default
)
{
var dataSize = readTop - inAddr;
if (dataSize < 0)
{
return (false);
}
if (inAddr > MAX_SIZE / 2)
{
if (dataSize > 0)
{
Array.Copy(InBuf, inAddr, InBuf, 0, dataSize);
}
inAddr = 0;
readTop = dataSize;
}
else
{
dataSize = readTop;
}
var readCode = await readStream
.ReadAsync(InBuf, dataSize, (MAX_SIZE - dataSize) & ~0xf, cancellationToken)
.ConfigureAwait(false);
if (readCode > 0)
{
readTop += readCode;
}
readBorder = readTop - 30;
return (readCode != -1);
}
private int getShortLen1(int pos) => pos == 1 ? Buf60 + 3 : ShortLen1[pos];
private int getShortLen2(int pos) => pos == 3 ? Buf60 + 3 : ShortLen2[pos];
@@ -952,26 +814,4 @@ internal partial class Unpack
}
wrPtr = unpPtr;
}
private async System.Threading.Tasks.Task oldUnpWriteBufAsync(
System.Threading.CancellationToken cancellationToken = default
)
{
if (unpPtr < wrPtr)
{
await writeStream
.WriteAsync(window, wrPtr, -wrPtr & PackDef.MAXWINMASK, cancellationToken)
.ConfigureAwait(false);
await writeStream
.WriteAsync(window, 0, unpPtr, cancellationToken)
.ConfigureAwait(false);
}
else
{
await writeStream
.WriteAsync(window, wrPtr, unpPtr - wrPtr, cancellationToken)
.ConfigureAwait(false);
}
wrPtr = unpPtr;
}
}

View File

@@ -0,0 +1,275 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Compressors.Rar.UnpackV1.Decode;
namespace SharpCompress.Compressors.Rar.UnpackV1;
internal partial class Unpack
{
private async Task unpack20Async(bool solid, CancellationToken cancellationToken = default)
{
int Bits;
if (suspended)
{
unpPtr = wrPtr;
}
else
{
UnpInitData(solid);
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return;
}
if (!solid)
{
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
{
return;
}
}
--destUnpSize;
}
while (destUnpSize >= 0)
{
unpPtr &= PackDef.MAXWINMASK;
if (inAddr > readTop - 30)
{
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
break;
}
}
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr)
{
oldUnpWriteBuf();
if (suspended)
{
return;
}
}
if (UnpAudioBlock != 0)
{
var AudioNumber = this.decodeNumber(MD[UnpCurChannel]);
if (AudioNumber == 256)
{
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
{
break;
}
continue;
}
window[unpPtr++] = DecodeAudio(AudioNumber);
if (++UnpCurChannel == UnpChannels)
{
UnpCurChannel = 0;
}
--destUnpSize;
continue;
}
var Number = this.decodeNumber(LD);
if (Number < 256)
{
window[unpPtr++] = (byte)Number;
--destUnpSize;
continue;
}
if (Number > 269)
{
var Length = LDecode[Number -= 270] + 3;
if ((Bits = LBits[Number]) > 0)
{
Length += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
var DistNumber = this.decodeNumber(DD);
var Distance = DDecode[DistNumber] + 1;
if ((Bits = DBits[DistNumber]) > 0)
{
Distance += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
if (Distance >= 0x2000)
{
Length++;
if (Distance >= 0x40000L)
{
Length++;
}
}
CopyString20(Length, Distance);
continue;
}
if (Number == 269)
{
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
{
break;
}
continue;
}
if (Number == 256)
{
CopyString20(lastLength, lastDist);
continue;
}
if (Number < 261)
{
var Distance = oldDist[(oldDistPtr - (Number - 256)) & 3];
var LengthNumber = this.decodeNumber(RD);
var Length = LDecode[LengthNumber] + 2;
if ((Bits = LBits[LengthNumber]) > 0)
{
Length += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
if (Distance >= 0x101)
{
Length++;
if (Distance >= 0x2000)
{
Length++;
if (Distance >= 0x40000)
{
Length++;
}
}
}
CopyString20(Length, Distance);
continue;
}
if (Number < 270)
{
var Distance = SDDecode[Number -= 261] + 1;
if ((Bits = SDBits[Number]) > 0)
{
Distance += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
CopyString20(2, Distance);
}
}
ReadLastTables();
oldUnpWriteBuf();
}
private async Task<bool> ReadTables20Async(CancellationToken cancellationToken = default)
{
byte[] BitLength = new byte[PackDef.BC20];
byte[] Table = new byte[PackDef.MC20 * 4];
int TableSize,
N,
I;
if (inAddr > readTop - 25)
{
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
var BitField = GetBits();
UnpAudioBlock = (BitField & 0x8000);
if (0 == (BitField & 0x4000))
{
new Span<byte>(UnpOldTable20).Clear();
}
AddBits(2);
if (UnpAudioBlock != 0)
{
UnpChannels = ((Utility.URShift(BitField, 12)) & 3) + 1;
if (UnpCurChannel >= UnpChannels)
{
UnpCurChannel = 0;
}
AddBits(2);
TableSize = PackDef.MC20 * UnpChannels;
}
else
{
TableSize = PackDef.NC20 + PackDef.DC20 + PackDef.RC20;
}
for (I = 0; I < PackDef.BC20; I++)
{
BitLength[I] = (byte)(Utility.URShift(GetBits(), 12));
AddBits(4);
}
UnpackUtility.makeDecodeTables(BitLength, 0, BD, PackDef.BC20);
I = 0;
while (I < TableSize)
{
if (inAddr > readTop - 5)
{
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
var Number = this.decodeNumber(BD);
if (Number < 16)
{
Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xf);
I++;
}
else if (Number == 16)
{
N = (Utility.URShift(GetBits(), 14)) + 3;
AddBits(2);
while (N-- > 0 && I < TableSize)
{
Table[I] = Table[I - 1];
I++;
}
}
else
{
if (Number == 17)
{
N = (Utility.URShift(GetBits(), 13)) + 3;
AddBits(3);
}
else
{
N = (Utility.URShift(GetBits(), 9)) + 11;
AddBits(7);
}
while (N-- > 0 && I < TableSize)
{
Table[I++] = 0;
}
}
}
if (inAddr > readTop)
{
return true;
}
if (UnpAudioBlock != 0)
{
for (I = 0; I < UnpChannels; I++)
{
UnpackUtility.makeDecodeTables(Table, I * PackDef.MC20, MD[I], PackDef.MC20);
}
}
else
{
UnpackUtility.makeDecodeTables(Table, 0, LD, PackDef.NC20);
UnpackUtility.makeDecodeTables(Table, PackDef.NC20, DD, PackDef.DC20);
UnpackUtility.makeDecodeTables(Table, PackDef.NC20 + PackDef.DC20, RD, PackDef.RC20);
}
for (var i = 0; i < UnpOldTable20.Length; i++)
{
UnpOldTable20[i] = Table[i];
}
return true;
}
}

View File

@@ -368,163 +368,6 @@ internal partial class Unpack
oldUnpWriteBuf();
}
private async System.Threading.Tasks.Task unpack20Async(
bool solid,
System.Threading.CancellationToken cancellationToken = default
)
{
int Bits;
if (suspended)
{
unpPtr = wrPtr;
}
else
{
UnpInitData(solid);
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return;
}
if (!solid)
{
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
{
return;
}
}
--destUnpSize;
}
while (destUnpSize >= 0)
{
unpPtr &= PackDef.MAXWINMASK;
if (inAddr > readTop - 30)
{
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
break;
}
}
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr)
{
await oldUnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
if (suspended)
{
return;
}
}
if (UnpAudioBlock != 0)
{
var AudioNumber = this.decodeNumber(MD[UnpCurChannel]);
if (AudioNumber == 256)
{
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
{
break;
}
continue;
}
window[unpPtr++] = DecodeAudio(AudioNumber);
if (++UnpCurChannel == UnpChannels)
{
UnpCurChannel = 0;
}
--destUnpSize;
continue;
}
var Number = this.decodeNumber(LD);
if (Number < 256)
{
window[unpPtr++] = (byte)Number;
--destUnpSize;
continue;
}
if (Number > 269)
{
var Length = LDecode[Number -= 270] + 3;
if ((Bits = LBits[Number]) > 0)
{
Length += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
var DistNumber = this.decodeNumber(DD);
var Distance = DDecode[DistNumber] + 1;
if ((Bits = DBits[DistNumber]) > 0)
{
Distance += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
if (Distance >= 0x2000)
{
Length++;
if (Distance >= 0x40000L)
{
Length++;
}
}
CopyString20(Length, Distance);
continue;
}
if (Number == 269)
{
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
{
break;
}
continue;
}
if (Number == 256)
{
CopyString20(lastLength, lastDist);
continue;
}
if (Number < 261)
{
var Distance = oldDist[(oldDistPtr - (Number - 256)) & 3];
var LengthNumber = this.decodeNumber(RD);
var Length = LDecode[LengthNumber] + 2;
if ((Bits = LBits[LengthNumber]) > 0)
{
Length += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
if (Distance >= 0x101)
{
Length++;
if (Distance >= 0x2000)
{
Length++;
if (Distance >= 0x40000)
{
Length++;
}
}
}
CopyString20(Length, Distance);
continue;
}
if (Number < 270)
{
var Distance = SDDecode[Number -= 261] + 1;
if ((Bits = SDBits[Number]) > 0)
{
Distance += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
CopyString20(2, Distance);
}
}
ReadLastTables();
await oldUnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
}
private void CopyString20(int Length, int Distance)
{
lastDist = oldDist[oldDistPtr++ & 3] = Distance;
@@ -691,120 +534,6 @@ internal partial class Unpack
return (true);
}
private async System.Threading.Tasks.Task<bool> ReadTables20Async(
System.Threading.CancellationToken cancellationToken = default
)
{
byte[] BitLength = new byte[PackDef.BC20];
byte[] Table = new byte[PackDef.MC20 * 4];
int TableSize,
N,
I;
if (inAddr > readTop - 25)
{
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return (false);
}
}
var BitField = GetBits();
UnpAudioBlock = (BitField & 0x8000);
if (0 == (BitField & 0x4000))
{
new Span<byte>(UnpOldTable20).Clear();
}
AddBits(2);
if (UnpAudioBlock != 0)
{
UnpChannels = ((Utility.URShift(BitField, 12)) & 3) + 1;
if (UnpCurChannel >= UnpChannels)
{
UnpCurChannel = 0;
}
AddBits(2);
TableSize = PackDef.MC20 * UnpChannels;
}
else
{
TableSize = PackDef.NC20 + PackDef.DC20 + PackDef.RC20;
}
for (I = 0; I < PackDef.BC20; I++)
{
BitLength[I] = (byte)(Utility.URShift(GetBits(), 12));
AddBits(4);
}
UnpackUtility.makeDecodeTables(BitLength, 0, BD, PackDef.BC20);
I = 0;
while (I < TableSize)
{
if (inAddr > readTop - 5)
{
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return (false);
}
}
var Number = this.decodeNumber(BD);
if (Number < 16)
{
Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xf);
I++;
}
else if (Number == 16)
{
N = (Utility.URShift(GetBits(), 14)) + 3;
AddBits(2);
while (N-- > 0 && I < TableSize)
{
Table[I] = Table[I - 1];
I++;
}
}
else
{
if (Number == 17)
{
N = (Utility.URShift(GetBits(), 13)) + 3;
AddBits(3);
}
else
{
N = (Utility.URShift(GetBits(), 9)) + 11;
AddBits(7);
}
while (N-- > 0 && I < TableSize)
{
Table[I++] = 0;
}
}
}
if (inAddr > readTop)
{
return (true);
}
if (UnpAudioBlock != 0)
{
for (I = 0; I < UnpChannels; I++)
{
UnpackUtility.makeDecodeTables(Table, I * PackDef.MC20, MD[I], PackDef.MC20);
}
}
else
{
UnpackUtility.makeDecodeTables(Table, 0, LD, PackDef.NC20);
UnpackUtility.makeDecodeTables(Table, PackDef.NC20, DD, PackDef.DC20);
UnpackUtility.makeDecodeTables(Table, PackDef.NC20 + PackDef.DC20, RD, PackDef.RC20);
}
for (var i = 0; i < UnpOldTable20.Length; i++)
{
UnpOldTable20[i] = Table[i];
}
return (true);
}
private void unpInitData20(bool Solid)
{
if (!Solid)

View File

@@ -0,0 +1,321 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Compressors.Rar.UnpackV1.Decode;
namespace SharpCompress.Compressors.Rar.UnpackV1;
internal partial class Unpack
{
private async Task<bool> UnpReadBufAsync(CancellationToken cancellationToken = default)
{
var DataSize = ReadTop - Inp.InAddr; // Data left to process.
if (DataSize < 0)
{
return false;
}
BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart;
if (Inp.InAddr > MAX_SIZE / 2)
{
if (DataSize > 0)
{
Array.Copy(InBuf, inAddr, InBuf, 0, DataSize);
}
Inp.InAddr = 0;
ReadTop = DataSize;
}
else
{
DataSize = ReadTop;
}
var ReadCode = 0;
if (MAX_SIZE != DataSize)
{
ReadCode = await readStream
.ReadAsync(InBuf, DataSize, MAX_SIZE - DataSize, cancellationToken)
.ConfigureAwait(false);
}
if (ReadCode > 0) // Can be also -1.
{
ReadTop += ReadCode;
}
ReadBorder = ReadTop - 30;
BlockHeader.BlockStart = Inp.InAddr;
if (BlockHeader.BlockSize != -1) // '-1' means not defined yet.
{
ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1);
}
return ReadCode != -1;
}
public async Task Unpack5Async(bool Solid, CancellationToken cancellationToken = default)
{
FileExtracted = true;
if (!Suspended)
{
UnpInitData(Solid);
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return;
}
// Check TablesRead5 to be sure that we read tables at least once
// regardless of current block header TablePresent flag.
// So we can safefly use these tables below.
if (
!await ReadBlockHeaderAsync(cancellationToken).ConfigureAwait(false)
|| !ReadTables()
|| !TablesRead5
)
{
return;
}
}
while (true)
{
UnpPtr &= MaxWinMask;
if (Inp.InAddr >= ReadBorder)
{
var FileDone = false;
// We use 'while', because for empty block containing only Huffman table,
// we'll be on the block border once again just after reading the table.
while (
Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1
|| Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1
&& Inp.InBit >= BlockHeader.BlockBitSize
)
{
if (BlockHeader.LastBlockInFile)
{
FileDone = true;
break;
}
if (
!await ReadBlockHeaderAsync(cancellationToken).ConfigureAwait(false)
|| !ReadTables()
)
{
return;
}
}
if (FileDone || !await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
break;
}
}
if (
((WriteBorder - UnpPtr) & MaxWinMask) < PackDef.MAX_LZ_MATCH + 3
&& WriteBorder != UnpPtr
)
{
UnpWriteBuf();
if (WrittenFileSize > DestUnpSize)
{
return;
}
if (Suspended)
{
FileExtracted = false;
return;
}
}
var MainSlot = this.DecodeNumber(LD);
if (MainSlot < 256)
{
Window[UnpPtr++] = (byte)MainSlot;
continue;
}
if (MainSlot >= 262)
{
var Length = SlotToLength(MainSlot - 262);
int DBits;
uint Distance = 1,
DistSlot = this.DecodeNumber(DD);
if (DistSlot < 4)
{
DBits = 0;
Distance += DistSlot;
}
else
{
DBits = (int)((DistSlot / 2) - 1);
Distance += (2 | (DistSlot & 1)) << DBits;
}
if (DBits > 0)
{
if (DBits >= 4)
{
if (DBits > 4)
{
Distance += ((Inp.getbits() >> (36 - DBits)) << 4);
Inp.AddBits(DBits - 4);
}
var LowDist = this.DecodeNumber(LDD);
Distance += LowDist;
}
else
{
Distance += Inp.getbits() >> (32 - DBits);
Inp.AddBits(DBits);
}
}
if (Distance > 0x100)
{
Length++;
if (Distance > 0x2000)
{
Length++;
if (Distance > 0x40000)
{
Length++;
}
}
}
InsertOldDist(Distance);
LastLength = Length;
CopyString(Length, Distance);
continue;
}
if (MainSlot == 256)
{
var Filter = new UnpackFilter();
if (
!await ReadFilterAsync(Filter, cancellationToken).ConfigureAwait(false)
|| !AddFilter(Filter)
)
{
break;
}
continue;
}
if (MainSlot == 257)
{
if (LastLength != 0)
{
CopyString(LastLength, OldDistN(0));
}
continue;
}
if (MainSlot < 262)
{
var DistNum = (int)(MainSlot - 258);
var Distance = OldDistN(DistNum);
for (var I = DistNum; I > 0; I--)
{
SetOldDistN(I, OldDistN(I - 1));
}
SetOldDistN(0, Distance);
var LengthSlot = this.DecodeNumber(RD);
var Length = SlotToLength(LengthSlot);
LastLength = Length;
CopyString(Length, Distance);
continue;
}
}
UnpWriteBuf();
}
private async Task<bool> ReadBlockHeaderAsync(CancellationToken cancellationToken = default)
{
Header.HeaderSize = 0;
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
Inp.faddbits((uint)((8 - Inp.InBit) & 7));
var BlockFlags = (byte)(Inp.fgetbits() >> 8);
Inp.faddbits(8);
var ByteCount = (uint)(((BlockFlags >> 3) & 3) + 1);
if (ByteCount == 4)
{
return false;
}
Header.HeaderSize = (int)(2 + ByteCount);
Header.BlockBitSize = (BlockFlags & 7) + 1;
var SavedCheckSum = (byte)(Inp.fgetbits() >> 8);
Inp.faddbits(8);
var BlockSize = 0;
for (var I = 0; I < ByteCount; I++)
{
BlockSize += (int)(Inp.fgetbits() >> 8) << (I * 8);
Inp.AddBits(8);
}
Header.BlockSize = BlockSize;
var CheckSum = (byte)(0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16));
if (CheckSum != SavedCheckSum)
{
return false;
}
Header.BlockStart = Inp.InAddr;
ReadBorder = Math.Min(ReadBorder, Header.BlockStart + Header.BlockSize - 1);
Header.LastBlockInFile = (BlockFlags & 0x40) != 0;
Header.TablePresent = (BlockFlags & 0x80) != 0;
return true;
}
private async Task<bool> ReadFilterAsync(
UnpackFilter Filter,
CancellationToken cancellationToken = default
)
{
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
Filter.uBlockStart = ReadFilterData();
Filter.uBlockLength = ReadFilterData();
if (Filter.BlockLength > MAX_FILTER_BLOCK_SIZE)
{
Filter.BlockLength = 0;
}
Filter.Type = (byte)(Inp.fgetbits() >> 13);
Inp.faddbits(3);
if (Filter.Type == (byte)FilterType.FILTER_DELTA)
{
Filter.Channels = (byte)((Inp.fgetbits() >> 11) + 1);
Inp.faddbits(5);
}
return true;
}
}

View File

@@ -479,354 +479,6 @@ internal partial class Unpack
return ReadCode != -1;
}
private async System.Threading.Tasks.Task<bool> UnpReadBufAsync(
System.Threading.CancellationToken cancellationToken = default
)
{
var DataSize = ReadTop - Inp.InAddr; // Data left to process.
if (DataSize < 0)
{
return false;
}
BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart;
if (Inp.InAddr > MAX_SIZE / 2)
{
if (DataSize > 0)
{
Array.Copy(InBuf, inAddr, InBuf, 0, DataSize);
}
Inp.InAddr = 0;
ReadTop = DataSize;
}
else
{
DataSize = ReadTop;
}
var ReadCode = 0;
if (MAX_SIZE != DataSize)
{
ReadCode = await readStream
.ReadAsync(InBuf, DataSize, MAX_SIZE - DataSize, cancellationToken)
.ConfigureAwait(false);
}
if (ReadCode > 0) // Can be also -1.
{
ReadTop += ReadCode;
}
ReadBorder = ReadTop - 30;
BlockHeader.BlockStart = Inp.InAddr;
if (BlockHeader.BlockSize != -1) // '-1' means not defined yet.
{
ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1);
}
return ReadCode != -1;
}
public async System.Threading.Tasks.Task Unpack5Async(
bool Solid,
System.Threading.CancellationToken cancellationToken = default
)
{
FileExtracted = true;
if (!Suspended)
{
UnpInitData(Solid);
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return;
}
// Check TablesRead5 to be sure that we read tables at least once
// regardless of current block header TablePresent flag.
// So we can safefly use these tables below.
if (
!await ReadBlockHeaderAsync(cancellationToken).ConfigureAwait(false)
|| !ReadTables()
|| !TablesRead5
)
{
return;
}
}
while (true)
{
UnpPtr &= MaxWinMask;
if (Inp.InAddr >= ReadBorder)
{
var FileDone = false;
// We use 'while', because for empty block containing only Huffman table,
// we'll be on the block border once again just after reading the table.
while (
Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1
|| Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1
&& Inp.InBit >= BlockHeader.BlockBitSize
)
{
if (BlockHeader.LastBlockInFile)
{
FileDone = true;
break;
}
if (
!await ReadBlockHeaderAsync(cancellationToken).ConfigureAwait(false)
|| !ReadTables()
)
{
return;
}
}
if (FileDone || !await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
break;
}
}
if (
((WriteBorder - UnpPtr) & MaxWinMask) < PackDef.MAX_LZ_MATCH + 3
&& WriteBorder != UnpPtr
)
{
UnpWriteBuf();
if (WrittenFileSize > DestUnpSize)
{
return;
}
if (Suspended)
{
FileExtracted = false;
return;
}
}
//uint MainSlot=DecodeNumber(Inp,LD);
var MainSlot = this.DecodeNumber(LD);
if (MainSlot < 256)
{
// if (Fragmented)
// FragWindow[UnpPtr++]=(byte)MainSlot;
// else
Window[UnpPtr++] = (byte)MainSlot;
continue;
}
if (MainSlot >= 262)
{
var Length = SlotToLength(MainSlot - 262);
//uint DBits,Distance=1,DistSlot=DecodeNumber(Inp,&BlockTables.DD);
int DBits;
uint Distance = 1,
DistSlot = this.DecodeNumber(DD);
if (DistSlot < 4)
{
DBits = 0;
Distance += DistSlot;
}
else
{
//DBits=DistSlot/2 - 1;
DBits = (int)((DistSlot / 2) - 1);
Distance += (2 | (DistSlot & 1)) << DBits;
}
if (DBits > 0)
{
if (DBits >= 4)
{
if (DBits > 4)
{
Distance += ((Inp.getbits() >> (36 - DBits)) << 4);
Inp.AddBits(DBits - 4);
}
//uint LowDist=DecodeNumber(Inp,&BlockTables.LDD);
var LowDist = this.DecodeNumber(LDD);
Distance += LowDist;
}
else
{
Distance += Inp.getbits() >> (32 - DBits);
Inp.AddBits(DBits);
}
}
if (Distance > 0x100)
{
Length++;
if (Distance > 0x2000)
{
Length++;
if (Distance > 0x40000)
{
Length++;
}
}
}
InsertOldDist(Distance);
LastLength = Length;
// if (Fragmented)
// FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask);
// else
CopyString(Length, Distance);
continue;
}
if (MainSlot == 256)
{
var Filter = new UnpackFilter();
if (
!await ReadFilterAsync(Filter, cancellationToken).ConfigureAwait(false)
|| !AddFilter(Filter)
)
{
break;
}
continue;
}
if (MainSlot == 257)
{
if (LastLength != 0)
// if (Fragmented)
// FragWindow.CopyString(LastLength,OldDist[0],UnpPtr,MaxWinMask);
// else
//CopyString(LastLength,OldDist[0]);
{
CopyString(LastLength, OldDistN(0));
}
continue;
}
if (MainSlot < 262)
{
//uint DistNum=MainSlot-258;
var DistNum = (int)(MainSlot - 258);
//uint Distance=OldDist[DistNum];
var Distance = OldDistN(DistNum);
//for (uint I=DistNum;I>0;I--)
for (var I = DistNum; I > 0; I--)
//OldDistN[I]=OldDistN(I-1);
{
SetOldDistN(I, OldDistN(I - 1));
}
//OldDistN[0]=Distance;
SetOldDistN(0, Distance);
var LengthSlot = this.DecodeNumber(RD);
var Length = SlotToLength(LengthSlot);
LastLength = Length;
// if (Fragmented)
// FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask);
// else
CopyString(Length, Distance);
continue;
}
}
UnpWriteBuf();
}
private async System.Threading.Tasks.Task<bool> ReadBlockHeaderAsync(
System.Threading.CancellationToken cancellationToken = default
)
{
Header.HeaderSize = 0;
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
//Inp.faddbits((8-Inp.InBit)&7);
Inp.faddbits((uint)((8 - Inp.InBit) & 7));
var BlockFlags = (byte)(Inp.fgetbits() >> 8);
Inp.faddbits(8);
//uint ByteCount=((BlockFlags>>3)&3)+1; // Block size byte count.
var ByteCount = (uint)(((BlockFlags >> 3) & 3) + 1); // Block size byte count.
if (ByteCount == 4)
{
return false;
}
//Header.HeaderSize=2+ByteCount;
Header.HeaderSize = (int)(2 + ByteCount);
Header.BlockBitSize = (BlockFlags & 7) + 1;
var SavedCheckSum = (byte)(Inp.fgetbits() >> 8);
Inp.faddbits(8);
var BlockSize = 0;
//for (uint I=0;I<ByteCount;I++)
for (var I = 0; I < ByteCount; I++)
{
//BlockSize+=(Inp.fgetbits()>>8)<<(I*8);
BlockSize += (int)(Inp.fgetbits() >> 8) << (I * 8);
Inp.AddBits(8);
}
Header.BlockSize = BlockSize;
var CheckSum = (byte)(0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16));
if (CheckSum != SavedCheckSum)
{
return false;
}
Header.BlockStart = Inp.InAddr;
ReadBorder = Math.Min(ReadBorder, Header.BlockStart + Header.BlockSize - 1);
Header.LastBlockInFile = (BlockFlags & 0x40) != 0;
Header.TablePresent = (BlockFlags & 0x80) != 0;
return true;
}
private async System.Threading.Tasks.Task<bool> ReadFilterAsync(
UnpackFilter Filter,
System.Threading.CancellationToken cancellationToken = default
)
{
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
Filter.uBlockStart = ReadFilterData();
Filter.uBlockLength = ReadFilterData();
if (Filter.BlockLength > MAX_FILTER_BLOCK_SIZE)
{
Filter.BlockLength = 0;
}
//Filter.Type=Inp.fgetbits()>>13;
Filter.Type = (byte)(Inp.fgetbits() >> 13);
Inp.faddbits(3);
if (Filter.Type == (byte)FilterType.FILTER_DELTA)
{
//Filter.Channels=(Inp.fgetbits()>>11)+1;
Filter.Channels = (byte)((Inp.fgetbits() >> 11) + 1);
Inp.faddbits(5);
}
return true;
}
//?
// void UnpWriteBuf()
// {

View File

@@ -1,5 +1,7 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common.Rar.Headers;
using size_t = System.UInt32;
@@ -23,11 +25,11 @@ internal partial class Unpack : IRarUnpack
// NOTE: caller has logic to check for -1 for error we throw instead.
readStream.Read(buf, offset, count);
private async System.Threading.Tasks.Task<int> UnpIO_UnpReadAsync(
private async Task<int> UnpIO_UnpReadAsync(
byte[] buf,
int offset,
int count,
System.Threading.CancellationToken cancellationToken = default
CancellationToken cancellationToken = default
) =>
// NOTE: caller has logic to check for -1 for error we throw instead.
await readStream.ReadAsync(buf, offset, count, cancellationToken).ConfigureAwait(false);
@@ -35,11 +37,11 @@ internal partial class Unpack : IRarUnpack
private void UnpIO_UnpWrite(byte[] buf, size_t offset, uint count) =>
writeStream.Write(buf, checked((int)offset), checked((int)count));
private async System.Threading.Tasks.Task UnpIO_UnpWriteAsync(
private async Task UnpIO_UnpWriteAsync(
byte[] buf,
size_t offset,
uint count,
System.Threading.CancellationToken cancellationToken = default
CancellationToken cancellationToken = default
) =>
await writeStream
.WriteAsync(buf, checked((int)offset), checked((int)count), cancellationToken)
@@ -66,11 +68,11 @@ internal partial class Unpack : IRarUnpack
DoUnpack();
}
public async System.Threading.Tasks.Task DoUnpackAsync(
public async Task DoUnpackAsync(
FileHeader fileHeader,
Stream readStream,
Stream writeStream,
System.Threading.CancellationToken cancellationToken = default
CancellationToken cancellationToken = default
)
{
DestUnpSize = fileHeader.UncompressedSize;
@@ -97,9 +99,7 @@ internal partial class Unpack : IRarUnpack
}
}
public async System.Threading.Tasks.Task DoUnpackAsync(
System.Threading.CancellationToken cancellationToken = default
)
public async Task DoUnpackAsync(CancellationToken cancellationToken = default)
{
if (fileHeader.IsStored)
{
@@ -133,9 +133,7 @@ internal partial class Unpack : IRarUnpack
} while (!Suspended);
}
private async System.Threading.Tasks.Task UnstoreFileAsync(
System.Threading.CancellationToken cancellationToken = default
)
private async Task UnstoreFileAsync(CancellationToken cancellationToken = default)
{
var buffer = new byte[(int)Math.Min(0x10000, DestUnpSize)];
do

View File

@@ -0,0 +1,100 @@
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.Compressors.Rar.UnpackV2017;
internal partial class Unpack
{
private async Task Unpack15Async(bool Solid, CancellationToken cancellationToken = default)
{
UnpInitData(Solid);
UnpInitData15(Solid);
await UnpReadBufAsync(cancellationToken).ConfigureAwait(false);
if (!Solid)
{
InitHuff();
UnpPtr = 0;
}
else
{
UnpPtr = WrPtr;
}
--DestUnpSize;
if (DestUnpSize >= 0)
{
GetFlagsBuf();
FlagsCnt = 8;
}
while (DestUnpSize >= 0)
{
UnpPtr &= MaxWinMask;
if (
Inp.InAddr > ReadTop - 30
&& !await UnpReadBufAsync(cancellationToken).ConfigureAwait(false)
)
{
break;
}
if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr)
{
UnpWriteBuf20();
}
if (StMode != 0)
{
HuffDecode();
continue;
}
if (--FlagsCnt < 0)
{
GetFlagsBuf();
FlagsCnt = 7;
}
if ((FlagBuf & 0x80) != 0)
{
FlagBuf <<= 1;
if (Nlzb > Nhfb)
{
LongLZ();
}
else
{
HuffDecode();
}
}
else
{
FlagBuf <<= 1;
if (--FlagsCnt < 0)
{
GetFlagsBuf();
FlagsCnt = 7;
}
if ((FlagBuf & 0x80) != 0)
{
FlagBuf <<= 1;
if (Nlzb > Nhfb)
{
HuffDecode();
}
else
{
LongLZ();
}
}
else
{
FlagBuf <<= 1;
ShortLZ();
}
}
}
UnpWriteBuf20();
}
}

View File

@@ -200,102 +200,6 @@ internal partial class Unpack
UnpWriteBuf20();
}
private async System.Threading.Tasks.Task Unpack15Async(
bool Solid,
System.Threading.CancellationToken cancellationToken = default
)
{
UnpInitData(Solid);
UnpInitData15(Solid);
await UnpReadBufAsync(cancellationToken).ConfigureAwait(false);
if (!Solid)
{
InitHuff();
UnpPtr = 0;
}
else
{
UnpPtr = WrPtr;
}
--DestUnpSize;
if (DestUnpSize >= 0)
{
GetFlagsBuf();
FlagsCnt = 8;
}
while (DestUnpSize >= 0)
{
UnpPtr &= MaxWinMask;
if (
Inp.InAddr > ReadTop - 30
&& !await UnpReadBufAsync(cancellationToken).ConfigureAwait(false)
)
{
break;
}
if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr)
{
await UnpWriteBuf20Async(cancellationToken).ConfigureAwait(false);
}
if (StMode != 0)
{
HuffDecode();
continue;
}
if (--FlagsCnt < 0)
{
GetFlagsBuf();
FlagsCnt = 7;
}
if ((FlagBuf & 0x80) != 0)
{
FlagBuf <<= 1;
if (Nlzb > Nhfb)
{
LongLZ();
}
else
{
HuffDecode();
}
}
else
{
FlagBuf <<= 1;
if (--FlagsCnt < 0)
{
GetFlagsBuf();
FlagsCnt = 7;
}
if ((FlagBuf & 0x80) != 0)
{
FlagBuf <<= 1;
if (Nlzb > Nhfb)
{
HuffDecode();
}
else
{
LongLZ();
}
}
else
{
FlagBuf <<= 1;
ShortLZ();
}
}
}
await UnpWriteBuf20Async(cancellationToken).ConfigureAwait(false);
}
//#define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos])
private uint GetShortLen1(uint pos) => ((pos) == 1 ? (uint)(Buf60 + 3) : ShortLen1[pos]);

View File

@@ -0,0 +1,319 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef;
using static SharpCompress.Compressors.Rar.UnpackV2017.Unpack.Unpack20Local;
namespace SharpCompress.Compressors.Rar.UnpackV2017;
internal partial class Unpack
{
private async Task Unpack20Async(bool Solid, CancellationToken cancellationToken = default)
{
uint Bits;
if (Suspended)
{
UnpPtr = WrPtr;
}
else
{
UnpInitData(Solid);
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return;
}
if (
(!Solid || !TablesRead2)
&& !await ReadTables20Async(cancellationToken).ConfigureAwait(false)
)
{
return;
}
--DestUnpSize;
}
while (DestUnpSize >= 0)
{
UnpPtr &= MaxWinMask;
if (Inp.InAddr > ReadTop - 30)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
break;
}
}
if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr)
{
UnpWriteBuf20();
if (Suspended)
{
return;
}
}
if (UnpAudioBlock)
{
var AudioNumber = DecodeNumber(Inp, MD[UnpCurChannel]);
if (AudioNumber == 256)
{
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
{
break;
}
continue;
}
Window[UnpPtr++] = DecodeAudio((int)AudioNumber);
if (++UnpCurChannel == UnpChannels)
{
UnpCurChannel = 0;
}
--DestUnpSize;
continue;
}
var Number = DecodeNumber(Inp, BlockTables.LD);
if (Number < 256)
{
Window[UnpPtr++] = (byte)Number;
--DestUnpSize;
continue;
}
if (Number > 269)
{
var Length = (uint)(LDecode[Number -= 270] + 3);
if ((Bits = LBits[Number]) > 0)
{
Length += Inp.getbits() >> (int)(16 - Bits);
Inp.addbits(Bits);
}
var DistNumber = DecodeNumber(Inp, BlockTables.DD);
var Distance = DDecode[DistNumber] + 1;
if ((Bits = DBits[DistNumber]) > 0)
{
Distance += Inp.getbits() >> (int)(16 - Bits);
Inp.addbits(Bits);
}
if (Distance >= 0x2000)
{
Length++;
if (Distance >= 0x40000L)
{
Length++;
}
}
CopyString20(Length, Distance);
continue;
}
if (Number == 269)
{
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
{
break;
}
continue;
}
if (Number == 256)
{
CopyString20(LastLength, LastDist);
continue;
}
if (Number < 261)
{
var Distance = OldDist[(OldDistPtr - (Number - 256)) & 3];
var LengthNumber = DecodeNumber(Inp, BlockTables.RD);
var Length = (uint)(LDecode[LengthNumber] + 2);
if ((Bits = LBits[LengthNumber]) > 0)
{
Length += Inp.getbits() >> (int)(16 - Bits);
Inp.addbits(Bits);
}
if (Distance >= 0x101)
{
Length++;
if (Distance >= 0x2000)
{
Length++;
if (Distance >= 0x40000)
{
Length++;
}
}
}
CopyString20(Length, Distance);
continue;
}
if (Number < 270)
{
var Distance = (uint)(SDDecode[Number -= 261] + 1);
if ((Bits = SDBits[Number]) > 0)
{
Distance += Inp.getbits() >> (int)(16 - Bits);
Inp.addbits(Bits);
}
CopyString20(2, Distance);
continue;
}
}
ReadLastTables();
UnpWriteBuf20();
}
private async Task UnpWriteBuf20Async(CancellationToken cancellationToken = default)
{
if (UnpPtr != WrPtr)
{
UnpSomeRead = true;
}
if (UnpPtr < WrPtr)
{
await UnpIO_UnpWriteAsync(
Window,
WrPtr,
(uint)(-(int)WrPtr & MaxWinMask),
cancellationToken
)
.ConfigureAwait(false);
await UnpIO_UnpWriteAsync(Window, 0, UnpPtr, cancellationToken).ConfigureAwait(false);
UnpAllBuf = true;
}
else
{
await UnpIO_UnpWriteAsync(Window, WrPtr, UnpPtr - WrPtr, cancellationToken)
.ConfigureAwait(false);
}
WrPtr = UnpPtr;
}
private async Task<bool> ReadTables20Async(CancellationToken cancellationToken = default)
{
byte[] BitLength = new byte[checked((int)BC20)];
byte[] Table = new byte[checked((int)MC20 * 4)];
if (Inp.InAddr > ReadTop - 25)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
var BitField = Inp.getbits();
UnpAudioBlock = (BitField & 0x8000) != 0;
if ((BitField & 0x4000) != 0)
{
Array.Clear(UnpOldTable20, 0, UnpOldTable20.Length);
}
Inp.addbits(2);
uint TableSize;
if (UnpAudioBlock)
{
UnpChannels = ((BitField >> 12) & 3) + 1;
if (UnpCurChannel >= UnpChannels)
{
UnpCurChannel = 0;
}
Inp.addbits(2);
TableSize = MC20 * UnpChannels;
}
else
{
TableSize = NC20 + DC20 + RC20;
}
for (int I = 0; I < checked((int)BC20); I++)
{
BitLength[I] = (byte)(Inp.getbits() >> 12);
Inp.addbits(4);
}
MakeDecodeTables(BitLength, 0, BlockTables.BD, BC20);
for (int I = 0; I < checked((int)TableSize); )
{
if (Inp.InAddr > ReadTop - 5)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
var Number = DecodeNumber(Inp, BlockTables.BD);
if (Number < 16)
{
Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xf);
I++;
}
else if (Number == 16)
{
var N = (Inp.getbits() >> 14) + 3;
Inp.addbits(2);
if (I == 0)
{
return false; // We cannot have "repeat previous" code at the first position.
}
else
{
while (N-- > 0 && I < TableSize)
{
Table[I] = Table[I - 1];
I++;
}
}
}
else
{
uint N;
if (Number == 17)
{
N = (Inp.getbits() >> 13) + 3;
Inp.addbits(3);
}
else
{
N = (Inp.getbits() >> 9) + 11;
Inp.addbits(7);
}
while (N-- > 0 && I < TableSize)
{
Table[I++] = 0;
}
}
}
TablesRead2 = true;
if (Inp.InAddr > ReadTop)
{
return true;
}
if (UnpAudioBlock)
{
for (int I = 0; I < UnpChannels; I++)
{
MakeDecodeTables(Table, (int)(I * MC20), MD[I], MC20);
}
}
else
{
MakeDecodeTables(Table, 0, BlockTables.LD, NC20);
MakeDecodeTables(Table, (int)NC20, BlockTables.DD, DC20);
MakeDecodeTables(Table, (int)(NC20 + DC20), BlockTables.RD, RC20);
}
Array.Copy(Table, 0, this.UnpOldTable20, 0, UnpOldTable20.Length);
return true;
}
}

View File

@@ -342,170 +342,6 @@ internal partial class Unpack
UnpWriteBuf20();
}
private async System.Threading.Tasks.Task Unpack20Async(
bool Solid,
System.Threading.CancellationToken cancellationToken = default
)
{
uint Bits;
if (Suspended)
{
UnpPtr = WrPtr;
}
else
{
UnpInitData(Solid);
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return;
}
if (
(!Solid || !TablesRead2)
&& !await ReadTables20Async(cancellationToken).ConfigureAwait(false)
)
{
return;
}
--DestUnpSize;
}
while (DestUnpSize >= 0)
{
UnpPtr &= MaxWinMask;
if (Inp.InAddr > ReadTop - 30)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
break;
}
}
if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr)
{
await UnpWriteBuf20Async(cancellationToken).ConfigureAwait(false);
if (Suspended)
{
return;
}
}
if (UnpAudioBlock)
{
var AudioNumber = DecodeNumber(Inp, MD[UnpCurChannel]);
if (AudioNumber == 256)
{
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
{
break;
}
continue;
}
Window[UnpPtr++] = DecodeAudio((int)AudioNumber);
if (++UnpCurChannel == UnpChannels)
{
UnpCurChannel = 0;
}
--DestUnpSize;
continue;
}
var Number = DecodeNumber(Inp, BlockTables.LD);
if (Number < 256)
{
Window[UnpPtr++] = (byte)Number;
--DestUnpSize;
continue;
}
if (Number > 269)
{
var Length = (uint)(LDecode[Number -= 270] + 3);
if ((Bits = LBits[Number]) > 0)
{
Length += Inp.getbits() >> (int)(16 - Bits);
Inp.addbits(Bits);
}
var DistNumber = DecodeNumber(Inp, BlockTables.DD);
var Distance = DDecode[DistNumber] + 1;
if ((Bits = DBits[DistNumber]) > 0)
{
Distance += Inp.getbits() >> (int)(16 - Bits);
Inp.addbits(Bits);
}
if (Distance >= 0x2000)
{
Length++;
if (Distance >= 0x40000L)
{
Length++;
}
}
CopyString20(Length, Distance);
continue;
}
if (Number == 269)
{
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
{
break;
}
continue;
}
if (Number == 256)
{
CopyString20(LastLength, LastDist);
continue;
}
if (Number < 261)
{
var Distance = OldDist[(OldDistPtr - (Number - 256)) & 3];
var LengthNumber = DecodeNumber(Inp, BlockTables.RD);
var Length = (uint)(LDecode[LengthNumber] + 2);
if ((Bits = LBits[LengthNumber]) > 0)
{
Length += Inp.getbits() >> (int)(16 - Bits);
Inp.addbits(Bits);
}
if (Distance >= 0x101)
{
Length++;
if (Distance >= 0x2000)
{
Length++;
if (Distance >= 0x40000)
{
Length++;
}
}
}
CopyString20(Length, Distance);
continue;
}
if (Number < 270)
{
var Distance = (uint)(SDDecode[Number -= 261] + 1);
if ((Bits = SDBits[Number]) > 0)
{
Distance += Inp.getbits() >> (int)(16 - Bits);
Inp.addbits(Bits);
}
CopyString20(2, Distance);
continue;
}
}
ReadLastTables();
await UnpWriteBuf20Async(cancellationToken).ConfigureAwait(false);
}
private void UnpWriteBuf20()
{
if (UnpPtr != WrPtr)
@@ -527,36 +363,6 @@ internal partial class Unpack
WrPtr = UnpPtr;
}
private async System.Threading.Tasks.Task UnpWriteBuf20Async(
System.Threading.CancellationToken cancellationToken = default
)
{
if (UnpPtr != WrPtr)
{
UnpSomeRead = true;
}
if (UnpPtr < WrPtr)
{
await UnpIO_UnpWriteAsync(
Window,
WrPtr,
(uint)(-(int)WrPtr & MaxWinMask),
cancellationToken
)
.ConfigureAwait(false);
await UnpIO_UnpWriteAsync(Window, 0, UnpPtr, cancellationToken).ConfigureAwait(false);
UnpAllBuf = true;
}
else
{
await UnpIO_UnpWriteAsync(Window, WrPtr, UnpPtr - WrPtr, cancellationToken)
.ConfigureAwait(false);
}
WrPtr = UnpPtr;
}
private bool ReadTables20()
{
Span<byte> BitLength = stackalloc byte[checked((int)BC20)];
@@ -677,130 +483,6 @@ internal partial class Unpack
return true;
}
private async System.Threading.Tasks.Task<bool> ReadTables20Async(
System.Threading.CancellationToken cancellationToken = default
)
{
byte[] BitLength = new byte[checked((int)BC20)];
byte[] Table = new byte[checked((int)MC20 * 4)];
if (Inp.InAddr > ReadTop - 25)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
var BitField = Inp.getbits();
UnpAudioBlock = (BitField & 0x8000) != 0;
if ((BitField & 0x4000) != 0)
{
Array.Clear(UnpOldTable20, 0, UnpOldTable20.Length);
}
Inp.addbits(2);
uint TableSize;
if (UnpAudioBlock)
{
UnpChannels = ((BitField >> 12) & 3) + 1;
if (UnpCurChannel >= UnpChannels)
{
UnpCurChannel = 0;
}
Inp.addbits(2);
TableSize = MC20 * UnpChannels;
}
else
{
TableSize = NC20 + DC20 + RC20;
}
for (int I = 0; I < checked((int)BC20); I++)
{
BitLength[I] = (byte)(Inp.getbits() >> 12);
Inp.addbits(4);
}
MakeDecodeTables(BitLength, 0, BlockTables.BD, BC20);
for (int I = 0; I < checked((int)TableSize); )
{
if (Inp.InAddr > ReadTop - 5)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
var Number = DecodeNumber(Inp, BlockTables.BD);
if (Number < 16)
{
Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xF);
I++;
}
else if (Number < 18)
{
uint N;
if (Number == 16)
{
N = (Inp.getbits() >> 14) + 3;
Inp.addbits(2);
}
else
{
N = (Inp.getbits() >> 13) + 11;
Inp.addbits(3);
}
if (I == 0)
{
return false;
}
while (N-- > 0 && I < checked((int)TableSize))
{
Table[I] = Table[I - 1];
I++;
}
}
else
{
uint N;
if (Number == 18)
{
N = (Inp.getbits() >> 13) + 3;
Inp.addbits(3);
}
else
{
N = (Inp.getbits() >> 9) + 11;
Inp.addbits(7);
}
while (N-- > 0 && I < checked((int)TableSize))
{
Table[I++] = 0;
}
}
}
if (UnpAudioBlock)
{
for (int I = 0; I < UnpChannels; I++)
{
MakeDecodeTables(Table, (int)(I * MC20), MD[I], MC20);
}
}
else
{
MakeDecodeTables(Table, 0, BlockTables.LD, NC20);
MakeDecodeTables(Table, (int)NC20, BlockTables.DD, DC20);
MakeDecodeTables(Table, (int)(NC20 + DC20), BlockTables.RD, RC20);
}
Array.Copy(Table, 0, this.UnpOldTable20, 0, UnpOldTable20.Length);
return true;
}
private void ReadLastTables()
{
if (ReadTop >= Inp.InAddr + 5)

View File

@@ -0,0 +1,709 @@
#nullable disable
using System;
using System.Threading;
using System.Threading.Tasks;
using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef;
using static SharpCompress.Compressors.Rar.UnpackV2017.UnpackGlobal;
using size_t = System.UInt32;
namespace SharpCompress.Compressors.Rar.UnpackV2017;
internal partial class Unpack
{
private async Task Unpack5Async(bool Solid, CancellationToken cancellationToken = default)
{
FileExtracted = true;
if (!Suspended)
{
UnpInitData(Solid);
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return;
}
// Check TablesRead5 to be sure that we read tables at least once
// regardless of current block header TablePresent flag.
// So we can safefly use these tables below.
if (
!await ReadBlockHeaderAsync(Inp, cancellationToken).ConfigureAwait(false)
|| !await ReadTablesAsync(Inp, cancellationToken).ConfigureAwait(false)
|| !TablesRead5
)
{
return;
}
}
while (true)
{
UnpPtr &= MaxWinMask;
if (Inp.InAddr >= ReadBorder)
{
var FileDone = false;
// We use 'while', because for empty block containing only Huffman table,
// we'll be on the block border once again just after reading the table.
while (
Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1
|| Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1
&& Inp.InBit >= BlockHeader.BlockBitSize
)
{
if (BlockHeader.LastBlockInFile)
{
FileDone = true;
break;
}
if (
!await ReadBlockHeaderAsync(Inp, cancellationToken).ConfigureAwait(false)
|| !await ReadTablesAsync(Inp, cancellationToken).ConfigureAwait(false)
)
{
return;
}
}
if (FileDone || !await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
break;
}
}
if (((WriteBorder - UnpPtr) & MaxWinMask) < MAX_LZ_MATCH + 3 && WriteBorder != UnpPtr)
{
await UnpWriteBufAsync(cancellationToken);
if (WrittenFileSize > DestUnpSize)
{
return;
}
if (Suspended)
{
FileExtracted = false;
return;
}
}
var MainSlot = DecodeNumber(Inp, BlockTables.LD);
if (MainSlot < 256)
{
if (Fragmented)
{
FragWindow[UnpPtr++] = (byte)MainSlot;
}
else
{
Window[UnpPtr++] = (byte)MainSlot;
}
continue;
}
if (MainSlot >= 262)
{
var Length = SlotToLength(Inp, MainSlot - 262);
uint DBits,
Distance = 1,
DistSlot = DecodeNumber(Inp, BlockTables.DD);
if (DistSlot < 4)
{
DBits = 0;
Distance += DistSlot;
}
else
{
DBits = (DistSlot / 2) - 1;
Distance += (2 | (DistSlot & 1)) << (int)DBits;
}
if (DBits > 0)
{
if (DBits >= 4)
{
if (DBits > 4)
{
Distance += ((Inp.getbits32() >> (int)(36 - DBits)) << 4);
Inp.addbits(DBits - 4);
}
var LowDist = DecodeNumber(Inp, BlockTables.LDD);
Distance += LowDist;
}
else
{
Distance += Inp.getbits32() >> (int)(32 - DBits);
Inp.addbits(DBits);
}
}
if (Distance > 0x100)
{
Length++;
if (Distance > 0x2000)
{
Length++;
if (Distance > 0x40000)
{
Length++;
}
}
}
InsertOldDist(Distance);
LastLength = Length;
if (Fragmented)
{
FragWindow.CopyString(Length, Distance, ref UnpPtr, MaxWinMask);
}
else
{
CopyString(Length, Distance);
}
continue;
}
if (MainSlot == 256)
{
var Filter = new UnpackFilter();
if (
!await ReadFilterAsync(Inp, Filter, cancellationToken).ConfigureAwait(false)
|| !AddFilter(Filter)
)
{
break;
}
continue;
}
if (MainSlot == 257)
{
if (LastLength != 0)
{
if (Fragmented)
{
FragWindow.CopyString(LastLength, OldDist[0], ref UnpPtr, MaxWinMask);
}
else
{
CopyString(LastLength, OldDist[0]);
}
}
continue;
}
if (MainSlot < 262)
{
var DistNum = MainSlot - 258;
var Distance = OldDist[DistNum];
for (var I = DistNum; I > 0; I--)
{
OldDist[I] = OldDist[I - 1];
}
OldDist[0] = Distance;
var LengthSlot = DecodeNumber(Inp, BlockTables.RD);
var Length = SlotToLength(Inp, LengthSlot);
LastLength = Length;
if (Fragmented)
{
FragWindow.CopyString(Length, Distance, ref UnpPtr, MaxWinMask);
}
else
{
CopyString(Length, Distance);
}
continue;
}
}
await UnpWriteBufAsync(cancellationToken);
}
private async Task<bool> ReadFilterAsync(
BitInput Inp,
UnpackFilter Filter,
CancellationToken cancellationToken = default
)
{
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
Filter.BlockStart = ReadFilterData(Inp);
Filter.BlockLength = ReadFilterData(Inp);
if (Filter.BlockLength > MAX_FILTER_BLOCK_SIZE)
{
Filter.BlockLength = 0;
}
Filter.Type = (byte)(Inp.fgetbits() >> 13);
Inp.faddbits(3);
if (Filter.Type == FILTER_DELTA)
{
Filter.Channels = (byte)((Inp.fgetbits() >> 11) + 1);
Inp.faddbits(5);
}
return true;
}
private async Task<bool> UnpReadBufAsync(CancellationToken cancellationToken = default)
{
var DataSize = ReadTop - Inp.InAddr; // Data left to process.
if (DataSize < 0)
{
return false;
}
BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart;
if (Inp.InAddr > MAX_SIZE / 2)
{
if (DataSize > 0)
{
Buffer.BlockCopy(Inp.InBuf, Inp.InAddr, Inp.InBuf, 0, DataSize);
}
Inp.InAddr = 0;
ReadTop = DataSize;
}
else
{
DataSize = ReadTop;
}
var ReadCode = 0;
if (MAX_SIZE != DataSize)
{
ReadCode = await UnpIO_UnpReadAsync(
Inp.InBuf,
DataSize,
MAX_SIZE - DataSize,
cancellationToken
)
.ConfigureAwait(false);
}
if (ReadCode > 0) // Can be also -1.
{
ReadTop += ReadCode;
}
ReadBorder = ReadTop - 30;
BlockHeader.BlockStart = Inp.InAddr;
if (BlockHeader.BlockSize != -1) // '-1' means not defined yet.
{
ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1);
}
return ReadCode != -1;
}
private async Task UnpWriteBufAsync(CancellationToken cancellationToken = default)
{
var WrittenBorder = WrPtr;
var FullWriteSize = (UnpPtr - WrittenBorder) & MaxWinMask;
var WriteSizeLeft = FullWriteSize;
var NotAllFiltersProcessed = false;
for (var I = 0; I < Filters.Count; I++)
{
var flt = Filters[I];
if (flt.Type == FILTER_NONE)
{
continue;
}
if (flt.NextWindow)
{
if (((flt.BlockStart - WrPtr) & MaxWinMask) <= FullWriteSize)
{
flt.NextWindow = false;
}
continue;
}
var BlockStart = flt.BlockStart;
var BlockLength = flt.BlockLength;
if (((BlockStart - WrittenBorder) & MaxWinMask) < WriteSizeLeft)
{
if (WrittenBorder != BlockStart)
{
await UnpWriteAreaAsync(WrittenBorder, BlockStart, cancellationToken)
.ConfigureAwait(false);
WrittenBorder = BlockStart;
WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask;
}
if (BlockLength <= WriteSizeLeft)
{
if (BlockLength > 0)
{
var BlockEnd = (BlockStart + BlockLength) & MaxWinMask;
FilterSrcMemory = EnsureCapacity(
FilterSrcMemory,
checked((int)BlockLength)
);
var Mem = FilterSrcMemory;
if (BlockStart < BlockEnd || BlockEnd == 0)
{
if (Fragmented)
{
FragWindow.CopyData(Mem, 0, BlockStart, BlockLength);
}
else
{
Buffer.BlockCopy(Window, (int)BlockStart, Mem, 0, (int)BlockLength);
}
}
else
{
var FirstPartLength = MaxWinSize - BlockStart;
if (Fragmented)
{
FragWindow.CopyData(Mem, 0, BlockStart, FirstPartLength);
FragWindow.CopyData(Mem, FirstPartLength, 0, BlockEnd);
}
else
{
Buffer.BlockCopy(
Window,
(int)BlockStart,
Mem,
0,
(int)FirstPartLength
);
Buffer.BlockCopy(
Window,
0,
Mem,
(int)FirstPartLength,
(int)BlockEnd
);
}
}
var OutMem = ApplyFilter(Mem, BlockLength, flt);
Filters[I].Type = FILTER_NONE;
if (OutMem != null)
{
await UnpIO_UnpWriteAsync(OutMem, 0, BlockLength, cancellationToken)
.ConfigureAwait(false);
WrittenFileSize += BlockLength;
}
WrittenBorder = BlockEnd;
WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask;
}
}
else
{
NotAllFiltersProcessed = true;
for (var J = I; J < Filters.Count; J++)
{
var fltj = Filters[J];
if (
fltj.Type != FILTER_NONE
&& fltj.NextWindow == false
&& ((fltj.BlockStart - WrPtr) & MaxWinMask) < FullWriteSize
)
{
fltj.NextWindow = true;
}
}
break;
}
}
}
var EmptyCount = 0;
for (var I = 0; I < Filters.Count; I++)
{
if (EmptyCount > 0)
{
Filters[I - EmptyCount] = Filters[I];
}
if (Filters[I].Type == FILTER_NONE)
{
EmptyCount++;
}
}
if (EmptyCount > 0)
{
Filters.RemoveRange(Filters.Count - EmptyCount, EmptyCount);
}
if (!NotAllFiltersProcessed)
{
await UnpWriteAreaAsync(WrittenBorder, UnpPtr, cancellationToken).ConfigureAwait(false);
WrPtr = UnpPtr;
}
WriteBorder = (UnpPtr + Math.Min(MaxWinSize, UNPACK_MAX_WRITE)) & MaxWinMask;
if (
WriteBorder == UnpPtr
|| WrPtr != UnpPtr
&& ((WrPtr - UnpPtr) & MaxWinMask) < ((WriteBorder - UnpPtr) & MaxWinMask)
)
{
WriteBorder = WrPtr;
}
}
private async Task UnpWriteAreaAsync(
size_t StartPtr,
size_t EndPtr,
CancellationToken cancellationToken = default
)
{
if (EndPtr != StartPtr)
{
UnpSomeRead = true;
}
if (EndPtr < StartPtr)
{
UnpAllBuf = true;
}
if (Fragmented)
{
var SizeToWrite = (EndPtr - StartPtr) & MaxWinMask;
while (SizeToWrite > 0)
{
var BlockSize = FragWindow.GetBlockSize(StartPtr, SizeToWrite);
FragWindow.GetBuffer(StartPtr, out var __buffer, out var __offset);
await UnpWriteDataAsync(__buffer, __offset, BlockSize, cancellationToken)
.ConfigureAwait(false);
SizeToWrite -= BlockSize;
StartPtr = (StartPtr + BlockSize) & MaxWinMask;
}
}
else if (EndPtr < StartPtr)
{
await UnpWriteDataAsync(Window, StartPtr, MaxWinSize - StartPtr, cancellationToken)
.ConfigureAwait(false);
await UnpWriteDataAsync(Window, 0, EndPtr, cancellationToken).ConfigureAwait(false);
}
else
{
await UnpWriteDataAsync(Window, StartPtr, EndPtr - StartPtr, cancellationToken)
.ConfigureAwait(false);
}
}
private async Task UnpWriteDataAsync(
byte[] Data,
size_t offset,
size_t Size,
CancellationToken cancellationToken = default
)
{
if (WrittenFileSize >= DestUnpSize)
{
return;
}
var WriteSize = Size;
var LeftToWrite = DestUnpSize - WrittenFileSize;
if (WriteSize > LeftToWrite)
{
WriteSize = (size_t)LeftToWrite;
}
await UnpIO_UnpWriteAsync(Data, offset, WriteSize, cancellationToken).ConfigureAwait(false);
WrittenFileSize += Size;
}
private async Task<bool> ReadBlockHeaderAsync(
BitInput Inp,
CancellationToken cancellationToken = default
)
{
BlockHeader.HeaderSize = 0;
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
Inp.faddbits((uint)((8 - Inp.InBit) & 7));
var BlockFlags = (byte)(Inp.fgetbits() >> 8);
Inp.faddbits(8);
var ByteCount = (uint)(((BlockFlags >> 3) & 3) + 1); // Block size byte count.
if (ByteCount == 4)
{
return false;
}
BlockHeader.HeaderSize = (int)(2 + ByteCount);
BlockHeader.BlockBitSize = (BlockFlags & 7) + 1;
var SavedCheckSum = (byte)(Inp.fgetbits() >> 8);
Inp.faddbits(8);
var BlockSize = 0;
for (uint I = 0; I < ByteCount; I++)
{
BlockSize += (int)((Inp.fgetbits() >> 8) << (int)(I * 8));
Inp.addbits(8);
}
BlockHeader.BlockSize = BlockSize;
var CheckSum = (byte)(0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16));
if (CheckSum != SavedCheckSum)
{
return false;
}
BlockHeader.BlockStart = Inp.InAddr;
ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1);
BlockHeader.LastBlockInFile = (BlockFlags & 0x40) != 0;
BlockHeader.TablePresent = (BlockFlags & 0x80) != 0;
return true;
}
private async Task<bool> ReadTablesAsync(
BitInput Inp,
CancellationToken cancellationToken = default
)
{
if (!BlockHeader.TablePresent)
{
return true;
}
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 25)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
var BitLength = new byte[checked((int)BC)];
for (int I = 0; I < BC; I++)
{
uint Length = (byte)(Inp.fgetbits() >> 12);
Inp.faddbits(4);
if (Length == 15)
{
uint ZeroCount = (byte)(Inp.fgetbits() >> 12);
Inp.faddbits(4);
if (ZeroCount == 0)
{
BitLength[I] = 15;
}
else
{
ZeroCount += 2;
while (ZeroCount-- > 0 && I < BitLength.Length)
{
BitLength[I++] = 0;
}
I--;
}
}
else
{
BitLength[I] = (byte)Length;
}
}
MakeDecodeTables(BitLength, 0, BlockTables.BD, BC);
var Table = new byte[checked((int)HUFF_TABLE_SIZE)];
const int TableSize = checked((int)HUFF_TABLE_SIZE);
for (int I = 0; I < TableSize; )
{
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 5)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return false;
}
}
var Number = DecodeNumber(Inp, BlockTables.BD);
if (Number < 16)
{
Table[I] = (byte)Number;
I++;
}
else if (Number < 18)
{
uint N;
if (Number == 16)
{
N = (Inp.fgetbits() >> 13) + 3;
Inp.faddbits(3);
}
else
{
N = (Inp.fgetbits() >> 9) + 11;
Inp.faddbits(7);
}
if (I == 0)
{
// We cannot have "repeat previous" code at the first position.
// Multiple such codes would shift Inp position without changing I,
// which can lead to reading beyond of Inp boundary in mutithreading
// mode, where Inp.ExternalBuffer disables bounds check and we just
// reserve a lot of buffer space to not need such check normally.
return false;
}
else
{
while (N-- > 0 && I < TableSize)
{
Table[I] = Table[I - 1];
I++;
}
}
}
else
{
uint N;
if (Number == 18)
{
N = (Inp.fgetbits() >> 13) + 3;
Inp.faddbits(3);
}
else
{
N = (Inp.fgetbits() >> 9) + 11;
Inp.faddbits(7);
}
while (N-- > 0 && I < TableSize)
{
Table[I++] = 0;
}
}
}
TablesRead5 = true;
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop)
{
return false;
}
MakeDecodeTables(Table, 0, BlockTables.LD, NC);
MakeDecodeTables(Table, (int)NC, BlockTables.DD, DC);
MakeDecodeTables(Table, (int)(NC + DC), BlockTables.LDD, LDC);
MakeDecodeTables(Table, (int)(NC + DC + LDC), BlockTables.RD, RC);
return true;
}
}

View File

@@ -24,11 +24,7 @@ internal partial class Unpack
// Check TablesRead5 to be sure that we read tables at least once
// regardless of current block header TablePresent flag.
// So we can safefly use these tables below.
if (
!ReadBlockHeader(Inp, ref BlockHeader)
|| !ReadTables(Inp, ref BlockHeader, ref BlockTables)
|| !TablesRead5
)
if (!ReadBlockHeader(Inp) || !ReadTables(Inp) || !TablesRead5)
{
return;
}
@@ -55,10 +51,7 @@ internal partial class Unpack
FileDone = true;
break;
}
if (
!ReadBlockHeader(Inp, ref BlockHeader)
|| !ReadTables(Inp, ref BlockHeader, ref BlockTables)
)
if (!ReadBlockHeader(Inp) || !ReadTables(Inp))
{
return;
}
@@ -216,180 +209,6 @@ internal partial class Unpack
UnpWriteBuf();
}
private async System.Threading.Tasks.Task Unpack5Async(
bool Solid,
System.Threading.CancellationToken cancellationToken = default
)
{
FileExtracted = true;
if (!Suspended)
{
UnpInitData(Solid);
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
return;
}
if (
!ReadBlockHeader(Inp, ref BlockHeader)
|| !ReadTables(Inp, ref BlockHeader, ref BlockTables)
|| !TablesRead5
)
{
return;
}
}
while (true)
{
UnpPtr &= MaxWinMask;
if (Inp.InAddr >= ReadBorder)
{
var FileDone = false;
while (
Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1
|| Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1
&& Inp.InBit >= BlockHeader.BlockBitSize
)
{
if (BlockHeader.LastBlockInFile)
{
FileDone = true;
break;
}
if (
!ReadBlockHeader(Inp, ref BlockHeader)
|| !ReadTables(Inp, ref BlockHeader, ref BlockTables)
)
{
return;
}
}
if (FileDone || !await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
break;
}
}
if (((WriteBorder - UnpPtr) & MaxWinMask) < MAX_LZ_MATCH + 3 && WriteBorder != UnpPtr)
{
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
if (WrittenFileSize > DestUnpSize)
{
return;
}
}
uint MainSlot = DecodeNumber(Inp, BlockTables.LD);
if (MainSlot < 256)
{
if (Fragmented)
{
FragWindow[UnpPtr++] = (byte)MainSlot;
}
else
{
Window[UnpPtr++] = (byte)MainSlot;
}
continue;
}
if (MainSlot >= 262)
{
uint Length = SlotToLength(Inp, MainSlot - 262);
uint DBits,
Distance = 1,
DistSlot = DecodeNumber(Inp, BlockTables.DD);
if (DistSlot < 4)
{
DBits = 0;
Distance += DistSlot;
}
else
{
DBits = (DistSlot / 2) - 1;
Distance += (2 | (DistSlot & 1)) << (int)DBits;
}
if (DBits > 0)
{
if (DBits >= 4)
{
if (DBits > 4)
{
Distance += ((Inp.getbits() >> (int)(20 - DBits)) << 4);
Inp.addbits(DBits - 4);
}
uint LowDist = DecodeNumber(Inp, BlockTables.LDD);
Distance += LowDist;
}
else
{
Distance += Inp.getbits() >> (int)(16 - DBits);
Inp.addbits(DBits);
}
}
if (Distance > 0x100)
{
Length++;
if (Distance > 0x2000)
{
Length++;
if (Distance > 0x40000)
{
Length++;
}
}
}
InsertOldDist(Distance);
LastLength = Length;
CopyString(Length, Distance);
continue;
}
if (MainSlot == 256)
{
var Filter = new UnpackFilter();
if (!ReadFilter(Inp, Filter) || !AddFilter(Filter))
{
break;
}
continue;
}
if (MainSlot == 257)
{
if (LastLength != 0)
{
CopyString((uint)LastLength, (uint)OldDist[0]);
}
continue;
}
if (MainSlot < 262)
{
uint DistNum = MainSlot - 258;
uint Distance = (uint)OldDist[(int)DistNum];
for (var I = (int)DistNum; I > 0; I--)
{
OldDist[I] = OldDist[I - 1];
}
OldDist[0] = Distance;
uint LengthSlot = DecodeNumber(Inp, BlockTables.RD);
uint Length = SlotToLength(Inp, LengthSlot);
LastLength = Length;
CopyString(Length, Distance);
continue;
}
}
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
}
private uint ReadFilterData(BitInput Inp)
{
var ByteCount = (Inp.fgetbits() >> 14) + 1;
@@ -507,58 +326,6 @@ internal partial class Unpack
return ReadCode != -1;
}
private async System.Threading.Tasks.Task<bool> UnpReadBufAsync(
System.Threading.CancellationToken cancellationToken = default
)
{
var DataSize = ReadTop - Inp.InAddr; // Data left to process.
if (DataSize < 0)
{
return false;
}
BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart;
if (Inp.InAddr > MAX_SIZE / 2)
{
if (DataSize > 0)
{
Buffer.BlockCopy(Inp.InBuf, Inp.InAddr, Inp.InBuf, 0, DataSize);
}
Inp.InAddr = 0;
ReadTop = DataSize;
}
else
{
DataSize = ReadTop;
}
var ReadCode = 0;
if (MAX_SIZE != DataSize)
{
ReadCode = await UnpIO_UnpReadAsync(
Inp.InBuf,
DataSize,
MAX_SIZE - DataSize,
cancellationToken
)
.ConfigureAwait(false);
}
if (ReadCode > 0) // Can be also -1.
{
ReadTop += ReadCode;
}
ReadBorder = ReadTop - 30;
BlockHeader.BlockStart = Inp.InAddr;
if (BlockHeader.BlockSize != -1) // '-1' means not defined yet.
{
ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1);
}
return ReadCode != -1;
}
private void UnpWriteBuf()
{
var WrittenBorder = WrPtr;
@@ -753,163 +520,6 @@ internal partial class Unpack
}
}
private async System.Threading.Tasks.Task UnpWriteBufAsync(
System.Threading.CancellationToken cancellationToken = default
)
{
var WrittenBorder = WrPtr;
var FullWriteSize = (UnpPtr - WrittenBorder) & MaxWinMask;
var WriteSizeLeft = FullWriteSize;
var NotAllFiltersProcessed = false;
for (var I = 0; I < Filters.Count; I++)
{
var flt = Filters[I];
if (flt.Type == FILTER_NONE)
{
continue;
}
if (flt.NextWindow)
{
if (((flt.BlockStart - WrPtr) & MaxWinMask) <= FullWriteSize)
{
flt.NextWindow = false;
}
continue;
}
var BlockStart = flt.BlockStart;
var BlockLength = flt.BlockLength;
if (((BlockStart - WrittenBorder) & MaxWinMask) < WriteSizeLeft)
{
if (WrittenBorder != BlockStart)
{
await UnpWriteAreaAsync(WrittenBorder, BlockStart, cancellationToken)
.ConfigureAwait(false);
WrittenBorder = BlockStart;
WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask;
}
if (BlockLength <= WriteSizeLeft)
{
if (BlockLength > 0)
{
var BlockEnd = (BlockStart + BlockLength) & MaxWinMask;
FilterSrcMemory = EnsureCapacity(
FilterSrcMemory,
checked((int)BlockLength)
);
var Mem = FilterSrcMemory;
if (BlockStart < BlockEnd || BlockEnd == 0)
{
if (Fragmented)
{
FragWindow.CopyData(Mem, 0, BlockStart, BlockLength);
}
else
{
Buffer.BlockCopy(Window, (int)BlockStart, Mem, 0, (int)BlockLength);
}
}
else
{
var FirstPartLength = MaxWinSize - BlockStart;
if (Fragmented)
{
FragWindow.CopyData(Mem, 0, BlockStart, FirstPartLength);
FragWindow.CopyData(Mem, FirstPartLength, 0, BlockEnd);
}
else
{
Buffer.BlockCopy(
Window,
(int)BlockStart,
Mem,
0,
(int)FirstPartLength
);
Buffer.BlockCopy(
Window,
0,
Mem,
(int)FirstPartLength,
(int)BlockEnd
);
}
}
var OutMem = ApplyFilter(Mem, BlockLength, flt);
Filters[I].Type = FILTER_NONE;
if (OutMem != null)
{
await UnpIO_UnpWriteAsync(OutMem, 0, BlockLength, cancellationToken)
.ConfigureAwait(false);
WrittenFileSize += BlockLength;
}
WrittenBorder = BlockEnd;
WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask;
}
}
else
{
NotAllFiltersProcessed = true;
for (var J = I; J < Filters.Count; J++)
{
var fltj = Filters[J];
if (
fltj.Type != FILTER_NONE
&& fltj.NextWindow == false
&& ((fltj.BlockStart - WrPtr) & MaxWinMask) < FullWriteSize
)
{
fltj.NextWindow = true;
}
}
break;
}
}
}
var EmptyCount = 0;
for (var I = 0; I < Filters.Count; I++)
{
if (EmptyCount > 0)
{
Filters[I - EmptyCount] = Filters[I];
}
if (Filters[I].Type == FILTER_NONE)
{
EmptyCount++;
}
}
if (EmptyCount > 0)
{
Filters.RemoveRange(Filters.Count - EmptyCount, EmptyCount);
}
if (!NotAllFiltersProcessed)
{
await UnpWriteAreaAsync(WrittenBorder, UnpPtr, cancellationToken).ConfigureAwait(false);
WrPtr = UnpPtr;
}
WriteBorder = (UnpPtr + Math.Min(MaxWinSize, UNPACK_MAX_WRITE)) & MaxWinMask;
if (
WriteBorder == UnpPtr
|| WrPtr != UnpPtr
&& ((WrPtr - UnpPtr) & MaxWinMask) < ((WriteBorder - UnpPtr) & MaxWinMask)
)
{
WriteBorder = WrPtr;
}
}
private byte[] ApplyFilter(byte[] __d, uint DataSize, UnpackFilter Flt)
{
var Data = 0;
@@ -1041,48 +651,6 @@ internal partial class Unpack
}
}
private async System.Threading.Tasks.Task UnpWriteAreaAsync(
size_t StartPtr,
size_t EndPtr,
System.Threading.CancellationToken cancellationToken = default
)
{
if (EndPtr != StartPtr)
{
UnpSomeRead = true;
}
if (EndPtr < StartPtr)
{
UnpAllBuf = true;
}
if (Fragmented)
{
var SizeToWrite = (EndPtr - StartPtr) & MaxWinMask;
while (SizeToWrite > 0)
{
var BlockSize = FragWindow.GetBlockSize(StartPtr, SizeToWrite);
FragWindow.GetBuffer(StartPtr, out var __buffer, out var __offset);
await UnpWriteDataAsync(__buffer, __offset, BlockSize, cancellationToken)
.ConfigureAwait(false);
SizeToWrite -= BlockSize;
StartPtr = (StartPtr + BlockSize) & MaxWinMask;
}
}
else if (EndPtr < StartPtr)
{
await UnpWriteDataAsync(Window, StartPtr, MaxWinSize - StartPtr, cancellationToken)
.ConfigureAwait(false);
await UnpWriteDataAsync(Window, 0, EndPtr, cancellationToken).ConfigureAwait(false);
}
else
{
await UnpWriteDataAsync(Window, StartPtr, EndPtr - StartPtr, cancellationToken)
.ConfigureAwait(false);
}
}
private void UnpWriteData(byte[] Data, size_t offset, size_t Size)
{
if (WrittenFileSize >= DestUnpSize)
@@ -1101,29 +669,6 @@ internal partial class Unpack
WrittenFileSize += Size;
}
private async System.Threading.Tasks.Task UnpWriteDataAsync(
byte[] Data,
size_t offset,
size_t Size,
System.Threading.CancellationToken cancellationToken = default
)
{
if (WrittenFileSize >= DestUnpSize)
{
return;
}
var WriteSize = Size;
var LeftToWrite = DestUnpSize - WrittenFileSize;
if (WriteSize > LeftToWrite)
{
WriteSize = (size_t)LeftToWrite;
}
await UnpIO_UnpWriteAsync(Data, offset, WriteSize, cancellationToken).ConfigureAwait(false);
WrittenFileSize += Size;
}
private void UnpInitData50(bool Solid)
{
if (!Solid)
@@ -1132,9 +677,9 @@ internal partial class Unpack
}
}
private bool ReadBlockHeader(BitInput Inp, ref UnpackBlockHeader Header)
private bool ReadBlockHeader(BitInput Inp)
{
Header.HeaderSize = 0;
BlockHeader.HeaderSize = 0;
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7)
{
@@ -1155,9 +700,9 @@ internal partial class Unpack
return false;
}
Header.HeaderSize = (int)(2 + ByteCount);
BlockHeader.HeaderSize = (int)(2 + ByteCount);
Header.BlockBitSize = (BlockFlags & 7) + 1;
BlockHeader.BlockBitSize = (BlockFlags & 7) + 1;
var SavedCheckSum = (byte)(Inp.fgetbits() >> 8);
Inp.faddbits(8);
@@ -1169,28 +714,24 @@ internal partial class Unpack
Inp.addbits(8);
}
Header.BlockSize = BlockSize;
BlockHeader.BlockSize = BlockSize;
var CheckSum = (byte)(0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16));
if (CheckSum != SavedCheckSum)
{
return false;
}
Header.BlockStart = Inp.InAddr;
ReadBorder = Math.Min(ReadBorder, Header.BlockStart + Header.BlockSize - 1);
BlockHeader.BlockStart = Inp.InAddr;
ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1);
Header.LastBlockInFile = (BlockFlags & 0x40) != 0;
Header.TablePresent = (BlockFlags & 0x80) != 0;
BlockHeader.LastBlockInFile = (BlockFlags & 0x40) != 0;
BlockHeader.TablePresent = (BlockFlags & 0x80) != 0;
return true;
}
private bool ReadTables(
BitInput Inp,
ref UnpackBlockHeader Header,
ref UnpackBlockTables Tables
)
private bool ReadTables(BitInput Inp)
{
if (!Header.TablePresent)
if (!BlockHeader.TablePresent)
{
return true;
}
@@ -1233,7 +774,7 @@ internal partial class Unpack
}
}
MakeDecodeTables(BitLength, 0, Tables.BD, BC);
MakeDecodeTables(BitLength, 0, BlockTables.BD, BC);
Span<byte> Table = stackalloc byte[checked((int)HUFF_TABLE_SIZE)];
const int TableSize = checked((int)HUFF_TABLE_SIZE);
@@ -1247,7 +788,7 @@ internal partial class Unpack
}
}
var Number = DecodeNumber(Inp, Tables.BD);
var Number = DecodeNumber(Inp, BlockTables.BD);
if (Number < 16)
{
Table[I] = (byte)Number;
@@ -1309,10 +850,10 @@ internal partial class Unpack
return false;
}
MakeDecodeTables(Table, 0, Tables.LD, NC);
MakeDecodeTables(Table, (int)NC, Tables.DD, DC);
MakeDecodeTables(Table, (int)(NC + DC), Tables.LDD, LDC);
MakeDecodeTables(Table, (int)(NC + DC + LDC), Tables.RD, RC);
MakeDecodeTables(Table, 0, BlockTables.LD, NC);
MakeDecodeTables(Table, (int)NC, BlockTables.DD, DC);
MakeDecodeTables(Table, (int)(NC + DC), BlockTables.LDD, LDC);
MakeDecodeTables(Table, (int)(NC + DC + LDC), BlockTables.RD, RC);
return true;
}

View File

@@ -2,6 +2,8 @@
using System;
using System.Buffers;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef;
using static SharpCompress.Compressors.Rar.UnpackV2017.UnpackGlobal;
@@ -196,10 +198,10 @@ internal sealed partial class Unpack : BitInput
}
}
private async System.Threading.Tasks.Task DoUnpackAsync(
private async Task DoUnpackAsync(
uint Method,
bool Solid,
System.Threading.CancellationToken cancellationToken = default
CancellationToken cancellationToken = default
)
{
// Methods <50 will crash in Fragmented mode when accessing NULL Window.

View File

@@ -19,7 +19,7 @@ internal class BitStream
31U,
63U,
(uint)sbyte.MaxValue,
byte.MaxValue,
(uint)byte.MaxValue,
511U,
1023U,
2047U,
@@ -27,7 +27,7 @@ internal class BitStream
8191U,
16383U,
(uint)short.MaxValue,
ushort.MaxValue,
(uint)ushort.MaxValue,
};
public BitStream(byte[] src, int srcLen)
@@ -62,7 +62,7 @@ internal class BitStream
_bitsLeft += 8;
}
}
result = (int)(_bitBuffer & _maskBits[nbits]);
result = (int)((long)_bitBuffer & (long)_maskBits[nbits]);
_bitBuffer >>= nbits;
_bitsLeft -= nbits;
return result;

View File

@@ -7,6 +7,7 @@ namespace SharpCompress.Compressors.Shrink;
internal partial class ShrinkStream : Stream
{
private Stream inStream;
private CompressionMode _compressionMode;
private ulong _compressedSize;
private long _uncompressedSize;
@@ -23,6 +24,7 @@ internal partial class ShrinkStream : Stream
)
{
inStream = stream;
_compressionMode = compressionMode;
_compressedSize = (ulong)compressedSize;
_uncompressedSize = uncompressedSize;

View File

@@ -10,6 +10,7 @@ namespace SharpCompress.Compressors.Squeezed;
public partial class SqueezeStream : Stream
{
private readonly Stream _stream;
private readonly int _compressedSize;
private const int NUMVALS = 257;
private const int SPEOF = 256;
@@ -18,6 +19,7 @@ public partial class SqueezeStream : Stream
private SqueezeStream(Stream stream, int compressedSize)
{
_stream = stream ?? throw new ArgumentNullException(nameof(stream));
_compressedSize = compressedSize;
}
public static SqueezeStream Create(Stream stream, int compressedSize)
@@ -61,41 +63,43 @@ public partial class SqueezeStream : Stream
private Stream BuildDecodedStream()
{
using var binaryReader = new BinaryReader(_stream, Encoding.Default, leaveOpen: true);
int numnodes = binaryReader.ReadUInt16();
if (numnodes >= NUMVALS || numnodes == 0)
using (var binaryReader = new BinaryReader(_stream, Encoding.Default, leaveOpen: true))
{
return new MemoryStream(Array.Empty<byte>());
}
int numnodes = binaryReader.ReadUInt16();
var dnode = new int[numnodes, 2];
for (int j = 0; j < numnodes; j++)
{
dnode[j, 0] = binaryReader.ReadInt16();
dnode[j, 1] = binaryReader.ReadInt16();
}
var bitReader = new BitReader(_stream);
var huffmanDecoded = new MemoryStream();
int i = 0;
while (true)
{
i = dnode[i, bitReader.ReadBit() ? 1 : 0];
if (i < 0)
if (numnodes >= NUMVALS || numnodes == 0)
{
i = -(i + 1);
if (i == SPEOF)
{
break;
}
huffmanDecoded.WriteByte((byte)i);
i = 0;
return new MemoryStream(Array.Empty<byte>());
}
}
huffmanDecoded.Position = 0;
return new RunLength90Stream(huffmanDecoded, (int)huffmanDecoded.Length);
var dnode = new int[numnodes, 2];
for (int j = 0; j < numnodes; j++)
{
dnode[j, 0] = binaryReader.ReadInt16();
dnode[j, 1] = binaryReader.ReadInt16();
}
var bitReader = new BitReader(_stream);
var huffmanDecoded = new MemoryStream();
int i = 0;
while (true)
{
i = dnode[i, bitReader.ReadBit() ? 1 : 0];
if (i < 0)
{
i = -(i + 1);
if (i == SPEOF)
{
break;
}
huffmanDecoded.WriteByte((byte)i);
i = 0;
}
}
huffmanDecoded.Position = 0;
return new RunLength90Stream(huffmanDecoded, (int)huffmanDecoded.Length);
}
}
}

View File

@@ -40,12 +40,12 @@ public abstract class BlockFilter : ReadOnlyStream
public static BlockFilter Read(BinaryReader reader)
{
var filterType = (FilterTypes)reader.ReadXZInteger();
if (!FILTER_MAP.TryGetValue(filterType, out var createFilter))
if (!FILTER_MAP.ContainsKey(filterType))
{
throw new NotImplementedException($"Filter {filterType} has not yet been implemented");
}
var filter = createFilter();
var filter = FILTER_MAP[filterType]();
var sizeOfProperties = reader.ReadXZInteger();
if (sizeOfProperties > int.MaxValue)

View File

@@ -10,18 +10,18 @@ internal static partial class MultiByteIntegers
{
public static async ValueTask<ulong> ReadXZIntegerAsync(
this BinaryReader reader,
int maxBytes = 9,
CancellationToken cancellationToken = default
CancellationToken cancellationToken = default,
int MaxBytes = 9
)
{
if (maxBytes <= 0)
if (MaxBytes <= 0)
{
throw new ArgumentOutOfRangeException(nameof(maxBytes));
throw new ArgumentOutOfRangeException(nameof(MaxBytes));
}
if (maxBytes > 9)
if (MaxBytes > 9)
{
maxBytes = 9;
MaxBytes = 9;
}
var LastByte = await reader.ReadByteAsync(cancellationToken).ConfigureAwait(false);
@@ -30,7 +30,7 @@ internal static partial class MultiByteIntegers
var i = 0;
while ((LastByte & 0x80) != 0)
{
if (++i >= maxBytes)
if (++i >= MaxBytes)
{
throw new InvalidFormatException();
}

View File

@@ -19,6 +19,7 @@ public sealed partial class XZBlock : XZReadOnlyStream
public ulong? UncompressedSize { get; private set; }
public Stack<BlockFilter> Filters { get; private set; } = new();
public bool HeaderIsLoaded { get; private set; }
private CheckType _checkType;
private readonly int _checkSize;
private bool _streamConnected;
private int _numFilters;
@@ -32,6 +33,7 @@ public sealed partial class XZBlock : XZReadOnlyStream
public XZBlock(Stream stream, CheckType checkType, int checkSize)
: base(stream)
{
_checkType = checkType;
_checkSize = checkSize;
_startPosition = stream.Position;
}

View File

@@ -33,9 +33,7 @@ public partial class XZIndex
await VerifyIndexMarkerAsync(cancellationToken).ConfigureAwait(false);
}
NumberOfRecords = await _reader
.ReadXZIntegerAsync(cancellationToken: cancellationToken)
.ConfigureAwait(false);
NumberOfRecords = await _reader.ReadXZIntegerAsync(cancellationToken).ConfigureAwait(false);
for (ulong i = 0; i < NumberOfRecords; i++)
{
Records.Add(

View File

@@ -13,9 +13,8 @@ public partial class XZIndexRecord
)
{
var record = new XZIndexRecord();
record.UnpaddedSize = await br.ReadXZIntegerAsync(cancellationToken: cancellationToken)
.ConfigureAwait(false);
record.UncompressedSize = await br.ReadXZIntegerAsync(cancellationToken: cancellationToken)
record.UnpaddedSize = await br.ReadXZIntegerAsync(cancellationToken).ConfigureAwait(false);
record.UncompressedSize = await br.ReadXZIntegerAsync(cancellationToken)
.ConfigureAwait(false);
return record;
}

View File

@@ -12,7 +12,10 @@ namespace SharpCompress.Compressors.Xz;
public sealed partial class XZStream : XZReadOnlyStream
{
public XZStream(Stream baseStream)
: base(baseStream) { }
: base(baseStream)
{
_baseStream = baseStream;
}
protected override void Dispose(bool disposing)
{
@@ -45,6 +48,7 @@ public sealed partial class XZStream : XZReadOnlyStream
}
}
private readonly Stream _baseStream;
public XZHeader Header { get; private set; }
public XZIndex Index { get; private set; }
public XZFooter Footer { get; private set; }

View File

@@ -16,13 +16,6 @@ public partial class CompressionStream : Stream
{
if (compressor == null)
{
#if LEGACY_DOTNET
Dispose(true);
GC.SuppressFinalize(this);
await Task.CompletedTask.ConfigureAwait(false);
#else
await base.DisposeAsync().ConfigureAwait(false);
#endif
return;
}
@@ -35,12 +28,6 @@ public partial class CompressionStream : Stream
ReleaseUnmanagedResources();
GC.SuppressFinalize(this);
}
#if LEGACY_DOTNET
Dispose(true);
await Task.CompletedTask.ConfigureAwait(false);
#else
await base.DisposeAsync().ConfigureAwait(false);
#endif
}
public override async Task FlushAsync(CancellationToken cancellationToken) =>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Buffers;
using System.IO;
using System.Threading;
@@ -84,7 +84,6 @@ public partial class CompressionStream : Stream
{
if (compressor == null)
{
base.Dispose(disposing);
return;
}
@@ -99,7 +98,6 @@ public partial class CompressionStream : Stream
{
ReleaseUnmanagedResources();
}
base.Dispose(disposing);
}
private void ReleaseUnmanagedResources()
@@ -123,8 +121,7 @@ public partial class CompressionStream : Stream
public override void Flush() => FlushInternal(ZSTD_EndDirective.ZSTD_e_flush);
private void FlushInternal(ZSTD_EndDirective directive) =>
WriteInternal(ReadOnlySpan<byte>.Empty, directive);
private void FlushInternal(ZSTD_EndDirective directive) => WriteInternal(null, directive);
public override void Write(byte[] buffer, int offset, int count) =>
Write(new ReadOnlySpan<byte>(buffer, offset, count));
@@ -141,7 +138,11 @@ public partial class CompressionStream : Stream
{
EnsureNotDisposed();
var input = new ZSTD_inBuffer_s { pos = 0, size = (nuint)buffer.Length };
var input = new ZSTD_inBuffer_s
{
pos = 0,
size = buffer != null ? (nuint)buffer.Length : 0,
};
nuint remaining;
do
{

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Buffers;
using System.IO;
using System.Threading;
@@ -90,7 +90,6 @@ public partial class DecompressionStream : Stream
{
if (decompressor == null)
{
base.Dispose(disposing);
return;
}
@@ -109,7 +108,6 @@ public partial class DecompressionStream : Stream
{
innerStream.Dispose();
}
base.Dispose(disposing);
}
public override int Read(byte[] buffer, int offset, int count) =>

View File

@@ -32,7 +32,7 @@ internal abstract unsafe class SafeZstdHandle : SafeHandle
internal sealed unsafe class SafeCctxHandle : SafeZstdHandle
{
/// <inheritdoc/>
internal SafeCctxHandle() { }
private SafeCctxHandle() { }
/// <summary>
/// Creates a new instance of <see cref="SafeCctxHandle"/>.
@@ -85,7 +85,7 @@ internal sealed unsafe class SafeCctxHandle : SafeZstdHandle
internal sealed unsafe class SafeDctxHandle : SafeZstdHandle
{
/// <inheritdoc/>
internal SafeDctxHandle() { }
private SafeDctxHandle() { }
/// <summary>
/// Creates a new instance of <see cref="SafeDctxHandle"/>.

View File

@@ -63,12 +63,26 @@ public class GZipFactory
GZipArchive.OpenArchive(stream, readerOptions);
/// <inheritdoc/>
public IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null) =>
(IAsyncArchive)OpenArchive(stream, readerOptions);
public ValueTask<IAsyncArchive> OpenAsyncArchive(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return new((IAsyncArchive)OpenArchive(stream, readerOptions));
}
/// <inheritdoc/>
public IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
(IAsyncArchive)OpenArchive(fileInfo, readerOptions);
public ValueTask<IAsyncArchive> OpenAsyncArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return new((IAsyncArchive)OpenArchive(fileInfo, readerOptions));
}
#endregion

View File

@@ -87,7 +87,7 @@ public class LzwFactory : Factory, IReaderFactory
)
{
cancellationToken.ThrowIfCancellationRequested();
return new(LzwReader.OpenAsyncReader(stream, options));
return LzwReader.OpenAsyncReader(stream, options);
}
#endregion

View File

@@ -54,16 +54,30 @@ public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReade
RarArchive.OpenArchive(stream, readerOptions);
/// <inheritdoc/>
public IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null) =>
(IAsyncArchive)OpenArchive(stream, readerOptions);
public ValueTask<IAsyncArchive> OpenAsyncArchive(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return new((IAsyncArchive)OpenArchive(stream, readerOptions));
}
/// <inheritdoc/>
public IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
RarArchive.OpenArchive(fileInfo, readerOptions);
/// <inheritdoc/>
public IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
(IAsyncArchive)OpenArchive(fileInfo, readerOptions);
public ValueTask<IAsyncArchive> OpenAsyncArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return new((IAsyncArchive)OpenArchive(fileInfo, readerOptions));
}
#endregion

View File

@@ -49,16 +49,30 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory
SevenZipArchive.OpenArchive(stream, readerOptions);
/// <inheritdoc/>
public IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null) =>
SevenZipArchive.OpenAsyncArchive(stream, readerOptions);
public ValueTask<IAsyncArchive> OpenAsyncArchive(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return new((IAsyncArchive)OpenArchive(stream, readerOptions));
}
/// <inheritdoc/>
public IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
SevenZipArchive.OpenArchive(fileInfo, readerOptions);
/// <inheritdoc/>
public IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
SevenZipArchive.OpenAsyncArchive(fileInfo, readerOptions);
public ValueTask<IAsyncArchive> OpenAsyncArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return new((IAsyncArchive)OpenArchive(fileInfo, readerOptions));
}
#endregion
@@ -74,7 +88,7 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory
public IAsyncArchive OpenAsyncArchive(
IReadOnlyList<Stream> streams,
ReaderOptions? readerOptions = null
) => SevenZipArchive.OpenAsyncArchive(streams, readerOptions);
) => (IAsyncArchive)OpenArchive(streams, readerOptions);
/// <inheritdoc/>
public IArchive OpenArchive(
@@ -86,7 +100,7 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory
public IAsyncArchive OpenAsyncArchive(
IReadOnlyList<FileInfo> fileInfos,
ReaderOptions? readerOptions = null
) => SevenZipArchive.OpenAsyncArchive(fileInfos, readerOptions);
) => (IAsyncArchive)OpenArchive(fileInfos, readerOptions);
#endregion

View File

@@ -109,6 +109,51 @@ public class TarFactory
#endregion
public static CompressionType GetCompressionType(Stream stream)
{
stream.Seek(0, SeekOrigin.Begin);
foreach (var wrapper in TarWrapper.Wrappers)
{
stream.Seek(0, SeekOrigin.Begin);
if (wrapper.IsMatch(stream))
{
stream.Seek(0, SeekOrigin.Begin);
var decompressedStream = wrapper.CreateStream(stream);
if (TarArchive.IsTarFile(decompressedStream))
{
return wrapper.CompressionType;
}
}
}
throw new InvalidFormatException("Not a tar file.");
}
public static async ValueTask<CompressionType> GetCompressionTypeAsync(
Stream stream,
CancellationToken cancellationToken = default
)
{
stream.Seek(0, SeekOrigin.Begin);
foreach (var wrapper in TarWrapper.Wrappers)
{
stream.Seek(0, SeekOrigin.Begin);
if (wrapper.IsMatch(stream))
{
stream.Seek(0, SeekOrigin.Begin);
var decompressedStream = wrapper.CreateStream(stream);
if (
await TarArchive
.IsTarFileAsync(decompressedStream, cancellationToken)
.ConfigureAwait(false)
)
{
return wrapper.CompressionType;
}
}
}
throw new InvalidFormatException("Not a tar file.");
}
#region IArchiveFactory
/// <inheritdoc/>
@@ -116,16 +161,28 @@ public class TarFactory
TarArchive.OpenArchive(stream, readerOptions);
/// <inheritdoc/>
public IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null) =>
(IAsyncArchive)OpenArchive(stream, readerOptions);
public async ValueTask<IAsyncArchive> OpenAsyncArchive(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
) =>
await TarArchive
.OpenAsyncArchive(stream, readerOptions, cancellationToken)
.ConfigureAwait(false);
/// <inheritdoc/>
public IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
TarArchive.OpenArchive(fileInfo, readerOptions);
/// <inheritdoc/>
public IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
(IAsyncArchive)OpenArchive(fileInfo, readerOptions);
public async ValueTask<IAsyncArchive> OpenAsyncArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
) =>
await TarArchive
.OpenAsyncArchive(fileInfo, readerOptions, cancellationToken)
.ConfigureAwait(false);
#endregion

View File

@@ -127,16 +127,30 @@ public class ZipFactory
ZipArchive.OpenArchive(stream, readerOptions);
/// <inheritdoc/>
public IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null) =>
(IAsyncArchive)OpenArchive(stream, readerOptions);
public ValueTask<IAsyncArchive> OpenAsyncArchive(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return new((IAsyncArchive)OpenArchive(stream, readerOptions));
}
/// <inheritdoc/>
public IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
ZipArchive.OpenArchive(fileInfo, readerOptions);
/// <inheritdoc/>
public IAsyncArchive OpenAsyncArchive(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
(IAsyncArchive)OpenArchive(fileInfo, readerOptions);
public ValueTask<IAsyncArchive> OpenAsyncArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return new((IAsyncArchive)OpenArchive(fileInfo, readerOptions));
}
#endregion

View File

@@ -275,7 +275,6 @@ internal partial class SharpCompressStream
_ringBuffer?.Dispose();
_ringBuffer = null;
}
await base.DisposeAsync().ConfigureAwait(false);
}
#endif
}

View File

@@ -63,11 +63,7 @@ internal static class NotNullExtensions
)
where T : struct
{
if (!obj.HasValue)
{
throw new ArgumentNullException(paramName);
}
ArgumentNullException.ThrowIfNull(obj, paramName);
return obj.Value;
}
#endif

View File

@@ -1,5 +1,7 @@
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
namespace SharpCompress.Readers.Ace;
@@ -33,15 +35,25 @@ public partial class AceReader
return new MultiVolumeAceReader(streams, options ?? new ReaderOptions());
}
public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null)
public static ValueTask<IAsyncReader> OpenAsyncReader(
string path,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
path.NotNullOrEmpty(nameof(path));
return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions);
return new((IAsyncReader)OpenReader(new FileInfo(path), readerOptions));
}
public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null)
public static ValueTask<IAsyncReader> OpenAsyncReader(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
return (IAsyncReader)OpenReader(stream, readerOptions);
cancellationToken.ThrowIfCancellationRequested();
return new((IAsyncReader)OpenReader(stream, readerOptions));
}
public static IAsyncReader OpenAsyncReader(
@@ -53,12 +65,14 @@ public partial class AceReader
return new MultiVolumeAceReader(streams, options ?? new ReaderOptions());
}
public static IAsyncReader OpenAsyncReader(
public static ValueTask<IAsyncReader> OpenAsyncReader(
FileInfo fileInfo,
ReaderOptions? readerOptions = null
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
return (IAsyncReader)OpenReader(fileInfo, readerOptions);
cancellationToken.ThrowIfCancellationRequested();
return new((IAsyncReader)OpenReader(fileInfo, readerOptions));
}
public static IReader OpenReader(string filePath, ReaderOptions? readerOptions = null)

View File

@@ -1,28 +1,42 @@
#if NET8_0_OR_GREATER
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
namespace SharpCompress.Readers.Arc;
public partial class ArcReader : IReaderOpenable
{
public static IAsyncReader OpenAsyncReader(string path, ReaderOptions? readerOptions = null)
{
path.NotNullOrEmpty(nameof(path));
return (IAsyncReader)OpenReader(new FileInfo(path), readerOptions);
}
public static IAsyncReader OpenAsyncReader(Stream stream, ReaderOptions? readerOptions = null)
{
return (IAsyncReader)OpenReader(stream, readerOptions);
}
public static IAsyncReader OpenAsyncReader(
FileInfo fileInfo,
ReaderOptions? readerOptions = null
public static ValueTask<IAsyncReader> OpenAsyncReader(
string path,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
return (IAsyncReader)OpenReader(fileInfo, readerOptions);
cancellationToken.ThrowIfCancellationRequested();
path.NotNullOrEmpty(nameof(path));
return new((IAsyncReader)OpenReader(new FileInfo(path), readerOptions));
}
public static ValueTask<IAsyncReader> OpenAsyncReader(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return new((IAsyncReader)OpenReader(stream, readerOptions));
}
public static ValueTask<IAsyncReader> OpenAsyncReader(
FileInfo fileInfo,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return new((IAsyncReader)OpenReader(fileInfo, readerOptions));
}
public static IReader OpenReader(string filePath, ReaderOptions? readerOptions = null)

Some files were not shown because too many files have changed in this diff Show More