diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index ef84a272..00b1a064 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"csharpier": {
- "version": "0.25.0",
+ "version": "0.28.1",
"commands": [
"dotnet-csharpier"
]
diff --git a/.editorconfig b/.editorconfig
index 1903a97c..eab3d428 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -70,7 +70,7 @@ indent_style = tab
[*.{cs,csx,cake,vb,vbx}]
# Default Severity for all .NET Code Style rules below
-dotnet_analyzer_diagnostic.severity = warning
+dotnet_analyzer_diagnostic.severity = silent
##########################################
# File Header (Uncomment to support file headers)
@@ -269,6 +269,8 @@ dotnet_diagnostic.CA1305.severity = suggestion
dotnet_diagnostic.CA1307.severity = suggestion
dotnet_diagnostic.CA1309.severity = suggestion
dotnet_diagnostic.CA1310.severity = error
+dotnet_diagnostic.CA1507.severity = suggestion
+dotnet_diagnostic.CA1513.severity = suggestion
dotnet_diagnostic.CA1707.severity = suggestion
dotnet_diagnostic.CA1708.severity = suggestion
dotnet_diagnostic.CA1711.severity = suggestion
@@ -286,6 +288,7 @@ dotnet_diagnostic.CA1834.severity = error
dotnet_diagnostic.CA1845.severity = suggestion
dotnet_diagnostic.CA1848.severity = suggestion
dotnet_diagnostic.CA1852.severity = suggestion
+dotnet_diagnostic.CA1860.severity = silent
dotnet_diagnostic.CA2016.severity = suggestion
dotnet_diagnostic.CA2201.severity = error
dotnet_diagnostic.CA2206.severity = error
@@ -303,13 +306,12 @@ dotnet_diagnostic.CS1998.severity = error
dotnet_diagnostic.CS8602.severity = error
dotnet_diagnostic.CS8604.severity = error
dotnet_diagnostic.CS8618.severity = error
-dotnet_diagnostic.CS0618.severity = error
+dotnet_diagnostic.CS0618.severity = suggestion
dotnet_diagnostic.CS1998.severity = error
dotnet_diagnostic.CS4014.severity = error
dotnet_diagnostic.CS8600.severity = error
dotnet_diagnostic.CS8603.severity = error
dotnet_diagnostic.CS8625.severity = error
-dotnet_diagnostic.CS8981.severity = suggestion
dotnet_diagnostic.BL0005.severity = suggestion
@@ -318,7 +320,7 @@ dotnet_diagnostic.MVC1000.severity = suggestion
dotnet_diagnostic.RZ10012.severity = error
dotnet_diagnostic.IDE0004.severity = error # redundant cast
-dotnet_diagnostic.IDE0005.severity = error
+dotnet_diagnostic.IDE0005.severity = suggestion
dotnet_diagnostic.IDE0007.severity = error # Use var
dotnet_diagnostic.IDE0011.severity = error # Use braces on if statements
dotnet_diagnostic.IDE0010.severity = silent # populate switch
@@ -329,7 +331,7 @@ dotnet_diagnostic.IDE0023.severity = suggestion # use expression body for operat
dotnet_diagnostic.IDE0024.severity = silent # expression body for operators
dotnet_diagnostic.IDE0025.severity = suggestion # use expression body for properties
dotnet_diagnostic.IDE0027.severity = suggestion # Use expression body for accessors
-dotnet_diagnostic.IDE0028.severity = silent
+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
@@ -337,7 +339,7 @@ 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
-dotnet_diagnostic.IDE0047.severity = suggestion # paratemeter name
+dotnet_diagnostic.IDE0047.severity = suggestion # parameter name
dotnet_diagnostic.IDE0051.severity = error # unused field
dotnet_diagnostic.IDE0052.severity = error # unused member
dotnet_diagnostic.IDE0053.severity = suggestion # lambda not needed
@@ -351,11 +353,20 @@ 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
dotnet_diagnostic.IDE0090.severity = suggestion # new can be simplified
-dotnet_diagnostic.IDE0130.severity = error # namespace folder structure
+dotnet_diagnostic.IDE0130.severity = suggestion # namespace folder structure
dotnet_diagnostic.IDE0160.severity = silent # Use block namespaces ARE NOT required
dotnet_diagnostic.IDE0161.severity = error # Please use file namespaces
dotnet_diagnostic.IDE0200.severity = suggestion # lambda not needed
dotnet_diagnostic.IDE1006.severity = suggestion # Naming rule violation: These words cannot contain lower case characters
+dotnet_diagnostic.IDE0260.severity = suggestion # Use pattern matching
+dotnet_diagnostic.IDE0270.severity = suggestion # Null check simplifcation
+dotnet_diagnostic.IDE0290.severity = error # Primary Constructor
+dotnet_diagnostic.IDE0300.severity = suggestion # Collection
+dotnet_diagnostic.IDE0305.severity = suggestion # Collection ToList
+
+dotnet_diagnostic.NX0001.severity = error
+dotnet_diagnostic.NX0002.severity = silent
+dotnet_diagnostic.NX0003.severity = silent
##########################################
# Styles
diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml
index 4486b23f..27d73e23 100644
--- a/.github/workflows/dotnetcore.yml
+++ b/.github/workflows/dotnetcore.yml
@@ -15,18 +15,11 @@ jobs:
steps:
- uses: actions/checkout@v4
- - uses: actions/setup-dotnet@v3
+ - uses: actions/setup-dotnet@v4
with:
- dotnet-version: 7.0.x
- - name: NuGet Caching
- uses: actions/cache@v3
- with:
- path: ~/.nuget/packages
- key: ${{ runner.os }}-nuget-${{ hashFiles('packages.lock.json', '*/packages.lock.json') }}
- restore-keys: |
- ${{ runner.os }}-nuget-
+ dotnet-version: 8.0.x
- run: dotnet run --project build/build.csproj
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
name: ${{ matrix.os }}-sharpcompress.nupkg
path: artifacts/*
diff --git a/Directory.Build.props b/Directory.Build.props
index 4b343bf8..b3d0b595 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -10,5 +10,7 @@
true
False
False
+ true
+ true
diff --git a/Directory.Packages.props b/Directory.Packages.props
new file mode 100644
index 00000000..e128f52f
--- /dev/null
+++ b/Directory.Packages.props
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NuGet.config b/NuGet.config
new file mode 100644
index 00000000..48259210
--- /dev/null
+++ b/NuGet.config
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index 20681105..2ab41c09 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,12 @@
# SharpCompress
-SharpCompress is a compression library in pure C# for .NET Standard 2.0, 2.1, .NET Core 3.1 and .NET 5.0 that can unrar, un7zip, unzip, untar unbzip2, ungzip, unlzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip/lzip are implemented.
+SharpCompress is a compression library in pure C# for .NET Framework 4.62, .NET Standard 2.1, .NET 6.0 and NET 8.0 that can unrar, un7zip, unzip, untar unbzip2, ungzip, unlzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip/lzip are implemented.
The major feature is support for non-seekable streams so large files can be processed on the fly (i.e. download stream).
GitHub Actions Build -
[](https://github.com/adamhathcock/sharpcompress/actions/workflows/dotnetcore.yml)
-[](https://www.robiniadocs.com/d/sharpcompress/api/SharpCompress.html)
+[](https://dndocs.com/d/sharpcompress/api/index.html)
## Need Help?
@@ -36,7 +36,7 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
## TODOs (always lots)
-* RAR 5 decryption support
+* RAR 5 decryption crc check support
* 7Zip writing
* Zip64 (Need writing and extend Reading)
* Multi-volume Zip support.
diff --git a/SharpCompress.sln b/SharpCompress.sln
index 71ec294e..ab4995b1 100644
--- a/SharpCompress.sln
+++ b/SharpCompress.sln
@@ -17,6 +17,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{CDB425
ProjectSection(SolutionItems) = preProject
Directory.Build.props = Directory.Build.props
global.json = global.json
+ .editorconfig = .editorconfig
+ Directory.Packages.props = Directory.Packages.props
+ NuGet.config = NuGet.config
EndProjectSection
EndProject
Global
diff --git a/SharpCompress.sln.DotSettings b/SharpCompress.sln.DotSettings
index 248b4c35..4ff50910 100644
--- a/SharpCompress.sln.DotSettings
+++ b/SharpCompress.sln.DotSettings
@@ -79,6 +79,10 @@
<Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" />
+ <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></Policy>
+ <Policy><Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></Policy>
+ <Policy><Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static readonly fields (not private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></Policy>
+ <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></Policy>
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
@@ -127,6 +131,7 @@
True
True
True
+ True
<SessionState ContinuousTestingIsOn="False" ContinuousTestingMode="0" FrameworkVersion="{x:Null}" IsLocked="False" Name="All tests from Solution" PlatformMonoPreference="{x:Null}" PlatformType="{x:Null}" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Solution />
</SessionState>
diff --git a/build/Program.cs b/build/Program.cs
index 9475a66b..acafec41 100644
--- a/build/Program.cs
+++ b/build/Program.cs
@@ -61,7 +61,7 @@ Target(
Target(
Test,
DependsOn(Build),
- ForEach("net7.0", "net462"),
+ ForEach("net8.0", "net462"),
framework =>
{
IEnumerable GetFiles(string d)
diff --git a/build/build.csproj b/build/build.csproj
index 7b478cf3..e0dffc7f 100644
--- a/build/build.csproj
+++ b/build/build.csproj
@@ -2,13 +2,13 @@
Exe
- net7.0
+ net8.0
-
-
-
+
+
+
diff --git a/build/packages.lock.json b/build/packages.lock.json
new file mode 100644
index 00000000..8a8fa2c0
--- /dev/null
+++ b/build/packages.lock.json
@@ -0,0 +1,25 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net8.0": {
+ "Bullseye": {
+ "type": "Direct",
+ "requested": "[5.0.0, )",
+ "resolved": "5.0.0",
+ "contentHash": "bqyt+m17ym+5aN45C5oZRAjuLDt8jKiCm/ys1XfymIXSkrTFwvI/QsbY3ucPSHDz7SF7uON7B57kXFv5H2k1ew=="
+ },
+ "Glob": {
+ "type": "Direct",
+ "requested": "[1.1.9, )",
+ "resolved": "1.1.9",
+ "contentHash": "AfK5+ECWYTP7G3AAdnU8IfVj+QpGjrh9GC2mpdcJzCvtQ4pnerAGwHsxJ9D4/RnhDUz2DSzd951O/lQjQby2Sw=="
+ },
+ "SimpleExec": {
+ "type": "Direct",
+ "requested": "[12.0.0, )",
+ "resolved": "12.0.0",
+ "contentHash": "ptxlWtxC8vM6Y6e3h9ZTxBBkOWnWrm/Sa1HT+2i1xcXY3Hx2hmKDZP5RShPf8Xr9D+ivlrXNy57ktzyH8kyt+Q=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/global.json b/global.json
index e6e67e4e..391ba3c2 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "7.0.101",
+ "version": "8.0.100",
"rollForward": "latestFeature"
}
}
diff --git a/src/SharpCompress/Algorithms/Adler32.cs b/src/SharpCompress/Algorithms/Adler32.cs
index 1f094c13..10dbfc4d 100644
--- a/src/SharpCompress/Algorithms/Adler32.cs
+++ b/src/SharpCompress/Algorithms/Adler32.cs
@@ -62,7 +62,7 @@ internal static class Adler32 // From https://github.com/SixLabors/ImageSharp/bl
public static int ReduceSum(Vector256 accumulator)
{
// Add upper lane to lower lane.
- Vector128 vsum = Sse2.Add(accumulator.GetLower(), accumulator.GetUpper());
+ var vsum = Sse2.Add(accumulator.GetLower(), accumulator.GetUpper());
// Add odd to even.
vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_11_01_01));
@@ -81,7 +81,7 @@ internal static class Adler32 // From https://github.com/SixLabors/ImageSharp/bl
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int EvenReduceSum(Vector256 accumulator)
{
- Vector128 vsum = Sse2.Add(accumulator.GetLower(), accumulator.GetUpper()); // add upper lane to lower lane
+ var vsum = Sse2.Add(accumulator.GetLower(), accumulator.GetUpper()); // add upper lane to lower lane
vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_10_11_10)); // add high to low
// Vector128.ToScalar() isn't optimized pre-net5.0 https://github.com/dotnet/runtime/pull/37882
@@ -189,29 +189,29 @@ internal static class Adler32 // From https://github.com/SixLabors/ImageSharp/bl
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
private static unsafe uint CalculateSse(uint adler, ReadOnlySpan buffer)
{
- uint s1 = adler & 0xFFFF;
- uint s2 = (adler >> 16) & 0xFFFF;
+ var s1 = adler & 0xFFFF;
+ var s2 = (adler >> 16) & 0xFFFF;
// Process the data in blocks.
- uint length = (uint)buffer.Length;
- uint blocks = length / BlockSize;
+ var length = (uint)buffer.Length;
+ var blocks = length / BlockSize;
length -= blocks * BlockSize;
fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer))
{
fixed (byte* tapPtr = &MemoryMarshal.GetReference(Tap1Tap2))
{
- byte* localBufferPtr = bufferPtr;
+ var localBufferPtr = bufferPtr;
// _mm_setr_epi8 on x86
- Vector128 tap1 = Sse2.LoadVector128((sbyte*)tapPtr);
- Vector128 tap2 = Sse2.LoadVector128((sbyte*)(tapPtr + 0x10));
- Vector128 zero = Vector128.Zero;
+ var tap1 = Sse2.LoadVector128((sbyte*)tapPtr);
+ var tap2 = Sse2.LoadVector128((sbyte*)(tapPtr + 0x10));
+ var zero = Vector128.Zero;
var ones = Vector128.Create((short)1);
while (blocks > 0)
{
- uint n = NMAX / BlockSize; /* The NMAX constraint. */
+ var n = NMAX / BlockSize; /* The NMAX constraint. */
if (n > blocks)
{
n = blocks;
@@ -221,15 +221,15 @@ internal static class Adler32 // From https://github.com/SixLabors/ImageSharp/bl
// Process n blocks of data. At most NMAX data bytes can be
// processed before s2 must be reduced modulo BASE.
- Vector128 v_ps = Vector128.CreateScalar(s1 * n);
- Vector128 v_s2 = Vector128.CreateScalar(s2);
- Vector128 v_s1 = Vector128.Zero;
+ var v_ps = Vector128.CreateScalar(s1 * n);
+ var v_s2 = Vector128.CreateScalar(s2);
+ var v_s1 = Vector128.Zero;
do
{
// Load 32 input bytes.
- Vector128 bytes1 = Sse3.LoadDquVector128(localBufferPtr);
- Vector128 bytes2 = Sse3.LoadDquVector128(localBufferPtr + 0x10);
+ var bytes1 = Sse3.LoadDquVector128(localBufferPtr);
+ var bytes2 = Sse3.LoadDquVector128(localBufferPtr + 0x10);
// Add previous block byte sum to v_ps.
v_ps = Sse2.Add(v_ps, v_s1);
@@ -237,11 +237,11 @@ internal static class Adler32 // From https://github.com/SixLabors/ImageSharp/bl
// Horizontally add the bytes for s1, multiply-adds the
// bytes by [ 32, 31, 30, ... ] for s2.
v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes1, zero).AsUInt32());
- Vector128 mad1 = Ssse3.MultiplyAddAdjacent(bytes1, tap1);
+ var mad1 = Ssse3.MultiplyAddAdjacent(bytes1, tap1);
v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad1, ones).AsUInt32());
v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes2, zero).AsUInt32());
- Vector128 mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2);
+ var mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2);
v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones).AsUInt32());
localBufferPtr += BlockSize;
@@ -281,15 +281,15 @@ internal static class Adler32 // From https://github.com/SixLabors/ImageSharp/bl
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
public static unsafe uint CalculateAvx2(uint adler, ReadOnlySpan buffer)
{
- uint s1 = adler & 0xFFFF;
- uint s2 = (adler >> 16) & 0xFFFF;
- uint length = (uint)buffer.Length;
+ var s1 = adler & 0xFFFF;
+ var s2 = (adler >> 16) & 0xFFFF;
+ var length = (uint)buffer.Length;
fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer))
{
- byte* localBufferPtr = bufferPtr;
+ var localBufferPtr = bufferPtr;
- Vector256 zero = Vector256.Zero;
+ var zero = Vector256.Zero;
var dot3v = Vector256.Create((short)1);
var dot2v = Vector256.Create(
32,
@@ -333,29 +333,29 @@ internal static class Adler32 // From https://github.com/SixLabors/ImageSharp/bl
while (length >= 32)
{
- int k = length < NMAX ? (int)length : (int)NMAX;
+ var k = length < NMAX ? (int)length : (int)NMAX;
k -= k % 32;
length -= (uint)k;
- Vector256 vs10 = vs1;
- Vector256 vs3 = Vector256.Zero;
+ var vs10 = vs1;
+ var vs3 = Vector256.Zero;
while (k >= 32)
{
// Load 32 input bytes.
- Vector256 block = Avx.LoadVector256(localBufferPtr);
+ var block = Avx.LoadVector256(localBufferPtr);
// Sum of abs diff, resulting in 2 x int32's
- Vector256 vs1sad = Avx2.SumAbsoluteDifferences(block, zero);
+ var vs1sad = Avx2.SumAbsoluteDifferences(block, zero);
vs1 = Avx2.Add(vs1, vs1sad.AsUInt32());
vs3 = Avx2.Add(vs3, vs10);
// sum 32 uint8s to 16 shorts.
- Vector256 vshortsum2 = Avx2.MultiplyAddAdjacent(block, dot2v);
+ var vshortsum2 = Avx2.MultiplyAddAdjacent(block, dot2v);
// sum 16 shorts to 8 uint32s.
- Vector256 vsum2 = Avx2.MultiplyAddAdjacent(vshortsum2, dot3v);
+ var vsum2 = Avx2.MultiplyAddAdjacent(vshortsum2, dot3v);
vs2 = Avx2.Add(vsum2.AsUInt32(), vs2);
vs10 = vs1;
@@ -434,14 +434,14 @@ internal static class Adler32 // From https://github.com/SixLabors/ImageSharp/bl
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
private static unsafe uint CalculateScalar(uint adler, ReadOnlySpan buffer)
{
- uint s1 = adler & 0xFFFF;
- uint s2 = (adler >> 16) & 0xFFFF;
+ var s1 = adler & 0xFFFF;
+ var s2 = (adler >> 16) & 0xFFFF;
uint k;
fixed (byte* bufferPtr = buffer)
{
var localBufferPtr = bufferPtr;
- uint length = (uint)buffer.Length;
+ var length = (uint)buffer.Length;
while (length > 0)
{
diff --git a/src/SharpCompress/Archives/AbstractArchive.cs b/src/SharpCompress/Archives/AbstractArchive.cs
index cfac55f2..df54d781 100644
--- a/src/SharpCompress/Archives/AbstractArchive.cs
+++ b/src/SharpCompress/Archives/AbstractArchive.cs
@@ -12,39 +12,35 @@ public abstract class AbstractArchive : IArchive, IArchiveExtra
where TEntry : IArchiveEntry
where TVolume : IVolume
{
- private readonly LazyReadOnlyCollection lazyVolumes;
- private readonly LazyReadOnlyCollection lazyEntries;
+ private readonly LazyReadOnlyCollection _lazyVolumes;
+ private readonly LazyReadOnlyCollection _lazyEntries;
+ private bool _disposed;
+ private readonly SourceStream? _sourceStream;
public event EventHandler>? EntryExtractionBegin;
public event EventHandler>? EntryExtractionEnd;
public event EventHandler? CompressedBytesRead;
public event EventHandler? FilePartExtractionBegin;
-
protected ReaderOptions ReaderOptions { get; }
- private bool disposed;
- protected SourceStream SrcStream;
-
- internal AbstractArchive(ArchiveType type, SourceStream srcStream)
+ internal AbstractArchive(ArchiveType type, SourceStream sourceStream)
{
Type = type;
- ReaderOptions = srcStream.ReaderOptions;
- SrcStream = srcStream;
- lazyVolumes = new LazyReadOnlyCollection(LoadVolumes(SrcStream));
- lazyEntries = new LazyReadOnlyCollection(LoadEntries(Volumes));
+ ReaderOptions = sourceStream.ReaderOptions;
+ _sourceStream = sourceStream;
+ _lazyVolumes = new LazyReadOnlyCollection(LoadVolumes(_sourceStream));
+ _lazyEntries = new LazyReadOnlyCollection(LoadEntries(Volumes));
}
-#nullable disable
internal AbstractArchive(ArchiveType type)
{
Type = type;
- lazyVolumes = new LazyReadOnlyCollection(Enumerable.Empty());
- lazyEntries = new LazyReadOnlyCollection(Enumerable.Empty());
+ ReaderOptions = new();
+ _lazyVolumes = new LazyReadOnlyCollection(Enumerable.Empty());
+ _lazyEntries = new LazyReadOnlyCollection(Enumerable.Empty());
}
-#nullable enable
-
public ArchiveType Type { get; }
void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry) =>
@@ -65,12 +61,12 @@ public abstract class AbstractArchive : IArchive, IArchiveExtra
///
/// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive.
///
- public virtual ICollection Entries => lazyEntries;
+ public virtual ICollection Entries => _lazyEntries;
///
/// Returns an ReadOnlyCollection of all the RarArchiveVolumes across the one or many parts of the RarArchive.
///
- public ICollection Volumes => lazyVolumes;
+ public ICollection Volumes => _lazyVolumes;
///
/// The total size of the files compressed in the archive.
@@ -84,29 +80,29 @@ public abstract class AbstractArchive : IArchive, IArchiveExtra
public virtual long TotalUncompressSize =>
Entries.Aggregate(0L, (total, cf) => total + cf.Size);
- protected abstract IEnumerable LoadVolumes(SourceStream srcStream);
+ protected abstract IEnumerable LoadVolumes(SourceStream sourceStream);
protected abstract IEnumerable LoadEntries(IEnumerable volumes);
IEnumerable IArchive.Entries => Entries.Cast();
- IEnumerable IArchive.Volumes => lazyVolumes.Cast();
+ IEnumerable IArchive.Volumes => _lazyVolumes.Cast();
public virtual void Dispose()
{
- if (!disposed)
+ if (!_disposed)
{
- lazyVolumes.ForEach(v => v.Dispose());
- lazyEntries.GetLoaded().Cast().ForEach(x => x.Close());
- SrcStream?.Dispose();
+ _lazyVolumes.ForEach(v => v.Dispose());
+ _lazyEntries.GetLoaded().Cast().ForEach(x => x.Close());
+ _sourceStream?.Dispose();
- disposed = true;
+ _disposed = true;
}
}
void IArchiveExtractionListener.EnsureEntriesLoaded()
{
- lazyEntries.EnsureFullyLoaded();
- lazyVolumes.EnsureFullyLoaded();
+ _lazyEntries.EnsureFullyLoaded();
+ _lazyVolumes.EnsureFullyLoaded();
}
void IExtractionListener.FireCompressedBytesRead(
diff --git a/src/SharpCompress/Archives/AbstractWritableArchive.cs b/src/SharpCompress/Archives/AbstractWritableArchive.cs
index 30083ec7..614489fe 100644
--- a/src/SharpCompress/Archives/AbstractWritableArchive.cs
+++ b/src/SharpCompress/Archives/AbstractWritableArchive.cs
@@ -31,18 +31,18 @@ public abstract class AbstractWritableArchive
}
}
- private readonly List newEntries = new List();
- private readonly List removedEntries = new List();
+ private readonly List newEntries = new();
+ private readonly List removedEntries = new();
- private readonly List modifiedEntries = new List();
+ private readonly List modifiedEntries = new();
private bool hasModifications;
private bool pauseRebuilding;
internal AbstractWritableArchive(ArchiveType type)
: base(type) { }
- internal AbstractWritableArchive(ArchiveType type, SourceStream srcStream)
- : base(type, srcStream) { }
+ internal AbstractWritableArchive(ArchiveType type, SourceStream sourceStream)
+ : base(type, sourceStream) { }
public override ICollection Entries
{
@@ -120,6 +120,10 @@ public abstract class AbstractWritableArchive
{
foreach (var path in Entries.Select(x => x.Key))
{
+ if (path is null)
+ {
+ continue;
+ }
var p = path.Replace('/', '\\');
if (p.Length > 0 && p[0] == '\\')
{
diff --git a/src/SharpCompress/Archives/ArchiveFactory.cs b/src/SharpCompress/Archives/ArchiveFactory.cs
index cd0952f1..3f479327 100644
--- a/src/SharpCompress/Archives/ArchiveFactory.cs
+++ b/src/SharpCompress/Archives/ArchiveFactory.cs
@@ -25,8 +25,8 @@ public static class ArchiveFactory
public static IWritableArchive Create(ArchiveType type)
{
- var factory = Factory.Factories
- .OfType()
+ var factory = Factory
+ .Factories.OfType()
.FirstOrDefault(item => item.KnownArchiveType == type);
if (factory != null)
diff --git a/src/SharpCompress/Archives/ArchiveVolumeFactory.cs b/src/SharpCompress/Archives/ArchiveVolumeFactory.cs
index d8f5535f..81a5d4fd 100644
--- a/src/SharpCompress/Archives/ArchiveVolumeFactory.cs
+++ b/src/SharpCompress/Archives/ArchiveVolumeFactory.cs
@@ -11,7 +11,7 @@ internal abstract class ArchiveVolumeFactory
FileInfo? item = null;
//split 001, 002 ...
- Match m = Regex.Match(part1.Name, @"^(.*\.)([0-9]+)$", RegexOptions.IgnoreCase);
+ var m = Regex.Match(part1.Name, @"^(.*\.)([0-9]+)$", RegexOptions.IgnoreCase);
if (m.Success)
item = new FileInfo(
Path.Combine(
diff --git a/src/SharpCompress/Archives/GZip/GZipArchive.cs b/src/SharpCompress/Archives/GZip/GZipArchive.cs
index fb2f7691..ea46e8d0 100644
--- a/src/SharpCompress/Archives/GZip/GZipArchive.cs
+++ b/src/SharpCompress/Archives/GZip/GZipArchive.cs
@@ -90,25 +90,23 @@ public class GZipArchive : AbstractWritableArchive
{
stream.CheckNotNull(nameof(stream));
return new GZipArchive(
- new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())
+ new SourceStream(stream, _ => null, readerOptions ?? new ReaderOptions())
);
}
- public static GZipArchive Create() => new GZipArchive();
+ public static GZipArchive Create() => new();
///
/// Constructor with a SourceStream able to handle FileInfo and Streams.
///
- ///
- ///
- internal GZipArchive(SourceStream srcStream)
- : base(ArchiveType.Tar, srcStream) { }
+ ///
+ private GZipArchive(SourceStream sourceStream)
+ : base(ArchiveType.GZip, sourceStream) { }
- protected override IEnumerable LoadVolumes(SourceStream srcStream)
+ protected override IEnumerable LoadVolumes(SourceStream sourceStream)
{
- srcStream.LoadAllParts();
- var idx = 0;
- return srcStream.Streams.Select(a => new GZipVolume(a, ReaderOptions, idx++));
+ sourceStream.LoadAllParts();
+ return sourceStream.Streams.Select(a => new GZipVolume(a, ReaderOptions, 0));
}
public static bool IsGZipFile(string filePath) => IsGZipFile(new FileInfo(filePath));
@@ -184,7 +182,11 @@ public class GZipArchive : AbstractWritableArchive
foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory))
{
using var entryStream = entry.OpenEntryStream();
- writer.Write(entry.Key, entryStream, entry.LastModifiedTime);
+ writer.Write(
+ entry.Key.NotNull("Entry Key is null"),
+ entryStream,
+ entry.LastModifiedTime
+ );
}
}
diff --git a/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs b/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs
index be872e80..459d042d 100644
--- a/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs
+++ b/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs
@@ -6,7 +6,7 @@ namespace SharpCompress.Archives.GZip;
public class GZipArchiveEntry : GZipEntry, IArchiveEntry
{
- internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part)
+ internal GZipArchiveEntry(GZipArchive archive, GZipFilePart? part)
: base(part) => Archive = archive;
public virtual Stream OpenEntryStream()
diff --git a/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs b/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs
index 27dfc2bf..90f6f16f 100644
--- a/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs
+++ b/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.IO;
@@ -32,7 +30,7 @@ internal sealed class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArch
public override long Crc => 0;
- public override string Key { get; }
+ public override string? Key { get; }
public override long CompressedSize => 0;
diff --git a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs
index 0992f152..3d1daa1a 100644
--- a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs
+++ b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs
@@ -17,15 +17,11 @@ public static class IArchiveEntryExtensions
streamListener.EnsureEntriesLoaded();
streamListener.FireEntryExtractionBegin(archiveEntry);
streamListener.FireFilePartExtractionBegin(
- archiveEntry.Key,
+ archiveEntry.Key ?? "Key",
archiveEntry.Size,
archiveEntry.CompressedSize
);
var entryStream = archiveEntry.OpenEntryStream();
- if (entryStream is null)
- {
- return;
- }
using (entryStream)
{
using Stream s = new ListeningStream(streamListener, entryStream);
diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs
index 56ea0d9f..382c3ddf 100644
--- a/src/SharpCompress/Archives/IArchiveExtensions.cs
+++ b/src/SharpCompress/Archives/IArchiveExtensions.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
-using System.Threading.Tasks;
using SharpCompress.Common;
namespace SharpCompress.Archives;
@@ -59,7 +58,7 @@ public static class IArchiveExtensions
}
// Create each directory
- var path = Path.Combine(destination, entry.Key);
+ var path = Path.Combine(destination, entry.Key.NotNull("Entry Key is null"));
if (Path.GetDirectoryName(path) is { } directory && seenDirectories.Add(path))
{
Directory.CreateDirectory(directory);
diff --git a/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs b/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs
index 3e576db3..6d9b44fd 100644
--- a/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs
+++ b/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs
@@ -13,7 +13,7 @@ namespace SharpCompress.Archives.Rar;
///
internal class FileInfoRarArchiveVolume : RarVolume
{
- internal FileInfoRarArchiveVolume(FileInfo fileInfo, ReaderOptions options, int index = 0)
+ internal FileInfoRarArchiveVolume(FileInfo fileInfo, ReaderOptions options, int index)
: base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options), index)
{
FileInfo = fileInfo;
diff --git a/src/SharpCompress/Archives/Rar/RarArchive.cs b/src/SharpCompress/Archives/Rar/RarArchive.cs
index 29d733f6..a05ad417 100644
--- a/src/SharpCompress/Archives/Rar/RarArchive.cs
+++ b/src/SharpCompress/Archives/Rar/RarArchive.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -14,40 +15,39 @@ namespace SharpCompress.Archives.Rar;
public class RarArchive : AbstractArchive
{
internal Lazy UnpackV2017 { get; } =
- new Lazy(() => new Compressors.Rar.UnpackV2017.Unpack());
- internal Lazy UnpackV1 { get; } =
- new Lazy(() => new Compressors.Rar.UnpackV1.Unpack());
+ new(() => new Compressors.Rar.UnpackV2017.Unpack());
+ internal Lazy UnpackV1 { get; } = new(() => new Compressors.Rar.UnpackV1.Unpack());
///
/// Constructor with a SourceStream able to handle FileInfo and Streams.
///
- ///
- ///
- internal RarArchive(SourceStream srcStream)
- : base(ArchiveType.Rar, srcStream) { }
+ ///
+ private RarArchive(SourceStream sourceStream)
+ : base(ArchiveType.Rar, sourceStream) { }
protected override IEnumerable LoadEntries(IEnumerable volumes) =>
RarArchiveEntryFactory.GetEntries(this, volumes, ReaderOptions);
- protected override IEnumerable LoadVolumes(SourceStream srcStream)
+ protected override IEnumerable LoadVolumes(SourceStream sourceStream)
{
- SrcStream.LoadAllParts(); //request all streams
- var streams = SrcStream.Streams.ToArray();
- var idx = 0;
+ sourceStream.LoadAllParts(); //request all streams
+ var streams = sourceStream.Streams.ToArray();
+ var i = 0;
if (streams.Length > 1 && IsRarFile(streams[1], ReaderOptions)) //test part 2 - true = multipart not split
{
- SrcStream.IsVolumes = true;
+ sourceStream.IsVolumes = true;
streams[1].Position = 0;
- SrcStream.Position = 0;
+ sourceStream.Position = 0;
- return srcStream.Streams.Select(
- a => new StreamRarArchiveVolume(a, ReaderOptions, idx++)
- );
- }
- else //split mode or single file
- {
- return new StreamRarArchiveVolume(SrcStream, ReaderOptions, idx++).AsEnumerable();
+ return sourceStream.Streams.Select(a => new StreamRarArchiveVolume(
+ a,
+ ReaderOptions,
+ i++
+ ));
}
+
+ //split mode or single file
+ return new StreamRarArchiveVolume(sourceStream, ReaderOptions, i++).AsEnumerable();
}
protected override IReader CreateReaderForSolidExtraction()
@@ -106,7 +106,7 @@ public class RarArchive : AbstractArchive
public static RarArchive Open(Stream stream, ReaderOptions? options = null)
{
stream.CheckNotNull(nameof(stream));
- return new RarArchive(new SourceStream(stream, i => null, options ?? new ReaderOptions()));
+ return new RarArchive(new SourceStream(stream, _ => null, options ?? new ReaderOptions()));
}
///
diff --git a/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs b/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs
index 5885210a..fa59b295 100644
--- a/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs
+++ b/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -40,7 +41,10 @@ public class RarArchiveEntry : RarEntry, IArchiveEntry
get
{
CheckIncomplete();
- return parts.Select(fp => fp.FileHeader).Single(fh => !fh.IsSplitAfter).FileCrc;
+ return BitConverter.ToUInt32(
+ parts.Select(fp => fp.FileHeader).Single(fh => !fh.IsSplitAfter).FileCrc,
+ 0
+ );
}
}
diff --git a/src/SharpCompress/Archives/Rar/RarArchiveVolumeFactory.cs b/src/SharpCompress/Archives/Rar/RarArchiveVolumeFactory.cs
index 72ccf60f..f5ce89b8 100644
--- a/src/SharpCompress/Archives/Rar/RarArchiveVolumeFactory.cs
+++ b/src/SharpCompress/Archives/Rar/RarArchiveVolumeFactory.cs
@@ -11,7 +11,7 @@ internal static class RarArchiveVolumeFactory
FileInfo? item = null;
//new style rar - ..part1 | /part01 | part001 ....
- Match m = Regex.Match(part1.Name, @"^(.*\.part)([0-9]+)(\.rar)$", RegexOptions.IgnoreCase);
+ var m = Regex.Match(part1.Name, @"^(.*\.part)([0-9]+)(\.rar)$", RegexOptions.IgnoreCase);
if (m.Success)
item = new FileInfo(
Path.Combine(
diff --git a/src/SharpCompress/Archives/Rar/SeekableFilePart.cs b/src/SharpCompress/Archives/Rar/SeekableFilePart.cs
index 08aceb13..97822d90 100644
--- a/src/SharpCompress/Archives/Rar/SeekableFilePart.cs
+++ b/src/SharpCompress/Archives/Rar/SeekableFilePart.cs
@@ -6,8 +6,8 @@ namespace SharpCompress.Archives.Rar;
internal class SeekableFilePart : RarFilePart
{
- private readonly Stream stream;
- private readonly string? password;
+ private readonly Stream _stream;
+ private readonly string? _password;
internal SeekableFilePart(
MarkHeader mh,
@@ -18,18 +18,27 @@ internal class SeekableFilePart : RarFilePart
)
: base(mh, fh, index)
{
- this.stream = stream;
- this.password = password;
+ _stream = stream;
+ _password = password;
}
internal override Stream GetCompressedStream()
{
- stream.Position = FileHeader.DataStartPosition;
+ _stream.Position = FileHeader.DataStartPosition;
+
if (FileHeader.R4Salt != null)
{
- return new RarCryptoWrapper(stream, password!, FileHeader.R4Salt);
+ var cryptKey = new CryptKey3(_password!);
+ return new RarCryptoWrapper(_stream, FileHeader.R4Salt, cryptKey);
}
- return stream;
+
+ if (FileHeader.Rar5CryptoInfo != null)
+ {
+ var cryptKey = new CryptKey5(_password!, FileHeader.Rar5CryptoInfo);
+ return new RarCryptoWrapper(_stream, FileHeader.Rar5CryptoInfo.Salt, cryptKey);
+ }
+
+ return _stream;
}
internal override string FilePartName => "Unknown Stream - File Entry: " + FileHeader.FileName;
diff --git a/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs b/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs
index 3eb5095c..60cbab9a 100644
--- a/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs
+++ b/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs
@@ -9,7 +9,7 @@ namespace SharpCompress.Archives.Rar;
internal class StreamRarArchiveVolume : RarVolume
{
- internal StreamRarArchiveVolume(Stream stream, ReaderOptions options, int index = 0)
+ internal StreamRarArchiveVolume(Stream stream, ReaderOptions options, int index)
: base(StreamingMode.Seekable, stream, options, index) { }
internal override IEnumerable ReadFileParts() => GetVolumeFileParts();
diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs
index 7577b43d..ee165982 100644
--- a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs
+++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.IO;
@@ -14,14 +12,14 @@ namespace SharpCompress.Archives.SevenZip;
public class SevenZipArchive : AbstractArchive
{
- private ArchiveDatabase database;
+ private ArchiveDatabase? _database;
///
/// Constructor expects a filepath to an existing file.
///
///
///
- public static SevenZipArchive Open(string filePath, ReaderOptions readerOptions = null)
+ public static SevenZipArchive Open(string filePath, ReaderOptions? readerOptions = null)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
@@ -32,7 +30,7 @@ public class SevenZipArchive : AbstractArchive
///
///
- public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
+ public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
{
fileInfo.CheckNotNull("fileInfo");
return new SevenZipArchive(
@@ -51,7 +49,7 @@ public class SevenZipArchive : AbstractArchive
public static SevenZipArchive Open(
IEnumerable fileInfos,
- ReaderOptions readerOptions = null
+ ReaderOptions? readerOptions = null
)
{
fileInfos.CheckNotNull(nameof(fileInfos));
@@ -72,7 +70,7 @@ public class SevenZipArchive : AbstractArchive
public static SevenZipArchive Open(
IEnumerable streams,
- ReaderOptions readerOptions = null
+ ReaderOptions? readerOptions = null
)
{
streams.CheckNotNull(nameof(streams));
@@ -91,27 +89,25 @@ public class SevenZipArchive : AbstractArchive
///
///
- public static SevenZipArchive Open(Stream stream, ReaderOptions readerOptions = null)
+ public static SevenZipArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
stream.CheckNotNull("stream");
return new SevenZipArchive(
- new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())
+ new SourceStream(stream, _ => null, readerOptions ?? new ReaderOptions())
);
}
///
/// Constructor with a SourceStream able to handle FileInfo and Streams.
///
- ///
- ///
- internal SevenZipArchive(SourceStream srcStream)
- : base(ArchiveType.SevenZip, srcStream) { }
+ ///
+ private SevenZipArchive(SourceStream sourceStream)
+ : base(ArchiveType.SevenZip, sourceStream) { }
- protected override IEnumerable LoadVolumes(SourceStream srcStream)
+ protected override IEnumerable LoadVolumes(SourceStream sourceStream)
{
- SrcStream.LoadAllParts(); //request all streams
- var idx = 0;
- return new SevenZipVolume(srcStream, ReaderOptions, idx++).AsEnumerable(); //simple single volume or split, multivolume not supported
+ sourceStream.NotNull("SourceStream is null").LoadAllParts(); //request all streams
+ return new SevenZipVolume(sourceStream, ReaderOptions, 0).AsEnumerable(); //simple single volume or split, multivolume not supported
}
public static bool IsSevenZipFile(string filePath) => IsSevenZipFile(new FileInfo(filePath));
@@ -135,13 +131,17 @@ public class SevenZipArchive : AbstractArchive();
+ }
+ var entries = new SevenZipArchiveEntry[_database._files.Count];
+ for (var i = 0; i < _database._files.Count; i++)
+ {
+ var file = _database._files[i];
entries[i] = new SevenZipArchiveEntry(
this,
- new SevenZipFilePart(stream, database, i, file, ReaderOptions.ArchiveEncoding)
+ new SevenZipFilePart(stream, _database, i, file, ReaderOptions.ArchiveEncoding)
);
}
foreach (var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder))
@@ -159,12 +159,12 @@ public class SevenZipArchive : AbstractArchive SIGNATURE =>
+ private static ReadOnlySpan Signature =>
new byte[] { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C };
private static bool SignatureMatch(Stream stream)
{
var reader = new BinaryReader(stream);
ReadOnlySpan signatureBytes = reader.ReadBytes(6);
- return signatureBytes.SequenceEqual(SIGNATURE);
+ return signatureBytes.SequenceEqual(Signature);
}
protected override IReader CreateReaderForSolidExtraction() =>
@@ -196,30 +196,24 @@ public class SevenZipArchive : AbstractArchive
Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1;
- public override long TotalSize
- {
- get
- {
- var i = Entries.Count;
- return database._packSizes.Aggregate(0L, (total, packSize) => total + packSize);
- }
- }
+ public override long TotalSize =>
+ _database?._packSizes.Aggregate(0L, (total, packSize) => total + packSize) ?? 0;
private sealed class SevenZipReader : AbstractReader
{
- private readonly SevenZipArchive archive;
- private CFolder currentFolder;
- private Stream currentStream;
- private CFileItem currentItem;
+ private readonly SevenZipArchive _archive;
+ private CFolder? _currentFolder;
+ private Stream? _currentStream;
+ private CFileItem? _currentItem;
internal SevenZipReader(ReaderOptions readerOptions, SevenZipArchive archive)
- : base(readerOptions, ArchiveType.SevenZip) => this.archive = archive;
+ : base(readerOptions, ArchiveType.SevenZip) => this._archive = archive;
- public override SevenZipVolume Volume => archive.Volumes.Single();
+ public override SevenZipVolume Volume => _archive.Volumes.Single();
protected override IEnumerable GetEntries(Stream stream)
{
- var entries = archive.Entries.ToList();
+ var entries = _archive.Entries.ToList();
stream.Position = 0;
foreach (var dir in entries.Where(x => x.IsDirectory))
{
@@ -229,37 +223,42 @@ public class SevenZipArchive : AbstractArchive !x.IsDirectory).GroupBy(x => x.FilePart.Folder)
)
{
- currentFolder = group.Key;
+ _currentFolder = group.Key;
if (group.Key is null)
{
- currentStream = Stream.Null;
+ _currentStream = Stream.Null;
}
else
{
- currentStream = archive.database.GetFolderStream(
+ _currentStream = _archive._database?.GetFolderStream(
stream,
- currentFolder,
+ _currentFolder,
new PasswordProvider(Options.Password)
);
}
foreach (var entry in group)
{
- currentItem = entry.FilePart.Header;
+ _currentItem = entry.FilePart.Header;
yield return entry;
}
}
}
protected override EntryStream GetEntryStream() =>
- CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size));
+ CreateEntryStream(
+ new ReadOnlySubStream(
+ _currentStream.NotNull("currentStream is not null"),
+ _currentItem?.Size ?? 0
+ )
+ );
}
private class PasswordProvider : IPasswordProvider
{
- private readonly string _password;
+ private readonly string? _password;
- public PasswordProvider(string password) => _password = password;
+ public PasswordProvider(string? password) => _password = password;
- public string CryptoGetTextPassword() => _password;
+ public string? CryptoGetTextPassword() => _password;
}
}
diff --git a/src/SharpCompress/Archives/Tar/TarArchive.cs b/src/SharpCompress/Archives/Tar/TarArchive.cs
index 43184b66..fdf8cd42 100644
--- a/src/SharpCompress/Archives/Tar/TarArchive.cs
+++ b/src/SharpCompress/Archives/Tar/TarArchive.cs
@@ -114,7 +114,7 @@ public class TarArchive : AbstractWritableArchive
var tarHeader = new TarHeader(new ArchiveEncoding());
var readSucceeded = tarHeader.Read(new BinaryReader(stream));
var isEmptyArchive =
- tarHeader.Name.Length == 0
+ tarHeader.Name?.Length == 0
&& tarHeader.Size == 0
&& Enum.IsDefined(typeof(EntryType), tarHeader.EntryType);
return readSucceeded || isEmptyArchive;
@@ -123,22 +123,20 @@ public class TarArchive : AbstractWritableArchive
return false;
}
- protected override IEnumerable LoadVolumes(SourceStream srcStream)
+ protected override IEnumerable LoadVolumes(SourceStream sourceStream)
{
- SrcStream.LoadAllParts(); //request all streams
- var idx = 0;
- return new TarVolume(srcStream, ReaderOptions, idx++).AsEnumerable(); //simple single volume or split, multivolume not supported
+ sourceStream.NotNull("SourceStream is null").LoadAllParts(); //request all streams
+ return new TarVolume(sourceStream, ReaderOptions, 1).AsEnumerable(); //simple single volume or split, multivolume not supported
}
///
/// Constructor with a SourceStream able to handle FileInfo and Streams.
///
- ///
- ///
- internal TarArchive(SourceStream srcStream)
- : base(ArchiveType.Tar, srcStream) { }
+ ///
+ private TarArchive(SourceStream sourceStream)
+ : base(ArchiveType.Tar, sourceStream) { }
- internal TarArchive()
+ private TarArchive()
: base(ArchiveType.Tar) { }
protected override IEnumerable LoadEntries(IEnumerable volumes)
@@ -192,10 +190,14 @@ public class TarArchive : AbstractWritableArchive
);
}
}
+ else
+ {
+ throw new IncompleteArchiveException("Failed to read TAR header");
+ }
}
}
- public static TarArchive Create() => new TarArchive();
+ public static TarArchive Create() => new();
protected override TarArchiveEntry CreateEntryInternal(
string filePath,
@@ -225,7 +227,12 @@ public class TarArchive : AbstractWritableArchive
foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory))
{
using var entryStream = entry.OpenEntryStream();
- writer.Write(entry.Key, entryStream, entry.LastModifiedTime, entry.Size);
+ writer.Write(
+ entry.Key.NotNull("Entry Key is null"),
+ entryStream,
+ entry.LastModifiedTime,
+ entry.Size
+ );
}
}
diff --git a/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs b/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs
index 2da84d71..d04c4ef8 100644
--- a/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs
+++ b/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs
@@ -7,7 +7,7 @@ namespace SharpCompress.Archives.Tar;
public class TarArchiveEntry : TarEntry, IArchiveEntry
{
- internal TarArchiveEntry(TarArchive archive, TarFilePart part, CompressionType compressionType)
+ internal TarArchiveEntry(TarArchive archive, TarFilePart? part, CompressionType compressionType)
: base(part, compressionType) => Archive = archive;
public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream();
diff --git a/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs b/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs
index 0bbea709..32be7d9b 100644
--- a/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs
+++ b/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/src/SharpCompress/Archives/Zip/ZipArchive.cs b/src/SharpCompress/Archives/Zip/ZipArchive.cs
index 14e4a93e..85130f70 100644
--- a/src/SharpCompress/Archives/Zip/ZipArchive.cs
+++ b/src/SharpCompress/Archives/Zip/ZipArchive.cs
@@ -16,10 +16,7 @@ namespace SharpCompress.Archives.Zip;
public class ZipArchive : AbstractWritableArchive
{
-#nullable disable
- private readonly SeekableZipHeaderFactory headerFactory;
-
-#nullable enable
+ private readonly SeekableZipHeaderFactory? headerFactory;
///
/// Gets or sets the compression level applied to files added to the archive,
@@ -30,13 +27,13 @@ public class ZipArchive : AbstractWritableArchive
///
/// Constructor with a SourceStream able to handle FileInfo and Streams.
///
- ///
+ ///
///
- internal ZipArchive(SourceStream srcStream)
- : base(ArchiveType.Zip, srcStream) =>
+ internal ZipArchive(SourceStream sourceStream)
+ : base(ArchiveType.Zip, sourceStream) =>
headerFactory = new SeekableZipHeaderFactory(
- srcStream.ReaderOptions.Password,
- srcStream.ReaderOptions.ArchiveEncoding
+ sourceStream.ReaderOptions.Password,
+ sourceStream.ReaderOptions.ArchiveEncoding
);
///
@@ -189,21 +186,21 @@ public class ZipArchive : AbstractWritableArchive
}
}
- protected override IEnumerable LoadVolumes(SourceStream srcStream)
+ protected override IEnumerable LoadVolumes(SourceStream stream)
{
- SrcStream.LoadAllParts(); //request all streams
- SrcStream.Position = 0;
+ stream.LoadAllParts(); //request all streams
+ stream.Position = 0;
- var streams = SrcStream.Streams.ToList();
+ var streams = stream.Streams.ToList();
var idx = 0;
- if (streams.Count > 1) //test part 2 - true = multipart not split
+ if (streams.Count() > 1) //test part 2 - true = multipart not split
{
streams[1].Position += 4; //skip the POST_DATA_DESCRIPTOR to prevent an exception
var isZip = IsZipFile(streams[1], ReaderOptions.Password);
streams[1].Position -= 4;
if (isZip)
{
- SrcStream.IsVolumes = true;
+ stream.IsVolumes = true;
var tmp = streams[0]; //arcs as zip, z01 ... swap the zip the end
streams.RemoveAt(0);
@@ -215,7 +212,7 @@ public class ZipArchive : AbstractWritableArchive
}
//split mode or single file
- return new ZipVolume(SrcStream, ReaderOptions, idx++).AsEnumerable();
+ return new ZipVolume(stream, ReaderOptions, idx++).AsEnumerable();
}
internal ZipArchive()
@@ -224,14 +221,13 @@ public class ZipArchive : AbstractWritableArchive
protected override IEnumerable LoadEntries(IEnumerable volumes)
{
var vols = volumes.ToArray();
- foreach (var h in headerFactory.ReadSeekableHeader(vols.Last().Stream))
+ foreach (var h in headerFactory.NotNull().ReadSeekableHeader(vols.Last().Stream))
{
if (h != null)
{
switch (h.ZipHeaderType)
{
case ZipHeaderType.DirectoryEntry:
-
{
var deh = (DirectoryEntryHeader)h;
Stream s;
@@ -254,14 +250,14 @@ public class ZipArchive : AbstractWritableArchive
yield return new ZipArchiveEntry(
this,
- new SeekableZipFilePart(headerFactory, deh, s)
+ new SeekableZipFilePart(headerFactory.NotNull(), deh, s)
);
}
break;
case ZipHeaderType.DirectoryEnd:
{
var bytes = ((DirectoryEndHeader)h).Comment ?? Array.Empty();
- volumes.Last().Comment = ReaderOptions.ArchiveEncoding.Decode(bytes);
+ vols.Last().Comment = ReaderOptions.ArchiveEncoding.Decode(bytes);
yield break;
}
}
@@ -282,7 +278,11 @@ public class ZipArchive : AbstractWritableArchive
foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory))
{
using var entryStream = entry.OpenEntryStream();
- writer.Write(entry.Key, entryStream, entry.LastModifiedTime);
+ writer.Write(
+ entry.Key.NotNull("Entry Key is null"),
+ entryStream,
+ entry.LastModifiedTime
+ );
}
}
@@ -294,7 +294,7 @@ public class ZipArchive : AbstractWritableArchive
bool closeStream
) => new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);
- public static ZipArchive Create() => new ZipArchive();
+ public static ZipArchive Create() => new();
protected override IReader CreateReaderForSolidExtraction()
{
diff --git a/src/SharpCompress/Archives/Zip/ZipArchiveVolumeFactory.cs b/src/SharpCompress/Archives/Zip/ZipArchiveVolumeFactory.cs
index fdaa85b9..1b2f093d 100644
--- a/src/SharpCompress/Archives/Zip/ZipArchiveVolumeFactory.cs
+++ b/src/SharpCompress/Archives/Zip/ZipArchiveVolumeFactory.cs
@@ -12,7 +12,7 @@ internal static class ZipArchiveVolumeFactory
//load files with zip/zipx first. Swapped to end once loaded in ZipArchive
//new style .zip, z01.. | .zipx, zx01 - if the numbers go beyond 99 then they use 100 ...1000 etc
- Match m = Regex.Match(part1.Name, @"^(.*\.)(zipx?|zx?[0-9]+)$", RegexOptions.IgnoreCase);
+ var m = Regex.Match(part1.Name, @"^(.*\.)(zipx?|zx?[0-9]+)$", RegexOptions.IgnoreCase);
if (m.Success)
item = new FileInfo(
Path.Combine(
diff --git a/src/SharpCompress/BufferPool.cs b/src/SharpCompress/BufferPool.cs
new file mode 100644
index 00000000..b11dbe6f
--- /dev/null
+++ b/src/SharpCompress/BufferPool.cs
@@ -0,0 +1,33 @@
+using System.Buffers;
+
+namespace SharpCompress;
+
+internal static class BufferPool
+{
+ ///
+ /// gets a buffer from the pool
+ ///
+ /// size of the buffer
+ /// the buffer
+ public static byte[] Rent(int bufferSize)
+ {
+#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
+ return ArrayPool.Shared.Rent(bufferSize);
+#else
+ return new byte[bufferSize];
+#endif
+ }
+
+ ///
+ /// returns a buffer to the pool
+ ///
+ /// the buffer to return
+ public static void Return(byte[] buffer)
+ {
+#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
+ ArrayPool.Shared.Return(buffer);
+#else
+ // no-op
+#endif
+ }
+}
diff --git a/src/SharpCompress/Common/ArchiveEncoding.cs b/src/SharpCompress/Common/ArchiveEncoding.cs
index f66044d3..3701a93b 100644
--- a/src/SharpCompress/Common/ArchiveEncoding.cs
+++ b/src/SharpCompress/Common/ArchiveEncoding.cs
@@ -8,12 +8,12 @@ public class ArchiveEncoding
///
/// Default encoding to use when archive format doesn't specify one.
///
- public Encoding Default { get; set; }
+ public Encoding? Default { get; set; }
///
/// ArchiveEncoding used by encryption schemes which don't comply with RFC 2898.
///
- public Encoding Password { get; set; }
+ public Encoding? Password { get; set; }
///
/// Set this encoding when you want to force it for all encoding operations.
@@ -50,6 +50,8 @@ public class ArchiveEncoding
public Encoding GetEncoding() => Forced ?? Default ?? Encoding.UTF8;
+ public Encoding GetPasswordEncoding() => Password ?? Encoding.UTF8;
+
public Func GetDecoder() =>
CustomDecoder ?? ((bytes, index, count) => GetEncoding().GetString(bytes, index, count));
}
diff --git a/src/SharpCompress/Common/CompressionType.cs b/src/SharpCompress/Common/CompressionType.cs
index 11263245..20f166c4 100644
--- a/src/SharpCompress/Common/CompressionType.cs
+++ b/src/SharpCompress/Common/CompressionType.cs
@@ -14,5 +14,7 @@ public enum CompressionType
LZip,
Xz,
Unknown,
- Deflate64
+ Deflate64,
+ Shrink,
+ Lzw
}
diff --git a/src/SharpCompress/Common/Entry.cs b/src/SharpCompress/Common/Entry.cs
index 85219a43..6209b3de 100644
--- a/src/SharpCompress/Common/Entry.cs
+++ b/src/SharpCompress/Common/Entry.cs
@@ -14,7 +14,7 @@ public abstract class Entry : IEntry
///
/// The string key of the file internal to the Archive.
///
- public abstract string Key { get; }
+ public abstract string? Key { get; }
///
/// The target of a symlink entry internal to the Archive. Will be null if not a symlink.
@@ -71,11 +71,11 @@ public abstract class Entry : IEntry
///
public abstract bool IsSplitAfter { get; }
- public int VolumeIndexFirst => Parts?.FirstOrDefault()?.Index ?? 0;
- public int VolumeIndexLast => Parts?.LastOrDefault()?.Index ?? 0;
+ public int VolumeIndexFirst => Parts.FirstOrDefault()?.Index ?? 0;
+ public int VolumeIndexLast => Parts.LastOrDefault()?.Index ?? 0;
///
- public override string ToString() => Key;
+ public override string ToString() => Key ?? "Entry";
internal abstract IEnumerable Parts { get; }
diff --git a/src/SharpCompress/Common/ExtractionMethods.cs b/src/SharpCompress/Common/ExtractionMethods.cs
index c8e5896e..27d41648 100644
--- a/src/SharpCompress/Common/ExtractionMethods.cs
+++ b/src/SharpCompress/Common/ExtractionMethods.cs
@@ -16,7 +16,7 @@ internal static class ExtractionMethods
)
{
string destinationFileName;
- string fullDestinationDirectoryPath = Path.GetFullPath(destinationDirectory);
+ var fullDestinationDirectoryPath = Path.GetFullPath(destinationDirectory);
//check for trailing slash.
if (
@@ -36,11 +36,12 @@ internal static class ExtractionMethods
options ??= new ExtractionOptions() { Overwrite = true };
- string file = Path.GetFileName(entry.Key);
+ var file = Path.GetFileName(entry.Key.NotNull("Entry Key is null")).NotNull("File is null");
if (options.ExtractFullPath)
{
- string folder = Path.GetDirectoryName(entry.Key)!;
- string destdir = Path.GetFullPath(Path.Combine(fullDestinationDirectoryPath, folder));
+ var folder = Path.GetDirectoryName(entry.Key.NotNull("Entry Key is null"))
+ .NotNull("Directory is null");
+ var destdir = Path.GetFullPath(Path.Combine(fullDestinationDirectoryPath, folder));
if (!Directory.Exists(destdir))
{
@@ -102,7 +103,7 @@ internal static class ExtractionMethods
}
else
{
- FileMode fm = FileMode.Create;
+ var fm = FileMode.Create;
options ??= new ExtractionOptions() { Overwrite = true };
if (!options.Overwrite)
diff --git a/src/SharpCompress/Common/FilePart.cs b/src/SharpCompress/Common/FilePart.cs
index 3c286d54..23b8b400 100644
--- a/src/SharpCompress/Common/FilePart.cs
+++ b/src/SharpCompress/Common/FilePart.cs
@@ -8,7 +8,7 @@ public abstract class FilePart
internal ArchiveEncoding ArchiveEncoding { get; }
- internal abstract string FilePartName { get; }
+ internal abstract string? FilePartName { get; }
public int Index { get; set; }
internal abstract Stream GetCompressedStream();
diff --git a/src/SharpCompress/Common/GZip/GZipEntry.cs b/src/SharpCompress/Common/GZip/GZipEntry.cs
index bb9a22da..9a551d07 100644
--- a/src/SharpCompress/Common/GZip/GZipEntry.cs
+++ b/src/SharpCompress/Common/GZip/GZipEntry.cs
@@ -6,23 +6,23 @@ namespace SharpCompress.Common.GZip;
public class GZipEntry : Entry
{
- private readonly GZipFilePart _filePart;
+ private readonly GZipFilePart? _filePart;
- internal GZipEntry(GZipFilePart filePart) => _filePart = filePart;
+ internal GZipEntry(GZipFilePart? filePart) => _filePart = filePart;
public override CompressionType CompressionType => CompressionType.GZip;
- public override long Crc => _filePart.Crc ?? 0;
+ public override long Crc => _filePart?.Crc ?? 0;
- public override string Key => _filePart.FilePartName;
+ public override string? Key => _filePart?.FilePartName;
public override string? LinkTarget => null;
public override long CompressedSize => 0;
- public override long Size => _filePart.UncompressedSize ?? 0;
+ public override long Size => _filePart?.UncompressedSize ?? 0;
- public override DateTime? LastModifiedTime => _filePart.DateModified;
+ public override DateTime? LastModifiedTime => _filePart?.DateModified;
public override DateTime? CreatedTime => null;
@@ -36,7 +36,7 @@ public class GZipEntry : Entry
public override bool IsSplitAfter => false;
- internal override IEnumerable Parts => _filePart.AsEnumerable();
+ internal override IEnumerable Parts => _filePart.Empty();
internal static IEnumerable GetEntries(Stream stream, OptionsBase options)
{
diff --git a/src/SharpCompress/Common/GZip/GZipFilePart.cs b/src/SharpCompress/Common/GZip/GZipFilePart.cs
index fbf4ee45..4a1c9515 100644
--- a/src/SharpCompress/Common/GZip/GZipFilePart.cs
+++ b/src/SharpCompress/Common/GZip/GZipFilePart.cs
@@ -34,7 +34,7 @@ internal sealed class GZipFilePart : FilePart
internal uint? Crc { get; private set; }
internal uint? UncompressedSize { get; private set; }
- internal override string FilePartName => _name!;
+ internal override string? FilePartName => _name;
internal override Stream GetCompressedStream() =>
new DeflateStream(_stream, CompressionMode.Decompress, CompressionLevel.Default);
diff --git a/src/SharpCompress/Common/GZip/GZipVolume.cs b/src/SharpCompress/Common/GZip/GZipVolume.cs
index 0dd9b8d9..600ba8e3 100644
--- a/src/SharpCompress/Common/GZip/GZipVolume.cs
+++ b/src/SharpCompress/Common/GZip/GZipVolume.cs
@@ -5,7 +5,7 @@ namespace SharpCompress.Common.GZip;
public class GZipVolume : Volume
{
- public GZipVolume(Stream stream, ReaderOptions options, int index = 0)
+ public GZipVolume(Stream stream, ReaderOptions? options, int index)
: base(stream, options, index) { }
public GZipVolume(FileInfo fileInfo, ReaderOptions options)
diff --git a/src/SharpCompress/Common/IEntry.cs b/src/SharpCompress/Common/IEntry.cs
index df1fa603..56e1db81 100644
--- a/src/SharpCompress/Common/IEntry.cs
+++ b/src/SharpCompress/Common/IEntry.cs
@@ -9,7 +9,7 @@ public interface IEntry
long CompressedSize { get; }
long Crc { get; }
DateTime? CreatedTime { get; }
- string Key { get; }
+ string? Key { get; }
string? LinkTarget { get; }
bool IsDirectory { get; }
bool IsEncrypted { get; }
diff --git a/src/SharpCompress/Common/IVolume.cs b/src/SharpCompress/Common/IVolume.cs
index abbc0406..aed35fd0 100644
--- a/src/SharpCompress/Common/IVolume.cs
+++ b/src/SharpCompress/Common/IVolume.cs
@@ -6,5 +6,5 @@ public interface IVolume : IDisposable
{
int Index { get; }
- string FileName { get; }
+ string? FileName { get; }
}
diff --git a/src/SharpCompress/Common/OptionsBase.cs b/src/SharpCompress/Common/OptionsBase.cs
index 61a6cb55..8d1cbd1c 100644
--- a/src/SharpCompress/Common/OptionsBase.cs
+++ b/src/SharpCompress/Common/OptionsBase.cs
@@ -7,5 +7,5 @@ public class OptionsBase
///
public bool LeaveStreamOpen { get; set; } = true;
- public ArchiveEncoding ArchiveEncoding { get; set; } = new ArchiveEncoding();
+ public ArchiveEncoding ArchiveEncoding { get; set; } = new();
}
diff --git a/src/SharpCompress/Common/PasswordProtectedException.cs b/src/SharpCompress/Common/PasswordProtectedException.cs
deleted file mode 100644
index 9ebe3d65..00000000
--- a/src/SharpCompress/Common/PasswordProtectedException.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System;
-
-namespace SharpCompress.Common;
-
-public class PasswordProtectedException : ExtractionException
-{
- public PasswordProtectedException(string message)
- : base(message) { }
-
- public PasswordProtectedException(string message, Exception inner)
- : base(message, inner) { }
-}
diff --git a/src/SharpCompress/Common/Rar/CryptKey3.cs b/src/SharpCompress/Common/Rar/CryptKey3.cs
new file mode 100644
index 00000000..93e451b1
--- /dev/null
+++ b/src/SharpCompress/Common/Rar/CryptKey3.cs
@@ -0,0 +1,84 @@
+#nullable disable
+
+using System.Security.Cryptography;
+using System.Text;
+using SharpCompress.Common.Rar.Headers;
+
+namespace SharpCompress.Common.Rar;
+
+internal class CryptKey3 : ICryptKey
+{
+ const int AES_128 = 128;
+
+ private string _password;
+
+ public CryptKey3(string password) => _password = password ?? "";
+
+ public ICryptoTransform Transformer(byte[] salt)
+ {
+ var aesIV = new byte[EncryptionConstV5.SIZE_INITV];
+
+ var rawLength = 2 * _password.Length;
+ var rawPassword = new byte[rawLength + EncryptionConstV5.SIZE_SALT30];
+ var passwordBytes = Encoding.UTF8.GetBytes(_password);
+ for (var i = 0; i < _password.Length; i++)
+ {
+ rawPassword[i * 2] = passwordBytes[i];
+ rawPassword[(i * 2) + 1] = 0;
+ }
+
+ for (var i = 0; i < salt.Length; i++)
+ {
+ rawPassword[i + rawLength] = salt[i];
+ }
+
+ var msgDigest = SHA1.Create();
+ const int noOfRounds = (1 << 18);
+ const int iblock = 3;
+
+ byte[] digest;
+ var data = new byte[(rawPassword.Length + iblock) * noOfRounds];
+
+ //TODO slow code below, find ways to optimize
+ for (var i = 0; i < noOfRounds; i++)
+ {
+ rawPassword.CopyTo(data, i * (rawPassword.Length + iblock));
+
+ data[(i * (rawPassword.Length + iblock)) + rawPassword.Length + 0] = (byte)i;
+ data[(i * (rawPassword.Length + iblock)) + rawPassword.Length + 1] = (byte)(i >> 8);
+ data[(i * (rawPassword.Length + iblock)) + rawPassword.Length + 2] = (byte)(i >> 16);
+
+ if (i % (noOfRounds / EncryptionConstV5.SIZE_INITV) == 0)
+ {
+ digest = msgDigest.ComputeHash(data, 0, (i + 1) * (rawPassword.Length + iblock));
+ aesIV[i / (noOfRounds / EncryptionConstV5.SIZE_INITV)] = digest[19];
+ }
+ }
+ digest = msgDigest.ComputeHash(data);
+ //slow code ends
+
+ var aesKey = new byte[EncryptionConstV5.SIZE_INITV];
+ for (var i = 0; i < 4; i++)
+ {
+ for (var j = 0; j < 4; j++)
+ {
+ aesKey[(i * 4) + j] = (byte)(
+ (
+ ((digest[i * 4] * 0x1000000) & 0xff000000)
+ | (uint)((digest[(i * 4) + 1] * 0x10000) & 0xff0000)
+ | (uint)((digest[(i * 4) + 2] * 0x100) & 0xff00)
+ | (uint)(digest[(i * 4) + 3] & 0xff)
+ ) >> (j * 8)
+ );
+ }
+ }
+
+ var aes = Aes.Create();
+ aes.KeySize = AES_128;
+ aes.Mode = CipherMode.CBC;
+ aes.Padding = PaddingMode.None;
+ aes.Key = aesKey;
+ aes.IV = aesIV;
+ return aes.CreateDecryptor();
+ }
+}
diff --git a/src/SharpCompress/Common/Rar/CryptKey5.cs b/src/SharpCompress/Common/Rar/CryptKey5.cs
new file mode 100644
index 00000000..0b802691
--- /dev/null
+++ b/src/SharpCompress/Common/Rar/CryptKey5.cs
@@ -0,0 +1,95 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using SharpCompress.Common.Rar.Headers;
+
+namespace SharpCompress.Common.Rar;
+
+internal class CryptKey5 : ICryptKey
+{
+ const int AES_256 = 256;
+ const int DERIVED_KEY_LENGTH = 0x10;
+ const int SHA256_DIGEST_SIZE = 32;
+
+ private string _password;
+ private Rar5CryptoInfo _cryptoInfo;
+ private byte[] _pswCheck = { };
+ private byte[] _hashKey = { };
+
+ public CryptKey5(string password, Rar5CryptoInfo rar5CryptoInfo)
+ {
+ _password = password ?? "";
+ _cryptoInfo = rar5CryptoInfo;
+ }
+
+ public byte[] PswCheck => _pswCheck;
+
+ public byte[] HashKey => _hashKey;
+
+ private static List GenerateRarPBKDF2Key(
+ string password,
+ byte[] salt,
+ int iterations,
+ int keyLength
+ )
+ {
+ using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(password));
+ var block = hmac.ComputeHash(salt);
+ var finalHash = (byte[])block.Clone();
+
+ var loop = new int[] { iterations, 17, 17 };
+ var res = new List { };
+
+ for (var x = 0; x < 3; x++)
+ {
+ for (var i = 1; i < loop[x]; i++)
+ {
+ block = hmac.ComputeHash(block);
+ for (var j = 0; j < finalHash.Length; j++)
+ {
+ finalHash[j] ^= block[j];
+ }
+ }
+
+ res.Add((byte[])finalHash.Clone());
+ }
+
+ return res;
+ }
+
+ public ICryptoTransform Transformer(byte[] salt)
+ {
+ var iterations = (1 << _cryptoInfo.LG2Count); // Adjust the number of iterations as needed
+
+ var salt_rar5 = salt.Concat(new byte[] { 0, 0, 0, 1 });
+ var derivedKey = GenerateRarPBKDF2Key(
+ _password,
+ salt_rar5.ToArray(),
+ iterations,
+ DERIVED_KEY_LENGTH
+ );
+
+ _hashKey = derivedKey[1];
+
+ _pswCheck = new byte[EncryptionConstV5.SIZE_PSWCHECK];
+
+ for (var i = 0; i < SHA256_DIGEST_SIZE; i++)
+ {
+ _pswCheck[i % EncryptionConstV5.SIZE_PSWCHECK] ^= derivedKey[2][i];
+ }
+
+ if (_cryptoInfo.UsePswCheck && !_cryptoInfo.PswCheck.SequenceEqual(_pswCheck))
+ {
+ throw new CryptographicException("The password did not match.");
+ }
+
+ var aes = Aes.Create();
+ aes.KeySize = AES_256;
+ aes.Mode = CipherMode.CBC;
+ aes.Padding = PaddingMode.None;
+ aes.Key = derivedKey[0];
+ aes.IV = _cryptoInfo.InitV;
+ return aes.CreateDecryptor();
+ }
+}
diff --git a/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs b/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs
index 619e8fc9..5aa29d49 100644
--- a/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs
+++ b/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs
@@ -1,50 +1,19 @@
#nullable disable
+using System;
+using System.Security.Cryptography;
+using SharpCompress.Common.Rar.Headers;
using SharpCompress.IO;
namespace SharpCompress.Common.Rar.Headers;
internal class ArchiveCryptHeader : RarHeader
{
- private const int CRYPT_VERSION = 0; // Supported encryption version.
- private const int SIZE_SALT50 = 16;
- private const int SIZE_PSWCHECK = 8;
- private const int SIZE_PSWCHECK_CSUM = 4;
- private const int CRYPT5_KDF_LG2_COUNT_MAX = 24; // LOG2 of maximum accepted iteration count.
-
- private bool _usePswCheck;
- private uint _lg2Count; // Log2 of PBKDF2 repetition count.
- private byte[] _salt;
- private byte[] _pswCheck;
- private byte[] _pswCheckCsm;
-
public ArchiveCryptHeader(RarHeader header, RarCrcBinaryReader reader)
: base(header, reader, HeaderType.Crypt) { }
- protected override void ReadFinish(MarkingBinaryReader reader)
- {
- var cryptVersion = reader.ReadRarVIntUInt32();
- if (cryptVersion > CRYPT_VERSION)
- {
- //error?
- return;
- }
- var encryptionFlags = reader.ReadRarVIntUInt32();
- _usePswCheck = FlagUtility.HasFlag(encryptionFlags, EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK);
- _lg2Count = reader.ReadRarVIntByte(1);
+ public Rar5CryptoInfo CryptInfo = new();
- //UsePswCheck = HasHeaderFlag(EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK);
- if (_lg2Count > CRYPT5_KDF_LG2_COUNT_MAX)
- {
- //error?
- return;
- }
-
- _salt = reader.ReadBytes(SIZE_SALT50);
- if (_usePswCheck)
- {
- _pswCheck = reader.ReadBytes(SIZE_PSWCHECK);
- _pswCheckCsm = reader.ReadBytes(SIZE_PSWCHECK_CSUM);
- }
- }
+ protected override void ReadFinish(MarkingBinaryReader reader) =>
+ CryptInfo = new Rar5CryptoInfo(reader, false);
}
diff --git a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs
index e95052ef..eea8293d 100644
--- a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs
+++ b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs
@@ -1,5 +1,11 @@
#nullable disable
+using System;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using SharpCompress.IO;
#if !Rar2017_64bit
using size_t = System.UInt32;
#else
@@ -8,16 +14,11 @@ using nuint = System.UInt64;
using size_t = System.UInt64;
#endif
-using SharpCompress.IO;
-using System;
-using System.IO;
-using System.Text;
-
namespace SharpCompress.Common.Rar.Headers;
internal class FileHeader : RarHeader
{
- private uint _fileCrc;
+ private byte[] _hash;
public FileHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType)
: base(header, reader, headerType) { }
@@ -52,7 +53,7 @@ internal class FileHeader : RarHeader
if (HasFlag(FileFlagsV5.HAS_CRC32))
{
- FileCrc = reader.ReadUInt32();
+ FileCrc = reader.ReadBytes(4);
}
var compressionInfo = reader.ReadRarVIntUInt16();
@@ -104,7 +105,13 @@ internal class FileHeader : RarHeader
throw new InvalidFormatException("rar5 header size / extra size inconsistency");
}
- isEncryptedRar5 = false;
+ const ushort FHEXTRA_CRYPT = 0x01;
+ const ushort FHEXTRA_HASH = 0x02;
+ const ushort FHEXTRA_HTIME = 0x03;
+ // const ushort FHEXTRA_VERSION = 0x04;
+ const ushort FHEXTRA_REDIR = 0x05;
+ // const ushort FHEXTRA_UOWNER = 0x06;
+ // const ushort FHEXTRA_SUBDATA = 0x07;
while (RemainingHeaderBytes(reader) > 0)
{
@@ -113,23 +120,30 @@ internal class FileHeader : RarHeader
var type = reader.ReadRarVIntUInt16();
switch (type)
{
- //TODO
- case 1: // file encryption
-
+ case FHEXTRA_CRYPT: // file encryption
{
- isEncryptedRar5 = true;
+ Rar5CryptoInfo = new Rar5CryptoInfo(reader, true);
- //var version = reader.ReadRarVIntByte();
- //if (version != 0) throw new InvalidFormatException("unknown encryption algorithm " + version);
+ if (Rar5CryptoInfo.PswCheck.All(singleByte => singleByte == 0))
+ {
+ Rar5CryptoInfo = null;
+ }
}
break;
- // case 2: // file hash
- // {
- //
- // }
- // break;
- case 3: // file time
-
+ case FHEXTRA_HASH:
+ {
+ const uint FHEXTRA_HASH_BLAKE2 = 0x0;
+ // const uint HASH_BLAKE2 = 0x03;
+ const int BLAKE2_DIGEST_SIZE = 0x20;
+ if ((uint)reader.ReadRarVInt() == FHEXTRA_HASH_BLAKE2)
+ {
+ // var hash = HASH_BLAKE2;
+ _hash = reader.ReadBytes(BLAKE2_DIGEST_SIZE);
+ }
+ // enum HASH_TYPE {HASH_NONE,HASH_RAR14,HASH_CRC32,HASH_BLAKE2};
+ }
+ break;
+ case FHEXTRA_HTIME: // file time
{
var flags = reader.ReadRarVIntUInt16();
var isWindowsTime = (flags & 1) == 0;
@@ -148,22 +162,27 @@ internal class FileHeader : RarHeader
}
break;
//TODO
- // case 4: // file version
+ // case FHEXTRA_VERSION: // file version
// {
//
// }
// break;
- // case 5: // file system redirection
+ case FHEXTRA_REDIR: // file system redirection
+ {
+ RedirType = reader.ReadRarVIntByte();
+ RedirFlags = reader.ReadRarVIntByte();
+ var nn = reader.ReadRarVIntUInt16();
+ var bb = reader.ReadBytes(nn);
+ RedirTargetName = ConvertPathV5(Encoding.UTF8.GetString(bb, 0, bb.Length));
+ }
+ break;
+ //TODO
+ // case FHEXTRA_UOWNER: // unix owner
// {
//
// }
// break;
- // case 6: // unix owner
- // {
- //
- // }
- // break;
- // case 7: // service data
+ // case FHEXTRA_SUBDATA: // service data
// {
//
// }
@@ -171,6 +190,7 @@ internal class FileHeader : RarHeader
default:
// skip unknown record types to allow new record types to be added in the future
+ //Console.WriteLine($"unhandled rar header field type {type}");
break;
}
// drain any trailing bytes of extra record
@@ -222,7 +242,7 @@ internal class FileHeader : RarHeader
HostOs = reader.ReadByte();
- FileCrc = reader.ReadUInt32();
+ FileCrc = reader.ReadBytes(4);
FileLastModifiedTime = Utility.DosDateToDateTime(reader.ReadUInt32());
@@ -255,13 +275,11 @@ internal class FileHeader : RarHeader
var fileNameBytes = reader.ReadBytes(nameSize);
- const int saltSize = 8;
const int newLhdSize = 32;
switch (HeaderCode)
{
case HeaderCodeV.RAR4_FILE_HEADER:
-
{
if (HasFlag(FileFlagsV4.UNICODE))
{
@@ -288,12 +306,11 @@ internal class FileHeader : RarHeader
}
break;
case HeaderCodeV.RAR4_NEW_SUB_HEADER:
-
{
var datasize = HeaderSize - newLhdSize - nameSize;
if (HasFlag(FileFlagsV4.SALT))
{
- datasize -= saltSize;
+ datasize -= EncryptionConstV5.SIZE_SALT30;
}
if (datasize > 0)
{
@@ -314,7 +331,7 @@ internal class FileHeader : RarHeader
if (HasFlag(FileFlagsV4.SALT))
{
- R4Salt = reader.ReadBytes(saltSize);
+ R4Salt = reader.ReadBytes(EncryptionConstV5.SIZE_SALT30);
}
if (HasFlag(FileFlagsV4.EXT_TIME))
{
@@ -395,18 +412,10 @@ internal class FileHeader : RarHeader
private bool HasFlag(ushort flag) => (Flags & flag) == flag;
- internal uint FileCrc
+ internal byte[] FileCrc
{
- get
- {
- if (IsRar5 && !HasFlag(FileFlagsV5.HAS_CRC32))
- {
- //!!! rar5:
- throw new InvalidOperationException("TODO rar5");
- }
- return _fileCrc;
- }
- private set => _fileCrc = value;
+ get => _hash;
+ private set => _hash = value;
}
// 0 - storing
@@ -428,11 +437,17 @@ internal class FileHeader : RarHeader
public bool IsSolid { get; private set; }
+ public byte RedirType { get; private set; }
+ public bool IsRedir => RedirType != 0;
+ public byte RedirFlags { get; private set; }
+ public bool IsRedirDirectory => (RedirFlags & RedirFlagV5.DIRECTORY) != 0;
+ public string RedirTargetName { get; private set; }
+
// unused for UnpackV1 implementation (limitation)
internal size_t WindowSize { get; private set; }
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; }
@@ -450,8 +465,7 @@ internal class FileHeader : RarHeader
public bool IsDirectory => HasFlag(IsRar5 ? FileFlagsV5.DIRECTORY : FileFlagsV4.DIRECTORY);
- private bool isEncryptedRar5 = false;
- public bool IsEncrypted => IsRar5 ? isEncryptedRar5 : HasFlag(FileFlagsV4.PASSWORD);
+ public bool IsEncrypted => IsRar5 ? Rar5CryptoInfo != null : HasFlag(FileFlagsV4.PASSWORD);
internal DateTime? FileLastModifiedTime { get; private set; }
diff --git a/src/SharpCompress/Common/Rar/Headers/Flags.cs b/src/SharpCompress/Common/Rar/Headers/Flags.cs
index 5a52f001..990dbc99 100644
--- a/src/SharpCompress/Common/Rar/Headers/Flags.cs
+++ b/src/SharpCompress/Common/Rar/Headers/Flags.cs
@@ -50,6 +50,17 @@ internal static class EncryptionFlagsV5
public const uint FHEXTRA_CRYPT_HASHMAC = 0x02;
}
+internal static class EncryptionConstV5
+{
+ public const int VERSION = 0;
+ public const uint CRYPT5_KDF_LG2_COUNT_MAX = 0x24;
+ public const int SIZE_SALT30 = 0x08;
+ public const int SIZE_SALT50 = 0x10;
+ public const int SIZE_INITV = 0x10;
+ public const int SIZE_PSWCHECK = 0x08;
+ public const int SIZE_PSWCHECK_CSUM = 0x04;
+}
+
internal static class HeaderFlagsV5
{
public const ushort HAS_EXTRA = 0x0001;
@@ -146,3 +157,17 @@ internal static class EndArchiveFlagsV5
{
public const ushort HAS_NEXT_VOLUME = 0x0001;
}
+
+internal static class RedirTypeV5
+{
+ public const byte UNIX_SYMLINK = 0x0001;
+ public const byte WIN_SYMLINK = 0x0002;
+ public const byte WIN_JUNCTION = 0x0003;
+ public const byte HARD_LINK = 0x0004;
+ public const byte FILE_COPY = 0x0005;
+}
+
+internal static class RedirFlagV5
+{
+ public const byte DIRECTORY = 0x0001;
+}
diff --git a/src/SharpCompress/Common/Rar/Headers/RarHeader.cs b/src/SharpCompress/Common/Rar/Headers/RarHeader.cs
index 81002fc4..0d8648e8 100644
--- a/src/SharpCompress/Common/Rar/Headers/RarHeader.cs
+++ b/src/SharpCompress/Common/Rar/Headers/RarHeader.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.IO;
using SharpCompress.IO;
diff --git a/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs
index d371166d..74d68fc7 100644
--- a/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs
+++ b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs
@@ -1,5 +1,7 @@
using System.Collections.Generic;
using System.IO;
+using System.Linq;
+using SharpCompress.Common.Rar;
using SharpCompress.IO;
using SharpCompress.Readers;
@@ -9,6 +11,8 @@ public class RarHeaderFactory
{
private bool _isRar5;
+ private Rar5CryptoInfo? _cryptInfo;
+
public RarHeaderFactory(StreamingMode mode, ReaderOptions options)
{
StreamingMode = mode;
@@ -53,7 +57,19 @@ public class RarHeaderFactory
"Encrypted Rar archive has no password specified."
);
}
- reader = new RarCryptoBinaryReader(stream, Options.Password);
+
+ if (_isRar5 && _cryptInfo != null)
+ {
+ _cryptInfo.ReadInitV(new MarkingBinaryReader(stream));
+ var _headerKey = new CryptKey5(Options.Password!, _cryptInfo);
+
+ reader = new RarCryptoBinaryReader(stream, _headerKey, _cryptInfo.Salt);
+ }
+ else
+ {
+ var key = new CryptKey3(Options.Password);
+ reader = new RarCryptoBinaryReader(stream, key);
+ }
}
var header = RarHeader.TryReadBase(reader, _isRar5, Options.ArchiveEncoding);
@@ -82,13 +98,11 @@ public class RarHeaderFactory
switch (StreamingMode)
{
case StreamingMode.Seekable:
-
{
reader.BaseStream.Position += ph.DataSize;
}
break;
case StreamingMode.Streaming:
-
{
reader.BaseStream.Skip(ph.DataSize);
}
@@ -105,7 +119,14 @@ public class RarHeaderFactory
case HeaderCodeV.RAR5_SERVICE_HEADER:
{
var fh = new FileHeader(header, reader, HeaderType.Service);
- SkipData(fh, reader);
+ if (fh.FileName == "CMT")
+ {
+ fh.PackedStream = new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize);
+ }
+ else
+ {
+ SkipData(fh, reader);
+ }
return fh;
}
@@ -123,17 +144,15 @@ public class RarHeaderFactory
switch (StreamingMode)
{
case StreamingMode.Seekable:
-
{
fh.DataStartPosition = reader.BaseStream.Position;
reader.BaseStream.Position += fh.CompressedSize;
}
break;
case StreamingMode.Streaming:
-
{
var ms = new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize);
- if (fh.R4Salt is null)
+ if (fh.R4Salt is null && fh.Rar5CryptoInfo is null)
{
fh.PackedStream = ms;
}
@@ -141,8 +160,10 @@ public class RarHeaderFactory
{
fh.PackedStream = new RarCryptoWrapper(
ms,
- Options.Password!,
- fh.R4Salt
+ fh.R4Salt is null ? fh.Rar5CryptoInfo.Salt : fh.R4Salt,
+ fh.R4Salt is null
+ ? new CryptKey5(Options.Password!, fh.Rar5CryptoInfo)
+ : new CryptKey3(Options.Password!)
);
}
}
@@ -161,9 +182,11 @@ public class RarHeaderFactory
}
case HeaderCodeV.RAR5_ARCHIVE_ENCRYPTION_HEADER:
{
- var ch = new ArchiveCryptHeader(header, reader);
+ var cryptoHeader = new ArchiveCryptHeader(header, reader);
IsEncrypted = true;
- return ch;
+ _cryptInfo = cryptoHeader.CryptInfo;
+
+ return cryptoHeader;
}
default:
{
@@ -177,14 +200,12 @@ public class RarHeaderFactory
switch (StreamingMode)
{
case StreamingMode.Seekable:
-
{
fh.DataStartPosition = reader.BaseStream.Position;
reader.BaseStream.Position += fh.CompressedSize;
}
break;
case StreamingMode.Streaming:
-
{
//skip the data because it's useless?
reader.BaseStream.Skip(fh.CompressedSize);
diff --git a/src/SharpCompress/Common/Rar/ICryptKey.cs b/src/SharpCompress/Common/Rar/ICryptKey.cs
new file mode 100644
index 00000000..94f068f5
--- /dev/null
+++ b/src/SharpCompress/Common/Rar/ICryptKey.cs
@@ -0,0 +1,8 @@
+using System.Security.Cryptography;
+
+namespace SharpCompress.Common.Rar;
+
+internal interface ICryptKey
+{
+ ICryptoTransform Transformer(byte[] salt);
+}
diff --git a/src/SharpCompress/Common/Rar/Rar5CryptoInfo.cs b/src/SharpCompress/Common/Rar/Rar5CryptoInfo.cs
new file mode 100644
index 00000000..7b8edff9
--- /dev/null
+++ b/src/SharpCompress/Common/Rar/Rar5CryptoInfo.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Security.Cryptography;
+using SharpCompress.Common.Rar.Headers;
+using SharpCompress.IO;
+
+namespace SharpCompress.Common.Rar;
+
+internal class Rar5CryptoInfo
+{
+ public Rar5CryptoInfo() { }
+
+ public Rar5CryptoInfo(MarkingBinaryReader reader, bool readInitV)
+ {
+ var cryptVersion = reader.ReadRarVIntUInt32();
+ if (cryptVersion > EncryptionConstV5.VERSION)
+ {
+ throw new CryptographicException($"Unsupported crypto version of {cryptVersion}");
+ }
+ var encryptionFlags = reader.ReadRarVIntUInt32();
+ UsePswCheck = FlagUtility.HasFlag(encryptionFlags, EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK);
+ LG2Count = reader.ReadRarVIntByte(1);
+
+ if (LG2Count > EncryptionConstV5.CRYPT5_KDF_LG2_COUNT_MAX)
+ {
+ throw new CryptographicException($"Unsupported LG2 count of {LG2Count}.");
+ }
+
+ Salt = reader.ReadBytes(EncryptionConstV5.SIZE_SALT50);
+
+ if (readInitV) // File header needs to read IV here
+ {
+ ReadInitV(reader);
+ }
+
+ if (UsePswCheck)
+ {
+ PswCheck = reader.ReadBytes(EncryptionConstV5.SIZE_PSWCHECK);
+ var _pswCheckCsm = reader.ReadBytes(EncryptionConstV5.SIZE_PSWCHECK_CSUM);
+
+ var sha = SHA256.Create();
+ UsePswCheck = sha.ComputeHash(PswCheck).AsSpan().StartsWith(_pswCheckCsm.AsSpan());
+ }
+ }
+
+ public void ReadInitV(MarkingBinaryReader reader) =>
+ InitV = reader.ReadBytes(EncryptionConstV5.SIZE_INITV);
+
+ public bool UsePswCheck = false;
+
+ public int LG2Count = 0;
+
+ public byte[] InitV = { };
+
+ public byte[] Salt = { };
+
+ public byte[] PswCheck = { };
+}
diff --git a/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs b/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs
index 0be6e74e..6e44286b 100644
--- a/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs
+++ b/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs
@@ -1,29 +1,29 @@
-using System.Collections.Generic;
+#nullable disable
+
+using System.Collections.Generic;
using System.IO;
+using SharpCompress.Common.Rar.Headers;
+using SharpCompress.Crypto;
namespace SharpCompress.Common.Rar;
internal sealed class RarCryptoBinaryReader : RarCrcBinaryReader
{
- private RarRijndael _rijndael;
- private byte[] _salt;
- private readonly string _password;
- private readonly Queue _data = new Queue();
+ private BlockTransformer _rijndael;
+ private readonly Queue _data = new();
private long _readCount;
- public RarCryptoBinaryReader(Stream stream, string password)
+ public RarCryptoBinaryReader(Stream stream, ICryptKey cryptKey)
: base(stream)
{
- _password = password;
-
- // coderb: not sure why this was being done at this logical point
- //SkipQueue();
- var salt = ReadBytes(8);
-
- _salt = salt;
- _rijndael = RarRijndael.InitializeFrom(_password, salt);
+ var salt = base.ReadBytes(EncryptionConstV5.SIZE_SALT30);
+ _readCount += EncryptionConstV5.SIZE_SALT30;
+ _rijndael = new BlockTransformer(cryptKey.Transformer(salt));
}
+ public RarCryptoBinaryReader(Stream stream, ICryptKey cryptKey, byte[] salt)
+ : base(stream) => _rijndael = new BlockTransformer(cryptKey.Transformer(salt));
+
// track read count ourselves rather than using the underlying stream since we buffer
public override long CurrentReadByteCount
{
@@ -36,29 +36,9 @@ internal sealed class RarCryptoBinaryReader : RarCrcBinaryReader
public override void Mark() => _readCount = 0;
- private bool UseEncryption => _salt != null;
+ public override byte ReadByte() => ReadAndDecryptBytes(1)[0];
- public override byte ReadByte()
- {
- if (UseEncryption)
- {
- return ReadAndDecryptBytes(1)[0];
- }
-
- _readCount++;
- return base.ReadByte();
- }
-
- public override byte[] ReadBytes(int count)
- {
- if (UseEncryption)
- {
- return ReadAndDecryptBytes(count);
- }
-
- _readCount += count;
- return base.ReadBytes(count);
- }
+ public override byte[] ReadBytes(int count) => ReadAndDecryptBytes(count);
private byte[] ReadAndDecryptBytes(int count)
{
diff --git a/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs b/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs
index a1cee046..5500af8d 100644
--- a/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs
+++ b/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs
@@ -1,37 +1,30 @@
using System;
using System.Collections.Generic;
using System.IO;
+using SharpCompress.Crypto;
namespace SharpCompress.Common.Rar;
internal sealed class RarCryptoWrapper : Stream
{
private readonly Stream _actualStream;
- private readonly byte[] _salt;
- private RarRijndael _rijndael;
- private readonly Queue _data = new Queue();
+ private BlockTransformer _rijndael;
+ private readonly Queue _data = new();
- public RarCryptoWrapper(Stream actualStream, string password, byte[] salt)
+ public RarCryptoWrapper(Stream actualStream, byte[] salt, ICryptKey key)
{
_actualStream = actualStream;
- _salt = salt;
- _rijndael = RarRijndael.InitializeFrom(password ?? "", salt);
+ _rijndael = new BlockTransformer(key.Transformer(salt));
}
- public override void Flush() => throw new NotSupportedException();
+ public override void Flush() { }
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override void SetLength(long value) => throw new NotSupportedException();
- public override int Read(byte[] buffer, int offset, int count)
- {
- if (_salt is null)
- {
- return _actualStream.Read(buffer, offset, count);
- }
- return ReadAndDecrypt(buffer, offset, count);
- }
+ public override int Read(byte[] buffer, int offset, int count) =>
+ ReadAndDecrypt(buffer, offset, count);
public int ReadAndDecrypt(byte[] buffer, int offset, int count)
{
@@ -41,7 +34,7 @@ internal sealed class RarCryptoWrapper : Stream
if (sizeToRead > 0)
{
var alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf);
- Span cipherText = stackalloc byte[RarRijndael.CRYPTO_BLOCK_SIZE];
+ Span cipherText = stackalloc byte[16];
for (var i = 0; i < alignedSize / 16; i++)
{
//long ax = System.currentTimeMillis();
@@ -77,11 +70,11 @@ internal sealed class RarCryptoWrapper : Stream
protected override void Dispose(bool disposing)
{
- if (_rijndael != null)
+ if (disposing)
{
_rijndael.Dispose();
- _rijndael = null!;
}
+
base.Dispose(disposing);
}
}
diff --git a/src/SharpCompress/Common/Rar/RarEntry.cs b/src/SharpCompress/Common/Rar/RarEntry.cs
index 7f280e4a..a064c2f8 100644
--- a/src/SharpCompress/Common/Rar/RarEntry.cs
+++ b/src/SharpCompress/Common/Rar/RarEntry.cs
@@ -20,12 +20,12 @@ public abstract class RarEntry : Entry
///
/// The File's 32 bit CRC Hash
///
- public override long Crc => FileHeader.FileCrc;
+ public override long Crc => BitConverter.ToUInt32(FileHeader.FileCrc, 0);
///
/// The path of the file internal to the Rar Archive.
///
- public override string Key => FileHeader.FileName;
+ public override string? Key => FileHeader.FileName;
public override string? LinkTarget => null;
@@ -55,12 +55,21 @@ public abstract class RarEntry : Entry
public override bool IsEncrypted => FileHeader.IsEncrypted;
///
- /// Entry is password protected and encrypted and cannot be extracted.
+ /// Entry Windows file attributes
+ ///
+ public override int? Attrib => (int)FileHeader.FileAttributes;
+
+ ///
+ /// Entry is a directory
///
public override bool IsDirectory => FileHeader.IsDirectory;
public override bool IsSplitAfter => FileHeader.IsSplitAfter;
+ public bool IsRedir => FileHeader.IsRedir;
+
+ public string RedirTargetName => FileHeader.RedirTargetName;
+
public override string ToString() =>
string.Format(
"Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}",
diff --git a/src/SharpCompress/Common/Rar/RarRijndael.cs b/src/SharpCompress/Common/Rar/RarRijndael.cs
deleted file mode 100644
index 94592639..00000000
--- a/src/SharpCompress/Common/Rar/RarRijndael.cs
+++ /dev/null
@@ -1,114 +0,0 @@
-#nullable disable
-
-using System;
-using System.Security.Cryptography;
-using System.Text;
-using SharpCompress.Crypto;
-
-namespace SharpCompress.Common.Rar;
-
-internal class RarRijndael : IDisposable
-{
- internal const int CRYPTO_BLOCK_SIZE = 16;
-
- private readonly string _password;
- private readonly byte[] _salt;
- private byte[] _aesInitializationVector;
- private RijndaelEngine _rijndael;
-
- private RarRijndael(string password, byte[] salt)
- {
- _password = password;
- _salt = salt;
- }
-
- private void Initialize()
- {
- _rijndael = new RijndaelEngine();
- _aesInitializationVector = new byte[CRYPTO_BLOCK_SIZE];
- var rawLength = 2 * _password.Length;
- var rawPassword = new byte[rawLength + 8];
- var passwordBytes = Encoding.UTF8.GetBytes(_password);
- for (var i = 0; i < _password.Length; i++)
- {
- rawPassword[i * 2] = passwordBytes[i];
- rawPassword[(i * 2) + 1] = 0;
- }
- for (var i = 0; i < _salt.Length; i++)
- {
- rawPassword[i + rawLength] = _salt[i];
- }
-
- const int noOfRounds = (1 << 18);
- const int iblock = 3;
- byte[] digest;
- var data = new byte[(rawPassword.Length + iblock) * noOfRounds];
-
- //TODO slow code below, find ways to optimize
- for (var i = 0; i < noOfRounds; i++)
- {
- rawPassword.CopyTo(data, i * (rawPassword.Length + iblock));
-
- data[(i * (rawPassword.Length + iblock)) + rawPassword.Length + 0] = (byte)i;
- data[(i * (rawPassword.Length + iblock)) + rawPassword.Length + 1] = (byte)(i >> 8);
- data[(i * (rawPassword.Length + iblock)) + rawPassword.Length + 2] = (byte)(
- i >> CRYPTO_BLOCK_SIZE
- );
-
- if (i % (noOfRounds / CRYPTO_BLOCK_SIZE) == 0)
- {
- digest = SHA1.Create()
- .ComputeHash(data, 0, (i + 1) * (rawPassword.Length + iblock));
- _aesInitializationVector[i / (noOfRounds / CRYPTO_BLOCK_SIZE)] = digest[19];
- }
- }
- digest = SHA1.Create().ComputeHash(data);
- //slow code ends
-
- var aesKey = new byte[CRYPTO_BLOCK_SIZE];
- for (var i = 0; i < 4; i++)
- {
- for (var j = 0; j < 4; j++)
- {
- aesKey[(i * 4) + j] = (byte)(
- (
- ((digest[i * 4] * 0x1000000) & 0xff000000)
- | (uint)((digest[(i * 4) + 1] * 0x10000) & 0xff0000)
- | (uint)((digest[(i * 4) + 2] * 0x100) & 0xff00)
- | (uint)(digest[(i * 4) + 3] & 0xff)
- ) >> (j * 8)
- );
- }
- }
-
- _rijndael.Init(false, new KeyParameter(aesKey));
- }
-
- public static RarRijndael InitializeFrom(string password, byte[] salt)
- {
- var rijndael = new RarRijndael(password, salt);
- rijndael.Initialize();
- return rijndael;
- }
-
- public byte[] ProcessBlock(ReadOnlySpan cipherText)
- {
- Span plainText = stackalloc byte[CRYPTO_BLOCK_SIZE]; // 16 bytes
- var decryptedBytes = new byte[CRYPTO_BLOCK_SIZE];
- _rijndael.ProcessBlock(cipherText, plainText);
-
- for (var j = 0; j < CRYPTO_BLOCK_SIZE; j++)
- {
- decryptedBytes[j] = (byte)(plainText[j] ^ _aesInitializationVector[j % 16]); //32:114, 33:101
- }
-
- for (var j = 0; j < _aesInitializationVector.Length; j++)
- {
- _aesInitializationVector[j] = cipherText[j];
- }
-
- return decryptedBytes;
- }
-
- public void Dispose() { }
-}
diff --git a/src/SharpCompress/Common/Rar/RarVolume.cs b/src/SharpCompress/Common/Rar/RarVolume.cs
index 7be719ec..d05e16c2 100644
--- a/src/SharpCompress/Common/Rar/RarVolume.cs
+++ b/src/SharpCompress/Common/Rar/RarVolume.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.IO;
using SharpCompress.Readers;
@@ -14,17 +15,14 @@ namespace SharpCompress.Common.Rar;
public abstract class RarVolume : Volume
{
private readonly RarHeaderFactory _headerFactory;
- internal int _maxCompressionAlgorithm;
+ private int _maxCompressionAlgorithm;
- internal RarVolume(StreamingMode mode, Stream stream, ReaderOptions options, int index = 0)
+ internal RarVolume(StreamingMode mode, Stream stream, ReaderOptions options, int index)
: base(stream, options, index) => _headerFactory = new RarHeaderFactory(mode, options);
-#nullable disable
- internal ArchiveHeader ArchiveHeader { get; private set; }
+ private ArchiveHeader? ArchiveHeader { get; set; }
-#nullable enable
-
- internal StreamingMode Mode => _headerFactory.StreamingMode;
+ private StreamingMode Mode => _headerFactory.StreamingMode;
internal abstract IEnumerable ReadFileParts();
@@ -38,19 +36,16 @@ public abstract class RarVolume : Volume
switch (header.HeaderType)
{
case HeaderType.Mark:
-
{
lastMarkHeader = (MarkHeader)header;
}
break;
case HeaderType.Archive:
-
{
ArchiveHeader = (ArchiveHeader)header;
}
break;
case HeaderType.File:
-
{
var fh = (FileHeader)header;
if (_maxCompressionAlgorithm < fh.CompressionAlgorithm)
@@ -62,19 +57,13 @@ public abstract class RarVolume : Volume
}
break;
case HeaderType.Service:
-
{
var fh = (FileHeader)header;
if (fh.FileName == "CMT")
{
- var part = CreateFilePart(lastMarkHeader!, fh);
var buffer = new byte[fh.CompressedSize];
- part.GetCompressedStream().Read(buffer, 0, buffer.Length);
- Comment = System.Text.Encoding.UTF8.GetString(
- buffer,
- 0,
- buffer.Length - 1
- );
+ fh.PackedStream.Read(buffer, 0, buffer.Length);
+ Comment = Encoding.UTF8.GetString(buffer, 0, buffer.Length - 1);
}
}
break;
@@ -108,7 +97,7 @@ public abstract class RarVolume : Volume
get
{
EnsureArchiveHeaderLoaded();
- return ArchiveHeader.IsFirstVolume;
+ return ArchiveHeader?.IsFirstVolume ?? false;
}
}
@@ -120,7 +109,7 @@ public abstract class RarVolume : Volume
get
{
EnsureArchiveHeaderLoaded();
- return ArchiveHeader.IsVolume;
+ return ArchiveHeader?.IsVolume ?? false;
}
}
@@ -133,7 +122,7 @@ public abstract class RarVolume : Volume
get
{
EnsureArchiveHeaderLoaded();
- return ArchiveHeader.IsSolid;
+ return ArchiveHeader?.IsSolid ?? false;
}
}
diff --git a/src/SharpCompress/Common/ReaderCancelledException.cs b/src/SharpCompress/Common/ReaderCancelledException.cs
new file mode 100644
index 00000000..918e5abb
--- /dev/null
+++ b/src/SharpCompress/Common/ReaderCancelledException.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace SharpCompress.Common;
+
+public class ReaderCancelledException : Exception
+{
+ public ReaderCancelledException(string message)
+ : base(message) { }
+
+ public ReaderCancelledException(string message, Exception inner)
+ : base(message, inner) { }
+}
diff --git a/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs b/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs
index 5e42494a..4bac08ad 100644
--- a/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs
+++ b/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs
@@ -15,15 +15,15 @@ internal class ArchiveDatabase
internal long _startPositionAfterHeader;
internal long _dataStartPosition;
- internal List _packSizes = new List();
- internal List _packCrCs = new List();
- internal List _folders = new List();
+ internal List _packSizes = new();
+ internal List _packCrCs = new();
+ internal List _folders = new();
internal List _numUnpackStreamsVector;
- internal List _files = new List();
+ internal List _files = new();
- internal List _packStreamStartPositions = new List();
- internal List _folderStartFileIndex = new List();
- internal List _fileIndexToFolderIndexMap = new List();
+ internal List _packStreamStartPositions = new();
+ internal List _folderStartFileIndex = new();
+ internal List _fileIndexToFolderIndexMap = new();
internal IPasswordProvider PasswordProvider { get; }
@@ -35,7 +35,7 @@ internal class ArchiveDatabase
_packSizes.Clear();
_packCrCs.Clear();
_folders.Clear();
- _numUnpackStreamsVector = null!;
+ _numUnpackStreamsVector = null;
_files.Clear();
_packStreamStartPositions.Clear();
diff --git a/src/SharpCompress/Common/SevenZip/ArchiveReader.cs b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs
index 42b5b6b2..3e506e0e 100644
--- a/src/SharpCompress/Common/SevenZip/ArchiveReader.cs
+++ b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs
@@ -14,13 +14,13 @@ namespace SharpCompress.Common.SevenZip;
internal class ArchiveReader
{
internal Stream _stream;
- internal Stack _readerStack = new Stack();
+ internal Stack _readerStack = new();
internal DataReader _currentReader;
internal long _streamOrigin;
internal long _streamEnding;
internal byte[] _header;
- private readonly Dictionary _cachedStreams = new Dictionary();
+ private readonly Dictionary _cachedStreams = new();
internal void AddByteStream(byte[] buffer, int offset, int length)
{
@@ -1359,7 +1359,7 @@ internal class ArchiveReader
{
internal int _fileIndex;
internal int _folderIndex;
- internal List _extractStatuses = new List();
+ internal List _extractStatuses = new();
internal CExtractFolderInfo(int fileIndex, int folderIndex)
{
@@ -1393,7 +1393,7 @@ internal class ArchiveReader
public override bool CanWrite => false;
- public override void Flush() => throw new NotSupportedException();
+ public override void Flush() { }
public override long Length => throw new NotSupportedException();
diff --git a/src/SharpCompress/Common/SevenZip/CFolder.cs b/src/SharpCompress/Common/SevenZip/CFolder.cs
index 9d3516b1..8b0123da 100644
--- a/src/SharpCompress/Common/SevenZip/CFolder.cs
+++ b/src/SharpCompress/Common/SevenZip/CFolder.cs
@@ -6,11 +6,11 @@ namespace SharpCompress.Common.SevenZip;
internal class CFolder
{
- internal List _coders = new List();
- internal List _bindPairs = new List();
- internal List _packStreams = new List();
+ internal List _coders = new();
+ internal List _bindPairs = new();
+ internal List _packStreams = new();
internal int _firstPackStreamId;
- internal List _unpackSizes = new List();
+ internal List _unpackSizes = new();
internal uint? _unpackCrc;
internal bool UnpackCrcDefined => _unpackCrc != null;
diff --git a/src/SharpCompress/Common/SevenZip/CMethodId.cs b/src/SharpCompress/Common/SevenZip/CMethodId.cs
index 6dce5773..8494aad5 100644
--- a/src/SharpCompress/Common/SevenZip/CMethodId.cs
+++ b/src/SharpCompress/Common/SevenZip/CMethodId.cs
@@ -7,10 +7,10 @@ internal readonly struct CMethodId
public const ulong K_LZMA2_ID = 0x21;
public const ulong K_AES_ID = 0x06F10701;
- public static readonly CMethodId K_COPY = new CMethodId(K_COPY_ID);
- public static readonly CMethodId K_LZMA = new CMethodId(K_LZMA_ID);
- public static readonly CMethodId K_LZMA2 = new CMethodId(K_LZMA2_ID);
- public static readonly CMethodId K_AES = new CMethodId(K_AES_ID);
+ public static readonly CMethodId K_COPY = new(K_COPY_ID);
+ public static readonly CMethodId K_LZMA = new(K_LZMA_ID);
+ public static readonly CMethodId K_LZMA2 = new(K_LZMA2_ID);
+ public static readonly CMethodId K_AES = new(K_AES_ID);
public readonly ulong _id;
diff --git a/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs b/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs
index 66170ba8..fbcb3d00 100644
--- a/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs
+++ b/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs
@@ -13,7 +13,7 @@ public class SevenZipEntry : Entry
public override long Crc => FilePart.Header.Crc ?? 0;
- public override string Key => FilePart.Header.Name;
+ public override string? Key => FilePart.Header.Name;
public override string? LinkTarget => null;
diff --git a/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs b/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs
index aad191c9..fe221b53 100644
--- a/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs
+++ b/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs
@@ -41,7 +41,7 @@ internal class SevenZipFilePart : FilePart
{
if (!Header.HasStream)
{
- return null!;
+ throw new InvalidOperationException("File does not have a stream.");
}
var folderStream = _database.GetFolderStream(_stream, Folder!, _database.PasswordProvider);
@@ -73,34 +73,24 @@ internal class SevenZipFilePart : FilePart
private const uint K_PPMD = 0x030401;
private const uint K_B_ZIP2 = 0x040202;
- internal CompressionType GetCompression()
+ private CompressionType GetCompression()
{
if (Header.IsDir)
- return CompressionType.None;
-
- var coder = Folder!._coders.First();
- switch (coder._methodId._id)
{
- case K_LZMA:
- case K_LZMA2:
- {
- return CompressionType.LZMA;
- }
- case K_PPMD:
- {
- return CompressionType.PPMd;
- }
- case K_B_ZIP2:
- {
- return CompressionType.BZip2;
- }
- default:
- throw new NotImplementedException();
+ return CompressionType.None;
}
+
+ var coder = Folder.NotNull()._coders.First();
+ return coder._methodId._id switch
+ {
+ K_LZMA or K_LZMA2 => CompressionType.LZMA,
+ K_PPMD => CompressionType.PPMd,
+ K_B_ZIP2 => CompressionType.BZip2,
+ _ => throw new NotImplementedException()
+ };
}
internal bool IsEncrypted =>
- Header.IsDir
- ? false
- : Folder!._coders.FindIndex(c => c._methodId._id == CMethodId.K_AES_ID) != -1;
+ !Header.IsDir
+ && Folder?._coders.FindIndex(c => c._methodId._id == CMethodId.K_AES_ID) != -1;
}
diff --git a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs
index ef86ab00..e9aa343c 100644
--- a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs
+++ b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Buffers.Binary;
using System.IO;
@@ -9,12 +7,12 @@ namespace SharpCompress.Common.Tar.Headers;
internal sealed class TarHeader
{
- internal static readonly DateTime EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ internal static readonly DateTime EPOCH = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public TarHeader(ArchiveEncoding archiveEncoding) => ArchiveEncoding = archiveEncoding;
- internal string Name { get; set; }
- internal string LinkName { get; set; }
+ internal string? Name { get; set; }
+ internal string? LinkName { get; set; }
internal long Mode { get; set; }
internal long UserId { get; set; }
@@ -22,7 +20,7 @@ internal sealed class TarHeader
internal long Size { get; set; }
internal DateTime LastModifiedTime { get; set; }
internal EntryType EntryType { get; set; }
- internal Stream PackedStream { get; set; }
+ internal Stream? PackedStream { get; set; }
internal ArchiveEncoding ArchiveEncoding { get; }
internal const int BLOCK_SIZE = 512;
@@ -36,7 +34,9 @@ internal sealed class TarHeader
WriteOctalBytes(0, buffer, 116, 8); // group ID
//ArchiveEncoding.UTF8.GetBytes("magic").CopyTo(buffer, 257);
- var nameByteCount = ArchiveEncoding.GetEncoding().GetByteCount(Name);
+ var nameByteCount = ArchiveEncoding
+ .GetEncoding()
+ .GetByteCount(Name.NotNull("Name is null"));
if (nameByteCount > 100)
{
// Set mock filename and filetype to indicate the next block is the actual name of the file
@@ -46,7 +46,7 @@ internal sealed class TarHeader
}
else
{
- WriteStringBytes(ArchiveEncoding.Encode(Name), buffer, 100);
+ WriteStringBytes(ArchiveEncoding.Encode(Name.NotNull("Name is null")), buffer, 100);
WriteOctalBytes(Size, buffer, 124, 12);
var time = (long)(LastModifiedTime.ToUniversalTime() - EPOCH).TotalSeconds;
WriteOctalBytes(time, buffer, 136, 12);
@@ -77,7 +77,7 @@ internal sealed class TarHeader
//
// and then infinite recursion is occured in WriteLongFilenameHeader because truncated.Length is 102.
Name = ArchiveEncoding.Decode(
- ArchiveEncoding.Encode(Name),
+ ArchiveEncoding.Encode(Name.NotNull("Name is null")),
0,
100 - ArchiveEncoding.GetEncoding().GetMaxByteCount(1)
);
@@ -87,7 +87,7 @@ internal sealed class TarHeader
private void WriteLongFilenameHeader(Stream output)
{
- var nameBytes = ArchiveEncoding.Encode(Name);
+ var nameBytes = ArchiveEncoding.Encode(Name.NotNull("Name is null"));
output.Write(nameBytes, 0, nameBytes.Length);
// pad to multiple of BlockSize bytes, and make sure a terminating null is added
@@ -101,57 +101,79 @@ internal sealed class TarHeader
internal bool Read(BinaryReader reader)
{
- var buffer = ReadBlock(reader);
- if (buffer.Length == 0)
- {
- return false;
- }
+ string? longName = null;
+ string? longLinkName = null;
+ var hasLongValue = true;
+ byte[] buffer;
+ EntryType entryType;
- // for symlinks, additionally read the linkname
- if (ReadEntryType(buffer) == EntryType.SymLink)
+ do
{
- LinkName = ArchiveEncoding.Decode(buffer, 157, 100).TrimNulls();
- }
-
- if (ReadEntryType(buffer) == EntryType.LongName)
- {
- Name = ReadLongName(reader, buffer);
buffer = ReadBlock(reader);
- }
- else
- {
- Name = ArchiveEncoding.Decode(buffer, 0, 100).TrimNulls();
- }
- EntryType = ReadEntryType(buffer);
+ if (buffer.Length == 0)
+ {
+ return false;
+ }
+
+ entryType = ReadEntryType(buffer);
+
+ // LongName and LongLink headers can follow each other and need
+ // to apply to the header that follows them.
+ if (entryType == EntryType.LongName)
+ {
+ longName = ReadLongName(reader, buffer);
+ continue;
+ }
+ else if (entryType == EntryType.LongLink)
+ {
+ longLinkName = ReadLongName(reader, buffer);
+ continue;
+ }
+
+ hasLongValue = false;
+ } while (hasLongValue);
+
+ Name = longName ?? ArchiveEncoding.Decode(buffer, 0, 100).TrimNulls();
+ EntryType = entryType;
Size = ReadSize(buffer);
+ // for symlinks, additionally read the linkname
+ if (entryType == EntryType.SymLink || entryType == EntryType.HardLink)
+ {
+ LinkName = longLinkName ?? ArchiveEncoding.Decode(buffer, 157, 100).TrimNulls();
+ }
+
Mode = ReadAsciiInt64Base8(buffer, 100, 7);
- if (EntryType == EntryType.Directory)
+
+ if (entryType == EntryType.Directory)
{
Mode |= 0b1_000_000_000;
}
- UserId = ReadAsciiInt64Base8(buffer, 108, 7);
- GroupId = ReadAsciiInt64Base8(buffer, 116, 7);
- var unixTimeStamp = ReadAsciiInt64Base8(buffer, 136, 11);
- LastModifiedTime = EPOCH.AddSeconds(unixTimeStamp).ToLocalTime();
+ UserId = ReadAsciiInt64Base8oldGnu(buffer, 108, 7);
+ GroupId = ReadAsciiInt64Base8oldGnu(buffer, 116, 7);
+ var unixTimeStamp = ReadAsciiInt64Base8(buffer, 136, 11);
+
+ LastModifiedTime = EPOCH.AddSeconds(unixTimeStamp).ToLocalTime();
Magic = ArchiveEncoding.Decode(buffer, 257, 6).TrimNulls();
if (!string.IsNullOrEmpty(Magic) && "ustar".Equals(Magic))
{
- var namePrefix = ArchiveEncoding.Decode(buffer, 345, 157);
- namePrefix = namePrefix.TrimNulls();
+ var namePrefix = ArchiveEncoding.Decode(buffer, 345, 157).TrimNulls();
+
if (!string.IsNullOrEmpty(namePrefix))
{
Name = namePrefix + "/" + Name;
}
}
- if (EntryType != EntryType.LongName && Name.Length == 0)
+
+ if (entryType != EntryType.LongName && Name.Length == 0)
{
return false;
}
+
return true;
}
@@ -249,6 +271,24 @@ internal sealed class TarHeader
return Convert.ToInt64(s, 8);
}
+ private static long ReadAsciiInt64Base8oldGnu(byte[] buffer, int offset, int count)
+ {
+ if (buffer[offset] == 0x80 && buffer[offset + 1] == 0x00)
+ {
+ return buffer[offset + 4] << 24
+ | buffer[offset + 5] << 16
+ | buffer[offset + 6] << 8
+ | buffer[offset + 7];
+ }
+ var s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls();
+
+ if (string.IsNullOrEmpty(s))
+ {
+ return 0;
+ }
+ return Convert.ToInt64(s, 8);
+ }
+
private static long ReadAsciiInt64(byte[] buffer, int offset, int count)
{
var s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls();
@@ -305,5 +345,5 @@ internal sealed class TarHeader
public long? DataStartPosition { get; set; }
- public string Magic { get; set; }
+ public string? Magic { get; set; }
}
diff --git a/src/SharpCompress/Common/Tar/TarEntry.cs b/src/SharpCompress/Common/Tar/TarEntry.cs
index 59743070..2597b837 100644
--- a/src/SharpCompress/Common/Tar/TarEntry.cs
+++ b/src/SharpCompress/Common/Tar/TarEntry.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.IO;
@@ -10,9 +8,9 @@ namespace SharpCompress.Common.Tar;
public class TarEntry : Entry
{
- private readonly TarFilePart _filePart;
+ private readonly TarFilePart? _filePart;
- internal TarEntry(TarFilePart filePart, CompressionType type)
+ internal TarEntry(TarFilePart? filePart, CompressionType type)
{
_filePart = filePart;
CompressionType = type;
@@ -22,15 +20,15 @@ public class TarEntry : Entry
public override long Crc => 0;
- public override string Key => _filePart.Header.Name;
+ public override string? Key => _filePart?.Header.Name;
- public override string LinkTarget => _filePart.Header.LinkName;
+ public override string? LinkTarget => _filePart?.Header.LinkName;
- public override long CompressedSize => _filePart.Header.Size;
+ public override long CompressedSize => _filePart?.Header.Size ?? 0;
- public override long Size => _filePart.Header.Size;
+ public override long Size => _filePart?.Header.Size ?? 0;
- public override DateTime? LastModifiedTime => _filePart.Header.LastModifiedTime;
+ public override DateTime? LastModifiedTime => _filePart?.Header.LastModifiedTime;
public override DateTime? CreatedTime => null;
@@ -40,17 +38,17 @@ public class TarEntry : Entry
public override bool IsEncrypted => false;
- public override bool IsDirectory => _filePart.Header.EntryType == EntryType.Directory;
+ public override bool IsDirectory => _filePart?.Header.EntryType == EntryType.Directory;
public override bool IsSplitAfter => false;
- public long Mode => _filePart.Header.Mode;
+ public long Mode => _filePart?.Header.Mode ?? 0;
- public long UserID => _filePart.Header.UserId;
+ public long UserID => _filePart?.Header.UserId ?? 0;
- public long GroupId => _filePart.Header.GroupId;
+ public long GroupId => _filePart?.Header.GroupId ?? 0;
- internal override IEnumerable Parts => _filePart.AsEnumerable();
+ internal override IEnumerable Parts => _filePart.Empty();
internal static IEnumerable GetEntries(
StreamingMode mode,
@@ -59,17 +57,17 @@ public class TarEntry : Entry
ArchiveEncoding archiveEncoding
)
{
- foreach (var h in TarHeaderFactory.ReadHeader(mode, stream, archiveEncoding))
+ foreach (var header in TarHeaderFactory.ReadHeader(mode, stream, archiveEncoding))
{
- if (h != null)
+ if (header != null)
{
if (mode == StreamingMode.Seekable)
{
- yield return new TarEntry(new TarFilePart(h, stream), compressionType);
+ yield return new TarEntry(new TarFilePart(header, stream), compressionType);
}
else
{
- yield return new TarEntry(new TarFilePart(h, null), compressionType);
+ yield return new TarEntry(new TarFilePart(header, null), compressionType);
}
}
else
diff --git a/src/SharpCompress/Common/Tar/TarFilePart.cs b/src/SharpCompress/Common/Tar/TarFilePart.cs
index bfd2fe29..06516114 100644
--- a/src/SharpCompress/Common/Tar/TarFilePart.cs
+++ b/src/SharpCompress/Common/Tar/TarFilePart.cs
@@ -5,9 +5,9 @@ namespace SharpCompress.Common.Tar;
internal sealed class TarFilePart : FilePart
{
- private readonly Stream _seekableStream;
+ private readonly Stream? _seekableStream;
- internal TarFilePart(TarHeader header, Stream seekableStream)
+ internal TarFilePart(TarHeader header, Stream? seekableStream)
: base(header.ArchiveEncoding)
{
_seekableStream = seekableStream;
@@ -16,16 +16,16 @@ internal sealed class TarFilePart : FilePart
internal TarHeader Header { get; }
- internal override string FilePartName => Header.Name;
+ internal override string? FilePartName => Header?.Name;
internal override Stream GetCompressedStream()
{
if (_seekableStream != null)
{
- _seekableStream.Position = Header.DataStartPosition!.Value;
+ _seekableStream.Position = Header.DataStartPosition ?? 0;
return new TarReadOnlySubStream(_seekableStream, Header.Size);
}
- return Header.PackedStream;
+ return Header.PackedStream.NotNull();
}
internal override Stream? GetRawStream() => null;
diff --git a/src/SharpCompress/Common/Tar/TarHeaderFactory.cs b/src/SharpCompress/Common/Tar/TarHeaderFactory.cs
index 85eec5b4..13813353 100644
--- a/src/SharpCompress/Common/Tar/TarHeaderFactory.cs
+++ b/src/SharpCompress/Common/Tar/TarHeaderFactory.cs
@@ -28,7 +28,6 @@ internal static class TarHeaderFactory
switch (mode)
{
case StreamingMode.Seekable:
-
{
header.DataStartPosition = reader.BaseStream.Position;
@@ -37,7 +36,6 @@ internal static class TarHeaderFactory
}
break;
case StreamingMode.Streaming:
-
{
header.PackedStream = new TarReadOnlySubStream(stream, header.Size);
}
diff --git a/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs b/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs
index 7ccfd238..09a2fdb8 100644
--- a/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs
+++ b/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs
@@ -1,6 +1,6 @@
-using SharpCompress.IO;
using System;
using System.IO;
+using SharpCompress.IO;
namespace SharpCompress.Common.Tar;
@@ -47,7 +47,7 @@ internal class TarReadOnlySubStream : NonDisposingStream
public override bool CanWrite => false;
- public override void Flush() => throw new NotSupportedException();
+ public override void Flush() { }
public override long Length => throw new NotSupportedException();
@@ -63,7 +63,7 @@ internal class TarReadOnlySubStream : NonDisposingStream
{
count = (int)BytesLeftToRead;
}
- int read = Stream.Read(buffer, offset, count);
+ var read = Stream.Read(buffer, offset, count);
if (read > 0)
{
BytesLeftToRead -= read;
@@ -78,7 +78,7 @@ internal class TarReadOnlySubStream : NonDisposingStream
{
return -1;
}
- int value = Stream.ReadByte();
+ var value = Stream.ReadByte();
if (value != -1)
{
--BytesLeftToRead;
diff --git a/src/SharpCompress/Common/Volume.cs b/src/SharpCompress/Common/Volume.cs
index 1f259257..7be161ec 100644
--- a/src/SharpCompress/Common/Volume.cs
+++ b/src/SharpCompress/Common/Volume.cs
@@ -9,11 +9,11 @@ public abstract class Volume : IVolume
{
private readonly Stream _actualStream;
- internal Volume(Stream stream, ReaderOptions readerOptions, int index = 0)
+ internal Volume(Stream stream, ReaderOptions? readerOptions, int index = 0)
{
Index = index;
- ReaderOptions = readerOptions;
- if (readerOptions.LeaveStreamOpen)
+ ReaderOptions = readerOptions ?? new ReaderOptions();
+ if (ReaderOptions.LeaveStreamOpen)
{
stream = NonDisposingStream.Create(stream);
}
@@ -32,7 +32,7 @@ public abstract class Volume : IVolume
public virtual int Index { get; internal set; }
- public string FileName => (_actualStream as FileStream)?.Name!;
+ public string? FileName => (_actualStream as FileStream)?.Name;
///
/// RarArchive is part of a multi-part archive.
diff --git a/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs b/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs
index fc2cb262..2b26d298 100644
--- a/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs
+++ b/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs
@@ -14,8 +14,8 @@ internal class DirectoryEntryHeader : ZipFileEntry
VersionNeededToExtract = reader.ReadUInt16();
Flags = (HeaderFlags)reader.ReadUInt16();
CompressionMethod = (ZipCompressionMethod)reader.ReadUInt16();
- LastModifiedTime = reader.ReadUInt16();
- LastModifiedDate = reader.ReadUInt16();
+ OriginalLastModifiedTime = LastModifiedTime = reader.ReadUInt16();
+ OriginalLastModifiedDate = LastModifiedDate = reader.ReadUInt16();
Crc = reader.ReadUInt32();
CompressedSize = reader.ReadUInt32();
UncompressedSize = reader.ReadUInt32();
@@ -52,8 +52,8 @@ internal class DirectoryEntryHeader : ZipFileEntry
LoadExtra(extra);
- var unicodePathExtra = Extra.FirstOrDefault(
- u => u.Type == ExtraDataType.UnicodePathExtraField
+ var unicodePathExtra = Extra.FirstOrDefault(u =>
+ u.Type == ExtraDataType.UnicodePathExtraField
);
if (unicodePathExtra != null && ArchiveEncoding.Forced == null)
{
@@ -85,6 +85,36 @@ internal class DirectoryEntryHeader : ZipFileEntry
RelativeOffsetOfEntryHeader = zip64ExtraData.RelativeOffsetOfEntryHeader;
}
}
+
+ var unixTimeExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnixTimeExtraField);
+
+ if (unixTimeExtra is not null)
+ {
+ // Tuple order is last modified time, last access time, and creation time.
+ var unixTimeTuple = ((UnixTimeExtraField)unixTimeExtra).UnicodeTimes;
+
+ if (unixTimeTuple.Item1.HasValue)
+ {
+ var dosTime = Utility.DateTimeToDosTime(unixTimeTuple.Item1.Value);
+
+ LastModifiedDate = (ushort)(dosTime >> 16);
+ LastModifiedTime = (ushort)(dosTime & 0x0FFFF);
+ }
+ else if (unixTimeTuple.Item2.HasValue)
+ {
+ var dosTime = Utility.DateTimeToDosTime(unixTimeTuple.Item2.Value);
+
+ LastModifiedDate = (ushort)(dosTime >> 16);
+ LastModifiedTime = (ushort)(dosTime & 0x0FFFF);
+ }
+ else if (unixTimeTuple.Item3.HasValue)
+ {
+ var dosTime = Utility.DateTimeToDosTime(unixTimeTuple.Item3.Value);
+
+ LastModifiedDate = (ushort)(dosTime >> 16);
+ LastModifiedTime = (ushort)(dosTime & 0x0FFFF);
+ }
+ }
}
internal ushort Version { get; private set; }
diff --git a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs
index 93cc55ac..1e3dc62d 100644
--- a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs
+++ b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs
@@ -13,8 +13,8 @@ internal class LocalEntryHeader : ZipFileEntry
Version = reader.ReadUInt16();
Flags = (HeaderFlags)reader.ReadUInt16();
CompressionMethod = (ZipCompressionMethod)reader.ReadUInt16();
- LastModifiedTime = reader.ReadUInt16();
- LastModifiedDate = reader.ReadUInt16();
+ OriginalLastModifiedTime = LastModifiedTime = reader.ReadUInt16();
+ OriginalLastModifiedDate = LastModifiedDate = reader.ReadUInt16();
Crc = reader.ReadUInt32();
CompressedSize = reader.ReadUInt32();
UncompressedSize = reader.ReadUInt32();
@@ -42,8 +42,8 @@ internal class LocalEntryHeader : ZipFileEntry
LoadExtra(extra);
- var unicodePathExtra = Extra.FirstOrDefault(
- u => u.Type == ExtraDataType.UnicodePathExtraField
+ var unicodePathExtra = Extra.FirstOrDefault(u =>
+ u.Type == ExtraDataType.UnicodePathExtraField
);
if (unicodePathExtra != null && ArchiveEncoding.Forced == null)
{
@@ -64,6 +64,36 @@ internal class LocalEntryHeader : ZipFileEntry
UncompressedSize = zip64ExtraData.UncompressedSize;
}
}
+
+ var unixTimeExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnixTimeExtraField);
+
+ if (unixTimeExtra is not null)
+ {
+ // Tuple order is last modified time, last access time, and creation time.
+ var unixTimeTuple = ((UnixTimeExtraField)unixTimeExtra).UnicodeTimes;
+
+ if (unixTimeTuple.Item1.HasValue)
+ {
+ var dosTime = Utility.DateTimeToDosTime(unixTimeTuple.Item1.Value);
+
+ LastModifiedDate = (ushort)(dosTime >> 16);
+ LastModifiedTime = (ushort)(dosTime & 0x0FFFF);
+ }
+ else if (unixTimeTuple.Item2.HasValue)
+ {
+ var dosTime = Utility.DateTimeToDosTime(unixTimeTuple.Item2.Value);
+
+ LastModifiedDate = (ushort)(dosTime >> 16);
+ LastModifiedTime = (ushort)(dosTime & 0x0FFFF);
+ }
+ else if (unixTimeTuple.Item3.HasValue)
+ {
+ var dosTime = Utility.DateTimeToDosTime(unixTimeTuple.Item3.Value);
+
+ LastModifiedDate = (ushort)(dosTime >> 16);
+ LastModifiedTime = (ushort)(dosTime & 0x0FFFF);
+ }
+ }
}
internal ushort Version { get; private set; }
diff --git a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs
index 80ec9b8f..88e4a187 100644
--- a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs
+++ b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Buffers.Binary;
using System.Text;
@@ -13,7 +13,8 @@ internal enum ExtraDataType : ushort
// Third Party Mappings
// -Info-ZIP Unicode Path Extra Field
UnicodePathExtraField = 0x7075,
- Zip64ExtendedInformationExtraField = 0x0001
+ Zip64ExtendedInformationExtraField = 0x0001,
+ UnixTimeExtraField = 0x5455
}
internal class ExtraData
@@ -145,6 +146,84 @@ internal sealed class Zip64ExtendedInformationExtraField : ExtraData
public uint VolumeNumber { get; private set; }
}
+internal sealed class UnixTimeExtraField : ExtraData
+{
+ public UnixTimeExtraField(ExtraDataType type, ushort length, byte[] dataBytes)
+ : base(type, length, dataBytes) { }
+
+ ///
+ /// The unix modified time, last access time, and creation time, if set.
+ ///
+ /// Must return Tuple explicitly due to net462 support.
+ internal Tuple UnicodeTimes
+ {
+ get
+ {
+ // There has to be at least 5 byte for there to be a timestamp.
+ // 1 byte for flags and 4 bytes for a timestamp.
+ if (DataBytes is null || DataBytes.Length < 5)
+ {
+ return Tuple.Create(null, null, null);
+ }
+
+ var flags = DataBytes[0];
+ var isModifiedTimeSpecified = (flags & 0x01) == 1;
+ var isLastAccessTimeSpecified = (flags & 0x02) == 1;
+ var isCreationTimeSpecified = (flags & 0x04) == 1;
+ var currentIndex = 1;
+ DateTime? modifiedTime = null;
+ DateTime? lastAccessTime = null;
+ DateTime? creationTime = null;
+
+ if (isModifiedTimeSpecified)
+ {
+ var modifiedEpochTime = BinaryPrimitives.ReadInt32LittleEndian(
+ DataBytes.AsSpan(currentIndex, 4)
+ );
+
+ currentIndex += 4;
+ modifiedTime = DateTimeOffset.FromUnixTimeSeconds(modifiedEpochTime).UtcDateTime;
+ }
+
+ if (isLastAccessTimeSpecified)
+ {
+ if (currentIndex + 4 > DataBytes.Length)
+ {
+ throw new ArchiveException("Invalid UnicodeExtraTime field");
+ }
+
+ var lastAccessEpochTime = BinaryPrimitives.ReadInt32LittleEndian(
+ DataBytes.AsSpan(currentIndex, 4)
+ );
+
+ currentIndex += 4;
+ lastAccessTime = DateTimeOffset
+ .FromUnixTimeSeconds(lastAccessEpochTime)
+ .UtcDateTime;
+ }
+
+ if (isCreationTimeSpecified)
+ {
+ if (currentIndex + 4 > DataBytes.Length)
+ {
+ throw new ArchiveException("Invalid UnicodeExtraTime field");
+ }
+
+ var creationTimeEpochTime = BinaryPrimitives.ReadInt32LittleEndian(
+ DataBytes.AsSpan(currentIndex, 4)
+ );
+
+ currentIndex += 4;
+ creationTime = DateTimeOffset
+ .FromUnixTimeSeconds(creationTimeEpochTime)
+ .UtcDateTime;
+ }
+
+ return Tuple.Create(modifiedTime, lastAccessTime, creationTime);
+ }
+ }
+}
+
internal static class LocalEntryHeaderExtraFactory
{
internal static ExtraData Create(ExtraDataType type, ushort length, byte[] extraData) =>
@@ -154,6 +233,7 @@ internal static class LocalEntryHeaderExtraFactory
=> new ExtraUnicodePathExtraField(type, length, extraData),
ExtraDataType.Zip64ExtendedInformationExtraField
=> new Zip64ExtendedInformationExtraField(type, length, extraData),
+ ExtraDataType.UnixTimeExtraField => new UnixTimeExtraField(type, length, extraData),
_ => new ExtraData(type, length, extraData)
};
}
diff --git a/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs b/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs
index 98d230f5..0570bf6d 100644
--- a/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs
+++ b/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
@@ -20,21 +18,21 @@ internal abstract class ZipFileEntry : ZipHeader
{
get
{
- if (Name.EndsWith('/'))
+ if (Name?.EndsWith('/') ?? false)
{
return true;
}
//.NET Framework 4.5 : System.IO.Compression::CreateFromDirectory() probably writes backslashes to headers
- return CompressedSize == 0 && UncompressedSize == 0 && Name.EndsWith('\\');
+ return CompressedSize == 0 && UncompressedSize == 0 && (Name?.EndsWith('\\') ?? false);
}
}
- internal Stream PackedStream { get; set; }
+ internal Stream? PackedStream { get; set; }
internal ArchiveEncoding ArchiveEncoding { get; }
- internal string Name { get; set; }
+ internal string? Name { get; set; }
internal HeaderFlags Flags { get; set; }
@@ -48,7 +46,7 @@ internal abstract class ZipFileEntry : ZipHeader
internal List Extra { get; set; }
- public string Password { get; set; }
+ public string? Password { get; set; }
internal PkwareTraditionalEncryptionData ComposeEncryptionData(Stream archiveStream)
{
@@ -65,10 +63,28 @@ internal abstract class ZipFileEntry : ZipHeader
return encryptionData;
}
- internal WinzipAesEncryptionData WinzipAesEncryptionData { get; set; }
+ internal WinzipAesEncryptionData? WinzipAesEncryptionData { get; set; }
+ ///
+ /// The last modified date as read from the Local or Central Directory header.
+ ///
+ internal ushort OriginalLastModifiedDate { get; set; }
+
+ ///
+ /// The last modified date from the UnixTimeExtraField, if present, or the
+ /// Local or Cental Directory header, if not.
+ ///
internal ushort LastModifiedDate { get; set; }
+ ///
+ /// The last modified time as read from the Local or Central Directory header.
+ ///
+ internal ushort OriginalLastModifiedTime { get; set; }
+
+ ///
+ /// The last modified time from the UnixTimeExtraField, if present, or the
+ /// Local or Cental Directory header, if not.
+ ///
internal ushort LastModifiedTime { get; set; }
internal uint Crc { get; set; }
@@ -101,7 +117,7 @@ internal abstract class ZipFileEntry : ZipHeader
}
}
- internal ZipFilePart Part { get; set; }
+ internal ZipFilePart? Part { get; set; }
internal bool IsZip64 => CompressedSize >= uint.MaxValue;
}
diff --git a/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs b/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs
index 273a7a3c..6ac48c6f 100644
--- a/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs
+++ b/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.IO;
namespace SharpCompress.Common.Zip;
@@ -87,10 +87,7 @@ internal class PkwareTraditionalCryptoStream : Stream
_stream.Write(encrypted, 0, encrypted.Length);
}
- public override void Flush()
- {
- //throw new NotSupportedException();
- }
+ public override void Flush() { }
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
diff --git a/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs b/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs
index 353000d8..7b517857 100644
--- a/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs
+++ b/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs
@@ -6,7 +6,7 @@ namespace SharpCompress.Common.Zip;
internal class PkwareTraditionalEncryptionData
{
- private static readonly CRC32 CRC32 = new CRC32();
+ private static readonly CRC32 CRC32 = new();
private readonly uint[] _keys = { 0x12345678, 0x23456789, 0x34567890 };
private readonly ArchiveEncoding _archiveEncoding;
@@ -39,7 +39,7 @@ internal class PkwareTraditionalEncryptionData
{
throw new CryptographicException("The password did not match.");
}
- if (plainTextHeader[11] != (byte)((header.LastModifiedTime >> 8) & 0xff))
+ if (plainTextHeader[11] != (byte)((header.OriginalLastModifiedTime >> 8) & 0xff))
{
throw new CryptographicException("The password did not match.");
}
@@ -103,7 +103,7 @@ internal class PkwareTraditionalEncryptionData
internal byte[] StringToByteArray(string value)
{
- var a = _archiveEncoding.Password.GetBytes(value);
+ var a = _archiveEncoding.GetPasswordEncoding().GetBytes(value);
return a;
}
diff --git a/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs b/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs
index 63fdc933..e37008e5 100644
--- a/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs
+++ b/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs
@@ -42,16 +42,16 @@ internal class SeekableZipFilePart : ZipFilePart
protected override Stream CreateBaseStream()
{
- BaseStream.Position = Header.DataStartPosition!.Value;
+ BaseStream.Position = Header.DataStartPosition.NotNull();
if (
(Header.CompressedSize == 0)
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)
- && (_directoryEntryHeader?.HasData == true)
- && (_directoryEntryHeader?.CompressedSize != 0)
+ && _directoryEntryHeader.HasData
+ && (_directoryEntryHeader.CompressedSize != 0)
)
{
- return new ReadOnlySubStream(BaseStream, _directoryEntryHeader!.CompressedSize);
+ return new ReadOnlySubStream(BaseStream, _directoryEntryHeader.CompressedSize);
}
return BaseStream;
diff --git a/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs
index 1cd1f61f..97e44b6b 100644
--- a/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs
+++ b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs
@@ -13,7 +13,7 @@ internal sealed class StreamingZipFilePart : ZipFilePart
internal StreamingZipFilePart(ZipFileEntry header, Stream stream)
: base(header, stream) { }
- protected override Stream CreateBaseStream() => Header.PackedStream;
+ protected override Stream CreateBaseStream() => Header.PackedStream.NotNull();
internal override Stream GetCompressedStream()
{
diff --git a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs
index e76a2856..508dfd1a 100644
--- a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs
+++ b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs
@@ -15,10 +15,7 @@ internal class StreamingZipHeaderFactory : ZipHeaderFactory
ArchiveEncoding archiveEncoding,
IEnumerable? entries
)
- : base(StreamingMode.Streaming, password, archiveEncoding)
- {
- _entries = entries;
- }
+ : base(StreamingMode.Streaming, password, archiveEncoding) => _entries = entries;
internal IEnumerable ReadStreamHeader(Stream stream)
{
@@ -39,16 +36,19 @@ internal class StreamingZipHeaderFactory : ZipHeaderFactory
uint headerBytes = 0;
if (
_lastEntryHeader != null
- && (
- FlagUtility.HasFlag(_lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor)
- || _lastEntryHeader.IsZip64
- )
+ && FlagUtility.HasFlag(_lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor)
)
{
+ if (_lastEntryHeader.Part is null)
+ {
+ continue;
+ }
reader = ((StreamingZipFilePart)_lastEntryHeader.Part).FixStreamedFileLocation(
ref rewindableStream
);
+
var pos = rewindableStream.CanSeek ? (long?)rewindableStream.Position : null;
+
var crc = reader.ReadUInt32();
if (crc == POST_DATA_DESCRIPTOR)
{
@@ -81,6 +81,60 @@ internal class StreamingZipHeaderFactory : ZipHeaderFactory
_lastEntryHeader.DataStartPosition = pos - _lastEntryHeader.CompressedSize;
}
}
+ else if (_lastEntryHeader != null && _lastEntryHeader.IsZip64)
+ {
+ if (_lastEntryHeader.Part is null)
+ continue;
+
+ reader = ((StreamingZipFilePart)_lastEntryHeader.Part).FixStreamedFileLocation(
+ ref rewindableStream
+ );
+
+ var pos = rewindableStream.CanSeek ? (long?)rewindableStream.Position : null;
+
+ headerBytes = reader.ReadUInt32();
+
+ var version = reader.ReadUInt16();
+ var flags = (HeaderFlags)reader.ReadUInt16();
+ var compressionMethod = (ZipCompressionMethod)reader.ReadUInt16();
+ var lastModifiedDate = reader.ReadUInt16();
+ var lastModifiedTime = reader.ReadUInt16();
+
+ var crc = reader.ReadUInt32();
+
+ if (crc == POST_DATA_DESCRIPTOR)
+ {
+ crc = reader.ReadUInt32();
+ }
+ _lastEntryHeader.Crc = crc;
+
+ // The DataDescriptor can be either 64bit or 32bit
+ var compressed_size = reader.ReadUInt32();
+ var uncompressed_size = reader.ReadUInt32();
+
+ // Check if we have header or 64bit DataDescriptor
+ var test_header = !(headerBytes == 0x04034b50 || headerBytes == 0x02014b50);
+
+ var test_64bit = ((long)uncompressed_size << 32) | compressed_size;
+ if (test_64bit == _lastEntryHeader.CompressedSize && test_header)
+ {
+ _lastEntryHeader.UncompressedSize =
+ ((long)reader.ReadUInt32() << 32) | headerBytes;
+ headerBytes = reader.ReadUInt32();
+ }
+ else
+ {
+ _lastEntryHeader.UncompressedSize = uncompressed_size;
+ }
+
+ if (pos.HasValue)
+ {
+ _lastEntryHeader.DataStartPosition = pos - _lastEntryHeader.CompressedSize;
+
+ // 4 = First 4 bytes of the entry header (i.e. 50 4B 03 04)
+ rewindableStream.Position = pos.Value + 4;
+ }
+ }
else
{
headerBytes = reader.ReadUInt32();
@@ -97,13 +151,12 @@ internal class StreamingZipHeaderFactory : ZipHeaderFactory
if (header.ZipHeaderType == ZipHeaderType.LocalEntry)
{
var local_header = ((LocalEntryHeader)header);
- var dir_header = _entries?.FirstOrDefault(
- entry =>
- entry.Key == local_header.Name
- && local_header.CompressedSize == 0
- && local_header.UncompressedSize == 0
- && local_header.Crc == 0
- && local_header.IsDirectory == false
+ var dir_header = _entries?.FirstOrDefault(entry =>
+ entry.Key == local_header.Name
+ && local_header.CompressedSize == 0
+ && local_header.UncompressedSize == 0
+ && local_header.Crc == 0
+ && local_header.IsDirectory == false
);
if (dir_header != null)
diff --git a/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs b/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs
index 093ac034..5742458a 100644
--- a/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs
+++ b/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs
@@ -73,7 +73,7 @@ internal class WinzipAesCryptoStream : Stream
}
}
- public override void Flush() => throw new NotSupportedException();
+ public override void Flush() { }
public override int Read(byte[] buffer, int offset, int count)
{
diff --git a/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs
index 251b919e..31322019 100644
--- a/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs
+++ b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Buffers.Binary;
using System.Security.Cryptography;
@@ -10,12 +8,7 @@ internal class WinzipAesEncryptionData
{
private const int RFC2898_ITERATIONS = 1000;
- private readonly byte[] _salt;
private readonly WinzipAesKeySize _keySize;
- private readonly byte[] _passwordVerifyValue;
- private readonly string _password;
-
- private byte[] _generatedVerifyValue;
internal WinzipAesEncryptionData(
WinzipAesKeySize keySize,
@@ -25,10 +18,28 @@ internal class WinzipAesEncryptionData
)
{
_keySize = keySize;
- _salt = salt;
- _passwordVerifyValue = passwordVerifyValue;
- _password = password;
- Initialize();
+
+#if NETFRAMEWORK || NETSTANDARD2_0
+ var rfc2898 = new Rfc2898DeriveBytes(password, salt, RFC2898_ITERATIONS);
+#else
+ var rfc2898 = new Rfc2898DeriveBytes(
+ password,
+ salt,
+ RFC2898_ITERATIONS,
+ HashAlgorithmName.SHA1
+ );
+#endif
+
+ KeyBytes = rfc2898.GetBytes(KeySizeInBytes); // 16 or 24 or 32 ???
+ IvBytes = rfc2898.GetBytes(KeySizeInBytes);
+ var generatedVerifyValue = rfc2898.GetBytes(2);
+
+ var verify = BinaryPrimitives.ReadInt16LittleEndian(passwordVerifyValue);
+ var generated = BinaryPrimitives.ReadInt16LittleEndian(generatedVerifyValue);
+ if (verify != generated)
+ {
+ throw new InvalidFormatException("bad password");
+ }
}
internal byte[] IvBytes { get; set; }
@@ -45,32 +56,4 @@ internal class WinzipAesEncryptionData
WinzipAesKeySize.KeySize256 => 32,
_ => throw new InvalidOperationException(),
};
-
- private void Initialize()
- {
-#if NET7_0
- var rfc2898 = new Rfc2898DeriveBytes(
- _password,
- _salt,
- RFC2898_ITERATIONS,
- HashAlgorithmName.SHA1
- );
-#else
- var rfc2898 = new Rfc2898DeriveBytes(_password, _salt, RFC2898_ITERATIONS);
-#endif
-
- KeyBytes = rfc2898.GetBytes(KeySizeInBytes); // 16 or 24 or 32 ???
- IvBytes = rfc2898.GetBytes(KeySizeInBytes);
- _generatedVerifyValue = rfc2898.GetBytes(2);
-
- var verify = BinaryPrimitives.ReadInt16LittleEndian(_passwordVerifyValue);
- if (_password != null)
- {
- var generated = BinaryPrimitives.ReadInt16LittleEndian(_generatedVerifyValue);
- if (verify != generated)
- {
- throw new InvalidFormatException("bad password");
- }
- }
- }
}
diff --git a/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs b/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs
index 13c2dbe7..a98ed667 100644
--- a/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs
+++ b/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs
@@ -3,6 +3,7 @@ namespace SharpCompress.Common.Zip;
internal enum ZipCompressionMethod
{
None = 0,
+ Shrink = 1,
Deflate = 8,
Deflate64 = 9,
BZip2 = 12,
diff --git a/src/SharpCompress/Common/Zip/ZipEntry.cs b/src/SharpCompress/Common/Zip/ZipEntry.cs
index 2c544b94..c2cecf39 100644
--- a/src/SharpCompress/Common/Zip/ZipEntry.cs
+++ b/src/SharpCompress/Common/Zip/ZipEntry.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using SharpCompress.Common.Zip.Headers;
@@ -8,67 +6,43 @@ namespace SharpCompress.Common.Zip;
public class ZipEntry : Entry
{
- private readonly ZipFilePart _filePart;
+ private readonly ZipFilePart? _filePart;
- internal ZipEntry(ZipFilePart filePart)
+ internal ZipEntry(ZipFilePart? filePart)
{
- if (filePart != null)
+ if (filePart == null)
{
- _filePart = filePart;
- LastModifiedTime = Utility.DosDateToDateTime(
- filePart.Header.LastModifiedDate,
- filePart.Header.LastModifiedTime
- );
+ return;
}
+ _filePart = filePart;
+ LastModifiedTime = Utility.DosDateToDateTime(
+ filePart.Header.LastModifiedDate,
+ filePart.Header.LastModifiedTime
+ );
}
- public override CompressionType CompressionType
- {
- get
+ public override CompressionType CompressionType =>
+ _filePart?.Header.CompressionMethod switch
{
- switch (_filePart.Header.CompressionMethod)
- {
- case ZipCompressionMethod.BZip2:
- {
- return CompressionType.BZip2;
- }
- case ZipCompressionMethod.Deflate:
- {
- return CompressionType.Deflate;
- }
- case ZipCompressionMethod.Deflate64:
- {
- return CompressionType.Deflate64;
- }
- case ZipCompressionMethod.LZMA:
- {
- return CompressionType.LZMA;
- }
- case ZipCompressionMethod.PPMd:
- {
- return CompressionType.PPMd;
- }
- case ZipCompressionMethod.None:
- {
- return CompressionType.None;
- }
- default:
- {
- return CompressionType.Unknown;
- }
- }
- }
- }
+ 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,
+ _ => CompressionType.Unknown
+ };
- public override long Crc => _filePart.Header.Crc;
+ public override long Crc => _filePart?.Header.Crc ?? 0;
- public override string Key => _filePart.Header.Name;
+ public override string? Key => _filePart?.Header.Name;
- public override string LinkTarget => null;
+ public override string? LinkTarget => null;
- public override long CompressedSize => _filePart.Header.CompressedSize;
+ public override long CompressedSize => _filePart?.Header.CompressedSize ?? 0;
- public override long Size => _filePart.Header.UncompressedSize;
+ public override long Size => _filePart?.Header.UncompressedSize ?? 0;
public override DateTime? LastModifiedTime { get; }
@@ -79,11 +53,11 @@ public class ZipEntry : Entry
public override DateTime? ArchivedTime => null;
public override bool IsEncrypted =>
- FlagUtility.HasFlag(_filePart.Header.Flags, HeaderFlags.Encrypted);
+ FlagUtility.HasFlag(_filePart?.Header.Flags ?? HeaderFlags.None, HeaderFlags.Encrypted);
- public override bool IsDirectory => _filePart.Header.IsDirectory;
+ public override bool IsDirectory => _filePart?.Header.IsDirectory ?? false;
public override bool IsSplitAfter => false;
- internal override IEnumerable Parts => _filePart.AsEnumerable();
+ internal override IEnumerable Parts => _filePart.Empty();
}
diff --git a/src/SharpCompress/Common/Zip/ZipFilePart.cs b/src/SharpCompress/Common/Zip/ZipFilePart.cs
index faefdf15..e8516150 100644
--- a/src/SharpCompress/Common/Zip/ZipFilePart.cs
+++ b/src/SharpCompress/Common/Zip/ZipFilePart.cs
@@ -9,6 +9,7 @@ using SharpCompress.Compressors.Deflate;
using SharpCompress.Compressors.Deflate64;
using SharpCompress.Compressors.LZMA;
using SharpCompress.Compressors.PPMd;
+using SharpCompress.Compressors.Shrink;
using SharpCompress.Compressors.Xz;
using SharpCompress.IO;
using ZstdSharp;
@@ -28,7 +29,7 @@ internal abstract class ZipFilePart : FilePart
internal Stream BaseStream { get; }
internal ZipFileEntry Header { get; set; }
- internal override string FilePartName => Header.Name;
+ internal override string? FilePartName => Header.Name;
internal override Stream GetCompressedStream()
{
@@ -79,6 +80,15 @@ internal abstract class ZipFilePart : FilePart
return new DataDescriptorStream(stream);
}
+ case ZipCompressionMethod.Shrink:
+ {
+ return new ShrinkStream(
+ stream,
+ CompressionMode.Decompress,
+ Header.CompressedSize,
+ Header.UncompressedSize
+ );
+ }
case ZipCompressionMethod.Deflate:
{
return new DeflateStream(stream, CompressionMode.Decompress);
@@ -192,6 +202,7 @@ internal abstract class ZipFilePart : FilePart
switch (Header.CompressionMethod)
{
case ZipCompressionMethod.None:
+ case ZipCompressionMethod.Shrink:
case ZipCompressionMethod.Deflate:
case ZipCompressionMethod.Deflate64:
case ZipCompressionMethod.BZip2:
diff --git a/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs
index 8a58e220..45869ff6 100644
--- a/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs
+++ b/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs
@@ -55,7 +55,13 @@ internal class ZipHeaderFactory
}
case POST_DATA_DESCRIPTOR:
{
- if (FlagUtility.HasFlag(_lastEntryHeader!.Flags, HeaderFlags.UsePostDataDescriptor))
+ if (
+ _lastEntryHeader != null
+ && FlagUtility.HasFlag(
+ _lastEntryHeader.NotNull().Flags,
+ HeaderFlags.UsePostDataDescriptor
+ )
+ )
{
_lastEntryHeader.Crc = reader.ReadUInt32();
_lastEntryHeader.CompressedSize = zip64
@@ -142,8 +148,8 @@ internal class ZipHeaderFactory
if (entryHeader.CompressionMethod == ZipCompressionMethod.WinzipAes)
{
- var data = entryHeader.Extra.SingleOrDefault(
- x => x.Type == ExtraDataType.WinZipAes
+ var data = entryHeader.Extra.SingleOrDefault(x =>
+ x.Type == ExtraDataType.WinZipAes
);
if (data != null)
{
diff --git a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs
index feea12d1..2c00ea71 100644
--- a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs
+++ b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs
@@ -69,7 +69,7 @@ public sealed class BZip2Stream : Stream
public override void SetLength(long value) => stream.SetLength(value);
-#if !NETFRAMEWORK && !NETSTANDARD2_0
+#if !NETFRAMEWORK&& !NETSTANDARD2_0
public override int Read(Span buffer) => stream.Read(buffer);
diff --git a/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs b/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs
index e03a5096..a467942f 100644
--- a/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs
+++ b/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs
@@ -1,4 +1,4 @@
-#nullable disable
+#nullable disable
using System;
using System.IO;
@@ -42,14 +42,17 @@ internal class CBZip2InputStream : Stream
private static void Cadvise()
{
//System.out.Println("CRC Error");
- //throw new CCoruptionError();
+ throw new InvalidOperationException("BZip2 error");
}
private static void BadBGLengths() => Cadvise();
private static void BitStreamEOF() => Cadvise();
- private static void CompressedStreamEOF() => Cadvise();
+ private static void CompressedStreamEOF()
+ {
+ throw new InvalidOperationException("BZip2 compressed file ends unexpectedly");
+ }
private void MakeMaps()
{
@@ -87,7 +90,7 @@ internal class CBZip2InputStream : Stream
private int bsBuff;
private int bsLive;
- private readonly CRC mCrc = new CRC();
+ private readonly CRC mCrc = new();
private readonly bool[] inUse = new bool[256];
private int nInUse;
diff --git a/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs b/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs
index a975ffbd..bf01c2c3 100644
--- a/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs
+++ b/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs
@@ -284,7 +284,7 @@ internal sealed class CBZip2OutputStream : Stream
private int bytesOut;
private int bsBuff;
private int bsLive;
- private readonly CRC mCrc = new CRC();
+ private readonly CRC mCrc = new();
private readonly bool[] inUse = new bool[256];
private int nInUse;
diff --git a/src/SharpCompress/Compressors/Deflate/DeflateManager.cs b/src/SharpCompress/Compressors/Deflate/DeflateManager.cs
index 27ad4018..cccd0237 100644
--- a/src/SharpCompress/Compressors/Deflate/DeflateManager.cs
+++ b/src/SharpCompress/Compressors/Deflate/DeflateManager.cs
@@ -69,7 +69,6 @@
// -----------------------------------------------------------------------
using System;
-
using SharpCompress.Algorithms;
namespace SharpCompress.Compressors.Deflate;
@@ -343,9 +342,9 @@ internal sealed partial class DeflateManager
private readonly short[] dyn_dtree; // distance tree
private readonly short[] bl_tree; // Huffman tree for bit lengths
- private readonly Tree treeLiterals = new Tree(); // desc for literal tree
- private readonly Tree treeDistances = new Tree(); // desc for distance tree
- private readonly Tree treeBitLengths = new Tree(); // desc for bit length tree
+ private readonly Tree treeLiterals = new(); // desc for literal tree
+ private readonly Tree treeDistances = new(); // desc for distance tree
+ private readonly Tree treeBitLengths = new(); // desc for bit length tree
// number of codes at each bit length for an optimal tree
private readonly short[] bl_count = new short[InternalConstants.MAX_BITS + 1];
@@ -1788,21 +1787,14 @@ internal sealed partial class DeflateManager
return status == BUSY_STATE ? ZlibConstants.Z_DATA_ERROR : ZlibConstants.Z_OK;
}
- private void SetDeflater()
- {
- switch (config.Flavor)
+ private void SetDeflater() =>
+ DeflateFunction = config.Flavor switch
{
- case DeflateFlavor.Store:
- DeflateFunction = DeflateNone;
- break;
- case DeflateFlavor.Fast:
- DeflateFunction = DeflateFast;
- break;
- case DeflateFlavor.Slow:
- DeflateFunction = DeflateSlow;
- break;
- }
- }
+ DeflateFlavor.Store => DeflateNone,
+ DeflateFlavor.Fast => DeflateFast,
+ DeflateFlavor.Slow => DeflateSlow,
+ _ => DeflateFunction
+ };
internal int SetParams(CompressionLevel level, CompressionStrategy strategy)
{
@@ -1959,7 +1951,9 @@ internal sealed partial class DeflateManager
// returning Z_STREAM_END instead of Z_BUFF_ERROR.
}
else if (
- _codec.AvailableBytesIn == 0 && (int)flush <= old_flush && flush != FlushType.Finish
+ _codec.AvailableBytesIn == 0
+ && (int)flush <= old_flush
+ && flush != FlushType.Finish
)
{
// workitem 8557
diff --git a/src/SharpCompress/Compressors/Deflate/DeflateStream.cs b/src/SharpCompress/Compressors/Deflate/DeflateStream.cs
index 05003d7f..5566e817 100644
--- a/src/SharpCompress/Compressors/Deflate/DeflateStream.cs
+++ b/src/SharpCompress/Compressors/Deflate/DeflateStream.cs
@@ -366,9 +366,5 @@ public class DeflateStream : Stream
#endregion
public MemoryStream InputBuffer =>
- new MemoryStream(
- _baseStream._z.InputBuffer,
- _baseStream._z.NextIn,
- _baseStream._z.AvailableBytesIn
- );
+ new(_baseStream._z.InputBuffer, _baseStream._z.NextIn, _baseStream._z.AvailableBytesIn);
}
diff --git a/src/SharpCompress/Compressors/Deflate/GZipStream.cs b/src/SharpCompress/Compressors/Deflate/GZipStream.cs
index c547df14..0f7beca8 100644
--- a/src/SharpCompress/Compressors/Deflate/GZipStream.cs
+++ b/src/SharpCompress/Compressors/Deflate/GZipStream.cs
@@ -35,15 +35,7 @@ namespace SharpCompress.Compressors.Deflate;
public class GZipStream : Stream
{
- internal static readonly DateTime UNIX_EPOCH = new DateTime(
- 1970,
- 1,
- 1,
- 0,
- 0,
- 0,
- DateTimeKind.Utc
- );
+ internal static readonly DateTime UNIX_EPOCH = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private string? _comment;
private string? _fileName;
diff --git a/src/SharpCompress/Compressors/Deflate/Inflate.cs b/src/SharpCompress/Compressors/Deflate/Inflate.cs
index ebea2805..d768548b 100644
--- a/src/SharpCompress/Compressors/Deflate/Inflate.cs
+++ b/src/SharpCompress/Compressors/Deflate/Inflate.cs
@@ -64,7 +64,6 @@
// -----------------------------------------------------------------------
using System;
-
using SharpCompress.Algorithms;
namespace SharpCompress.Compressors.Deflate;
@@ -106,11 +105,11 @@ internal sealed class InflateBlocks
internal int[] blens; // bit lengths of codes
internal uint check; // check on output
internal object checkfn; // check function
- internal InflateCodes codes = new InflateCodes(); // if CODES, current state
+ internal InflateCodes codes = new(); // if CODES, current state
internal int end; // one byte after sliding window
internal int[] hufts; // single malloc for tree space
internal int index; // index into blens (or border)
- internal InfTree inftree = new InfTree();
+ internal InfTree inftree = new();
internal int last; // true if this block is the last block
internal int left; // if STORED, bytes left to copy
private InflateBlockMode mode; // current inflate_block mode
diff --git a/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs b/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs
index 19a3c60a..94b1491d 100644
--- a/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs
+++ b/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs
@@ -30,8 +30,8 @@ using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
-using SharpCompress.Common.Tar.Headers;
using System.Text;
+using SharpCompress.Common.Tar.Headers;
namespace SharpCompress.Compressors.Deflate;
@@ -102,7 +102,7 @@ internal class ZlibBaseStream : Stream
{
if (_z is null)
{
- bool wantRfc1950Header = (_flavor == ZlibStreamFlavor.ZLIB);
+ var wantRfc1950Header = (_flavor == ZlibStreamFlavor.ZLIB);
_z = new ZlibCodec();
if (_compressionMode == CompressionMode.Decompress)
{
@@ -147,13 +147,13 @@ internal class ZlibBaseStream : Stream
z.InputBuffer = buffer;
_z.NextIn = offset;
_z.AvailableBytesIn = count;
- bool done = false;
+ var done = false;
do
{
_z.OutputBuffer = workingBuffer;
_z.NextOut = 0;
_z.AvailableBytesOut = _workingBuffer.Length;
- int rc = (_wantCompress) ? _z.Deflate(_flushMode) : _z.Inflate(_flushMode);
+ var rc = (_wantCompress) ? _z.Deflate(_flushMode) : _z.Inflate(_flushMode);
if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
{
throw new ZlibException((_wantCompress ? "de" : "in") + "flating: " + _z.Message);
@@ -181,18 +181,18 @@ internal class ZlibBaseStream : Stream
if (_streamMode == StreamMode.Writer)
{
- bool done = false;
+ var done = false;
do
{
_z.OutputBuffer = workingBuffer;
_z.NextOut = 0;
_z.AvailableBytesOut = _workingBuffer.Length;
- int rc =
+ var rc =
(_wantCompress) ? _z.Deflate(FlushType.Finish) : _z.Inflate(FlushType.Finish);
if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK)
{
- string verb = (_wantCompress ? "de" : "in") + "flating";
+ var verb = (_wantCompress ? "de" : "in") + "flating";
if (_z.Message is null)
{
throw new ZlibException(String.Format("{0}: (rc = {1})", verb, rc));
@@ -225,7 +225,7 @@ internal class ZlibBaseStream : Stream
Span intBuf = stackalloc byte[4];
BinaryPrimitives.WriteInt32LittleEndian(intBuf, crc.Crc32Result);
_stream.Write(intBuf);
- int c2 = (int)(crc.TotalBytesRead & 0x00000000FFFFFFFF);
+ var c2 = (int)(crc.TotalBytesRead & 0x00000000FFFFFFFF);
BinaryPrimitives.WriteInt32LittleEndian(intBuf, c2);
_stream.Write(intBuf);
}
@@ -256,8 +256,8 @@ internal class ZlibBaseStream : Stream
{
// Make sure we have read to the end of the stream
_z.InputBuffer.AsSpan(_z.NextIn, _z.AvailableBytesIn).CopyTo(trailer);
- int bytesNeeded = 8 - _z.AvailableBytesIn;
- int bytesRead = _stream.Read(
+ var bytesNeeded = 8 - _z.AvailableBytesIn;
+ var bytesRead = _stream.Read(
trailer.Slice(_z.AvailableBytesIn, bytesNeeded)
);
if (bytesNeeded != bytesRead)
@@ -275,10 +275,10 @@ internal class ZlibBaseStream : Stream
_z.InputBuffer.AsSpan(_z.NextIn, trailer.Length).CopyTo(trailer);
}
- Int32 crc32_expected = BinaryPrimitives.ReadInt32LittleEndian(trailer);
- Int32 crc32_actual = crc.Crc32Result;
- Int32 isize_expected = BinaryPrimitives.ReadInt32LittleEndian(trailer.Slice(4));
- Int32 isize_actual = (Int32)(_z.TotalBytesOut & 0x00000000FFFFFFFF);
+ var crc32_expected = BinaryPrimitives.ReadInt32LittleEndian(trailer);
+ var crc32_actual = crc.Crc32Result;
+ var isize_expected = BinaryPrimitives.ReadInt32LittleEndian(trailer.Slice(4));
+ var isize_actual = (Int32)(_z.TotalBytesOut & 0x00000000FFFFFFFF);
if (crc32_actual != crc32_expected)
{
@@ -380,11 +380,11 @@ internal class ZlibBaseStream : Stream
private string ReadZeroTerminatedString()
{
var list = new List();
- bool done = false;
+ var done = false;
do
{
// workitem 7740
- int n = _stream.Read(_buf1, 0, 1);
+ var n = _stream.Read(_buf1, 0, 1);
if (n != 1)
{
throw new ZlibException("Unexpected EOF reading GZIP header.");
@@ -398,17 +398,17 @@ internal class ZlibBaseStream : Stream
list.Add(_buf1[0]);
}
} while (!done);
- byte[] buffer = list.ToArray();
+ var buffer = list.ToArray();
return _encoding.GetString(buffer, 0, buffer.Length);
}
private int _ReadAndValidateGzipHeader()
{
- int totalBytesRead = 0;
+ var totalBytesRead = 0;
// read the header on the first read
Span header = stackalloc byte[10];
- int n = _stream.Read(header);
+ var n = _stream.Read(header);
// workitem 8501: handle edge case (decompress empty stream)
if (n == 0)
@@ -426,7 +426,7 @@ internal class ZlibBaseStream : Stream
throw new ZlibException("Bad GZIP header.");
}
- int timet = BinaryPrimitives.ReadInt32LittleEndian(header.Slice(4));
+ var timet = BinaryPrimitives.ReadInt32LittleEndian(header.Slice(4));
_GzipMtime = TarHeader.EPOCH.AddSeconds(timet);
totalBytesRead += n;
if ((header[3] & 0x04) == 0x04)
@@ -435,8 +435,8 @@ internal class ZlibBaseStream : Stream
n = _stream.Read(header.Slice(0, 2)); // 2-byte length field
totalBytesRead += n;
- short extraLength = (short)(header[0] + header[1] * 256);
- byte[] extra = new byte[extraLength];
+ var extraLength = (short)(header[0] + header[1] * 256);
+ var extra = new byte[extraLength];
n = _stream.Read(extra, 0, extra.Length);
if (n != extraLength)
{
@@ -498,7 +498,7 @@ internal class ZlibBaseStream : Stream
throw new ZlibException("Cannot Read after Writing.");
}
- int rc = 0;
+ var rc = 0;
// set up the output of the deflate/inflate codec:
_z.OutputBuffer = buffer;
diff --git a/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs b/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs
index 149f7c92..da4117b9 100644
--- a/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs
+++ b/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs
@@ -4,11 +4,11 @@
#nullable disable
-using SharpCompress.Common.Zip;
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
+using SharpCompress.Common.Zip;
namespace SharpCompress.Compressors.Deflate64;
@@ -118,8 +118,8 @@ public sealed class Deflate64Stream : Stream
EnsureNotDisposed();
int bytesRead;
- int currentOffset = offset;
- int remainingCount = count;
+ var currentOffset = offset;
+ var remainingCount = count;
while (true)
{
@@ -142,7 +142,7 @@ public sealed class Deflate64Stream : Stream
break;
}
- int bytes = _stream.Read(_buffer, 0, _buffer.Length);
+ var bytes = _stream.Read(_buffer, 0, _buffer.Length);
if (bytes <= 0)
{
break;
diff --git a/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs b/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs
index 6a12df3b..304a2a78 100644
--- a/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs
+++ b/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs
@@ -22,7 +22,7 @@ internal sealed class DeflateInput
Debug.Assert(StartIndex + Count <= Buffer.Length, "Input buffer is in invalid state!");
}
- internal InputState DumpState() => new InputState(Count, StartIndex);
+ internal InputState DumpState() => new(Count, StartIndex);
internal void RestoreState(InputState state)
{
diff --git a/src/SharpCompress/Compressors/Deflate64/HuffmanTree.cs b/src/SharpCompress/Compressors/Deflate64/HuffmanTree.cs
index 051b613e..e37802bb 100644
--- a/src/SharpCompress/Compressors/Deflate64/HuffmanTree.cs
+++ b/src/SharpCompress/Compressors/Deflate64/HuffmanTree.cs
@@ -42,11 +42,9 @@ internal sealed class HuffmanTree
private readonly int _tableMask;
// huffman tree for static block
- public static HuffmanTree StaticLiteralLengthTree { get; } =
- new HuffmanTree(GetStaticLiteralTreeLength());
+ public static HuffmanTree StaticLiteralLengthTree { get; } = new(GetStaticLiteralTreeLength());
- public static HuffmanTree StaticDistanceTree { get; } =
- new HuffmanTree(GetStaticDistanceTreeLength());
+ public static HuffmanTree StaticDistanceTree { get; } = new(GetStaticDistanceTreeLength());
public HuffmanTree(byte[] codeLengths)
{
diff --git a/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs b/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs
index 6a3c226b..4e11854f 100644
--- a/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs
+++ b/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs
@@ -243,8 +243,8 @@ internal sealed class InflaterManaged
private void Reset() =>
_state = //_hasFormatReader ?
- //InflaterState.ReadingHeader : // start by reading Header info
- InflaterState.ReadingBFinal; // start by reading BFinal bit
+ //InflaterState.ReadingHeader : // start by reading Header info
+ InflaterState.ReadingBFinal; // start by reading BFinal bit
public void SetInput(byte[] inputBytes, int offset, int length) =>
_input.SetInput(inputBytes, offset, length); // append the bytes
diff --git a/src/SharpCompress/Compressors/Filters/BCJ2Filter.cs b/src/SharpCompress/Compressors/Filters/BCJ2Filter.cs
index f658b385..1ed531cc 100644
--- a/src/SharpCompress/Compressors/Filters/BCJ2Filter.cs
+++ b/src/SharpCompress/Compressors/Filters/BCJ2Filter.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.IO;
namespace SharpCompress.Compressors.Filters;
@@ -79,7 +79,7 @@ internal class BCJ2Filter : Stream
public override bool CanWrite => false;
- public override void Flush() => throw new NotSupportedException();
+ public override void Flush() { }
public override long Length => _baseStream.Length + _data1.Length + _data2.Length;
diff --git a/src/SharpCompress/Compressors/Filters/BCJFilterARM.cs b/src/SharpCompress/Compressors/Filters/BCJFilterARM.cs
index 86e90b10..5d861621 100644
--- a/src/SharpCompress/Compressors/Filters/BCJFilterARM.cs
+++ b/src/SharpCompress/Compressors/Filters/BCJFilterARM.cs
@@ -18,7 +18,7 @@ internal class BCJFilterARM : Filter
{
if ((buffer[i + 3] & 0xFF) == 0xEB)
{
- int src =
+ var src =
((buffer[i + 2] & 0xFF) << 16)
| ((buffer[i + 1] & 0xFF) << 8)
| (buffer[i] & 0xFF);
diff --git a/src/SharpCompress/Compressors/Filters/BCJFilterARM64.cs b/src/SharpCompress/Compressors/Filters/BCJFilterARM64.cs
new file mode 100644
index 00000000..24f5ab17
--- /dev/null
+++ b/src/SharpCompress/Compressors/Filters/BCJFilterARM64.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Buffers.Binary;
+using System.IO;
+
+namespace SharpCompress.Compressors.Filters;
+
+internal class BCJFilterARM64 : Filter
+{
+ private int _pos;
+
+ public BCJFilterARM64(bool isEncoder, Stream baseStream)
+ : base(isEncoder, baseStream, 8) => _pos = 0;
+
+ protected override int Transform(byte[] buffer, int offset, int count)
+ {
+ var end = offset + count - 4;
+ int i;
+
+ for (i = offset; i <= end; i += 4)
+ {
+ uint pc = (uint)(_pos + i - offset);
+ uint instr = BinaryPrimitives.ReadUInt32LittleEndian(
+ new ReadOnlySpan(buffer, i, 4)
+ );
+
+ if ((instr >> 26) == 0x25)
+ {
+ uint src = instr;
+ instr = 0x94000000;
+
+ pc >>= 2;
+ if (!_isEncoder)
+ pc = 0U - pc;
+
+ instr |= (src + pc) & 0x03FFFFFF;
+ BinaryPrimitives.WriteUInt32LittleEndian(new Span(buffer, i, 4), instr);
+ }
+ else if ((instr & 0x9F000000) == 0x90000000)
+ {
+ uint src = ((instr >> 29) & 3) | ((instr >> 3) & 0x001FFFFC);
+
+ if (((src + 0x00020000) & 0x001C0000) != 0)
+ continue;
+
+ instr &= 0x9000001F;
+
+ pc >>= 12;
+ if (!_isEncoder)
+ pc = 0U - pc;
+
+ uint dest = src + pc;
+ instr |= (dest & 3) << 29;
+ instr |= (dest & 0x0003FFFC) << 3;
+ instr |= (0U - (dest & 0x00020000)) & 0x00E00000;
+ BinaryPrimitives.WriteUInt32LittleEndian(new Span(buffer, i, 4), instr);
+ }
+ }
+
+ i -= offset;
+ _pos += i;
+ return i;
+ }
+}
diff --git a/src/SharpCompress/Compressors/Filters/BCJFilterARMT.cs b/src/SharpCompress/Compressors/Filters/BCJFilterARMT.cs
index d2ad1bbf..db5b36f2 100644
--- a/src/SharpCompress/Compressors/Filters/BCJFilterARMT.cs
+++ b/src/SharpCompress/Compressors/Filters/BCJFilterARMT.cs
@@ -18,7 +18,7 @@ internal class BCJFilterARMT : Filter
{
if ((buffer[i + 1] & 0xF8) == 0xF0 && (buffer[i + 3] & 0xF8) == 0xF8)
{
- int src =
+ var src =
((buffer[i + 1] & 0x07) << 19)
| ((buffer[i] & 0xFF) << 11)
| ((buffer[i + 3] & 0x07) << 8)
diff --git a/src/SharpCompress/Compressors/Filters/BCJFilterIA64.cs b/src/SharpCompress/Compressors/Filters/BCJFilterIA64.cs
index 4d89ba39..07eaf319 100644
--- a/src/SharpCompress/Compressors/Filters/BCJFilterIA64.cs
+++ b/src/SharpCompress/Compressors/Filters/BCJFilterIA64.cs
@@ -52,29 +52,29 @@ internal class BCJFilterIA64 : Filter
for (i = offset; i <= end; i += 16)
{
- int instrTemplate = buffer[i] & 0x1F;
- int mask = BRANCH_TABLE[instrTemplate];
+ var instrTemplate = buffer[i] & 0x1F;
+ var mask = BRANCH_TABLE[instrTemplate];
for (int slot = 0, bitPos = 5; slot < 3; ++slot, bitPos += 41)
{
if (((mask >>> slot) & 1) == 0)
continue;
- int bytePos = bitPos >>> 3;
- int bitRes = bitPos & 7;
+ var bytePos = bitPos >>> 3;
+ var bitRes = bitPos & 7;
long instr = 0;
- for (int j = 0; j < 6; ++j)
+ for (var j = 0; j < 6; ++j)
{
instr |= (buffer[i + bytePos + j] & 0xFFL) << (8 * j);
}
- long instrNorm = instr >>> bitRes;
+ var instrNorm = instr >>> bitRes;
if (((instrNorm >>> 37) & 0x0F) != 0x05 || ((instrNorm >>> 9) & 0x07) != 0x00)
continue;
- int src = (int)((instrNorm >>> 13) & 0x0FFFFF);
+ var src = (int)((instrNorm >>> 13) & 0x0FFFFF);
src |= ((int)(instrNorm >>> 36) & 1) << 20;
src <<= 4;
@@ -93,7 +93,7 @@ internal class BCJFilterIA64 : Filter
instr &= (1 << bitRes) - 1;
instr |= instrNorm << bitRes;
- for (int j = 0; j < 6; ++j)
+ for (var j = 0; j < 6; ++j)
{
buffer[i + bytePos + j] = (byte)(instr >>> (8 * j));
}
diff --git a/src/SharpCompress/Compressors/Filters/BCJFilterPPC.cs b/src/SharpCompress/Compressors/Filters/BCJFilterPPC.cs
index 11ed61a1..ccfa7480 100644
--- a/src/SharpCompress/Compressors/Filters/BCJFilterPPC.cs
+++ b/src/SharpCompress/Compressors/Filters/BCJFilterPPC.cs
@@ -18,7 +18,7 @@ internal class BCJFilterPPC : Filter
{
if ((buffer[i] & 0xFC) == 0x48 && (buffer[i + 3] & 0x03) == 0x01)
{
- int src =
+ var src =
((buffer[i] & 0x03) << 24)
| ((buffer[i + 1] & 0xFF) << 16)
| ((buffer[i + 2] & 0xFF) << 8)
diff --git a/src/SharpCompress/Compressors/Filters/BCJFilterRISCV.cs b/src/SharpCompress/Compressors/Filters/BCJFilterRISCV.cs
new file mode 100644
index 00000000..67d9cb52
--- /dev/null
+++ b/src/SharpCompress/Compressors/Filters/BCJFilterRISCV.cs
@@ -0,0 +1,210 @@
+using System;
+using System.Buffers.Binary;
+using System.IO;
+
+namespace SharpCompress.Compressors.Filters;
+
+internal class BCJFilterRISCV : Filter
+{
+ private int _pos;
+
+ public BCJFilterRISCV(bool isEncoder, Stream baseStream)
+ : base(isEncoder, baseStream, 8) => _pos = 0;
+
+ private int Decode(byte[] buffer, int offset, int count)
+ {
+ if (count < 8)
+ {
+ return 0;
+ }
+
+ var end = offset + count - 8;
+ int i;
+ for (i = offset; i <= end; i += 2)
+ {
+ uint inst = buffer[i];
+ if (inst == 0xEF)
+ {
+ uint b1 = buffer[i + 1];
+ if ((b1 & 0x0D) != 0)
+ continue;
+
+ uint b2 = buffer[i + 2];
+ uint b3 = buffer[i + 3];
+ uint pc = (uint)(_pos + i);
+
+ uint addr = ((b1 & 0xF0) << 13) | (b2 << 9) | (b3 << 1);
+
+ addr -= pc;
+
+ buffer[i + 1] = (byte)((b1 & 0x0F) | ((addr >> 8) & 0xF0));
+
+ buffer[i + 2] = (byte)(
+ ((addr >> 16) & 0x0F) | ((addr >> 7) & 0x10) | ((addr << 4) & 0xE0)
+ );
+
+ buffer[i + 3] = (byte)(((addr >> 4) & 0x7F) | ((addr >> 13) & 0x80));
+
+ i += 4 - 2;
+ }
+ else if ((inst & 0x7F) == 0x17)
+ {
+ uint inst2 = 0;
+ inst |= (uint)buffer[i + 1] << 8;
+ inst |= (uint)buffer[i + 2] << 16;
+ inst |= (uint)buffer[i + 3] << 24;
+
+ if ((inst & 0xE80) != 0)
+ {
+ inst2 = BinaryPrimitives.ReadUInt32LittleEndian(
+ new ReadOnlySpan(buffer, i + 4, 4)
+ );
+ if (((((inst) << 8) ^ (inst2)) & 0xF8003) != 3)
+ {
+ i += 6 - 2;
+ continue;
+ }
+ uint addr = inst & 0xFFFFF000;
+ addr += inst2 >> 20;
+
+ inst = 0x17 | (2 << 7) | (inst2 << 12);
+ inst2 = addr;
+ }
+ else
+ {
+ uint inst2_rs1 = inst >> 27;
+ if ((uint)(((inst) - 0x3117) << 18) >= ((inst2_rs1) & 0x1D))
+ {
+ i += 4 - 2;
+ continue;
+ }
+
+ uint addr = BinaryPrimitives.ReadUInt32BigEndian(
+ new ReadOnlySpan(buffer, i + 4, 4)
+ );
+
+ addr -= (uint)(_pos + i);
+
+ inst2 = (inst >> 12) | (addr << 20);
+
+ inst = 0x17 | (inst2_rs1 << 7) | ((addr + 0x800) & 0xFFFFF000);
+ }
+ BinaryPrimitives.WriteUInt32LittleEndian(new Span(buffer, i, 4), inst);
+ BinaryPrimitives.WriteUInt32LittleEndian(new Span(buffer, i + 4, 4), inst2);
+
+ i += 8 - 2;
+ }
+ }
+ i -= offset;
+ _pos += i;
+ return i;
+ }
+
+ private int Encode(byte[] buffer, int offset, int count)
+ {
+ if (count < 8)
+ {
+ return 0;
+ }
+
+ var end = offset + count - 8;
+ int i;
+ for (i = offset; i <= end; i += 2)
+ {
+ uint inst = buffer[i];
+ if (inst == 0xEF)
+ {
+ uint b1 = buffer[i + 1];
+ if ((b1 & 0x0D) != 0)
+ continue;
+
+ uint b2 = buffer[i + 2];
+ uint b3 = buffer[i + 3];
+ uint pc = (uint)(_pos + i);
+
+ uint addr =
+ ((b1 & 0xF0) << 8)
+ | ((b2 & 0x0F) << 16)
+ | ((b2 & 0x10) << 7)
+ | ((b2 & 0xE0) >> 4)
+ | ((b3 & 0x7F) << 4)
+ | ((b3 & 0x80) << 13);
+
+ addr += pc;
+
+ buffer[i + 1] = (byte)((b1 & 0x0F) | ((addr >> 13) & 0xF0));
+
+ buffer[i + 2] = (byte)(addr >> 9);
+
+ buffer[i + 3] = (byte)(addr >> 1);
+
+ i += 4 - 2;
+ }
+ else if ((inst & 0x7F) == 0x17)
+ {
+ inst |= (uint)buffer[i + 1] << 8;
+ inst |= (uint)buffer[i + 2] << 16;
+ inst |= (uint)buffer[i + 3] << 24;
+
+ if ((inst & 0xE80) != 0)
+ {
+ uint inst2 = BinaryPrimitives.ReadUInt32LittleEndian(
+ new ReadOnlySpan(buffer, i + 4, 4)
+ );
+ if (((((inst) << 8) ^ (inst2)) & 0xF8003) != 3)
+ {
+ i += 6 - 2;
+ continue;
+ }
+ uint addr = inst & 0xFFFFF000;
+ addr += (inst2 >> 20) - ((inst2 >> 19) & 0x1000);
+
+ addr += (uint)(_pos + i);
+ inst = 0x17 | (2 << 7) | (inst2 << 12);
+
+ BinaryPrimitives.WriteUInt32LittleEndian(new Span(buffer, i, 4), inst);
+ BinaryPrimitives.WriteUInt32BigEndian(new Span(buffer, i + 4, 4), addr);
+ }
+ else
+ {
+ uint fake_rs1 = inst >> 27;
+ if ((uint)(((inst) - 0x3117) << 18) >= ((fake_rs1) & 0x1D))
+ {
+ i += 4 - 2;
+ continue;
+ }
+
+ uint fake_addr = BinaryPrimitives.ReadUInt32LittleEndian(
+ new ReadOnlySpan(buffer, i + 4, 4)
+ );
+
+ uint fake_inst2 = (inst >> 12) | (fake_addr << 20);
+
+ inst = 0x17 | (fake_rs1 << 7) | (fake_addr & 0xFFFFF000);
+
+ BinaryPrimitives.WriteUInt32LittleEndian(new Span(buffer, i, 4), inst);
+ BinaryPrimitives.WriteUInt32LittleEndian(
+ new Span(buffer, i + 4, 4),
+ fake_inst2
+ );
+ }
+ i += 8 - 2;
+ }
+ }
+ i -= offset;
+ _pos += i;
+ return i;
+ }
+
+ protected override int Transform(byte[] buffer, int offset, int count)
+ {
+ if (_isEncoder)
+ {
+ return Encode(buffer, offset, count);
+ }
+ else
+ {
+ return Decode(buffer, offset, count);
+ }
+ }
+}
diff --git a/src/SharpCompress/Compressors/Filters/BCJFilterSPARC.cs b/src/SharpCompress/Compressors/Filters/BCJFilterSPARC.cs
index 67756d34..db7c75be 100644
--- a/src/SharpCompress/Compressors/Filters/BCJFilterSPARC.cs
+++ b/src/SharpCompress/Compressors/Filters/BCJFilterSPARC.cs
@@ -21,7 +21,7 @@ internal class BCJFilterSPARC : Filter
|| (buffer[i] == 0x7F && (buffer[i + 1] & 0xC0) == 0xC0)
)
{
- int src =
+ var src =
((buffer[i] & 0xFF) << 24)
| ((buffer[i + 1] & 0xFF) << 16)
| ((buffer[i + 2] & 0xFF) << 8)
diff --git a/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs b/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs
index 9fc439d4..d198cf8f 100644
--- a/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs
+++ b/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs
@@ -24,40 +24,27 @@ public sealed class BranchExecFilter
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool X86TestByte(byte b)
- {
- return b == 0x00 || b == 0xFF;
- }
+ private static bool X86TestByte(byte b) => b == 0x00 || b == 0xFF;
//Replaced X86Converter with bcj_x86() - https://github.com/torvalds/linux/blob/master/lib/xz/xz_dec_bcj.c
//This was to fix an issue decoding a Test zip made with WinZip (that 7zip was also able to read).
//The previous version of the code would corrupt 2 bytes in the Test.exe at 0x6CF9 (3D6D - should be 4000) - Test zip: WinZip27.Xz.zipx
public static void X86Converter(byte[] buf, uint ip, ref uint state)
{
- bool[] mask_to_allowed_status = new[]
- {
- true,
- true,
- true,
- false,
- true,
- false,
- false,
- false
- };
+ var mask_to_allowed_status = new[] { true, true, true, false, true, false, false, false };
- byte[] mask_to_bit_num = new byte[] { 0, 1, 2, 2, 3, 3, 3, 3 };
+ var mask_to_bit_num = new byte[] { 0, 1, 2, 2, 3, 3, 3, 3 };
int i;
- int prev_pos = -1;
- uint prev_mask = state & 7;
+ var prev_pos = -1;
+ var prev_mask = state & 7;
uint src;
uint dest;
uint j;
byte b;
- uint pos = ip;
+ var pos = ip;
- uint size = (uint)buf.Length;
+ var size = (uint)buf.Length;
if (size <= 4)
return;
diff --git a/src/SharpCompress/Compressors/Filters/DeltaFilter.cs b/src/SharpCompress/Compressors/Filters/DeltaFilter.cs
index c5fbeb41..85ec9b15 100644
--- a/src/SharpCompress/Compressors/Filters/DeltaFilter.cs
+++ b/src/SharpCompress/Compressors/Filters/DeltaFilter.cs
@@ -23,9 +23,9 @@ namespace SharpCompress.Compressors.Filters
protected override int Transform(byte[] buffer, int offset, int count)
{
- int end = offset + count;
+ var end = offset + count;
- for (int i = offset; i < end; i++)
+ for (var i = offset; i < end; i++)
{
buffer[i] += _history[(_distance + _position--) & DISTANCE_MASK];
_history[_position & DISTANCE_MASK] = buffer[i];
diff --git a/src/SharpCompress/Compressors/Filters/Filter.cs b/src/SharpCompress/Compressors/Filters/Filter.cs
index 93d95195..aa5e620d 100644
--- a/src/SharpCompress/Compressors/Filters/Filter.cs
+++ b/src/SharpCompress/Compressors/Filters/Filter.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.IO;
namespace SharpCompress.Compressors.Filters;
@@ -40,7 +40,7 @@ internal abstract class Filter : Stream
public override bool CanWrite => _isEncoder;
- public override void Flush() => throw new NotSupportedException();
+ public override void Flush() { }
public override long Length => _baseStream.Length;
diff --git a/src/SharpCompress/Compressors/LZMA/AesDecoderStream.cs b/src/SharpCompress/Compressors/LZMA/AesDecoderStream.cs
index 24823c73..e89d705a 100644
--- a/src/SharpCompress/Compressors/LZMA/AesDecoderStream.cs
+++ b/src/SharpCompress/Compressors/LZMA/AesDecoderStream.cs
@@ -20,7 +20,8 @@ internal sealed class AesDecoderStream : DecoderStream2
public AesDecoderStream(Stream input, byte[] info, IPasswordProvider pass, long limit)
{
- if (pass.CryptoGetTextPassword() == null)
+ var password = pass.CryptoGetTextPassword();
+ if (password == null)
{
throw new SharpCompress.Common.CryptographicException(
"Encrypted 7Zip archive has no password specified."
@@ -35,10 +36,10 @@ internal sealed class AesDecoderStream : DecoderStream2
throw new NotSupportedException("AES decoder does not support padding.");
}
- Init(info, out int numCyclesPower, out byte[] salt, out byte[] seed);
+ Init(info, out var numCyclesPower, out var salt, out var seed);
- byte[] password = Encoding.Unicode.GetBytes(pass.CryptoGetTextPassword());
- byte[]? key = InitKey(numCyclesPower, salt, password);
+ var passwordBytes = Encoding.Unicode.GetBytes(password);
+ var key = InitKey(numCyclesPower, salt, passwordBytes);
if (key == null)
{
throw new InvalidOperationException("Initialized with null key");
@@ -100,7 +101,7 @@ internal sealed class AesDecoderStream : DecoderStream2
do
{
- int read = mStream.Read(mBuffer, mEnding, mBuffer.Length - mEnding);
+ var read = mStream.Read(mBuffer, mEnding, mBuffer.Length - mEnding);
if (read == 0)
{
// We are not done decoding and have less than 16 bytes.
@@ -133,7 +134,7 @@ internal sealed class AesDecoderStream : DecoderStream2
}
// Otherwise we transform directly into the target buffer.
- int processed = mDecoder.TransformBlock(mBuffer, mOffset, count & ~15, buffer, offset);
+ var processed = mDecoder.TransformBlock(mBuffer, mOffset, count & ~15, buffer, offset);
mOffset += processed;
mWritten += processed;
return processed;
@@ -143,7 +144,7 @@ internal sealed class AesDecoderStream : DecoderStream2
private void Init(byte[] info, out int numCyclesPower, out byte[] salt, out byte[] iv)
{
- byte bt = info[0];
+ var bt = info[0];
numCyclesPower = bt & 0x3F;
if ((bt & 0xC0) == 0)
@@ -153,14 +154,14 @@ internal sealed class AesDecoderStream : DecoderStream2
return;
}
- int saltSize = (bt >> 7) & 1;
- int ivSize = (bt >> 6) & 1;
+ var saltSize = (bt >> 7) & 1;
+ var ivSize = (bt >> 6) & 1;
if (info.Length == 1)
{
throw new InvalidOperationException();
}
- byte bt2 = info[1];
+ var bt2 = info[1];
saltSize += (bt2 >> 4);
ivSize += (bt2 & 15);
if (info.Length < 2 + saltSize + ivSize)
@@ -169,13 +170,13 @@ internal sealed class AesDecoderStream : DecoderStream2
}
salt = new byte[saltSize];
- for (int i = 0; i < saltSize; i++)
+ for (var i = 0; i < saltSize; i++)
{
salt[i] = info[i + 2];
}
iv = new byte[16];
- for (int i = 0; i < ivSize; i++)
+ for (var i = 0; i < ivSize; i++)
{
iv[i] = info[i + saltSize + 2];
}
@@ -198,7 +199,7 @@ internal sealed class AesDecoderStream : DecoderStream2
key[pos] = salt[pos];
}
- for (int i = 0; i < pass.Length && pos < 32; i++)
+ for (var i = 0; i < pass.Length && pos < 32; i++)
{
key[pos++] = pass[i];
}
@@ -207,31 +208,9 @@ internal sealed class AesDecoderStream : DecoderStream2
}
else
{
-#if NETSTANDARD2_0
- using IncrementalHash sha = IncrementalHash.CreateHash(HashAlgorithmName.SHA256);
- byte[] counter = new byte[8];
- long numRounds = 1L << mNumCyclesPower;
- for (long round = 0; round < numRounds; round++)
- {
- sha.AppendData(salt, 0, salt.Length);
- sha.AppendData(pass, 0, pass.Length);
- sha.AppendData(counter, 0, 8);
-
- // This mirrors the counter so we don't have to convert long to byte[] each round.
- // (It also ensures the counter is little endian, which BitConverter does not.)
- for (int i = 0; i < 8; i++)
- {
- if (++counter[i] != 0)
- {
- break;
- }
- }
- }
- return sha.GetHashAndReset();
-#else
using var sha = SHA256.Create();
- byte[] counter = new byte[8];
- long numRounds = 1L << mNumCyclesPower;
+ var counter = new byte[8];
+ var numRounds = 1L << mNumCyclesPower;
for (long round = 0; round < numRounds; round++)
{
sha.TransformBlock(salt, 0, salt.Length, null, 0);
@@ -240,7 +219,7 @@ internal sealed class AesDecoderStream : DecoderStream2
// This mirrors the counter so we don't have to convert long to byte[] each round.
// (It also ensures the counter is little endian, which BitConverter does not.)
- for (int i = 0; i < 8; i++)
+ for (var i = 0; i < 8; i++)
{
if (++counter[i] != 0)
{
@@ -251,7 +230,6 @@ internal sealed class AesDecoderStream : DecoderStream2
sha.TransformFinalBlock(counter, 0, 0);
return sha.Hash;
-#endif
}
}
@@ -261,7 +239,7 @@ internal sealed class AesDecoderStream : DecoderStream2
// Just transform as much as possible so we can feed from it as long as possible.
if (mUnderflow == 0)
{
- int blockSize = (mEnding - mOffset) & ~15;
+ var blockSize = (mEnding - mOffset) & ~15;
mUnderflow = mDecoder.TransformBlock(mBuffer, mOffset, blockSize, mBuffer, mOffset);
}
diff --git a/src/SharpCompress/Compressors/LZMA/DecoderStream.cs b/src/SharpCompress/Compressors/LZMA/DecoderStream.cs
index 16865351..a3dbf37f 100644
--- a/src/SharpCompress/Compressors/LZMA/DecoderStream.cs
+++ b/src/SharpCompress/Compressors/LZMA/DecoderStream.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.IO;
using SharpCompress.Common.SevenZip;
using SharpCompress.Compressors.LZMA.Utilites;
@@ -14,7 +14,7 @@ internal abstract class DecoderStream2 : Stream
public override bool CanWrite => false;
- public override void Flush() => throw new NotSupportedException();
+ public override void Flush() { }
public override long Length => throw new NotSupportedException();
diff --git a/src/SharpCompress/Compressors/LZMA/LZipStream.cs b/src/SharpCompress/Compressors/LZMA/LZipStream.cs
index 4b63a621..5e987214 100644
--- a/src/SharpCompress/Compressors/LZMA/LZipStream.cs
+++ b/src/SharpCompress/Compressors/LZMA/LZipStream.cs
@@ -63,18 +63,18 @@ public sealed class LZipStream : Stream
var crc32Stream = (Crc32Stream)_stream;
crc32Stream.WrappedStream.Dispose();
crc32Stream.Dispose();
- var compressedCount = _countingWritableSubStream!.Count;
+ var compressedCount = _countingWritableSubStream.NotNull().Count;
Span intBuf = stackalloc byte[8];
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, crc32Stream.Crc);
- _countingWritableSubStream.Write(intBuf.Slice(0, 4));
+ _countingWritableSubStream?.Write(intBuf.Slice(0, 4));
BinaryPrimitives.WriteInt64LittleEndian(intBuf, _writeCount);
- _countingWritableSubStream.Write(intBuf);
+ _countingWritableSubStream?.Write(intBuf);
//total with headers
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, compressedCount + 6 + 20);
- _countingWritableSubStream.Write(intBuf);
+ _countingWritableSubStream?.Write(intBuf);
}
_finished = true;
}
diff --git a/src/SharpCompress/Compressors/LZMA/Log.cs b/src/SharpCompress/Compressors/LZMA/Log.cs
index e954e259..1431966c 100644
--- a/src/SharpCompress/Compressors/LZMA/Log.cs
+++ b/src/SharpCompress/Compressors/LZMA/Log.cs
@@ -6,7 +6,7 @@ namespace SharpCompress.Compressors.LZMA;
internal static class Log
{
- private static readonly Stack INDENT = new Stack();
+ private static readonly Stack INDENT = new();
private static bool NEEDS_INDENT = true;
static Log() => INDENT.Push("");
diff --git a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs
index 31039761..1b2fdc81 100644
--- a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs
+++ b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs
@@ -11,11 +11,11 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
{
private class LenDecoder
{
- private BitDecoder _choice = new BitDecoder();
- private BitDecoder _choice2 = new BitDecoder();
+ private BitDecoder _choice = new();
+ private BitDecoder _choice2 = new();
private readonly BitTreeDecoder[] _lowCoder = new BitTreeDecoder[Base.K_NUM_POS_STATES_MAX];
private readonly BitTreeDecoder[] _midCoder = new BitTreeDecoder[Base.K_NUM_POS_STATES_MAX];
- private BitTreeDecoder _highCoder = new BitTreeDecoder(Base.K_NUM_HIGH_LEN_BITS);
+ private BitTreeDecoder _highCoder = new(Base.K_NUM_HIGH_LEN_BITS);
private uint _numPosStates;
public void Create(uint numPosStates)
@@ -173,18 +173,18 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX
];
- private BitTreeDecoder _posAlignDecoder = new BitTreeDecoder(Base.K_NUM_ALIGN_BITS);
+ private BitTreeDecoder _posAlignDecoder = new(Base.K_NUM_ALIGN_BITS);
- private readonly LenDecoder _lenDecoder = new LenDecoder();
- private readonly LenDecoder _repLenDecoder = new LenDecoder();
+ private readonly LenDecoder _lenDecoder = new();
+ private readonly LenDecoder _repLenDecoder = new();
- private readonly LiteralDecoder _literalDecoder = new LiteralDecoder();
+ private readonly LiteralDecoder _literalDecoder = new();
private int _dictionarySize;
private uint _posStateMask;
- private Base.State _state = new Base.State();
+ private Base.State _state = new();
private uint _rep0,
_rep1,
_rep2,
@@ -318,9 +318,8 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
{
var posState = (uint)outWindow._total & _posStateMask;
if (
- _isMatchDecoders[
- (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState
- ].Decode(rangeDecoder) == 0
+ _isMatchDecoders[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState]
+ .Decode(rangeDecoder) == 0
)
{
byte b;
@@ -355,7 +354,8 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
if (
_isRep0LongDecoders[
(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState
- ].Decode(rangeDecoder) == 0
+ ]
+ .Decode(rangeDecoder) == 0
)
{
_state.UpdateShortRep();
diff --git a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs
index 558fe37b..509e54c8 100644
--- a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs
+++ b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs
@@ -61,7 +61,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
return (uint)(G_FAST_POS[pos >> 26] + 52);
}
- private Base.State _state = new Base.State();
+ private Base.State _state = new();
private byte _previousByte;
private readonly uint[] _repDistances = new uint[Base.K_NUM_REP_DISTANCES];
@@ -191,15 +191,15 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
private class LenEncoder
{
- private BitEncoder _choice = new BitEncoder();
- private BitEncoder _choice2 = new BitEncoder();
+ private BitEncoder _choice = new();
+ private BitEncoder _choice2 = new();
private readonly BitTreeEncoder[] _lowCoder = new BitTreeEncoder[
Base.K_NUM_POS_STATES_ENCODING_MAX
];
private readonly BitTreeEncoder[] _midCoder = new BitTreeEncoder[
Base.K_NUM_POS_STATES_ENCODING_MAX
];
- private BitTreeEncoder _highCoder = new BitTreeEncoder(Base.K_NUM_HIGH_LEN_BITS);
+ private BitTreeEncoder _highCoder = new(Base.K_NUM_HIGH_LEN_BITS);
public LenEncoder()
{
@@ -359,7 +359,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
private readonly Optimal[] _optimum = new Optimal[K_NUM_OPTS];
private BinTree _matchFinder;
- private readonly RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder();
+ private readonly RangeCoder.Encoder _rangeEncoder = new();
private readonly BitEncoder[] _isMatch = new BitEncoder[
Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX
@@ -382,12 +382,12 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX
];
- private BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.K_NUM_ALIGN_BITS);
+ private BitTreeEncoder _posAlignEncoder = new(Base.K_NUM_ALIGN_BITS);
- private readonly LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();
- private readonly LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();
+ private readonly LenPriceTableEncoder _lenEncoder = new();
+ private readonly LenPriceTableEncoder _repMatchLenEncoder = new();
- private readonly LiteralEncoder _literalEncoder = new LiteralEncoder();
+ private readonly LiteralEncoder _literalEncoder = new();
private readonly uint[] _matchDistances = new uint[(Base.K_MATCH_MAX_LEN * 2) + 2];
@@ -553,9 +553,8 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
if (repIndex == 0)
{
price = _isRepG0[state._index].GetPrice0();
- price += _isRep0Long[
- (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState
- ].GetPrice1();
+ price += _isRep0Long[(state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState]
+ .GetPrice1();
}
else
{
@@ -713,9 +712,8 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
.GetPrice(!_state.IsCharState(), matchByte, currentByte);
_optimum[1].MakeAsChar();
- var matchPrice = _isMatch[
- (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState
- ].GetPrice1();
+ var matchPrice = _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState]
+ .GetPrice1();
var repMatchPrice = matchPrice + _isRep[_state._index].GetPrice1();
if (matchByte == currentByte)
@@ -995,9 +993,8 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
var posStateNext = (position + 1) & _posStateMask;
var nextRepMatchPrice =
curAnd1Price
- + _isMatch[
- (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext
- ].GetPrice1()
+ + _isMatch[(state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext]
+ .GetPrice1()
+ _isRep[state2._index].GetPrice1();
{
var offset = cur + 1 + lenTest2;
@@ -1069,7 +1066,8 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
+ GetRepPrice(repIndex, lenTest, state, posState)
+ _isMatch[
(state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext
- ].GetPrice0()
+ ]
+ .GetPrice0()
+ _literalEncoder
.GetSubCoder(
position + lenTest,
@@ -1088,7 +1086,8 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
curAndLenCharPrice
+ _isMatch[
(state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext
- ].GetPrice1();
+ ]
+ .GetPrice1();
var nextRepMatchPrice = nextMatchPrice + _isRep[state2._index].GetPrice1();
// for(; lenTest2 >= 2; lenTest2--)
@@ -1174,7 +1173,8 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
+ _isMatch[
(state2._index << Base.K_NUM_POS_STATES_BITS_MAX)
+ posStateNext
- ].GetPrice0()
+ ]
+ .GetPrice0()
+ _literalEncoder
.GetSubCoder(
position + lenTest,
@@ -1194,7 +1194,8 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
+ _isMatch[
(state2._index << Base.K_NUM_POS_STATES_BITS_MAX)
+ posStateNext
- ].GetPrice1();
+ ]
+ .GetPrice1();
var nextRepMatchPrice =
nextMatchPrice + _isRep[state2._index].GetPrice1();
@@ -1243,10 +1244,8 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
return;
}
- _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].Encode(
- _rangeEncoder,
- 1
- );
+ _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState]
+ .Encode(_rangeEncoder, 1);
_isRep[_state._index].Encode(_rangeEncoder, 0);
_state.UpdateMatch();
var len = Base.K_MATCH_MIN_LEN;
@@ -1321,10 +1320,8 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
// it's not used
ReadMatchDistances(out var len, out var numDistancePairs);
var posState = (uint)(_nowPos64) & _posStateMask;
- _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].Encode(
- _rangeEncoder,
- 0
- );
+ _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState]
+ .Encode(_rangeEncoder, 0);
_state.UpdateChar();
var curByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset));
_literalEncoder
@@ -1730,7 +1727,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
ReadOnlySpan