Merge pull request #1321 from adamhathcock/adam/some-cleanup

This commit is contained in:
Adam Hathcock 2026-05-13 16:03:37 +01:00 committed by GitHub
commit 55393ca73c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 122 additions and 140 deletions

2
.gitignore vendored
View file

@ -24,4 +24,4 @@ profiler-snapshots/
.DS_Store
*.snupkg
benchmark-results/
/.opencode
.opencode/

View file

@ -9,7 +9,7 @@ internal static partial class IEntryExtensions
{
extension(IEntry entry)
{
public async ValueTask WriteEntryToDirectoryAsync(
internal async ValueTask WriteEntryToDirectoryAsync(
string destinationDirectory,
ExtractionOptions? options,
Func<string, CancellationToken, ValueTask> writeAsync,

View file

@ -10,7 +10,7 @@ internal static partial class IEntryExtensions
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
public void WriteEntryToDirectory(
internal void WriteEntryToDirectory(
string destinationDirectory,
ExtractionOptions? options,
Action<string> write

View file

@ -239,7 +239,7 @@ internal partial class Unpack
{
Header.HeaderSize = 0;
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7)
if (Inp.InAddr > ReadTop - 7)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{
@ -292,7 +292,7 @@ internal partial class Unpack
CancellationToken cancellationToken = default
)
{
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16)
if (Inp.InAddr > ReadTop - 16)
{
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
{

View file

@ -372,7 +372,7 @@ internal partial class Unpack
private bool ReadFilter(UnpackFilter Filter)
{
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16)
if (Inp.InAddr > ReadTop - 16)
{
if (!UnpReadBuf())
{
@ -762,7 +762,7 @@ internal partial class Unpack
{
Header.HeaderSize = 0;
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7)
if (Inp.InAddr > ReadTop - 7)
{
if (!UnpReadBuf())
{

View file

@ -156,40 +156,24 @@ if (Decoded!=NULL)
//struct UnpackFilter
internal class UnpackFilter
{
public byte Type;
public uint BlockStart;
public uint BlockLength;
public byte Channels;
internal byte Type;
internal uint BlockStart;
internal uint BlockLength;
internal byte Channels;
// uint Width;
// byte PosR;
public bool NextWindow;
};
//struct UnpackFilter30
internal class UnpackFilter30
{
public uint BlockStart;
public uint BlockLength;
public bool NextWindow;
// Position of parent filter in Filters array used as prototype for filter
// in PrgStack array. Not defined for filters in Filters array.
public uint ParentFilter;
/*#if !RarV2017_RAR5ONLY
public VM_PreparedProgram Prg;
#endif*/
internal bool NextWindow;
};
internal class AudioVariables // For RAR 2.0 archives only.
{
public int K1,
internal int K1,
K2,
K3,
K4,
K5;
public int D1,
internal int D1,
D2,
D3,
D4;
@ -369,8 +353,6 @@ internal partial class Unpack
#endif*/
private int PPMEscChar;
private readonly byte[] UnpOldTable = new byte[HUFF_TABLE_SIZE30];
// If we already read decoding tables for Unpack v2,v3,v5.
// We should not use a single variable for all algorithm versions,
// because we can have a corrupt archive with one algorithm file
@ -379,26 +361,6 @@ internal partial class Unpack
private bool TablesRead2,
TablesRead5;
// Virtual machine to execute filters code.
/*#if !RarV2017_RAR5ONLY
RarVM VM;
#endif*/
// Buffer to read VM filters code. We moved it here from AddVMCode
// function to reduce time spent in BitInput constructor.
private readonly BitInput VMCodeInp = new(true);
// Filters code, one entry per filter.
private readonly List<UnpackFilter30> Filters30 = new();
// Filters stack, several entrances of same filter are possible.
private readonly List<UnpackFilter30> PrgStack = new();
// Lengths of preceding data blocks, one length of one last block
// for every filter. Used to reduce the size required to write
// the data block length if lengths are repeating.
private readonly List<int> OldFilterLengths = new();
/*#if RarV2017_RAR_SMP
// More than 8 threads are unlikely to provide a noticeable gain
// for unpacking, but would use the additional memory.

View file

@ -22,8 +22,7 @@ internal class BitInput : IDisposable
get => inBit;
set => inBit = value;
}
public bool ExternalBuffer;
private byte[] _privateBuffer = ArrayPool<byte>.Shared.Rent(MAX_SIZE);
private readonly byte[] _privateBuffer = ArrayPool<byte>.Shared.Rent(MAX_SIZE);
private bool _disposed;
/// <summary> </summary>

View file

@ -268,9 +268,9 @@
"net10.0": {
"Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[10.0.5, )",
"resolved": "10.0.5",
"contentHash": "A+5ZuQ0f449tM+MQrhf6R9ZX7lYpjk/ODEwLYKrnF6111rtARx8fVsm4YznUnQiKnnXfaXNBqgxmil6RW3L3SA=="
"requested": "[10.0.6, )",
"resolved": "10.0.6",
"contentHash": "QKuvS0LWX4fjFqeDkyM7Kqt8P3wYTiPD4nwU+9y59n0sCiG714fxDgbbN82vDnzq89AF/PiHl92TP2C4aFDUQA=="
},
"Microsoft.NETFramework.ReferenceAssemblies": {
"type": "Direct",
@ -358,9 +358,9 @@
"net8.0": {
"Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[8.0.25, )",
"resolved": "8.0.25",
"contentHash": "sqX4nmBft05ivqKvUT4nxaN8rT3apCLt9SWFkfRrQPwra1zPwFknQAw1lleuMCKOCLvVmOWwrC2iPSm9RiXZUg=="
"requested": "[8.0.26, )",
"resolved": "8.0.26",
"contentHash": "o7/yVssM2r9Wyln2s9edBd5ANZXqdSdBI+g7JqXkyJmXrhs2WsJp25K5yPnYrTgdKBCjKB8bg+O2oew4sgzFaA=="
},
"Microsoft.NETFramework.ReferenceAssemblies": {
"type": "Direct",

View file

@ -0,0 +1,83 @@
using System;
using System.IO;
using System.Threading.Tasks;
namespace SharpCompress.Test;
internal sealed class TempDirectory : IAsyncDisposable
{
private const int MaxDeleteAttempts = 5;
private static readonly TimeSpan DeleteRetryDelay = TimeSpan.FromMilliseconds(100);
public TempDirectory(string prefix)
{
Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"{prefix}.{Guid.NewGuid():N}");
Directory.CreateDirectory(Path);
}
public string Path { get; }
public string GetDirectory(string name)
{
var path = System.IO.Path.Combine(Path, name);
Directory.CreateDirectory(path);
return path;
}
public string CreateDirectory(string name)
{
var path = System.IO.Path.Combine(Path, name, System.IO.Path.GetRandomFileName());
Directory.CreateDirectory(path);
return path;
}
public void ResetDirectory(string name)
{
DeleteDirectory(System.IO.Path.Combine(Path, name));
Directory.CreateDirectory(System.IO.Path.Combine(Path, name));
}
public async ValueTask DisposeAsync()
{
for (var attempt = 1; attempt <= MaxDeleteAttempts; attempt++)
{
try
{
DeleteDirectory(Path);
if (Directory.Exists(Path))
{
throw new IOException(
$"Temp test directory '{Path}' still exists after deletion."
);
}
return;
}
catch (Exception ex)
when (IsRetryableDeleteException(ex) && attempt < MaxDeleteAttempts)
{
await Task.Delay(DeleteRetryDelay).ConfigureAwait(false);
}
catch (Exception ex) when (IsRetryableDeleteException(ex))
{
throw new InvalidOperationException(
$"Failed to clean up temp test directory '{Path}'.",
ex
);
}
}
throw new InvalidOperationException($"Temp test directory '{Path}' was not cleaned up.");
}
private static void DeleteDirectory(string path)
{
if (Directory.Exists(path))
{
Directory.Delete(path, true);
}
}
private static bool IsRetryableDeleteException(Exception ex) =>
ex is IOException or UnauthorizedAccessException;
}

View file

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Readers;
using Xunit;
@ -31,70 +30,40 @@ public class TestBase : IAsyncDisposable
MISC_TEST_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "MiscTest");
}
private readonly Guid _testGuid = Guid.NewGuid();
private readonly string _testTempDirectory;
private readonly TempDirectory _tempDirectory;
protected readonly string SCRATCH_FILES_PATH;
protected readonly string SCRATCH2_FILES_PATH;
protected TestBase()
{
_testTempDirectory = Path.Combine(Path.GetTempPath(), $"SharpCompress.Test.{_testGuid:N}");
SCRATCH_FILES_PATH = Path.Combine(_testTempDirectory, "Scratch");
SCRATCH2_FILES_PATH = Path.Combine(_testTempDirectory, "Scratch2");
Directory.CreateDirectory(SCRATCH_FILES_PATH);
Directory.CreateDirectory(SCRATCH2_FILES_PATH);
_tempDirectory = new TempDirectory("SharpCompress.Test");
SCRATCH_FILES_PATH = _tempDirectory.GetDirectory("Scratch");
SCRATCH2_FILES_PATH = _tempDirectory.GetDirectory("Scratch2");
}
//always use async dispose since we have I/O and sync Dispose doesn't wait when using xunit
public async ValueTask DisposeAsync()
{
await Task.CompletedTask;
DeleteScratchDirectory(_testTempDirectory);
}
// Always use async dispose since we have I/O and sync Dispose doesn't wait when using xunit.
public ValueTask DisposeAsync() => _tempDirectory.DisposeAsync();
public void CleanScratch()
{
ResetScratchDirectory(SCRATCH_FILES_PATH);
ResetScratchDirectory(SCRATCH2_FILES_PATH);
_tempDirectory.ResetDirectory("Scratch");
_tempDirectory.ResetDirectory("Scratch2");
}
private static void ResetScratchDirectory(string path)
{
if (Directory.Exists(path))
{
Directory.Delete(path, true);
}
protected string CreateScratchDirectory(string name) =>
_tempDirectory.CreateDirectory(Path.Combine("Scratch", name));
Directory.CreateDirectory(path);
}
protected string CreateScratch2Directory(string name) =>
_tempDirectory.CreateDirectory(Path.Combine("Scratch2", name));
private static void DeleteScratchDirectory(string path)
{
if (!Directory.Exists(path))
{
return;
}
protected string GetScratchPath(params string[] parts) =>
CombinePath(SCRATCH_FILES_PATH, parts);
try
{
Directory.Delete(path, true);
}
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
{
throw new InvalidOperationException(
$"Failed to clean up temp test directory '{path}'.",
ex
);
}
protected string GetScratch2Path(params string[] parts) =>
CombinePath(SCRATCH2_FILES_PATH, parts);
if (Directory.Exists(path))
{
throw new InvalidOperationException(
$"Temp test directory '{path}' was not cleaned up."
);
}
}
private static string CombinePath(string root, string[] parts) =>
parts.Length == 0 ? root : Path.Combine(root, Path.Combine(parts));
public void VerifyFiles()
{

View file

@ -309,30 +309,6 @@
}
}
},
".NETFramework,Version=v4.8/win-x86": {
"Microsoft.Win32.Registry": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==",
"dependencies": {
"System.Security.AccessControl": "5.0.0",
"System.Security.Principal.Windows": "5.0.0"
}
},
"System.Security.AccessControl": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==",
"dependencies": {
"System.Security.Principal.Windows": "5.0.0"
}
},
"System.Security.Principal.Windows": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA=="
}
},
"net10.0": {
"AwesomeAssertions": {
"type": "Direct",
@ -545,13 +521,6 @@
"resolved": "8.0.0",
"contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw=="
}
},
"net10.0/win-x86": {
"Microsoft.Win32.Registry": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg=="
}
}
}
}